sysmgr-admin/src/api/user.ts
liuyun 5549b2e75c feat: user management page (search/table/pagination/dialog/delete/reset-pwd)
占位数据源 src/api/user.ts(字段对齐后端 User),页面跑通 CRUD 模式,后续接后端只换数据源。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-11 01:16:08 +08:00

140 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 用户管理数据源。
* TODO: 对接后端后,把下面 mock 实现替换为 http 调用(字段与返回形状保持不变)。
* 后端 User 实体字段:id/tenantCode/username/nickname/email/phone/status/orgCode/createdAt
*/
export type UserStatus = 'enabled' | 'disabled' | 'locked'
export interface User {
id: string
tenantCode: string
username: string
nickname: string | null
email: string | null
phone: string | null
status: UserStatus
orgCode: string | null
createdAt: number
}
export interface UserListQuery {
page: number
pageSize: number
username?: string
nickname?: string
phone?: string
status?: UserStatus | ''
}
export interface UserListResult {
list: User[]
total: number
page: number
pageSize: number
}
export interface UserUpsertData {
username: string
nickname?: string
email?: string
phone?: string
status?: UserStatus
orgCode?: string | null
password?: string
}
/** 占位组织(后续接后端换真实组织数据)。 */
export const mockOrgs: { code: string; name: string }[] = [
{ code: 'touyun', name: '投云总部' },
{ code: 'rd', name: '研发部' },
{ code: 'ops', name: '运维部' },
{ code: 'sales', name: '销售部' },
]
const now = Date.now()
const day = 24 * 60 * 60 * 1000
function mockUser(id: string, username: string, nickname: string, orgCode: string, status: UserStatus, daysAgo: number): User {
return {
id,
tenantCode: 'touyun',
username,
nickname,
email: `${username}@example.com`,
phone: `1380000${String(1000 + Number(id)).slice(-4)}`,
status,
orgCode,
createdAt: now - daysAgo * day,
}
}
let mockUsers: User[] = [
mockUser('1', 'touyun', '超级管理员', 'touyun', 'enabled', 30),
mockUser('2', 'zhangsan', '张三', 'rd', 'enabled', 20),
mockUser('3', 'lisi', '李四', 'rd', 'disabled', 18),
mockUser('4', 'wangwu', '王五', 'ops', 'locked', 15),
mockUser('5', 'zhaoliu', '赵六', 'sales', 'enabled', 12),
mockUser('6', 'sunqi', '孙七', 'ops', 'enabled', 9),
mockUser('7', 'zhouba', '周八', 'rd', 'enabled', 7),
mockUser('8', 'wujiu', '吴九', 'sales', 'disabled', 5),
mockUser('9', 'zhengshi', '郑十', 'rd', 'enabled', 3),
mockUser('10', 'chenyi', '陈一', 'sales', 'enabled', 1),
]
function uuid(): string {
return crypto.randomUUID()
}
export function orgName(code: string | null): string {
if (!code) return '-'
return mockOrgs.find((o) => o.code === code)?.name ?? code
}
export async function listUsers(query: UserListQuery): Promise<UserListResult> {
const { page, pageSize, username, nickname, phone, status } = query
const filtered = mockUsers.filter((u) => {
if (username && !u.username.includes(username)) return false
if (nickname && !(u.nickname ?? '').includes(nickname)) return false
if (phone && !(u.phone ?? '').includes(phone)) return false
if (status && u.status !== status) return false
return true
})
const total = filtered.length
const start = (page - 1) * pageSize
return { list: filtered.slice(start, start + pageSize), total, page, pageSize }
}
export async function createUser(data: UserUpsertData): Promise<User> {
const user: User = {
id: uuid(),
tenantCode: 'touyun',
username: data.username,
nickname: data.nickname ?? null,
email: data.email ?? null,
phone: data.phone ?? null,
status: data.status ?? 'enabled',
orgCode: data.orgCode ?? null,
createdAt: Date.now(),
}
mockUsers.unshift(user)
return user
}
export async function updateUser(id: string, data: Partial<UserUpsertData>): Promise<User> {
const user = mockUsers.find((u) => u.id === id)
if (!user) throw new Error('用户不存在')
Object.assign(user, data)
return user
}
export async function deleteUser(id: string): Promise<null> {
mockUsers = mockUsers.filter((u) => u.id !== id)
return null
}
export async function resetPassword(_id: string, _password: string): Promise<null> {
// mock:无真实密码存储,仅占位
return null
}