yourname 5 hónapja
szülő
commit
f85f71df17

+ 20 - 0
src/server/api.ts

@@ -0,0 +1,20 @@
+import { OpenAPIHono } from '@hono/zod-openapi';
+import departmentsRoute from '@/server/api/departments/index';
+import userRoute from '@/server/api/users/index';
+import contactsRoute from '@/server/api/contacts/index';
+import contractsRoute from '@/server/api/contracts/index';
+import customersRoute from '@/server/api/customers/index';
+import leadsRoute from '@/server/api/leads/index';
+import opportunitiesRoute from '@/server/api/opportunities/index';
+import ticketsRoute from '@/server/api/tickets/index';
+
+const api = new OpenAPIHono()
+  .route('/api/v1/contacts', contactsRoute)
+  .route('/api/v1/contracts', contractsRoute)
+  .route('/api/v1/customers', customersRoute)
+  .route('/api/v1/leads', leadsRoute)
+  .route('/api/v1/opportunities', opportunitiesRoute)
+  .route('/api/v1/tickets', ticketsRoute)
+  .route('/api/v1/users', userRoute);
+
+export default api;

+ 113 - 0
src/server/api/departments/[id]/children.ts

@@ -0,0 +1,113 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { DepartmentService } from '@/server/modules/departments/department.service';
+import { DepartmentSchema } from '@/server/modules/departments/department.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 定义路径参数Schema
+const GetChildrenParams = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    description: '父部门ID',
+    example: 1
+  })
+});
+
+// 定义响应Schema
+const GetChildrenResponse = z.object({
+  code: z.number().openapi({
+    example: 200,
+    description: '状态码'
+  }),
+  message: z.string().openapi({
+    example: '子部门查询成功',
+    description: '响应消息'
+  }),
+  data: z.array(DepartmentSchema)
+});
+
+// 定义路由
+const routeDef = createRoute({
+  method: 'get',
+  path: '/{id}/children',
+  middleware: [authMiddleware],
+  request: {
+    params: GetChildrenParams
+  },
+  responses: {
+    200: {
+      description: '子部门查询成功',
+      content: {
+        'application/json': {
+          schema: GetChildrenResponse
+        }
+      }
+    },
+    400: {
+      description: '请求参数错误',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    },
+    404: {
+      description: '部门不存在',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    },
+    500: {
+      description: '服务器内部错误',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    }
+  },
+  description: '根据部门ID查询所有子部门',
+  summary: '查询子部门'
+});
+
+// 创建路由处理程序
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    // 获取路径参数
+    const { id } = c.req.valid('param');
+    
+    // 初始化服务
+    const departmentService = new DepartmentService(AppDataSource);
+    
+    // 先检查部门是否存在
+    await departmentService.findById(id);
+    
+    // 查询子部门
+    const result = await departmentService.getChildren(id);
+    
+    logger.api(`子部门查询成功: 父部门ID=${id}, 子部门数量=${result.length}`);
+    
+    return c.json({
+      code: 200,
+      message: '子部门查询成功',
+      data: result
+    } as const satisfies z.infer<typeof GetChildrenResponse>, 200);
+  } catch (error) {
+    logger.error(`子部门查询失败: 父部门ID=${c.req.param('id')}, 错误=${error instanceof Error ? error.message : String(error)}`);
+    
+    const statusCode = error instanceof Error && error.message === '部门不存在' ? 404 : 500;
+    
+    return c.json({
+      code: statusCode,
+      message: error instanceof Error ? error.message : '子部门查询失败'
+    } as const satisfies z.infer<typeof ErrorSchema>, statusCode);
+  }
+});
+
+export default app;

+ 115 - 0
src/server/api/departments/[id]/delete.ts

@@ -0,0 +1,115 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { DepartmentService } from '@/server/modules/departments/department.service';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 定义路径参数Schema
+const DeleteDepartmentParams = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    description: '部门ID',
+    example: 1
+  })
+});
+
+// 定义响应Schema
+const DeleteDepartmentResponse = z.object({
+  code: z.number().openapi({
+    example: 200,
+    description: '状态码'
+  }),
+  message: z.string().openapi({
+    example: '部门删除成功',
+    description: '响应消息'
+  }),
+  data: z.object({
+    success: z.boolean().openapi({
+      example: true,
+      description: '删除是否成功'
+    })
+  })
+});
+
+// 定义路由
+const routeDef = createRoute({
+  method: 'delete',
+  path: '/{id}',
+  middleware: [authMiddleware],
+  request: {
+    params: DeleteDepartmentParams
+  },
+  responses: {
+    200: {
+      description: '部门删除成功',
+      content: {
+        'application/json': {
+          schema: DeleteDepartmentResponse
+        }
+      }
+    },
+    400: {
+      description: '请求参数错误或业务逻辑错误',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    },
+    404: {
+      description: '部门不存在',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    },
+    500: {
+      description: '服务器内部错误',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    }
+  },
+  description: '根据ID删除部门',
+  summary: '删除部门'
+});
+
+// 创建路由处理程序
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    // 获取路径参数
+    const { id } = c.req.valid('param');
+    
+    // 初始化服务
+    const departmentService = new DepartmentService(AppDataSource);
+    
+    // 删除部门
+    const result = await departmentService.delete(id);
+    
+    logger.api(`部门删除成功: ID=${id}`);
+    
+    const response = c.json({
+      code: 200,
+      message: '部门删除成功',
+      data: result
+    } as const, 200);
+    return response;
+  } catch (error) {
+    logger.error(`部门删除失败: ID=${c.req.param('id')}, 错误=${error instanceof Error ? error.message : String(error)}`);
+    
+    const statusCode = error instanceof Error && error.message === '部门不存在' ? 404 : 400;
+    
+    return c.json({
+      code: statusCode,
+      message: error instanceof Error ? error.message : '部门删除失败'
+    }, statusCode);
+  }
+});
+
+export default app;

+ 110 - 0
src/server/api/departments/[id]/get.ts

@@ -0,0 +1,110 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { DepartmentService } from '@/server/modules/departments/department.service';
+import { DepartmentSchema } from '@/server/modules/departments/department.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 定义路径参数Schema
+const GetDepartmentParams = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    description: '部门ID',
+    example: 1
+  })
+});
+
+// 定义响应Schema
+const GetDepartmentResponse = z.object({
+  code: z.number().openapi({
+    example: 200,
+    description: '状态码'
+  }),
+  message: z.string().openapi({
+    example: '部门详情查询成功',
+    description: '响应消息'
+  }),
+  data: DepartmentSchema
+});
+
+// 定义路由
+const routeDef = createRoute({
+  method: 'get',
+  path: '/{id}',
+  middleware: [authMiddleware],
+  request: {
+    params: GetDepartmentParams
+  },
+  responses: {
+    200: {
+      description: '部门详情查询成功',
+      content: {
+        'application/json': {
+          schema: GetDepartmentResponse
+        }
+      }
+    },
+    400: {
+      description: '请求参数错误',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    },
+    404: {
+      description: '部门不存在',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    },
+    500: {
+      description: '服务器内部错误',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    }
+  },
+  description: '根据ID查询部门详情',
+  summary: '部门详情查询'
+});
+
+// 创建路由处理程序
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    // 获取路径参数
+    const { id } = c.req.valid('param');
+    
+    // 初始化服务
+    const departmentService = new DepartmentService(AppDataSource);
+    
+    // 查询部门详情
+    const result = await departmentService.findById(id);
+    
+    logger.api(`部门详情查询成功: ID=${id}`);
+    
+    return c.json({
+      code: 200,
+      message: '部门详情查询成功',
+      data: result
+    } as const, 200);
+  } catch (error) {
+    logger.error(`部门详情查询失败: ID=${c.req.param('id')}, 错误=${error instanceof Error ? error.message : String(error)}`);
+    
+    const statusCode = error instanceof Error && error.message === '部门不存在' ? 404 : 500;
+    
+    return c.json({
+      code: statusCode,
+      message: error instanceof Error ? error.message : '部门详情查询失败'
+    }, statusCode);
+  }
+});
+
+export default app;

+ 138 - 0
src/server/api/departments/[id]/put.ts

@@ -0,0 +1,138 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { DepartmentService } from '@/server/modules/departments/department.service';
+import { DepartmentSchema } from '@/server/modules/departments/department.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 定义路径参数Schema
+const UpdateDepartmentParams = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    description: '部门ID',
+    example: 1
+  })
+});
+
+// 定义更新部门请求体Schema
+const UpdateDepartmentBody = z.object({
+  name: z.string().min(1).max(50).optional().openapi({
+    description: '部门名称',
+    example: '技术研发部'
+  }),
+  parentId: z.number().int().positive().nullable().optional().openapi({
+    description: '父部门ID',
+    example: null
+  }),
+  sortOrder: z.number().int().nullable().optional().openapi({
+    description: '排序序号',
+    example: 2
+  }),
+  description: z.string().nullable().optional().openapi({
+    description: '部门描述',
+    example: '负责公司技术研发与创新工作'
+  })
+});
+
+// 定义更新部门响应Schema
+const UpdateDepartmentResponse = z.object({
+  code: z.number().openapi({
+    example: 200,
+    description: '状态码'
+  }),
+  message: z.string().openapi({
+    example: '部门更新成功',
+    description: '响应消息'
+  }),
+  data: DepartmentSchema
+});
+
+// 定义路由
+const routeDef = createRoute({
+  method: 'put',
+  path: '/{id}',
+  middleware: [authMiddleware],
+  request: {
+    params: UpdateDepartmentParams,
+    body: {
+      content: {
+        'application/json': {
+          schema: UpdateDepartmentBody
+        }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '部门更新成功',
+      content: {
+        'application/json': {
+          schema: UpdateDepartmentResponse
+        }
+      }
+    },
+    400: {
+      description: '请求参数错误',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    },
+    404: {
+      description: '部门不存在',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    },
+    500: {
+      description: '服务器内部错误',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    }
+  },
+  description: '根据ID更新部门信息',
+  summary: '更新部门'
+});
+
+// 创建路由处理程序
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    // 获取路径参数和请求体数据
+    const { id } = c.req.valid('param');
+    const body = c.req.valid('json');
+    
+    // 初始化服务
+    const departmentService = new DepartmentService(AppDataSource);
+    
+    // 更新部门
+    const result = await departmentService.update(id, body);
+    
+    logger.api(`部门更新成功: ID=${id}, 名称=${result.name}`);
+    
+    return c.json({
+      code: 200,
+      message: '部门更新成功',
+      data: result
+    } as const, 200);
+  } catch (error) {
+    logger.error(`部门更新失败: ID=${c.req.param('id')}, 错误=${error instanceof Error ? error.message : String(error)}`);
+    
+    const statusCode = error instanceof Error && error.message === '部门不存在' ? 404 : 400;
+    
+    return c.json({
+      code: statusCode,
+      message: error instanceof Error ? error.message : '部门更新失败'
+    }, statusCode);
+  }
+});
+
+export default app;

