Files
lehuo/packages/contracts/src/content-notifications.ts
T

144 lines
4.0 KiB
TypeScript
Raw Normal View History

2026-08-12 14:35:12 +08:00
export const CONTENT_POST_TYPES = [
'ORGANIZATION_INTRO',
'PUBLIC_WELFARE_NEWS',
'SERVICE_STORY',
'NOTICE',
'FAQ',
] as const;
export type ContentPostType = (typeof CONTENT_POST_TYPES)[number];
export const CONTENT_POST_TYPE_LABELS: Record<ContentPostType, string> = {
ORGANIZATION_INTRO: '机构介绍',
PUBLIC_WELFARE_NEWS: '公益动态',
SERVICE_STORY: '服务故事',
NOTICE: '通知公告',
FAQ: '常见问题',
};
export const CONTENT_POST_STATUSES = ['DRAFT', 'PENDING_REVIEW', 'PUBLISHED', 'ARCHIVED'] as const;
export type ContentPostStatus = (typeof CONTENT_POST_STATUSES)[number];
export const CONTENT_POST_STATUS_LABELS: Record<ContentPostStatus, string> = {
DRAFT: '草稿',
PENDING_REVIEW: '待审核',
PUBLISHED: '已发布',
ARCHIVED: '已归档',
};
export interface ContentPostListItem {
publicId: string;
type: ContentPostType;
title: string;
summary: string;
status: ContentPostStatus;
revision: number;
publishedAt: string | null;
updatedAt: string;
}
export interface ContentStatusHistoryItem {
fromStatus: ContentPostStatus | null;
toStatus: ContentPostStatus;
reasonCode: string;
note: string | null;
createdAt: string;
}
export interface ContentPostDetail extends ContentPostListItem {
content: string;
coverFilePublicId: string | null;
privacyReviewedAt: string | null;
reviewedAt: string | null;
history: ContentStatusHistoryItem[];
}
export interface PaginatedContentPostsResponse {
items: ContentPostListItem[];
page: number;
pageSize: number;
total: number;
}
export interface ContentPostDetailResponse {
post: ContentPostDetail;
idempotentReplay?: boolean;
}
export interface CreateContentPostRequest {
clientRequestId: string;
type: ContentPostType;
title: string;
summary: string;
content: string;
coverFilePublicId?: string;
}
export interface UpdateContentPostRequest extends Omit<
CreateContentPostRequest,
'clientRequestId'
> {
expectedRevision: number;
}
export interface TransitionContentPostRequest {
clientRequestId: string;
targetStatus: ContentPostStatus;
note: string;
privacyReviewed?: true;
}
export const NOTIFICATION_TYPES = [
'APPLICATION_SUBMITTED',
'APPLICATION_ACCEPTED',
'SERVICE_ARRANGED',
'SERVICE_COMPLETED',
'FOLLOW_UP_PENDING',
'ACTIVITY_REGISTRATION_RESULT',
] as const;
export type NotificationType = (typeof NOTIFICATION_TYPES)[number];
export const NOTIFICATION_TYPE_LABELS: Record<NotificationType, string> = {
APPLICATION_SUBMITTED: '申请已提交',
APPLICATION_ACCEPTED: '申请已受理',
SERVICE_ARRANGED: '服务已安排',
SERVICE_COMPLETED: '服务已完成',
FOLLOW_UP_PENDING: '待回访',
ACTIVITY_REGISTRATION_RESULT: '活动报名结果',
};
export interface NotificationItem {
publicId: string;
type: NotificationType;
title: string;
body: string;
resourceType: string | null;
resourcePublicId: string | null;
readAt: string | null;
createdAt: string;
}
export interface PaginatedNotificationsResponse {
items: NotificationItem[];
page: number;
pageSize: number;
total: number;
unreadCount: number;
}
export interface NotificationPreferenceItem {
type: NotificationType;
inAppEnabled: boolean;
wechatEnabled: boolean;
authorizedAt: string | null;
}
export interface NotificationPreferencesResponse {
items: NotificationPreferenceItem[];
wechatAdapterConfigured: boolean;
}
export interface UpdateNotificationPreferencesRequest {
items: Array<{ type: NotificationType; inAppEnabled: boolean; wechatEnabled: boolean }>;
}
export interface NotificationDeliveryItem {
publicId: string;
notificationPublicId: string;
type: NotificationType;
channel: 'WECHAT_SUBSCRIPTION';
status: 'PENDING' | 'PROCESSING' | 'SENT' | 'FAILED' | 'DEAD';
attemptCount: number;
nextAttemptAt: string;
lastAttemptAt: string | null;
errorCode: string | null;
createdAt: string;
}
export interface PaginatedNotificationDeliveriesResponse {
items: NotificationDeliveryItem[];
page: number;
pageSize: number;
total: number;
}