/** 店铺中心共享 DTO(任务 81):店铺密钥/店铺摘要/明文凭据/分组与分页类型; * 纯逻辑、无框架依赖,与 Java shopkey 模块的 camelCase 接口契约对齐。 */ export const SHOP_PAGE_DEFAULT_SIZE = 15 export const SHOP_PAGE_MIN_PAGE = 1 export const SHOP_PAGE_MAX_SIZE = 100 /** 敏感字符串品牌:紫鸟令牌、店铺密码等明文只允许经 toSensitiveString 标记,禁止直接进入通用日志/上报。 */ export type SensitiveString = string & { readonly __sensitiveBrand: unique symbol } export function toSensitiveString(value: string): SensitiveString { return value as SensitiveString } /** 紫鸟 IP 白名单状态。 */ export type IpWhitelistStatus = 'UNKNOWN' | 'ALLOWED' | 'BLOCKED' /** 店铺密钥行(GET /api/admin/shop-keys data.items;Java ShopKeyItemVo)。 */ export interface ShopKeyItem { id: number remarkName: string ziniaoAccountName: string /** 紫鸟令牌:敏感字段,列表展示必须掩码。 */ ziniaoToken: SensitiveString /** 静态代理地址;为空表示直连。用于出口 IP 不在紫鸟白名单的 key。 */ proxyUrl: string ipWhitelistStatus: IpWhitelistStatus ipWhitelistCheckedAt?: string ipWhitelistMessage?: string /** 连续白名单失败次数;达上限后不再自动重试,需人工检测。 */ ipWhitelistFailCount: number createdAt?: string updatedAt?: string } export interface ShopKeyPageResult { items: ShopKeyItem[] total: number page: number pageSize: number } /** 店铺行(GET /api/admin/shop-manages data.items;Java ShopManageItemVo,密码只下发掩码)。 */ export interface ShopSummary { id: number groupId: number | null groupName: string shopName: string mallName: string znUsername: string account: string passwordMasked?: string createdAt?: string updatedAt?: string } export interface ShopPageResult { items: ShopSummary[] total: number page: number pageSize: number } /** 店铺明文凭据(GET /api/admin/shop-manages/{id}/credential data;Java ShopManageCredentialVo)。 */ export interface ShopCredential { id: number groupId: number | null groupName: string shopName: string mallName: string znUsername: string account: string password: SensitiveString } /** 店铺分组下拉项(GET /api/admin/shop-manages/groups data)。 */ export interface ShopGroupOption { id: number groupName: string memberCount?: number leaderUsername?: string } /** 店铺密钥列表分页参数(该接口只支持分页)。 */ export interface ShopKeyListParams { page: number pageSize: number } /** 店铺列表分页/筛选参数。 */ export interface ShopManageListParams { page: number pageSize: number groupId?: number | null shopName?: string } export interface ShopKeyPageQuery { page: number pageSize: number } export interface ShopManagePageQuery { page: number pageSize: number groupId?: number shopName?: string } function finiteInt(value: unknown): number | null { return typeof value === 'number' && Number.isFinite(value) ? Math.floor(value) : null } function positiveIdOrNull(value: unknown): number | null { const id = finiteInt(value) return id === null || id < 1 ? null : id } function trimOrUndefined(value: unknown): string | undefined { return typeof value === 'string' && value.trim() ? value.trim() : undefined } /** 归一化分页:页码下限 1、页大小钳制在 1..100(与 Java 服务端一致)。 */ function normalizePageCore(raw: { page?: unknown; pageSize?: unknown }): { page: number; pageSize: number } { const page = Math.max(finiteInt(raw.page) ?? SHOP_PAGE_MIN_PAGE, SHOP_PAGE_MIN_PAGE) const rawSize = finiteInt(raw.pageSize) const pageSize = rawSize === null || rawSize < SHOP_PAGE_MIN_PAGE ? SHOP_PAGE_DEFAULT_SIZE : Math.min(rawSize, SHOP_PAGE_MAX_SIZE) return { page, pageSize } } /** 店铺密钥列表分页归一。 */ export function normalizeKeyListParams(raw: Partial): ShopKeyListParams { return normalizePageCore(raw) } /** 店铺列表分页/筛选归一:负/缺分组 id 视为无筛选,空白店铺名视为无过滤。 */ export function normalizeShopListParams(raw: Partial): ShopManageListParams { return { ...normalizePageCore(raw), groupId: positiveIdOrNull(raw.groupId), shopName: trimOrUndefined(raw.shopName), } } export function toKeyPageQuery(params: ShopKeyListParams): ShopKeyPageQuery { return { page: params.page, pageSize: params.pageSize } } /** 前端状态 → Java 查询参数(camelCase);仅下发非空可选字段。 */ export function toShopManagePageQuery(params: ShopManageListParams): ShopManagePageQuery { const query: ShopManagePageQuery = { page: params.page, pageSize: params.pageSize } if (params.groupId != null) query.groupId = params.groupId if (params.shopName) query.shopName = params.shopName return query } /** 无数据密钥分页缺省值(首屏/加载前占位)。 */ export function emptyShopKeyPageResult(): ShopKeyPageResult { return { items: [], total: 0, page: SHOP_PAGE_MIN_PAGE, pageSize: SHOP_PAGE_DEFAULT_SIZE } } /** 无数据店铺分页缺省值(首屏/加载前占位)。 */ export function emptyShopPageResult(): ShopPageResult { return { items: [], total: 0, page: SHOP_PAGE_MIN_PAGE, pageSize: SHOP_PAGE_DEFAULT_SIZE } }