@mindbase/express-admin 1.0.2 → 1.0.8

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/index.ts ADDED
@@ -0,0 +1,23 @@
1
+ // 核心模块
2
+ // Service 层
3
+ export * as UserService from './service/UserService';
4
+
5
+ // 路由
6
+ export { default as userRoutes } from './routes/Users.route';
7
+ export { default as deviceRoutes } from './routes/Devices.route';
8
+
9
+ // Zod Schema
10
+ export {
11
+ createUserSchema,
12
+ listUsersSchema,
13
+ updateUserSchema,
14
+ resetPasswordSchema,
15
+ userIdParamsSchema,
16
+ type CreateUserInput,
17
+ type ListUsersInput,
18
+ type UpdateUserInput,
19
+ type ResetPasswordInput,
20
+ } from './zod/User.schema';
21
+
22
+ import AdminModule from './module/AdminModule';
23
+ export default AdminModule;
@@ -0,0 +1,19 @@
1
+ import { createModule, MindBaseApp, logger } from "@mindbase/express-common";
2
+ import * as UserService from "../service/UserService";
3
+
4
+ /**
5
+ * 管理模块
6
+ */
7
+ export default createModule(async (app: MindBaseApp) => {
8
+ const db = app.getDB();
9
+
10
+ if (!db) {
11
+ logger.error("[Admin] Database not found in app, skipping service initialization");
12
+ return;
13
+ }
14
+
15
+ // 初始化 UserService
16
+ UserService.initUserService(db);
17
+
18
+ logger.startup("管理", "模块初始化完成");
19
+ }, __filename);
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "@mindbase/express-admin",
3
- "version": "1.0.2",
3
+ "version": "1.0.8",
4
4
  "exports": {
5
- ".": {
6
- "development": "./index.ts",
7
- "import": "./dist/index.js",
8
- "types": "./dist/index.d.ts"
9
- }
5
+ ".": "./index.ts"
10
6
  },
11
7
  "files": [
12
- "dist"
8
+ "routes",
9
+ "zod",
10
+ "module",
11
+ "service",
12
+ "index.ts",
13
+ "tsconfig.json"
13
14
  ],
14
15
  "engines": {
15
16
  "node": ">=20.0.0"
@@ -26,14 +27,13 @@
26
27
  },
27
28
  "devDependencies": {
28
29
  "@types/express": "^5.0.6",
29
- "tsup": "^8.0.0",
30
30
  "typescript": "^5.1.3",
31
31
  "vitest": "^2.1.0"
32
32
  },
33
33
  "scripts": {
34
34
  "test": "vitest run",
35
35
  "test:watch": "vitest",
36
- "prepublishOnly": "tsup"
36
+ "prepare": "tsc --noEmit"
37
37
  },
