import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm'; import { z } from 'zod'; import { Customer } from '@/server/modules/customers/customer.entity'; import { Opportunity } from '@/server/modules/opportunities/opportunity.entity'; import { User } from '@/server/modules/users/user.entity'; @Entity('contracts') export class Contract { @PrimaryGeneratedColumn({ unsigned: true }) id!: number; @Column({ name: 'contract_no', type: 'varchar', length: 50, nullable: false, unique: true, comment: '合同编号' }) contractNo!: string; @Column({ name: 'title', type: 'varchar', length: 100, nullable: false, comment: '合同标题' }) title!: string; @Column({ name: 'customer_id', type: 'int', unsigned: true, nullable: false, comment: '客户ID' }) customerId!: number; @Column({ name: 'opportunity_id', type: 'int', unsigned: true, nullable: true, comment: '销售机会ID' }) opportunityId!: number | null; @Column({ name: 'amount', type: 'decimal', precision: 12, scale: 2, nullable: false, comment: '合同金额' }) amount!: number; @Column({ name: 'signed_date', type: 'date', nullable: false, comment: '签约日期' }) signedDate!: Date; @Column({ name: 'start_date', type: 'date', nullable: false, comment: '开始日期' }) startDate!: Date; @Column({ name: 'end_date', type: 'date', nullable: true, comment: '结束日期' }) endDate!: Date | null; @Column({ name: 'status', type: 'tinyint', default: 0, comment: '合同状态(0-草稿, 1-已签约, 2-执行中, 3-已完成, 4-已终止)' }) status!: number; @Column({ name: 'payment_terms', type: 'text', nullable: true, comment: '付款条件' }) paymentTerms!: string | null; @Column({ name: 'signed_by', type: 'int', unsigned: true, nullable: true, comment: '签约人ID' }) signedBy!: number | null; @Column({ name: 'attachment_url', type: 'varchar', length: 255, nullable: true, comment: '合同附件URL' }) attachmentUrl!: string | 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; @Column({ name: 'created_at', type: 'timestamp', default: () => 'CURRENT_TIMESTAMP', comment: '创建时间' }) createdAt!: Date; @Column({ name: 'updated_at', type: 'timestamp', default: () => 'CURRENT_TIMESTAMP', onUpdate: 'CURRENT_TIMESTAMP', comment: '更新时间' }) updatedAt!: Date; // 关系定义 @ManyToOne(() => Customer, customer => customer.contracts) customer!: Customer; @ManyToOne(() => Opportunity, opportunity => opportunity.id) opportunity!: Opportunity; @ManyToOne(() => User, user => user.id) signedUser!: User; } export const ContractSchema = z.object({ id: z.number().int().positive().openapi({ description: '合同ID', example: 1 }), contractNo: z.string().min(1).max(50).openapi({ description: '合同编号', example: 'HT-20230001' }), title: z.string().min(1).max(100).openapi({ description: '合同标题', example: 'ERP系统升级服务合同' }), customerId: z.number().int().positive().openapi({ description: '客户ID', example: 1 }), opportunityId: z.number().int().positive().nullable().openapi({ description: '销售机会ID', example: 1 }), amount: z.number().openapi({ description: '合同金额', example: 150000.00 }), signedDate: z.date().openapi({ description: '签约日期', example: '2023-01-15' }), startDate: z.date().openapi({ description: '开始日期', example: '2023-02-01' }), endDate: z.date().nullable().openapi({ description: '结束日期', example: '2023-12-31' }), status: z.number().int().min(0).max(4).openapi({ description: '合同状态(0-草稿, 1-已签约, 2-执行中, 3-已完成, 4-已终止)', example: 2 }), paymentTerms: z.string().nullable().openapi({ description: '付款条件', example: '首付50%,验收后付40%,质保金10%' }), signedBy: z.number().int().positive().nullable().openapi({ description: '签约人ID', example: 1 }), attachmentUrl: z.string().url().max(255).nullable().openapi({ description: '合同附件URL', example: 'https://example.com/contracts/HT-20230001.pdf' }), description: z.string().nullable().openapi({ description: '合同描述', example: '为客户提供ERP系统升级服务' }), 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' }) });