Răsfoiți Sursa

🗑️ chore(api): remove unused customer, opportunity and follow-up modules

- delete customer, opportunity and follow-up entity files
- remove related service and route files
- clean up API type definitions and route registrations
- remove entities from data source configuration
- delete client API definitions for removed modules
yourname 8 luni în urmă
părinte
comite
f7e9d6d415

+ 1 - 13
src/client/api.ts

@@ -1,7 +1,7 @@
 import axios, { isAxiosError } from 'axios';
 import { hc } from 'hono/client'
 import type {
-  AuthRoutes, UserRoutes, RoleRoutes, CustomerRoutes, OpportunityRoutes, FollowUpRoutes,
+  AuthRoutes, UserRoutes, RoleRoutes, 
   AreaRoutes, ClientRoutes, ExpenseRoutes, FileRoutes, HetongRoutes, HetongRenewRoutes, LinkmanRoutes, LogfileRoutes
 } from '@/server/api';
 
@@ -72,18 +72,6 @@ export const roleClient = hc<RoleRoutes>('/', {
   fetch: axiosFetch,
 }).api.v1.roles;
 
-export const customerClient = hc<CustomerRoutes>('/', {
-  fetch: axiosFetch,
-}).api.v1.customers;
-
-export const opportunityClient = hc<OpportunityRoutes>('/', {
-  fetch: axiosFetch,
-}).api.v1.opportunities;
-
-export const followUpClient = hc<FollowUpRoutes>('/', {
-  fetch: axiosFetch,
-}).api.v1['follow-ups'];
-
 export const areaClient = hc<AreaRoutes>('/', {
   fetch: axiosFetch,
 }).api.v1.areas;

+ 0 - 9
src/server/api.ts

@@ -3,9 +3,6 @@ import { errorHandler } from './utils/errorHandler'
 import usersRouter from './api/users/index'
 import authRoute from './api/auth/index'
 import rolesRoute from './api/roles/index'
-import customerRoutes from './api/customers/index'
-import opportunityRoutes from './api/opportunities/index'
-import followUpRoutes from './api/follow-ups/index'
 // 新实体路由导入
 import areaRoutes from './api/areas/index'
 import clientRoutes from './api/clients/index'
