yourname 5 tháng trước cách đây
mục cha
commit
bdd294c32c

+ 7 - 0
src/server/api.ts

@@ -2,6 +2,8 @@ import { OpenAPIHono } from '@hono/zod-openapi'
 import { errorHandler } from './utils/errorHandler'
 import usersRouter from './api/users/index'
 import authRoute from './api/auth/index'
+import believersRoute from './api/believers/index'
+import groupsRoute from '@/server/api/groups/index';
 import { AuthContext } from './types/context'
 import { AppDataSource } from './data-source'
 
@@ -49,10 +51,15 @@ if(!import.meta.env.PROD){
 
 
 
+// 注册信徒管理路由
 const userRoutes = api.route('/api/v1/users', usersRouter)
 const authRoutes = api.route('/api/v1/auth', authRoute)
+const believersRoutes = api.route('/api/v1/believers', believersRoute);
+const groupsRoutes = api.route('/api/v1/groups', groupsRoute)
 
 export type AuthRoutes = typeof authRoutes
 export type UserRoutes = typeof userRoutes
+export type BelieversRoutes = typeof believersRoutes
+export type GroupsRoutes = typeof groupsRoutes
 
 export default api

+ 112 - 0
src/server/api/believers/get.ts

@@ -0,0 +1,112 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from '@hono/zod-openapi';
+import { AppDataSource } from '@/server/data-source';
+import { BelieverService } from '@/server/modules/believers/believer.service';
+import { BelieverSchema } from '@/server/modules/believers/believer.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth.middleware';
+import { AuthContext } from '@/server/types/context';
+
+// 查询参数Schema
+const GetBelieversQuery = 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
+  }),
+  keyword: z.string().optional().openapi({
+    description: '搜索关键词',
+    example: '张三'
+  })
+});
+
+// 响应Schema
+const BelieverListResponse = z.object({
+  data: z.array(BelieverSchema),
+  pagination: z.object({
+    total: z.number().openapi({
+      example: 100,
+      description: '总记录数'
+    }),
+    current: z.number().openapi({
+      example: 1,
+      description: '当前页码'
+    }),
+    pageSize: z.number().openapi({
+      example: 10,
+      description: '每页数量'
+    })
+  })
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'get',
+  path: '/',
+  middleware: [authMiddleware],
+  request: {
+    query: GetBelieversQuery
+  },
+  responses: {
+    200: {
+      description: '成功获取信徒列表',
+      content: {
+        'application/json': {
+          schema: BelieverListResponse
+        }
+      }
+    },
+    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 { page, pageSize, keyword } = c.req.valid('query');
+    const believerService = new BelieverService(AppDataSource);
+    
+    const [believers, total] = await believerService.getBelieversWithPagination({
+      page,
+      pageSize,
+      keyword
+    });
+    
+    return c.json({
+      data: believers,
+      pagination: {
+        total,
+        current: page,
+        pageSize
+      }
+    }, 200);
+  } catch (error) {
+    if (error instanceof z.ZodError) {
+      return c.json({ code: 400, message: '参数错误' }, 400);
+    }
+    return c.json({ 
+      code: 500, 
+      message: error instanceof Error ? error.message : '获取信徒列表失败' 
+    }, 500);
+  }
+});
+
+export default app;

+ 9 - 0
src/server/api/believers/index.ts

@@ -0,0 +1,9 @@
+import { OpenAPIHono } from '@hono/zod-openapi';
+import listBelieversRoute from './get';
+import createBelieverRoute from './post';
+
+const app = new OpenAPIHono()
+  .route('/', listBelieversRoute)
+  .route('/', createBelieverRoute);
+
+export default app;

+ 94 - 0
src/server/api/believers/post.ts

