yourname 5 hónapja
szülő
commit
9cc125f099

+ 3 - 0
package.json

@@ -4,12 +4,15 @@
   },
   "dependencies": {
     "@hono/zod-openapi": "^0.19.8",
+    "jsonwebtoken": "^9.0.2",
     "mysql2": "^3.14.1",
     "reflect-metadata": "^0.2.2",
     "typeorm": "^0.3.25",
     "zod": "^3.25.67"
   },
   "devDependencies": {
+    "@types/debug": "^4.1.12",
+    "@types/jsonwebtoken": "^9.0.10",
     "@types/node": "^24.0.3",
     "ts-node": "^10.9.2",
     "tsconfig-paths": "^4.2.0",

+ 104 - 0
src/server/api/contacts/[id]/get.ts

@@ -0,0 +1,104 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from '@hono/zod-openapi';
+import { AppDataSource } from '@/server/data-source';
+import { ContactService } from '@/server/modules/contacts/contact.service';
+import { ContactSchema } from '@/server/modules/contacts/contact.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { logger } from '@/server/utils/logger';
+import { AuthContext } from '@/server/types/context';
+
+// Initialize service
+const contactService = new ContactService(AppDataSource);
+
+// Path parameters schema
+const ParamsSchema = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    example: 1,
+    description: '联系人ID'
+  })
+});
+
+// Success response schema
+const SuccessResponseSchema = z.object({
+  code: z.number().openapi({ example: 200 }),
+  message: z.string().openapi({ example: 'success' }),
+  data: ContactSchema
+});
+
+// Route definition
+const routeDef = createRoute({
+  method: 'get',
+  path: '/{id}',
+  middleware: [authMiddleware],
+  request: {
+    params: ParamsSchema
+  },
+  responses: {
+    200: {
+      description: '获取联系人详情成功',
+      content: {
+        'application/json': { schema: SuccessResponseSchema }
+      }
+    },
+    400: {
+      description: '客户端错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    401: {
+      description: '未授权访问',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    404: {
+      description: '联系人不存在',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    }
+  }
+});
+
+// Create route instance
+const getByIdRoute = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    const { id } = c.req.valid('param');
+    const user = c.get('user');
+    
+    if (!user) {
+      return c.json({ 
+        code: 401, 
+        message: '未授权访问' 
+      }, 401);
+    }
+    
+    logger.api(`用户 ${user.id} 获取联系人详情: ${id}`);
+    const contact = await contactService.findOne(id);
+    
+    return c.json({
+      code: 200,
+      message: 'success',
+      data: contact
+    }, 200);
+  } catch (err) {
+    const error = err as Error;
+    logger.error('获取联系人详情失败:', error);
+    
+    // Check if error is "contact not found"
+    if (error.message === '联系人不存在') {
+      return c.json({ 
+        code: 404, 
+        message: error.message 
+      }, 404);
+    }
+    
+    return c.json({
+      code: 500,
+      message: error.message || '获取联系人详情失败'
+    }, 500);
+  }
+});
+
+export default getByIdRoute;

+ 106 - 0
src/server/api/contacts/get.ts

@@ -0,0 +1,106 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from '@hono/zod-openapi';
+import { AppDataSource } from '@/server/data-source';
+import { ContactService } from '@/server/modules/contacts/contact.service';
+import { ContactSchema } from '@/server/modules/contacts/contact.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { logger } from '@/server/utils/logger';
+import { AuthContext } from '@/server/types/context';
+
+// Initialize service
+const contactService = new ContactService(AppDataSource);
+
+// Query parameters 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: '每页数量'
+  }),
+  customerId: z.coerce.number().int().positive().optional().openapi({
+    example: 1,
+    description: '客户ID,用于筛选特定客户的联系人'
+  })
+});
+
+// Response schema
+const ResponseSchema = z.object({
+  code: z.number().openapi({ example: 200 }),
+  message: z.string().openapi({ example: 'success' }),
+  data: z.object({
+    data: z.array(ContactSchema),
+    pagination: z.object({
+      total: z.number().openapi({ example: 100 }),
+      current: z.number().openapi({ example: 1 }),
+      pageSize: z.number().openapi({ example: 10 })
+    })
+  })
+});
+
+// Route definition
+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 } }
+    },
+    401: {
+      description: '未授权访问',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    }
+  }
+});
+
+// Create route instance
+const getRoute = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    const { page, pageSize, customerId } = c.req.valid('query');
+    const user = c.get('user');
+    
+    if (!user) {
+      return c.json({ 
+        code: 401, 
+        message: '未授权访问' 
+      }, 401);
+    }
+    
+    logger.api(`用户 ${user.id} 获取联系人列表: 页码=${page}, 每页数量=${pageSize}, 客户ID=${customerId || '未指定'}`);
+    const result = await contactService.findAll(page, pageSize, customerId);
+    
+    return c.json({
+      code: 200,
+      message: 'success',
+      data: result
+    }, 200);
+  } catch (err) {
+    const error = err as Error;
+    logger.error('获取联系人列表失败:', error);
+    
+    return c.json({
+      code: 500,
+      message: error.message || '获取联系人列表失败'
+    }, 500);
+  }
+});
+
+export default getRoute;

