Files
qipai/admin/src/types.ts
T

956 lines
24 KiB
TypeScript

export type TaskStatus =
| 'WAITING'
| 'CLAIMED'
| 'STARTED'
| 'SUBMITTED'
| 'COMPLETED'
| 'REJECTED'
| 'EXEMPT'
| 'SETTLED'
| 'CANCELLED';
export type SettlementStatus = 'DRAFT' | 'CONFIRMED' | 'PAID' | 'CANCELLED';
export type PayoutStateFilter = 'NONE' | 'SUCCESS' | 'FAIL' | 'PROCESSING' | 'WAIT_USER_CONFIRM';
export type TransferMode = 'API' | 'MOCK';
export type UserStatus = 'ACTIVE' | 'DISABLED';
export type StaffRole = 'CLEANER' | 'STAFF' | 'STORE_ADMIN' | 'TENANT_ADMIN';
export interface PageResult<T> {
items: T[];
total: number;
page: number;
pageSize: number;
}
export interface ProductListing {
id: string; storeId: string; productId: string; categoryId: string;
categoryName: string; productCode: string; productName: string;
status: 'ACTIVE' | 'INACTIVE'; fulfillmentMode: 'DELIVERY' | 'SELF_SERVICE' | 'BOTH';
salesStartAt: string | null; salesEndAt: string | null; version: number;
}
export interface InventoryStock {
id: string; storeId: string; productId: string; productCode: string; productName: string;
skuId: string; skuCode: string; skuName: string; salePriceCents: number;
policyType: 'TRACKED' | 'UNLIMITED'; availableQuantity: number;
lockedQuantity: number; lossQuantity: number; lowStockThreshold: number;
lowStock: boolean; version: number;
}
export interface ProductOrder {
id: string; storeId: string; memberId: string | null; roomOrderId: string | null;
orderNo: string; fulfillmentMode: 'DELIVERY' | 'SELF_SERVICE'; status: string;
itemCount: number; totalQuantity: number; totalAmountCents: number;
paidAmountCents: number; refundedAmountCents: number; note: string;
inventoryStatus: string; createdAt: string; updatedAt: string;
items?: ProductOrderItem[]; payments?: ProductPayment[];
refunds?: ProductRefund[]; events?: ProductOrderEvent[];
}
export interface ProductOrderItem {
id: string; productName: string; skuName: string; quantity: number;
unitPriceCents: number; subtotalCents: number; note?: string;
}
export interface ProductPayment {
id: string; paymentNo: string; provider: string; channel: string; status: string;
amountCents: number; refundedAmountCents: number;
expiresAt: string; paidAt: string | null; createdAt: string;
}
export interface ProductRefund {
id: string; paymentId: string; refundNo: string; provider: string; status: string;
amountCents: number; reason: string; inventoryDisposition: string;
inventoryStatus: string; completedAt: string | null; createdAt: string;
}
export interface ProductOrderEvent {
id: string; fromStatus: string | null; toStatus: string; action: string;
actorType: string; actorId: string | null; versionAfter: number;
reason: string; createdAt: string;
}
export interface ProductOrderReconciliation {
order: { id: string; orderNo: string; status: string; inventoryStatus: string };
amounts: {
orderAmountCents: number; itemAmountCents: number;
paidAmountCents: number; capturedAmountCents: number;
refundedAmountCents: number; paymentRefundedCents: number;
succeededRefundCents: number; netRevenueCents: number;
};
inventory: {
status: string; reservationBalance: number; saleBalance: number;
ledger: Array<{
id: string; inventoryId: string; skuId: string; productName: string; skuName: string;
requestId: string; operation: string; availableDelta: number; lockedDelta: number;
lossDelta: number; reservationDelta: number; saleDelta: number;
availableAfter: number; lockedAfter: number; lossAfter: number;
versionAfter: number; createdAt: string;
}>;
};
storages: Array<{
id: string; storageNo: string; status: string; recordTotalQuantity: number;
recordRemainingQuantity: number; itemTotalQuantity: number;
itemRemainingQuantity: number; itemCount: number; consistent: boolean;
}>;
checks: Array<{ key: string; passed: boolean; expected: number; actual: number }>;
consistent: boolean;
}
export interface ProductStorage {
id: string; storeId: string; memberId: string; sourceOrderId: string | null;
storageNo: string; sourceType: 'ORDER' | 'MANUAL'; status: string;
itemCount: number; totalQuantity: number; remainingQuantity: number;
expiresAt: string; claimCredentialVersion: number; claimCredentialConsumed: boolean;
createdAt: string; updatedAt: string; cancelReason: string;
items?: ProductStorageItem[]; events?: Array<Record<string, unknown>>;
movements?: Array<Record<string, unknown>>; claimCredential?: string | null;
nextClaimCredential?: string | null;
}
export interface ProductStorageItem {
id: string; productName: string; skuName: string; skuId: string;
totalQuantity: number; remainingQuantity: number;
}
export interface ManagedStore {
id: string;
name: string;
address: string;
city: string;
district: string;
longitude: number | null;
latitude: number | null;
contactPhone: string;
businessStatus: 'OPEN' | 'CLOSED' | 'SUSPENDED';
timezone: string;
wifiSsid: string;
wifiConfigured: boolean;
notificationUrl: string;
sortOrder: number;
businessHours: StoreBusinessHour[];
}
export interface StoreBusinessHour {
weekday: number;
openMinute: number;
closeMinute: number;
isClosed: boolean;
}
export interface StoreInput {
name: string;
address: string;
city: string;
district: string;
longitude?: number | null;
latitude?: number | null;
contactPhone: string;
timezone: string;
businessStatus: ManagedStore['businessStatus'];
wifiSsid: string;
wifiPassword?: string;
notificationUrl: string;
sortOrder: number;
businessHours: StoreBusinessHour[];
}
export type RoomConfigurationStatus = 'ENABLED' | 'DISABLED';
export type RoomOperationalStatus =
| 'AVAILABLE'
| 'MAINTENANCE'
| 'RESERVED'
| 'IN_USE'
| 'CLEANING_REQUIRED';
export interface ManagedRoom {
id: string;
storeId: string;
categoryName: string;
name: string;
roomNo: string;
capacity: number;
basePriceCents: number;
weekdayPriceCents: number;
holidayPriceCents: number;
overnightPriceCents: number;
fullDayPriceCents: number;
minimumSpendCents: number;
depositCents: number;
minimumMinutes: number;
maxAdvanceStartMinutes: number;
maxAdvanceDays: number;
configurationStatus: RoomConfigurationStatus;
operationalStatus: RoomOperationalStatus;
tags: string[];
images: string[];
sortOrder: number;
}
export type RoomInput = Omit<ManagedRoom, 'id'>;
export type OrderStatus =
| 'DRAFT'
| 'PENDING_PAYMENT'
| 'PAID'
| 'RESERVED'
| 'IN_PROGRESS'
| 'FINISHED'
| 'CANCELLED'
| 'REFUNDING'
| 'REFUNDED'
| 'CLOSED';
export type OrderAction =
| 'SUBMIT'
| 'CONFIRM_PAYMENT'
| 'RESERVE'
| 'START'
| 'FINISH'
| 'CANCEL'
| 'BEGIN_REFUND'
| 'COMPLETE_REFUND'
| 'CLOSE';
export interface ManagedOrder {
id: string;
orderNo: string;
storeId: string;
storeName: string;
roomId: string;
roomName: string;
roomNo: string;
status: OrderStatus;
startAt: string;
endAt: string;
totalAmountCents: number;
paidAmountCents: number;
latestPayment: null | { id: string; provider: string; status: string };
createdAt: string;
}
export interface OrderHistoryItem {
id: string;
fromStatus: OrderStatus | null;
toStatus: OrderStatus;
action: OrderAction | 'CREATED' | 'EXPIRED' | 'MIGRATED';
actorType: string;
actorId: string | null;
source: string;
reason: string;
traceId: string;
createdAt: string;
}
export type PaymentAuthorizationStatus = 'UNAUTHORIZED' | 'PENDING' | 'AUTHORIZED' | 'REVOKED';
export interface CollectionAccount {
id: string;
platformAppId: string;
storeId: string | null;
provider: string;
merchantId: string;
authorizationStatus: PaymentAuthorizationStatus;
profitSharingEnabled: boolean | number;
enabled: boolean | number;
}
export interface ProfitShareReceiver {
id: string;
collectionAccountId: string;
receiverType: 'MERCHANT_ID' | 'PERSONAL_OPENID';
receiverMasked: string;
relationType: string;
name: string;
authorizationStatus: PaymentAuthorizationStatus;
enabled: boolean | number;
}
export interface ProfitSharePolicy {
id: string;
collectionAccountId: string;
storeId: string | null;
receiverId: string;
percentageBps: number;
enabled: boolean | number;
}
export interface ProfitShareRecord {
id: string;
paymentId: string;
orderId: string;
storeId: string;
shareNo: string;
receiverType: string;
receiverMasked: string;
percentageBps: number;
amountCents: number;
status: string;
failureCode: string;
createdAt: string;
}
export interface ProfitSharingSnapshot {
accounts: CollectionAccount[];
receivers: ProfitShareReceiver[];
policies: ProfitSharePolicy[];
shares: ProfitShareRecord[];
}
export type ThirdPartyProvider = 'MEITUAN' | 'DIANPING' | 'DOUYIN' | 'KUAISHOU';
export type ThirdPartyMode = 'MANUAL' | 'MOCK' | 'API';
export interface DirectBookingRecord {
id: string;
provider: ThirdPartyProvider;
externalBookingNo: string;
storeId: string | null;
roomId: string | null;
startsAt: string;
endsAt: string;
amountCents: number;
status: string;
orderId: string | null;
failureCode: string;
createdAt: string;
}
export interface GroupRedemptionRecord {
id: string;
provider: ThirdPartyProvider;
voucherMasked: string;
orderId: string;
storeId: string;
mode: ThirdPartyMode;
actorId: string | null;
status: string;
failureCode: string;
createdAt: string;
completedAt: string | null;
}
export interface ThirdPartyRecords {
bookings: DirectBookingRecord[];
redemptions: GroupRedemptionRecord[];
}
export interface ThirdPartyConfigSummary {
id: string;
provider: ThirdPartyProvider;
storeId: string | null;
mode: ThirdPartyMode;
enabled: boolean;
credentialRef: string;
credentialConfigured: boolean;
settings: Record<string, unknown>;
updatedAt: string;
}
export interface ThirdPartyMappingSummary {
id: string;
provider: ThirdPartyProvider;
resourceType: 'STORE' | 'ROOM';
externalRef: string;
localResourceId: string;
}
export interface ThirdPartySetup {
configs: ThirdPartyConfigSummary[];
mappings: ThirdPartyMappingSummary[];
}
export interface BusinessStatistics {
storeId: string;
from: string;
to: string;
summary: {
orderTotal: number;
activeOrderTotal: number;
finishedOrderTotal: number;
bookedAmountCents: number;
collectedAmountCents: number;
payingMemberTotal: number;
voucherTotal: number;
voucherSucceeded: number;
voucherFailed: number;
roomTotal: number;
availableRoomTotal: number;
attentionRoomTotal: number;
};
orderStatuses: Array<{ status: string; total: number; amountCents: number }>;
paymentChannels: Array<{ channel: string; total: number; amountCents: number }>;
dailyRevenue: Array<{ date: string; total: number; amountCents: number }>;
}
export interface ManagedUser {
id: string;
userType: string;
status: UserStatus;
nickname: string;
avatarUrl: string;
maskedPhone: string;
maskedLastIp: string;
note: string;
roles: StaffRole[];
storeIds: string[];
wechatMiniappBound: boolean;
registeredAt: string;
lastLoginAt: string | null;
}
export interface MemberWalletSummary {
accountCount: number;
cashBalanceCents: number;
giftBalanceCents: number;
totalBalanceCents: number;
}
export interface MemberBenefitSummary {
availableCoupons: number;
frozenCoupons: number;
activePackages: number;
frozenPackages: number;
packageMinutes: number;
packageAmountCents: number;
}
export interface MemberCard {
memberId: string;
status: UserStatus;
nickname: string;
maskedPhone: string;
registeredAt: string;
lastLoginAt: string | null;
wallet: MemberWalletSummary;
benefits: MemberBenefitSummary;
recharge: {
rechargeOrderCount: number;
creditedRechargeCount: number;
creditedRechargeCents: number;
giftedRechargeCents: number;
lastRechargeAt: string | null;
};
orders: {
orderCount: number;
paidOrderCount: number;
paidAmountCents: number;
lastOrderAt: string | null;
};
}
export interface MemberLedgerEntry {
ledgerId: string;
storeId: string | null;
businessType: string;
businessId: string;
entryType: string;
cashDeltaCents: number;
giftDeltaCents: number;
cashBalanceAfterCents: number;
giftBalanceAfterCents: number;
createdAt: string;
}
export interface MemberDetail extends MemberCard {
recentLedger: MemberLedgerEntry[];
}
export type DeviceType = 'CONTROL_BOX' | 'SUB_LOCK' | 'SMART_SOCKET';
export interface DeviceAsset {
id: string;
storeId: string;
roomId: string | null;
deviceId: string;
imei: string;
iccid: string | null;
deviceType: DeviceType;
model: string;
firmwareVersion: string;
status: 'ONLINE' | 'OFFLINE' | 'FAULT';
signalStrength: number | null;
capabilities: string[];
stateSnapshot: Record<string, unknown>;
lastSeenAt: string | null;
lastHeartbeatAt: string | null;
maintenanceStatus: string;
}
export interface DeviceChannel {
id: string;
assetId: string;
roomId: string;
channelCode: string;
purpose: string;
targetKey: string;
enabled: boolean;
}
export interface DeviceLink {
id: string;
parentAssetId: string;
childAssetId: string;
roomId: string;
linkType: string;
subId: string;
subtype: string;
status: string;
}
export interface DeviceAlert {
id: string;
assetId: string;
roomId: string | null;
alertType: string;
severity: string;
status: string;
summary: string;
firstSeenAt: string;
lastSeenAt: string;
}
export interface DeviceMaintenance {
id: string;
assetId: string;
roomId: string | null;
recordType: 'INSPECTION' | 'REPAIR' | 'REPLACEMENT';
status: 'OPEN' | 'RESOLVED';
description: string;
createdAt: string;
resolvedAt: string | null;
}
export interface DeviceTopology {
assets: DeviceAsset[];
channels: DeviceChannel[];
links: DeviceLink[];
openAlerts: DeviceAlert[];
maintenance: DeviceMaintenance[];
}
export interface PlatformApplication {
platformAppId: string;
appId: string;
appName: string;
appStatus: 'ACTIVE' | 'DISABLED';
bindingStatus: 'ACTIVE' | 'DISABLED';
isDefault: boolean;
brandName: string;
logoUrl: string;
themeColor: string;
servicePhone: string;
franchisePhone: string;
shareTitle: string;
shareImageUrl: string;
defaultStoreId: string | null;
extraConfig: Record<string, unknown>;
updatedAt: string;
}
export interface TenantApplicationConfig {
brandName: string;
logoUrl: string;
themeColor: string;
servicePhone: string;
franchisePhone: string;
shareTitle: string;
shareImageUrl: string;
defaultStoreId: string | null;
extraConfig: Record<string, unknown>;
bindingStatus: 'ACTIVE' | 'DISABLED';
isDefault: boolean;
}
export interface MediaAsset {
id: string;
storeId: string | null;
url: string;
mimeType: string;
byteSize: number;
width: number;
height: number;
createdAt: string;
}
export type DecorationComponentType = 'HERO' | 'NOTICE' | 'GALLERY' | 'CONTACT' | 'ROOM_LIST';
export interface DecorationComponent {
type: DecorationComponentType;
props: Record<string, unknown>;
}
export interface DecorationVersion {
id: string;
storeId: string;
templateCode: string;
schemaVersion: number;
content: { components: DecorationComponent[] };
status: 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';
version: number;
publishedAt: string | null;
createdAt: string;
}
export interface AdvertisementInput {
scopeType: 'PLATFORM' | 'TENANT' | 'STORE';
storeId: string | null;
title: string;
imageAssetId: string;
targetType: 'NONE' | 'PAGE' | 'URL';
targetValue: string;
startsAt: string | null;
endsAt: string | null;
status: 'DRAFT' | 'ACTIVE' | 'INACTIVE';
sortOrder: number;
}
export interface Advertisement extends AdvertisementInput {
id: string;
imageUrl: string;
}
export type FranchiseStatus = 'NEW' | 'CONTACTED' | 'QUALIFIED' | 'REJECTED' | 'CONVERTED';
export type FranchiseFollowUpType = 'CALL' | 'WECHAT' | 'MEETING' | 'NOTE' | 'STATUS' | 'ASSIGNMENT';
export interface FranchiseApplication {
id: string; tenantId: string; applicationNo: string; city: string; contactName: string;
contactPhone: string; message: string; source: string; status: FranchiseStatus;
assigneeUserId: string | null; assigneeName: string | null; submittedUserId: string | null;
nextFollowUpAt: string | null; closedAt: string | null; createdAt: string; updatedAt: string;
}
export interface FranchiseFollowUp {
id: string; actorUserId: string; actorName: string; followUpType: FranchiseFollowUpType;
fromStatus: FranchiseStatus | null; toStatus: FranchiseStatus | null;
note: string; nextFollowUpAt: string | null; createdAt: string;
}
export interface FranchiseApplicationDetail {
application: FranchiseApplication;
followUps: FranchiseFollowUp[];
}
export interface AuditLog {
id: string;
tenantId: string;
actorType: string;
actorId: string | null;
actorName: string | null;
action: string;
resourceType: string;
resourceId: string | null;
traceId: string;
ip: string;
userAgent: string;
metadata: unknown;
createdAt: string;
}
export interface SystemOverview {
tenant: {
id: string;
code: string;
name: string;
status: 'ACTIVE' | 'DISABLED';
timezone: string;
createdAt: string;
updatedAt: string;
};
counts: {
storeCount: number;
userCount: number;
activeSessionCount: number;
appBindingCount: number;
auditTodayCount: number;
};
latestMigration: null | { version: string; name: string; appliedAt: string };
}
export interface AdminIdentity {
id: string;
tenantId: string;
userType: string;
nickname: string;
avatarUrl: string;
roleVersion: number;
}
export interface AdminAccess {
roles: string[];
capabilities: string[];
storeIds: string[];
menus: string[];
}
export interface AdminSessionPayload {
accessToken: string;
refreshToken: string;
expiresIn: number;
user: AdminIdentity;
access: AdminAccess;
}
export interface CleaningTask {
id: string;
taskNo: string;
storeId: string;
storeName: string;
roomId: string;
roomName: string;
roomNo: string;
orderId: string | null;
orderNo: string | null;
status: TaskStatus;
cleanerUserId: string | null;
priority: number;
rewardCents: number;
requirement: string;
cleaningTemplateId: string | null;
cleaningTemplateVersion: number;
photoRequired: boolean;
minPhotoCount: number;
maxPhotoCount: number;
exemptPolicy: CleaningExemptPolicy;
photoUrls: string[];
rejectReason: string;
reworkCount: number;
photoRevision: number;
claimedAt?: string;
startedAt?: string;
submittedAt?: string;
completedAt?: string;
memberCount: number;
createdAt?: string;
updatedAt?: string;
}
export type CleaningTemplateScope = 'TENANT' | 'STORE' | 'ROOM';
export type CleaningExemptPolicy = 'DISABLED' | 'BEFORE_START' | 'ANY_ACTIVE';
export interface CleaningTemplate {
id: string;
scopeKey: string;
scopeType: CleaningTemplateScope;
storeId: string | null;
roomId: string | null;
name: string;
requirement: string;
photoRequired: boolean;
minPhotoCount: number;
maxPhotoCount: number;
exemptPolicy: CleaningExemptPolicy;
version: number;
status: 'ACTIVE' | 'DISABLED';
updatedAt: string;
appliesToExistingTasks: false;
}
export interface CleaningTaskMember {
id: string;
taskId: string;
userId: string;
nickname: string;
memberRole: 'LEAD' | 'ASSIST';
rewardCents: number;
joinedAt?: string;
removedAt?: string | null;
settledAt?: string | null;
}
export interface CleaningTaskEvent {
id: string;
taskId: string;
fromStatus: TaskStatus | null;
toStatus: TaskStatus;
action: string;
actorId: string;
actorType: 'USER' | 'SYSTEM';
traceId: string;
note: string;
createdAt: string;
}
export interface CleaningTaskSubmission {
id: string;
taskId: string;
revision: number;
status: 'SUBMITTED' | 'ACCEPTED' | 'REJECTED';
photoUrls: string[];
note: string;
rejectReason: string;
submittedBy: string;
reviewedBy: string | null;
submittedAt: string;
reviewedAt: string | null;
}
export interface CleaningSettlement {
id: string;
settlementNo: string;
cleanerUserId: string;
cleanerName: string;
storeId: string | null;
storeName: string | null;
status: SettlementStatus;
taskCount: number;
totalRewardCents: number;
periodStart: string | null;
periodEnd: string | null;
paidBy: string | null;
cancelledBy: string | null;
confirmedAt: string | null;
paidAt: string | null;
cancelledAt: string | null;
payoutChannel: string;
payoutRequestNo: string;
payoutReference: string;
payoutState: string;
payoutPackageInfo: string;
payoutError: string;
note: string;
createdAt: string;
}
export interface CleaningSettlementItem {
id: string;
settlementId: string;
taskId: string;
taskNo: string;
orderNo: string | null;
storeName: string;
roomName: string;
roomNo: string;
cleanerUserId: string;
cleanerName: string;
rewardCents: number;
reversedAt: string | null;
completedAt: string | null;
createdAt: string;
}
export interface CleaningSettlementEvent {
id: string;
settlementId: string;
fromStatus: SettlementStatus | null;
toStatus: SettlementStatus;
action: string;
actorType: 'USER' | 'SYSTEM';
actorId: string;
traceId: string;
note: string;
createdAt: string;
}
export interface CleaningSettlementReversal {
id: string;
settlementId: string;
reversalNo: string;
amountDeltaCents: number;
reason: string;
reversedBy: string;
createdAt: string;
}
export interface CleaningSettlementDetail {
settlement: CleaningSettlement;
items: CleaningSettlementItem[];
events: CleaningSettlementEvent[];
reversals: CleaningSettlementReversal[];
}
export interface CleaningStatistics {
summary: {
taskTotal: number;
pendingReview: number;
active: number;
rejected: number;
exempted: number;
completed: number;
rewardCents: number;
pendingSettlementCents: number;
draftSettlementCents: number;
confirmedSettlementCents: number;
paidSettlementCents: number;
};
byStatus: Array<{
status: TaskStatus;
total: number;
rewardCents: number;
}>;
byStore: Array<{
storeId: string;
storeName: string;
taskTotal: number;
pendingReview: number;
completed: number;
rejected: number;
exempted: number;
rewardCents: number;
}>;
settlements: Array<{
status: SettlementStatus;
total: number;
rewardCents: number;
}>;
members: Array<{
cleanerUserId: string;
cleanerName: string;
taskCount: number;
completedTaskCount: number;
rejectedTaskCount: number;
pendingSettlementCents: number;
settledRewardCents: number;
}>;
trend: Array<{
date: string;
taskTotal: number;
pendingReview: number;
completed: number;
rejected: number;
exempted: number;
rewardCents: number;
paidSettlementCents: number;
}>;
}
export type WechatTransferPreflightStatus = 'PASS' | 'WARN' | 'FAIL';
export interface WechatTransferPreflightCheck {
key: string;
status: WechatTransferPreflightStatus;
message: string;
}
export interface WechatTransferPreflight {
ready: boolean;
settlement: {
id: string;
settlementNo: string;
status: SettlementStatus;
totalRewardCents: number;
cleanerUserId: string;
storeId: string | null;
};
account: {
configured: boolean;
id?: string;
storeScoped?: boolean;
merchantIdMasked?: string;
credentialRefMasked?: string;
authorizationStatus?: string;
};
credential: {
configured: boolean;
appIdPresent?: boolean;
serialNoPresent?: boolean;
transferSceneId?: string;
reportInfoCount?: number;
transferNotifyUrlConfigured?: boolean;
platformCertificateCount?: number;
};
cleaner: {
openidConfigured: boolean;
};
checks: WechatTransferPreflightCheck[];
}