feat(old-items): complete reuse workflow and refine miniapp home

This commit is contained in:
2026-08-15 16:38:30 +08:00
parent 65d23eab4a
commit f3737c80be
94 changed files with 7880 additions and 215 deletions
+191
View File
@@ -0,0 +1,191 @@
import { Type } from 'class-transformer';
import {
IsArray,
ArrayMaxSize,
ArrayMinSize,
IsDateString,
IsIn,
IsInt,
IsMobilePhone,
IsOptional,
IsString,
IsUUID,
Length,
Max,
Matches,
Min,
ValidateNested,
} from 'class-validator';
import {
OLD_ITEM_CATEGORIES,
OLD_ITEM_CONDITIONS,
OLD_ITEM_DONATION_METHODS,
OLD_ITEM_DONATION_STATUSES,
OLD_ITEM_NEED_STATUSES,
OLD_ITEM_INVENTORY_STATUSES,
} from '@lehuo/contracts';
import { PaginationDto } from '../../case-management/dto/case-management.dto';
export class OldItemDonationQueryDto extends PaginationDto {
@IsOptional() @IsIn(OLD_ITEM_DONATION_STATUSES) status?: string;
@IsOptional() @IsIn(OLD_ITEM_DONATION_METHODS) method?: string;
@IsOptional() @IsString() @Length(1, 100) keyword?: string;
}
export class OldItemNeedQueryDto extends PaginationDto {
@IsOptional() @IsIn(OLD_ITEM_CATEGORIES) category?: string;
@IsOptional() @IsIn(OLD_ITEM_NEED_STATUSES) status?: string;
}
export class CreateOldItemDonationDto {
@IsUUID('4') clientRequestId!: string;
@IsIn(OLD_ITEM_CATEGORIES) category!: string;
@IsIn(OLD_ITEM_CONDITIONS) itemCondition!: string;
@Type(() => Number) @IsInt() @Min(1) @Max(9999) quantity!: number;
@IsString() @Length(2, 1000) description!: string;
@IsIn(OLD_ITEM_DONATION_METHODS) method!: 'PICKUP' | 'DROP_OFF';
@IsString() @Length(2, 50) contactName!: string;
@IsMobilePhone('zh-CN') mobile!: string;
@IsOptional() @IsString() @Length(5, 500) address?: string;
@IsOptional() @IsDateString() appointmentAt?: string;
@IsOptional() @IsUUID('4') dropOffPointPublicId?: string;
@IsOptional() @IsUUID('4') targetNeedPublicId?: string;
@IsOptional() @IsArray() @IsUUID('4', { each: true }) imagePublicIds?: string[];
}
export class CreateOldItemMediaUploadIntentDto {
@IsUUID('4') clientRequestId!: string;
@IsIn(['OLD_ITEM_DONATION_IMAGE']) businessType!: 'OLD_ITEM_DONATION_IMAGE';
@IsString() @Length(1, 255) filename!: string;
@IsIn(['image/jpeg', 'image/png', 'image/webp']) mimeType!:
'image/jpeg' | 'image/png' | 'image/webp';
@Type(() => Number) @IsInt() @Min(1) @Max(10 * 1024 * 1024) size!: number;
@IsOptional() @Matches(/^[a-fA-F0-9]{64}$/) sha256?: string;
}
export class TransitionOldItemDonationDto {
@IsUUID('4') clientRequestId!: string;
@Type(() => Number) @IsInt() @Min(1) expectedRevision!: number;
@IsIn(OLD_ITEM_DONATION_STATUSES) targetStatus!: string;
@IsOptional() @IsString() @Length(1, 500) note?: string;
@IsOptional() @IsUUID('4') assignedUserPublicId?: string;
@IsOptional() @Type(() => Number) @IsInt() @Min(0) @Max(999999) assistedPeople?: number;
}
export class CreateOldItemNeedDto {
@IsUUID('4') clientRequestId!: string;
@IsString() @Length(2, 160) title!: string;
@IsIn(OLD_ITEM_CATEGORIES) category!: string;
@IsString() @Length(2, 120) regionText!: string;
@IsString() @Length(2, 160) beneficiaryGroup!: string;
@IsString() @Length(2, 2000) description!: string;
@Type(() => Number) @IsInt() @Min(1) @Max(999999) requestedQuantity!: number;
@IsOptional() @Type(() => Number) @IsInt() @Min(0) @Max(100) priority?: number;
@IsOptional() @Type(() => Number) @IsInt() @Min(-9999) @Max(9999) sortOrder?: number;
}
export class UpdateOldItemNeedDto {
@Type(() => Number) @IsInt() @Min(1) expectedRevision!: number;
@IsString() @Length(2, 160) title!: string;
@IsIn(OLD_ITEM_CATEGORIES) category!: string;
@IsString() @Length(2, 120) regionText!: string;
@IsString() @Length(2, 160) beneficiaryGroup!: string;
@IsString() @Length(2, 2000) description!: string;
@Type(() => Number) @IsInt() @Min(1) @Max(999999) requestedQuantity!: number;
@IsOptional() @Type(() => Number) @IsInt() @Min(0) @Max(100) priority?: number;
@IsOptional() @Type(() => Number) @IsInt() @Min(-9999) @Max(9999) sortOrder?: number;
}
export class TransitionOldItemNeedDto {
@IsUUID('4') clientRequestId!: string;
@Type(() => Number) @IsInt() @Min(1) expectedRevision!: number;
@IsIn(OLD_ITEM_NEED_STATUSES) targetStatus!: string;
}
export class CreateOldItemDropOffPointDto {
@IsString() @Length(2, 120) name!: string;
@IsString() @Length(2, 120) regionText!: string;
@IsString() @Length(5, 300) addressText!: string;
@IsString() @Length(2, 200) openingHours!: string;
@IsOptional() @Type(() => Number) @IsInt() @Min(-9999) @Max(9999) sortOrder?: number;
}
export class OldItemInventoryQueryDto extends PaginationDto {
@IsOptional() @IsIn(OLD_ITEM_INVENTORY_STATUSES) status?: string;
@IsOptional() @IsIn(OLD_ITEM_CATEGORIES) category?: string;
@IsOptional() @IsString() @Length(1, 100) keyword?: string;
}
export class CreateOldItemInventoryDto {
@IsUUID('4') clientRequestId!: string;
@IsOptional() @IsUUID('4') sourceDonationPublicId?: string;
@IsIn(OLD_ITEM_CATEGORIES) category!: string;
@IsString() @Length(1, 160) itemName!: string;
@Type(() => Number) @IsInt() @Min(1) @Max(999999) quantity!: number;
@IsString() @Length(1, 20) unit!: string;
@IsString() @Length(2, 160) storageLocation!: string;
@IsOptional() @IsUUID('4') targetNeedPublicId?: string;
@IsOptional() @IsString() @Length(1, 1000) note?: string;
@IsOptional() @IsDateString() inboundAt?: string;
}
export class OldItemInventoryImportRowDto {
@IsOptional() @IsString() @Length(1, 32) sourceDonationNo?: string;
@IsIn(OLD_ITEM_CATEGORIES) category!: string;
@IsString() @Length(1, 160) itemName!: string;
@Type(() => Number) @IsInt() @Min(1) @Max(999999) quantity!: number;
@IsString() @Length(1, 20) unit!: string;
@IsString() @Length(2, 160) storageLocation!: string;
@IsOptional() @IsUUID('4') targetNeedPublicId?: string;
@IsOptional() @IsString() @Length(1, 1000) note?: string;
@IsOptional() @IsDateString() inboundAt?: string;
}
export class ImportOldItemInventoryDto {
@IsUUID('4') clientRequestId!: string;
@IsString() @Length(1, 255) originalFilename!: string;
@IsArray()
@ArrayMinSize(1)
@ArrayMaxSize(500)
@ValidateNested({ each: true })
@Type(() => OldItemInventoryImportRowDto)
rows!: OldItemInventoryImportRowDto[];
}
export class TransitionOldItemInventoryDto {
@IsUUID('4') clientRequestId!: string;
@Type(() => Number) @IsInt() @Min(1) expectedRevision!: number;
@IsIn(OLD_ITEM_INVENTORY_STATUSES) targetStatus!: string;
@IsOptional() @IsDateString() eventAt?: string;
@IsOptional() @IsString() @Length(2, 160) locationText?: string;
@IsOptional() @IsString() @Length(1, 1000) note?: string;
@IsOptional() @IsUUID('4') targetNeedPublicId?: string;
@IsOptional() @IsUUID('4') beneficiaryPublicId?: string;
@IsOptional() @IsString() @Length(2, 120) destinationRegion?: string;
@IsOptional() @Type(() => Number) @IsInt() @Min(0) @Max(999999) assistedPeople?: number;
}
export class ActivateOldItemRewardConfigDto {
@IsUUID('4') clientRequestId!: string;
@IsString() @Length(2, 120) certificateTitle!: string;
@IsString() @Length(10, 1000) certificateMessage!: string;
@IsString() @Length(2, 120) issuerName!: string;
@IsString() @Length(10, 500) legalNotice!: string;
@Type(() => Number) @IsInt() @Min(0) @Max(1000) clothingPoints!: number;
@Type(() => Number) @IsInt() @Min(0) @Max(1000) booksPoints!: number;
@Type(() => Number) @IsInt() @Min(0) @Max(1000) householdPoints!: number;
@Type(() => Number) @IsInt() @Min(0) @Max(1000) sportsPoints!: number;
@Type(() => Number) @IsInt() @Min(0) @Max(100000) maxPointsPerDonation!: number;
}
export class IssueOldItemCertificateDto {
@IsUUID('4') clientRequestId!: string;
}
export class RevokeOldItemCertificateDto {
@IsUUID('4') clientRequestId!: string;
@IsString() @Length(2, 500) reason!: string;
}
export class AdjustOldItemPointsDto {
@IsUUID('4') clientRequestId!: string;
@Type(() => Number) @IsInt() @Min(1) expectedRevision!: number;
@Type(() => Number) @IsInt() @Min(-100000) @Max(100000) pointsDelta!: number;
@IsString() @Length(2, 500) reason!: string;
}
export class OldItemPointAccountQueryDto extends PaginationDto {
@IsOptional() @IsString() @Length(1, 100) keyword?: string;
}