+ 103 - 0
src/server/api/contacts/post.ts

@@ -0,0 +1,103 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from '@hono/zod-openapi';
+import { AppDataSource } from '@/server/data-source';
+import { ContactService } from '@/server/modules/contacts/contact.service';
+import { ContactSchema } from '@/server/modules/contacts/contact.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { logger } from '@/server/utils/logger';
+import { AuthContext } from '@/server/types/context';
+
+// Initialize service
+const contactService = new ContactService(AppDataSource);
+
+// Create request schema (omit auto-generated fields)
+const CreateContactSchema = ContactSchema.omit({
+  id: true,
+  createdAt: true,
+  updatedAt: true,
+  isDeleted: true
+});
+
+// Success response schema
+const SuccessResponseSchema = z.object({
+  code: z.number().openapi({ example: 200 }),
+  message: z.string().openapi({ example: '联系人创建成功' }),
+  data: ContactSchema
+});
+
+// Route definition
+const routeDef = createRoute({
+  method: 'post',
+  path: '/',
+  middleware: [authMiddleware],
+  request: {
+    body: {
+      content: {
+        'application/json': { schema: CreateContactSchema }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '联系人创建成功',
+      content: {
+        'application/json': { schema: SuccessResponseSchema }
+      }
+    },
+    400: {
+      description: '客户端错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    401: {
+      description: '未授权访问',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    }
+  }
+});
+
+// Create route instance
+const postRoute = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    const contactData = c.req.valid('json');
+    const user = c.get('user');
+    
+    if (!user) {
+      return c.json({ 
+        code: 401, 
+        message: '未授权访问' 
+      }, 401);
+    }
+    
+    logger.api(`用户 ${user.id} 创建联系人: %o`, contactData);
+    const newContact = await contactService.create(contactData);
+    
+    return c.json({
+      code: 200,
+      message: '联系人创建成功',
+      data: newContact
+    }, 200);
+  } catch (err) {
+    const error = err as Error;
+    logger.error('创建联系人失败:', error);
+    
+    // Handle validation errors
+    if (error instanceof z.ZodError) {
+      return c.json({
+        code: 400,
+        message: '参数验证失败: ' + error.errors.map(e => e.message).join(', ')
+      }, 400);
+    }
+    
+    return c.json({
+      code: 500,
+      message: error.message || '创建联系人失败'
+    }, 500);
+  }
+});
+
+export default postRoute;

+ 108 - 0
src/server/api/customers/[id]/delete.ts

