feat: 完成客户拜访模块全功能开发
本次提交实现了完整的客户拜访业务系统: 1. 新增对象存储上传服务,支持S3兼容协议的RustFS存储 2. 完善客户拜访实体与数据库表结构,补充全业务字段 3. 开发拜访台账与记录的前后端接口,包含增删改查、批量创建、状态流转等能力 4. 新增拜访表单页面与路由,支持父级菜单补全面包屑 5. 新增勘察列表页预填客户ID跳转逻辑 6. 补充UI设计文档与页面截图 7. 调整日志中间件跳过上传路由,优化RBAC权限配置
This commit is contained in:
1 parent
68af363ca9
commit
1c83e09fa1
33 files changed
+6920
-587
No files matched your search
@@ -1,4 +1,16 @@
|
||||
import { IsNotEmpty, IsOptional, IsString, IsInt, IsNumber, Matches, Min, Max, MaxLength } from "class-validator";
|
||||
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;
|
||||
@@ -6,24 +18,70 @@ export class CustomerVisitQueryDTO {
|
||||
@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;
|
||||
@IsNotEmpty({ message: '拜访人不能为空' }) @IsString() @MaxLength(64) @Matches(/^[^<>]*$/) visitPerson!: string;
|
||||
@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 {
|
||||
@IsOptional() @IsInt() customerId?: number;
|
||||
@IsOptional() @IsString() @MaxLength(64) @Matches(/^[^<>]*$/) visitPerson?: string;
|
||||
@IsOptional() @Matches(/^1[3-9]\d{9}$/) visitPhone?: string;
|
||||
@IsOptional() @IsString() @MaxLength(2000) @Matches(/^[^<>]*$/) visitContent?: string;
|
||||
@IsOptional() @IsString() @MaxLength(10) visitTime?: 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(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;
|
||||
}
|
||||
|
||||
// 状态流转(执行跟进 / 审核现场取证 / 取消 / 归档)
|
||||
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;
|
||||
}
|
||||
Reference in new issue
Block a user