jsharness 1.0.0
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/.harness/README.md +199 -0
- package/.harness/agents/code-reviewer/contract.yaml +64 -0
- package/.harness/agents/developer/contract.yaml +72 -0
- package/.harness/agents/gate-controller/contract.yaml +64 -0
- package/.harness/agents/project-manager/contract.yaml +77 -0
- package/.harness/agents/prompt-templates.md +352 -0
- package/.harness/agents/requirements-analyst/contract.yaml +64 -0
- package/.harness/agents/solution-designer/contract.yaml +75 -0
- package/.harness/agents/tester/contract.yaml +92 -0
- package/.harness/config/models.yaml +67 -0
- package/.harness/dev-map/backend/api-definition.md +131 -0
- package/.harness/dev-map/backend/auth-security.md +131 -0
- package/.harness/dev-map/backend/conventions-java.md +471 -0
- package/.harness/dev-map/backend/conventions.md +192 -0
- package/.harness/dev-map/backend/database.md +106 -0
- package/.harness/dev-map/backend/structure.md +140 -0
- package/.harness/dev-map/decisions.md +275 -0
- package/.harness/dev-map/frontend/api-integration.md +139 -0
- package/.harness/dev-map/frontend/components.md +178 -0
- package/.harness/dev-map/frontend/conventions.md +416 -0
- package/.harness/dev-map/frontend/state-management.md +170 -0
- package/.harness/dev-map/frontend/structure.md +103 -0
- package/.harness/dev-map/overview.md +267 -0
- package/.harness/docs/integration-test-plan.md +248 -0
- package/.harness/docs/team-guidelines/README.md +161 -0
- package/.harness/docs/team-guidelines/arch-team.md +811 -0
- package/.harness/docs/team-guidelines/collaboration.md +556 -0
- package/.harness/docs/team-guidelines/pm-team.md +337 -0
- package/.harness/docs/team-guidelines/qa-team.md +562 -0
- package/.harness/docs/team-guidelines/rd-team.md +714 -0
- package/.harness/docs/training-materials.md +280 -0
- package/.harness/gate/baseline.js +220 -0
- package/.harness/gate/checks/build-gates-frontend.js +152 -0
- package/.harness/gate/checks/build-gates-java.js +155 -0
- package/.harness/gate/checks/build-gates.js +119 -0
- package/.harness/gate/checks/engineering-consistency.js +138 -0
- package/.harness/gate/checks/security-quality.js +129 -0
- package/.harness/gate/checks/static-compliance.js +313 -0
- package/.harness/gate/checks/test-compliance.js +114 -0
- package/.harness/gate/index.js +315 -0
- package/.harness/mcp/config.yaml +435 -0
- package/.harness/rules/global/coding-standard.md +232 -0
- package/.harness/rules/global/commit-convention.md +165 -0
- package/.harness/rules/global/process-discipline.md +192 -0
- package/.harness/rules/global/security-baseline.md +306 -0
- package/.harness/rules/project/frontend-vue3.md +293 -0
- package/.harness/rules/project/java-backend.md +460 -0
- package/.harness/rules/project/web-specific.md +231 -0
- package/.harness/skills/build.md +192 -0
- package/.harness/skills/code-review.md +251 -0
- package/.harness/skills/docker-build.md +227 -0
- package/.harness/skills/docs-update.md +164 -0
- package/.harness/skills/java-build.md +261 -0
- package/.harness/skills/lint-check.md +482 -0
- package/.harness/skills/task-board-maintenance.md +105 -0
- package/.harness/skills/test-api.md +461 -0
- package/.harness/skills/test-e2e.md +431 -0
- package/.harness/skills/test-unit.md +649 -0
- package/.harness/skills/vue-frontend-build.md +344 -0
- package/.harness/specs/quality-feedback/implementation-guide.md +350 -0
- package/.harness/task-board.md +121 -0
- package/.harness/workflow/definition.yaml +504 -0
- package/.harness/workflow/validate.js +320 -0
- package/.harness/workflow/variants.yaml +253 -0
- package/README.md +237 -0
- package/bin/jsharness.js +53 -0
- package/lib/index.mjs +778 -0
- package/package.json +1 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# Vue3 + TypeScript 前端编码规范 (frontend-vue3)
|
|
2
|
+
|
|
3
|
+
> **级别**: 项目级强制 | **适用范围**: 前端 Vue3 项目
|
|
4
|
+
> **来源**: `files/frontend-project-conventions/SKILL.md` (v1.0.0)
|
|
5
|
+
> **归档日期**: 2026-05-21
|
|
6
|
+
> **技术栈**: Vue 3 + TypeScript + Vite + Pinia + Vue Router + Element Plus
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1. Composition API 强制使用
|
|
11
|
+
|
|
12
|
+
所有 Vue 组件 **必须** 使用 `<script setup>` 语法的 Composition API。
|
|
13
|
+
|
|
14
|
+
| 规则 | 要求 | 违规后果 |
|
|
15
|
+
|------|------|----------|
|
|
16
|
+
| 组件语法 | 必须使用 `<script setup lang="ts">` | Code Review FAIL |
|
|
17
|
+
| 禁止 Options API | 禁止出现 `export default { data(), methods(), mounted() }` | Code Review FAIL |
|
|
18
|
+
| 禁止 this 关键字 | 生成的代码中不得出现 `this.` | Code Review WARNING |
|
|
19
|
+
|
|
20
|
+
**正确示例**:
|
|
21
|
+
```vue
|
|
22
|
+
<script setup lang="ts">
|
|
23
|
+
import { ref, computed, onMounted } from 'vue';
|
|
24
|
+
|
|
25
|
+
interface Props {
|
|
26
|
+
userId: string;
|
|
27
|
+
userName?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
31
|
+
userName: '',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const isLoading = ref(false);
|
|
35
|
+
const userInfo = ref<UserInfo | null>(null);
|
|
36
|
+
|
|
37
|
+
const displayName = computed(() => props.userName || '匿名用户');
|
|
38
|
+
|
|
39
|
+
onMounted(() => {
|
|
40
|
+
fetchUserInfo();
|
|
41
|
+
});
|
|
42
|
+
</script>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 2. TypeScript 类型安全约束
|
|
48
|
+
|
|
49
|
+
| 规则 | 要求 | 违规后果 |
|
|
50
|
+
|------|------|----------|
|
|
51
|
+
| Props 定义 | 必须使用 TS `interface` 或 `defineProps<T>()` 泛型 | Code Review WARNING |
|
|
52
|
+
| 禁止裸 any | 禁止无注释说明的 `any` 类型 | Code Review WARNING |
|
|
53
|
+
| Pinia 类型 | State 字段必须有明确类型,Getters/Actions 参数和返回值必须标注类型 | Code Review WARNING |
|
|
54
|
+
|
|
55
|
+
**类型定义规范**:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// ✅ 正确:Props 使用 interface
|
|
59
|
+
interface UserProfileProps {
|
|
60
|
+
id: string;
|
|
61
|
+
name: string;
|
|
62
|
+
avatar?: string;
|
|
63
|
+
onUpdate?: (id: string) => void;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const props = defineProps<UserProfileProps>();
|
|
67
|
+
|
|
68
|
+
// ✅ 正确:Emits 使用类型
|
|
69
|
+
const emit = defineEmits<{
|
|
70
|
+
update: [id: string];
|
|
71
|
+
delete: [id: string];
|
|
72
|
+
}>();
|
|
73
|
+
|
|
74
|
+
// ⚠️ 允许但有条件:必须注释说明 why
|
|
75
|
+
const legacyData: any = parseLegacyFormat(raw); // Legacy API, 待重构
|
|
76
|
+
|
|
77
|
+
// ❌ 错误:禁止裸 any
|
|
78
|
+
const data: any = fetchData();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 3. 文件命名与目录结构
|
|
84
|
+
|
|
85
|
+
### 3.1 命名约定
|
|
86
|
+
|
|
87
|
+
| 类型 | 格式 | 示例 |
|
|
88
|
+
|------|------|------|
|
|
89
|
+
| Vue 组件文件 | PascalCase | `UserProfile.vue` |
|
|
90
|
+
| 目录名 | kebab-case | `user-profile/` |
|
|
91
|
+
| 工具函数文件 | camelCase | `formatDate.ts` |
|
|
92
|
+
| 类型定义文件 | camelCase + types | `user.types.ts` |
|
|
93
|
+
| 常量文件 | UPPER_SNAKE_CASE | `API_ENDPOINTS.ts` |
|
|
94
|
+
| Hook 文件 | use + PascalCase | `useUserProfile.ts` |
|
|
95
|
+
|
|
96
|
+
### 3.2 标准目录结构
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
src/
|
|
100
|
+
├── api/ # API 接口封装(axios 实例、拦截器、类型定义)
|
|
101
|
+
├── assets/ # 静态资源(全局样式、图片、字体)
|
|
102
|
+
├── components/ # 可复用组件
|
|
103
|
+
│ ├── ui/ # 通用 UI 组件(Button、Modal 等)
|
|
104
|
+
│ └── business/ # 业务组件
|
|
105
|
+
├── pages/ # 页面级组件(路由对应)
|
|
106
|
+
├── router/ # 路由配置(路由定义、守卫、菜单结构)
|
|
107
|
+
├── store/ # Pinia Store(按模块拆分)
|
|
108
|
+
│ ├── modules/ # 各业务模块 store
|
|
109
|
+
│ └── index.ts # Store 入口
|
|
110
|
+
├── types/ # 全局 TypeScript 类型定义
|
|
111
|
+
├── utils/ # 工具函数
|
|
112
|
+
└── composables/ # 组合式函数(Vue3 Hooks)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 4. 变量命名约定
|
|
118
|
+
|
|
119
|
+
| 标识符类型 | 规范 | 示例 |
|
|
120
|
+
|-----------|------|------|
|
|
121
|
+
| 普通变量/函数 | camelCase | `userName`, `fetchUserData` |
|
|
122
|
+
| 常量/配置项 | UPPER_SNAKE_CASE | `API_BASE_URL`, `MAX_RETRY_COUNT` |
|
|
123
|
+
| 布尔变量 | `is`/`has`/`can`/`should`/`will` 前缀 | `isLoading`, `hasPermission`, `canEdit` |
|
|
124
|
+
| 事件处理函数 | `handle` 前缀 | `handleSubmit`, `handleClick`, `handleChange` |
|
|
125
|
+
| 计算属性 | 形容词/名词短语 | `displayName`, `filteredItems` |
|
|
126
|
+
| Store action | 动词短语 | `fetchUsers`, `createOrder`, `toggleSidebar` |
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
// ✅ 正确示例
|
|
130
|
+
const isLoading = ref(false);
|
|
131
|
+
const hasPermission = computed(() => user.role === 'admin');
|
|
132
|
+
const MAX_RETRY_COUNT = 3;
|
|
133
|
+
const handleClick = () => { /* ... */ };
|
|
134
|
+
const handleSubmit = async () => { /* ... */ };
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 5. Element Plus 组件使用规范
|
|
140
|
+
|
|
141
|
+
| 场景 | 要求 | 说明 |
|
|
142
|
+
|------|------|------|
|
|
143
|
+
| 消息提示 | 使用 `ElMessage.success/warning/error/info` | 轻量反馈,自动消失 |
|
|
144
|
+
| 确认操作 | 使用 `ElMessageBox.confirm` | 删除/提交等需二次确认的操作 |
|
|
145
|
+
| 加载状态 | 使用 `v-loading` 指令 | 禁止手动控制 loading 变量实现 |
|
|
146
|
+
| 图标使用 | 图标组件包裹在容器标签中 | 避免直接暴露图标组件 |
|
|
147
|
+
| 表单校验 | 使用 ElForm + rules | 统一校验逻辑和提示样式 |
|
|
148
|
+
| 数据表格 | 使用 el-table + 分页组件 | 配合 Pagination 组件使用 |
|
|
149
|
+
|
|
150
|
+
**标准用法示例**:
|
|
151
|
+
```vue
|
|
152
|
+
<template>
|
|
153
|
+
<!-- 加载状态 -->
|
|
154
|
+
<div v-loading="isLoading">
|
|
155
|
+
<el-table :data="tableData" border>
|
|
156
|
+
<el-table-column prop="name" label="名称" />
|
|
157
|
+
<el-table-column prop="status" label="状态" />
|
|
158
|
+
</el-table>
|
|
159
|
+
<el-pagination
|
|
160
|
+
:current-page="pagination.page"
|
|
161
|
+
:page-size="pagination.pageSize"
|
|
162
|
+
:total="pagination.total"
|
|
163
|
+
@current-change="handlePageChange"
|
|
164
|
+
/>
|
|
165
|
+
</div>
|
|
166
|
+
</template>
|
|
167
|
+
|
|
168
|
+
<script setup lang="ts">
|
|
169
|
+
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
170
|
+
|
|
171
|
+
const handleDelete = async (row: TableRow) => {
|
|
172
|
+
try {
|
|
173
|
+
await ElMessageBox.confirm('确定要删除该记录吗?', '提示', {
|
|
174
|
+
confirmButtonText: '确定',
|
|
175
|
+
cancelButtonText: '取消',
|
|
176
|
+
type: 'warning',
|
|
177
|
+
});
|
|
178
|
+
await deleteRecord(row.id);
|
|
179
|
+
ElMessage.success('删除成功');
|
|
180
|
+
} catch {
|
|
181
|
+
// 用户取消操作
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
</script>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## 6. 响应式数据管理规范
|
|
190
|
+
|
|
191
|
+
### 6.1 分层原则
|
|
192
|
+
|
|
193
|
+
| 数据范围 | 管理方式 | 示例 |
|
|
194
|
+
|---------|----------|------|
|
|
195
|
+
| 组件内部局部状态 | `ref()` / `reactive()` | 表单输入、弹窗开关 |
|
|
196
|
+
| 跨组件共享状态 | Pinia Store | 用户信息、权限列表 |
|
|
197
|
+
| 服务端状态缓存 | Pinia Plugin / `keepAlive` | 列表数据缓存 |
|
|
198
|
+
|
|
199
|
+
### 6.2 禁止事项
|
|
200
|
+
|
|
201
|
+
| 行为 | 原因 | 替代方案 |
|
|
202
|
+
|------|------|----------|
|
|
203
|
+
| prop drilling 超过两层 | 维护困难 | 使用 Pinia Store |
|
|
204
|
+
| event bus 方式通信 | Vue3 已移除 `$on`/`$off` | 使用 Pinia 或 provide/inject |
|
|
205
|
+
| 直接修改 props | 单向数据流破坏 | emit 事件或 computed |
|
|
206
|
+
|
|
207
|
+
### 6.3 Pinia Store 组织规范
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
// stores/modules/user.ts
|
|
211
|
+
import { defineStore } from 'pinia';
|
|
212
|
+
import type { UserInfo } from '@/types/user';
|
|
213
|
+
|
|
214
|
+
export const useUserStore = defineStore('user', {
|
|
215
|
+
state: (): UserState => ({
|
|
216
|
+
userInfo: null,
|
|
217
|
+
token: '',
|
|
218
|
+
permissions: [],
|
|
219
|
+
}),
|
|
220
|
+
|
|
221
|
+
getters: {
|
|
222
|
+
isLoggedIn: (state): boolean => !!state.token,
|
|
223
|
+
isAdmin: (state): boolean => state.permissions.includes('admin'),
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
actions: {
|
|
227
|
+
async login(credentials: LoginCredentials) {
|
|
228
|
+
// ...
|
|
229
|
+
},
|
|
230
|
+
logout() {
|
|
231
|
+
// ...
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## 7. 注释和文档规范
|
|
240
|
+
|
|
241
|
+
### 7.1 JSDoc 标准
|
|
242
|
+
|
|
243
|
+
**组件级注释** — 文件顶部必须包含:
|
|
244
|
+
```typescript
|
|
245
|
+
/**
|
|
246
|
+
* UserProfile.vue — 用户信息展示卡片
|
|
247
|
+
*
|
|
248
|
+
* @description 展示用户基本信息,支持编辑和删除操作
|
|
249
|
+
* @props id (string) - 用户唯一标识
|
|
250
|
+
* @props name (string, optional) - 用户显示名
|
|
251
|
+
* @emits update - 编辑时触发,参数为用户 ID
|
|
252
|
+
* @emits delete - 删除确认后触发,参数为用户 ID
|
|
253
|
+
* @author frontend-team
|
|
254
|
+
*/
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**函数级注释**:
|
|
258
|
+
```typescript
|
|
259
|
+
/**
|
|
260
|
+
* 根据用户 ID 批量获取用户详情
|
|
261
|
+
*
|
|
262
|
+
* @param ids - 用户 ID 数组
|
|
263
|
+
* @returns Promise<UserInfo[]> 用户信息数组,不存在的 ID 对应位置为 null
|
|
264
|
+
* @throws {NetworkError} 当网络请求失败时抛出
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* const users = await batchGetUserIds(['id1', 'id2']);
|
|
268
|
+
*/
|
|
269
|
+
async function batchGetUserIds(ids: string[]): Promise<(UserInfo | null)[]> {
|
|
270
|
+
// ...
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### 7.2 注释要求
|
|
275
|
+
|
|
276
|
+
- 所有公开 API 必须有 JSDoc
|
|
277
|
+
- 复杂逻辑必须有行内注释解释「**为什么**」而非「是什么」
|
|
278
|
+
- TODO/FIXME 必须附带场景说明:`// TODO: [场景描述] - 待[具体动作]`
|
|
279
|
+
- 注释与代码必须同步更新
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## 8. 禁止事项清单
|
|
284
|
+
|
|
285
|
+
| # | 禁止行为 | 触发条件 | 后果 |
|
|
286
|
+
|---|---------|---------|------|
|
|
287
|
+
| FV-01 | Options API | 出现 `data()`, `methods()`, `mounted()` 等 Options API 写法 | **Code Review FAIL** |
|
|
288
|
+
| FV-02 | 裸 any 类型 | `const x: any` 无注释说明原因 | **Code Review WARNING** |
|
|
289
|
+
| FV-03 | 直接操作 DOM | 使用 `document.getElementById` 等 DOM 操作 | **Code Review FAIL** |
|
|
290
|
+
| FV-04 | jQuery 引入 | package.json 中出现 jquery 依赖 | **Gate BLOCK** |
|
|
291
|
+
| FV-05 | 内联样式字符串 | `style="color: red"` 非绑定形式(动态计算值除外) | **Lint ERROR** |
|
|
292
|
+
| FV-06 | console.log 残留 | 生产代码中出现 console.log/debugger | **Gate A 类 WARNING** |
|
|
293
|
+
| FV-07 | 魔法数字 | 无命名常量的数字字面量(除 0/1/-1) | **Code Review WARNING** |
|