@@ -0,0 +1,108 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from '@hono/zod-openapi';
+import { AppDataSource } from '@/server/data-source';
+import { CustomerService } from '@/server/modules/customers/customer.service';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { logger } from '@/server/utils/logger';
+import { AuthContext } from '@/server/types/context';
+
+// Initialize service
+const customerService = new CustomerService(AppDataSource);
+
+// Path parameters schema
+const ParamsSchema = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    example: 1,
+    description: '客户ID'
+  })
+});
+
+// Success response schema
+const SuccessResponseSchema = z.object({
+  code: z.number().openapi({ example: 200 }),
+  message: z.string().openapi({ example: '客户删除成功' }),
+  data: z.object({
+    success: z.boolean().openapi({ example: true })
+  })
+});
+
+// Route definition
+const routeDef = createRoute({
+  method: 'delete',
+  path: '/{id}',
+  middleware: [authMiddleware],
+  request: {
+    params: ParamsSchema
+  },
+  responses: {
+    200: {
+      description: '客户删除成功',
+      content: {
+        'application/json': { schema: SuccessResponseSchema }
+      }
+    },
+    400: {
+      description: '客户端错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    401: {
+      description: '未授权访问',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    404: {
+      description: '客户不存在',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    }
+  }
+});
+
+// Create route instance
+const deleteRoute = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    const { id } = c.req.valid('param');
+    const user = c.get('user');
+    
+    if (!user) {
+      return c.json({ 
+        code: 401, 
+        message: '未授权访问' 
+      }, 401);
+    }
+    
+    logger.api(`用户 ${user.id} 删除客户: ${id}`);
+    
+    // Check if customer exists
+    const existingCustomer = await customerService.findOne(id);
+    if (!existingCustomer) {
+      return c.json({ 
+        code: 404, 
+        message: '客户不存在' 
+      }, 404);
+    }
+    
+    // Delete customer (soft delete)
+    await customerService.remove(id);
+    
+    return c.json({
+      code: 200,
+      message: '客户删除成功',
+      data: { success: true }
+    }, 200);
+  } catch (err) {
+    const error = err as Error;
+    logger.error('删除客户失败:', error);
+    
+    return c.json({
+      code: 500,
+      message: error.message || '删除客户失败'
+    }, 500);
+  }
+});
+
+export default deleteRoute;

+ 103 - 0
src/server/api/customers/[id]/get.ts

@@ -0,0 +1,103 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from '@hono/zod-openapi';
+import { AppDataSource } from '@/server/data-source';
+import { CustomerService } from '@/server/modules/customers/customer.service';
+import { CustomerSchema } from '@/server/modules/customers/customer.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { logger } from '@/server/utils/logger';
+import { AuthContext } from '@/server/types/context';
+
+// Initialize service
+const customerService = new CustomerService(AppDataSource);
+
+// Path parameters schema
+const ParamsSchema = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    example: 1,
+    description: '客户ID'
+  })
+});
+
+// Success response schema
+const SuccessResponseSchema = z.object({
+  code: z.number().openapi({ example: 200 }),
+  message: z.string().openapi({ example: 'success' }),
+  data: CustomerSchema
+});
+
+// Route definition
+const routeDef = createRoute({
+  method: 'get',
+  path: '/{id}',
+  middleware: [authMiddleware],
+  request: {
+    params: ParamsSchema
+  },
+  responses: {
+    200: {
+      description: '获取客户详情成功',
+      content: {
+        'application/json': { schema: SuccessResponseSchema }
+      }
+    },
+    400: {
+      description: '客户端错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    401: {
+      description: '未授权访问',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    404: {
+      description: '客户不存在',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    }
+  }
+});
+
+// Create route instance
+const getByIdRoute = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    const { id } = c.req.valid('param');
+    const user = c.get('user');
+    
+    if (!user) {
+      return c.json({ 
+        code: 401, 
+        message: '未授权访问' 
+      }, 401);
+    }
+    
+    logger.api(`用户 ${user.id} 获取客户详情: ${id}`);
+    const customer = await customerService.findOne(id);
+    
+    if (!customer) {
+      return c.json({ 
+        code: 404, 
+        message: '客户不存在' 
+      }, 404);
+    }
+    
+    return c.json({
+      code: 200,
+      message: 'success',
+      data: customer
+    }, 200);
+  } catch (err) {
+    const error = err as Error;
+    logger.error('获取客户详情失败:', error);
+    
+    return c.json({
+      code: 500,
+      message: error.message || '获取客户详情失败'
+    }, 500);
+  }
+});
+
+export default getByIdRoute;

+ 129 - 0
src/server/api/customers/[id]/put.ts

