## 问题概览 - 缺失模块:`@/mock/temp/commentDetail` 导致 TS2307(src/components/business/comment-widget/index.vue:46)。 - 事件类型不匹配:`emit('search', ...)` 未在 `defineEmits` 中声明载荷(activity-search、player-search)。 - 缺少类型声明:`crypto-js/md5` 导致 TS7016(login)。 - 返回类型不一致:登录接口不含 `refreshToken` 导致 TS2339(login)。 - 表格数据类型为 `unknown[]` 与组件期望 `Record[]` 不匹配(guild、banner、product)。 ## 修复方案(不改接口协议,最小改动) - 缺失模块补齐:新增 `web/admin/src/mock/temp/commentDetail.ts`,导出 `Comment` 类型与 `commentList: Ref`。 - 使 `src/components/business/comment-widget/index.vue:46` 的导入可解析。 - 事件类型声明完善:在以下文件的 `defineEmits` 中为 `search` 声明载荷类型 `Props['modelValue']`: - `src/views/activity/manage/modules/activity-search.vue:93-101,148-151` - `src/views/player-manage/modules/player-search.vue:82-90,136-139` - 为 `crypto-js/md5` 提供类型:新增 `web/admin/src/types/shims-crypto-js.d.ts` 内容:`declare module 'crypto-js/md5';` - 保证 `src/views/auth/login/index.vue:117` 类型可解析。 - 登录返回类型与使用一致化:修改登录页不解构 `refreshToken`,仅解构 `token` 并调用 `userStore.setToken(token)`: - `src/views/auth/login/index.vue:223-236`;当前后端返回结构为 `{ token, is_super }`(参考后端 `internal/service/admin/login.go:22-25,62-63` 与前端 `src/api/auth.ts:8-14`)。 - 表格数据类型注解:在各视图的 `apiFn` 显式标注返回类型为 `Promise>`,使 `useTable` 能推导出 `TRecord`,从而 `data` 类型为记录数组: - Guild 列表:`src/views/guild/manage/index.vue:137-173`,返回 `PaginatedResponse<{ id; name; owner_id; ... }>`。 - Banner 列表:`src/views/operations/banner/index.vue:77-98`,返回 `PaginatedResponse`(`src/api/banner.ts:3-10`)。 - Product 分类:`src/views/product/categories/index.vue:80-102`,返回 `PaginatedResponse<{ id; name; parent_id; status }>`。 - Product 列表:`src/views/product/list/index.vue`(同样模式)。 - 若不方便标注,临时方案:在模板传参处显式断言 `:data="data as Record[]"`(不推荐,先按注解方案处理)。 ## 具体改动明细 - 新增 `src/mock/temp/commentDetail.ts`: - 导出 `export interface Comment { id:number; author:string; content:string; timestamp:string; replies: Comment[] }` - `export const commentList = ref([])`(保持与组件 `comments.value.push(...)` 一致)。 - 更新事件声明: - `activity-search.vue` `defineEmits()` 中将 `(e: 'search'): void` 改为 `(e: 'search', value: Props['modelValue']): void`。 - `player-search.vue` 同步调整。 - 新增类型声明文件:`src/types/shims-crypto-js.d.ts` 写入 `declare module 'crypto-js/md5';`。 - 登录页使用调整: - 改为 `const { token } = await fetchLogin(...)`,并调用 `userStore.setToken(token)`。 - useTable 返回类型注解:在上述 4 个视图 `apiFn` 的返回 `then` 中显式声明返回值类型为 `Api.Common.PaginatedResponse<...>`。 ## 验证步骤 - 安装依赖后(若需要):`npm i --save-dev @types/crypto-js`(可省略,因已加 shims)。 - 执行 `npm run build`,expect:无 TS 错误;资源正常打包。 - 运行本地:`npm run dev`,检查各页面: - 评论组件能正常发布与回复。 - 搜索模块能正常触发,父组件收到带载荷的 `search` 事件。 - 登录页能正常登录并存储 `token`。 - Guild、Banner、Product 列表渲染正常,分页操作无类型报错。 ## 影响面与风险 - 均为类型与前端视图层改动,不涉及后端接口或数据结构变更。 - `crypto-js` 类型通过 shims 解决,不强依赖 `@types` 包。 - `useTable` 类型注解只提升类型推导,不改变运行时行为。 ## 后续优化建议 - 统一在 `api/*` 层将后端分页响应封装为 `Api.Common.PaginatedResponse`,视图层的 `apiFn` 直接返回该类型,减少重复 `then` 转换与类型注解。 - 为常见搜索子组件抽取 `Emits` 模板,避免事件签名遗漏。