@@ -65,9 +62,6 @@ if(!import.meta.env.PROD){
 const userRoutes = api.route('/api/v1/users', usersRouter)
 const authRoutes = api.route('/api/v1/auth', authRoute)
 const roleRoutes = api.route('/api/v1/roles', rolesRoute)
-const customerApiRoutes = api.route('/api/v1/customers', customerRoutes)
-const opportunityApiRoutes = api.route('/api/v1/opportunities', opportunityRoutes)
-const followUpApiRoutes = api.route('/api/v1/follow-ups', followUpRoutes)
 // 新实体路由注册
 const areaApiRoutes = api.route('/api/v1/areas', areaRoutes)
 const clientApiRoutes = api.route('/api/v1/clients', clientRoutes)
@@ -81,9 +75,6 @@ const logfileApiRoutes = api.route('/api/v1/logs', logfileRoutes)
 export type AuthRoutes = typeof authRoutes
 export type UserRoutes = typeof userRoutes
 export type RoleRoutes = typeof roleRoutes
-export type CustomerRoutes = typeof customerApiRoutes
-export type OpportunityRoutes = typeof opportunityApiRoutes
-export type FollowUpRoutes = typeof followUpApiRoutes
 // 新实体路由类型导出
 export type AreaRoutes = typeof areaApiRoutes
 export type ClientRoutes = typeof clientApiRoutes

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

@@ -1,16 +0,0 @@
-import { createCrudRoutes } from '@/server/utils/generic-crud.routes';
-import { Customer } from '@/server/modules/customers/customer.entity';
-import { CustomerSchema, CreateCustomerDto, UpdateCustomerDto } from '@/server/modules/customers/customer.entity';
-import { authMiddleware } from '@/server/middleware/auth.middleware';
-
-const customerRoutes = createCrudRoutes({
-  entity: Customer,
-  createSchema: CreateCustomerDto,
-  updateSchema: UpdateCustomerDto,
-  getSchema: CustomerSchema,
-  listSchema: CustomerSchema,
-  searchFields: ['name', 'company', 'phone', 'email'],
-  middleware: [authMiddleware]
-});
-
-export default customerRoutes;

+ 0 - 16
src/server/api/follow-ups/index.ts

@@ -1,16 +0,0 @@
-import { createCrudRoutes } from '@/server/utils/generic-crud.routes';
-import { FollowUp } from '@/server/modules/follow-ups/follow-up.entity';
-import { FollowUpSchema, CreateFollowUpDto, UpdateFollowUpDto } from '@/server/modules/follow-ups/follow-up.entity';
-import { authMiddleware } from '@/server/middleware/auth.middleware';
-
-const followUpRoutes = createCrudRoutes({
-  entity: FollowUp,
-  createSchema: CreateFollowUpDto,
-  updateSchema: UpdateFollowUpDto,
-  getSchema: FollowUpSchema,
-  listSchema: FollowUpSchema,
-  searchFields: ['content', 'method'],
-  middleware: [authMiddleware]
-});
-
-export default followUpRoutes;

+ 0 - 16
src/server/api/opportunities/index.ts

@@ -1,16 +0,0 @@
-import { createCrudRoutes } from '@/server/utils/generic-crud.routes';
-import { Opportunity } from '@/server/modules/opportunities/opportunity.entity';
-import { OpportunitySchema, CreateOpportunityDto, UpdateOpportunityDto } from '@/server/modules/opportunities/opportunity.entity';
-import { authMiddleware } from '@/server/middleware/auth.middleware';
-
-const opportunityRoutes = createCrudRoutes({
-  entity: Opportunity,
-  createSchema: CreateOpportunityDto,
-  updateSchema: UpdateOpportunityDto,
-  getSchema: OpportunitySchema,
-  listSchema: OpportunitySchema,
-  searchFields: ['title', 'description', 'stage'],
-  middleware: [authMiddleware]
-});
-
-export default opportunityRoutes;

+ 1 - 4
src/server/data-source.ts

@@ -5,9 +5,6 @@ import process from 'node:process'
 // 实体类导入
 import { UserEntity as User } from "./modules/users/user.entity"
 import { Role } from "./modules/users/role.entity"
-import { Customer } from "./modules/customers/customer.entity"
-import { Opportunity } from "./modules/opportunities/opportunity.entity"
-import { FollowUp } from "./modules/follow-ups/follow-up.entity"
 // 新实体导入
 import { AreaData } from "./modules/areas/area-data.entity"
 import { Client } from "./modules/clients/client.entity"
@@ -26,7 +23,7 @@ export const AppDataSource = new DataSource({
   password: process.env.DB_PASSWORD || "",
   database: process.env.DB_DATABASE || "d8dai",
   entities: [
-    User, Role, Customer, Opportunity, FollowUp,
+    User, Role, 
     AreaData, Client, Expense, File, Hetong, HetongRenew, Linkman, Logfile
   ],
   migrations: [],

+ 0 - 117
src/server/modules/customers/customer.entity.ts

@@ -1,117 +0,0 @@
-import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
-import { z } from '@hono/zod-openapi';
-
-@Entity('customer')
-export class Customer {
-  @PrimaryGeneratedColumn({ unsigned: true, comment: '客户ID' })
-  id!: number;
-
-  @Column({ name: 'name', type: 'varchar', length: 255, comment: '客户姓名' })
-  name!: string;
-
-  @Column({ name: 'phone', type: 'varchar', length: 20, nullable: true, comment: '联系电话' })
-  phone!: string | null;
-
-  @Column({ name: 'email', type: 'varchar', length: 255, nullable: true, comment: '电子邮箱' })
-  email!: string | null;
-
-  @Column({ name: 'company', type: 'varchar', length: 255, nullable: true, comment: '公司名称' })
-  company!: string | null;
-
-  @Column({ name: 'source', type: 'varchar', length: 50, nullable: true, comment: '客户来源' })
-  source!: string | null;
-
-  @Column({ name: 'is_deleted', type: 'tinyint', default: 0, comment: '是否删除(0:未删除,1:已删除)' })
-  isDeleted!: number;
-
-  @CreateDateColumn({ name: 'created_at', type: 'timestamp', comment: '创建时间' })
-  createdAt!: Date;
-
-  @UpdateDateColumn({ name: 'updated_at', type: 'timestamp', comment: '更新时间' })
-  updatedAt!: Date;
-}
-
-export const CustomerSchema = z.object({
-  id: z.number().int().positive().openapi({
-    description: '客户ID',
-    example: 1
-  }),
-  name: z.string().max(255).openapi({
-    description: '客户姓名',
-    example: '张三'
-  }),
-  phone: z.string().max(20).nullable().openapi({
-    description: '联系电话',
-    example: '13800138000'
-  }),
-  email: z.string().email().nullable().openapi({
-    description: '电子邮箱',
-    example: 'zhangsan@example.com'
-  }),
-  company: z.string().max(255).nullable().openapi({
-    description: '公司名称',
-    example: '示例科技有限公司'
-  }),
-  source: z.string().max(50).nullable().openapi({
-    description: '客户来源',
-    example: '网站'
-  }),
-  isDeleted: z.number().int().min(0).max(1).openapi({
-    description: '是否删除(0:未删除,1:已删除)',
-    example: 0
-  }),
-  createdAt: z.date().openapi({
-    description: '创建时间',
-    example: '2023-01-01T00:00:00Z'
-  }),
-  updatedAt: z.date().openapi({
-    description: '更新时间',
-    example: '2023-01-01T00:00:00Z'
-  })
-});
-
-export const CreateCustomerDto = z.object({
-  name: z.string().max(255).openapi({
-    description: '客户姓名',
-    example: '张三'
-  }),
-  phone: z.string().max(20).nullable().optional().openapi({
-    description: '联系电话',
-    example: '13800138000'
-  }),
-  email: z.string().email().nullable().optional().openapi({
-    description: '电子邮箱',
-    example: 'zhangsan@example.com'
-  }),
-  company: z.string().max(255).nullable().optional().openapi({
-    description: '公司名称',
-    example: '示例科技有限公司'
-  }),
-  source: z.string().max(50).nullable().optional().openapi({
-    description: '客户来源',
-    example: '网站'
-  })
-});
-
-export const UpdateCustomerDto = z.object({
-  name: z.string().max(255).optional().openapi({
-    description: '客户姓名',
-    example: '张三'
-  }),
-  phone: z.string().max(20).nullable().optional().openapi({
-    description: '联系电话',
-    example: '13800138000'
-  }),
-  email: z.string().email().nullable().optional().openapi({
-    description: '电子邮箱',
-    example: 'zhangsan@example.com'
-  }),
-  company: z.string().max(255).nullable().optional().openapi({
-    description: '公司名称',
-    example: '示例科技有限公司'
-  }),
-  source: z.string().max(50).nullable().optional().openapi({
-    description: '客户来源',
-    example: '网站'
-  })
-});

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

@@ -1,21 +0,0 @@
-import { GenericCrudService } from '@/server/utils/generic-crud.service';
-import { DataSource } from 'typeorm';
-import { Customer } from './customer.entity';
-
-export class CustomerService extends GenericCrudService<Customer> {
-  constructor(dataSource: DataSource) {
-    super(dataSource, Customer);
-  }
-  
-  // 可以添加客户特有的业务逻辑方法
-  async getCustomerByName(name: string): Promise<Customer | null> {
-    return this.repository.findOneBy({ name });
-  }
-  
-  async getCustomersByCompany(company: string): Promise<Customer[]> {
-    return this.repository.find({
-      where: { company },
-      order: { createdAt: 'DESC' }
-    });
-  }
-}

+ 0 - 134
src/server/modules/follow-ups/follow-up.entity.ts

@@ -1,134 +0,0 @@
-import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
-import { z } from '@hono/zod-openapi';
-import { Opportunity } from '../opportunities/opportunity.entity';
-
-export enum FollowUpMethod {
-  PHONE = 'phone',
-  EMAIL = 'email',
-  MEETING = 'meeting',
-  OTHER = 'other'
-}
-
-@Entity('follow_up')
-export class FollowUp {
-  @PrimaryGeneratedColumn({ unsigned: true, comment: '跟进记录ID' })
-  id!: number;
-
-  @Column({ name: 'opportunity_id', type: 'int', unsigned: true, comment: '销售机会ID' })
-  opportunityId!: number;
-
-  @ManyToOne(() => Opportunity)
-  @JoinColumn({ name: 'opportunity_id' })
-  opportunity!: Opportunity;
-
-  @Column({ 
-    name: 'method', 
-    type: 'enum', 
-    enum: FollowUpMethod, 
-    comment: '跟进方式(phone:电话,email:邮件,meeting:会议,other:其他)' 
-  })
-  method!: FollowUpMethod;
-
-  @Column({ name: 'content', type: 'text', comment: '跟进内容' })
-  content!: string;
-
-  @Column({ name: 'next_follow_up_date', type: 'date', nullable: true, comment: '下次跟进日期' })
-  nextFollowUpDate!: Date | null;
-
-  @Column({ name: 'is_deleted', type: 'tinyint', default: 0, comment: '是否删除(0:未删除,1:已删除)' })
-  isDeleted!: number;
-
-  @CreateDateColumn({ name: 'created_at', type: 'timestamp', comment: '创建时间' })
-  createdAt!: Date;
-
-  @UpdateDateColumn({ name: 'updated_at', type: 'timestamp', comment: '更新时间' })
-  updatedAt!: Date;
-}
-
-export const FollowUpSchema = z.object({
-  id: z.number().int().positive().openapi({
-    description: '跟进记录ID',
-    example: 1
-  }),
-  opportunityId: z.number().int().positive().openapi({
-    description: '销售机会ID',
-    example: 1
-  }),
-  method: z.enum([
-    FollowUpMethod.PHONE,
-    FollowUpMethod.EMAIL,
-    FollowUpMethod.MEETING,
-    FollowUpMethod.OTHER
-  ]).openapi({
-    description: '跟进方式',
-    example: FollowUpMethod.PHONE
-  }),
-  content: z.string().openapi({
-    description: '跟进内容',
-    example: '与客户电话沟通,了解到客户对产品功能有进一步需求'
-  }),
-  nextFollowUpDate: z.coerce.date().nullable().openapi({
-    description: '下次跟进日期',
-    example: '2023-06-15'
-  }),
-  isDeleted: z.number().int().min(0).max(1).openapi({
-    description: '是否删除(0:未删除,1:已删除)',
-    example: 0
-  }),
-  createdAt: z.date().openapi({
-    description: '创建时间',
-    example: '2023-06-01T10:30:00Z'
-  }),
-  updatedAt: z.date().openapi({
-    description: '更新时间',
-    example: '2023-06-01T10:30:00Z'
-  })
-});
-
-export const CreateFollowUpDto = z.object({
-  opportunityId: z.coerce.number().int().positive().openapi({
-    description: '销售机会ID',
-    example: 1
-  }),
-  method: z.enum([
-    FollowUpMethod.PHONE,
-    FollowUpMethod.EMAIL,
-    FollowUpMethod.MEETING,
-    FollowUpMethod.OTHER
-  ]).openapi({
-    description: '跟进方式',
-    example: FollowUpMethod.PHONE
-  }),
-  content: z.string().openapi({
-    description: '跟进内容',
-    example: '与客户电话沟通,了解到客户对产品功能有进一步需求'
-  }),
-  nextFollowUpDate: z.coerce.date().nullable().optional().openapi({
-    description: '下次跟进日期',
-    example: '2023-06-15'
-  })
-});
-
-export const UpdateFollowUpDto = z.object({
-  opportunityId: z.coerce.number().int().positive().optional().openapi({
-    description: '销售机会ID',
-    example: 1
-  }),
-  method: z.enum([
-    FollowUpMethod.PHONE,
-    FollowUpMethod.EMAIL,
-    FollowUpMethod.MEETING,
-    FollowUpMethod.OTHER
-  ]).optional().openapi({
-    description: '跟进方式',
-    example: FollowUpMethod.PHONE
-  }),
-  content: z.string().optional().openapi({
-    description: '跟进内容',
-    example: '与客户电话沟通,了解到客户对产品功能有进一步需求'
-  }),
-  nextFollowUpDate: z.coerce.date().nullable().optional().openapi({
-    description: '下次跟进日期',
-    example: '2023-06-15'
-  })
-});

+ 0 - 41
src/server/modules/follow-ups/follow-up.service.ts

@@ -1,41 +0,0 @@
-import { GenericCrudService } from '@/server/utils/generic-crud.service';
-import { DataSource } from 'typeorm';
-import { FollowUp, FollowUpMethod } from './follow-up.entity';
-
-export class FollowUpService extends GenericCrudService<FollowUp> {
-  constructor(dataSource: DataSource) {
-    super(dataSource, FollowUp);
-  }
-  
-  // 根据销售机会ID获取跟进记录
-  async getByOpportunityId(opportunityId: number): Promise<FollowUp[]> {
-    return this.repository.find({
-      where: { opportunityId, isDeleted: 0 },
-      order: { createdAt: 'DESC' }
-    });
-  }
-  
-  // 根据跟进方式获取跟进记录
-  async getByMethod(method: FollowUpMethod): Promise<FollowUp[]> {
-    return this.repository.find({
-      where: { method, isDeleted: 0 },
-      order: { createdAt: 'DESC' }
-    });
-  }
-  
-  // 获取即将到期的跟进记录
-  async getUpcomingFollowUps(days: number = 7): Promise<FollowUp[]> {
-    const today = new Date();
-    const futureDate = new Date();
-    futureDate.setDate(today.getDate() + days);
-    
-    return this.repository.createQueryBuilder('follow_up')
-      .where('follow_up.nextFollowUpDate BETWEEN :today AND :futureDate', { 
-        today: today.toISOString().split('T')[0], 
-        futureDate: futureDate.toISOString().split('T')[0] 
-      })
-      .andWhere('follow_up.isDeleted = 0')
-      .orderBy('follow_up.nextFollowUpDate', 'ASC')
-      .getMany();
-  }
-}

+ 0 - 173
src/server/modules/opportunities/opportunity.entity.ts

@@ -1,173 +0,0 @@
-import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
-import { z } from '@hono/zod-openapi';
-import { Customer } from '../customers/customer.entity';
-
-export enum OpportunityStage {
-  INITIAL_CONTACT = 'initial_contact',
-  NEEDS_ANALYSIS = 'needs_analysis',
-  SOLUTION_PROPOSAL = 'solution_proposal',
-  NEGOTIATION = 'negotiation',
-  CLOSED_WON = 'closed_won',
-  CLOSED_LOST = 'closed_lost'
-}
-
-@Entity('opportunity')
-export class Opportunity {
-  @PrimaryGeneratedColumn({ unsigned: true, comment: '销售机会ID' })
-  id!: number;
-
-  @Column({ name: 'customer_id', type: 'int', unsigned: true, comment: '客户ID' })
-  customerId!: number;
-
-  @ManyToOne(() => Customer)
-  @JoinColumn({ name: 'customer_id' })
-  customer!: Customer;
-
-  @Column({ name: 'title', type: 'varchar', length: 255, comment: '销售机会标题' })
-  title!: string;
-
-  @Column({ name: 'amount', type: 'decimal', precision: 10, scale: 2, comment: '预计金额' })
-  amount!: number;
-
-  @Column({ 
-    name: 'stage', 
-    type: 'enum', 
-    enum: OpportunityStage, 
-    default: OpportunityStage.INITIAL_CONTACT, 
-    comment: '销售阶段(initial_contact:初步接触,needs_analysis:需求确认,solution_proposal:方案制定,negotiation:谈判阶段,closed_won:成交,closed_lost:丢失)' 
-  })
-  stage!: OpportunityStage;
-
-  @Column({ name: 'expected_close_date', type: 'date', nullable: true, comment: '预计成交日期' })
-  expectedCloseDate!: Date | null;
-
-  @Column({ name: 'description', type: 'text', nullable: true, comment: '销售机会描述' })
-  description!: string | null;
-
-  @Column({ name: 'is_deleted', type: 'tinyint', default: 0, comment: '是否删除(0:未删除,1:已删除)' })
-  isDeleted!: number;
-
-  @CreateDateColumn({ name: 'created_at', type: 'timestamp', comment: '创建时间' })
-  createdAt!: Date;
-
-  @UpdateDateColumn({ name: 'updated_at', type: 'timestamp', comment: '更新时间' })
-  updatedAt!: Date;
-}
-
-export const OpportunitySchema = z.object({
-  id: z.number().int().positive().openapi({
-    description: '销售机会ID',
-    example: 1
-  }),
-  customerId: z.number().int().positive().openapi({
-    description: '客户ID',
-    example: 1
-  }),
-  title: z.string().max(255).openapi({
-    description: '销售机会标题',
-    example: '企业软件升级项目'
-  }),
-  amount: z.coerce.number().multipleOf(0.01).openapi({
-    description: '预计金额',
-    example: 50000.00
-  }),
-  stage: z.enum([
-    OpportunityStage.INITIAL_CONTACT,
-    OpportunityStage.NEEDS_ANALYSIS,
-    OpportunityStage.SOLUTION_PROPOSAL,
-    OpportunityStage.NEGOTIATION,
-    OpportunityStage.CLOSED_WON,
-    OpportunityStage.CLOSED_LOST
-  ]).openapi({
-    description: '销售阶段',
-    example: OpportunityStage.INITIAL_CONTACT
-  }),
-  expectedCloseDate: z.coerce.date().nullable().openapi({
-    description: '预计成交日期',
-    example: '2023-12-31'
-  }),
-  description: z.string().nullable().openapi({
-    description: '销售机会描述',
-    example: '为客户提供企业级软件升级方案'
-  }),
-  isDeleted: z.number().int().min(0).max(1).openapi({
-    description: '是否删除(0:未删除,1:已删除)',
-    example: 0
-  }),
-  createdAt: z.date().openapi({
-    description: '创建时间',
-    example: '2023-01-01T00:00:00Z'
-  }),
-  updatedAt: z.date().openapi({
-    description: '更新时间',
-    example: '2023-01-01T00:00:00Z'
-  })
-});
-
-export const CreateOpportunityDto = z.object({
-  customerId: z.coerce.number().int().positive().openapi({
-    description: '客户ID',
-    example: 1
-  }),
-  title: z.string().max(255).openapi({
-    description: '销售机会标题',
-    example: '企业软件升级项目'
-  }),
-  amount: z.coerce.number().multipleOf(0.01).openapi({
-    description: '预计金额',
-    example: 50000.00
-  }),
-  stage: z.enum([
-    OpportunityStage.INITIAL_CONTACT,
-    OpportunityStage.NEEDS_ANALYSIS,
-    OpportunityStage.SOLUTION_PROPOSAL,
-    OpportunityStage.NEGOTIATION,
-    OpportunityStage.CLOSED_WON,
-    OpportunityStage.CLOSED_LOST
-  ]).optional().default(OpportunityStage.INITIAL_CONTACT).openapi({
-    description: '销售阶段',
-    example: OpportunityStage.INITIAL_CONTACT
-  }),
-  expectedCloseDate: z.coerce.date().nullable().optional().openapi({
-    description: '预计成交日期',
-    example: '2023-12-31'
-  }),
-  description: z.string().nullable().optional().openapi({
-    description: '销售机会描述',
-    example: '为客户提供企业级软件升级方案'
-  })
-});
-
-export const UpdateOpportunityDto = z.object({
-  customerId: z.coerce.number().int().positive().optional().openapi({
-    description: '客户ID',
-    example: 1
-  }),
-  title: z.string().max(255).optional().openapi({
-    description: '销售机会标题',
-    example: '企业软件升级项目'
-  }),
-  amount: z.coerce.number().multipleOf(0.01).optional().openapi({
-    description: '预计金额',
-    example: 50000.00
-  }),
-  stage: z.enum([
-    OpportunityStage.INITIAL_CONTACT,
-    OpportunityStage.NEEDS_ANALYSIS,
-    OpportunityStage.SOLUTION_PROPOSAL,
-    OpportunityStage.NEGOTIATION,
-    OpportunityStage.CLOSED_WON,
-    OpportunityStage.CLOSED_LOST
-  ]).optional().openapi({
-    description: '销售阶段',
-    example: OpportunityStage.INITIAL_CONTACT
-  }),
-  expectedCloseDate: z.coerce.date().nullable().optional().openapi({
-    description: '预计成交日期',
-    example: '2023-12-31'
-  }),
-  description: z.string().nullable().optional().openapi({
-    description: '销售机会描述',
-    example: '为客户提供企业级软件升级方案'
-  })
-});

+ 0 - 44
src/server/modules/opportunities/opportunity.service.ts

@@ -1,44 +0,0 @@
-import { GenericCrudService } from '@/server/utils/generic-crud.service';
-import { DataSource, Repository } from 'typeorm';
-import { Opportunity, OpportunityStage } from './opportunity.entity';
-
-export class OpportunityService extends GenericCrudService<Opportunity> {
-  constructor(dataSource: DataSource) {
-    super(dataSource, Opportunity);
-  }
-  
-  // 根据客户ID获取销售机会
-  async getByCustomerId(customerId: number): Promise<Opportunity[]> {
-    return this.repository.find({
-      where: { customerId, isDeleted: 0 },
-      order: { updatedAt: 'DESC' }
-    });
-  }
-  
-  // 根据销售阶段获取销售机会
-  async getByStage(stage: OpportunityStage): Promise<Opportunity[]> {
-    return this.repository.find({
-      where: { stage, isDeleted: 0 },
-      order: { expectedCloseDate: 'ASC' }
-    });
-  }
-  
-  // 获取特定时间段内的销售机会
-  async getByDateRange(startDate: Date, endDate: Date): Promise<Opportunity[]> {
-    return this.repository.createQueryBuilder('opportunity')
-      .where('opportunity.expectedCloseDate BETWEEN :startDate AND :endDate', { startDate, endDate })
-      .andWhere('opportunity.isDeleted = 0')
-      .orderBy('opportunity.expectedCloseDate', 'ASC')
-      .getMany();
-  }
-  
-  // 获取销售机会总额统计
-  async getTotalAmountByStage(): Promise<{ stage: OpportunityStage, total: number }[]> {
-    return this.repository.createQueryBuilder('opportunity')
-      .select('opportunity.stage', 'stage')
-      .addSelect('SUM(opportunity.amount)', 'total')
-      .where('opportunity.isDeleted = 0')
-      .groupBy('opportunity.stage')
-      .getRawMany();
-  }
-}