@@ -0,0 +1,94 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from '@hono/zod-openapi';
+import { AppDataSource } from '@/server/data-source';
+import { BelieverService } from '@/server/modules/believers/believer.service';
+import { Believer, BelieverSchema, BelieverStatus } from '@/server/modules/believers/believer.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth.middleware';
+import { AuthContext } from '@/server/types/context';
+
+// 创建信徒请求Schema
+const CreateBelieverSchema = BelieverSchema.omit({
+  id: true,
+  createdAt: true,
+  updatedAt: true,
+  createdBy: true
+}).extend({
+  status: z.enum([
+    BelieverStatus.ACTIVE, 
+    BelieverStatus.INACTIVE, 
+    BelieverStatus.TRANSFERRED, 
+    BelieverStatus.DECEASED
+  ]).optional().default(BelieverStatus.ACTIVE)
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'post',
+  path: '/',
+  middleware: [authMiddleware],
+  request: {
+    body: {
+      content: {
+        'application/json': {
+          schema: CreateBelieverSchema
+        }
+      }
+    }
+  },
+  responses: {
+    201: {
+      description: '成功创建信徒记录',
+      content: {
+        'application/json': {
+          schema: BelieverSchema
+        }
+      }
+    },
+    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 data = c.req.valid('json');
+    const user = c.get('user');
+    if (!user) {
+      return c.json({ code: 401, message: '未授权' }, 401);
+    }
+    
+    const believerService = new BelieverService(AppDataSource);
+    const believer = await believerService.createBeliever({
+      ...data,
+      createdBy: user.id
+    });
+    
+    return c.json(believer, 201);
+  } catch (error) {
+    if (error instanceof z.ZodError) {
+      return c.json({ code: 400, message: '参数错误' }, 400);
+    }
+    return c.json({ 
+      code: 500, 
+      message: error instanceof Error ? error.message : '创建信徒记录失败' 
+    }, 500);
+  }
+});
+
+export default app;

+ 113 - 0
src/server/api/groups/get.ts

@@ -0,0 +1,113 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from '@hono/zod-openapi';
+import { AppDataSource } from '@/server/data-source';
+import { GroupService } from '@/server/modules/groups/group.service';
+import { GroupSchema } from '@/server/modules/groups/group.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth.middleware';
+import { AuthContext } from '@/server/types/context';
+
+// 查询参数Schema
+const GetGroupsQuery = 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
+  }),
+  keyword: z.string().optional().openapi({
+    description: '搜索关键词',
+    example: '青年团契'
+  })
+});
+
+// 响应Schema
+const GroupListResponse = z.object({
+  data: z.array(GroupSchema),
+  pagination: z.object({
+    total: z.number().openapi({
+      example: 100,
+      description: '总记录数'
+    }),
+    current: z.number().openapi({
+      example: 1,
+      description: '当前页码'
+    }),
+    pageSize: z.number().openapi({
+      example: 10,
+      description: '每页数量'
+    })
+  })
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'get',
+  path: '/',
+  middleware: [authMiddleware],
+  request: {
+    query: GetGroupsQuery
+  },
+  responses: {
+    200: {
+      description: '成功获取小组列表',
+      content: {
+        'application/json': {
+          schema: GroupListResponse
+        }
+      }
+    },
+    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 { page, pageSize, keyword } = c.req.valid('query');
+    const groupService = new GroupService(AppDataSource);
+    
+    const [groups, total] = await groupService.getGroupsWithPagination({
+      page,
+      pageSize,
+      keyword
+    });
+    
+    const response = c.json({
+      data: groups,
+      pagination: {
+        total,
+        current: page,
+        pageSize
+      }
+    }, 200);
+    return response;
+  } catch (error) {
+    if (error instanceof z.ZodError) {
+      return c.json({ code: 400, message: '参数错误' }, 400);
+    }
+    return c.json({ 
+      code: 500, 
+      message: error instanceof Error ? error.message : '获取小组列表失败' 
+    }, 500);
+  }
+});
+
+export default app;

+ 30 - 0
src/server/api/groups/index.ts

@@ -0,0 +1,30 @@
+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 addBelieverRoute from './[id]/believers/post';
+import removeBelieverRoute from './[id]/believers/[believerId]/delete';
+import listBelieversRoute from './[id]/believers/get';
+import setLeaderRoute from './[id]/leader/put';
+
+// 创建路由实例
+const app = new OpenAPIHono<AuthContext>()
+  // 小组CRUD
+  .route('/', listRoute)
+  .route('/', createRoute)
+  .route('/{id}', getByIdRoute)
+  .route('/{id}', updateRoute)
+  .route('/{id}', deleteRoute)
+  // 小组信徒管理
+  .route('/{id}/believers', listBelieversRoute)
+  .route('/{id}/believers', addBelieverRoute)
+  .route('/{id}/believers/{believerId}', removeBelieverRoute)
+  // 组长管理
+  .route('/{id}/leader', setLeaderRoute);
+
+export default app;

+ 85 - 0
src/server/api/groups/post.ts