38
38
  "publishConfig": {
39
39
  "access": "public"
@@ -0,0 +1,135 @@
1
+ import { Router, Request, Response } from "express";
2
+ import { eq, and, desc, count } from "drizzle-orm";
3
+ import { userDevices } from "@mindbase/express-auth";
4
+ import { DeviceService } from "@mindbase/express-auth";
5
+ import { validate } from "@mindbase/express-common";
6
+ import { deviceIdParamsSchema, userIdParamsSchema } from "../zod/Device.schema";
7
+ import type { ApiResponse } from "@mindbase/express-common";
8
+
9
+ const router = Router();
10
+
11
+ /**
12
+ * 获取所有设备列表(分页、按用户筛选)
13
+ * @apiParam {number} [page] 页码(可选,默认1)
14
+ * @apiParam {number} [pageSize] 每页数量(可选,默认10)
15
+ * @apiParam {number} [userId] 用户ID(可选)
16
+ * @apiSuccess {number} code 状态码
17
+ * @apiSuccess {string} msg 消息
18
+ * @apiSuccess {Object} data 设备列表
19
+ * @apiSuccess {Object[]} data.list 设备数组
20
+ * @apiSuccess {number} data.total 总数
21
+ * @apiSuccess {number} data.page 当前页
22
+ * @apiSuccess {number} data.pageSize 每页数量
23
+ */
24
+ router.get("/", async (req: Request, res: Response) => {
25
+ const db = req.app.getDB();
26
+ const page = parseInt(req.query.page as string) || 1;
27
+ const pageSize = Math.min(parseInt(req.query.pageSize as string) || 10, 100);
28
+ const userId = req.query.userId ? parseInt(req.query.userId as string) : undefined;
29
+
30
+ // 构建查询条件
31
+ const conditions = [eq(userDevices.isExpired, 0)];
32
+ if (userId) {
33
+ conditions.push(eq(userDevices.userId, userId));
34
+ }
35
+ const whereClause = and(...conditions);
36
+
37
+ // 查询总数
38
+ const [{ total }] = await db
39
+ .select({ total: count() })
40
+ .from(userDevices)
41
+ .where(whereClause)
42
+ .execute();
43
+
44
+ // 查询列表
45
+ const list = await db
46
+ .select()
47
+ .from(userDevices)
48
+ .where(whereClause)
49
+ .orderBy(desc(userDevices.createdAt))
50
+ .limit(pageSize)
51
+ .offset((page - 1) * pageSize)
52
+ .execute();
53
+
54
+ res.json({
55
+ code: 200,
56
+ data: {
57
+ list,
58
+ total,
59
+ page,
60
+ pageSize,
61
+ },
62
+ msg: "获取成功",
63
+ });
64
+ });
65
+
66
+ /**
67
+ * 获取单个设备详情
68
+ * @apiParam {string} id 设备ID(路径参数,必填)
69
+ * @apiSuccess {number} code 状态码
70
+ * @apiSuccess {string} msg 消息
71
+ * @apiSuccess {Object} data 设备详情
72
+ */
73
+ router.get("/:id", validate(deviceIdParamsSchema as any, "params"), async (req: Request, res: Response) => {
74
+ const db = req.app.getDB();
75
+ const { id } = req.params as any;
76
+
77
+ const [device] = await db
78
+ .select()
79
+ .from(userDevices)
80
+ .where(eq(userDevices.id, id))
81
+ .execute();
82
+
83
+ if (!device) {
84
+ return res.status(404).json({ code: 404, msg: "设备不存在" });
85
+ }
86
+
87
+ res.json({
88
+ code: 200,
89
+ data: device,
90
+ msg: "获取成功",
91
+ });
92
+ });
93
+
94
+ /**
95
+ * 强制下线指定设备
96
+ * @apiParam {string} id 设备ID(路径参数,必填)
97
+ * @apiSuccess {number} code 状态码
98
+ * @apiSuccess {string} msg 消息
99
+ * @apiSuccess {boolean} data 是否下线成功
100
+ */
101
+ router.delete("/:id", validate(deviceIdParamsSchema as any, "params"), async (req: Request, res: Response) => {
102
+ const { id } = req.params as any;
103
+ await DeviceService.revoke(id);
104
+
105
+ res.json({
106
+ code: 200,
107
+ data: true,
108
+ msg: "已强制下线该设备",
109
+ });
110
+ });
111
+
112
+ /**
113
+ * 下线用户的所有设备
114
+ * @apiParam {number} userId 用户ID(路径参数,必填)
115
+ * @apiSuccess {number} code 状态码
116
+ * @apiSuccess {string} msg 消息
117
+ * @apiSuccess {boolean} data 是否下线成功
118
+ */
119
+ router.delete("/users/:userId/devices", validate(userIdParamsSchema as any, "params"), async (req: Request, res: Response) => {
120
+ const { userId } = req.params as any;
121
+ const db = req.app.getDB();
122
+ await db
123
+ .update(userDevices)
124
+ .set({ isExpired: 1 })
125
+ .where(and(eq(userDevices.userId, userId), eq(userDevices.isExpired, 0)))
126
+ .execute();
127
+
128
+ res.json({
129
+ code: 200,
130
+ data: true,
131
+ msg: "已下线该用户的所有设备",
132
+ });
133
+ });
134
+
135
+ export default router;
@@ -0,0 +1,124 @@
1
+ import { Router, Request, Response } from "express";
2
+ import { validate } from "@mindbase/express-common";
3
+ import * as UserService from "../service/UserService";
4
+ import { createUserSchema, listUsersSchema, updateUserSchema, resetPasswordSchema, userIdParamsSchema } from "../zod/User.schema";
5
+ import type { ApiResponse } from "@mindbase/express-common";
6
+
7
+ const router = Router();
8
+
9
+ /**
10
+ * 创建用户(管理员)
11
+ * @apiParam {string} username 用户名(必填,最少4位)
12
+ * @apiParam {string} password 密码(必填,最少6位)
13
+ * @apiParam {string} [nickname] 昵称(可选)
14
+ * @apiParam {number} [status] 状态(可选,0:禁用, 1:启用)
15
+ * @apiSuccess {number} code 状态码
16
+ * @apiSuccess {string} msg 消息
17
+ * @apiSuccess {Object} data 用户信息
18
+ */
19
+ router.post("/", validate(createUserSchema as any), async (req: Request, res: Response) => {
20
+ const result = await UserService.createUser(req.body);
21
+ res.json({
22
+ code: 200,
23
+ data: result,
24
+ msg: "创建成功",
25
+ });
26
+ });
27
+
28
+ /**
29
+ * 获取用户列表(分页、搜索)
30
+ * @apiParam {number} [page] 页码(可选,默认1)
31
+ * @apiParam {number} [pageSize] 每页数量(可选,默认10,最大100)
32
+ * @apiParam {string} [keyword] 搜索关键词(可选)
33
+ * @apiParam {number} [status] 状态筛选(可选,0:禁用, 1:启用)
34
+ * @apiSuccess {number} code 状态码
35
+ * @apiSuccess {string} msg 消息
36
+ * @apiSuccess {Object} data 用户列表
37
+ * @apiSuccess {Object[]} data.list 用户数组
38
+ * @apiSuccess {number} data.total 总数
39
+ * @apiSuccess {number} data.page 当前页
40
+ * @apiSuccess {number} data.pageSize 每页数量
41
+ */
42
+ router.get("/", validate(listUsersSchema as any, "query"), async (req: Request, res: Response) => {
43
+ const result = await UserService.listUsers(req.query as any);
44
+ res.json({
45
+ code: 200,
46
+ data: result,
47
+ msg: "获取成功",
48
+ });
49
+ });
50
+
51
+ /**
52
+ * 获取单个用户
53
+ * @apiParam {number} id 用户ID(路径参数,必填)
54
+ * @apiSuccess {number} code 状态码
55
+ * @apiSuccess {string} msg 消息
56
+ * @apiSuccess {Object} data 用户详情
57
+ */
58
+ router.get("/:id", validate(userIdParamsSchema as any, "params"), async (req: Request, res: Response) => {
59
+ const { id } = req.params as any;
60
+ const result = await UserService.getUserById(id);
61
+ res.json({
62
+ code: 200,
63
+ data: result,
64
+ msg: "获取成功",
65
+ });
66
+ });
67
+
68
+ /**
69
+ * 更新用户信息
70
+ * @apiParam {number} id 用户ID(路径参数,必填)
71
+ * @apiParam {string} [nickname] 昵称(可选)
72
+ * @apiParam {number} [status] 状态(可选,0:禁用, 1:启用)
73
+ * @apiSuccess {number} code 状态码
74
+ * @apiSuccess {string} msg 消息
75
+ * @apiSuccess {Object} data 更新后的用户信息
76
+ */
77
+ router.put("/:id", validate(userIdParamsSchema as any, "params"), validate(updateUserSchema as any), async (req: Request, res: Response) => {
78
+ const { id } = req.params as any;
79
+ const result = await UserService.updateUser(id, req.body);
80
+ res.json({
81
+ code: 200,
82
+ data: result,
83
+ msg: "更新成功",
84
+ });
85
+ });
86
+
87
+ /**
88
+ * 删除用户(软删除)
89
+ * @apiParam {number} id 用户ID(路径参数,必填)
90
+ * @apiSuccess {number} code 状态码
91
+ * @apiSuccess {string} msg 消息
92
+ * @apiSuccess {boolean} data 是否删除成功
93
+ */
94
+ router.delete("/:id", validate(userIdParamsSchema as any, "params"), async (req: Request, res: Response) => {
95
+ const { id } = req.params as any;
96
+ const currentUserId = res.locals.user?.id;
97
+ await UserService.deleteUser(id, currentUserId);
98
+
99
+ res.json({
100
+ code: 200,
101
+ data: true,
102
+ msg: "删除成功",
103
+ });
104
+ });
105
+
106
+ /**
107
+ * 重置用户密码
108
+ * @apiParam {number} id 用户ID(路径参数,必填)
109
+ * @apiParam {string} newPassword 新密码(必填,最少6位)
110
+ * @apiSuccess {number} code 状态码
111
+ * @apiSuccess {string} msg 消息
112
+ * @apiSuccess {boolean} data 是否重置成功
113
+ */
114
+ router.post("/:id/reset-password", validate(userIdParamsSchema as any, "params"), validate(resetPasswordSchema as any), async (req: Request, res: Response) => {
115
+ const { id } = req.params as any;
116
+ await UserService.resetUserPassword(id, req.body.newPassword);
117
+ res.json({
118
+ code: 200,
119
+ data: true,
120
+ msg: "密码重置成功",
121
+ });
122
+ });
123
+
124
+ export default router;
@@ -0,0 +1,261 @@
1
+ import { eq, and, like, or, desc, count, isNull } from "drizzle-orm";
2
+ import { users } from "@mindbase/express-auth";
3
+ import { md5 } from "@mindbase/express-auth";
4
+
5
+ let _db: any;
6
+
7
+ export function initUserService(db: any) {
8
+ _db = db;
9
+ }
10
+
11
+ function getDB() {
12
+ if (!_db) throw new Error("UserService not initialized with DB");
13
+ return _db;
14
+ }
15
+
16
+ /**
17
+ * 检查用户名是否存在
18
+ */
19
+ export async function checkUsernameExists(username: string, excludeId?: number): Promise<boolean> {
20
+ const db = getDB();
21
+ const conditions = [eq(users.username, username), isNull(users.deletedAt)];
22
+
23
+ if (excludeId) {
24
+ conditions.push(eq(users.id, excludeId));
25
+ }
26
+
27
+ const [existing] = await db
28
+ .select({ id: users.id })
29
+ .from(users)
30
+ .where(and(...conditions))
31
+ .execute();
32
+
33
+ return !!existing;
34
+ }
35
+
36
+ /**
37
+ * 创建用户(管理员)
38
+ */
39
+ export async function createUser(data: {
40
+ username: string;
41
+ password: string;
42
+ nickname?: string;
43
+ status?: number;
44
+ }) {
45
+ const db = getDB();
46
+
47
+ // 检查用户名是否已存在
48
+ const exists = await checkUsernameExists(data.username);
49
+ if (exists) {
50
+ throw new Error("用户名已存在");
51
+ }
52
+
53
+ const now = new Date();
54
+ const [user] = await db
55
+ .insert(users)
56
+ .values({
57
+ username: data.username,
58
+ password: md5(data.password),
59
+ nickname: data.nickname || data.username,
60
+ status: data.status ?? 1,
61
+ created: now,
62
+ updated: now,
63
+ })
64
+ .returning()
65
+ .execute();
66
+
67
+ return {
68
+ id: user.id,
69
+ username: user.username,
70
+ nickname: user.nickname,
71
+ status: user.status,
72
+ created: user.created,
73
+ };
74
+ }
75
+
76
+ /**
77
+ * 获取用户列表(分页、搜索)
78
+ */
79
+ export async function listUsers(options: {
80
+ page: number;
81
+ pageSize: number;
82
+ keyword?: string;
83
+ status?: number;
84
+ }) {
85
+ const db = getDB();
86
+ const { page, pageSize, keyword, status } = options;
87
+
88
+ // 构建查询条件
89
+ const conditions = [isNull(users.deletedAt)];
90
+
91
+ if (status !== undefined) {
92
+ conditions.push(eq(users.status, status));
93
+ }
94
+
95
+ if (keyword) {
96
+ conditions.push(
97
+ or(
98
+ like(users.username, `%${keyword}%`),
99
+ like(users.nickname, `%${keyword}%`)
100
+ )!
101
+ );
102
+ }
103
+
104
+ const whereClause = and(...conditions);
105
+
106
+ // 查询总数
107
+ const [{ total }] = await db
108
+ .select({ total: count() })
109
+ .from(users)
110
+ .where(whereClause)
111
+ .execute();
112
+
113
+ // 查询列表
114
+ const list = await db
115
+ .select({
116
+ id: users.id,
117
+ username: users.username,
118
+ nickname: users.nickname,
119
+ status: users.status,
120
+ created: users.created,
121
+ updated: users.updated,
122
+ })
123
+ .from(users)
124
+ .where(whereClause)
125
+ .orderBy(desc(users.created))
126
+ .limit(pageSize)
127
+ .offset((page - 1) * pageSize)
128
+ .execute();
129
+
130
+ return {
131
+ list,
132
+ total,
133
+ page,
134
+ pageSize,
135
+ };
136
+ }
137
+
138
+ /**
139
+ * 根据 ID 获取用户
140
+ */
141
+ export async function getUserById(id: number) {
142
+ const db = getDB();
143
+
144
+ const [user] = await db
145
+ .select({
146
+ id: users.id,
147
+ username: users.username,
148
+ nickname: users.nickname,
149
+ status: users.status,
150
+ created: users.created,
151
+ updated: users.updated,
152
+ })
153
+ .from(users)
154
+ .where(and(eq(users.id, id), isNull(users.deletedAt)))
155
+ .execute();
156
+
157
+ if (!user) {
158
+ throw new Error("用户不存在");
159
+ }
160
+
161
+ return user;
162
+ }
163
+
164
+ /**
165
+ * 更新用户信息
166
+ */
167
+ export async function updateUser(id: number, data: { nickname?: string; status?: number }) {
168
+ const db = getDB();
169
+
170
+ // 检查用户是否存在
171
+ const [existing] = await db
172
+ .select({ id: users.id })
173
+ .from(users)
174
+ .where(and(eq(users.id, id), isNull(users.deletedAt)))
175
+ .execute();
176
+
177
+ if (!existing) {
178
+ throw new Error("用户不存在");
179
+ }
180
+
181
+ // 更新
182
+ const [user] = await db
183
+ .update(users)
184
+ .set({
185
+ ...data,
186
+ updated: new Date(),
187
+ })
188
+ .where(eq(users.id, id))
189
+ .returning()
190
+ .execute();
191
+
192
+ return {
193
+ id: user.id,
194
+ username: user.username,
195
+ nickname: user.nickname,
196
+ status: user.status,
197
+ updated: user.updated,
198
+ };
199
+ }
200
+
201
+ /**
202
+ * 删除用户(软删除)
203
+ */
204
+ export async function deleteUser(id: number, currentUserId?: number) {
205
+ const db = getDB();
206
+
207
+ // 不允许删除自己
208
+ if (currentUserId && id === currentUserId) {
209
+ throw new Error("不能删除当前登录用户");
210
+ }
211
+
212
+ // 检查用户是否存在
213
+ const [existing] = await db
214
+ .select({ id: users.id })
215
+ .from(users)
216
+ .where(and(eq(users.id, id), isNull(users.deletedAt)))
217
+ .execute();
218
+
219
+ if (!existing) {
220
+ throw new Error("用户不存在");
221
+ }
222
+
223
+ // 软删除
224
+ await db
225
+ .update(users)
226
+ .set({ deletedAt: new Date() })
227
+ .where(eq(users.id, id))
228
+ .execute();
229
+
230
+ return { success: true };
231
+ }
232
+
233
+ /**
234
+ * 重置用户密码
235
+ */
236
+ export async function resetUserPassword(id: number, newPassword: string) {
237
+ const db = getDB();
238
+
239
+ // 检查用户是否存在
240
+ const [existing] = await db
241
+ .select({ id: users.id })
242
+ .from(users)
243
+ .where(and(eq(users.id, id), isNull(users.deletedAt)))
244
+ .execute();
245
+
246
+ if (!existing) {
247
+ throw new Error("用户不存在");
248
+ }
249
+
250
+ // 更新密码
251
+ await db
252
+ .update(users)
253
+ .set({
254
+ password: md5(newPassword),
255
+ updated: new Date(),
256
+ })
257
+ .where(eq(users.id, id))
258
+ .execute();
259
+
260
+ return { success: true };
261
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist"
5
+ },
6
+ "include": ["./**/*"],
7
+ "exclude": ["node_modules", "dist"]
8
+ }
@@ -0,0 +1,15 @@
1
+ import { z } from "zod";
2
+
3
+ // 设备ID(字符串)
4
+ export const deviceIdParamsSchema = z.object({
5
+ id: z.string().min(1, "设备ID不能为空"),
6
+ });
7
+
8
+ // 用户ID(数字)
9
+ export const userIdParamsSchema = z.object({
10
+ userId: z.coerce.number().int().positive("无效的用户ID"),
11
+ });
12
+
13
+ // 类型导出
14
+ export type DeviceIdParams = z.infer<typeof deviceIdParamsSchema>;
15
+ export type UserIdParams = z.infer<typeof userIdParamsSchema>;
@@ -0,0 +1,39 @@
1
+ import { z } from "zod";
2
+
3
+ // 创建用户(管理员)
4
+ export const createUserSchema = z.object({
5
+ username: z.string().min(4, "用户名长度不能小于4位"),
6
+ password: z.string().min(6, "密码长度不能小于6位"),
7
+ nickname: z.string().optional(),
8
+ status: z.number().int().min(0).max(1).optional(),
9
+ });
10
+
11
+ // 查询用户列表
12
+ export const listUsersSchema = z.object({
13
+ page: z.coerce.number().int().positive().default(1),
14
+ pageSize: z.coerce.number().int().positive().max(100).default(10),
15
+ keyword: z.string().optional(),
16
+ status: z.coerce.number().int().min(0).max(1).optional(),
17
+ });
18
+
19
+ // 更新用户
20
+ export const updateUserSchema = z.object({
21
+ nickname: z.string().min(1, "昵称不能为空").optional(),
22
+ status: z.number().int().min(0).max(1).optional(),
23
+ });
24
+
25
+ // 重置密码
26
+ export const resetPasswordSchema = z.object({
27
+ newPassword: z.string().min(6, "新密码长度不能少于6位"),
28
+ });
29
+
30
+ // 路径参数
31
+ export const userIdParamsSchema = z.object({
32
+ id: z.coerce.number().int().positive("无效的用户ID"),
33
+ });
34
+
35
+ // 类型导出
36
+ export type CreateUserInput = z.infer<typeof createUserSchema>;
37
+ export type ListUsersInput = z.infer<typeof listUsersSchema>;
38
+ export type UpdateUserInput = z.infer<typeof updateUserSchema>;
39
+ export type ResetPasswordInput = z.infer<typeof resetPasswordSchema>;
package/dist/index.d.mts DELETED
@@ -1,210 +0,0 @@
1
- import * as express_serve_static_core from 'express-serve-static-core';
2
- import { z } from 'zod';
3
- import { Express } from 'express';
4
-
5
- declare function initUserService(db: any): void;
6
- /**
7
- * 检查用户名是否存在
8
- */
9
- declare function checkUsernameExists(username: string, excludeId?: number): Promise<boolean>;
10
- /**
11
- * 创建用户(管理员)
12
- */
13
- declare function createUser(data: {
14
- username: string;
15
- password: string;
16
- nickname?: string;
17
- status?: number;
18
- }): Promise<{
19
- id: any;
20
- username: any;
21
- nickname: any;
22
- status: any;
23
- created: any;
24
- }>;
25
- /**
26
- * 获取用户列表(分页、搜索)
27
- */
28
- declare function listUsers(options: {
29
- page: number;
30
- pageSize: number;
31
- keyword?: string;
32
- status?: number;
33
- }): Promise<{
34
- list: any;
35
- total: any;
36
- page: number;
37
- pageSize: number;
38
- }>;
39
- /**
40
- * 根据 ID 获取用户
41
- */
42
- declare function getUserById(id: number): Promise<any>;
43
- /**
44
- * 更新用户信息
45
- */
46
- declare function updateUser(id: number, data: {
47
- nickname?: string;
48
- status?: number;
49
- }): Promise<{
50
- id: any;
51
- username: any;
52
- nickname: any;
53
- status: any;
54
- updated: any;
55
- }>;
56
- /**
57
- * 删除用户(软删除)
58
- */
59
- declare function deleteUser(id: number, currentUserId?: number): Promise<{
60
- success: boolean;
61
- }>;
62
- /**
63
- * 重置用户密码
64
- */
65
- declare function resetUserPassword(id: number, newPassword: string): Promise<{
66
- success: boolean;
67
- }>;
68
-
69
- declare const UserService_checkUsernameExists: typeof checkUsernameExists;
70
- declare const UserService_createUser: typeof createUser;
71
- declare const UserService_deleteUser: typeof deleteUser;
72
- declare const UserService_getUserById: typeof getUserById;
73
- declare const UserService_initUserService: typeof initUserService;
74
- declare const UserService_listUsers: typeof listUsers;
75
- declare const UserService_resetUserPassword: typeof resetUserPassword;
76
- declare const UserService_updateUser: typeof updateUser;
77
- declare namespace UserService {
78
- export { UserService_checkUsernameExists as checkUsernameExists, UserService_createUser as createUser, UserService_deleteUser as deleteUser, UserService_getUserById as getUserById, UserService_initUserService as initUserService, UserService_listUsers as listUsers, UserService_resetUserPassword as resetUserPassword, UserService_updateUser as updateUser };
79
- }
80
-
81
- declare const router$1: express_serve_static_core.Router;
82
-
83
- declare const router: express_serve_static_core.Router;
84
-
85
- declare const createUserSchema: z.ZodObject<{
86
- username: z.ZodString;
87
- password: z.ZodString;
88
- nickname: z.ZodOptional<z.ZodString>;
89
- status: z.ZodOptional<z.ZodNumber>;
90
- }, "strip", z.ZodTypeAny, {
91
- username?: string;
92
- password?: string;
93
- nickname?: string;
94
- status?: number;
95
- }, {
96
- username?: string;
97
- password?: string;
98
- nickname?: string;
99
- status?: number;
100
- }>;
101
- declare const listUsersSchema: z.ZodObject<{
102
- page: z.ZodDefault<z.ZodNumber>;
103
- pageSize: z.ZodDefault<z.ZodNumber>;
104
- keyword: z.ZodOptional<z.ZodString>;
105
- status: z.ZodOptional<z.ZodNumber>;
106
- }, "strip", z.ZodTypeAny, {
107
- status?: number;
108
- page?: number;
109
- pageSize?: number;
110
- keyword?: string;
111
- }, {
112
- status?: number;
113
- page?: number;
114
- pageSize?: number;
115
- keyword?: string;
116
- }>;
117
- declare const updateUserSchema: z.ZodObject<{
118
- nickname: z.ZodOptional<z.ZodString>;
119
- status: z.ZodOptional<z.ZodNumber>;
120
- }, "strip", z.ZodTypeAny, {
121
- nickname?: string;
122
- status?: number;
123
- }, {
124
- nickname?: string;
125
- status?: number;
126
- }>;
127
- declare const resetPasswordSchema: z.ZodObject<{
128
- newPassword: z.ZodString;
129
- }, "strip", z.ZodTypeAny, {
130
- newPassword?: string;
131
- }, {
132
- newPassword?: string;
133
- }>;
134
- declare const userIdParamsSchema: z.ZodObject<{
135
- id: z.ZodNumber;
136
- }, "strip", z.ZodTypeAny, {
137
- id?: number;
138
- }, {
139
- id?: number;
140
- }>;
141
- type CreateUserInput = z.infer<typeof createUserSchema>;
142
- type ListUsersInput = z.infer<typeof listUsersSchema>;
143
- type UpdateUserInput = z.infer<typeof updateUserSchema>;
144
- type ResetPasswordInput = z.infer<typeof resetPasswordSchema>;
145
-
146
- interface MindBaseAppOptions {
147
- /** 服务监听主机名 @default 127.0.0.1 */
148
- host?: string;
149
- /** 服务监听端口 @default 3000 */
150
- port?: number;
151
- /** 是否启用请求日志 @default true */
152
- logging?: boolean;
153
- /** 静态文件目录路径 */
154
- staticPath?: string;
155
- /** 是否解析 User-Agent 信息 @default true */
156
- userAgent?: boolean;
157
- /** 是否解析 IP 地理位置信息 @default true */
158
- ip?: boolean;
159
- /** 是否启用 CORS 跨域 @default true */
160
- cors?: boolean;
161
- /** API 路由前缀,如 "/api" */
162
- apiPrefix?: string;
163
- /**
164
- * 日志级别(优先级从低到高):
165
- * - debug: 调试信息(显示所有)
166
- * - info: 普通信息(隐藏 debug)
167
- * - warn: 警告信息(隐藏 debug、info)
168
- * - error: 错误信息(隐藏 debug、info、warn)
169
- * - silent: 静默模式(隐藏所有)
170
- * @default "info"
171
- */
172
- logLevel?: LogLevel;
173
- /** 数据库配置 */
174
- database?: {
175
- /** SQLite 数据库文件路径 @default "./data/app.db" */
176
- path?: string;
177
- };
178
- /** 认证白名单路径(支持字符串和正则表达式) */
179
- authWhitelist?: (string | RegExp)[];
180
- }
181
-
182
- type LogLevel = "debug" | "info" | "warn" | "error" | "silent";
183
-
184
- /**
185
- * MindBase 应用实例
186
- */
187
- interface MindBaseApp {
188
- /** 注册插件模块 */
189
- use(plugin: any): void;
190
- /** 启动应用(初始化数据库、注册路由、启动 HTTP 服务) */
191
- startup(): Promise<void>;
192
- /** 获取 Express 实例 */
193
- getApp(): Express;
194
- /** 获取 Drizzle 数据库实例 */
195
- getDB(): any;
196
- /** 获取应用配置选项 */
197
- getOptions(): MindBaseAppOptions;
198
- }
199
-
200
- interface LightUpModule {
201
- install(app: MindBaseApp): Promise<void>;
202
- __modulePath: string;
203
- }
204
-
205
- /**
206
- * 管理模块
207
- */
208
- declare const _default: LightUpModule;
209
-
210
- export { type CreateUserInput, type ListUsersInput, type ResetPasswordInput, type UpdateUserInput, UserService, createUserSchema, _default as default, router as deviceRoutes, listUsersSchema, resetPasswordSchema, updateUserSchema, userIdParamsSchema, router$1 as userRoutes };
package/dist/index.mjs DELETED
@@ -1,344 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, { get: all[name], enumerable: true });
5
- };
6
-
7
- // ../../node_modules/tsup/assets/esm_shims.js
8
- import path from "path";
9
- import { fileURLToPath } from "url";
10
- var getFilename = () => fileURLToPath(import.meta.url);
11
- var __filename = /* @__PURE__ */ getFilename();
12
-
13
- // service/UserService.ts
14
- var UserService_exports = {};
15
- __export(UserService_exports, {
16
- checkUsernameExists: () => checkUsernameExists,
17
- createUser: () => createUser,
18
- deleteUser: () => deleteUser,
19
- getUserById: () => getUserById,
20
- initUserService: () => initUserService,
21
- listUsers: () => listUsers,
22
- resetUserPassword: () => resetUserPassword,
23
- updateUser: () => updateUser
24
- });
25
- import { eq, and, like, or, desc, count, isNull } from "drizzle-orm";
26
- import { users } from "@mindbase/express-auth";
27
- import { md5 } from "@mindbase/express-auth";
28
- var _db;
29
- function initUserService(db) {
30
- _db = db;
31
- }
32
- function getDB() {
33
- if (!_db) throw new Error("UserService not initialized with DB");
34
- return _db;
35
- }
36
- async function checkUsernameExists(username, excludeId) {
37
- const db = getDB();
38
- const conditions = [eq(users.username, username), isNull(users.deletedAt)];
39
- if (excludeId) {
40
- conditions.push(eq(users.id, excludeId));
41
- }
42
- const [existing] = await db.select({ id: users.id }).from(users).where(and(...conditions)).execute();
43
- return !!existing;
44
- }
45
- async function createUser(data) {
46
- const db = getDB();
47
- const exists = await checkUsernameExists(data.username);
48
- if (exists) {
49
- throw new Error("\u7528\u6237\u540D\u5DF2\u5B58\u5728");
50
- }
51
- const now = /* @__PURE__ */ new Date();
52
- const [user] = await db.insert(users).values({
53
- username: data.username,
54
- password: md5(data.password),
55
- nickname: data.nickname || data.username,
56
- status: data.status ?? 1,
57
- created: now,
58
- updated: now
59
- }).returning().execute();
60
- return {
61
- id: user.id,
62
- username: user.username,
63
- nickname: user.nickname,
64
- status: user.status,
65
- created: user.created
66
- };
67
- }
68
- async function listUsers(options) {
69
- const db = getDB();
70
- const { page, pageSize, keyword, status } = options;
71
- const conditions = [isNull(users.deletedAt)];
72
- if (status !== void 0) {
73
- conditions.push(eq(users.status, status));
74
- }
75
- if (keyword) {
76
- conditions.push(
77
- or(
78
- like(users.username, `%${keyword}%`),
79
- like(users.nickname, `%${keyword}%`)
80
- )
81
- );
82
- }
83
- const whereClause = and(...conditions);
84
- const [{ total }] = await db.select({ total: count() }).from(users).where(whereClause).execute();
85
- const list = await db.select({
86
- id: users.id,
87
- username: users.username,
88
- nickname: users.nickname,
89
- status: users.status,
90
- created: users.created,
91
- updated: users.updated
92
- }).from(users).where(whereClause).orderBy(desc(users.created)).limit(pageSize).offset((page - 1) * pageSize).execute();
93
- return {
94
- list,
95
- total,
96
- page,
97
- pageSize
98
- };
99
- }
100
- async function getUserById(id) {
101
- const db = getDB();
102
- const [user] = await db.select({
103
- id: users.id,
104
- username: users.username,
105
- nickname: users.nickname,
106
- status: users.status,
107
- created: users.created,
108
- updated: users.updated
109
- }).from(users).where(and(eq(users.id, id), isNull(users.deletedAt))).execute();
110
- if (!user) {
111
- throw new Error("\u7528\u6237\u4E0D\u5B58\u5728");
112
- }
113
- return user;
114
- }
115
- async function updateUser(id, data) {
116
- const db = getDB();
117
- const [existing] = await db.select({ id: users.id }).from(users).where(and(eq(users.id, id), isNull(users.deletedAt))).execute();
118
- if (!existing) {
119
- throw new Error("\u7528\u6237\u4E0D\u5B58\u5728");
120
- }
121
- const [user] = await db.update(users).set({
122
- ...data,
123
- updated: /* @__PURE__ */ new Date()
124
- }).where(eq(users.id, id)).returning().execute();
125
- return {
126
- id: user.id,
127
- username: user.username,
128
- nickname: user.nickname,
129
- status: user.status,
130
- updated: user.updated
131
- };
132
- }
133
- async function deleteUser(id, currentUserId) {
134
- const db = getDB();
135
- if (currentUserId && id === currentUserId) {
136
- throw new Error("\u4E0D\u80FD\u5220\u9664\u5F53\u524D\u767B\u5F55\u7528\u6237");
137
- }
138
- const [existing] = await db.select({ id: users.id }).from(users).where(and(eq(users.id, id), isNull(users.deletedAt))).execute();
139
- if (!existing) {
140
- throw new Error("\u7528\u6237\u4E0D\u5B58\u5728");
141
- }
142
- await db.update(users).set({ deletedAt: /* @__PURE__ */ new Date() }).where(eq(users.id, id)).execute();
143
- return { success: true };
144
- }
145
- async function resetUserPassword(id, newPassword) {
146
- const db = getDB();
147
- const [existing] = await db.select({ id: users.id }).from(users).where(and(eq(users.id, id), isNull(users.deletedAt))).execute();
148
- if (!existing) {
149
- throw new Error("\u7528\u6237\u4E0D\u5B58\u5728");
150
- }
151
- await db.update(users).set({
152
- password: md5(newPassword),
153
- updated: /* @__PURE__ */ new Date()
154
- }).where(eq(users.id, id)).execute();
155
- return { success: true };
156
- }
157
-
158
- // routes/Users.route.ts
159
- import { Router } from "express";
160
- import { validate } from "@mindbase/express-common";
161
-
162
- // zod/User.schema.ts
163
- import { z } from "zod";
164
- var createUserSchema = z.object({
165
- username: z.string().min(4, "\u7528\u6237\u540D\u957F\u5EA6\u4E0D\u80FD\u5C0F\u4E8E4\u4F4D"),
166
- password: z.string().min(6, "\u5BC6\u7801\u957F\u5EA6\u4E0D\u80FD\u5C0F\u4E8E6\u4F4D"),
167
- nickname: z.string().optional(),
168
- status: z.number().int().min(0).max(1).optional()
169
- });
170
- var listUsersSchema = z.object({
171
- page: z.coerce.number().int().positive().default(1),
172
- pageSize: z.coerce.number().int().positive().max(100).default(10),
173
- keyword: z.string().optional(),
174
- status: z.coerce.number().int().min(0).max(1).optional()
175
- });
176
- var updateUserSchema = z.object({
177
- nickname: z.string().min(1, "\u6635\u79F0\u4E0D\u80FD\u4E3A\u7A7A").optional(),
178
- status: z.number().int().min(0).max(1).optional()
179
- });
180
- var resetPasswordSchema = z.object({
181
- newPassword: z.string().min(6, "\u65B0\u5BC6\u7801\u957F\u5EA6\u4E0D\u80FD\u5C11\u4E8E6\u4F4D")
182
- });
183
- var userIdParamsSchema = z.object({
184
- id: z.coerce.number().int().positive("\u65E0\u6548\u7684\u7528\u6237ID")
185
- });
186
-
187
- // routes/Users.route.ts
188
- var router = Router();
189
- router.post("/", validate(createUserSchema), async (req, res) => {
190
- const result = await createUser(req.body);
191
- res.json({
192
- code: 200,
193
- data: result,
194
- msg: "\u521B\u5EFA\u6210\u529F"
195
- });
196
- });
197
- router.get("/", validate(listUsersSchema, "query"), async (req, res) => {
198
- const result = await listUsers(req.query);
199
- res.json({
200
- code: 200,
201
- data: result,
202
- msg: "\u83B7\u53D6\u6210\u529F"
203
- });
204
- });
205
- router.get("/:id", validate(userIdParamsSchema, "params"), async (req, res) => {
206
- const { id } = req.params;
207
- const result = await getUserById(id);
208
- res.json({
209
- code: 200,
210
- data: result,
211
- msg: "\u83B7\u53D6\u6210\u529F"
212
- });
213
- });
214
- router.put("/:id", validate(userIdParamsSchema, "params"), validate(updateUserSchema), async (req, res) => {
215
- const { id } = req.params;
216
- const result = await updateUser(id, req.body);
217
- res.json({
218
- code: 200,
219
- data: result,
220
- msg: "\u66F4\u65B0\u6210\u529F"
221
- });
222
- });
223
- router.delete("/:id", validate(userIdParamsSchema, "params"), async (req, res) => {
224
- const { id } = req.params;
225
- const currentUserId = res.locals.user?.id;
226
- await deleteUser(id, currentUserId);
227
- res.json({
228
- code: 200,
229
- data: true,
230
- msg: "\u5220\u9664\u6210\u529F"
231
- });
232
- });
233
- router.post("/:id/reset-password", validate(userIdParamsSchema, "params"), validate(resetPasswordSchema), async (req, res) => {
234
- const { id } = req.params;
235
- await resetUserPassword(id, req.body.newPassword);
236
- res.json({
237
- code: 200,
238
- data: true,
239
- msg: "\u5BC6\u7801\u91CD\u7F6E\u6210\u529F"
240
- });
241
- });
242
- var Users_route_default = router;
243
-
244
- // routes/Devices.route.ts
245
- import { Router as Router2 } from "express";
246
- import { eq as eq2, and as and2, desc as desc2, count as count2 } from "drizzle-orm";
247
- import { userDevices } from "@mindbase/express-auth";
248
- import { DeviceService } from "@mindbase/express-auth";
249
- import { validate as validate2 } from "@mindbase/express-common";
250
-
251
- // zod/Device.schema.ts
252
- import { z as z2 } from "zod";
253
- var deviceIdParamsSchema = z2.object({
254
- id: z2.string().min(1, "\u8BBE\u5907ID\u4E0D\u80FD\u4E3A\u7A7A")
255
- });
256
- var userIdParamsSchema2 = z2.object({
257
- userId: z2.coerce.number().int().positive("\u65E0\u6548\u7684\u7528\u6237ID")
258
- });
259
-
260
- // routes/Devices.route.ts
261
- var router2 = Router2();
262
- router2.get("/", async (req, res) => {
263
- const db = req.app.getDB();
264
- const page = parseInt(req.query.page) || 1;
265
- const pageSize = Math.min(parseInt(req.query.pageSize) || 10, 100);
266
- const userId = req.query.userId ? parseInt(req.query.userId) : void 0;
267
- const conditions = [eq2(userDevices.isExpired, 0)];
268
- if (userId) {
269
- conditions.push(eq2(userDevices.userId, userId));
270
- }
271
- const whereClause = and2(...conditions);
272
- const [{ total }] = await db.select({ total: count2() }).from(userDevices).where(whereClause).execute();
273
- const list = await db.select().from(userDevices).where(whereClause).orderBy(desc2(userDevices.createdAt)).limit(pageSize).offset((page - 1) * pageSize).execute();
274
- res.json({
275
- code: 200,
276
- data: {
277
- list,
278
- total,
279
- page,
280
- pageSize
281
- },
282
- msg: "\u83B7\u53D6\u6210\u529F"
283
- });
284
- });
285
- router2.get("/:id", validate2(deviceIdParamsSchema, "params"), async (req, res) => {
286
- const db = req.app.getDB();
287
- const { id } = req.params;
288
- const [device] = await db.select().from(userDevices).where(eq2(userDevices.id, id)).execute();
289
- if (!device) {
290
- return res.status(404).json({ code: 404, msg: "\u8BBE\u5907\u4E0D\u5B58\u5728" });
291
- }
292
- res.json({
293
- code: 200,
294
- data: device,
295
- msg: "\u83B7\u53D6\u6210\u529F"
296
- });
297
- });
298
- router2.delete("/:id", validate2(deviceIdParamsSchema, "params"), async (req, res) => {
299
- const { id } = req.params;
300
- await DeviceService.revoke(id);
301
- res.json({
302
- code: 200,
303
- data: true,
304
- msg: "\u5DF2\u5F3A\u5236\u4E0B\u7EBF\u8BE5\u8BBE\u5907"
305
- });
306
- });
307
- router2.delete("/users/:userId/devices", validate2(userIdParamsSchema2, "params"), async (req, res) => {
308
- const { userId } = req.params;
309
- const db = req.app.getDB();
310
- await db.update(userDevices).set({ isExpired: 1 }).where(and2(eq2(userDevices.userId, userId), eq2(userDevices.isExpired, 0))).execute();
311
- res.json({
312
- code: 200,
313
- data: true,
314
- msg: "\u5DF2\u4E0B\u7EBF\u8BE5\u7528\u6237\u7684\u6240\u6709\u8BBE\u5907"
315
- });
316
- });
317
- var Devices_route_default = router2;
318
-
319
- // module/AdminModule.ts
320
- import { createModule, logger } from "@mindbase/express-common";
321
- var AdminModule_default = createModule(async (app) => {
322
- const db = app.getDB();
323
- if (!db) {
324
- logger.error("[Admin] Database not found in app, skipping service initialization");
325
- return;
326
- }
327
- initUserService(db);
328
- logger.startup("\u7BA1\u7406", "\u6A21\u5757\u521D\u59CB\u5316\u5B8C\u6210");
329
- }, __filename);
330
-
331
- // index.ts
332
- var index_default = AdminModule_default;
333
- export {
334
- UserService_exports as UserService,
335
- createUserSchema,
336
- index_default as default,
337
- Devices_route_default as deviceRoutes,
338
- listUsersSchema,
339
- resetPasswordSchema,
340
- updateUserSchema,
341
- userIdParamsSchema,
342
- Users_route_default as userRoutes
343
- };
344
- //# sourceMappingURL=index.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../node_modules/tsup/assets/esm_shims.js","../service/UserService.ts","../routes/Users.route.ts","../zod/User.schema.ts","../routes/Devices.route.ts","../zod/Device.schema.ts","../module/AdminModule.ts","../index.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import { eq, and, like, or, desc, count, isNull } from \"drizzle-orm\";\nimport { users } from \"@mindbase/express-auth\";\nimport { md5 } from \"@mindbase/express-auth\";\n\nlet _db: any;\n\nexport function initUserService(db: any) {\n _db = db;\n}\n\nfunction getDB() {\n if (!_db) throw new Error(\"UserService not initialized with DB\");\n return _db;\n}\n\n/**\n * 检查用户名是否存在\n */\nexport async function checkUsernameExists(username: string, excludeId?: number): Promise<boolean> {\n const db = getDB();\n const conditions = [eq(users.username, username), isNull(users.deletedAt)];\n\n if (excludeId) {\n conditions.push(eq(users.id, excludeId));\n }\n\n const [existing] = await db\n .select({ id: users.id })\n .from(users)\n .where(and(...conditions))\n .execute();\n\n return !!existing;\n}\n\n/**\n * 创建用户(管理员)\n */\nexport async function createUser(data: {\n username: string;\n password: string;\n nickname?: string;\n status?: number;\n}) {\n const db = getDB();\n\n // 检查用户名是否已存在\n const exists = await checkUsernameExists(data.username);\n if (exists) {\n throw new Error(\"用户名已存在\");\n }\n\n const now = new Date();\n const [user] = await db\n .insert(users)\n .values({\n username: data.username,\n password: md5(data.password),\n nickname: data.nickname || data.username,\n status: data.status ?? 1,\n created: now,\n updated: now,\n })\n .returning()\n .execute();\n\n return {\n id: user.id,\n username: user.username,\n nickname: user.nickname,\n status: user.status,\n created: user.created,\n };\n}\n\n/**\n * 获取用户列表(分页、搜索)\n */\nexport async function listUsers(options: {\n page: number;\n pageSize: number;\n keyword?: string;\n status?: number;\n}) {\n const db = getDB();\n const { page, pageSize, keyword, status } = options;\n\n // 构建查询条件\n const conditions = [isNull(users.deletedAt)];\n\n if (status !== undefined) {\n conditions.push(eq(users.status, status));\n }\n\n if (keyword) {\n conditions.push(\n or(\n like(users.username, `%${keyword}%`),\n like(users.nickname, `%${keyword}%`)\n )!\n );\n }\n\n const whereClause = and(...conditions);\n\n // 查询总数\n const [{ total }] = await db\n .select({ total: count() })\n .from(users)\n .where(whereClause)\n .execute();\n\n // 查询列表\n const list = await db\n .select({\n id: users.id,\n username: users.username,\n nickname: users.nickname,\n status: users.status,\n created: users.created,\n updated: users.updated,\n })\n .from(users)\n .where(whereClause)\n .orderBy(desc(users.created))\n .limit(pageSize)\n .offset((page - 1) * pageSize)\n .execute();\n\n return {\n list,\n total,\n page,\n pageSize,\n };\n}\n\n/**\n * 根据 ID 获取用户\n */\nexport async function getUserById(id: number) {\n const db = getDB();\n\n const [user] = await db\n .select({\n id: users.id,\n username: users.username,\n nickname: users.nickname,\n status: users.status,\n created: users.created,\n updated: users.updated,\n })\n .from(users)\n .where(and(eq(users.id, id), isNull(users.deletedAt)))\n .execute();\n\n if (!user) {\n throw new Error(\"用户不存在\");\n }\n\n return user;\n}\n\n/**\n * 更新用户信息\n */\nexport async function updateUser(id: number, data: { nickname?: string; status?: number }) {\n const db = getDB();\n\n // 检查用户是否存在\n const [existing] = await db\n .select({ id: users.id })\n .from(users)\n .where(and(eq(users.id, id), isNull(users.deletedAt)))\n .execute();\n\n if (!existing) {\n throw new Error(\"用户不存在\");\n }\n\n // 更新\n const [user] = await db\n .update(users)\n .set({\n ...data,\n updated: new Date(),\n })\n .where(eq(users.id, id))\n .returning()\n .execute();\n\n return {\n id: user.id,\n username: user.username,\n nickname: user.nickname,\n status: user.status,\n updated: user.updated,\n };\n}\n\n/**\n * 删除用户(软删除)\n */\nexport async function deleteUser(id: number, currentUserId?: number) {\n const db = getDB();\n\n // 不允许删除自己\n if (currentUserId && id === currentUserId) {\n throw new Error(\"不能删除当前登录用户\");\n }\n\n // 检查用户是否存在\n const [existing] = await db\n .select({ id: users.id })\n .from(users)\n .where(and(eq(users.id, id), isNull(users.deletedAt)))\n .execute();\n\n if (!existing) {\n throw new Error(\"用户不存在\");\n }\n\n // 软删除\n await db\n .update(users)\n .set({ deletedAt: new Date() })\n .where(eq(users.id, id))\n .execute();\n\n return { success: true };\n}\n\n/**\n * 重置用户密码\n */\nexport async function resetUserPassword(id: number, newPassword: string) {\n const db = getDB();\n\n // 检查用户是否存在\n const [existing] = await db\n .select({ id: users.id })\n .from(users)\n .where(and(eq(users.id, id), isNull(users.deletedAt)))\n .execute();\n\n if (!existing) {\n throw new Error(\"用户不存在\");\n }\n\n // 更新密码\n await db\n .update(users)\n .set({\n password: md5(newPassword),\n updated: new Date(),\n })\n .where(eq(users.id, id))\n .execute();\n\n return { success: true };\n}\n","import { Router, Request, Response } from \"express\";\nimport { validate } from \"@mindbase/express-common\";\nimport * as UserService from \"../service/UserService\";\nimport { createUserSchema, listUsersSchema, updateUserSchema, resetPasswordSchema, userIdParamsSchema } from \"../zod/User.schema\";\nimport type { ApiResponse } from \"@mindbase/express-common\";\n\nconst router = Router();\n\n/**\n * 创建用户(管理员)\n * @apiParam {string} username 用户名(必填,最少4位)\n * @apiParam {string} password 密码(必填,最少6位)\n * @apiParam {string} [nickname] 昵称(可选)\n * @apiParam {number} [status] 状态(可选,0:禁用, 1:启用)\n * @apiSuccess {number} code 状态码\n * @apiSuccess {string} msg 消息\n * @apiSuccess {Object} data 用户信息\n */\nrouter.post(\"/\", validate(createUserSchema as any), async (req: Request, res: Response) => {\n const result = await UserService.createUser(req.body);\n res.json({\n code: 200,\n data: result,\n msg: \"创建成功\",\n });\n});\n\n/**\n * 获取用户列表(分页、搜索)\n * @apiParam {number} [page] 页码(可选,默认1)\n * @apiParam {number} [pageSize] 每页数量(可选,默认10,最大100)\n * @apiParam {string} [keyword] 搜索关键词(可选)\n * @apiParam {number} [status] 状态筛选(可选,0:禁用, 1:启用)\n * @apiSuccess {number} code 状态码\n * @apiSuccess {string} msg 消息\n * @apiSuccess {Object} data 用户列表\n * @apiSuccess {Object[]} data.list 用户数组\n * @apiSuccess {number} data.total 总数\n * @apiSuccess {number} data.page 当前页\n * @apiSuccess {number} data.pageSize 每页数量\n */\nrouter.get(\"/\", validate(listUsersSchema as any, \"query\"), async (req: Request, res: Response) => {\n const result = await UserService.listUsers(req.query as any);\n res.json({\n code: 200,\n data: result,\n msg: \"获取成功\",\n });\n});\n\n/**\n * 获取单个用户\n * @apiParam {number} id 用户ID(路径参数,必填)\n * @apiSuccess {number} code 状态码\n * @apiSuccess {string} msg 消息\n * @apiSuccess {Object} data 用户详情\n */\nrouter.get(\"/:id\", validate(userIdParamsSchema as any, \"params\"), async (req: Request, res: Response) => {\n const { id } = req.params as any;\n const result = await UserService.getUserById(id);\n res.json({\n code: 200,\n data: result,\n msg: \"获取成功\",\n });\n});\n\n/**\n * 更新用户信息\n * @apiParam {number} id 用户ID(路径参数,必填)\n * @apiParam {string} [nickname] 昵称(可选)\n * @apiParam {number} [status] 状态(可选,0:禁用, 1:启用)\n * @apiSuccess {number} code 状态码\n * @apiSuccess {string} msg 消息\n * @apiSuccess {Object} data 更新后的用户信息\n */\nrouter.put(\"/:id\", validate(userIdParamsSchema as any, \"params\"), validate(updateUserSchema as any), async (req: Request, res: Response) => {\n const { id } = req.params as any;\n const result = await UserService.updateUser(id, req.body);\n res.json({\n code: 200,\n data: result,\n msg: \"更新成功\",\n });\n});\n\n/**\n * 删除用户(软删除)\n * @apiParam {number} id 用户ID(路径参数,必填)\n * @apiSuccess {number} code 状态码\n * @apiSuccess {string} msg 消息\n * @apiSuccess {boolean} data 是否删除成功\n */\nrouter.delete(\"/:id\", validate(userIdParamsSchema as any, \"params\"), async (req: Request, res: Response) => {\n const { id } = req.params as any;\n const currentUserId = res.locals.user?.id;\n await UserService.deleteUser(id, currentUserId);\n\n res.json({\n code: 200,\n data: true,\n msg: \"删除成功\",\n });\n});\n\n/**\n * 重置用户密码\n * @apiParam {number} id 用户ID(路径参数,必填)\n * @apiParam {string} newPassword 新密码(必填,最少6位)\n * @apiSuccess {number} code 状态码\n * @apiSuccess {string} msg 消息\n * @apiSuccess {boolean} data 是否重置成功\n */\nrouter.post(\"/:id/reset-password\", validate(userIdParamsSchema as any, \"params\"), validate(resetPasswordSchema as any), async (req: Request, res: Response) => {\n const { id } = req.params as any;\n await UserService.resetUserPassword(id, req.body.newPassword);\n res.json({\n code: 200,\n data: true,\n msg: \"密码重置成功\",\n });\n});\n\nexport default router;\n","import { z } from \"zod\";\n\n// 创建用户(管理员)\nexport const createUserSchema = z.object({\n username: z.string().min(4, \"用户名长度不能小于4位\"),\n password: z.string().min(6, \"密码长度不能小于6位\"),\n nickname: z.string().optional(),\n status: z.number().int().min(0).max(1).optional(),\n});\n\n// 查询用户列表\nexport const listUsersSchema = z.object({\n page: z.coerce.number().int().positive().default(1),\n pageSize: z.coerce.number().int().positive().max(100).default(10),\n keyword: z.string().optional(),\n status: z.coerce.number().int().min(0).max(1).optional(),\n});\n\n// 更新用户\nexport const updateUserSchema = z.object({\n nickname: z.string().min(1, \"昵称不能为空\").optional(),\n status: z.number().int().min(0).max(1).optional(),\n});\n\n// 重置密码\nexport const resetPasswordSchema = z.object({\n newPassword: z.string().min(6, \"新密码长度不能少于6位\"),\n});\n\n// 路径参数\nexport const userIdParamsSchema = z.object({\n id: z.coerce.number().int().positive(\"无效的用户ID\"),\n});\n\n// 类型导出\nexport type CreateUserInput = z.infer<typeof createUserSchema>;\nexport type ListUsersInput = z.infer<typeof listUsersSchema>;\nexport type UpdateUserInput = z.infer<typeof updateUserSchema>;\nexport type ResetPasswordInput = z.infer<typeof resetPasswordSchema>;\n","import { Router, Request, Response } from \"express\";\nimport { eq, and, desc, count } from \"drizzle-orm\";\nimport { userDevices } from \"@mindbase/express-auth\";\nimport { DeviceService } from \"@mindbase/express-auth\";\nimport { validate } from \"@mindbase/express-common\";\nimport { deviceIdParamsSchema, userIdParamsSchema } from \"../zod/Device.schema\";\nimport type { ApiResponse } from \"@mindbase/express-common\";\n\nconst router = Router();\n\n/**\n * 获取所有设备列表(分页、按用户筛选)\n * @apiParam {number} [page] 页码(可选,默认1)\n * @apiParam {number} [pageSize] 每页数量(可选,默认10)\n * @apiParam {number} [userId] 用户ID(可选)\n * @apiSuccess {number} code 状态码\n * @apiSuccess {string} msg 消息\n * @apiSuccess {Object} data 设备列表\n * @apiSuccess {Object[]} data.list 设备数组\n * @apiSuccess {number} data.total 总数\n * @apiSuccess {number} data.page 当前页\n * @apiSuccess {number} data.pageSize 每页数量\n */\nrouter.get(\"/\", async (req: Request, res: Response) => {\n const db = req.app.getDB();\n const page = parseInt(req.query.page as string) || 1;\n const pageSize = Math.min(parseInt(req.query.pageSize as string) || 10, 100);\n const userId = req.query.userId ? parseInt(req.query.userId as string) : undefined;\n\n // 构建查询条件\n const conditions = [eq(userDevices.isExpired, 0)];\n if (userId) {\n conditions.push(eq(userDevices.userId, userId));\n }\n const whereClause = and(...conditions);\n\n // 查询总数\n const [{ total }] = await db\n .select({ total: count() })\n .from(userDevices)\n .where(whereClause)\n .execute();\n\n // 查询列表\n const list = await db\n .select()\n .from(userDevices)\n .where(whereClause)\n .orderBy(desc(userDevices.createdAt))\n .limit(pageSize)\n .offset((page - 1) * pageSize)\n .execute();\n\n res.json({\n code: 200,\n data: {\n list,\n total,\n page,\n pageSize,\n },\n msg: \"获取成功\",\n });\n});\n\n/**\n * 获取单个设备详情\n * @apiParam {string} id 设备ID(路径参数,必填)\n * @apiSuccess {number} code 状态码\n * @apiSuccess {string} msg 消息\n * @apiSuccess {Object} data 设备详情\n */\nrouter.get(\"/:id\", validate(deviceIdParamsSchema as any, \"params\"), async (req: Request, res: Response) => {\n const db = req.app.getDB();\n const { id } = req.params as any;\n\n const [device] = await db\n .select()\n .from(userDevices)\n .where(eq(userDevices.id, id))\n .execute();\n\n if (!device) {\n return res.status(404).json({ code: 404, msg: \"设备不存在\" });\n }\n\n res.json({\n code: 200,\n data: device,\n msg: \"获取成功\",\n });\n});\n\n/**\n * 强制下线指定设备\n * @apiParam {string} id 设备ID(路径参数,必填)\n * @apiSuccess {number} code 状态码\n * @apiSuccess {string} msg 消息\n * @apiSuccess {boolean} data 是否下线成功\n */\nrouter.delete(\"/:id\", validate(deviceIdParamsSchema as any, \"params\"), async (req: Request, res: Response) => {\n const { id } = req.params as any;\n await DeviceService.revoke(id);\n\n res.json({\n code: 200,\n data: true,\n msg: \"已强制下线该设备\",\n });\n});\n\n/**\n * 下线用户的所有设备\n * @apiParam {number} userId 用户ID(路径参数,必填)\n * @apiSuccess {number} code 状态码\n * @apiSuccess {string} msg 消息\n * @apiSuccess {boolean} data 是否下线成功\n */\nrouter.delete(\"/users/:userId/devices\", validate(userIdParamsSchema as any, \"params\"), async (req: Request, res: Response) => {\n const { userId } = req.params as any;\n const db = req.app.getDB();\n await db\n .update(userDevices)\n .set({ isExpired: 1 })\n .where(and(eq(userDevices.userId, userId), eq(userDevices.isExpired, 0)))\n .execute();\n\n res.json({\n code: 200,\n data: true,\n msg: \"已下线该用户的所有设备\",\n });\n});\n\nexport default router;\n","import { z } from \"zod\";\n\n// 设备ID(字符串)\nexport const deviceIdParamsSchema = z.object({\n id: z.string().min(1, \"设备ID不能为空\"),\n});\n\n// 用户ID(数字)\nexport const userIdParamsSchema = z.object({\n userId: z.coerce.number().int().positive(\"无效的用户ID\"),\n});\n\n// 类型导出\nexport type DeviceIdParams = z.infer<typeof deviceIdParamsSchema>;\nexport type UserIdParams = z.infer<typeof userIdParamsSchema>;\n","import { createModule, MindBaseApp, logger } from \"@mindbase/express-common\";\nimport * as UserService from \"../service/UserService\";\n\n/**\n * 管理模块\n */\nexport default createModule(async (app: MindBaseApp) => {\n const db = app.getDB();\n\n if (!db) {\n logger.error(\"[Admin] Database not found in app, skipping service initialization\");\n return;\n }\n\n // 初始化 UserService\n UserService.initUserService(db);\n\n logger.startup(\"管理\", \"模块初始化完成\");\n}, __filename);\n","// 核心模块\n// Service 层\nexport * as UserService from './service/UserService';\n\n// 路由\nexport { default as userRoutes } from './routes/Users.route';\nexport { default as deviceRoutes } from './routes/Devices.route';\n\n// Zod Schema\nexport {\n createUserSchema,\n listUsersSchema,\n updateUserSchema,\n resetPasswordSchema,\n userIdParamsSchema,\n type CreateUserInput,\n type ListUsersInput,\n type UpdateUserInput,\n type ResetPasswordInput,\n} from './zod/User.schema';\n\nimport AdminModule from './module/AdminModule';\nexport default AdminModule;\n"],"mappings":"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","names":["Router","eq","and","desc","count","validate","z","userIdParamsSchema","router","Router","eq","and","count","desc","validate","userIdParamsSchema"]}