@@ -0,0 +1,129 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from '@hono/zod-openapi';
+import { AppDataSource } from '@/server/data-source';
+import { CustomerService } from '@/server/modules/customers/customer.service';
+import { CustomerSchema } from '@/server/modules/customers/customer.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { logger } from '@/server/utils/logger';
+import { AuthContext } from '@/server/types/context';
+
+// Initialize service
+const customerService = new CustomerService(AppDataSource);
+
+// Path parameters schema
+const ParamsSchema = z.object({
+  id: z.coerce.number().int().positive().openapi({
+    param: { name: 'id', in: 'path' },
+    example: 1,
+    description: '客户ID'
+  })
+});
+
+// Update request schema (omit auto-generated fields)
+const UpdateCustomerSchema = CustomerSchema.omit({
+  id: true,
+  createdAt: true,
+  updatedAt: true,
+  isDeleted: true
+});
+
+// Success response schema
+const SuccessResponseSchema = z.object({
+  code: z.number().openapi({ example: 200 }),
+  message: z.string().openapi({ example: '客户更新成功' }),
+  data: CustomerSchema
+});
+
+// Route definition
+const routeDef = createRoute({
+  method: 'put',
+  path: '/{id}',
+  middleware: [authMiddleware],
+  request: {
+    params: ParamsSchema,
+    body: {
+      content: {
+        'application/json': { schema: UpdateCustomerSchema }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '客户更新成功',
+      content: {
+        'application/json': { schema: SuccessResponseSchema }
+      }
+    },
+    400: {
+      description: '客户端错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    401: {
+      description: '未授权访问',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    404: {
+      description: '客户不存在',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    }
+  }
+});
+
+// Create route instance
+const updateRoute = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    const { id } = c.req.valid('param');
+    const customerData = c.req.valid('json');
+    const user = c.get('user');
+    
+    if (!user) {
+      return c.json({ 
+        code: 401, 
+        message: '未授权访问' 
+      }, 401);
+    }
+    
+    logger.api(`用户 ${user.id} 更新客户: ${id}, 数据: %o`, customerData);
+    
+    // Check if customer exists
+    const existingCustomer = await customerService.findOne(id);
+    if (!existingCustomer) {
+      return c.json({ 
+        code: 404, 
+        message: '客户不存在' 
+      }, 404);
+    }
+    
+    // Update customer
+    const updatedCustomer = await customerService.update(id, customerData);
+    
+    return c.json({
+      code: 200,
+      message: '客户更新成功',
+      data: updatedCustomer
+    }, 200);
+  } catch (err) {
+    const error = err as Error;
+    logger.error('更新客户失败:', error);
+    
+    // Handle validation errors
+    if (error instanceof z.ZodError) {
+      return c.json({
+        code: 400,
+        message: '参数验证失败: ' + error.errors.map(e => e.message).join(', ')
+      }, 400);
+    }
+    
+    return c.json({
+      code: 500,
+      message: error.message || '更新客户失败'
+    }, 500);
+  }
+});
+
+export default updateRoute;

+ 86 - 0
src/server/api/customers/get.ts

@@ -0,0 +1,86 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from '@hono/zod-openapi';
+import { AppDataSource } from '@/server/data-source';
+import { CustomerService } from '@/server/modules/customers/customer.service';
+import { CustomerSchema } from '@/server/modules/customers/customer.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { AuthContext } from '@/server/types/context';
+import { authMiddleware } from '@/server/middleware/auth';
+import { logger } from '@/server/utils/logger';
+
+// Initialize service
+const customerService = new CustomerService(AppDataSource);
+
+// Query parameters 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: '每页数量'
+  })
+});
+
+// Response schema
+const ResponseSchema = z.object({
+  code: z.number().openapi({ example: 200 }),
+  message: z.string().openapi({ example: 'success' }),
+  data: z.object({
+    data: z.array(CustomerSchema),
+    pagination: z.object({
+      total: z.number().openapi({ example: 100 }),
+      current: z.number().openapi({ example: 1 }),
+      pageSize: z.number().openapi({ example: 10 })
+    })
+  })
+});
+
+// Route definition
+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 } }
+    }
+  }
+});
+
+// Create route instance
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    const { page, pageSize } = c.req.valid('query');
+    const result = await customerService.findAll(page, pageSize);
+    
+    return c.json({
+      code: 200,
+      message: 'success',
+      data: result
+    }, 200);
+  } catch (error) {
+    logger.error('获取客户列表失败:', error);
+    return c.json({
+      code: 500,
+      message: error instanceof Error ? error.message : '获取客户列表失败'
+    }, 500);
+  }
+});
+
+export default app;

