733 lines
13 KiB
TypeScript
733 lines
13 KiB
TypeScript
import { OrderStatus } from '@dukang/shared-types';
|
||
import { Type, Transform } from 'class-transformer';
|
||
import { IsArray, IsBoolean, IsIn, IsInt, IsOptional, IsString, Max, Min } from 'class-validator';
|
||
|
||
const ORDER_STATUS_VALUES = Object.values(OrderStatus);
|
||
|
||
function toOptionalBoolean(value: unknown): boolean | undefined {
|
||
if (value === undefined || value === null || value === '') return undefined;
|
||
if (value === true || value === 'true' || value === '1' || value === 1) return true;
|
||
if (value === false || value === 'false' || value === '0' || value === 0) return false;
|
||
return undefined;
|
||
}
|
||
|
||
/** Query/body:单值、逗号串、重复 key、数组均可 → string[] */
|
||
function toOptionalStringList(value: unknown): string[] | undefined {
|
||
if (value === undefined || value === null || value === '') return undefined;
|
||
const raw = Array.isArray(value) ? value : [value];
|
||
const items = [...new Set(
|
||
raw
|
||
.flatMap((v) => String(v).split(','))
|
||
.map((s) => s.trim())
|
||
.filter(Boolean),
|
||
)];
|
||
return items.length ? items : undefined;
|
||
}
|
||
|
||
export class PaginationQueryDto {
|
||
@IsOptional()
|
||
@Type(() => Number)
|
||
@IsInt()
|
||
@Min(1)
|
||
page?: number = 1;
|
||
|
||
@IsOptional()
|
||
@Type(() => Number)
|
||
@IsInt()
|
||
@Min(1)
|
||
@Max(100)
|
||
pageSize?: number = 20;
|
||
}
|
||
|
||
export class AdminUsersQueryDto extends PaginationQueryDto {
|
||
/** 综合搜索:编号 / 昵称 / 备注 / 手机 / 数字 ID */
|
||
@IsOptional()
|
||
@IsString()
|
||
keyword?: string;
|
||
|
||
/** 关联合伙人:主账号 ID;`none` 未关联;`any` 已关联(全部) */
|
||
@IsOptional()
|
||
@IsString()
|
||
assocPartnerAccountId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
phone?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
userNo?: string;
|
||
|
||
/** 精确匹配用户主键,供订单等页的用户快链带入筛选 */
|
||
@IsOptional()
|
||
@IsString()
|
||
userId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
deviceKey?: string;
|
||
|
||
@IsOptional()
|
||
@IsIn(['0', '1'])
|
||
phoneVerified?: string;
|
||
|
||
@IsOptional()
|
||
@Type(() => Number)
|
||
@IsIn([0, 1])
|
||
status?: number;
|
||
|
||
/** 勾选「过滤测试账号」时传 true */
|
||
@IsOptional()
|
||
@Transform(({ value }) => toOptionalBoolean(value))
|
||
@IsBoolean()
|
||
excludeTest?: boolean;
|
||
}
|
||
|
||
export class AdminOrdersQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
orderNo?: string;
|
||
|
||
/** 单值或多项:`?status=PENDING_PAY` / `?status=A&status=B` / `?status=A,B` */
|
||
@IsOptional()
|
||
@Transform(({ value }) => toOptionalStringList(value))
|
||
@IsArray()
|
||
@IsIn(ORDER_STATUS_VALUES, { each: true })
|
||
status?: string[];
|
||
|
||
@IsOptional()
|
||
@IsIn(['NORMAL', 'PROXY'])
|
||
orderType?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
userId?: string;
|
||
|
||
/** 用户编号 / 昵称 / 备注 / 手机 模糊匹配 */
|
||
@IsOptional()
|
||
@IsString()
|
||
userKeyword?: string;
|
||
|
||
/** 商品名称 / 规格 模糊匹配 */
|
||
@IsOptional()
|
||
@IsString()
|
||
productKeyword?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
cityId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
receiverPhone?: string;
|
||
|
||
/** 仅看大单拦截待总部确认:true / 1 */
|
||
@IsOptional()
|
||
fulfillmentHold?: string | boolean;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
createdFrom?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
createdTo?: string;
|
||
|
||
@IsOptional()
|
||
@Transform(({ value }) => toOptionalBoolean(value))
|
||
@IsBoolean()
|
||
excludeTest?: boolean;
|
||
|
||
@IsOptional()
|
||
@IsIn(['LOCAL', 'CROSS_CITY', 'ON_SITE_PICKUP'])
|
||
deliveryType?: string;
|
||
|
||
/** 按下单时绑定的推广码筛选 */
|
||
@IsOptional()
|
||
@IsString()
|
||
promoCodeId?: string;
|
||
|
||
/** 本单佣金关联合伙人:主账号 ID,或 `none` 表示无快照 */
|
||
@IsOptional()
|
||
@IsString()
|
||
assocPartnerAccountId?: string;
|
||
}
|
||
|
||
/** HQ 订单导出(筛选 + 勾选范围) */
|
||
export class AdminOrdersExportDto {
|
||
@IsIn(['filter', 'selected'])
|
||
scope: 'filter' | 'selected';
|
||
|
||
@IsIn(['xlsx', 'pdf'])
|
||
format: 'xlsx' | 'pdf';
|
||
|
||
@IsOptional()
|
||
@IsArray()
|
||
@IsString({ each: true })
|
||
ids?: string[];
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
orderNo?: string;
|
||
|
||
@IsOptional()
|
||
@Transform(({ value }) => toOptionalStringList(value))
|
||
@IsArray()
|
||
@IsIn(ORDER_STATUS_VALUES, { each: true })
|
||
status?: string[];
|
||
|
||
@IsOptional()
|
||
@IsIn(['NORMAL', 'PROXY', 'RESHIPMENT'])
|
||
orderType?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
cityId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
userKeyword?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
productKeyword?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
receiverPhone?: string;
|
||
|
||
@IsOptional()
|
||
@Transform(({ value }) => toOptionalBoolean(value))
|
||
@IsBoolean()
|
||
fulfillmentHold?: boolean;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
createdFrom?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
createdTo?: string;
|
||
|
||
@IsOptional()
|
||
@Transform(({ value }) => toOptionalBoolean(value))
|
||
@IsBoolean()
|
||
excludeTest?: boolean;
|
||
|
||
@IsOptional()
|
||
@IsIn(['LOCAL', 'CROSS_CITY', 'ON_SITE_PICKUP'])
|
||
deliveryType?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
promoCodeId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
assocPartnerAccountId?: string;
|
||
|
||
/** 按列表可见列导出(中文列名或英文 key) */
|
||
@IsOptional()
|
||
@IsArray()
|
||
@IsString({ each: true })
|
||
columns?: string[];
|
||
}
|
||
|
||
/** 概览页用户/订单 ECharts 聚合筛选 */
|
||
export class AdminDashboardAnalyticsQueryDto {
|
||
/** YYYY-MM-DD,默认近 30 天 */
|
||
@IsOptional()
|
||
@IsString()
|
||
dateFrom?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
dateTo?: string;
|
||
|
||
/** 开城城市 id;`none` = 用户未选城 */
|
||
@IsOptional()
|
||
@IsString()
|
||
cityId?: string;
|
||
|
||
/** 推广码 id;`none` = 无归因 / 订单无推广码 */
|
||
@IsOptional()
|
||
@IsString()
|
||
promoCodeId?: string;
|
||
|
||
/** 城市合伙人(主账号)id */
|
||
@IsOptional()
|
||
@IsString()
|
||
partnerAccountId?: string;
|
||
}
|
||
|
||
export class AdminStoresQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
name?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
status?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
cityId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
partnerId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
phone?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
auditStatus?: string;
|
||
|
||
@IsOptional()
|
||
@Transform(({ value }) => toOptionalBoolean(value))
|
||
@IsBoolean()
|
||
excludeTest?: boolean;
|
||
}
|
||
|
||
export class AdminStoreAccountsQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
phone?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
storeId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
status?: string;
|
||
|
||
@IsOptional()
|
||
@Transform(({ value }) => toOptionalBoolean(value))
|
||
@IsBoolean()
|
||
excludeTest?: boolean;
|
||
}
|
||
|
||
export class AdminPartnersQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
companyName?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
contactPhone?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
phone?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
cityId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
partnerId?: string;
|
||
|
||
@IsOptional()
|
||
@Transform(({ value }) => toOptionalBoolean(value))
|
||
@IsBoolean()
|
||
excludeTest?: boolean;
|
||
}
|
||
|
||
export class AdminCityWarehousesQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
cityId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
name?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
managerType?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
status?: string;
|
||
}
|
||
|
||
export class AdminPartnerAccountsQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
phone?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
partnerId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
status?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
isPrimary?: string;
|
||
}
|
||
|
||
export class AdminBenefitCouponsQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
couponNo?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
userId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
status?: string;
|
||
}
|
||
|
||
export class AdminBenefitLedgersQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
userId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
couponId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
type?: string;
|
||
}
|
||
|
||
export class AdminRedeemRecordsQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
redeemNo?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
storeId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
userId?: string;
|
||
|
||
/** SCAN | PHONE */
|
||
@IsOptional()
|
||
@IsString()
|
||
channel?: string;
|
||
|
||
@IsOptional()
|
||
@Transform(({ value }) => toOptionalBoolean(value))
|
||
@IsBoolean()
|
||
excludeTest?: boolean;
|
||
}
|
||
|
||
export class AdminStoreRatingsQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
storeId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
cityId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
redeemNo?: string;
|
||
}
|
||
|
||
export class AdminDeliveriesQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
provider?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
trackingNo?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
orderNo?: string;
|
||
}
|
||
|
||
export class AdminHqAccountsQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
phone?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
adminRole?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
status?: string;
|
||
}
|
||
|
||
export class AdminCitiesQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
name?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
code?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
status?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
partnerId?: string;
|
||
}
|
||
|
||
export class AdminProductsQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
name?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
status?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
aromaType?: string;
|
||
}
|
||
|
||
export class AdminProductDetailTemplatesQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
name?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
code?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
status?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
aromaType?: string;
|
||
}
|
||
|
||
export class AdminUserLogsQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
userId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
phone?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
userNo?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
category?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
eventName?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
from?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
to?: string;
|
||
}
|
||
|
||
export class AdminStoreLogsQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
storeId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
storeAccountId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
phone?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
storeName?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
category?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
eventName?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
from?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
to?: string;
|
||
}
|
||
|
||
export class AdminPartnerLogsQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
partnerId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
partnerAccountId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
phone?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
companyName?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
category?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
eventName?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
from?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
to?: string;
|
||
}
|
||
|
||
export class AdminHqLogsQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
hqAccountId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
action?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
refType?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
from?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
to?: string;
|
||
}
|
||
|
||
export class AdminOssLogsQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
scene?: string;
|
||
|
||
@IsOptional()
|
||
@IsIn(['SUCCESS', 'FAILED', 'PENDING'])
|
||
status?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
bizType?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
clientApp?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
refType?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
refId?: string;
|
||
}
|
||
|
||
export class AdminStoreMediaQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
storeId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
mediaType?: string;
|
||
}
|
||
|
||
export class AdminPromoCodesQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
name?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
code?: string;
|
||
|
||
@IsOptional()
|
||
@IsIn(['ACTIVE', 'DISABLED'])
|
||
status?: string;
|
||
}
|
||
|
||
export class AdminWechatBindingsQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsIn(['USER', 'STORE', 'PARTNER', 'HQ'])
|
||
actorType?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
phone?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
unionId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
openId?: string;
|
||
}
|
||
|
||
export class AdminWecomBotLogsQueryDto extends PaginationQueryDto {
|
||
@IsOptional()
|
||
@IsString()
|
||
botId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
wecomUserId?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
action?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
success?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
from?: string;
|
||
|
||
@IsOptional()
|
||
@IsString()
|
||
to?: string;
|
||
}
|