@qilitt-mickey/vue3-temp-skill 1.0.12 → 1.1.2
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 +66 -214
- package/SKILL.md +165 -527
- package/package.json +2 -2
- package/references/api-check.md +187 -128
- package/references/base-code-dict.md +49 -48
- package/references/chart-echarts.md +61 -0
- package/references/code-quality.md +44 -15
- package/references/core-kernel.md +305 -0
- package/references/crud-pages.md +87 -261
- package/references/data-compare.md +502 -501
- package/references/data-mapping.md +218 -213
- package/references/data-screen.md +94 -79
- package/references/data-writeback.md +104 -104
- package/references/detail-page.md +100 -99
- package/references/directives-advanced.md +27 -4
- package/references/download-export.md +70 -68
- package/references/feedback-loading.md +62 -60
- package/references/feedback-ui.md +125 -111
- package/references/file-management.md +28 -7
- package/references/flowchart-g6.md +249 -244
- package/references/form-advanced.md +264 -26
- package/references/graph-relation.md +12 -7
- package/references/http-api.md +138 -103
- package/references/icons.md +326 -0
- package/references/layout-theme.md +1 -1
- package/references/mobile-h5.md +20 -0
- package/references/particles.md +143 -0
- package/references/permission-auth.md +8 -31
- package/references/project-inventory.md +175 -120
- package/references/qrcode-barcode.md +107 -92
- package/references/rich-text.md +85 -73
- package/references/seamless-scroll.md +40 -38
- package/references/table-vxe.md +114 -0
- package/references/tree-table.md +2 -1
- package/references/ui-components.md +5 -1
- package/references/verify-captcha.md +110 -96
- package/references/websocket-realtime.md +2 -1
- package/references/wechat-js.md +58 -0
- package/references/workflow-bpmn.md +207 -206
- package/references/advanced-ui.md +0 -302
- package/references/build-optim.md +0 -282
- package/references/vue-core.md +0 -209
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
skill: advanced-ui
|
|
3
|
-
description: 规范高级 UI 组件的使用与开发,包括选择器组件(下拉/树/级联)、高级表格(vxe-table)、高级表单、图表(ECharts)、工作流(BPMN)、树形表格等。在开发复杂交互组件时调用。
|
|
4
|
-
scope: project
|
|
5
|
-
tags: [vue3, select, tree, table, vxe-table, echarts, bpmn, cascader, form-advanced]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# 高级 UI 组件规范
|
|
9
|
-
|
|
10
|
-
## 选择器组件
|
|
11
|
-
|
|
12
|
-
### ReSelectQuery(下拉查询选择器)
|
|
13
|
-
|
|
14
|
-
适用于需要搜索、分页、远程加载的下拉选择场景:
|
|
15
|
-
|
|
16
|
-
```vue
|
|
17
|
-
<script setup lang="ts">
|
|
18
|
-
import { ReSelectQuery } from "@/components/ReSelectQuery";
|
|
19
|
-
|
|
20
|
-
const value = ref("");
|
|
21
|
-
|
|
22
|
-
// 远程搜索
|
|
23
|
-
function remoteMethod(query: string) {
|
|
24
|
-
// 调用 API 获取选项列表
|
|
25
|
-
}
|
|
26
|
-
</script>
|
|
27
|
-
|
|
28
|
-
<template>
|
|
29
|
-
<ReSelectQuery
|
|
30
|
-
v-model="value"
|
|
31
|
-
:api="getUserListApi"
|
|
32
|
-
label-key="name"
|
|
33
|
-
value-key="id"
|
|
34
|
-
placeholder="请选择用户"
|
|
35
|
-
:remote="true"
|
|
36
|
-
:remote-method="remoteMethod"
|
|
37
|
-
/>
|
|
38
|
-
</template>
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### el-tree-select(树形下拉选择)
|
|
42
|
-
|
|
43
|
-
适用于组织架构、分类选择等树形数据场景:
|
|
44
|
-
|
|
45
|
-
```vue
|
|
46
|
-
<template>
|
|
47
|
-
<el-tree-select
|
|
48
|
-
v-model="value"
|
|
49
|
-
:data="treeData"
|
|
50
|
-
:props="{ label: 'name', value: 'id', children: 'children' }"
|
|
51
|
-
check-strictly
|
|
52
|
-
:render-after-expand="false"
|
|
53
|
-
placeholder="请选择部门"
|
|
54
|
-
/>
|
|
55
|
-
</template>
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### ReCascader(级联选择器)
|
|
59
|
-
|
|
60
|
-
适用于省市区、多级分类等联动选择场景:
|
|
61
|
-
|
|
62
|
-
```vue
|
|
63
|
-
<template>
|
|
64
|
-
<ReCascader
|
|
65
|
-
v-model="value"
|
|
66
|
-
:api="getAreaListApi"
|
|
67
|
-
:props="{ label: 'name', value: 'code', children: 'children' }"
|
|
68
|
-
placeholder="请选择地区"
|
|
69
|
-
/>
|
|
70
|
-
</template>
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### 选择器约定
|
|
74
|
-
|
|
75
|
-
1. 简单下拉使用 `el-select`,需要搜索+分页用 `ReSelectQuery`。
|
|
76
|
-
2. 树形数据选择使用 `el-tree-select`,不要用 `el-select` 嵌套 `el-tree`。
|
|
77
|
-
3. 级联场景使用 `ReCascader`,支持异步加载子节点。
|
|
78
|
-
4. 移动端选择使用 `RePopupPicker`(基于 Vant)。
|
|
79
|
-
5. 选择器必须设置 `placeholder`,清除按钮默认开启。
|
|
80
|
-
|
|
81
|
-
## 高级表格
|
|
82
|
-
|
|
83
|
-
### ReTableBar(表格工具栏)
|
|
84
|
-
|
|
85
|
-
```vue
|
|
86
|
-
<ReTableBar>
|
|
87
|
-
<template #left>
|
|
88
|
-
<el-button type="primary" @click="handleAdd">新增</el-button>
|
|
89
|
-
<el-button type="danger" :disabled="!selected.length" @click="handleBatchDelete">
|
|
90
|
-
批量删除
|
|
91
|
-
</el-button>
|
|
92
|
-
</template>
|
|
93
|
-
<template #right>
|
|
94
|
-
<!-- 右侧默认包含:列配置、密度、全屏按钮 -->
|
|
95
|
-
</template>
|
|
96
|
-
</ReTableBar>
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
### ReTableOperate(操作列按钮组)
|
|
100
|
-
|
|
101
|
-
```vue
|
|
102
|
-
<el-table-column label="操作" width="200" fixed="right">
|
|
103
|
-
<template #default="{ row }">
|
|
104
|
-
<ReTableOperate
|
|
105
|
-
:buttons="[
|
|
106
|
-
{ label: '查看', type: 'primary', link: true, onClick: () => handleView(row) },
|
|
107
|
-
{ label: '编辑', type: 'primary', link: true, onClick: () => handleEdit(row) },
|
|
108
|
-
{
|
|
109
|
-
label: '删除',
|
|
110
|
-
type: 'danger',
|
|
111
|
-
link: true,
|
|
112
|
-
confirm: { title: '确认删除?', message: `将删除「${row.name}」` },
|
|
113
|
-
onClick: () => handleDelete(row),
|
|
114
|
-
},
|
|
115
|
-
]"
|
|
116
|
-
:max="3"
|
|
117
|
-
/>
|
|
118
|
-
</template>
|
|
119
|
-
</el-table-column>
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### ReGrid(数据表格)
|
|
123
|
-
|
|
124
|
-
```vue
|
|
125
|
-
<ReGrid
|
|
126
|
-
v-loading="loading"
|
|
127
|
-
:data="content"
|
|
128
|
-
:pagination="pagination"
|
|
129
|
-
@page-change="handlePageChange"
|
|
130
|
-
@size-change="handleSizeChange"
|
|
131
|
-
@selection-change="handleSelectionChange"
|
|
132
|
-
>
|
|
133
|
-
<el-table-column type="selection" width="55" />
|
|
134
|
-
<el-table-column prop="name" label="名称" sortable />
|
|
135
|
-
<el-table-column prop="createTime" label="创建时间" width="180" />
|
|
136
|
-
<el-table-column label="操作" width="200" fixed="right">
|
|
137
|
-
<!-- ... -->
|
|
138
|
-
</el-table-column>
|
|
139
|
-
</ReGrid>
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### vxe-table(高性能表格)
|
|
143
|
-
|
|
144
|
-
当数据量超过 1000 行或需要复杂编辑(行内编辑、单元格合并)时使用 vxe-table:
|
|
145
|
-
|
|
146
|
-
```vue
|
|
147
|
-
<script setup lang="ts">
|
|
148
|
-
import { ref } from "vue";
|
|
149
|
-
|
|
150
|
-
const gridRef = ref();
|
|
151
|
-
const tableData = ref([]);
|
|
152
|
-
|
|
153
|
-
const columns = [
|
|
154
|
-
{ type: "seq", width: 60 },
|
|
155
|
-
{ field: "name", title: "名称", sortable: true },
|
|
156
|
-
{ field: "status", title: "状态", formatter: (v) => (v ? "启用" : "禁用") },
|
|
157
|
-
];
|
|
158
|
-
</script>
|
|
159
|
-
|
|
160
|
-
<template>
|
|
161
|
-
<vxe-grid
|
|
162
|
-
ref="gridRef"
|
|
163
|
-
:data="tableData"
|
|
164
|
-
:columns="columns"
|
|
165
|
-
:pager-config="{ total: 100 }"
|
|
166
|
-
:edit-config="{ trigger: 'click', mode: 'cell' }"
|
|
167
|
-
/>
|
|
168
|
-
</template>
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
## 树形表格
|
|
172
|
-
|
|
173
|
-
### 数据转换
|
|
174
|
-
|
|
175
|
-
使用 `handleTree` 工具函数将平铺数据转为树形结构:
|
|
176
|
-
|
|
177
|
-
```typescript
|
|
178
|
-
import { handleTree } from "@/utils/tree";
|
|
179
|
-
|
|
180
|
-
const flatData = ref<FlatItem[]>([]);
|
|
181
|
-
const treeData = computed(() =>
|
|
182
|
-
handleTree(flatData.value, "id", "parentId", "children")
|
|
183
|
-
);
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
### 树形表格渲染
|
|
187
|
-
|
|
188
|
-
```vue
|
|
189
|
-
<ReGrid :data="treeData" :tree-props="{ children: 'children' }" row-key="id">
|
|
190
|
-
<el-table-column prop="name" label="名称" />
|
|
191
|
-
<el-table-column prop="code" label="编码" />
|
|
192
|
-
</ReGrid>
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
### 树形连线展示
|
|
196
|
-
|
|
197
|
-
使用 `ReTreeLine` 组件为树形表格添加视觉连线:
|
|
198
|
-
|
|
199
|
-
```vue
|
|
200
|
-
<template>
|
|
201
|
-
<ReTreeLine :data="treeData">
|
|
202
|
-
<template #default="{ row }">
|
|
203
|
-
<span>{{ row.name }}</span>
|
|
204
|
-
</template>
|
|
205
|
-
</ReTreeLine>
|
|
206
|
-
</template>
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
## 高级表单组件
|
|
210
|
-
|
|
211
|
-
### ReIconPicker(图标选择器)
|
|
212
|
-
|
|
213
|
-
```vue
|
|
214
|
-
<el-form-item label="菜单图标">
|
|
215
|
-
<ReIconPicker v-model="formData.icon" />
|
|
216
|
-
</el-form-item>
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
### ReSegmented(分段控制器)
|
|
220
|
-
|
|
221
|
-
```vue
|
|
222
|
-
<ReSegmented
|
|
223
|
-
v-model="activeTab"
|
|
224
|
-
:options="[
|
|
225
|
-
{ label: '基本信息', value: 'basic' },
|
|
226
|
-
{ label: '详细配置', value: 'config' },
|
|
227
|
-
{ label: '权限设置', value: 'permission' },
|
|
228
|
-
]"
|
|
229
|
-
/>
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
### ReCheckCard(多选卡片)
|
|
233
|
-
|
|
234
|
-
```vue
|
|
235
|
-
<ReCheckCard
|
|
236
|
-
v-model="selectedRoles"
|
|
237
|
-
:options="roleOptions"
|
|
238
|
-
multiple
|
|
239
|
-
/>
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
## 图表 (ECharts)
|
|
243
|
-
|
|
244
|
-
### 基础用法
|
|
245
|
-
|
|
246
|
-
```vue
|
|
247
|
-
<script setup lang="ts">
|
|
248
|
-
import { ref, onMounted } from "vue";
|
|
249
|
-
import * as echarts from "echarts";
|
|
250
|
-
|
|
251
|
-
const chartRef = ref<HTMLDivElement>();
|
|
252
|
-
let chartInstance: echarts.ECharts;
|
|
253
|
-
|
|
254
|
-
onMounted(() => {
|
|
255
|
-
chartInstance = echarts.init(chartRef.value!);
|
|
256
|
-
chartInstance.setOption({
|
|
257
|
-
title: { text: "数据统计" },
|
|
258
|
-
tooltip: { trigger: "axis" },
|
|
259
|
-
xAxis: { type: "category", data: ["1月", "2月", "3月"] },
|
|
260
|
-
yAxis: { type: "value" },
|
|
261
|
-
series: [{ type: "bar", data: [120, 200, 150] }],
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
// 响应式:监听容器大小变化
|
|
266
|
-
const resizeObserver = new ResizeObserver(() => chartInstance?.resize());
|
|
267
|
-
onMounted(() => resizeObserver.observe(chartRef.value!));
|
|
268
|
-
onUnmounted(() => {
|
|
269
|
-
resizeObserver.disconnect();
|
|
270
|
-
chartInstance?.dispose();
|
|
271
|
-
});
|
|
272
|
-
</script>
|
|
273
|
-
|
|
274
|
-
<template>
|
|
275
|
-
<div ref="chartRef" style="width: 100%; height: 400px;" />
|
|
276
|
-
</template>
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
### 图表约定
|
|
280
|
-
|
|
281
|
-
1. 始终在 `onUnmounted` 中 `dispose()` 图表实例,防止内存泄漏。
|
|
282
|
-
2. 使用 `ResizeObserver` 监听容器变化自动调整大小。
|
|
283
|
-
3. 图表配置项抽取为独立变量或函数,不要内联在 `setOption` 中。
|
|
284
|
-
4. 数据大屏场景使用 `ReFlicker` 组件实现闪烁效果。
|
|
285
|
-
|
|
286
|
-
## 工作流
|
|
287
|
-
|
|
288
|
-
### BPMN 流程设计器
|
|
289
|
-
|
|
290
|
-
项目集成 `bpmn-js` 用于流程设计,使用方式参考 `src/views/workflow/` 下的示例页面。
|
|
291
|
-
|
|
292
|
-
### jsplumb 关系图
|
|
293
|
-
|
|
294
|
-
用于可视化连线配置场景(如审批流程配置),参考 `src/components/` 下的封装组件。
|
|
295
|
-
|
|
296
|
-
## 常见反例
|
|
297
|
-
|
|
298
|
-
- 大数据量表格使用 `el-table` 而不是 `vxe-table`(性能问题)。
|
|
299
|
-
- 树形数据不使用 `handleTree` 转换,手动递归。
|
|
300
|
-
- 图表实例不在组件卸载时销毁,导致内存泄漏。
|
|
301
|
-
- 操作列超过 3 个按钮不使用 `ReTableOperate` 的 `max` 属性折叠。
|
|
302
|
-
- 选择器不设置 `placeholder`。
|
|
@@ -1,282 +0,0 @@
|
|
|
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` 注释。
|