初始化
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
# 参考模板
|
||||
|
||||
## 1) Service 方法模板
|
||||
|
||||
```ts
|
||||
import request from '@/utils/request';
|
||||
|
||||
export interface QueryListParams {
|
||||
pageNumber: number;
|
||||
pageSize: number;
|
||||
mediaId?: string;
|
||||
}
|
||||
|
||||
export interface QueryListResp {
|
||||
list: Array<{
|
||||
id: string;
|
||||
title: string;
|
||||
}>;
|
||||
total: number;
|
||||
}
|
||||
|
||||
export default class ExampleApi {
|
||||
static queryList(params: QueryListParams): Promise<QueryListResp> {
|
||||
return request.get('/example/list', params);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 2) Hook 模板(单一职责)
|
||||
|
||||
```ts
|
||||
import { reactive } from 'vue';
|
||||
import ExampleApi, { QueryListParams } from '@/service/example';
|
||||
|
||||
export function useExampleList(initialParams: QueryListParams) {
|
||||
const state = reactive({
|
||||
loading: false,
|
||||
error: false,
|
||||
list: [] as Array<{ id: string; title: string }>,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const fetchList = async (params = initialParams) => {
|
||||
state.loading = true;
|
||||
state.error = false;
|
||||
|
||||
try {
|
||||
const res = await ExampleApi.queryList(params);
|
||||
state.list = res.list || [];
|
||||
state.total = Number(res.total || 0);
|
||||
} catch (err) {
|
||||
state.error = true;
|
||||
state.list = [];
|
||||
state.total = 0;
|
||||
} finally {
|
||||
state.loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
state,
|
||||
fetchList,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## 3) 容器页模板(Container View)
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useExampleList } from './hooks/useExampleList';
|
||||
|
||||
const route = useRoute();
|
||||
const mediaId = computed(() => String(route.query.id || ''));
|
||||
|
||||
const { state, fetchList } = useExampleList({
|
||||
pageNumber: 1,
|
||||
pageSize: 30,
|
||||
mediaId: mediaId.value,
|
||||
});
|
||||
|
||||
fetchList();
|
||||
</script>
|
||||
```
|
||||
|
||||
## 4) 错误处理最低检查项
|
||||
|
||||
- 每个异步动作都具备成对的 loading 开关。
|
||||
- 请求失败时会落到确定性兜底状态。
|
||||
- 接口细节与类型由 service 层承载。
|
||||
- UI 层能展示空态/错误态,不允许静默失败。
|
||||
|
||||
## 5) 旧代码 any 的渐进迁移模式
|
||||
|
||||
```ts
|
||||
// 改造前
|
||||
// static getMediaHot(data: any) {
|
||||
// return request.get('/media/hot', data);
|
||||
// }
|
||||
|
||||
// 改造后(增量迁移)
|
||||
export interface GetMediaHotParams {
|
||||
pageNumber: number;
|
||||
pageSize: number;
|
||||
moduleId?: string;
|
||||
}
|
||||
|
||||
export interface GetMediaHotResp {
|
||||
list: Types.Acg.MediaContentListItem[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
static getMediaHot(data: GetMediaHotParams): Promise<GetMediaHotResp> {
|
||||
return request.get('/media/hot', data);
|
||||
}
|
||||
```
|
||||
|
||||
## 6) PR 自检输出模板
|
||||
|
||||
在实现说明中必须附上以下区块(与 `SKILL.md` 保持一致):
|
||||
|
||||
```markdown
|
||||
### 自检结果
|
||||
- [x] view/hook 层没有直接请求调用
|
||||
- [x] service 边界方法具备明确类型
|
||||
- [x] 未新增宽泛 any
|
||||
- [x] 异步失败分支具备兜底状态
|
||||
- [x] 混杂职责已拆分为聚焦 hooks/components
|
||||
```
|
||||
|
||||
## 7) 轻量自动校验命令(可执行)
|
||||
|
||||
在仓库根目录执行以下命令进行快速自检:
|
||||
|
||||
```bash
|
||||
# 1) 优先检查本次改动的 view/hook 文件是否直接调用 request
|
||||
rg "request\\.(get|post|put|delete|deletes)\\(" <changed-view-or-hook-files>
|
||||
|
||||
# 2) 检查本次改动文件是否引入 any(人工结合 diff 判断)
|
||||
rg "\\bany\\b" <changed-files>
|
||||
```
|
||||
|
||||
判定规则:
|
||||
- 命令 1 预期为“无结果”;有结果则说明可能绕过 service。
|
||||
- 命令 2 不要求仓库清零,但本次改动不应新增宽泛 `any`。
|
||||
- 只有在做全仓治理或用户明确要求时,才扩展到 `src/views src/hooks src/service` 全量扫描。
|
||||
Reference in New Issue
Block a user