import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; import { catchError, map, Observable, of } from 'rxjs'; // 定义模板类型枚举 export enum TemplateType { OTHER = 0, NEW_USER_WELCOM = 1, // 欢迎与引导 ENCOURAGE_AND_REWARD = 2, // 鼓励与奖励 DAILY_REWARD_REMINDER = 3, // 每日奖励提醒 PERSONALIZED_RECOMMENDATION = 4, // 个性化推荐 NEW_CONTENT_REMINDER = 5, // 新画作提醒 HOT_CONTENT_RECOMMENDATION = 6, // 热门画作推荐 LIMITED_TIME_EVENT_REMINDER = 7, // 限时活动提醒 HOLIDAY_CELEBRATION = 8, // 节日/特殊日庆贺 COMPLETION_ENCOURAGEMENT = 9, // 完成度鼓励 SOCIAL_SHARING_ENCOURAGEMENT = 10, // 社交分享鼓励 UNACTIVE_USER_RECALL = 11, // 长时间不活跃用户召回 NEW_FEATURE_INTRODUCTION = 12, // 新功能介绍 CHALLENGE_TASK_REMINDER = 13, // 挑战任务提醒 } // 定义模板类型映射 export const TEMPLATE_TYPE_MAP: Record = { [TemplateType.OTHER]: '其他', [TemplateType.NEW_USER_WELCOM]: '欢迎与引导', [TemplateType.ENCOURAGE_AND_REWARD]: '鼓励与奖励', [TemplateType.DAILY_REWARD_REMINDER]: '每日奖励提醒', [TemplateType.PERSONALIZED_RECOMMENDATION]: '个性化推荐', [TemplateType.NEW_CONTENT_REMINDER]: '新画作提醒', [TemplateType.HOT_CONTENT_RECOMMENDATION]: '热门画作推荐', [TemplateType.LIMITED_TIME_EVENT_REMINDER]: '限时活动提醒', [TemplateType.HOLIDAY_CELEBRATION]: '假日/节日主题', [TemplateType.COMPLETION_ENCOURAGEMENT]: '完成度鼓励', [TemplateType.SOCIAL_SHARING_ENCOURAGEMENT]: '社交分享鼓励', [TemplateType.UNACTIVE_USER_RECALL]: '长时间不活跃用户召回', [TemplateType.NEW_FEATURE_INTRODUCTION]: '新功能介绍', [TemplateType.CHALLENGE_TASK_REMINDER]: '挑战任务提醒', }; // 新增 ActionType 枚举和映射 export enum ActionType { GO_APP = 'go/app', GO_ART = 'go/art', GO_ALBUM = 'go/album', GAIN_HINT = 'gain/hint', KEEP_GOING = 'keepgoing', } export const ACTION_TYPE_MAP: Record = { [ActionType.GO_APP]: '打开应用', [ActionType.GO_ART]: '打开填色作品', [ActionType.GO_ALBUM]: '打开专辑', [ActionType.GAIN_HINT]: '获取提示奖励', [ActionType.KEEP_GOING]: '继续完成作品', }; export const ACTION_PARAM_PLACEHOLDERS: Record = { [ActionType.GO_APP]: '', [ActionType.GO_ART]: '输入作品ID', [ActionType.GO_ALBUM]: '输入专辑ID', [ActionType.GAIN_HINT]: '输入提示数量', [ActionType.KEEP_GOING]: '输入作品ID', }; // 定义消息模板接口 export interface IMessageTemplate { _id: string; templateName: string; templateType: TemplateType; description: string; messageTitle: { [key: string]: string }; messageContent: { [key: string]: string }; image?: string; bigger?: boolean; action?: ActionType; param?: string; extend?: string; createdAt: Date; updatedAt: Date; } // 定义创建/更新模板的数据结构 export interface MessageTemplateData { templateName: string; templateType: TemplateType; descritpion: string; messageTitle: { [key: string]: string }; messageContent: { [key: string]: string }; image?: string; bigger?: boolean; action?: string; param?: string; extend?: string; } // 定义目标用户筛选项相关接口 export interface FilterCondition { field: string; operator: string; value: any; } export interface FieldConfig { value: string; label: string; type: 'country' | 'date' | 'number' | 'number_days' | 'text'; } export interface OperatorOption { value: string; label: string; valueType: 'single' | 'multiple' | 'range'; } // 更新模板信息接口 export interface IMessageTemplateInfo { _id: string; templateName: string; templateType?: TemplateType; description?: string; createdAt?: Date; updatedAt?: Date; } // 策略接口保持不变 export interface IMessageStrategy { _id: string; name: string; description?: string; templates: IMessageTemplateInfo[]; // 使用 IMessageTemplateInfo 类型 createdAt: Date; updatedAt: Date; } // 创建策略数据接口保持不变 export interface MessageStrategyData { name: string; description?: string; templates: string[]; // 创建时只需要模板ID数组 } // 定义消息活动接口 export interface IMessageActivity { _id: string; name: string; templateId: string; image?: string; bigger: boolean; action?: ActionType; description: string; param?: string; extend?: string; strategy: number; filter?: FilterCondition[]; scheduleAt?: string; everyday: boolean; status: number; createdAt: Date; updatedAt: Date; } // 定义创建/更新消息活动的数据结构 export interface MessageActivityData { name: string; templateId: string; image?: string; bigger: boolean; action?: string; param?: string; extend?: string; strategy: number; filter?: FilterCondition[]; scheduleAt?: string; everyday: boolean; status: number; description: string; } // 定义消息记录接口 export interface IMessageRecord { _id: string; uid: string; cc?: string; activityId?: string; activityName?: string; templateId?: string; templateName?: string; strategyId?: string; strategyName?: string; title: string; content: string; image?: string; bigger: boolean; action?: string; param?: string; extend?: string; status: number; inforeground?: boolean; errno?: string; fcmReceipt?: string; plannedSendAt?: Date; actualSendAt?: Date; deliveredAt?: Date; openedAt?: Date; createdAt: Date; updatedAt: Date; } // 定义分页响应接口 export interface IMessageRecordPaginationResponse { success: boolean; data: IMessageRecord[]; pagination: { total: number; page: number; limit: number; totalPages: number; }; } // 定义删除操作的响应结构 interface DeleteResponse { deletedCount?: number; } @Injectable({ providedIn: 'root', }) export class MessageService { private templatesApiUrl = '/api/message-template'; private activitiesApiUrl = '/api/message-activity'; private activityListApiUri = '/api/message-activities'; private recordsApiUrl = '/api/message-record'; private recordsListApiUrl = '/api/message-records'; private strategiesApiUrl = '/api/message-strategy'; private httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }), }; constructor(private http: HttpClient) {} /** * 获取所有客户端行为选项 */ getActionOptions(): { value: ActionType; label: string }[] { return Object.entries(ACTION_TYPE_MAP).map(([value, label]) => ({ value: value as ActionType, label, })); } /** * 获取行为参数占位符 */ getActionParamPlaceholder(action: ActionType): string { return ACTION_PARAM_PLACEHOLDERS[action] || '输入参数'; } /** * 获取所有模板类型选项 */ getTemplateTypeOptions(): { value: TemplateType; label: string }[] { return Object.entries(TEMPLATE_TYPE_MAP).map(([value, label]) => ({ value: parseInt(value, 10) as TemplateType, label, })); } /** * 获取模板类型映射 */ getTemplateTypeMap(): Record { return TEMPLATE_TYPE_MAP; } /** * 模板管理 API */ createTemplate( templateData: MessageTemplateData ): Observable { return this.http.post( this.templatesApiUrl, templateData, this.httpOptions ); } getTemplateById(templateId: string): Observable { return this.http.get( `${this.templatesApiUrl}/${templateId}`, this.httpOptions ); } getTemplateByName(templateName: string): Observable { return this.http.get( `${this.templatesApiUrl}/name/${templateName}`, this.httpOptions ); } getAllTemplates(): Observable { return this.http.get( this.templatesApiUrl, this.httpOptions ); } updateTemplate( templateId: string, updateData: Partial ): Observable { return this.http.put( `${this.templatesApiUrl}/${templateId}`, updateData, this.httpOptions ); } deleteTemplate(templateId: string): Observable { return this.http.delete( `${this.templatesApiUrl}/${templateId}`, this.httpOptions ); } getAllStrategies(): Observable { return this.http .get('/api/message-strategies', this.httpOptions) .pipe( map((response) => (Array.isArray(response) ? response : [])), catchError((err) => { console.error('获取策略失败:', err); return of([]); }) ); } getStrategyById(id: string): Observable { return this.http.get( `${this.strategiesApiUrl}/${id}`, this.httpOptions ); } createStrategy( strategyData: MessageStrategyData ): Observable { return this.http.post( this.strategiesApiUrl, strategyData, this.httpOptions ); } updateStrategy( id: string, updateData: Partial ): Observable { return this.http.put( `${this.strategiesApiUrl}/${id}`, updateData, this.httpOptions ); } deleteStrategy(id: string): Observable<{ deletedCount?: number }> { return this.http.delete<{ deletedCount?: number }>( `${this.strategiesApiUrl}/${id}`, this.httpOptions ); } /** * 活动管理 API */ getAllActivities(): Observable { return this.http.get( this.activityListApiUri, this.httpOptions ); } getActivityById(activityId: string): Observable { return this.http.get( `${this.activitiesApiUrl}/${activityId}`, this.httpOptions ); } createActivity( activityData: MessageActivityData ): Observable { return this.http.post( this.activitiesApiUrl, activityData, this.httpOptions ); } updateActivity( id: string, updateData: Partial ): Observable { return this.http.put( `${this.activitiesApiUrl}/${id}`, updateData, this.httpOptions ); } deleteActivity(id: string): Observable { return this.http.delete( `${this.activitiesApiUrl}/${id}`, this.httpOptions ); } updateActivityStatus( id: string, status: number ): Observable { return this.http.put( `${this.activitiesApiUrl}/${id}/status`, { status }, this.httpOptions ); } /** * 语言支持相关 */ getSupportedLanguages(): { code: string; name: string }[] { return [ { code: 'en', name: 'English' }, { code: 'zh-cn', name: '简体中文' }, { code: 'zh-tw', name: '繁體中文' }, { code: 'es', name: 'Español' }, { code: 'fr', name: 'Français' }, { code: 'de', name: 'Deutsch' }, { code: 'ja', name: '日本語' }, { code: 'ko', name: '한국어' }, { code: 'ru', name: 'Русский' }, { code: 'pt', name: 'Português' }, ]; } getLanguageName(code: string): string { const lang = this.getSupportedLanguages().find((l) => l.code === code); return lang ? lang.name : code; } /** * 目标用户筛选相关 */ countTargetUsers(filters: FilterCondition[]): Observable { return this.http.post( `/api/users/count`, { filters }, this.httpOptions ); } /** * 模板内容验证 */ validateTemplateContent( content: string ): Observable<{ valid: boolean; message?: string }> { return this.http.post<{ valid: boolean; message?: string }>( `${this.templatesApiUrl}/validate`, { content }, this.httpOptions ); } /** * 模板名称可用性检查 */ checkTemplateNameAvailable(name: string): Observable<{ available: boolean }> { return this.http.post<{ available: boolean }>( `${this.templatesApiUrl}/check-name`, { name }, this.httpOptions ); } /** * 获取模板默认内容 */ getDefaultTemplateContent( language: string ): Observable<{ title: string; content: string }> { return this.http.get<{ title: string; content: string }>( `${this.templatesApiUrl}/default-content/${language}`, this.httpOptions ); } /** * 消息记录管理 API */ createRecord( recordData: Partial ): Observable { return this.http.post( this.recordsApiUrl, recordData, this.httpOptions ); } getPaginatedRecords(params: { page?: number; limit?: number; uid?: string; activityId?: string; status?: number; startDate?: string; endDate?: string; }): Observable { let httpParams = new HttpParams(); for (const key in params) { if (params.hasOwnProperty(key) && params[key as keyof typeof params]) { httpParams = httpParams.append( key, String(params[key as keyof typeof params]) ); } } return this.http.get( this.recordsListApiUrl, { ...this.httpOptions, params: httpParams, } ); } getRecordById(recordId: string): Observable { return this.http.get( `${this.recordsApiUrl}/${recordId}`, this.httpOptions ); } updateRecord( recordId: string, updateData: Partial ): Observable { return this.http.put( `${this.recordsApiUrl}/${recordId}`, updateData, this.httpOptions ); } }