@@ -0,0 +1,85 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from '@hono/zod-openapi';
+import { AppDataSource } from '@/server/data-source';
+import { GroupService } from '@/server/modules/groups/group.service';
+import { Group, GroupSchema } from '@/server/modules/groups/group.entity';
+import { ErrorSchema } from '@/server/utils/errorHandler';
+import { authMiddleware } from '@/server/middleware/auth.middleware';
+import { AuthContext } from '@/server/types/context';
+
+// 创建小组请求Schema
+const CreateGroupSchema = GroupSchema.omit({
+  id: true,
+  createdAt: true,
+  updatedAt: true
+});
+
+// 路由定义
+const routeDef = createRoute({
+  method: 'post',
+  path: '/',
+  middleware: [authMiddleware],
+  request: {
+    body: {
+      content: {
+        'application/json': {
+          schema: CreateGroupSchema
+        }
+      }
+    }
+  },
+  responses: {
+    201: {
+      description: '成功创建小组记录',
+      content: {
+        'application/json': {
+          schema: GroupSchema
+        }
+      }
+    },
+    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 data = c.req.valid('json');
+    const user = c.get('user');
+    
+    if (!user) {
+      return c.json({ code: 401, message: '未授权' }, 401);
+    }
+    
+    const groupService = new GroupService(AppDataSource);
+    const group = await groupService.createGroup(data);
+    
+    const response = c.json(group, 201);
+    return response as any;
+  } catch (error) {
+    if (error instanceof z.ZodError) {
+      return c.json({ code: 400, message: '参数错误' }, 400);
+    }
+    return c.json({ 
+      code: 500, 
+      message: error instanceof Error ? error.message : '创建小组记录失败' 
+    }, 500);
+  }
+});
+
+export default app;

+ 107 - 0
src/server/modules/believers/believer.entity.ts

@@ -0,0 +1,107 @@
+import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
+import { z } from '@hono/zod-openapi';
+
+export enum BelieverStatus {
+  ACTIVE = 'active',
+  INACTIVE = 'inactive',
+  TRANSFERRED = 'transferred',
+  DECEASED = 'deceased'
+}
+
+@Entity('believers')
+export class Believer {
+  @PrimaryGeneratedColumn({ unsigned: true, comment: '信徒ID' })
+  id!: number;
+
+  @Column({ name: 'name', type: 'varchar', length: 100, comment: '姓名' })
+  name!: string;
+
+  @Column({ name: 'gender', type: 'varchar', length: 10, comment: '性别' })
+  gender!: string;
+
+  @Column({ name: 'birth_date', type: 'date', nullable: true, comment: '出生日期' })
+  birthDate!: Date | null;
+
+  @Column({ name: 'contact_info', type: 'varchar', length: 200, comment: '联系方式' })
+  contactInfo!: string;
+
+  @Column({ name: 'address', type: 'varchar', length: 255, nullable: true, comment: '住址' })
+  address!: string | null;
+
+  @Column({ name: 'baptism_date', type: 'date', nullable: true, comment: '受洗日期' })
+  baptismDate!: Date | null;
+
+  @Column({ 
+    name: 'status', 
+    type: 'varchar', 
+    length: 20, 
+    default: BelieverStatus.ACTIVE, 
+    comment: '状态(active:活跃, inactive:不活跃, transferred:已转会, deceased:已故)' 
+  })
+  status!: BelieverStatus;
+
+  @Column({ name: 'created_by', type: 'int', unsigned: true, comment: '创建人ID' })
+  createdBy!: number;
+
+  @CreateDateColumn({ name: 'created_at', type: 'timestamp', comment: '创建时间' })
+  createdAt!: Date;
+
+  @UpdateDateColumn({ name: 'updated_at', type: 'timestamp', comment: '更新时间' })
+  updatedAt!: Date;
+
+  constructor(partial?: Partial<Believer>) {
+    Object.assign(this, partial);
+  }
+}
+
+export const BelieverSchema = z.object({
+  id: z.number().int().positive().openapi({ 
+    description: '信徒ID',
+    example: 1 
+  }),
+  name: z.string().max(100).openapi({ 
+    description: '姓名',
+    example: '张三' 
+  }),
+  gender: z.string().max(10).openapi({ 
+    description: '性别',
+    example: '男' 
+  }),
+  birthDate: z.date().nullable().openapi({ 
+    description: '出生日期',
+    example: '1980-01-15' 
+  }),
+  contactInfo: z.string().max(200).openapi({ 
+    description: '联系方式',
+    example: '13800138000' 
+  }),
+  address: z.string().max(255).nullable().openapi({ 
+    description: '住址',
+    example: '北京市海淀区' 
+  }),
+  baptismDate: z.date().nullable().openapi({ 
+    description: '受洗日期',
+    example: '2010-05-20' 
+  }),
+  status: z.enum([
+    BelieverStatus.ACTIVE, 
+    BelieverStatus.INACTIVE, 
+    BelieverStatus.TRANSFERRED, 
+    BelieverStatus.DECEASED
+  ]).openapi({ 
+    description: '信徒状态',
+    example: BelieverStatus.ACTIVE 
+  }),
+  createdBy: z.number().int().positive().openapi({ 
+    description: '创建人ID',
+    example: 1 
+  }),
+  createdAt: z.date().openapi({ 
+    description: '创建时间',
+    example: '2023-01-01T00:00:00Z' 
+  }),
+  updatedAt: z.date().openapi({ 
+    description: '更新时间',
+    example: '2023-01-01T00:00:00Z' 
+  })
+});

