From d760838e71af2193b544cb9a04d4b19f02d9cc53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E8=87=AA=E8=BE=BE?= <980324341@qq.com> Date: Sat, 5 Sep 2026 14:31:32 +0800 Subject: [PATCH] =?UTF-8?q?task-42(=E8=B4=A6=E5=8F=B7/=E6=9D=83=E9=99=90?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2):=20=E5=AE=9E=E7=8E=B0=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=9F=A5=E8=AF=A2=E9=80=82=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 users-model.ts 纯解析(Java AdminUserItemVo snake_case→camelCase、 缺 id 行过滤、分页字段归一、success=false 抛后端 message)与 users.ts adapter(fetchUserList:normalize+GET /api/admin/users+parse);UsersPage 改用 adapter,去掉模板内联 http.get+unwrap。task-41 依赖断言改指数据层。 8 用例全过,299 单测 + build 绿。 --- admin-frontend-vue/src/api/users-model.ts | 54 +++++++++++ admin-frontend-vue/src/api/users.ts | 15 +++ .../src/pages/account/UsersPage.vue | 12 +-- admin-frontend-vue/tests/task-41.test.ts | 8 +- admin-frontend-vue/tests/task-42.test.ts | 91 +++++++++++++++++++ 5 files changed, 170 insertions(+), 10 deletions(-) create mode 100644 admin-frontend-vue/src/api/users-model.ts create mode 100644 admin-frontend-vue/src/api/users.ts create mode 100644 admin-frontend-vue/tests/task-42.test.ts diff --git a/admin-frontend-vue/src/api/users-model.ts b/admin-frontend-vue/src/api/users-model.ts new file mode 100644 index 00000000..9142575e --- /dev/null +++ b/admin-frontend-vue/src/api/users-model.ts @@ -0,0 +1,54 @@ +/** 用户列表查询适配(任务 42):纯解析模块,无 axios 依赖,与 Java AdminUserListVo 对齐。 */ +import { unwrap } from './envelope.ts' +import { emptyUserPageResult, type UserPageResult } from './users-dto.ts' +import type { AdminUser } from '../types/admin' + +function text(value: unknown): string { + return typeof value === 'string' ? value : '' +} + +function numberOrNull(value: unknown): number | null { + return typeof value === 'number' && Number.isFinite(value) ? value : null +} + +/** 把 Java AdminUserItemVo(snake_case) 映射为前端 AdminUser(camelCase);缺 id 视为无效。 */ +export function toAdminUserItem(raw: unknown): AdminUser | null { + if (!raw || typeof raw !== 'object') return null + const r = raw as Record + const id = numberOrNull(r.id) + if (id === null) return null + const item: AdminUser = { id, username: text(r.username), role: text(r.role) } + if (typeof r.is_admin === 'boolean') item.isAdmin = r.is_admin + const createdById = numberOrNull(r.created_by_id) + if (createdById !== null) item.createdById = createdById + const createdAt = text(r.created_at) + if (createdAt) item.createdAt = createdAt + const creator = text(r.creator_username) + if (creator) item.creatorUsername = creator + const abbr = text(r.pinyin_abbr) + if (abbr) item.pinyinAbbr = abbr + return item +} + +/** + * 归一化 Java 用户列表负载(data:{items,total,page,page_size} 或已解包 VO)为前端 + * UserPageResult;空/缺省字段回默认,success=false 抛后端 message。 + */ +export function parseUserPage(payload: unknown): UserPageResult { + const out = emptyUserPageResult() + const core = unwrap(payload) + if (!core || typeof core !== 'object') return out + const record = core as Record + if (Array.isArray(record.items)) { + out.items = record.items + .map((raw) => toAdminUserItem(raw)) + .filter((item): item is AdminUser => item !== null) + } + if (typeof record.total === 'number') out.total = record.total + if (typeof record.page === 'number' && record.page >= 1) out.page = Math.floor(record.page) + const rawSize = record.page_size ?? record.pageSize + if (typeof rawSize === 'number' && rawSize >= 1) out.pageSize = Math.floor(rawSize) + if (typeof record.current_user_id === 'number') out.currentUserId = record.current_user_id + if (typeof record.current_user_username === 'string') out.currentUserUsername = record.current_user_username + return out +} diff --git a/admin-frontend-vue/src/api/users.ts b/admin-frontend-vue/src/api/users.ts new file mode 100644 index 00000000..0b09c491 --- /dev/null +++ b/admin-frontend-vue/src/api/users.ts @@ -0,0 +1,15 @@ +import { http } from './http' +import { parseUserPage } from './users-model' +import { + normalizeUserPageParams, + toUserListQuery, + type UserListParams, + type UserPageResult, +} from './users-dto' + +/** 分页查询用户列表:归一化参数 → GET /api/admin/users → 解析 Java 分页负载。 */ +export async function fetchUserList(params: Partial = {}): Promise { + const normalized = normalizeUserPageParams(params) + const { data } = await http.get('/api/admin/users', { params: toUserListQuery(normalized) }) + return parseUserPage(data) +} diff --git a/admin-frontend-vue/src/pages/account/UsersPage.vue b/admin-frontend-vue/src/pages/account/UsersPage.vue index 013985cb..8393a125 100644 --- a/admin-frontend-vue/src/pages/account/UsersPage.vue +++ b/admin-frontend-vue/src/pages/account/UsersPage.vue @@ -1,9 +1,9 @@