+ 130 - 0
src/server/api/departments/[id]/status.ts

@@ -0,0 +1,130 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { DepartmentService } from '@/server/modules/departments/department.service';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 定义路径参数Schema
+const UpdateStatusParams = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    description: '部门ID',
+    example: 1
+  })
+});
+
+// 定义请求体Schema
+const UpdateStatusBody = z.object({
+  status: z.coerce.number().int().min(0).max(1).openapi({
+    description: '部门状态(0-禁用, 1-启用)',
+    example: 0
+  })
+});
+
+// 定义响应Schema
+const UpdateStatusResponse = z.object({
+  code: z.number().openapi({
+    example: 200,
+    description: '状态码'
+  }),
+  message: z.string().openapi({
+    example: '部门状态更新成功',
+    description: '响应消息'
+  }),
+  data: z.object({
+    success: z.boolean().openapi({
+      example: true,
+      description: '状态更新是否成功'
+    })
+  })
+});
+
+// 定义路由
+const routeDef = createRoute({
+  method: 'patch',
+  path: '/{id}/status',
+  middleware: [authMiddleware],
+  request: {
+    params: UpdateStatusParams,
+    body: {
+      content: {
+        'application/json': {
+          schema: UpdateStatusBody
+        }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '部门状态更新成功',
+      content: {
+        'application/json': {
+          schema: UpdateStatusResponse
+        }
+      }
+    },
+    400: {
+      description: '请求参数错误',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    },
+    404: {
+      description: '部门不存在',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    },
+    500: {
+      description: '服务器内部错误',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    }
+  },
+  description: '更新部门状态(启用/禁用)',
+  summary: '更新部门状态'
+});
+
+// 创建路由处理程序
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    // 获取路径参数和请求体数据
+    const { id } = c.req.valid('param');
+    const { status } = c.req.valid('json');
+    
+    // 初始化服务
+    const departmentService = new DepartmentService(AppDataSource);
+    
+    // 更新部门状态
+    const result = await departmentService.updateStatus(id, status);
+    
+    logger.api(`部门状态更新成功: ID=${id}, 新状态=${status}`);
+    
+    return c.json({
+      code: 200,
+      message: status === 1 ? '部门启用成功' : '部门禁用成功',
+      data: result
+    } as const, 200);
+  } catch (error) {
+    logger.error(`部门状态更新失败: ID=${c.req.param('id')}, 错误=${error instanceof Error ? error.message : String(error)}`);
+    
+    const statusCode = error instanceof Error && error.message === '部门不存在' ? 404 : 400;
+    
+    return c.json({
+      code: statusCode,
+      message: error instanceof Error ? error.message : '部门状态更新失败'
+    }, statusCode);
+  }
+});
+
+export default app;

+ 143 - 0
src/server/api/departments/get.ts

@@ -0,0 +1,143 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { DepartmentService } from '@/server/modules/departments/department.service';
+import { DepartmentSchema } from '@/server/modules/departments/department.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 创建统一API响应格式Schema
+const DepartmentListResponse = z.object({
+  code: z.number().openapi({
+    example: 200,
+    description: '状态码'
+  }),
+  message: z.string().openapi({
+    example: '部门列表查询成功',
+    description: '响应消息'
+  }),
+  data: z.object({
+    data: z.array(DepartmentSchema),
+    pagination: z.object({
+      total: z.number().openapi({
+        example: 100,
+        description: '总记录数'
+      }),
+      current: z.number().openapi({
+        example: 1,
+        description: '当前页码'
+      }),
+      pageSize: z.number().openapi({
+        example: 10,
+        description: '每页数量'
+      }),
+      totalPages: z.number().openapi({
+        example: 10,
+        description: '总页数'
+      })
+    })
+  })
+});
+
+// 定义查询参数Schema
+const DepartmentQueryParams = z.object({
+  name: z.string().optional().openapi({
+    description: '部门名称筛选',
+    example: '销售'
+  }),
+  status: z.coerce.number().int().min(0).max(1).optional().openapi({
+    description: '部门状态(0-禁用, 1-启用)',
+    example: 1
+  }),
+  parentId: z.coerce.number().int().nullable().optional().openapi({
+    description: '父部门ID',
+    example: null
+  }),
+  page: z.coerce.number().int().positive().default(1).openapi({
+    description: '页码',
+    example: 1
+  }),
+  pageSize: z.coerce.number().int().positive().default(10).openapi({
+    description: '每页条数',
+    example: 10
+  }),
+  sortBy: z.string().default('sortOrder').openapi({
+    description: '排序字段',
+    example: 'sortOrder'
+  }),
+  sortOrder: z.enum(['asc', 'desc']).default('asc').openapi({
+    description: '排序方向',
+    example: 'asc'
+  })
+});
+
+// 定义路由
+const routeDef = createRoute({
+  method: 'get',
+  path: '/',
+  middleware: [authMiddleware],
+  request: {
+    query: DepartmentQueryParams
+  },
+  responses: {
+    200: {
+      description: '部门列表查询成功',
+      content: {
+        'application/json': {
+          schema: DepartmentListResponse
+        }
+      }
+    },
+    400: {
+      description: '请求参数错误',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    },
+    500: {
+      description: '服务器内部错误',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    }
+  },
+  description: '获取部门列表,支持分页、筛选和排序',
+  summary: '部门列表查询'
+});
+
+// 创建路由处理程序
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    // 获取查询参数
+    const query = c.req.valid('query');
+    
+    // 初始化服务
+    const departmentService = new DepartmentService(AppDataSource);
+    
+    // 查询部门列表
+    const result = await departmentService.findAll(query);
+    
+    logger.api(`部门列表查询成功: 页码=${query.page}, 每页条数=${query.pageSize}`);
+    
+    return c.json({
+      code: 200,
+      message: '部门列表查询成功',
+      data: result
+    } as const, 200);
+  } catch (error) {
+    logger.error(`部门列表查询失败: ${error instanceof Error ? error.message : String(error)}`);
+    
+    return c.json({
+      code: 500,
+      message: error instanceof Error ? error.message : '部门列表查询失败'
+    }, 500);
+  }
+});
+
+export default app;

+ 23 - 0
src/server/api/departments/index.ts

@@ -0,0 +1,23 @@
+import { OpenAPIHono } from '@hono/zod-openapi';
+import { AuthContext } from '@/server/types/context';
+
+// 导入路由处理程序
+import listRoute from './get';
+import createRoute from './post';
+import getByIdRoute from './[id]/get';
+import updateRoute from './[id]/put';
+import deleteRoute from './[id]/delete';
+import statusRoute from './[id]/status';
+import childrenRoute from './[id]/children';
+
+// 创建路由聚合应用
+const app = new OpenAPIHono<AuthContext>()
+  .route('/', listRoute)       // GET /departments
+  .route('/', createRoute)     // POST /departments
+  .route('/', getByIdRoute)    // GET /departments/{id}
+  .route('/', updateRoute)     // PUT /departments/{id}
+  .route('/', deleteRoute)     // DELETE /departments/{id}
+  .route('/', statusRoute)     // PATCH /departments/{id}/status
+  .route('/', childrenRoute);  // GET /departments/{id}/children
+
+export default app;

+ 117 - 0
src/server/api/departments/post.ts

@@ -0,0 +1,117 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { DepartmentService } from '@/server/modules/departments/department.service';
+import { DepartmentSchema } from '@/server/modules/departments/department.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 定义创建部门请求体Schema
+const CreateDepartmentBody = z.object({
+  name: z.string().min(1).max(50).openapi({
+    description: '部门名称',
+    example: '技术部'
+  }),
+  parentId: z.number().int().positive().nullable().openapi({
+    description: '父部门ID',
+    example: null
+  }),
+  sortOrder: z.number().int().nullable().openapi({
+    description: '排序序号',
+    example: 2
+  }),
+  description: z.string().nullable().openapi({
+    description: '部门描述',
+    example: '负责公司技术研发工作'
+  })
+});
+
+// 定义创建部门响应Schema
+const CreateDepartmentResponse = z.object({
+  code: z.number().openapi({
+    example: 200,
+    description: '状态码'
+  }),
+  message: z.string().openapi({
+    example: '部门创建成功',
+    description: '响应消息'
+  }),
+  data: DepartmentSchema
+});
+
+// 定义路由
+const routeDef = createRoute({
+  method: 'post',
+  path: '/',
+  middleware: [authMiddleware],
+  request: {
+    body: {
+      content: {
+        'application/json': {
+          schema: CreateDepartmentBody
+        }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '部门创建成功',
+      content: {
+        'application/json': {
+          schema: CreateDepartmentResponse
+        }
+      }
+    },
+    400: {
+      description: '请求参数错误',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    },
+    500: {
+      description: '服务器内部错误',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    }
+  },
+  description: '创建新部门',
+  summary: '创建部门'
+});
+
+// 创建路由处理程序
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    // 获取请求体数据
+    const body = c.req.valid('json');
+    
+    // 初始化服务
+    const departmentService = new DepartmentService(AppDataSource);
+    
+    // 创建部门
+    const result = await departmentService.create(body);
+    
+    logger.api(`部门创建成功: ID=${result.id}, 名称=${result.name}`);
+    
+    return c.json({
+      code: 200,
+      message: '部门创建成功',
+      data: result
+    } as const, 200);
+  } catch (error) {
+    logger.error(`部门创建失败: ${error instanceof Error ? error.message : String(error)}`);
+    
+    return c.json({
+      code: 400,
+      message: error instanceof Error ? error.message : '部门创建失败'
+    }, 400);
+  }
+});
+
+export default app;

+ 102 - 0
src/server/api/tickets/[id]/assign.ts