+ 86 - 0
src/server/modules/believers/believer.service.ts

@@ -0,0 +1,86 @@
+import { DataSource, Repository } from 'typeorm';
+import { Believer } from './believer.entity';
+import { logger } from '@/server/utils/logger';
+
+export class BelieverService {
+  private believerRepository: Repository<Believer>;
+
+  constructor(dataSource: DataSource) {
+    this.believerRepository = dataSource.getRepository(Believer);
+  }
+
+  /**
+   * 创建新信徒记录
+   */
+  async createBeliever(data: Partial<Believer>): Promise<Believer> {
+    try {
+      const believer = this.believerRepository.create(data);
+      return await this.believerRepository.save(believer);
+    } catch (error) {
+      logger.error('创建信徒失败:', error);
+      throw new Error('创建信徒记录失败');
+    }
+  }
+
+  /**
+   * 获取信徒列表(分页)
+   */
+  async getBelieversWithPagination(params: {
+    page: number;
+    pageSize: number;
+    keyword?: string;
+  }): Promise<[Believer[], number]> {
+    const { page, pageSize, keyword } = params;
+    const skip = (page - 1) * pageSize;
+    
+    const query = this.believerRepository.createQueryBuilder('believer');
+    
+    if (keyword) {
+      query.andWhere('believer.name LIKE :keyword', { keyword: `%${keyword}%` })
+           .orWhere('believer.contactInfo LIKE :keyword', { keyword: `%${keyword}%` });
+    }
+    
+    return query.skip(skip)
+                .take(pageSize)
+                .orderBy('believer.createdAt', 'DESC')
+                .getManyAndCount();
+  }
+
+  /**
+   * 根据ID获取信徒详情
+   */
+  async getBelieverById(id: number): Promise<Believer | null> {
+    try {
+      return await this.believerRepository.findOneBy({ id });
+    } catch (error) {
+      logger.error(`获取信徒ID为${id}的详情失败:`, error);
+      throw new Error('获取信徒详情失败');
+    }
+  }
+
+  /**
+   * 更新信徒信息
+   */
+  async updateBeliever(id: number, data: Partial<Believer>): Promise<Believer | null> {
+    try {
+      await this.believerRepository.update(id, data);
+      return this.getBelieverById(id);
+    } catch (error) {
+      logger.error(`更新信徒ID为${id}的信息失败:`, error);
+      throw new Error('更新信徒信息失败');
+    }
+  }
+
+  /**
+   * 删除信徒记录
+   */
+  async deleteBeliever(id: number): Promise<boolean> {
+    try {
+      const result = await this.believerRepository.delete(id);
+      return result.affected === 1;
+    } catch (error) {
+      logger.error(`删除信徒ID为${id}的记录失败:`, error);
+      throw new Error('删除信徒记录失败');
+    }
+  }
+}

+ 48 - 0
src/server/modules/groups/believer-group.entity.ts