+ 17 - 0
src/server/api/customers/index.ts

@@ -0,0 +1,17 @@
+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';
+
+// Create a new OpenAPI Hono instance for customer routes
+const customersApp = new OpenAPIHono()
+  // Register all customer routes
+  .route('/', listRoute)       // GET /customers
+  .route('/', createRoute)     // POST /customers
+  .route('/', getByIdRoute)    // GET /customers/{id}
+  .route('/', updateRoute)     // PUT /customers/{id}
+  .route('/', deleteRoute);    // DELETE /customers/{id}
+
+export default customersApp;

+ 104 - 0
src/server/api/customers/post.ts

@@ -0,0 +1,104 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from '@hono/zod-openapi';
+import { AppDataSource } from '@/server/data-source';
+import { CustomerService } from '@/server/modules/customers/customer.service';
+import { CustomerSchema } from '@/server/modules/customers/customer.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth';
+import { logger } from '@/server/utils/logger';
+import { AuthContext } from '@/server/types/context';
+
+// Initialize service
+const customerService = new CustomerService(AppDataSource);
+
+// Create request schema (omit auto-generated fields)
+const CreateCustomerSchema = CustomerSchema.omit({
+  id: true,
+  createdAt: true,
+  updatedAt: true,
+  isDeleted: true
+});
+
+// Success response schema
+const SuccessResponseSchema = z.object({
+  code: z.number().openapi({ example: 200 }),
+  message: z.string().openapi({ example: '客户创建成功' }),
+  data: CustomerSchema
+});
+
+// Route definition
+const routeDef = createRoute({
+  method: 'post',
+  path: '/',
+  middleware: [authMiddleware],
+  request: {
+    body: {
+      content: {
+        'application/json': { schema: CreateCustomerSchema }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '客户创建成功',
+      content: {
+        'application/json': { schema: SuccessResponseSchema }
+      }
+    },
+    400: {
+      description: '客户端错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    401: {
+      description: '未授权访问',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    }
+  }
+});
+
+// Create route instance
+const postRoute = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    // Get and validate request body
+    const customerData = c.req.valid('json');
+    const user = c.get('user');
+    
+    if (!user) {
+      return c.json({ 
+        code: 401, 
+        message: '未授权访问' 
+      }, 401);
+    }
+    
+    logger.api(`用户 ${user.id} 创建客户: %o`, customerData);
+    const newCustomer = await customerService.create(customerData);
+    
+    return c.json({
+      code: 200,
+      message: '客户创建成功',
+      data: newCustomer
+    }, 200);
+  } catch (err) {
+    const error = err as Error;
+    logger.error('创建客户失败:', error);
+    
+    // Handle validation errors
+    if (error instanceof z.ZodError) {
+      return c.json({
+        code: 400,
+        message: '参数验证失败: ' + error.errors.map(e => e.message).join(', ')
+      }, 400);
+    }
+    
+    return c.json({
+      code: 500,
+      message: error.message || '创建客户失败'
+    }, 500);
+  }
+});
+
+export default postRoute;

+ 53 - 0
src/server/middleware/auth.ts

@@ -0,0 +1,53 @@
+import { Context, MiddlewareHandler } from 'hono';
+import { AuthContext } from '@/server/types/context';
+import { AppErrors, createError } from '@/server/utils/errorHandler';
+import { logger } from '@/server/utils/logger';
+import { AppDataSource } from '@/server/data-source';
+import { User as UserEntity } from '@/server/modules/users/user.entity';
+import jwt from 'jsonwebtoken';
+
+/**
+ * 认证中间件 - 验证用户JWT令牌并设置用户上下文
+ */
+export const authMiddleware: MiddlewareHandler = async (c: Context<AuthContext>, next) => {
+  try {
+    // 获取Authorization头
+    const authHeader = c.req.header('Authorization');
+    
+    if (!authHeader || !authHeader.startsWith('Bearer ')) {
+      logger.error('未提供有效的Authorization令牌');
+      return c.json(AppErrors.UNAUTHORIZED, 401);
+    }
+    
+    // 提取并验证token
+    const token = authHeader.split(' ')[1];
+    let decoded: any;
+    
+    try {
+      // 使用环境变量中的密钥验证token
+      decoded = jwt.verify(token, process.env.JWT_SECRET || 'your-secret-key');
+    } catch (error) {
+      logger.error('令牌验证失败:', error);
+      return c.json(createError(401, '无效的令牌或令牌已过期'), 401);
+    }
+    
+    // 验证用户是否存在
+    const userRepository = AppDataSource.getRepository(UserEntity);
+    const user = await userRepository.findOne({
+      where: { id: decoded.userId, isDeleted: 0 }
+    });
+    
+    if (!user) {
+      logger.error(`令牌中的用户不存在: ${decoded.userId}`);
+      return c.json(createError(401, '用户不存在或已被删除'), 401);
+    }
+    
+    c.set('user', user);
+    
+    // 继续处理请求
+    await next();
+  } catch (error) {
+    logger.error('认证中间件错误:', error);
+    return c.json(AppErrors.SERVER_ERROR, 500);
+  }
+};

