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
+9
View File
@@ -54,6 +54,15 @@ export const PERMISSION_CODES = {
NOTIFICATIONS_MANAGE: 'notifications:manage',
STATISTICS_READ: 'statistics:read',
EXPORTS_CREATE: 'exports:create',
OLD_ITEMS_READ: 'old_items:read',
OLD_ITEMS_MANAGE: 'old_items:manage',
OLD_ITEM_NEEDS_MANAGE: 'old_item_needs:manage',
OLD_ITEM_INVENTORY_READ: 'old_item_inventory:read',
OLD_ITEM_INVENTORY_MANAGE: 'old_item_inventory:manage',
OLD_ITEM_INVENTORY_IMPORT: 'old_item_inventory:import',
OLD_ITEM_INVENTORY_EXPORT: 'old_item_inventory:export',
OLD_ITEM_REWARDS_READ: 'old_item_rewards:read',
OLD_ITEM_REWARDS_MANAGE: 'old_item_rewards:manage',
} as const;
export type PermissionCode = (typeof PERMISSION_CODES)[keyof typeof PERMISSION_CODES];
+54
View File
@@ -26,6 +26,60 @@ export {
SERVICE_CATEGORIES,
SERVICE_CATEGORY_LABELS,
} from './service-applications.js';
export {
OLD_ITEM_CATEGORIES,
OLD_ITEM_CATEGORY_LABELS,
OLD_ITEM_CONDITIONS,
OLD_ITEM_CONDITION_LABELS,
OLD_ITEM_DONATION_METHODS,
OLD_ITEM_DONATION_STATUSES,
OLD_ITEM_DONATION_STATUS_LABELS,
OLD_ITEM_NEED_STATUSES,
OLD_ITEM_INVENTORY_STATUSES,
OLD_ITEM_INVENTORY_STATUS_LABELS,
OLD_ITEM_INVENTORY_EVENT_TYPES,
OLD_ITEM_CERTIFICATE_STATUSES,
OLD_ITEM_POINT_ENTRY_TYPES,
} from './old-items.js';
export type {
OldItemCategory,
OldItemCondition,
OldItemDonationMethod,
OldItemDonationStatus,
OldItemNeedStatus,
OldItemStats,
OldItemDropOffPoint,
OldItemNeedItem,
OldItemDonationHistoryItem,
OldItemDonationItem,
OldItemAssigneeOption,
CreateOldItemDonationRequest,
TransitionOldItemDonationRequest,
CreateOldItemNeedRequest,
UpdateOldItemNeedRequest,
TransitionOldItemNeedRequest,
OldItemInventoryStatus,
OldItemInventoryEventType,
OldItemPublicInventoryEvent,
OldItemInventoryEventItem,
OldItemInventoryItem,
CreateOldItemInventoryRequest,
OldItemInventoryImportRow,
ImportOldItemInventoryRequest,
TransitionOldItemInventoryRequest,
OldItemInventoryExportRow,
OldItemCertificateStatus,
OldItemPointEntryType,
OldItemRewardConfig,
OldItemCertificateItem,
OldItemPointEntryItem,
OldItemRewardsSummary,
OldItemPointAccountItem,
ActivateOldItemRewardConfigRequest,
IssueOldItemCertificateRequest,
RevokeOldItemCertificateRequest,
AdjustOldItemPointsRequest,
} from './old-items.js';
export type { StatisticsOverview } from './statistics.js';
export {
FINANCIAL_DISCLOSURE_STATUSES,
+338
View File
@@ -0,0 +1,338 @@
export const OLD_ITEM_CATEGORIES = ['CLOTHING', 'BOOKS', 'HOUSEHOLD', 'SPORTS'] as const;
export type OldItemCategory = (typeof OLD_ITEM_CATEGORIES)[number];
export const OLD_ITEM_CATEGORY_LABELS: Record<OldItemCategory, string> = {
CLOTHING: '服饰',
BOOKS: '书籍',
HOUSEHOLD: '生活用品',
SPORTS: '文体用品',
};
export const OLD_ITEM_CONDITIONS = ['NEW', 'LIKE_NEW', 'GOOD', 'FAIR'] as const;
export type OldItemCondition = (typeof OLD_ITEM_CONDITIONS)[number];
export const OLD_ITEM_CONDITION_LABELS: Record<OldItemCondition, string> = {
NEW: '全新',
LIKE_NEW: '九成新',
GOOD: '使用良好',
FAIR: '可正常使用',
};
export const OLD_ITEM_DONATION_METHODS = ['PICKUP', 'DROP_OFF'] as const;
export type OldItemDonationMethod = (typeof OLD_ITEM_DONATION_METHODS)[number];
export const OLD_ITEM_DONATION_STATUSES = [
'SUBMITTED',
'REJECTED',
'WAITING_PICKUP',
'WAITING_DROP_OFF',
'RECEIVED',
'PROCESSING',
'COMPLETED',
'CANCELLED',
] as const;
export type OldItemDonationStatus = (typeof OLD_ITEM_DONATION_STATUSES)[number];
export const OLD_ITEM_DONATION_STATUS_LABELS: Record<OldItemDonationStatus, string> = {
SUBMITTED: '待审核',
REJECTED: '已驳回',
WAITING_PICKUP: '待取件',
WAITING_DROP_OFF: '待投递',
RECEIVED: '已接收',
PROCESSING: '分拣中',
COMPLETED: '已完成',
CANCELLED: '已取消',
};
export const OLD_ITEM_NEED_STATUSES = ['DRAFT', 'PUBLISHED', 'FULFILLED', 'CLOSED'] as const;
export type OldItemNeedStatus = (typeof OLD_ITEM_NEED_STATUSES)[number];
export const OLD_ITEM_INVENTORY_STATUSES = [
'IN_STOCK',
'SORTED',
'DISINFECTED',
'OUTBOUND',
'DELIVERED',
] as const;
export type OldItemInventoryStatus = (typeof OLD_ITEM_INVENTORY_STATUSES)[number];
export const OLD_ITEM_INVENTORY_STATUS_LABELS: Record<OldItemInventoryStatus, string> = {
IN_STOCK: '已入库',
SORTED: '已分拣',
DISINFECTED: '已消毒',
OUTBOUND: '已出库',
DELIVERED: '已落地',
};
export const OLD_ITEM_INVENTORY_EVENT_TYPES = [
'INBOUND',
'SORTED',
'DISINFECTED',
'OUTBOUND',
'DELIVERED',
] as const;
export type OldItemInventoryEventType = (typeof OLD_ITEM_INVENTORY_EVENT_TYPES)[number];
export const OLD_ITEM_CERTIFICATE_STATUSES = ['ISSUED', 'REVOKED'] as const;
export type OldItemCertificateStatus = (typeof OLD_ITEM_CERTIFICATE_STATUSES)[number];
export const OLD_ITEM_POINT_ENTRY_TYPES = ['EARNED', 'ADJUSTMENT'] as const;
export type OldItemPointEntryType = (typeof OLD_ITEM_POINT_ENTRY_TYPES)[number];
export interface OldItemStats {
totalItems: number;
assistedPeople: number;
monthlyKindActs: number;
}
export interface OldItemDropOffPoint {
publicId: string;
name: string;
regionText: string;
addressText: string;
openingHours: string;
}
export interface OldItemNeedItem {
publicId: string;
title: string;
category: OldItemCategory;
regionText: string;
beneficiaryGroup: string;
description: string;
requestedQuantity: number;
fulfilledQuantity: number;
remainingQuantity: number;
priority: number;
status: OldItemNeedStatus;
revision: number;
publishedAt: string | null;
}
export interface OldItemDonationHistoryItem {
fromStatus: OldItemDonationStatus | null;
toStatus: OldItemDonationStatus;
note: string | null;
createdAt: string;
}
export interface OldItemDonationItem {
publicId: string;
donationNo: string;
category: OldItemCategory;
itemCondition: OldItemCondition;
quantity: number;
description: string;
method: OldItemDonationMethod;
status: OldItemDonationStatus;
targetNeed: Pick<OldItemNeedItem, 'publicId' | 'title'> | null;
dropOffPoint: OldItemDropOffPoint | null;
appointmentAt: string | null;
contactName: string;
mobileMasked: string;
address: string | null;
assigneeName: string | null;
rejectionReason: string | null;
assistedPeople: number;
revision: number;
createdAt: string;
history: OldItemDonationHistoryItem[];
imagePublicIds: string[];
inventoryTrace: OldItemPublicInventoryEvent[];
}
export interface OldItemAssigneeOption {
publicId: string;
displayName: string;
}
export interface CreateOldItemDonationRequest {
clientRequestId: string;
category: OldItemCategory;
itemCondition: OldItemCondition;
quantity: number;
description: string;
method: OldItemDonationMethod;
contactName: string;
mobile: string;
address?: string;
appointmentAt?: string;
dropOffPointPublicId?: string;
targetNeedPublicId?: string;
imagePublicIds?: string[];
}
export interface TransitionOldItemDonationRequest {
clientRequestId: string;
expectedRevision: number;
targetStatus: OldItemDonationStatus;
note?: string;
assignedUserPublicId?: string;
assistedPeople?: number;
}
export interface CreateOldItemNeedRequest {
clientRequestId: string;
title: string;
category: OldItemCategory;
regionText: string;
beneficiaryGroup: string;
description: string;
requestedQuantity: number;
priority?: number;
sortOrder?: number;
}
export interface UpdateOldItemNeedRequest extends Omit<
CreateOldItemNeedRequest,
'clientRequestId'
> {
expectedRevision: number;
}
export interface TransitionOldItemNeedRequest {
clientRequestId: string;
expectedRevision: number;
targetStatus: OldItemNeedStatus;
}
export interface OldItemPublicInventoryEvent {
status: OldItemInventoryStatus;
locationText: string | null;
eventAt: string;
}
export interface OldItemInventoryEventItem extends OldItemPublicInventoryEvent {
eventType: OldItemInventoryEventType;
fromStatus: OldItemInventoryStatus | null;
note: string | null;
operatorName: string;
}
export interface OldItemInventoryItem {
publicId: string;
inventoryNo: string;
sourceDonation: { publicId: string; donationNo: string } | null;
category: OldItemCategory;
itemName: string;
quantity: number;
unit: string;
storageLocation: string;
status: OldItemInventoryStatus;
targetNeed: Pick<OldItemNeedItem, 'publicId' | 'title'> | null;
beneficiaryPublicId: string | null;
destinationRegion: string | null;
note: string | null;
landingAt: string | null;
revision: number;
createdAt: string;
events: OldItemInventoryEventItem[];
}
export interface CreateOldItemInventoryRequest {
clientRequestId: string;
sourceDonationPublicId?: string;
category: OldItemCategory;
itemName: string;
quantity: number;
unit: string;
storageLocation: string;
targetNeedPublicId?: string;
note?: string;
inboundAt?: string;
}
export interface OldItemInventoryImportRow {
sourceDonationNo?: string;
category: OldItemCategory;
itemName: string;
quantity: number;
unit: string;
storageLocation: string;
targetNeedPublicId?: string;
note?: string;
inboundAt?: string;
}
export interface ImportOldItemInventoryRequest {
clientRequestId: string;
originalFilename: string;
rows: OldItemInventoryImportRow[];
}
export interface TransitionOldItemInventoryRequest {
clientRequestId: string;
expectedRevision: number;
targetStatus: OldItemInventoryStatus;
eventAt?: string;
locationText?: string;
note?: string;
targetNeedPublicId?: string;
beneficiaryPublicId?: string;
destinationRegion?: string;
assistedPeople?: number;
}
export interface OldItemInventoryExportRow {
inventoryNo: string;
sourceDonationNo: string;
category: OldItemCategory;
itemName: string;
quantity: number;
unit: string;
storageLocation: string;
status: OldItemInventoryStatus;
targetNeedTitle: string;
beneficiaryPublicId: string;
destinationRegion: string;
landingAt: string;
createdAt: string;
}
export interface OldItemRewardConfig {
publicId: string | null;
version: number;
certificateTitle: string;
certificateMessage: string;
issuerName: string;
legalNotice: string;
clothingPoints: number;
booksPoints: number;
householdPoints: number;
sportsPoints: number;
maxPointsPerDonation: number;
createdAt: string | null;
}
export interface OldItemCertificateItem {
publicId: string;
certificateNo: string;
donationPublicId: string;
donationNo: string;
status: OldItemCertificateStatus;
recipientName: string;
title: string;
message: string;
issuerName: string;
legalNotice: string;
issuedAt: string;
revokedAt: string | null;
revokeReason: string | null;
}
export interface OldItemPointEntryItem {
publicId: string;
entryType: OldItemPointEntryType;
pointsDelta: number;
balanceAfter: number;
donationNo: string | null;
note: string | null;
createdAt: string;
}
export interface OldItemRewardsSummary {
balance: number;
certificates: OldItemCertificateItem[];
entries: OldItemPointEntryItem[];
}
export interface OldItemPointAccountItem {
publicId: string;
userPublicId: string;
displayName: string;
balance: number;
revision: number;
updatedAt: string;
}
export interface ActivateOldItemRewardConfigRequest {
clientRequestId: string;
certificateTitle: string;
certificateMessage: string;
issuerName: string;
legalNotice: string;
clothingPoints: number;
booksPoints: number;
householdPoints: number;
sportsPoints: number;
maxPointsPerDonation: number;
}
export interface IssueOldItemCertificateRequest {
clientRequestId: string;
}
export interface RevokeOldItemCertificateRequest {
clientRequestId: string;
reason: string;
}
export interface AdjustOldItemPointsRequest {
clientRequestId: string;
expectedRevision: number;
pointsDelta: number;
reason: string;
}
+1 -1
View File
@@ -355,7 +355,7 @@ export interface RecordServiceMinutesRequest {
export interface CreateMediaUploadIntentRequest {
clientRequestId: string;
businessType: 'PROJECT_COVER' | 'ACTIVITY_COVER';
businessType: 'PROJECT_COVER' | 'ACTIVITY_COVER' | 'OLD_ITEM_DONATION_IMAGE';
filename: string;
mimeType: 'image/jpeg' | 'image/png' | 'image/webp';
size: number;