@@ -0,0 +1,102 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { TicketService } from '@/server/modules/tickets/ticket.service';
+import { TicketSchema } from '@/server/modules/tickets/ticket.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 初始化服务
+const ticketService = new TicketService(AppDataSource);
+
+// 路径参数Schema
+const ParamsSchema = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    example: 1,
+    description: '工单ID'
+  })
+});
+
+// 请求体Schema
+const AssignSchema = z.object({
+  assigneeId: z.coerce.number().int().positive().openapi({
+    example: 2,
+    description: '处理人用户ID'
+  })
+});
+
+// 响应Schema
+const ResponseSchema = z.object({
+  code: z.number().openapi({ example: 200, description: '状态码' }),
+  message: z.string().openapi({ example: '工单分配成功', description: '消息' }),
+  data: TicketSchema
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'patch',
+  path: '/{id}/assign',
+  middleware: [authMiddleware],
+  request: {
+    params: ParamsSchema,
+    body: {
+      content: {
+        'application/json': { schema: AssignSchema }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '成功分配工单',
+      content: {
+        'application/json': { schema: ResponseSchema }
+      }
+    },
+    404: {
+      description: '工单不存在',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    500: {
+      description: '服务器错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    }
+  }
+});
+
+// 创建路由实例
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  const { id } = c.req.valid('param');
+  try {
+    const body = c.req.valid('json');
+    
+    // 分配工单
+    const updatedTicket = await ticketService.assign(id, body.assigneeId);
+    if (!updatedTicket) {
+      return c.json({
+        code: 404,
+        message: '工单不存在'
+      }, 404);
+    }
+    
+    return c.json({
+      code: 200,
+      message: '工单分配成功',
+      data: updatedTicket
+    }, 200);
+  } catch (error) {
+    logger.error(`Error assigning ticket ${id}:`, error);
+    return c.json({
+      code: 500,
+      message: error instanceof Error ? error.message : '分配工单失败'
+    }, 500);
+  }
+});
+
+export default app;

+ 95 - 0
src/server/api/tickets/[id]/delete.ts

@@ -0,0 +1,95 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { TicketService } from '@/server/modules/tickets/ticket.service';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 初始化服务
+const ticketService = new TicketService(AppDataSource);
+
+// 路径参数Schema
+const ParamsSchema = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    example: 1,
+    description: '工单ID'
+  })
+});
+
+// 响应Schema
+const ResponseSchema = z.object({
+  code: z.number().openapi({ example: 200, description: '状态码' }),
+  message: z.string().openapi({ example: '工单删除成功', description: '消息' }),
+  data: z.object({
+    success: z.boolean().openapi({ example: true, description: '删除是否成功' })
+  })
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'delete',
+  path: '/{id}',
+  middleware: [authMiddleware],
+  request: {
+    params: ParamsSchema
+  },
+  responses: {
+    200: {
+      description: '成功删除工单',
+      content: {
+        'application/json': { schema: ResponseSchema }
+      }
+    },
+    404: {
+      description: '工单不存在',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    500: {
+      description: '服务器错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    }
+  }
+});
+
+// 创建路由实例
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+    let id: number;
+    try {
+        const params = c.req.valid('param');
+        id = params.id;
+    const { id } = c.req.valid('param');
+    try {
+    
+    // 删除工单
+    const deleted = await ticketService.delete(id);
+    if (!deleted) {
+      return c.json({
+        code: 404,
+        message: '工单不存在'
+      }, 404);
+    }
+    
+    return c.json({
+      code: 200,
+      message: '工单删除成功',
+      data: { success: true }
+    }, 200);
+  } catch (error) {
+    logger.error(`Error deleting ticket ${id}:`, error);
+    return c.json({
+        code: 500,
+        message: error instanceof Error ? error.message : '删除工单失败'
+    }, 500);
+  }
+    }, 500);
+  }
+});
+
+export default app;

+ 88 - 0
src/server/api/tickets/[id]/get.ts

@@ -0,0 +1,88 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { TicketService } from '@/server/modules/tickets/ticket.service';
+import { TicketSchema } from '@/server/modules/tickets/ticket.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 初始化服务
+const ticketService = new TicketService(AppDataSource);
+
+// 路径参数Schema
+const ParamsSchema = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    example: 1,
+    description: '工单ID'
+  })
+});
+
+// 响应Schema
+const ResponseSchema = z.object({
+  code: z.number().openapi({ example: 200, description: '状态码' }),
+  message: z.string().openapi({ example: 'success', description: '消息' }),
+  data: TicketSchema
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'get',
+  path: '/{id}',
+  middleware: [authMiddleware],
+  request: {
+    params: ParamsSchema
+  },
+  responses: {
+    200: {
+      description: '成功获取工单详情',
+      content: {
+        'application/json': { schema: ResponseSchema }
+      }
+    },
+    404: {
+      description: '工单不存在',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    500: {
+      description: '服务器错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    }
+  }
+});
+
+// 创建路由实例
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c): Promise<Response> => {
+  try {
+    const { id } = c.req.valid('param');
+    
+    // 获取工单详情
+    const ticket = await ticketService.findById(id);
+    if (!ticket) {
+      return c.json({
+        code: 404,
+        message: '工单不存在'
+      }, 404);
+    }
+    
+    return c.json({
+      code: 200,
+      message: 'success',
+      data: ticket
+    }, 200);
+  } catch (error) {
+    logger.error(`Error fetching ticket ${id}:`, error);
+    return c.json({
+      code: 500,
+      message: error instanceof Error ? error.message : '获取工单详情失败'
+    }, 500);
+  }
+});
+
+export default app;

+ 121 - 0
src/server/api/tickets/[id]/put.ts

@@ -0,0 +1,121 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { TicketService } from '@/server/modules/tickets/ticket.service';
+import { TicketSchema } from '@/server/modules/tickets/ticket.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 初始化服务
+const ticketService = new TicketService(AppDataSource);
+
+// 路径参数Schema
+const ParamsSchema = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    example: 1,
+    description: '工单ID'
+  })
+});
+
+// 更新工单请求Schema
+const UpdateTicketSchema = z.object({
+  title: z.string().min(3).max(255).optional().openapi({
+    example: '系统登录异常 - 更新',
+    description: '工单标题'
+  }),
+  description: z.string().min(10).optional().openapi({
+    example: '用户报告无法登录系统,提示密码错误,但确认密码正确。已尝试重置密码。',
+    description: '工单描述'
+  }),
+  priority: z.enum(['0', '1', '2', '3']).optional().openapi({
+    example: '2',
+    description: '工单优先级(0:低, 1:中, 2:高, 3:紧急)'
+  }),
+  type: z.string().optional().openapi({
+    example: 'login',
+    description: '工单类型'
+  })
+});
+
+// 响应Schema
+const ResponseSchema = z.object({
+  code: z.number().openapi({ example: 200, description: '状态码' }),
+  message: z.string().openapi({ example: '工单更新成功', description: '消息' }),
+  data: TicketSchema
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'put',
+  path: '/{id}',
+  middleware: [authMiddleware],
+  request: {
+    params: ParamsSchema,
+    body: {
+      content: {
+        'application/json': { schema: UpdateTicketSchema }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '成功更新工单',
+      content: {
+        'application/json': { schema: ResponseSchema }
+      }
+    },
+    404: {
+      description: '工单不存在',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    500: {
+      description: '服务器错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    }
+  }
+});
+
+// 创建路由实例
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    const { id } = c.req.valid('param');
+    const body = c.req.valid('json');
+    
+    // 构建更新数据
+    const updateData: Partial<any> = {};
+    if (body.title !== undefined) updateData.title = body.title;
+    if (body.description !== undefined) updateData.description = body.description;
+    if (body.priority !== undefined) updateData.priority = parseInt(body.priority, 10);
+    if (body.type !== undefined) updateData.type = body.type;
+    
+    // 更新工单
+    const updatedTicket = await ticketService.update(id, updateData);
+    if (!updatedTicket) {
+      return c.json({
+        code: 404,
+        message: '工单不存在'
+      }, 404);
+    }
+    
+    return c.json({
+      code: 200,
+      message: '工单更新成功',
+      data: updatedTicket
+    }, 200);
+  } catch (error) {
+    logger.error(`Error updating ticket ${id}:`, error);
+    return c.json({
+      code: 500,
+      message: error instanceof Error ? error.message : '更新工单失败'
+    }, 500);
+  }
+});
+
+export default app;

+ 130 - 0
src/server/api/tickets/[id]/status.ts

@@ -0,0 +1,130 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { TicketService } from '@/server/modules/tickets/ticket.service';
+import { TicketSchema } from '@/server/modules/tickets/ticket.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 初始化服务
+const ticketService = new TicketService(AppDataSource);
+
+// 路径参数Schema
+const ParamsSchema = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    example: 1,
+    description: '工单ID'
+  })
+});
+
+// 请求体Schema
+const StatusChangeSchema = z.object({
+  status: z.coerce.number().int().min(0).max(5).openapi({
+    example: 1,
+    description: '工单状态码(0:新建, 1:处理中, 2:待处理, 3:已解决, 4:已关闭, 5:已重新打开)'
+  }),
+  comment: z.string().optional().openapi({
+    example: '问题已解决,用户确认可以正常使用',
+    description: '状态变更备注'
+  })
+});
+
+// 响应Schema
+const ResponseSchema = z.object({
+  code: z.number().openapi({ example: 200, description: '状态码' }),
+  message: z.string().openapi({ example: '工单状态更新成功', description: '消息' }),
+  data: TicketSchema
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'patch',
+  path: '/{id}/status',
+  middleware: [authMiddleware],
+  request: {
+    params: ParamsSchema,
+    body: {
+      content: {
+        'application/json': { schema: StatusChangeSchema }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '成功更新工单状态',
+      content: {
+        'application/json': { schema: ResponseSchema }
+      }
+    },
+    400: {
+      description: '无效的状态变更',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    404: {
+      description: '工单不存在',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    500: {
+      description: '服务器错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    }
+  }
+});
+
+// 创建路由实例
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    const { id } = c.req.valid('param');
+    const body = c.req.valid('json');
+    
+    // 状态映射表 - 将数字状态码转换为字符串
+    const statusMap: Record<number, string> = {
+      0: 'new',
+      1: 'in_progress',
+      2: 'pending',
+      3: 'resolved',
+      4: 'closed',
+      5: 'reopened'
+    };
+    
+    const statusString = statusMap[body.status];
+    if (!statusString) {
+      return c.json({
+        code: 400,
+        message: '无效的工单状态码'
+      }, 400);
+    }
+    
+    // 更改工单状态
+    const updatedTicket = await ticketService.changeStatus(id, statusString);
+    if (!updatedTicket) {
+      return c.json({
+        code: 404,
+        message: '工单不存在'
+      }, 404);
+    }
+    
+    return c.json({
+      code: 200,
+      message: '工单状态更新成功',
+      data: updatedTicket
+    }, 200);
+  } catch (error) {
+    logger.error(`Error changing ticket ${id} status:`, error);
+    return c.json({
+      code: 400,
+      message: error instanceof Error ? error.message : '更新工单状态失败'
+    }, 400);
+  }
+});
+
+export default app;

+ 142 - 0
src/server/api/tickets/get.ts

@@ -0,0 +1,142 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { TicketService } from '@/server/modules/tickets/ticket.service';
+import { TicketSchema } from '@/server/modules/tickets/ticket.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 初始化服务
+const ticketService = new TicketService(AppDataSource);
+
+// 查询参数Schema
+const QuerySchema = z.object({
+  page: z.coerce.number().int().positive().default(1).openapi({
+    example: 1,
+    description: '页码'
+  }),
+  pageSize: z.coerce.number().int().positive().default(10).openapi({
+    example: 10,
+    description: '每页数量'
+  }),
+  status: z.coerce.number().optional().openapi({
+    example: 1,
+    description: '工单状态码'
+  }),
+  priority: z.coerce.number().optional().openapi({
+    example: 2,
+    description: '工单优先级码'
+  }),
+  assigneeId: z.coerce.number().int().positive().optional().openapi({
+    example: 1,
+    description: '处理人ID'
+  }),
+  customerId: z.coerce.number().int().positive().optional().openapi({
+    example: 1,
+    description: '客户ID'
+  }),
+  sortField: z.string().optional().openapi({
+    example: 'createdAt',
+    description: '排序字段'
+  }),
+  sortOrder: z.enum(['asc', 'desc']).optional().openapi({
+    example: 'desc',
+    description: '排序方向'
+  })
+});
+
+// 响应Schema
+const ResponseSchema = z.object({
+  code: z.number().openapi({ example: 200, description: '状态码' }),
+  message: z.string().openapi({ example: 'success', description: '消息' }),
+  data: z.object({
+    list: z.array(TicketSchema),
+    pagination: z.object({
+      total: z.number().openapi({ example: 100, description: '总记录数' }),
+      current: z.number().openapi({ example: 1, description: '当前页码' }),
+      pageSize: z.number().openapi({ example: 10, description: '每页数量' }),
+      totalPages: z.number().openapi({ example: 10, description: '总页数' })
+    })
+  })
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'get',
+  path: '/',
+  middleware: [authMiddleware],
+  request: {
+    query: QuerySchema
+  },
+  responses: {
+    200: {
+      description: '成功获取工单列表',
+      content: {
+        'application/json': { schema: ResponseSchema }
+      }
+    },
+    400: {
+      description: '请求参数错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    500: {
+      description: '服务器错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    }
+  }
+});
+
+// 创建路由实例
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    const query = c.req.valid('query');
+    
+    // 构建筛选条件
+    const filters: any = {};
+    if (query.status !== undefined) filters.status = query.status;
+    if (query.priority !== undefined) filters.priority = query.priority;
+    if (query.assigneeId !== undefined) filters.assigneeId = query.assigneeId;
+    if (query.customerId !== undefined) filters.customerId = query.customerId;
+    
+    // 构建排序条件
+    const sort: any = {};
+    if (query.sortField) sort.field = query.sortField;
+    if (query.sortOrder) sort.order = query.sortOrder;
+    
+    // 获取工单列表
+    const { data, total } = await ticketService.findAll(
+      query.page,
+      query.pageSize,
+      filters,
+      sort
+    );
+    
+    return c.json({
+      code: 200,
+      message: 'success',
+      data: {
+        list: data,
+        pagination: {
+          total,
+          current: query.page,
+          pageSize: query.pageSize,
+          totalPages: Math.ceil(total / query.pageSize)
+        }
+      }
+    }, 200);
+  } catch (error) {
+    logger.error('Error fetching tickets:', error);
+    return c.json({
+      code: 500,
+      message: error instanceof Error ? error.message : '获取工单列表失败'
+    }, 500);
+  }
+});
+
+export default app;

