vue2server7 7.0.105 → 7.0.107
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/package.json
CHANGED
package/test/231231
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="error-page">
|
|
3
|
+
<div class="error-content">
|
|
4
|
+
<div class="illustration">
|
|
5
|
+
<svg viewBox="0 0 420 260" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
6
|
+
<path d="M120 75H310L292 155H95L120 75Z" stroke="#5B83F7" stroke-width="2" />
|
|
7
|
+
<path d="M135 90H290" stroke="#5B83F7" stroke-width="14" />
|
|
8
|
+
<path d="M104 110H150" stroke="#5B83F7" stroke-width="14" />
|
|
9
|
+
<path d="M292 110H345" stroke="#5B83F7" stroke-width="8" />
|
|
10
|
+
<path d="M306 135H335" stroke="#5B83F7" stroke-width="5" />
|
|
11
|
+
<path d="M260 175H355" stroke="#5B83F7" stroke-width="14" />
|
|
12
|
+
<path d="M85 168H250" stroke="#5B83F7" stroke-width="2" />
|
|
13
|
+
<circle cx="245" cy="122" r="43" fill="#6B8DFF" />
|
|
14
|
+
<path d="M230 107L260 137M260 107L230 137" stroke="white" stroke-width="10" stroke-linecap="round" />
|
|
15
|
+
<circle cx="65" cy="155" r="24" stroke="#5B83F7" stroke-width="2" />
|
|
16
|
+
<circle cx="95" cy="158" r="34" stroke="#5B83F7" stroke-width="2" />
|
|
17
|
+
<circle cx="95" cy="158" r="22" fill="#87A4FF" />
|
|
18
|
+
<path d="M48 155C20 150 25 130 50 132C74 134 85 143 92 154" stroke="#5B83F7" stroke-width="2" />
|
|
19
|
+
<path d="M30 185H118C124 185 129 190 129 196C129 202 124 207 118 207H82C76 207 71 212 71 218C71 224 76 229 82 229H52" stroke="#5B83F7" stroke-width="2" />
|
|
20
|
+
<path d="M40 196H155" stroke="#5B83F7" stroke-width="18" stroke-linecap="round" />
|
|
21
|
+
<path d="M92 190V222" stroke="#5B83F7" stroke-width="18" stroke-linecap="round" />
|
|
22
|
+
<path d="M58 223H115" stroke="#5B83F7" stroke-width="16" stroke-linecap="round" />
|
|
23
|
+
<path d="M270 223H330" stroke="#5B83F7" stroke-width="2" />
|
|
24
|
+
<path d="M280 210H310C318 210 325 217 325 225H275C275 217 276 210 280 210Z" fill="#5B83F7" />
|
|
25
|
+
<path d="M318 210H333" stroke="#5B83F7" stroke-width="2" />
|
|
26
|
+
<path d="M130 62L140 30H315L300 75" stroke="#5B83F7" stroke-width="2" />
|
|
27
|
+
<path d="M320 40L305 100" stroke="#5B83F7" stroke-width="2" />
|
|
28
|
+
<path d="M115 112L92 175" stroke="#5B83F7" stroke-width="2" />
|
|
29
|
+
<path d="M305 78H340" stroke="#476AD7" stroke-width="8" />
|
|
30
|
+
<circle cx="148" cy="48" r="3" fill="#5B83F7" />
|
|
31
|
+
<circle cx="162" cy="48" r="3" fill="#5B83F7" />
|
|
32
|
+
</svg>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div class="text-box">
|
|
36
|
+
<h2>抱歉,服务器出错了</h2>
|
|
37
|
+
<el-button type="primary" class="back-btn" @click="goHome">
|
|
38
|
+
返回首页
|
|
39
|
+
</el-button>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<script setup lang="ts">
|
|
46
|
+
import { useRouter } from 'vue-router'
|
|
47
|
+
|
|
48
|
+
const router = useRouter()
|
|
49
|
+
|
|
50
|
+
const goHome = (): void => {
|
|
51
|
+
router.push('/')
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<style scoped>
|
|
56
|
+
.error-page {
|
|
57
|
+
width: 100%;
|
|
58
|
+
min-height: 100vh;
|
|
59
|
+
background: #f7f8fa;
|
|
60
|
+
display: flex;
|
|
61
|
+
align-items: center;
|
|
62
|
+
justify-content: center;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.error-content {
|
|
66
|
+
display: flex;
|
|
67
|
+
align-items: center;
|
|
68
|
+
gap: 110px;
|
|
69
|
+
transform: translateY(-20px);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.illustration {
|
|
73
|
+
width: 420px;
|
|
74
|
+
height: 260px;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.illustration svg {
|
|
78
|
+
width: 100%;
|
|
79
|
+
height: 100%;
|
|
80
|
+
display: block;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.text-box {
|
|
84
|
+
padding-top: 10px;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.text-box h2 {
|
|
88
|
+
margin: 0 0 28px;
|
|
89
|
+
font-size: 26px;
|
|
90
|
+
font-weight: 600;
|
|
91
|
+
color: #71809a;
|
|
92
|
+
letter-spacing: 1px;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.back-btn {
|
|
96
|
+
width: 118px;
|
|
97
|
+
height: 48px;
|
|
98
|
+
border-radius: 6px;
|
|
99
|
+
font-size: 16px;
|
|
100
|
+
background: #5b83f7;
|
|
101
|
+
border-color: #5b83f7;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.back-btn:hover,
|
|
105
|
+
.back-btn:focus {
|
|
106
|
+
background: #6b8dff;
|
|
107
|
+
border-color: #6b8dff;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@media (max-width: 768px) {
|
|
111
|
+
.error-content {
|
|
112
|
+
flex-direction: column;
|
|
113
|
+
gap: 24px;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.illustration {
|
|
117
|
+
width: 320px;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.text-box {
|
|
121
|
+
text-align: center;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.text-box h2 {
|
|
125
|
+
font-size: 22px;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
</style>
|
package/test/500 (1).svg
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg
|
|
2
|
+
viewBox="0 0 400 300"
|
|
3
|
+
fill="none"
|
|
4
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
5
|
+
><mask id="a" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="47" y="38" width="307" height="224"><path d="M353.3 38H47.5v223.8h305.8V38Z" fill="#fff"/></mask><g mask="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M299.2 200.6H61.6v5.1h240.3l-2.7-5.1Z" fill="#C7DEFF"/><path d="m308.9 185.8-6.5 20H183.7M332.3 127.6h10.6l-5 16.7-14.8-.1-7.2 21.1M328.8 127.4l13.6-39.6M307.6 166 337 84.7H180.6l-9.8 26.9h-10.5M296.6 196l4.3-11.8M157.2 149.2l6.4-17.7" stroke="#071F4D"/><path fill-rule="evenodd" clip-rule="evenodd" d="M324.8 93.1H188.5l-34.8 95.8h136.4l34.7-95.8ZM169.9 166.2l5-13.6-5 13.6Z" fill="#fff"/><path d="m169.9 166.2 5-13.6" stroke="#071F4D"/><path fill-rule="evenodd" clip-rule="evenodd" d="M324.8 93.1H188.5l-4 11.7h135.8l4.5-11.7Z" fill="#006EFF"/><path fill-rule="evenodd" clip-rule="evenodd" d="M102.6 159.5h38.3l2.7 36.6h-38.4c-10.1 0-20.9-8.2-20.9-18.3 0-10.1 8.2-18.3 18.3-18.3Z" fill="#DEEBFC"/><path fill-rule="evenodd" clip-rule="evenodd" d="M84.3 174.102c2.5 3.4 10 5 17.9 2.8 16.6-6.5 23.8-3.9 23.8-3.9s.5-3.4 1.3-5c-5.8-3-15.4.3-26.1 3.1-10.7 2.8-15.8-2.5-15.8-2.5-.4 0-1.1 2.8-1.1 5.5Z" fill="#fff"/><path d="M96.5 194.2c-7.2-3.3-12.2-10.5-12.2-19m0 0c0-11.5 9.3-20.8 20.8-20.8h29.4" stroke="#071F4D"/><path fill-rule="evenodd" clip-rule="evenodd" d="M140.3 195.1c-8.4-2.7-14.5-10.6-14.5-19.8l14.5 19.8Zm-14.5-19.8c0-11.5 9.3-20.8 20.8-20.8l-20.8 20.8Zm20.8-20.8c11.5 0 20.8 9.3 20.8 20.8l-20.8-20.8Zm20.8 20.8c0 8.4-5 15.6-12.1 18.9l12.1-18.9Z" fill="#fff"/><path d="M140.3 195.1c-8.4-2.7-14.5-10.6-14.5-19.8m0 0c0-11.5 9.3-20.8 20.8-20.8m0 0c11.5 0 20.8 9.3 20.8 20.8m0 0c0 8.4-5 15.6-12.1 18.9" stroke="#071F4D"/><path fill-rule="evenodd" clip-rule="evenodd" d="M161.5 177.2c0-7.7-6.3-14-14-14s-14 6.3-14 14c0 5.8 3.5 10.8 8.6 12.9.1 0 5.8 1.6 10.7 0 5.3-1.7 8.7-7.1 8.7-12.9Z" fill="#00E4E5"/><path d="M140.5 190.1c-5.8-2.4-9.9-8.2-9.9-14.9 0-8.9 7.2-16.1 16.1-16.1 8.9 0 16.1 7.2 16.1 16.1 0 6.8-4.2 12.5-10.1 14.9M88.4 170.604c2.9 1.3 7.7 2.6 13.6.3 14.7-5.7 22.3-4.3 24.6-3.5M84.5 174.599s5.9 6.5 19 1.7c9.2-3.4 15.3-3.9 18.8-3.8" stroke="#071F4D"/><path fill-rule="evenodd" clip-rule="evenodd" d="M340.6 112.3h-55.2l-2.7 6.2H338l2.6-6.2Z" fill="#071F4D"/><path fill-rule="evenodd" clip-rule="evenodd" d="M236.8 117.9c-16.13 0-29.2 13.07-29.2 29.2s13.07 29.2 29.2 29.2 29.2-13.07 29.2-29.2-13.07-29.2-29.2-29.2Z" fill="#00E4E5"/><path d="M265 123.3c13.1 13.1 13.1 34.4 0 47.6M306 205.9h19.2M61.7 205.9h32.9M181.2 196.2h115.2M47.5 205.9h10v-9.7h73.8" stroke="#071F4D"/><path fill-rule="evenodd" clip-rule="evenodd" d="M146.7 179.2c-2.49 0-4.5 2.01-4.5 4.5s2.01 4.5 4.5 4.5 4.5-2.01 4.5-4.5-2.01-4.5-4.5-4.5Z" fill="#071F4D"/><path fill-rule="evenodd" clip-rule="evenodd" d="M169.5 196.2c3.9 0 7.1 3.2 7.1 7.1 0 3.9-3.2 7.1-7.1 7.1H144c-2.1 0-3.9 1.7-3.9 3.9v1c0 2.1 1.7 3.9 3.9 3.9h48c5.1 0 9.2 4.1 9.2 9.2s-4.1 9.3-9.2 9.2h-33.8c-2.3 0-4.1 1.8-4.1 4.1s1.8 4.1 4.1 4.1h4.2c4.4 0 8 3.6 8 8s-3.6 8-8 8H111c-3.7 0-6.8-3-6.8-6.8 0-3.7 3-6.8 6.8-6.8h.3c2.3 0 4.1-1.8 4.1-4.1s-1.8-4.1-4.1-4.1H79c-4.5 0-8.1-3.6-8.1-8.1s3.6-8.1 8.1-8.1h37.7c2.1 0 3.9-1.7 3.9-3.9 0-2.1-1.7-3.9-3.9-3.9h-7.9c-4.4 0-7.9-3.5-7.9-7.9s3.5-7.9 7.9-7.9h30.4c2.2 0 3.9-1.8 3.9-3.9V187c0-1.9 1.6-3.5 3.5-3.5s3.5 1.6 3.5 3.5v5.3c0 2.2 1.8 3.9 3.9 3.9h15.5Z" fill="#006EFF"/><path d="m227.8 138.5 18.7 18.7M227.8 157.2l18.7-18.7" stroke="#fff" stroke-width="6"/><path fill-rule="evenodd" clip-rule="evenodd" d="M194.8 96.9c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8ZM202.9 96.9c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8Z" fill="#fff"/><path d="m291.7 184.3-1.6 4.6h-121M298.1 166.7l22.5-61.9" stroke="#071F4D"/><path fill-rule="evenodd" clip-rule="evenodd" d="m193 134.1 2.2-5.1h-19.4l-2.3 5.1H193ZM313.2 123.5l2.2-5.1h-24.5l-2.3 5.1h24.6Z" fill="#DEEBFC"/><path d="m164.5 159.2 19.8-54.6" stroke="#071F4D"/><path fill-rule="evenodd" clip-rule="evenodd" d="M199.6 119.8h-53.2l-4.4 9.3h53.2l4.4-9.3Z" fill="#00E4E5"/><path d="M151.3 129.1H142l4.4-9.3h16.9" stroke="#071F4D"/><path fill-rule="evenodd" clip-rule="evenodd" d="M353.3 169.4h-67.4l-4.8 12.2h67.3l4.9-12.2Z" fill="#006EFF"/><path d="M332.4 169.4h20.9l-4.9 12.2h-39.7M242.7 235.5v-4.8c0-3.8 3.1-7 7-7h20.2c3.8 0 7 3.1 7 7" stroke="#071F4D"/><path d="M261.1 235.5v-4.8c0-3.8 3.1-7 7-7h13.7c3.8 0 7 3.1 7 7v4.8M242.6 230.7h13.7M235.2 237.7h63.3M224 237.7h6.7" stroke="#071F4D"/><path fill-rule="evenodd" clip-rule="evenodd" d="M324.1 141.3H335l3.3-10.7h-10.2l-4 10.7Z" fill="#C7DEFF"/><path fill-rule="evenodd" clip-rule="evenodd" d="M288.3 230.4c0-3.6-2.9-6.5-6.5-6.5h-14.2c-3.6 0-6.5 2.9-6.5 6.5v5.3h27.2v-5.3Z" fill="#071F4D"/><path d="M80.4 228.5H83M87.7 228.5h19.2M146.3 195.8v2c0 3.6-2.9 6.6-6.6 6.6H138M133.4 204.3h1.5M154 249.9h9.4" stroke="#DEEBFC"/><path d="m299.4 141.9 5.1-13.9" stroke="#071F4D"/></g></svg>
|
|
@@ -0,0 +1,871 @@
|
|
|
1
|
+
# Vue3 项目开发规范
|
|
2
|
+
|
|
3
|
+
## 1. 文档说明
|
|
4
|
+
|
|
5
|
+
本文档用于规范 Vue3 项目的目录结构、代码风格、组件开发、路由管理、状态管理、接口请求、样式编写、Git 提交以及团队协作流程。
|
|
6
|
+
|
|
7
|
+
适用技术栈:
|
|
8
|
+
|
|
9
|
+
- Vue 3
|
|
10
|
+
- Vite
|
|
11
|
+
- TypeScript
|
|
12
|
+
- Vue Router
|
|
13
|
+
- Pinia
|
|
14
|
+
- Axios
|
|
15
|
+
- Element Plus / TDesign Vue Next
|
|
16
|
+
- ESLint
|
|
17
|
+
- Prettier
|
|
18
|
+
- Stylelint
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 2. 项目目录规范
|
|
23
|
+
|
|
24
|
+
推荐目录结构:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
src
|
|
28
|
+
├── api # 接口请求模块
|
|
29
|
+
├── assets # 静态资源
|
|
30
|
+
│ ├── images
|
|
31
|
+
│ ├── icons
|
|
32
|
+
│ └── fonts
|
|
33
|
+
├── components # 公共组件
|
|
34
|
+
├── composables # 组合式函数
|
|
35
|
+
├── constants # 常量配置
|
|
36
|
+
├── directives # 自定义指令
|
|
37
|
+
├── hooks # 业务 hooks
|
|
38
|
+
├── layouts # 页面布局
|
|
39
|
+
├── plugins # 插件注册
|
|
40
|
+
├── router # 路由配置
|
|
41
|
+
│ ├── index.ts
|
|
42
|
+
│ └── modules
|
|
43
|
+
├── stores # Pinia 状态管理
|
|
44
|
+
├── styles # 全局样式
|
|
45
|
+
├── types # TypeScript 类型声明
|
|
46
|
+
├── utils # 工具函数
|
|
47
|
+
├── views # 页面模块
|
|
48
|
+
├── App.vue
|
|
49
|
+
└── main.ts
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 3. 文件命名规范
|
|
55
|
+
|
|
56
|
+
### 3.1 Vue 组件命名
|
|
57
|
+
|
|
58
|
+
组件文件使用大驼峰命名:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
UserCard.vue
|
|
62
|
+
UserForm.vue
|
|
63
|
+
BaseTable.vue
|
|
64
|
+
SearchPanel.vue
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 3.2 页面文件命名
|
|
68
|
+
|
|
69
|
+
页面文件建议使用大驼峰命名:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
views/user/UserList.vue
|
|
73
|
+
views/user/UserDetail.vue
|
|
74
|
+
views/system/RoleManage.vue
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 3.3 工具文件命名
|
|
78
|
+
|
|
79
|
+
工具文件使用小驼峰命名:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
formatDate.ts
|
|
83
|
+
storage.ts
|
|
84
|
+
request.ts
|
|
85
|
+
validate.ts
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 3.4 类型文件命名
|
|
89
|
+
|
|
90
|
+
类型文件使用 `.type.ts` 后缀:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
user.type.ts
|
|
94
|
+
order.type.ts
|
|
95
|
+
api.type.ts
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 3.5 路由文件命名
|
|
99
|
+
|
|
100
|
+
路由文件使用 `.route.ts` 后缀:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
user.route.ts
|
|
104
|
+
order.route.ts
|
|
105
|
+
system.route.ts
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 4. 代码风格规范
|
|
111
|
+
|
|
112
|
+
### 4.1 统一使用 `<script setup>`
|
|
113
|
+
|
|
114
|
+
```vue
|
|
115
|
+
<script setup lang="ts">
|
|
116
|
+
import { ref } from 'vue'
|
|
117
|
+
|
|
118
|
+
const count = ref(0)
|
|
119
|
+
|
|
120
|
+
function handleAdd() {
|
|
121
|
+
count.value++
|
|
122
|
+
}
|
|
123
|
+
</script>
|
|
124
|
+
|
|
125
|
+
<template>
|
|
126
|
+
<button @click="handleAdd">
|
|
127
|
+
{{ count }}
|
|
128
|
+
</button>
|
|
129
|
+
</template>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 4.2 使用 TypeScript
|
|
133
|
+
|
|
134
|
+
所有 Vue 文件推荐使用:
|
|
135
|
+
|
|
136
|
+
```vue
|
|
137
|
+
<script setup lang="ts">
|
|
138
|
+
</script>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 4.3 禁止滥用 any
|
|
142
|
+
|
|
143
|
+
不推荐:
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
const user: any = {}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
推荐:
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
interface UserInfo {
|
|
153
|
+
id: number
|
|
154
|
+
username: string
|
|
155
|
+
avatar?: string
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const user = ref<UserInfo | null>(null)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 5. 组件开发规范
|
|
164
|
+
|
|
165
|
+
### 5.1 组件职责单一
|
|
166
|
+
|
|
167
|
+
一个组件只负责一个明确的功能,例如:
|
|
168
|
+
|
|
169
|
+
- 用户表格组件只负责展示用户列表
|
|
170
|
+
- 搜索组件只负责搜索条件输入
|
|
171
|
+
- 弹窗组件只负责表单录入和提交
|
|
172
|
+
|
|
173
|
+
### 5.2 Props 定义规范
|
|
174
|
+
|
|
175
|
+
必须定义 Props 类型。
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
interface Props {
|
|
179
|
+
title: string
|
|
180
|
+
loading?: boolean
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
184
|
+
loading: false
|
|
185
|
+
})
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
禁止使用:
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
defineProps(['title', 'loading'])
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 5.3 Emits 定义规范
|
|
195
|
+
|
|
196
|
+
事件名建议使用 kebab-case。
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
const emit = defineEmits<{
|
|
200
|
+
'submit-form': [value: FormData]
|
|
201
|
+
'update:modelValue': [value: string]
|
|
202
|
+
}>()
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### 5.4 不直接修改 Props
|
|
206
|
+
|
|
207
|
+
错误写法:
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
props.visible = false
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
正确写法:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
const emit = defineEmits<{
|
|
217
|
+
'update:visible': [value: boolean]
|
|
218
|
+
}>()
|
|
219
|
+
|
|
220
|
+
emit('update:visible', false)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## 6. 页面开发规范
|
|
226
|
+
|
|
227
|
+
页面建议按以下顺序组织:
|
|
228
|
+
|
|
229
|
+
1. import 引入
|
|
230
|
+
2. 类型定义
|
|
231
|
+
3. 响应式数据
|
|
232
|
+
4. 计算属性
|
|
233
|
+
5. 方法函数
|
|
234
|
+
6. 生命周期
|
|
235
|
+
7. 监听器
|
|
236
|
+
|
|
237
|
+
示例:
|
|
238
|
+
|
|
239
|
+
```vue
|
|
240
|
+
<script setup lang="ts">
|
|
241
|
+
import { onMounted, ref } from 'vue'
|
|
242
|
+
import { getUserListApi } from '@/api/user.api'
|
|
243
|
+
import type { UserInfo } from '@/types/user.type'
|
|
244
|
+
|
|
245
|
+
const loading = ref(false)
|
|
246
|
+
const userList = ref<UserInfo[]>([])
|
|
247
|
+
|
|
248
|
+
async function getUserList() {
|
|
249
|
+
loading.value = true
|
|
250
|
+
|
|
251
|
+
try {
|
|
252
|
+
const res = await getUserListApi()
|
|
253
|
+
userList.value = res.data
|
|
254
|
+
} finally {
|
|
255
|
+
loading.value = false
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
onMounted(() => {
|
|
260
|
+
getUserList()
|
|
261
|
+
})
|
|
262
|
+
</script>
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## 7. 路由规范
|
|
268
|
+
|
|
269
|
+
### 7.1 路由目录
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
router
|
|
273
|
+
├── index.ts
|
|
274
|
+
└── modules
|
|
275
|
+
├── user.route.ts
|
|
276
|
+
├── order.route.ts
|
|
277
|
+
└── system.route.ts
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### 7.2 路由配置示例
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
import type { RouteRecordRaw } from 'vue-router'
|
|
284
|
+
|
|
285
|
+
const userRoutes: RouteRecordRaw[] = [
|
|
286
|
+
{
|
|
287
|
+
path: '/user',
|
|
288
|
+
name: 'User',
|
|
289
|
+
component: () => import('@/views/user/UserList.vue'),
|
|
290
|
+
meta: {
|
|
291
|
+
title: '用户管理',
|
|
292
|
+
requiresAuth: true,
|
|
293
|
+
permissions: ['user:list']
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
]
|
|
297
|
+
|
|
298
|
+
export default userRoutes
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### 7.3 路由 meta 规范
|
|
302
|
+
|
|
303
|
+
```ts
|
|
304
|
+
meta: {
|
|
305
|
+
title: '页面标题',
|
|
306
|
+
requiresAuth: true,
|
|
307
|
+
keepAlive: false,
|
|
308
|
+
permissions: ['user:list']
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
常用字段说明:
|
|
313
|
+
|
|
314
|
+
| 字段 | 说明 |
|
|
315
|
+
| --- | --- |
|
|
316
|
+
| title | 页面标题 |
|
|
317
|
+
| requiresAuth | 是否需要登录 |
|
|
318
|
+
| keepAlive | 是否缓存页面 |
|
|
319
|
+
| permissions | 页面权限标识 |
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## 8. 状态管理规范
|
|
324
|
+
|
|
325
|
+
### 8.1 Store 文件命名
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
stores/user.store.ts
|
|
329
|
+
stores/app.store.ts
|
|
330
|
+
stores/permission.store.ts
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### 8.2 Pinia 示例
|
|
334
|
+
|
|
335
|
+
```ts
|
|
336
|
+
import { ref } from 'vue'
|
|
337
|
+
import { defineStore } from 'pinia'
|
|
338
|
+
|
|
339
|
+
export const useUserStore = defineStore('user', () => {
|
|
340
|
+
const token = ref('')
|
|
341
|
+
const username = ref('')
|
|
342
|
+
|
|
343
|
+
function setToken(value: string) {
|
|
344
|
+
token.value = value
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function clearUser() {
|
|
348
|
+
token.value = ''
|
|
349
|
+
username.value = ''
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return {
|
|
353
|
+
token,
|
|
354
|
+
username,
|
|
355
|
+
setToken,
|
|
356
|
+
clearUser
|
|
357
|
+
}
|
|
358
|
+
})
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## 9. API 请求规范
|
|
364
|
+
|
|
365
|
+
### 9.1 API 目录结构
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
api
|
|
369
|
+
├── request.ts
|
|
370
|
+
├── user.api.ts
|
|
371
|
+
├── order.api.ts
|
|
372
|
+
└── system.api.ts
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### 9.2 接口命名规范
|
|
376
|
+
|
|
377
|
+
接口函数建议使用动词开头:
|
|
378
|
+
|
|
379
|
+
```ts
|
|
380
|
+
getUserList()
|
|
381
|
+
getUserDetail()
|
|
382
|
+
createUser()
|
|
383
|
+
updateUser()
|
|
384
|
+
deleteUser()
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### 9.3 API 示例
|
|
388
|
+
|
|
389
|
+
```ts
|
|
390
|
+
import request from './request'
|
|
391
|
+
import type { CreateUserDTO, UserListParams } from '@/types/user.type'
|
|
392
|
+
|
|
393
|
+
export function getUserListApi(params: UserListParams) {
|
|
394
|
+
return request.get('/users', { params })
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export function createUserApi(data: CreateUserDTO) {
|
|
398
|
+
return request.post('/users', data)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export function updateUserApi(id: number, data: CreateUserDTO) {
|
|
402
|
+
return request.put(`/users/${id}`, data)
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
export function deleteUserApi(id: number) {
|
|
406
|
+
return request.delete(`/users/${id}`)
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## 10. Axios 封装规范
|
|
413
|
+
|
|
414
|
+
```ts
|
|
415
|
+
import axios from 'axios'
|
|
416
|
+
import type { AxiosError, AxiosResponse } from 'axios'
|
|
417
|
+
|
|
418
|
+
const request = axios.create({
|
|
419
|
+
baseURL: import.meta.env.VITE_API_BASE_URL,
|
|
420
|
+
timeout: 10000
|
|
421
|
+
})
|
|
422
|
+
|
|
423
|
+
request.interceptors.request.use(config => {
|
|
424
|
+
const token = localStorage.getItem('token')
|
|
425
|
+
|
|
426
|
+
if (token) {
|
|
427
|
+
config.headers.Authorization = `Bearer ${token}`
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return config
|
|
431
|
+
})
|
|
432
|
+
|
|
433
|
+
request.interceptors.response.use(
|
|
434
|
+
(response: AxiosResponse) => {
|
|
435
|
+
return response.data
|
|
436
|
+
},
|
|
437
|
+
(error: AxiosError) => {
|
|
438
|
+
return Promise.reject(error)
|
|
439
|
+
}
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
export default request
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## 11. TypeScript 类型规范
|
|
448
|
+
|
|
449
|
+
### 11.1 通用响应类型
|
|
450
|
+
|
|
451
|
+
```ts
|
|
452
|
+
export interface ApiResponse<T = unknown> {
|
|
453
|
+
code: number
|
|
454
|
+
message: string
|
|
455
|
+
data: T
|
|
456
|
+
}
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### 11.2 分页类型
|
|
460
|
+
|
|
461
|
+
```ts
|
|
462
|
+
export interface PageParams {
|
|
463
|
+
page: number
|
|
464
|
+
pageSize: number
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
export interface PageResult<T> {
|
|
468
|
+
list: T[]
|
|
469
|
+
total: number
|
|
470
|
+
page: number
|
|
471
|
+
pageSize: number
|
|
472
|
+
}
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### 11.3 用户类型示例
|
|
476
|
+
|
|
477
|
+
```ts
|
|
478
|
+
export interface UserInfo {
|
|
479
|
+
id: number
|
|
480
|
+
username: string
|
|
481
|
+
nickname: string
|
|
482
|
+
avatar?: string
|
|
483
|
+
status: number
|
|
484
|
+
createdAt: string
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
export interface UserListParams extends PageParams {
|
|
488
|
+
keyword?: string
|
|
489
|
+
status?: number
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
export interface CreateUserDTO {
|
|
493
|
+
username: string
|
|
494
|
+
password: string
|
|
495
|
+
nickname: string
|
|
496
|
+
}
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## 12. 样式规范
|
|
502
|
+
|
|
503
|
+
### 12.1 样式目录
|
|
504
|
+
|
|
505
|
+
```bash
|
|
506
|
+
styles
|
|
507
|
+
├── index.scss
|
|
508
|
+
├── reset.scss
|
|
509
|
+
├── variables.scss
|
|
510
|
+
├── mixin.scss
|
|
511
|
+
└── transition.scss
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
### 12.2 组件样式
|
|
515
|
+
|
|
516
|
+
组件样式默认使用 scoped。
|
|
517
|
+
|
|
518
|
+
```vue
|
|
519
|
+
<style scoped lang="scss">
|
|
520
|
+
.user-card {
|
|
521
|
+
padding: 16px;
|
|
522
|
+
border-radius: 8px;
|
|
523
|
+
background-color: #fff;
|
|
524
|
+
}
|
|
525
|
+
</style>
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### 12.3 CSS 命名规范
|
|
529
|
+
|
|
530
|
+
推荐使用 BEM 命名。
|
|
531
|
+
|
|
532
|
+
```scss
|
|
533
|
+
.user-card {
|
|
534
|
+
&__header {
|
|
535
|
+
display: flex;
|
|
536
|
+
align-items: center;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
&__title {
|
|
540
|
+
font-size: 18px;
|
|
541
|
+
font-weight: 600;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
&--active {
|
|
545
|
+
border-color: #409eff;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
## 13. 环境变量规范
|
|
553
|
+
|
|
554
|
+
### 13.1 文件命名
|
|
555
|
+
|
|
556
|
+
```bash
|
|
557
|
+
.env.development
|
|
558
|
+
.env.test
|
|
559
|
+
.env.production
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
### 13.2 变量命名
|
|
563
|
+
|
|
564
|
+
Vite 项目环境变量必须使用 `VITE_` 前缀。
|
|
565
|
+
|
|
566
|
+
```env
|
|
567
|
+
VITE_APP_TITLE=Vue3后台管理系统
|
|
568
|
+
VITE_API_BASE_URL=https://api.example.com
|
|
569
|
+
VITE_UPLOAD_URL=https://upload.example.com
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
### 13.3 使用方式
|
|
573
|
+
|
|
574
|
+
```ts
|
|
575
|
+
const baseURL = import.meta.env.VITE_API_BASE_URL
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
## 14. 权限规范
|
|
581
|
+
|
|
582
|
+
权限建议分为:
|
|
583
|
+
|
|
584
|
+
- 登录权限
|
|
585
|
+
- 路由权限
|
|
586
|
+
- 菜单权限
|
|
587
|
+
- 按钮权限
|
|
588
|
+
- 接口权限
|
|
589
|
+
|
|
590
|
+
### 14.1 路由权限
|
|
591
|
+
|
|
592
|
+
```ts
|
|
593
|
+
meta: {
|
|
594
|
+
requiresAuth: true,
|
|
595
|
+
permissions: ['user:list']
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### 14.2 按钮权限
|
|
600
|
+
|
|
601
|
+
```vue
|
|
602
|
+
<el-button v-if="hasPermission('user:create')">
|
|
603
|
+
新增用户
|
|
604
|
+
</el-button>
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
## 15. 表单开发规范
|
|
610
|
+
|
|
611
|
+
### 15.1 表单数据
|
|
612
|
+
|
|
613
|
+
```ts
|
|
614
|
+
const formData = reactive({
|
|
615
|
+
username: '',
|
|
616
|
+
password: '',
|
|
617
|
+
status: 1
|
|
618
|
+
})
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### 15.2 表单校验
|
|
622
|
+
|
|
623
|
+
```ts
|
|
624
|
+
const rules = {
|
|
625
|
+
username: [
|
|
626
|
+
{ required: true, message: '请输入用户名', trigger: 'blur' }
|
|
627
|
+
],
|
|
628
|
+
password: [
|
|
629
|
+
{ required: true, message: '请输入密码', trigger: 'blur' }
|
|
630
|
+
]
|
|
631
|
+
}
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### 15.3 提交规范
|
|
635
|
+
|
|
636
|
+
```ts
|
|
637
|
+
async function handleSubmit() {
|
|
638
|
+
try {
|
|
639
|
+
await formRef.value?.validate()
|
|
640
|
+
await createUserApi(formData)
|
|
641
|
+
} catch (error) {
|
|
642
|
+
console.error(error)
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
---
|
|
648
|
+
|
|
649
|
+
## 16. 列表页面规范
|
|
650
|
+
|
|
651
|
+
列表页面通常包含:
|
|
652
|
+
|
|
653
|
+
- 搜索区域
|
|
654
|
+
- 操作按钮区域
|
|
655
|
+
- 表格区域
|
|
656
|
+
- 分页区域
|
|
657
|
+
|
|
658
|
+
推荐状态命名:
|
|
659
|
+
|
|
660
|
+
```ts
|
|
661
|
+
const loading = ref(false)
|
|
662
|
+
const tableData = ref([])
|
|
663
|
+
const total = ref(0)
|
|
664
|
+
const queryParams = reactive({
|
|
665
|
+
page: 1,
|
|
666
|
+
pageSize: 10,
|
|
667
|
+
keyword: ''
|
|
668
|
+
})
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
---
|
|
672
|
+
|
|
673
|
+
## 17. 工具函数规范
|
|
674
|
+
|
|
675
|
+
工具函数必须保持职责单一。
|
|
676
|
+
|
|
677
|
+
```ts
|
|
678
|
+
export function formatDate(date: string | Date): string {
|
|
679
|
+
const d = new Date(date)
|
|
680
|
+
return d.toLocaleDateString()
|
|
681
|
+
}
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
不建议一个工具函数同时处理多个不相关功能。
|
|
685
|
+
|
|
686
|
+
---
|
|
687
|
+
|
|
688
|
+
## 18. 常量规范
|
|
689
|
+
|
|
690
|
+
常量统一放在 `constants` 目录。
|
|
691
|
+
|
|
692
|
+
```ts
|
|
693
|
+
export const USER_STATUS = {
|
|
694
|
+
ENABLED: 1,
|
|
695
|
+
DISABLED: 0
|
|
696
|
+
} as const
|
|
697
|
+
|
|
698
|
+
export const USER_STATUS_TEXT = {
|
|
699
|
+
[USER_STATUS.ENABLED]: '启用',
|
|
700
|
+
[USER_STATUS.DISABLED]: '禁用'
|
|
701
|
+
}
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
---
|
|
705
|
+
|
|
706
|
+
## 19. 代码提交规范
|
|
707
|
+
|
|
708
|
+
推荐使用 Conventional Commits。
|
|
709
|
+
|
|
710
|
+
```bash
|
|
711
|
+
feat: 新增用户管理页面
|
|
712
|
+
fix: 修复登录状态失效问题
|
|
713
|
+
docs: 更新项目开发文档
|
|
714
|
+
style: 调整页面样式
|
|
715
|
+
refactor: 重构接口请求封装
|
|
716
|
+
perf: 优化列表加载性能
|
|
717
|
+
test: 新增单元测试
|
|
718
|
+
chore: 修改构建配置
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
提交类型说明:
|
|
722
|
+
|
|
723
|
+
| 类型 | 说明 |
|
|
724
|
+
| --- | --- |
|
|
725
|
+
| feat | 新功能 |
|
|
726
|
+
| fix | 修复问题 |
|
|
727
|
+
| docs | 文档修改 |
|
|
728
|
+
| style | 样式或格式调整 |
|
|
729
|
+
| refactor | 代码重构 |
|
|
730
|
+
| perf | 性能优化 |
|
|
731
|
+
| test | 测试相关 |
|
|
732
|
+
| chore | 构建或工具配置 |
|
|
733
|
+
|
|
734
|
+
---
|
|
735
|
+
|
|
736
|
+
## 20. ESLint 与 Prettier 规范
|
|
737
|
+
|
|
738
|
+
### 20.1 Prettier 配置
|
|
739
|
+
|
|
740
|
+
```json
|
|
741
|
+
{
|
|
742
|
+
"semi": false,
|
|
743
|
+
"singleQuote": true,
|
|
744
|
+
"printWidth": 100,
|
|
745
|
+
"trailingComma": "none"
|
|
746
|
+
}
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
### 20.2 ESLint 规则示例
|
|
750
|
+
|
|
751
|
+
```js
|
|
752
|
+
export default [
|
|
753
|
+
{
|
|
754
|
+
rules: {
|
|
755
|
+
'vue/multi-word-component-names': 'off',
|
|
756
|
+
'no-console': 'warn',
|
|
757
|
+
'no-debugger': 'warn'
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
]
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
---
|
|
764
|
+
|
|
765
|
+
## 21. 性能优化规范
|
|
766
|
+
|
|
767
|
+
### 21.1 路由懒加载
|
|
768
|
+
|
|
769
|
+
```ts
|
|
770
|
+
component: () => import('@/views/user/UserList.vue')
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
### 21.2 组件按需加载
|
|
774
|
+
|
|
775
|
+
大型组件、弹窗、图表组件建议按需加载。
|
|
776
|
+
|
|
777
|
+
### 21.3 避免不必要的响应式
|
|
778
|
+
|
|
779
|
+
大数据列表可以使用 `shallowRef`。
|
|
780
|
+
|
|
781
|
+
```ts
|
|
782
|
+
const list = shallowRef([])
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
### 21.4 图片优化
|
|
786
|
+
|
|
787
|
+
- 图片压缩后再上传
|
|
788
|
+
- 小图标优先使用 SVG
|
|
789
|
+
- 大图使用懒加载
|
|
790
|
+
- 静态资源放入 CDN
|
|
791
|
+
|
|
792
|
+
---
|
|
793
|
+
|
|
794
|
+
## 22. 安全规范
|
|
795
|
+
|
|
796
|
+
- 不在前端代码中写死密钥
|
|
797
|
+
- 不在仓库中提交 `.env.production`
|
|
798
|
+
- 接口请求必须携带必要鉴权信息
|
|
799
|
+
- 用户输入内容需要校验
|
|
800
|
+
- 富文本内容需要防止 XSS
|
|
801
|
+
- 文件上传需要限制类型和大小
|
|
802
|
+
|
|
803
|
+
---
|
|
804
|
+
|
|
805
|
+
## 23. 开发注意事项
|
|
806
|
+
|
|
807
|
+
- 组件不要过大,复杂页面要拆分组件
|
|
808
|
+
- 接口请求统一放到 `api` 目录
|
|
809
|
+
- 公共逻辑抽离到 `composables` 或 `hooks`
|
|
810
|
+
- 不要直接操作 DOM,优先使用 Vue 响应式能力
|
|
811
|
+
- 列表渲染必须添加唯一 `key`
|
|
812
|
+
- 异步请求必须处理 loading 状态
|
|
813
|
+
- 删除、提交、重置等危险操作需要二次确认
|
|
814
|
+
- 禁止在组件中硬编码接口地址
|
|
815
|
+
- 禁止将大量业务逻辑写在模板中
|
|
816
|
+
|
|
817
|
+
---
|
|
818
|
+
|
|
819
|
+
## 24. 推荐 package.json scripts
|
|
820
|
+
|
|
821
|
+
```json
|
|
822
|
+
{
|
|
823
|
+
"scripts": {
|
|
824
|
+
"dev": "vite",
|
|
825
|
+
"build": "vue-tsc -b && vite build",
|
|
826
|
+
"preview": "vite preview",
|
|
827
|
+
"lint": "eslint .",
|
|
828
|
+
"format": "prettier --write src"
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
---
|
|
834
|
+
|
|
835
|
+
## 25. 项目启动流程
|
|
836
|
+
|
|
837
|
+
```bash
|
|
838
|
+
pnpm install
|
|
839
|
+
pnpm dev
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
生产构建:
|
|
843
|
+
|
|
844
|
+
```bash
|
|
845
|
+
pnpm build
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
本地预览:
|
|
849
|
+
|
|
850
|
+
```bash
|
|
851
|
+
pnpm preview
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
---
|
|
855
|
+
|
|
856
|
+
## 26. 总结
|
|
857
|
+
|
|
858
|
+
Vue3 项目开发应重点关注以下几点:
|
|
859
|
+
|
|
860
|
+
- 目录结构清晰
|
|
861
|
+
- 命名风格统一
|
|
862
|
+
- 组件职责单一
|
|
863
|
+
- 类型定义完善
|
|
864
|
+
- 接口统一封装
|
|
865
|
+
- 状态管理规范
|
|
866
|
+
- 样式风格一致
|
|
867
|
+
- 权限设计清晰
|
|
868
|
+
- Git 提交规范
|
|
869
|
+
- 构建部署流程稳定
|
|
870
|
+
|
|
871
|
+
良好的开发规范可以提升团队协作效率,降低维护成本,并让项目在长期迭代中保持稳定和可扩展。
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!-- 500页面 -->
|
|
2
|
+
<template>
|
|
3
|
+
<ArtException
|
|
4
|
+
:data="{
|
|
5
|
+
title: '500',
|
|
6
|
+
desc: $t('exceptionPage.500'),
|
|
7
|
+
btnText: $t('exceptionPage.gohome'),
|
|
8
|
+
imgUrl
|
|
9
|
+
}"
|
|
10
|
+
/>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script setup lang="ts">
|
|
14
|
+
import imgUrl from '@imgs/svg/500.svg'
|
|
15
|
+
defineOptions({ name: 'Exception500' })
|
|
16
|
+
</script>
|