+ 94 - 0
src/server/modules/contacts/contact.service.ts

@@ -0,0 +1,94 @@
+import { DataSource, Repository } from 'typeorm';
+import { Contact } from './contact.entity';
+import { logger } from '@/server/utils/logger';
+
+export class ContactService {
+  private repository: Repository<Contact>;
+
+  constructor(dataSource: DataSource) {
+    this.repository = dataSource.getRepository(Contact);
+  }
+
+  async findAll(page: number = 1, pageSize: number = 10, customerId?: number) {
+    logger.api('Fetching contacts with pagination - page: %d, pageSize: %d, customerId: %s', 
+      page, pageSize, customerId);
+    
+    const where: any = { isDeleted: 0 };
+    if (customerId) {
+      where.customerId = customerId;
+    }
+    
+    const [data, total] = await this.repository.findAndCount({
+      skip: (page - 1) * pageSize,
+      take: pageSize,
+      where,
+      order: { updatedAt: 'DESC' }
+    });
+    
+    return {
+      data,
+      pagination: {
+        total,
+        current: page,
+        pageSize
+      }
+    };
+  }
+
+  async findOne(id: number) {
+    logger.api('Fetching contact with id: %d', id);
+    
+    const contact = await this.repository.findOne({
+      where: { id, isDeleted: 0 }
+    });
+    
+    if (!contact) {
+      logger.error('Contact not found with id: %d', id);
+      throw new Error('联系人不存在');
+    }
+    
+    return contact;
+  }
+
+  async create(contactData: Partial<Contact>) {
+    logger.api('Creating new contact: %o', contactData);
+    
+    const contact = this.repository.create({
+      ...contactData,
+      createdAt: new Date(),
+      updatedAt: new Date(),
+      isDeleted: 0
+    });
+    
+    return this.repository.save(contact);
+  }
+
+  async update(id: number, contactData: Partial<Contact>) {
+    logger.api('Updating contact with id: %d, data: %o', id, contactData);
+    
+    // Check if contact exists
+    await this.findOne(id);
+    
+    await this.repository.update(id, {
+      ...contactData,
+      updatedAt: new Date()
+    });
+    
+    return this.findOne(id);
+  }
+
+  async remove(id: number) {
+    logger.api('Deleting contact with id: %d', id);
+    
+    // Check if contact exists
+    await this.findOne(id);
+    
+    // Soft delete
+    await this.repository.update(id, { 
+      isDeleted: 1,
+      updatedAt: new Date()
+    });
+    
+    return { success: true };
+  }
+}

+ 88 - 0
src/server/modules/customers/customer.service.ts