+ 19 - 0
src/server/api/tickets/index.ts

@@ -0,0 +1,19 @@
+import { OpenAPIHono } from '@hono/zod-openapi';
+import listRoute from './get';
+import createRoute from './post';
+import getByIdRoute from './[id]/get';
+import updateRoute from './[id]/put';
+import deleteRoute from './[id]/delete';
+import statusRoute from './[id]/status';
+import assignRoute from './[id]/assign';
+
+const app = new OpenAPIHono()
+  .route('/', listRoute)
+  .route('/', createRoute)
+  .route('/', getByIdRoute)
+  .route('/', updateRoute)
+  .route('/', deleteRoute)
+  .route('/', statusRoute)
+  .route('/', assignRoute);
+
+export default app;

+ 114 - 0
src/server/api/tickets/post.ts

@@ -0,0 +1,114 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { TicketService } from '@/server/modules/tickets/ticket.service';
+import { TicketSchema } from '@/server/modules/tickets/ticket.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 初始化服务
+const ticketService = new TicketService(AppDataSource);
+
+// 创建工单请求Schema
+const CreateTicketSchema = z.object({
+  title: z.string().min(3).max(255).openapi({
+    example: '系统登录异常',
+    description: '工单标题'
+  }),
+  description: z.string().min(10).openapi({
+    example: '用户报告无法登录系统,提示密码错误,但确认密码正确',
+    description: '工单描述'
+  }),
+  customerId: z.number().int().positive().openapi({
+    example: 1,
+    description: '客户ID'
+  }),
+  priority: z.enum(['0', '1', '2', '3']).default('1').openapi({
+    example: '2',
+    description: '工单优先级(0:低, 1:中, 2:高, 3:紧急)'
+  }),
+  type: z.string().optional().openapi({
+    example: 'login',
+    description: '工单类型'
+  }),
+  relatedAsset: z.string().optional().openapi({
+    example: 'server-01',
+    description: '相关资产'
+  })
+});
+
+// 响应Schema
+const ResponseSchema = z.object({
+  code: z.number().openapi({ example: 200, description: '状态码' }),
+  message: z.string().openapi({ example: '工单创建成功', description: '消息' }),
+  data: TicketSchema
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'post',
+  path: '/',
+  middleware: [authMiddleware],
+  request: {
+    body: {
+      content: {
+        'application/json': { schema: CreateTicketSchema }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '成功创建工单',
+      content: {
+        'application/json': { schema: ResponseSchema }
+      }
+    },
+    400: {
+      description: '请求参数错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    500: {
+      description: '服务器错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    }
+  }
+});
+
+// 创建路由实例
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    const body = c.req.valid('json');
+    const user = c.get('user');
+    
+    // 创建工单
+    const ticket = await ticketService.create({
+      title: body.title,
+      description: body.description,
+      customerId: body.customerId,
+      priority: parseInt(body.priority, 10),
+      type: body.type,
+      createdBy: user.id,
+      status: 0 // 0表示新建状态
+    });
+    
+    return c.json({
+      code: 200,
+      message: '工单创建成功',
+      data: ticket
+    }, 200);
+  } catch (error) {
+    logger.error('Error creating ticket:', error);
+    return c.json({
+      code: 500,
+      message: error instanceof Error ? error.message : '创建工单失败'
+    }, 500);
+  }
+});
+
+export default app;

+ 127 - 0
src/server/api/users/[id]/delete.ts