@@ -0,0 +1,48 @@
+import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, CreateDateColumn } from 'typeorm';
+import { z } from '@hono/zod-openapi';
+import { Believer } from '../believers/believer.entity';
+import { Group } from './group.entity';
+
+@Entity('believer_group')
+export class BelieverGroup {
+  @PrimaryGeneratedColumn({ unsigned: true, comment: 'ID' })
+  id!: number;
+
+  @Column({ name: 'believer_id', type: 'int', unsigned: true, comment: '信徒ID' })
+  believerId!: number;
+
+  @Column({ name: 'group_id', type: 'int', unsigned: true, comment: '小组ID' })
+  groupId!: number;
+
+  @Column({ name: 'joined_at', type: 'timestamp', default: () => 'CURRENT_TIMESTAMP', comment: '加入时间' })
+  joinedAt!: Date;
+
+  @ManyToOne(() => Believer, believer => believer.id)
+  believer!: Believer;
+
+  @ManyToOne(() => Group, group => group.believerGroups)
+  group!: Group;
+
+  constructor(partial?: Partial<BelieverGroup>) {
+    Object.assign(this, partial);
+  }
+}
+
+export const BelieverGroupSchema = z.object({
+  id: z.number().int().positive().openapi({
+    description: '记录ID',
+    example: 1
+  }),
+  believerId: z.number().int().positive().openapi({
+    description: '信徒ID',
+    example: 123
+  }),
+  groupId: z.number().int().positive().openapi({
+    description: '小组ID',
+    example: 1
+  }),
+  joinedAt: z.date().openapi({
+    description: '加入时间',
+    example: '2023-01-01T00:00:00Z'
+  })
+});

+ 62 - 0
src/server/modules/groups/group.entity.ts

@@ -0,0 +1,62 @@
+import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, OneToMany } from 'typeorm';
+import { z } from '@hono/zod-openapi';
+import { Believer } from '../believers/believer.entity';
+import { BelieverGroup } from './believer-group.entity';
+
+@Entity('groups')
+export class Group {
+  @PrimaryGeneratedColumn({ unsigned: true, comment: '小组ID' })
+  id!: number;
+
+  @Column({ name: 'name', type: 'varchar', length: 100, comment: '小组名称' })
+  name!: string;
+
+  @Column({ name: 'description', type: 'text', nullable: true, comment: '小组描述' })
+  description!: string | null;
+
+  @Column({ name: 'leader_id', type: 'int', unsigned: true, nullable: true, comment: '组长ID' })
+  leaderId!: number | null;
+
+  @ManyToOne(() => Believer, believer => believer.id)
+  leader?: Believer;
+
+  @OneToMany(() => BelieverGroup, believerGroup => believerGroup.group)
+  believerGroups!: BelieverGroup[];
+
+  @CreateDateColumn({ name: 'created_at', type: 'timestamp', comment: '创建时间' })
+  createdAt!: Date;
+
+  @UpdateDateColumn({ name: 'updated_at', type: 'timestamp', comment: '更新时间' })
+  updatedAt!: Date;
+
+  constructor(partial?: Partial<Group>) {
+    Object.assign(this, partial);
+  }
+}
+
+export const GroupSchema = z.object({
+  id: z.number().int().positive().openapi({
+    description: '小组ID',
+    example: 1
+  }),
+  name: z.string().max(100).openapi({
+    description: '小组名称',
+    example: '青年团契'
+  }),
+  description: z.string().nullable().openapi({
+    description: '小组描述',
+    example: '18-30岁青年组成的团契小组'
+  }),
+  leaderId: z.number().int().positive().nullable().openapi({
+    description: '组长ID',
+    example: 123
+  }),
+  createdAt: z.date().openapi({
+    description: '创建时间',
+    example: '2023-01-01T00:00:00Z'
+  }),
+  updatedAt: z.date().openapi({
+    description: '更新时间',
+    example: '2023-01-01T00:00:00Z'
+  })
+});

+ 179 - 0
src/server/modules/groups/group.service.ts

