2026-09-09 22:05:00 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 业务类型定义(规范 §134 types 目录)
|
|
|
|
|
|
*
|
|
|
|
|
|
* 统一存放 User / Profile / PartnerPreference / MatchRelation / Conversation /
|
|
|
|
|
|
* Activity / MatchmakerService / Report 等核心类型。
|
|
|
|
|
|
* 配合 package.json 的 `tsc --noEmit` 提供 IntelliSense 与类型检查。
|
|
|
|
|
|
* 状态字符串引用 constants/statusEnums.js 的同名常量,避免魔法字符串。
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
// ============ 统一 API 响应(规范 §1 API 规范) ============
|
|
|
|
|
|
export interface ApiResponse<T = unknown> {
|
|
|
|
|
|
success: boolean;
|
|
|
|
|
|
code: string;
|
|
|
|
|
|
message: string;
|
|
|
|
|
|
data: T;
|
|
|
|
|
|
requestId?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface ApiError {
|
|
|
|
|
|
code: string;
|
|
|
|
|
|
message: string;
|
|
|
|
|
|
requestId?: string;
|
|
|
|
|
|
/** 原始错误(仅 NETWORK_ERROR 携带) */
|
|
|
|
|
|
error?: unknown;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============ User / Profile(规范 §107-108) ============
|
|
|
|
|
|
export interface User {
|
2026-10-15 09:47:31 +08:00
|
|
|
|
displayId?: string
|
|
|
|
|
|
displayNumber?: string
|
|
|
|
|
|
userDisplayNumber?: string
|
|
|
|
|
|
serviceDisplayId?: string
|
2026-09-09 22:05:00 +08:00
|
|
|
|
userId: string;
|
|
|
|
|
|
displayName: string; // 前台显示:王女士
|
|
|
|
|
|
age: number; // 前台显示:32
|
|
|
|
|
|
heightCm?: number;
|
|
|
|
|
|
regionName: string; // 前台显示:丹阳
|
|
|
|
|
|
educationCode?: string; // 本科 / 大专 / 硕士 等
|
|
|
|
|
|
occupationCode?: string; // 教师 / 制造业 等(不公开 XX公司XX部门)
|
|
|
|
|
|
maritalStatus?: MaritalStatus;
|
|
|
|
|
|
avatarUrl?: string;
|
|
|
|
|
|
verified?: boolean; // 已实名
|
|
|
|
|
|
reviewed?: boolean; // 已审核
|
|
|
|
|
|
photoUrls?: string[];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export type MaritalStatus = 'never_married' | 'divorced' | 'widowed';
|
|
|
|
|
|
|
|
|
|
|
|
export interface Profile {
|
|
|
|
|
|
userId: string;
|
|
|
|
|
|
displayName: string;
|
|
|
|
|
|
avatarUrl?: string;
|
|
|
|
|
|
photoUrls: string[];
|
|
|
|
|
|
birthDate?: string; // 服务端存储完整,前台只显示 age
|
|
|
|
|
|
heightCm?: number;
|
|
|
|
|
|
regionName: string;
|
|
|
|
|
|
educationCode?: string;
|
|
|
|
|
|
occupationCode?: string;
|
|
|
|
|
|
maritalStatus: MaritalStatus;
|
|
|
|
|
|
hasChildren: boolean;
|
|
|
|
|
|
smoking: boolean;
|
|
|
|
|
|
drinking?: DrinkingHabit;
|
|
|
|
|
|
interests: string[];
|
|
|
|
|
|
intro: string; // 自我介绍
|
|
|
|
|
|
intent: RelationshipIntent; // 婚恋态度
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export type DrinkingHabit = 'never' | 'occasionally' | 'frequently';
|
|
|
|
|
|
|
|
|
|
|
|
export type RelationshipIntent =
|
|
|
|
|
|
| 'serious_marriage' // 认真找对象结婚
|
|
|
|
|
|
| 'getting_to_know' // 先了解
|
|
|
|
|
|
| 'open_minded'; // 顺其自然
|
|
|
|
|
|
|
|
|
|
|
|
// ============ PartnerPreference(择偶条件,规范 §30) ============
|
|
|
|
|
|
export interface PartnerPreference {
|
|
|
|
|
|
ageMin: number;
|
|
|
|
|
|
ageMax: number;
|
|
|
|
|
|
ageImportance: PreferenceImportance; // 必须符合 / 最好符合
|
|
|
|
|
|
heightMin?: number;
|
|
|
|
|
|
heightMax?: number;
|
|
|
|
|
|
heightImportance: PreferenceImportance;
|
|
|
|
|
|
region: string[]; // [丹阳]
|
|
|
|
|
|
regionImportance: PreferenceImportance;
|
|
|
|
|
|
maritalStatusAccepted: MaritalStatus[];
|
|
|
|
|
|
educationAccepted: string[]; // [不限/大专+/本科+]
|
|
|
|
|
|
acceptChildren: 'any' | 'accept' | 'reject';
|
|
|
|
|
|
intentAligned: boolean; // 婚恋计划一致
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export type PreferenceImportance = 'required' | 'preferred'; // 必须符合 / 最好符合
|
|
|
|
|
|
|
|
|
|
|
|
// ============ MatchRelation / Recommendation(规范 §22-25, §107-108) ============
|
|
|
|
|
|
export type RelationStatus =
|
|
|
|
|
|
| 'neutral'
|
|
|
|
|
|
| 'liked'
|
|
|
|
|
|
| 'passed'
|
|
|
|
|
|
| 'mutual_match'
|
|
|
|
|
|
| 'blocked'
|
|
|
|
|
|
| 'unmatched';
|
|
|
|
|
|
|
|
|
|
|
|
export interface Recommendation extends User {
|
|
|
|
|
|
recommendationReasons: string[]; // 最多 3~4 条,弱文字
|
|
|
|
|
|
recommendationLevel?: 'high' | 'medium' | 'normal';
|
|
|
|
|
|
relationStatus: RelationStatus;
|
|
|
|
|
|
likeStatus?: 'liked' | 'passed';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface LikeResult {
|
|
|
|
|
|
relationStatus: RelationStatus;
|
|
|
|
|
|
mutualMatch: boolean;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============ Conversation / Message(规范 §35-38, §61-63) ============
|
|
|
|
|
|
export interface Conversation {
|
|
|
|
|
|
conversationId: string;
|
|
|
|
|
|
targetUserId: string;
|
|
|
|
|
|
targetDisplayName: string;
|
|
|
|
|
|
targetAvatarUrl?: string;
|
|
|
|
|
|
lastMessage?: string;
|
|
|
|
|
|
lastMessageAt?: number; // 服务端时间戳
|
|
|
|
|
|
unreadCount: number;
|
|
|
|
|
|
relationStatus: RelationStatus;
|
|
|
|
|
|
canSendMessage: boolean; // 仅 mutual_match + 双方正常 + 未拉黑 + 未解除
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export type MessageSendStatus = 'sending' | 'sent' | 'failed';
|
|
|
|
|
|
export type ChatBubbleType = 'self' | 'other' | 'system';
|
|
|
|
|
|
|
|
|
|
|
|
export interface Message {
|
|
|
|
|
|
messageId: string; // 前端去重依据(规范 §106)
|
|
|
|
|
|
conversationId: string;
|
|
|
|
|
|
senderId: string;
|
|
|
|
|
|
bubbleType: ChatBubbleType;
|
|
|
|
|
|
content: string;
|
|
|
|
|
|
sentAt: number;
|
|
|
|
|
|
sendStatus?: MessageSendStatus; // 本地消息状态
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============ Activity(规范 §43-46) ============
|
|
|
|
|
|
export type ActivityStatus =
|
|
|
|
|
|
| 'draft'
|
|
|
|
|
|
| 'registration_open'
|
|
|
|
|
|
| 'registration_closed'
|
|
|
|
|
|
| 'ongoing'
|
|
|
|
|
|
| 'ended'
|
|
|
|
|
|
| 'cancelled';
|
|
|
|
|
|
|
|
|
|
|
|
export type RegistrationStatus =
|
|
|
|
|
|
| 'not_applied'
|
|
|
|
|
|
| 'pending'
|
|
|
|
|
|
| 'approved'
|
|
|
|
|
|
| 'rejected'
|
|
|
|
|
|
| 'cancelled';
|
|
|
|
|
|
|
|
|
|
|
|
export interface Activity {
|
2026-10-15 09:47:31 +08:00
|
|
|
|
displayId?: string
|
|
|
|
|
|
displayNumber?: string
|
|
|
|
|
|
userDisplayNumber?: string
|
|
|
|
|
|
serviceDisplayId?: string
|
2026-09-09 22:05:00 +08:00
|
|
|
|
activityId: string;
|
|
|
|
|
|
title: string;
|
|
|
|
|
|
coverUrl?: string;
|
|
|
|
|
|
startAt: number;
|
|
|
|
|
|
endAt: number;
|
|
|
|
|
|
location: string;
|
|
|
|
|
|
organizer: string; // 主办单位
|
|
|
|
|
|
suitableFor?: string; // 适合人群
|
|
|
|
|
|
intro: string;
|
|
|
|
|
|
schedule?: string;
|
|
|
|
|
|
notes?: string;
|
|
|
|
|
|
feeType: 'free' | 'paid'; // 前台重点突出 公益免费
|
|
|
|
|
|
status: ActivityStatus;
|
|
|
|
|
|
capacity?: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============ MatchmakerService(规范 §48-50) ============
|
|
|
|
|
|
export type MatchmakerServiceStatus =
|
|
|
|
|
|
| 'submitted'
|
|
|
|
|
|
| 'assigned'
|
|
|
|
|
|
| 'in_service'
|
|
|
|
|
|
| 'waiting_user'
|
|
|
|
|
|
| 'completed'
|
|
|
|
|
|
| 'cancelled';
|
|
|
|
|
|
|
|
|
|
|
|
export type MatchmakerRecommendationStatus =
|
|
|
|
|
|
| 'pending_view'
|
|
|
|
|
|
| 'viewed'
|
|
|
|
|
|
| 'liked'
|
|
|
|
|
|
| 'passed'
|
|
|
|
|
|
| 'mutual_match'
|
|
|
|
|
|
| 'expired';
|
|
|
|
|
|
|
|
|
|
|
|
export interface MatchmakerService {
|
2026-10-15 09:47:31 +08:00
|
|
|
|
displayId?: string
|
|
|
|
|
|
displayNumber?: string
|
|
|
|
|
|
userDisplayNumber?: string
|
|
|
|
|
|
serviceDisplayId?: string
|
2026-09-09 22:05:00 +08:00
|
|
|
|
serviceId: string;
|
|
|
|
|
|
userId: string;
|
|
|
|
|
|
matchmakerId?: string;
|
|
|
|
|
|
matchmakerName?: string;
|
|
|
|
|
|
matchmakerOrg?: string; // 所属公益机构
|
|
|
|
|
|
status: MatchmakerServiceStatus;
|
|
|
|
|
|
requirement: string;
|
|
|
|
|
|
lastFollowUpAt?: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface MatchmakerRecommendation extends User {
|
|
|
|
|
|
serviceId: string;
|
|
|
|
|
|
recommendationStatus: MatchmakerRecommendationStatus;
|
|
|
|
|
|
recommendReason: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============ Report(规范 §41-42) ============
|
|
|
|
|
|
export type ReportType = 'fraud' | 'harassment' | 'ad' | 'inappropriate' | 'other';
|
|
|
|
|
|
export type RiskLevel = 'normal' | 'attention' | 'high' | 'banned';
|
|
|
|
|
|
|
|
|
|
|
|
export interface Report {
|
|
|
|
|
|
reportId: string;
|
|
|
|
|
|
targetUserId: string;
|
|
|
|
|
|
type: ReportType;
|
|
|
|
|
|
reason: string;
|
|
|
|
|
|
evidencePhotoUrls?: string[];
|
|
|
|
|
|
submittedAt: number;
|
|
|
|
|
|
status: 'pending' | 'processing' | 'resolved';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============ 全局用户状态聚合(规范 §6, §141) ============
|
|
|
|
|
|
export interface UserState {
|
|
|
|
|
|
isLoggedIn: boolean;
|
|
|
|
|
|
hasPhone: boolean;
|
|
|
|
|
|
isRealNameVerified: boolean;
|
|
|
|
|
|
profileCompletionStatus: 'not_started' | 'in_progress' | 'completed';
|
|
|
|
|
|
profileReviewStatus: 'not_submitted' | 'pending' | 'approved' | 'need_edit' | 'rejected';
|
|
|
|
|
|
accountStatus: 'normal' | 'reviewing_risk' | 'limited' | 'suspended' | 'banned' | 'closed';
|
|
|
|
|
|
relationshipStatus: 'searching' | 'getting_to_know' | 'paused' | 'matched_successfully' | 'service_exited';
|
|
|
|
|
|
recommendationEnabled: boolean;
|
|
|
|
|
|
searchVisibility: boolean;
|
|
|
|
|
|
matchmakerEnabled: boolean;
|
|
|
|
|
|
activityRecommendationEnabled: boolean;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============ 隐私设置(规范 §59) ============
|
|
|
|
|
|
export interface PrivacySettings {
|
|
|
|
|
|
visibleInRecommendations: boolean;
|
|
|
|
|
|
visibleInSearch: boolean;
|
|
|
|
|
|
showOccupation: boolean;
|
|
|
|
|
|
showLifestylePhotos: boolean;
|
|
|
|
|
|
receiveActivityRecommendations: boolean;
|
|
|
|
|
|
acceptMatchmakerRecommendations: boolean;
|
|
|
|
|
|
}
|