本次提交实现了完整的客户拜访业务系统: 1. 新增对象存储上传服务,支持S3兼容协议的RustFS存储 2. 完善客户拜访实体与数据库表结构,补充全业务字段 3. 开发拜访台账与记录的前后端接口,包含增删改查、批量创建、状态流转等能力 4. 新增拜访表单页面与路由,支持父级菜单补全面包屑 5. 新增勘察列表页预填客户ID跳转逻辑 6. 补充UI设计文档与页面截图 7. 调整日志中间件跳过上传路由,优化RBAC权限配置
88 lines
4.4 KiB
TypeScript
88 lines
4.4 KiB
TypeScript
import {
|
||
IsNotEmpty,
|
||
IsOptional,
|
||
IsString,
|
||
IsInt,
|
||
IsArray,
|
||
IsDateString,
|
||
ArrayNotEmpty,
|
||
Matches,
|
||
Min,
|
||
Max,
|
||
MaxLength
|
||
} from "class-validator";
|
||
|
||
export class CustomerVisitQueryDTO {
|
||
@IsOptional() @IsInt() @Min(1) page?: number = 1;
|
||
@IsOptional() @IsInt() @Min(1) @Max(200) pageSize?: number = 10;
|
||
@IsOptional() @IsString() @MaxLength(64) keyword?: string;
|
||
@IsOptional() @IsInt() customerId?: number;
|
||
@IsOptional() @IsInt() salesmanId?: number;
|
||
@IsOptional() @IsInt() @Min(1) @Max(5) visitType?: number;
|
||
@IsOptional() @IsInt() @Min(0) @Max(5) status?: number;
|
||
@IsOptional() @IsInt() @Min(1) @Max(3) priority?: number;
|
||
// 计划拜访日期窗口(YYYY-MM-DD)
|
||
@IsOptional() @IsString() @MaxLength(10) planStartDate?: string;
|
||
@IsOptional() @IsString() @MaxLength(10) planEndDate?: string;
|
||
}
|
||
|
||
export class CustomerVisitCreateDTO {
|
||
@IsNotEmpty({ message: '所属客户不能为空' }) @IsInt() customerId!: number;
|
||
@IsOptional() @IsString() @MaxLength(64) @Matches(/^[^<>]*$/) visitPerson?: string;
|
||
@IsOptional() @Matches(/^1[3-9]\d{9}$/, { message: '手机号格式不正确' }) visitPhone?: string;
|
||
@IsOptional() @IsString() @MaxLength(2000) @Matches(/^[^<>]*$/) visitContent?: string;
|
||
@IsOptional() @IsString() @MaxLength(10) visitTime?: string;
|
||
@IsOptional() @IsInt() salesmanId?: number;
|
||
@IsOptional() @IsInt() @Min(0) @Max(1) willPlan?: number;
|
||
@IsOptional() @IsInt() @Min(1) @Max(5) visitType?: number;
|
||
@IsOptional() @IsInt() @Min(1) @Max(4) visitMode?: number;
|
||
@IsOptional() @IsInt() @Min(1) @Max(3) priority?: number;
|
||
@IsOptional() @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) subject?: string;
|
||
@IsOptional() @IsDateString() planTime?: string;
|
||
@IsOptional() @IsDateString() planEndTime?: string;
|
||
@IsOptional() @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) spaceDesc?: string;
|
||
@IsOptional() @IsInt() @Min(1) @Max(3) intentLevel?: number;
|
||
@IsOptional() @IsString() @MaxLength(64) @Matches(/^[^<>]*$/) intentDesc?: string;
|
||
@IsOptional() @IsString() @MaxLength(512) @Matches(/^[^<>]*$/) demands?: string;
|
||
@IsOptional() @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) companion?: string;
|
||
@IsOptional() @IsString() @MaxLength(64) @Matches(/^[^<>]*$/) receptionPerson?: string;
|
||
@IsOptional() @IsString() @MaxLength(64) @Matches(/^[^<>]*$/) receptionTitle?: string;
|
||
@IsOptional() @Matches(/^1[3-9]\d{9}$/, { message: '接待人联系方式格式不正确' }) receptionPhone?: string;
|
||
@IsOptional() @IsString() @MaxLength(64) @Matches(/^[^<>]*$/) resultRating?: string;
|
||
@IsOptional() @IsInt() @Min(0) @Max(5) status?: number;
|
||
@IsOptional() @IsString() @MaxLength(10) nextVisitTime?: string;
|
||
@IsOptional() @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) nextAction?: string;
|
||
// 现场照片对象 key 列表(对象存储),最多 2 张
|
||
@IsOptional() @IsArray() @MaxLength(2) photos?: string[];
|
||
}
|
||
|
||
export class CustomerVisitUpdateDTO extends CustomerVisitCreateDTO {
|
||
@IsOptional() @IsInt() declare customerId: number;
|
||
@IsOptional() @IsInt() @Min(0) @Max(5) declare status?: number;
|
||
@IsOptional() @IsInt() @Min(0) @Max(1) declare checkinStatus?: number;
|
||
@IsOptional() @IsDateString() declare checkinTime?: string;
|
||
@IsOptional() declare checkinLng?: number;
|
||
@IsOptional() declare checkinLat?: number;
|
||
}
|
||
|
||
// 批量安排拜访:多选客户 + 统一计划信息,批量生成待执行(status=0)记录
|
||
export class CustomerVisitBatchCreateDTO {
|
||
@IsArray() @ArrayNotEmpty({ message: '请至少选择一个客户' }) @IsInt({ each: true }) customerIds!: number[];
|
||
@IsNotEmpty({ message: '计划拜访时间不能为空' }) @IsDateString() planTime!: string;
|
||
@IsOptional() @IsDateString() planEndTime?: string;
|
||
@IsOptional() @IsInt() salesmanId?: number;
|
||
@IsOptional() @IsInt() @Min(1) @Max(5) visitType?: number;
|
||
@IsOptional() @IsInt() @Min(1) @Max(4) visitMode?: number;
|
||
@IsOptional() @IsInt() @Min(1) @Max(3) priority?: number;
|
||
@IsOptional() @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) subject?: string;
|
||
}
|
||
|
||
// 状态流转(执行跟进 / 审核现场取证 / 取消 / 归档)
|
||
export class CustomerVisitStatusDTO {
|
||
@IsNotEmpty({ message: '目标状态不能为空' }) @IsInt() @Min(0) @Max(5) status!: number;
|
||
@IsOptional() @IsDateString() checkinTime?: string;
|
||
@IsOptional() @IsString() @MaxLength(64) @Matches(/^[^<>]*$/) resultRating?: string;
|
||
@IsOptional() @IsInt() surveyOrderId?: number;
|
||
@IsOptional() @IsString() @MaxLength(64) @Matches(/^[^<>]*$/) projectNo?: string;
|
||
}
|