@@ -0,0 +1,179 @@
+import { DataSource, Repository } from 'typeorm';
+import { Group } from './group.entity';
+import { BelieverGroup } from './believer-group.entity';
+import { logger } from '@/server/utils/logger';
+import { Believer } from '../believers/believer.entity';
+
+export class GroupService {
+  private groupRepository: Repository<Group>;
+  private believerGroupRepository: Repository<BelieverGroup>;
+
+  constructor(dataSource: DataSource) {
+    this.groupRepository = dataSource.getRepository(Group);
+    this.believerGroupRepository = dataSource.getRepository(BelieverGroup);
+  }
+
+  /**
+   * 创建小组
+   */
+  async createGroup(data: Partial<Group>): Promise<Group> {
+    try {
+      const group = this.groupRepository.create(data);
+      return await this.groupRepository.save(group);
+    } catch (error) {
+      logger.error('创建小组失败:', error);
+      throw new Error('创建小组记录失败');
+    }
+  }
+
+  /**
+   * 获取小组列表(分页)
+   */
+  async getGroupsWithPagination(params: {
+    page: number;
+    pageSize: number;
+    keyword?: string;
+  }): Promise<[Group[], number]> {
+    const { page, pageSize, keyword } = params;
+    const skip = (page - 1) * pageSize;
+    
+    const query = this.groupRepository.createQueryBuilder('group');
+    
+    if (keyword) {
+      query.andWhere('group.name LIKE :keyword', { keyword: `%${keyword}%` })
+           .orWhere('group.description LIKE :keyword', { keyword: `%${keyword}%` });
+    }
+    
+    return query.skip(skip)
+                .take(pageSize)
+                .orderBy('group.createdAt', 'DESC')
+                .getManyAndCount();
+  }
+
+  /**
+   * 根据ID获取小组详情
+   */
+  async getGroupById(id: number): Promise<Group | null> {
+    try {
+      return await this.groupRepository.findOneBy({ id });
+    } catch (error) {
+      logger.error(`获取小组ID为${id}的详情失败:`, error);
+      throw new Error('获取小组详情失败');
+    }
+  }
+
+  /**
+   * 更新小组信息
+   */
+  async updateGroup(id: number, data: Partial<Group>): Promise<Group | null> {
+    try {
+      await this.groupRepository.update(id, data);
+      return this.getGroupById(id);
+    } catch (error) {
+      logger.error(`更新小组ID为${id}的信息失败:`, error);
+      throw new Error('更新小组信息失败');
+    }
+  }
+
+  /**
+   * 删除小组
+   */
+  async deleteGroup(id: number): Promise<boolean> {
+    try {
+      // 先删除关联记录
+      await this.believerGroupRepository.delete({ groupId: id });
+      
+      // 再删除小组
+      const result = await this.groupRepository.delete(id);
+      return result.affected === 1;
+    } catch (error) {
+      logger.error(`删除小组ID为${id}的记录失败:`, error);
+      throw new Error('删除小组记录失败');
+    }
+  }
+
+  /**
+   * 添加信徒到小组
+   */
+  async addBelieverToGroup(believerId: number, groupId: number): Promise<BelieverGroup> {
+    try {
+      // 检查是否已存在关联
+      const existing = await this.believerGroupRepository.findOneBy({
+        believerId,
+        groupId
+      });
+      
+      if (existing) {
+        throw new Error('该信徒已在小组中');
+      }
+      
+      const believerGroup = this.believerGroupRepository.create({
+        believerId,
+        groupId
+      });
+      
+      return await this.believerGroupRepository.save(believerGroup);
+    } catch (error) {
+      logger.error(`添加信徒${believerId}到小组${groupId}失败:`, error);
+      throw error instanceof Error ? error : new Error('添加信徒到小组失败');
+    }
+  }
+
+  /**
+   * 从小组移除信徒
+   */
+  async removeBelieverFromGroup(believerId: number, groupId: number): Promise<boolean> {
+    try {
+      const result = await this.believerGroupRepository.delete({
+        believerId,
+        groupId
+      });
+      
+      return result.affected === 1;
+    } catch (error) {
+      logger.error(`从小组${groupId}移除信徒${believerId}失败:`, error);
+      throw new Error('从小组移除信徒失败');
+    }
+  }
+
+  /**
+   * 获取小组的所有信徒
+   */
+  async getBelieversInGroup(groupId: number): Promise<Believer[]> {
+    try {
+      const query = this.believerGroupRepository.createQueryBuilder('believerGroup')
+        .leftJoinAndSelect('believerGroup.believer', 'believer')
+        .where('believerGroup.groupId = :groupId', { groupId });
+      
+      const believerGroups = await query.getMany();
+      return believerGroups.map(bg => bg.believer);
+    } catch (error) {
+      logger.error(`获取小组${groupId}的信徒列表失败:`, error);
+      throw new Error('获取小组信徒列表失败');
+    }
+  }
+
+  /**
+   * 设置小组组长
+   */
+  async setGroupLeader(groupId: number, leaderId: number): Promise<Group | null> {
+    try {
+      // 先确认该信徒是否在小组中
+      const isMember = await this.believerGroupRepository.exists({
+        where: {
+          groupId,
+          believerId: leaderId
+        }
+      });
+      
+      if (!isMember) {
+        throw new Error('组长必须是小组中的成员');
+      }
+      
+      return this.updateGroup(groupId, { leaderId });
+    } catch (error) {
+      logger.error(`设置小组${groupId}的组长${leaderId}失败:`, error);
+      throw error instanceof Error ? error : new Error('设置小组组长失败');
+    }
+  }
+}