@@ -0,0 +1,88 @@
+import { DataSource, Repository } from 'typeorm';
+import { Customer } from './customer.entity';
+import { logger } from '@/server/utils/logger';
+
+export class CustomerService {
+  private repository: Repository<Customer>;
+
+  constructor(dataSource: DataSource) {
+    this.repository = dataSource.getRepository(Customer);
+  }
+
+  async findAll(page: number = 1, pageSize: number = 10) {
+    logger.api('Fetching customers with pagination - page: %d, pageSize: %d', page, pageSize);
+    
+    const [data, total] = await this.repository.findAndCount({
+      skip: (page - 1) * pageSize,
+      take: pageSize,
+      where: { isDeleted: 0 },
+      order: { updatedAt: 'DESC' }
+    });
+    
+    return {
+      data,
+      pagination: {
+        total,
+        current: page,
+        pageSize
+      }
+    };
+  }
+
+  async findOne(id: number) {
+    logger.api('Fetching customer with id: %d', id);
+    
+    const customer = await this.repository.findOne({
+      where: { id, isDeleted: 0 }
+    });
+    
+    if (!customer) {
+      logger.error('Customer not found with id: %d', id);
+      throw new Error('客户不存在');
+    }
+    
+    return customer;
+  }
+
+  async create(customerData: Partial<Customer>) {
+    logger.api('Creating new customer: %o', customerData);
+    
+    const customer = this.repository.create({
+      ...customerData,
+      createdAt: new Date(),
+      updatedAt: new Date(),
+      isDeleted: 0
+    });
+    
+    return this.repository.save(customer);
+  }
+
+  async update(id: number, customerData: Partial<Customer>) {
+    logger.api('Updating customer with id: %d, data: %o', id, customerData);
+    
+    // Check if customer exists
+    await this.findOne(id);
+    
+    await this.repository.update(id, {
+      ...customerData,
+      updatedAt: new Date()
+    });
+    
+    return this.findOne(id);
+  }
+
+  async remove(id: number) {
+    logger.api('Deleting customer with id: %d', id);
+    
+    // Check if customer exists
+    await this.findOne(id);
+    
+    // Soft delete
+    await this.repository.update(id, { 
+      isDeleted: 1,
+      updatedAt: new Date()
+    });
+    
+    return { success: true };
+  }
+}

+ 12 - 0
src/server/types/context.ts

@@ -0,0 +1,12 @@
+import { User } from '../modules/users/user.entity';
+
+// 扩展Context类型
+export type Variables = {
+  user: User;
+}
+
+
+/**
+ * 带认证信息的上下文类型
+ */
+export type AuthContext = { Variables: Variables }

+ 41 - 0
src/server/utils/errorHandler.ts

@@ -0,0 +1,41 @@
+import { z } from '@hono/zod-openapi';
+
+/**
+ * 统一错误响应Schema
+ */
+export const ErrorSchema = z.object({
+  code: z.number().openapi({ 
+    example: 500, 
+    description: '错误代码' 
+  }),
+  message: z.string().openapi({ 
+    example: '操作失败', 
+    description: '错误信息' 
+  })
+});
+
+/**
+ * 错误响应类型定义
+ */
+export type ErrorResponse = z.infer<typeof ErrorSchema>;
+
+/**
+ * 创建标准化错误响应
+ * @param code 错误代码
+ * @param message 错误信息
+ * @returns 标准化错误对象
+ */
+export function createError(code: number, message: string): ErrorResponse {
+  return { code, message };
+}
+
+/**
+ * 常见错误类型
+ */
+export const AppErrors = {
+  NOT_FOUND: createError(404, '资源不存在'),
+  UNAUTHORIZED: createError(401, '未授权访问'),
+  FORBIDDEN: createError(403, '权限不足'),
+  VALIDATION_ERROR: createError(400, '参数验证失败'),
+  SERVER_ERROR: createError(500, '服务器内部错误')
+};

+ 27 - 0
src/server/utils/logger.ts

@@ -0,0 +1,27 @@
+import debug from 'debug';
+
+/**
+ * 后端日志工具,遵循项目日志规范
+ * 命名空间格式:backend:<模块>:<功能>
+ */
+export const logger = {
+  /** 错误日志 - 系统错误、异常情况 */
+  error: debug('backend:error'),
+  
+  /** API日志 - API请求与响应 */
+  api: debug('backend:api'),
+  
+  /** 数据库日志 - 数据库查询与操作 */
+  db: debug('backend:db'),
+  
+  /** 中间件日志 - 中间件处理流程 */
+  middleware: debug('backend:middleware'),
+  
+  /** 认证日志 - 登录、权限相关操作 */
+  auth: debug('backend:auth')
+};
+
+// 开发环境默认启用所有日志
+if (process.env.NODE_ENV === 'development') {
+  Object.values(logger).forEach(log => log.enabled = true);
+}