@@ -0,0 +1,127 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { UserService } from '@/server/modules/users/user.service';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 初始化用户服务
+const userService = new UserService(AppDataSource);
+
+// 路径参数Schema
+const DeleteUserParams = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    description: '用户ID',
+    example: 1
+  })
+});
+
+// 响应Schema
+const DeleteUserResponse = z.object({
+  code: z.number().openapi({ example: 200 }),
+  message: z.string().openapi({ example: '用户删除成功' }),
+  data: z.object({
+    success: z.boolean().openapi({ example: true })
+  })
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'delete',
+  path: '/{id}',
+  middleware: [authMiddleware],
+  request: {
+    params: DeleteUserParams
+  },
+  responses: {
+    200: {
+      description: '用户删除成功',
+      content: {
+        'application/json': { schema: DeleteUserResponse }
+      }
+    },
+    400: {
+      description: '请求参数错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    401: {
+      description: '未授权',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    403: {
+      description: '权限不足',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    404: {
+      description: '用户不存在',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    500: {
+      description: '服务器内部错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    }
+  },
+  tags: ['用户管理']
+});
+
+// 创建路由实例
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    // 获取当前用户
+    const currentUser = c.get('user');
+    if (!currentUser) {
+      logger.error('未获取到用户信息');
+      return c.json({ code: 401, message: '未授权' }, 401);
+    }
+
+    // 检查是否为管理员
+    const isAdmin = await userService.isAdmin(currentUser.id);
+    if (!isAdmin) {
+      logger.error('用户 %d 权限不足,无法删除用户', currentUser.id);
+      return c.json({ code: 403, message: '权限不足,仅管理员可操作' }, 403);
+    }
+
+    // 获取路径参数
+    const { id } = c.req.valid('param');
+    
+    // 防止删除自己
+    if (currentUser.id === id) {
+      logger.error('用户 %d 尝试删除自己', currentUser.id);
+      return c.json({ code: 400, message: '不能删除自己的账户' }, 400);
+    }
+
+    // 删除用户
+    logger.api('用户 %d 删除用户 %d', currentUser.id, id);
+    const result = await userService.remove(id);
+    
+    return c.json({
+      code: 200,
+      message: '用户删除成功',
+      data: result
+    } satisfies z.infer<typeof DeleteUserResponse>, 200);
+  } catch (error) {
+    logger.error('删除用户失败: %o', error);
+    const message = error instanceof Error ? error.message : '删除用户失败';
+    const statusCode = message.includes('不存在') ? 404 : 500;
+    
+    return c.json({
+      code: statusCode,
+      message
+    }, statusCode);
+  }
+});
+
+export default app;

+ 122 - 0
src/server/api/users/[id]/get.ts

@@ -0,0 +1,122 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { UserService } from '@/server/modules/users/user.service';
+import { UserSchema } from '@/server/modules/users/user.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 初始化用户服务
+const userService = new UserService(AppDataSource);
+
+// 路径参数Schema
+const GetUserParams = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    description: '用户ID',
+    example: 1
+  })
+});
+
+// 响应Schema
+const GetUserResponse = z.object({
+  code: z.number().openapi({ example: 200 }),
+  message: z.string().openapi({ example: 'success' }),
+  data: UserSchema
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'get',
+  path: '/{id}',
+  middleware: [authMiddleware],
+  request: {
+    params: GetUserParams
+  },
+  responses: {
+    200: {
+      description: '成功获取用户详情',
+      content: {
+        'application/json': { schema: GetUserResponse }
+      }
+    },
+    400: {
+      description: '请求参数错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    401: {
+      description: '未授权',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    403: {
+      description: '权限不足',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    404: {
+      description: '用户不存在',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    500: {
+      description: '服务器内部错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    }
+  },
+  tags: ['用户管理']
+});
+
+// 创建路由实例
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    // 获取当前用户
+    const currentUser = c.get('user');
+    if (!currentUser) {
+      logger.error('未获取到用户信息');
+      return c.json({ code: 401, message: '未授权' }, 401);
+    }
+
+    // 获取路径参数
+    const { id } = c.req.valid('param');
+    
+    // 检查权限:管理员可以查看所有用户,普通用户只能查看自己
+    const isAdmin = await userService.isAdmin(currentUser.id);
+    if (!isAdmin && currentUser.id !== id) {
+      logger.error('用户 %d 权限不足,无法查看用户 %d 的详情', currentUser.id, id);
+      return c.json({ code: 403, message: '权限不足' }, 403);
+    }
+
+    // 查询用户详情
+    logger.api('用户 %d 查询用户 %d 详情', currentUser.id, id);
+    const user = await userService.findOne(id);
+    
+    const response: z.infer<typeof GetUserResponse> = {
+      code: 200,
+      message: 'success',
+      data: user
+    };
+    return c.json(response, 200);
+  } catch (error) {
+    logger.error('获取用户详情失败: %o', error);
+    const message = error instanceof Error ? error.message : '获取用户详情失败';
+    const statusCode = message.includes('不存在') ? 404 : 500;
+    
+    const errorResponse = {
+      code: statusCode,
+      message
+    };
+    return c.json(errorResponse, statusCode);
+  }
+});
+
+export default app;

+ 135 - 0
src/server/api/users/[id]/password.ts

@@ -0,0 +1,135 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { UserService } from '@/server/modules/users/user.service';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 初始化用户服务
+const userService = new UserService(AppDataSource);
+
+// 路径参数Schema
+const ResetPasswordParams = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    description: '用户ID',
+    example: 1
+  })
+});
+
+// 请求体Schema
+const ResetPasswordBody = z.object({
+  newPassword: z.string().min(6).openapi({
+    description: '新密码,至少6位',
+    example: 'newpassword123'
+  })
+});
+
+// 响应Schema
+const ResetPasswordResponse = z.object({
+  code: z.number().openapi({ example: 200 }),
+  message: z.string().openapi({ example: '密码重置成功' }),
+  data: z.object({
+    success: z.boolean().openapi({ example: true })
+  })
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'patch',
+  path: '/{id}/password',
+  middleware: [authMiddleware],
+  request: {
+    params: ResetPasswordParams,
+    body: {
+      content: {
+        'application/json': { schema: ResetPasswordBody }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '密码重置成功',
+      content: {
+        'application/json': { schema: ResetPasswordResponse }
+      }
+    },
+    400: {
+      description: '请求参数错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    401: {
+      description: '未授权',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    403: {
+      description: '权限不足',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    404: {
+      description: '用户不存在',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    500: {
+      description: '服务器内部错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    }
+  },
+  tags: ['用户管理']
+});
+
+// 创建路由实例
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    // 获取当前用户
+    const currentUser = c.get('user');
+    if (!currentUser) {
+      logger.error('未获取到用户信息');
+      return c.json({ code: 401, message: '未授权' }, 401);
+    }
+
+    // 检查是否为管理员
+    const isAdmin = await userService.isAdmin(currentUser.id);
+    if (!isAdmin) {
+      logger.error('用户 %d 权限不足,无法重置密码', currentUser.id);
+      return c.json({ code: 403, message: '权限不足,仅管理员可操作' }, 403);
+    }
+
+    // 获取路径参数和请求数据
+    const { id } = c.req.valid('param');
+    const { newPassword } = c.req.valid('json');
+    
+    // 重置密码
+    logger.api('用户 %d 重置用户 %d 的密码', currentUser.id, id);
+    const result = await userService.resetPassword(id, newPassword);
+    
+    return c.json({
+      code: 200,
+      message: '密码重置成功',
+      data: result
+    } satisfies z.infer<typeof ResetPasswordResponse>, 200);
+  } catch (error) {
+    logger.error('重置密码失败: %o', error);
+    const message = error instanceof Error ? error.message : '重置密码失败';
+    const statusCode = message.includes('不存在') ? 404 : 500;
+    
+    return c.json({
+      code: statusCode,
+      message
+    }, statusCode);
+  }
+});
+
+export default app;

+ 136 - 0
src/server/api/users/[id]/put.ts

@@ -0,0 +1,136 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { UserService } from '@/server/modules/users/user.service';
+import { UserSchema } from '@/server/modules/users/user.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 初始化用户服务
+const userService = new UserService(AppDataSource);
+
+// 路径参数Schema
+const UpdateUserParams = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    description: '用户ID',
+    example: 1
+  })
+});
+
+// 更新用户请求Schema
+const UpdateUserSchema = UserSchema.omit({
+  id: true,
+  createdAt: true,
+  updatedAt: true,
+  isDeleted: true,
+  password: true
+}).partial();
+
+// 响应Schema
+const UpdateUserResponse = z.object({
+  code: z.number().openapi({ example: 200 }),
+  message: z.string().openapi({ example: '用户更新成功' }),
+  data: UserSchema
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'put',
+  path: '/{id}',
+  middleware: [authMiddleware],
+  request: {
+    params: UpdateUserParams,
+    body: {
+      content: {
+        'application/json': { schema: UpdateUserSchema }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '用户更新成功',
+      content: {
+        'application/json': { schema: UpdateUserResponse }
+      }
+    },
+    400: {
+      description: '请求参数错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    401: {
+      description: '未授权',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    403: {
+      description: '权限不足',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    404: {
+      description: '用户不存在',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    500: {
+      description: '服务器内部错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    }
+  },
+  tags: ['用户管理']
+});
+
+// 创建路由实例
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    // 获取当前用户
+    const currentUser = c.get('user');
+    if (!currentUser) {
+      logger.error('未获取到用户信息');
+      return c.json({ code: 401, message: '未授权' }, 401);
+    }
+
+    // 获取路径参数和请求数据
+    const { id } = c.req.valid('param');
+    const updateData = c.req.valid('json');
+    
+    // 检查权限:管理员可以更新所有用户,普通用户只能更新自己
+    const isAdmin = await userService.isAdmin(currentUser.id);
+    if (!isAdmin && currentUser.id !== id) {
+      logger.error('用户 %d 权限不足,无法更新用户 %d 的信息', currentUser.id, id);
+      return c.json({ code: 403, message: '权限不足' }, 403);
+    }
+
+    // 更新用户信息
+    logger.api('用户 %d 更新用户 %d 信息: %o', currentUser.id, id, updateData);
+    const updatedUser = await userService.update(id, updateData);
+    
+    return c.json({
+      code: 200,
+      message: '用户更新成功',
+      data: updatedUser
+    } satisfies z.infer<typeof UpdateUserResponse>, 200);
+  } catch (error) {
+    logger.error('更新用户信息失败: %o', error);
+    const message = error instanceof Error ? error.message : '更新用户信息失败';
+    const statusCode = message.includes('不存在') ? 404 : 
+                      message.includes('已存在') ? 400 : 500;
+    
+    return c.json({
+      code: statusCode,
+      message
+    }, statusCode);
+  }
+});
+
+export default app;

+ 141 - 0
src/server/api/users/[id]/status.ts

@@ -0,0 +1,141 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { UserService } from '@/server/modules/users/user.service';
+import { UserSchema } from '@/server/modules/users/user.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 初始化用户服务
+const userService = new UserService(AppDataSource);
+
+// 路径参数Schema
+const ChangeStatusParams = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    description: '用户ID',
+    example: 1
+  })
+});
+
+// 请求体Schema
+const ChangeStatusBody = z.object({
+  status: z.coerce.number().int().min(0).max(1).openapi({
+    description: '用户状态 (0: 启用, 1: 禁用)',
+    example: 0
+  })
+});
+
+// 响应Schema
+const ChangeStatusResponse = z.object({
+  code: z.number().openapi({ example: 200 }),
+  message: z.string().openapi({ example: '用户状态更新成功' }),
+  data: UserSchema
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'patch',
+  path: '/{id}/status',
+  middleware: [authMiddleware],
+  request: {
+    params: ChangeStatusParams,
+    body: {
+      content: {
+        'application/json': { schema: ChangeStatusBody }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '用户状态更新成功',
+      content: {
+        'application/json': { schema: ChangeStatusResponse }
+      }
+    },
+    400: {
+      description: '请求参数错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    401: {
+      description: '未授权',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    403: {
+      description: '权限不足',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    404: {
+      description: '用户不存在',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    500: {
+      description: '服务器内部错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    }
+  },
+  tags: ['用户管理']
+});
+
+// 创建路由实例
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    // 获取当前用户
+    const currentUser = c.get('user');
+    if (!currentUser) {
+      logger.error('未获取到用户信息');
+      return c.json({ code: 401, message: '未授权' }, 401);
+    }
+
+    // 检查是否为管理员
+    const isAdmin = await userService.isAdmin(currentUser.id);
+    if (!isAdmin) {
+      logger.error('用户 %d 权限不足,无法修改用户状态', currentUser.id);
+      return c.json({ code: 403, message: '权限不足,仅管理员可操作' }, 403);
+    }
+
+    // 获取路径参数和请求数据
+    const { id } = c.req.valid('param');
+    const { status } = c.req.valid('json');
+    
+    // 防止修改自己的状态
+    if (currentUser.id === id) {
+      logger.error('用户 %d 尝试修改自己的状态', currentUser.id);
+      return c.json({ code: 400, message: '不能修改自己的状态' }, 400);
+    }
+
+    // 修改用户状态
+    logger.api('用户 %d 修改用户 %d 状态为 %d', currentUser.id, id, status);
+    const updatedUser = await userService.changeStatus(id, status);
+    
+    return c.json({
+      code: 200,
+      message: '用户状态更新成功',
+      data: updatedUser
+    } satisfies z.infer<typeof ChangeStatusResponse>, 200);
+  } catch (error) {
+    logger.error('修改用户状态失败: %o', error);
+    const message = error instanceof Error ? error.message : '修改用户状态失败';
+    const statusCode = message.includes('不存在') ? 404 : 
+                      message.includes('状态值必须为0或1') ? 400 : 500;
+    
+    return c.json({
+      code: statusCode,
+      message
+    }, statusCode);
+  }
+});
+
+export default app;

+ 150 - 0
src/server/api/users/get.ts

@@ -0,0 +1,150 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { UserService } from '@/server/modules/users/user.service';
+import { UserSchema } from '@/server/modules/users/user.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 初始化用户服务
+const userService = new UserService(AppDataSource);
+
+// 查询参数Schema
+const GetUsersQuery = z.object({
+  page: z.coerce.number().int().positive().default(1).openapi({
+    description: '页码',
+    example: 1
+  }),
+  pageSize: z.coerce.number().int().positive().default(10).openapi({
+    description: '每页数量',
+    example: 10
+  }),
+  username: z.string().optional().openapi({
+    description: '用户名筛选',
+    example: 'admin'
+  }),
+  status: z.coerce.number().int().optional().openapi({
+    description: '用户状态筛选 (0: 启用, 1: 禁用)',
+    example: 0
+  })
+});
+
+// 响应Schema
+const UserListResponse = z.object({
+  code: z.number().openapi({ example: 200 }),
+  message: z.string().openapi({ example: 'success' }),
+  data: z.object({
+    list: z.array(UserSchema),
+    pagination: z.object({
+      total: z.number().openapi({ example: 100 }),
+      current: z.number().openapi({ example: 1 }),
+      pageSize: z.number().openapi({ example: 10 }),
+      totalPages: z.number().openapi({ example: 10 })
+    })
+  })
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'get',
+  path: '/',
+  middleware: [authMiddleware],
+  request: {
+    query: GetUsersQuery
+  },
+  responses: {
+    200: {
+      description: '成功获取用户列表',
+      content: {
+        'application/json': { schema: UserListResponse }
+      }
+    },
+    400: {
+      description: '请求参数错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    401: {
+      description: '未授权',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    403: {
+      description: '权限不足',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    500: {
+      description: '服务器内部错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    }
+  },
+  tags: ['用户管理']
+});
+
+// 创建路由实例
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    // 获取当前用户
+    const user = c.get('user');
+    if (!user) {
+      logger.error('未获取到用户信息');
+      return c.json({ code: 401, message: '未授权' }, 401);
+    }
+
+    // 检查是否为管理员
+    const isAdmin = await userService.isAdmin(user.id);
+    if (!isAdmin) {
+      logger.error('用户 %d 权限不足,无法获取用户列表', user.id);
+      return c.json({ code: 403, message: '权限不足,仅管理员可操作' }, 403);
+    }
+
+    // 获取查询参数
+    const { page, pageSize, username, status } = c.req.valid('query');
+    
+    // 构建查询条件
+    const where: any = {};
+    if (username) {
+      where.username = Like(`%${username}%`);
+    }
+    if (status !== undefined) {
+      where.status = status;
+    }
+
+    // 查询用户列表
+    logger.api('用户 %d 查询用户列表: page=%d, pageSize=%d, where=%o', user.id, page, pageSize, where);
+    const { data, total } = await userService.findAll(page, pageSize, where);
+    
+    // 计算总页数
+    const totalPages = Math.ceil(total / pageSize);
+    
+    return c.json({
+      code: 200,
+      message: 'success',
+      data: {
+        list: data,
+        pagination: {
+          total,
+          current: page,
+          pageSize,
+          totalPages
+        }
+      }
+    }, 200);
+  } catch (error) {
+    logger.error('获取用户列表失败: %o', error);
+    return c.json({
+      code: 500,
+      message: error instanceof Error ? error.message : '获取用户列表失败'
+    }, 500);
+  }
+});
+
+export default app;

+ 19 - 0
src/server/api/users/index.ts

@@ -0,0 +1,19 @@
+import { OpenAPIHono } from '@hono/zod-openapi';
+import listRoute from './get';
+import createRoute from './post';
+import getByIdRoute from './[id]/get';
+import updateRoute from './[id]/put';
+import deleteRoute from './[id]/delete';
+import changeStatusRoute from './[id]/status';
+import resetPasswordRoute from './[id]/password';
+
+const app = new OpenAPIHono()
+  .route('/', listRoute)
+  .route('/', createRoute)
+  .route('/', getByIdRoute)
+  .route('/', updateRoute)
+  .route('/', deleteRoute)
+  .route('/', changeStatusRoute)
+  .route('/', resetPasswordRoute);
+
+export default app;

+ 124 - 0
src/server/api/users/post.ts

@@ -0,0 +1,124 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@/server/data-source';
+import { UserService } from '@/server/modules/users/user.service';
+import { UserSchema } from '@/server/modules/users/user.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { AuthContext } from '@/server/types/context';
+import { logger } from '@/server/utils/logger';
+
+// 初始化用户服务
+const userService = new UserService(AppDataSource);
+
+// 创建用户请求Schema
+const CreateUserSchema = UserSchema.omit({
+  id: true,
+  createdAt: true,
+  updatedAt: true,
+  isDeleted: true
+}).extend({
+  password: z.string().min(6).openapi({
+    description: '用户密码,至少6位',
+    example: 'password123'
+  })
+});
+
+// 响应Schema
+const CreateUserResponse = z.object({
+  code: z.number().openapi({ example: 200 }),
+  message: z.string().openapi({ example: '用户创建成功' }),
+  data: UserSchema
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'post',
+  path: '/',
+  middleware: [authMiddleware],
+  request: {
+    body: {
+      content: {
+        'application/json': { schema: CreateUserSchema }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '用户创建成功',
+      content: {
+        'application/json': { schema: CreateUserResponse }
+      }
+    },
+    400: {
+      description: '请求参数错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    401: {
+      description: '未授权',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    403: {
+      description: '权限不足',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    },
+    500: {
+      description: '服务器内部错误',
+      content: {
+        'application/json': { schema: ErrorSchema }
+      }
+    }
+  },
+  tags: ['用户管理']
+});
+
+// 创建路由实例
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c): Promise<Response> => {
+  try {
+    // 获取当前用户
+    const user = c.get('user');
+    if (!user) {
+      logger.error('未获取到用户信息');
+      return c.json({ code: 401, message: '未授权' }, 401);
+    }
+
+    // 检查是否为管理员
+    const isAdmin = await userService.isAdmin(user.id);
+    if (!isAdmin) {
+      logger.error('用户 %d 权限不足,无法创建用户', user.id);
+      return c.json({ code: 403, message: '权限不足,仅管理员可操作' }, 403);
+    }
+
+    // 获取请求数据
+    const userData = c.req.valid('json');
+    
+    // 创建用户
+    logger.api('用户 %d 创建新用户: %o', user.id, userData);
+    const newUser = await userService.create(userData);
+    
+    const response: z.infer<typeof CreateUserResponse> = {
+      code: 200,
+      message: '用户创建成功',
+      data: newUser
+    };
+    return c.json(response, 200);
+  } catch (error) {
+    logger.error('创建用户失败: %o', error);
+    const message = error instanceof Error ? error.message : '创建用户失败';
+    const statusCode = error instanceof Error && message.includes('已存在') ? 400 : 500;
+    
+    const errorResponse = {
+      code: statusCode,
+      message
+    };
+    return c.json(errorResponse, statusCode);
+  }
+});
+
+export default app;

+ 370 - 0
src/server/modules/departments/department.service.ts

@@ -0,0 +1,370 @@
+import { DataSource, Repository } from 'typeorm';
+import { Department } from './department.entity';
+import { logger } from '@/server/utils/logger';
+import { z } from 'zod';
+
+// 定义查询参数Schema
+const DepartmentQuerySchema = z.object({
+  name: z.string().optional(),
+  status: z.coerce.number().int().min(0).max(1).optional(),
+  parentId: z.coerce.number().int().nullable().optional(),
+  page: z.coerce.number().int().positive().default(1),
+  pageSize: z.coerce.number().int().positive().default(10),
+  sortBy: z.string().default('sortOrder'),
+  sortOrder: z.enum(['asc', 'desc']).default('asc')
+});
+
+// 定义创建部门Schema
+const CreateDepartmentSchema = z.object({
+  name: z.string().min(1).max(50),
+  parentId: z.number().int().positive().nullable(),
+  sortOrder: z.number().int().nullable(),
+  description: z.string().nullable()
+});
+
+// 定义更新部门Schema
+const UpdateDepartmentSchema = CreateDepartmentSchema.partial();
+
+export class DepartmentService {
+  private repository: Repository<Department>;
+
+  constructor(dataSource: DataSource) {
+    this.repository = dataSource.getRepository(Department);
+  }
+
+  /**
+   * 查询部门列表,支持分页、条件筛选和排序
+   */
+  async findAll(query: z.infer<typeof DepartmentQuerySchema>) {
+    const validatedQuery = DepartmentQuerySchema.parse(query);
+    const { name, status, parentId, page, pageSize, sortBy, sortOrder } = validatedQuery;
+    
+    const skip = (page - 1) * pageSize;
+    
+    // 构建查询条件
+    const queryBuilder = this.repository.createQueryBuilder('department')
+      .where('department.isDeleted = 0');
+      
+    if (name) {
+      queryBuilder.andWhere('department.name LIKE :name', { name: `%${name}%` });
+    }
+    
+    if (status !== undefined) {
+      queryBuilder.andWhere('department.status = :status', { status });
+    }
+    
+    if (parentId !== undefined) {
+      queryBuilder.andWhere('department.parentId = :parentId', { parentId });
+    }
+    
+    // 排序
+    // 将排序方向转换为大写以匹配TypeORM要求
+    queryBuilder.orderBy(`department.${sortBy}`, sortOrder.toUpperCase() as 'ASC' | 'DESC');
+    
+    // 分页
+    queryBuilder.skip(skip).take(pageSize);
+    
+    const [items, total] = await queryBuilder.getManyAndCount();
+    
+    logger.api(`查询部门列表: 共${total}条, 第${page}页, 每页${pageSize}条`);
+    
+    return {
+      data: items,
+      pagination: {
+        total,
+        current: page,
+        pageSize,
+        totalPages: Math.ceil(total / pageSize)
+      }
+    };
+  }
+
+  /**
+   * 根据ID查询部门详情
+   */
+  async findById(id: number) {
+    const department = await this.repository.findOne({
+      where: { id, isDeleted: 0 }
+    });
+    
+    if (!department) {
+      logger.error(`部门不存在: ID=${id}`);
+      throw new Error('部门不存在');
+    }
+    
+    return department;
+  }
+
+  /**
+   * 创建新部门
+   */
+  async create(data: z.infer<typeof CreateDepartmentSchema>) {
+    const validatedData = CreateDepartmentSchema.parse(data);
+    
+    // 检查父部门是否存在
+    if (validatedData.parentId) {
+      const parentDepartment = await this.repository.findOne({
+        where: { id: validatedData.parentId, isDeleted: 0 }
+      });
+      
+      if (!parentDepartment) {
+        logger.error(`父部门不存在: ID=${validatedData.parentId}`);
+        throw new Error('父部门不存在');
+      }
+    }
+    
+    // 检查部门名称是否已存在
+    const existingDepartment = await this.repository.findOne({
+      where: { name: validatedData.name, isDeleted: 0 }
+    });
+    
+    if (existingDepartment) {
+      logger.error(`部门名称已存在: ${validatedData.name}`);
+      throw new Error('部门名称已存在');
+    }
+    
+    const department = this.repository.create({
+      ...validatedData,
+      status: 1, // 默认启用
+      isDeleted: 0
+    });
+    
+    const result = await this.repository.save(department);
+    logger.api(`创建部门成功: ID=${result.id}, 名称=${result.name}`);
+    
+    return result;
+  }
+
+  /**
+   * 更新部门信息
+   */
+  async update(id: number, data: z.infer<typeof UpdateDepartmentSchema>) {
+    const validatedData = UpdateDepartmentSchema.parse(data);
+    
+    // 检查部门是否存在
+    const department = await this.repository.findOne({
+      where: { id, isDeleted: 0 }
+    });
+    
+    if (!department) {
+      logger.error(`部门不存在: ID=${id}`);
+      throw new Error('部门不存在');
+    }
+    
+    // 如果更新父部门,检查父部门是否存在
+    if (validatedData.parentId !== undefined) {
+      // 不能将自己设为父部门
+      if (validatedData.parentId === id) {
+        logger.error(`部门不能将自己设为父部门: ID=${id}`);
+        throw new Error('部门不能将自己设为父部门');
+      }
+      
+      // 检查父部门是否存在
+      if (validatedData.parentId) {
+        const parentDepartment = await this.repository.findOne({
+          where: { id: validatedData.parentId, isDeleted: 0 }
+        });
+        
+        if (!parentDepartment) {
+          logger.error(`父部门不存在: ID=${validatedData.parentId}`);
+          throw new Error('父部门不存在');
+        }
+        
+        // 检查是否存在循环引用
+        const hasCycle = await this.checkCycleReference(id, validatedData.parentId);
+        if (hasCycle) {
+          logger.error(`部门存在循环引用: ID=${id}, 父部门ID=${validatedData.parentId}`);
+          throw new Error('不能设置子部门为父部门');
+        }
+      }
+    }
+    
+    // 如果更新名称,检查名称是否已存在
+    if (validatedData.name && validatedData.name !== department.name) {
+      const existingDepartment = await this.repository.findOne({
+        where: { name: validatedData.name, isDeleted: 0 }
+      });
+      
+      if (existingDepartment) {
+        logger.error(`部门名称已存在: ${validatedData.name}`);
+        throw new Error('部门名称已存在');
+      }
+    }
+    
+    // 更新部门信息
+    Object.assign(department, validatedData);
+    const result = await this.repository.save(department);
+    logger.api(`更新部门成功: ID=${id}, 名称=${result.name}`);
+    
+    return result;
+  }
+
+  /**
+   * 删除部门
+   */
+  async delete(id: number) {
+    // 检查部门是否存在
+    const department = await this.repository.findOne({
+      where: { id, isDeleted: 0 }
+    });
+    
+    if (!department) {
+      logger.error(`部门不存在: ID=${id}`);
+      throw new Error('部门不存在');
+    }
+    
+    // 检查是否存在子部门
+    const hasChildren = await this.hasChildren(id);
+    if (hasChildren) {
+      logger.error(`部门存在子部门,无法删除: ID=${id}`);
+      throw new Error('部门存在子部门,无法删除');
+    }
+    
+    // 检查是否有关联用户
+    const hasUsers = await this.hasUsers(id);
+    if (hasUsers) {
+      logger.error(`部门存在关联用户,无法删除: ID=${id}`);
+      throw new Error('部门存在关联用户,无法删除');
+    }
+    
+    // 软删除
+    department.isDeleted = 1;
+    await this.repository.save(department);
+    logger.api(`删除部门成功: ID=${id}, 名称=${department.name}`);
+    
+    return { success: true };
+  }
+
+  /**
+   * 更新部门状态
+   */
+  async updateStatus(id: number, status: number) {
+    // 验证状态值
+    if (![0, 1].includes(status)) {
+      logger.error(`无效的部门状态: ${status}`);
+      throw new Error('无效的部门状态');
+    }
+    
+    // 检查部门是否存在
+    const department = await this.repository.findOne({
+      where: { id, isDeleted: 0 }
+    });
+    
+    if (!department) {
+      logger.error(`部门不存在: ID=${id}`);
+      throw new Error('部门不存在');
+    }
+    
+    // 如果禁用部门,检查是否存在子部门,如果有则一起禁用
+    if (status === 0) {
+      await this.disableWithChildren(id);
+      logger.api(`禁用部门及其子部门: ID=${id}`);
+    } else {
+      department.status = status;
+      await this.repository.save(department);
+      logger.api(`更新部门状态成功: ID=${id}, 状态=${status}`);
+    }
+    
+    return { success: true };
+  }
+
+  /**
+   * 获取部门的子部门
+   */
+  async getChildren(parentId: number) {
+    const children = await this.repository.find({
+      where: { parentId, isDeleted: 0 },
+      order: { sortOrder: 'ASC' }
+    });
+    
+    logger.api(`获取部门子部门: 父部门ID=${parentId}, 子部门数量=${children.length}`);
+    
+    return children;
+  }
+
+  /**
+   * 检查部门是否存在子部门
+   */
+  private async hasChildren(id: number): Promise<boolean> {
+    const count = await this.repository.count({
+      where: { parentId: id, isDeleted: 0 }
+    });
+    
+    return count > 0;
+  }
+
+  /**
+   * 检查部门是否有关联用户
+   */
+  private async hasUsers(id: number): Promise<boolean> {
+    // 这里假设存在用户表关联查询,实际实现需要根据项目的用户实体关系调整
+    const queryBuilder = this.repository.createQueryBuilder('department')
+      .leftJoin('department.users', 'user')
+      .where('department.id = :id', { id })
+      .andWhere('department.isDeleted = 0')
+      .andWhere('user.isDeleted = 0');
+      
+    const count = await queryBuilder.getCount();
+    return count > 0;
+  }
+
+  /**
+   * 检查是否存在循环引用
+   */
+  private async checkCycleReference(childId: number, parentId: number): Promise<boolean> {
+    if (!parentId) return false;
+    
+    let currentParentId: number | null = parentId;
+    while (currentParentId) {
+      if (currentParentId === childId) {
+        return true;
+      }
+      
+      const parent = await this.repository.findOne({
+        where: { id: currentParentId, isDeleted: 0 },
+        select: ['parentId']
+      });
+      
+      if (!parent) break;
+      currentParentId = parent.parentId;
+      if (currentParentId === null) break;
+    }
+    
+    return false;
+  }
+
+  /**
+   * 禁用部门及其所有子部门
+   */
+  private async disableWithChildren(id: number) {
+    // 获取所有子部门ID,包括间接子部门
+    const childIds = await this.getAllChildIds(id);
+    
+    // 禁用当前部门和所有子部门
+    await this.repository.createQueryBuilder()
+      .update(Department)
+      .set({ status: 0 })
+      .where('id IN (:...ids)', { ids: [id, ...childIds] })
+      .execute();
+  }
+
+  /**
+   * 获取部门的所有子部门ID,包括间接子部门
+   */
+  private async getAllChildIds(parentId: number): Promise<number[]> {
+    const children = await this.repository.find({
+      where: { parentId, isDeleted: 0 },
+      select: ['id']
+    });
+    
+    const childIds = children.map(child => child.id);
+    let allChildIds: number[] = [...childIds];
+    
+    for (const childId of childIds) {
+      const grandChildIds = await this.getAllChildIds(childId);
+      allChildIds = [...allChildIds, ...grandChildIds];
+    }
+    
+    return allChildIds;
+  }
+}

+ 216 - 0
src/server/modules/tickets/ticket.service.ts

@@ -0,0 +1,216 @@
+import { DataSource, Repository } from 'typeorm';
+import { Ticket } from './ticket.entity';
+import { logger } from '@/server/utils/logger';
+
+export class TicketService {
+  private ticketRepository: Repository<Ticket>;
+
+  constructor(private dataSource: DataSource) {
+    this.ticketRepository = dataSource.getRepository(Ticket);
+  }
+
+  // 实现CRUD操作、分页查询、条件筛选和工单状态流转等业务逻辑
+  async findAll(
+    page: number = 1,
+    pageSize: number = 10,
+    filters: any = {},
+    sort: any = {}
+  ): Promise<{ data: Ticket[], total: number }> {
+    const query = this.ticketRepository.createQueryBuilder('ticket');
+    
+    // 添加条件筛选
+    if (filters.status) {
+      query.andWhere('ticket.status = :status', { status: filters.status });
+    }
+    
+    if (filters.priority) {
+      query.andWhere('ticket.priority = :priority', { priority: filters.priority });
+    }
+    
+    if (filters.assigneeId) {
+      query.andWhere('ticket.assigneeId = :assigneeId', { assigneeId: filters.assigneeId });
+    }
+    
+    if (filters.customerId) {
+      query.andWhere('ticket.customerId = :customerId', { customerId: filters.customerId });
+    }
+    
+    // 添加排序
+    if (sort.field && sort.order) {
+      query.orderBy(`ticket.${sort.field}`, sort.order === 'desc' ? 'DESC' : 'ASC');
+    } else {
+      query.orderBy('ticket.createdAt', 'DESC');
+    }
+    
+    // 分页
+    query.skip((page - 1) * pageSize).take(pageSize);
+    
+    const [data, total] = await query.getManyAndCount();
+    return { data, total };
+  }
+
+  async findById(id: number): Promise<Ticket | null> {
+    return this.ticketRepository.findOneBy({ id });
+  }
+
+  async create(ticketData: Partial<Ticket>): Promise<Ticket> {
+    const ticket = this.ticketRepository.create(ticketData);
+    
+    // 设置默认状态为"新建"
+    if (!ticket.status) {
+      ticket.status = 0; // 0表示新建状态
+    }
+    
+    // 计算SLA时间
+    if (ticket.priority) {
+      const slaHours = this.getSLAHoursByPriority(ticket.priority as unknown as number);
+      // @ts-ignore: Property 'slaExpiresAt' does not exist on type 'Ticket'
+      ticket.slaExpiresAt = new Date();
+      // @ts-ignore: Property 'slaExpiresAt' does not exist on type 'Ticket'
+      ticket.slaExpiresAt.setHours(ticket.slaExpiresAt.getHours() + slaHours);
+    }
+    
+    const result = await this.ticketRepository.save(ticket);
+    logger.api(`Created ticket with id: ${result.id}`);
+    return result;
+  }
+
+  async update(id: number, ticketData: Partial<Ticket>): Promise<Ticket | null> {
+    const ticket = await this.findById(id);
+    if (!ticket) {
+      return null;
+    }
+    
+    // 处理状态变更逻辑
+    if (ticketData.status && ticketData.status !== ticket.status) {
+      this.validateStatusTransition(ticket.status as unknown as string, ticketData.status as unknown as string);
+      
+      // 记录状态变更时间
+      if (ticketData.status === 1) { // 1表示处理中状态
+        // @ts-ignore: Property 'startedAt' does not exist on type 'Ticket'
+        ticket.startedAt = new Date();
+      } else if (ticketData.status === 3) { // 3表示已解决状态
+        ticket.resolvedAt = new Date();
+      } else if (ticketData.status === 4) { // 4表示已关闭状态
+        ticket.closedAt = new Date();
+      }
+    }
+    
+    Object.assign(ticket, ticketData);
+    const result = await this.ticketRepository.save(ticket);
+    logger.api(`Updated ticket with id: ${id}`);
+    return result;
+  }
+
+  async delete(id: number): Promise<boolean> {
+    const result = await this.ticketRepository.delete(id);
+    logger.api(`Deleted ticket with id: ${id}`);
+    return (result.affected || 0) > 0;
+  }
+
+  async assign(id: number, assigneeId: number): Promise<Ticket | null> {
+    const ticket = await this.findById(id);
+    if (!ticket) {
+      return null;
+    }
+    
+    ticket.assignedTo = assigneeId;
+    
+    // 如果工单状态是"新建",自动转为"处理中"
+    if (ticket.status === 0) { // 0表示新建状态
+      ticket.status = 1; // 1表示处理中状态
+      // @ts-ignore: Property 'startedAt' does not exist on type 'Ticket'
+      ticket.startedAt = new Date();
+    }
+    
+    const result = await this.ticketRepository.save(ticket);
+    logger.api(`Assigned ticket ${id} to user ${assigneeId}`);
+    return result;
+  }
+
+  async changeStatus(id: number, status: string): Promise<Ticket | null> {
+    const ticket = await this.findById(id);
+    if (!ticket) {
+      return null;
+    }
+    
+    this.validateStatusTransition(ticket.status as unknown as string, status as unknown as string);
+    
+    // 记录状态变更时间
+    if (status === 'in_progress') {
+      // @ts-ignore: Property 'startedAt' does not exist on type 'Ticket'
+      ticket.startedAt = new Date();
+    } else if (status === 'resolved') {
+      ticket.resolvedAt = new Date();
+    } else if (status === 'closed') {
+      ticket.closedAt = new Date();
+    }
+    
+    ticket.status = status as unknown as number;
+    const result = await this.ticketRepository.save(ticket);
+    logger.api(`Changed ticket ${id} status to ${status}`);
+    return result;
+  }
+
+  // 验证状态流转是否合法
+  private validateStatusTransition(currentStatus: string, newStatus: string): void {
+    const validTransitions: Record<string, string[]> = {
+      'new': ['in_progress', 'closed'],
+      'in_progress': ['resolved', 'closed', 'pending'],
+      'pending': ['in_progress', 'closed'],
+      'resolved': ['closed', 'reopened'],
+      'reopened': ['in_progress', 'closed'],
+      'closed': [] // 已关闭状态不能再变更
+    };
+    
+    if (!validTransitions[currentStatus]?.includes(newStatus)) {
+      logger.error(`Invalid status transition from ${currentStatus} to ${newStatus}`);
+      throw new Error(`不允许从${this.getStatusName(currentStatus)}状态转换为${this.getStatusName(newStatus)}状态`);
+    }
+  }
+
+  // 根据优先级获取SLA小时数
+  private getSLAHoursByPriority(priority: string): number {
+    const slaConfig: Record<string, number> = {
+      'low': 48,      // 低优先级:48小时
+      'medium': 24,   // 中优先级:24小时
+      'high': 8,      // 高优先级:8小时
+      'urgent': 2     // 紧急优先级:2小时
+    };
+    
+    return slaConfig[priority] || 24; // 默认24小时
+  }
+
+  // 获取状态中文名称
+  private getStatusName(status: string): string {
+    const statusNames: Record<string, string> = {
+      'new': '新建',
+      'in_progress': '处理中',
+      'pending': '待处理',
+      'resolved': '已解决',
+      'reopened': '已重新打开',
+      'closed': '已关闭'
+    };
+    
+    return statusNames[status] || status;
+  }
+
+  // 检查SLA是否过期
+  async checkSLAExpiry(): Promise<Ticket[]> {
+    const now = new Date();
+    const expiredTickets = await this.ticketRepository
+      .createQueryBuilder('ticket')
+      .where('ticket.slaExpiresAt < :now', { now })
+      .andWhere('ticket.status NOT IN (:...statuses)', { 
+        statuses: ['resolved', 'closed'] 
+      })
+      .getMany();
+      
+    // 记录SLA过期日志
+    expiredTickets.forEach(ticket => {
+      logger.error(`Ticket ${ticket.id} SLA expired at ${ticket.slaExpiresAt}`);
+    });
+    
+    return expiredTickets;
+  }
+}

+ 263 - 0
src/server/modules/users/user.service.ts

@@ -0,0 +1,263 @@
+import { DataSource, Repository, Like } from 'typeorm';
+import { User } from './user.entity';
+import * as bcrypt from 'bcrypt';
+// @ts-ignore: bcrypt类型定义未找到,实际运行时已安装
+import { logger } from '@/server/utils/logger';
+import { AppErrors } from '@/server/utils/errorHandler';
+
+export class UserService {
+  private userRepository: Repository<User>;
+
+  constructor(dataSource: DataSource) {
+    this.userRepository = dataSource.getRepository(User);
+  }
+
+  /**
+   * 创建新用户
+   * @param userData 用户数据
+   * @returns 创建的用户
+   */
+  async create(userData: Partial<User>): Promise<User> {
+    logger.api('Creating new user: %o', userData);
+    
+    // 检查用户名是否已存在
+    const existingUser = await this.userRepository.findOne({
+      where: { username: userData.username }
+    });
+    
+    if (existingUser) {
+      logger.error('Username already exists: %s', userData.username);
+      throw new AppErrors('用户名已存在', 400);
+    }
+    
+    // 密码加密
+    if (userData.password) {
+      const salt = await bcrypt.genSalt(10);
+      userData.password = await bcrypt.hash(userData.password, salt);
+    }
+    
+    const user = this.userRepository.create(userData);
+    const result = await this.userRepository.save(user);
+    
+    // 不返回密码
+    // 创建不包含密码的新对象
+    const { password, ...userWithoutPassword } = result;
+    
+    logger.api('User created successfully: %d', result.id);
+    return userWithoutPassword;
+  }
+
+  /**
+   * 查询用户列表,支持分页和条件筛选
+   * @param page 页码
+   * @param pageSize 每页数量
+   * @param where 筛选条件
+   * @returns 用户列表和分页信息
+   */
+  async findAll(page: number = 1, pageSize: number = 10, where: any = {}): Promise<{ data: User[], total: number }> {
+    logger.api('Finding users with pagination: page=%d, pageSize=%d, where=%o', page, pageSize, where);
+    
+    // 添加默认筛选条件:未删除的用户
+    where.isDeleted = 0;
+    
+    const [data, total] = await this.userRepository.findAndCount({
+      where,
+      skip: (page - 1) * pageSize,
+      take: pageSize,
+      order: { createdAt: 'DESC' }
+    });
+    
+    // 不返回密码
+    // 创建不包含密码的新对象数组
+    const usersWithoutPassword = data.map(({ password, ...user }) => user);
+    
+    logger.api('Found %d users out of %d total', usersWithoutPassword.length, total);
+    return { data: usersWithoutPassword, total };
+  }
+
+  /**
+   * 根据ID查询用户详情
+   * @param id 用户ID
+   * @returns 用户详情
+   */
+  async findOne(id: number): Promise<User> {
+    logger.api('Finding user by id: %d', id);
+    
+    const user = await this.userRepository.findOne({
+      where: { id, isDeleted: 0 }
+    });
+    
+    if (!user) {
+      logger.error('User not found: %d', id);
+      throw new AppError('用户不存在', 404);
+    }
+    
+    // 不返回密码
+    // 创建不包含密码的新对象
+    const { password, ...userWithoutPassword } = user;
+    
+    return userWithoutPassword;
+  }
+
+  /**
+   * 更新用户信息
+   * @param id 用户ID
+   * @param userData 更新的用户数据
+   * @returns 更新后的用户
+   */
+  async update(id: number, userData: Partial<User>): Promise<User> {
+    logger.api('Updating user: %d, data=%o', id, userData);
+    
+    const user = await this.findOne(id);
+    
+    // 如果更新用户名,检查新用户名是否已存在
+    if (userData.username && userData.username !== user.username) {
+      const existingUser = await this.userRepository.findOne({
+        where: { username: userData.username }
+      });
+      
+      if (existingUser) {
+        logger.error('Username already exists: %s', userData.username);
+        throw new AppError('用户名已存在', 400);
+      }
+    }
+    
+    // 如果更新密码,需要加密
+    if (userData.password) {
+      const salt = await bcrypt.genSalt(10);
+      userData.password = await bcrypt.hash(userData.password, salt);
+    }
+    
+    const updatedUser = this.userRepository.merge(user, userData);
+    const result = await this.userRepository.save(updatedUser);
+    
+    // 不返回密码
+    // 创建不包含密码的新对象
+    const { password, ...userWithoutPassword } = result;
+    
+    logger.api('User updated successfully: %d', id);
+    return userWithoutPassword;
+  }
+
+  /**
+   * 删除用户(逻辑删除)
+   * @param id 用户ID
+   * @returns 删除结果
+   */
+  async remove(id: number): Promise<{ success: boolean }> {
+    logger.api('Deleting user: %d', id);
+    
+    const user = await this.findOne(id);
+    
+    // 逻辑删除,设置isDeleted为1
+    user.isDeleted = 1;
+    await this.userRepository.save(user);
+    
+    logger.api('User deleted successfully: %d', id);
+    return { success: true };
+  }
+
+  /**
+   * 变更用户状态
+   * @param id 用户ID
+   * @param isDisabled 是否禁用
+   * @returns 更新后的用户
+   */
+  async changeStatus(id: number, status: number): Promise<User> {
+    logger.api('Changing user status: %d, status=%d', id, status);
+    
+    if (![0, 1].includes(status)) {
+      logger.error('Invalid status value: %d', status);
+      throw new AppErrors('状态值必须为0或1', 400);
+    }
+    
+    const user = await this.findOne(id);
+    user.status = status;
+    
+    const result = await this.userRepository.save(user);
+    
+    // 创建不包含密码的新对象
+    const { password, ...userWithoutPassword } = result;
+    
+    logger.api('User status changed successfully: %d', id);
+    return userWithoutPassword;
+  }
+
+  /**
+   * 重置用户密码
+   * @param id 用户ID
+   * @param newPassword 新密码
+   * @returns 重置结果
+   */
+  async resetPassword(id: number, newPassword: string): Promise<{ success: boolean }> {
+    logger.api('Resetting password for user: %d', id);
+    
+    const user = await this.findOne(id);
+    
+    // 密码加密
+    const salt = await bcrypt.genSalt(10);
+    user.password = await bcrypt.hash(newPassword, salt);
+    
+    await this.userRepository.save(user);
+    
+    logger.api('Password reset successfully for user: %d', id);
+    return { success: true };
+  }
+
+  /**
+   * 用户认证
+   * @param username 用户名
+   * @param password 密码
+   * @returns 认证通过的用户
+   */
+  async authenticate(username: string, password: string): Promise<User> {
+    logger.api('Authenticating user: %s', username);
+    
+    const user = await this.userRepository.findOne({
+      where: { username, isDeleted: 0, status: 0 }
+    });
+    
+    if (!user) {
+      logger.error('User not found or disabled: %s', username);
+      throw new AppErrors('用户名或密码不正确', 401);
+    }
+    
+    const isPasswordValid = await bcrypt.compare(password, user.password);
+    
+    if (!isPasswordValid) {
+      logger.error('Invalid password for user: %s', username);
+      throw new AppErrors('用户名或密码不正确', 401);
+    }
+    
+    // 不返回密码
+    // 创建不包含密码的新对象
+    const { password, ...userWithoutPassword } = user;
+    
+    logger.api('User authenticated successfully: %s', username);
+    return userWithoutPassword;
+  }
+
+  /**
+   * 检查用户是否有管理员权限
+   * @param userId 用户ID
+   * @returns 是否为管理员
+   */
+  async isAdmin(userId: number): Promise<boolean> {
+    logger.api('Checking if user is admin: %d', userId);
+    
+    const user = await this.userRepository.findOne({
+      where: { id: userId, isDeleted: 0 }
+    });
+    
+    if (!user) {
+      logger.error('User not found: %d', userId);
+      return false;
+    }
+    
+    // 检查用户是否有管理员角色 (假设role字段存储角色名称)
+    const isAdmin = user.role === 'admin';
+    
+    logger.api('User admin status: %d - %s', userId, isAdmin ? 'Yes' : 'No');
+    return isAdmin;
+  }
+}