@quantabit/journey-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1021 @@
1
+ import { BaseApiClient } from '@quantabit/sdk-config';
2
+ import React, { useState, useCallback, useEffect } from 'react';
3
+
4
+ /**
5
+ * Journey SDK - API 客户端
6
+ * 用户旅程分析系统后端接口封装
7
+ *
8
+ * 使用 BaseApiClient 基类简化代码
9
+ */
10
+
11
+
12
+ /**
13
+ * 用户旅程 API 客户端
14
+ */
15
+ class JourneyApiClient extends BaseApiClient {
16
+ constructor(config = {}) {
17
+ super('/journey', config);
18
+ }
19
+
20
+ // ============ 旅程定义 ============
21
+
22
+ /**
23
+ * 获取旅程列表
24
+ * @param {Object} params - 查询参数
25
+ */
26
+ async getJourneys(params = {}) {
27
+ return this.get('/list', params);
28
+ }
29
+
30
+ /**
31
+ * 获取旅程详情
32
+ * @param {string} journeyId - 旅程 ID
33
+ */
34
+ async getJourney(journeyId) {
35
+ return this.get(`/${journeyId}`);
36
+ }
37
+
38
+ /**
39
+ * 创建旅程(管理员)
40
+ * @param {Object} data - 旅程数据
41
+ */
42
+ async createJourney(data) {
43
+ return this.post('/', data);
44
+ }
45
+
46
+ /**
47
+ * 更新旅程(管理员)
48
+ * @param {string} journeyId - 旅程 ID
49
+ * @param {Object} updates - 更新数据
50
+ */
51
+ async updateJourney(journeyId, updates) {
52
+ return this.put(`/${journeyId}`, updates);
53
+ }
54
+
55
+ /**
56
+ * 删除旅程(管理员)
57
+ * @param {string} journeyId - 旅程 ID
58
+ */
59
+ async deleteJourney(journeyId) {
60
+ return this.delete(`/${journeyId}`);
61
+ }
62
+
63
+ // ============ 旅程分析 ============
64
+
65
+ /**
66
+ * 获取旅程分析数据
67
+ * @param {string} journeyId - 旅程 ID
68
+ * @param {Object} params - 分析参数
69
+ */
70
+ async analyzeJourney(journeyId, params = {}) {
71
+ return this.post(`/${journeyId}/analyze`, params);
72
+ }
73
+
74
+ /**
75
+ * 获取步骤转化率
76
+ * @param {string} journeyId - 旅程 ID
77
+ */
78
+ async getStepConversion(journeyId) {
79
+ return this.get(`/${journeyId}/conversion`);
80
+ }
81
+
82
+ /**
83
+ * 获取用户掉落点
84
+ * @param {string} journeyId - 旅程 ID
85
+ * @param {Object} params - 查询参数
86
+ */
87
+ async getDropoffPoints(journeyId, params = {}) {
88
+ return this.get(`/${journeyId}/dropoff`, params);
89
+ }
90
+
91
+ /**
92
+ * 获取路径分布
93
+ * @param {string} journeyId - 旅程 ID
94
+ */
95
+ async getPathDistribution(journeyId) {
96
+ return this.get(`/${journeyId}/paths`);
97
+ }
98
+
99
+ // ============ 用户旅程 ============
100
+
101
+ /**
102
+ * 获取用户的旅程记录
103
+ * @param {string} userId - 用户 ID
104
+ * @param {Object} params - 查询参数
105
+ */
106
+ async getUserJourneys(userId, params = {}) {
107
+ return this.get(`/users/${userId}`, params);
108
+ }
109
+
110
+ /**
111
+ * 获取我的旅程记录
112
+ * @param {Object} params - 查询参数
113
+ */
114
+ async getMyJourneys(params = {}) {
115
+ return this.get('/my', params);
116
+ }
117
+
118
+ /**
119
+ * 记录旅程事件
120
+ * @param {string} journeyId - 旅程 ID
121
+ * @param {string} stepId - 步骤 ID
122
+ * @param {Object} data - 事件数据
123
+ */
124
+ async trackStep(journeyId, stepId, data = {}) {
125
+ return this.post(`/${journeyId}/track`, {
126
+ step_id: stepId,
127
+ ...data
128
+ });
129
+ }
130
+
131
+ // ============ 触点管理 ============
132
+
133
+ /**
134
+ * 获取触点列表
135
+ * @param {string} journeyId - 旅程 ID
136
+ */
137
+ async getTouchpoints(journeyId) {
138
+ return this.get(`/${journeyId}/touchpoints`);
139
+ }
140
+
141
+ /**
142
+ * 添加触点(管理员)
143
+ * @param {string} journeyId - 旅程 ID
144
+ * @param {Object} touchpoint - 触点数据
145
+ */
146
+ async addTouchpoint(journeyId, touchpoint) {
147
+ return this.post(`/${journeyId}/touchpoints`, touchpoint);
148
+ }
149
+
150
+ /**
151
+ * 更新触点(管理员)
152
+ * @param {string} journeyId - 旅程 ID
153
+ * @param {string} touchpointId - 触点 ID
154
+ * @param {Object} updates - 更新数据
155
+ */
156
+ async updateTouchpoint(journeyId, touchpointId, updates) {
157
+ return this.put(`/${journeyId}/touchpoints/${touchpointId}`, updates);
158
+ }
159
+
160
+ // ============ 统计报表 ============
161
+
162
+ /**
163
+ * 获取旅程统计
164
+ * @param {string} journeyId - 旅程 ID
165
+ * @param {Object} params - 统计参数
166
+ */
167
+ async getStats(journeyId, params = {}) {
168
+ return this.get(`/${journeyId}/stats`, params);
169
+ }
170
+
171
+ /**
172
+ * 获取趋势数据
173
+ * @param {string} journeyId - 旅程 ID
174
+ * @param {Object} params - 查询参数
175
+ */
176
+ async getTrend(journeyId, params = {}) {
177
+ return this.get(`/${journeyId}/trend`, params);
178
+ }
179
+
180
+ /**
181
+ * 导出报表
182
+ * @param {string} journeyId - 旅程 ID
183
+ * @param {Object} options - 导出选项
184
+ */
185
+ async exportReport(journeyId, options = {}) {
186
+ return this.post(`/${journeyId}/export`, options);
187
+ }
188
+
189
+ /**
190
+ * 启动旅程
191
+ * @param {string} journeyId - 旅程 ID
192
+ */
193
+ async startJourney(journeyId) {
194
+ return this.post(`/${journeyId}/start`);
195
+ }
196
+
197
+ /**
198
+ * 暂停旅程
199
+ * @param {string} journeyId - 旅程 ID
200
+ */
201
+ async pauseJourney(journeyId) {
202
+ return this.post(`/${journeyId}/pause`);
203
+ }
204
+
205
+ /**
206
+ * 停止旅程
207
+ * @param {string} journeyId - 旅程 ID
208
+ */
209
+ async stopJourney(journeyId) {
210
+ return this.post(`/${journeyId}/stop`);
211
+ }
212
+
213
+ /**
214
+ * 获取旅程统计 (快捷方法包装)
215
+ * @param {string} journeyId - 旅程 ID
216
+ * @param {Object} params - 统计参数
217
+ */
218
+ async getJourneyStats(journeyId, params = {}) {
219
+ return this.getStats(journeyId, params);
220
+ }
221
+
222
+ /**
223
+ * 获取参与旅程的用户列表
224
+ * @param {string} journeyId - 旅程 ID
225
+ * @param {Object} params - 查询参数
226
+ */
227
+ async getJourneyUsers(journeyId, params = {}) {
228
+ return this.get(`/${journeyId}/users`, params);
229
+ }
230
+ }
231
+
232
+ // 创建默认实例
233
+ const journeyApi = new JourneyApiClient();
234
+
235
+ /**
236
+ * Journey SDK - 类型定义
237
+ */
238
+
239
+ // 旅程状态
240
+ const JourneyStatus = {
241
+ DRAFT: 'draft',
242
+ ACTIVE: 'active',
243
+ PAUSED: 'paused',
244
+ COMPLETED: 'completed',
245
+ ARCHIVED: 'archived'
246
+ };
247
+
248
+ // 触发类型
249
+ const TriggerType = {
250
+ EVENT: 'event',
251
+ // 事件触发
252
+ SEGMENT: 'segment',
253
+ // 分群进入
254
+ SCHEDULE: 'schedule',
255
+ // 定时触发
256
+ API: 'api' // API调用
257
+ };
258
+
259
+ // 动作类型
260
+ const ActionType = {
261
+ SEND_EMAIL: 'send_email',
262
+ SEND_SMS: 'send_sms',
263
+ SEND_PUSH: 'send_push',
264
+ SEND_IN_APP: 'send_in_app',
265
+ WEBHOOK: 'webhook',
266
+ WAIT: 'wait',
267
+ CONDITION: 'condition',
268
+ SPLIT: 'split',
269
+ UPDATE_PROFILE: 'update_profile',
270
+ ADD_TAG: 'add_tag'
271
+ };
272
+
273
+ // 等待类型
274
+ const WaitType = {
275
+ DURATION: 'duration',
276
+ // 固定时长
277
+ UNTIL: 'until',
278
+ // 到指定时间
279
+ EVENT: 'event' // 等待事件
280
+ };
281
+
282
+ /**
283
+ * Journey SDK - 国际化
284
+ */
285
+
286
+ const SUPPORTED_LANGUAGES = ['en', 'zh', 'ja', 'ko'];
287
+ const messages = {
288
+ zh: {
289
+ // 旅程
290
+ journey: '用户旅程',
291
+ journeys: '旅程列表',
292
+ createJourney: '创建旅程',
293
+ myJourneys: '我的旅程',
294
+ // 状态
295
+ draft: '草稿',
296
+ active: '运行中',
297
+ paused: '已暂停',
298
+ completed: '已完成',
299
+ archived: '已归档',
300
+ // 触发器
301
+ trigger: '触发条件',
302
+ triggers: '触发器',
303
+ event: '事件触发',
304
+ schedule: '定时触发',
305
+ segment: '分群触发',
306
+ manual: '手动触发',
307
+ // 动作
308
+ action: '动作',
309
+ actions: '动作列表',
310
+ sendEmail: '发送邮件',
311
+ sendSMS: '发送短信',
312
+ sendPush: '发送推送',
313
+ sendNotification: '发送通知',
314
+ addTag: '添加标签',
315
+ removeTag: '移除标签',
316
+ updateProfile: '更新画像',
317
+ webhook: '调用Webhook',
318
+ // 等待
319
+ wait: '等待',
320
+ waitTime: '等待时间',
321
+ minutes: '分钟',
322
+ hours: '小时',
323
+ days: '天',
324
+ // 条件
325
+ condition: '条件',
326
+ ifThen: '如果...则...',
327
+ abTest: 'A/B测试',
328
+ // 统计
329
+ entered: '进入人数',
330
+ completed: '完成人数',
331
+ active: '活跃人数',
332
+ conversionRate: '转化率',
333
+ // 操作
334
+ start: '启动',
335
+ pause: '暂停',
336
+ resume: '继续',
337
+ stop: '停止',
338
+ duplicate: '复制',
339
+ delete: '删除'
340
+ },
341
+ ja: {
342
+ // 旅程
343
+ journey: 'ユーザージャーニー',
344
+ journeys: 'ジャーニーリスト',
345
+ createJourney: 'ジャーニー作成',
346
+ myJourneys: 'マイジャーニー',
347
+ // 状态
348
+ draft: '下書き',
349
+ active: '実行中',
350
+ paused: '一時停止中',
351
+ completed: '完了',
352
+ archived: 'アーカイブ済み',
353
+ // 触发器
354
+ trigger: 'トリガー条件',
355
+ triggers: 'トリガー',
356
+ event: 'イベントトリガー',
357
+ schedule: 'スケジュールトリガー',
358
+ segment: 'セグメントトリガー',
359
+ manual: '手動トリガー',
360
+ // 动作
361
+ action: 'アクション',
362
+ actions: 'アクションリスト',
363
+ sendEmail: 'メール送信',
364
+ sendSMS: 'SMS送信',
365
+ sendPush: 'プッシュ送信',
366
+ sendNotification: '通知送信',
367
+ addTag: 'タグ追加',
368
+ removeTag: 'タグ削除',
369
+ updateProfile: 'プロフィール更新',
370
+ webhook: 'Webhook呼び出し',
371
+ // 等待
372
+ wait: '待機',
373
+ waitTime: '待機時間',
374
+ minutes: '分',
375
+ hours: '時間',
376
+ days: '日',
377
+ // 条件
378
+ condition: '条件',
379
+ ifThen: 'もし...ならば...',
380
+ abTest: 'A/B测试',
381
+ // 统计
382
+ entered: '参加者数',
383
+ completed: '完了者数',
384
+ active: 'アクティブ数',
385
+ conversionRate: 'コンバージョン率',
386
+ // 操作
387
+ start: '起動',
388
+ pause: '一時停止',
389
+ resume: '再開',
390
+ stop: '停止',
391
+ duplicate: 'コピー',
392
+ delete: '削除'
393
+ },
394
+ ko: {
395
+ // 旅程
396
+ journey: '사용자 여정',
397
+ journeys: '여정 목록',
398
+ createJourney: '여정 만들기',
399
+ myJourneys: '내 여정',
400
+ // 状态
401
+ draft: '초안',
402
+ active: '실행 중',
403
+ paused: '일시 중지됨',
404
+ completed: '완료됨',
405
+ archived: '보관됨',
406
+ // 触发器
407
+ trigger: '트리거 조건',
408
+ triggers: '트리거',
409
+ event: '이벤트 트리거',
410
+ schedule: '예약 트리거',
411
+ segment: '세그먼트 트리거',
412
+ manual: '수동 트리거',
413
+ // 动作
414
+ action: '작업',
415
+ actions: '작업 목록',
416
+ sendEmail: '이메일 전송',
417
+ sendSMS: 'SMS 전송',
418
+ sendPush: '푸시 알림 전송',
419
+ sendNotification: '알림 전송',
420
+ addTag: '태그 추가',
421
+ removeTag: '태그 제거',
422
+ updateProfile: '프로필 업데이트',
423
+ webhook: 'Webhook 호출',
424
+ // 等待
425
+ wait: '대기',
426
+ waitTime: '대기 시간',
427
+ minutes: '분',
428
+ hours: '시간',
429
+ days: '일',
430
+ // 条件
431
+ condition: '조건',
432
+ ifThen: '만약...라면...',
433
+ abTest: 'A/B测试',
434
+ // 统计
435
+ entered: '참여자 수',
436
+ completed: '완료자 수',
437
+ active: '활성 사용자 수',
438
+ conversionRate: '전환율',
439
+ // 操作
440
+ start: '시작',
441
+ pause: '일시 정지',
442
+ resume: '계속',
443
+ stop: '중지',
444
+ duplicate: '복사',
445
+ delete: '삭제'
446
+ },
447
+ en: {
448
+ journey: 'Journey',
449
+ journeys: 'Journeys',
450
+ createJourney: 'Create Journey',
451
+ myJourneys: 'My Journeys',
452
+ draft: 'Draft',
453
+ active: 'Active',
454
+ paused: 'Paused',
455
+ completed: 'Completed',
456
+ archived: 'Archived',
457
+ trigger: 'Trigger',
458
+ triggers: 'Triggers',
459
+ event: 'Event',
460
+ schedule: 'Schedule',
461
+ segment: 'Segment',
462
+ manual: 'Manual',
463
+ action: 'Action',
464
+ actions: 'Actions',
465
+ sendEmail: 'Send Email',
466
+ sendSMS: 'Send SMS',
467
+ sendPush: 'Send Push',
468
+ sendNotification: 'Send Notification',
469
+ addTag: 'Add Tag',
470
+ removeTag: 'Remove Tag',
471
+ updateProfile: 'Update Profile',
472
+ webhook: 'Webhook',
473
+ wait: 'Wait',
474
+ waitTime: 'Wait Time',
475
+ minutes: 'minutes',
476
+ hours: 'hours',
477
+ days: 'days',
478
+ condition: 'Condition',
479
+ ifThen: 'If...Then...',
480
+ abTest: 'A/B Test',
481
+ entered: 'Entered',
482
+ completed: 'Completed',
483
+ active: 'Active',
484
+ conversionRate: 'Conversion Rate',
485
+ start: 'Start',
486
+ pause: 'Pause',
487
+ resume: 'Resume',
488
+ stop: 'Stop',
489
+ duplicate: 'Duplicate',
490
+ delete: 'Delete'
491
+ }
492
+ };
493
+ let currentLanguage = 'zh';
494
+ function setLanguage(lang) {
495
+ if (SUPPORTED_LANGUAGES.includes(lang)) currentLanguage = lang;
496
+ }
497
+ function getLanguage() {
498
+ return currentLanguage;
499
+ }
500
+ function t(key) {
501
+ return (messages[currentLanguage] || messages.en)[key] || key;
502
+ }
503
+
504
+ /**
505
+ * Journey SDK - React Hooks
506
+ */
507
+
508
+
509
+ /**
510
+ * useJourneys - 旅程列表Hook
511
+ */
512
+ function useJourneys(options = {}) {
513
+ const [journeys, setJourneys] = useState([]);
514
+ const [loading, setLoading] = useState(false);
515
+ const [page, setPage] = useState(1);
516
+ const [hasMore, setHasMore] = useState(true);
517
+ const [total, setTotal] = useState(0);
518
+ const loadJourneys = useCallback(async (reset = false) => {
519
+ const currentPage = reset ? 1 : page;
520
+ setLoading(true);
521
+ try {
522
+ const result = await journeyApi.getJourneys({
523
+ ...options,
524
+ page: currentPage,
525
+ pageSize: 20
526
+ });
527
+ const newJourneys = result.journeys || [];
528
+ setJourneys(prev => reset ? newJourneys : [...prev, ...newJourneys]);
529
+ setTotal(result.total || 0);
530
+ setHasMore(newJourneys.length >= 20);
531
+ if (reset) setPage(1);
532
+ } finally {
533
+ setLoading(false);
534
+ }
535
+ }, [options.status, page]);
536
+ const loadMore = useCallback(() => {
537
+ if (hasMore && !loading) {
538
+ setPage(p => p + 1);
539
+ }
540
+ }, [hasMore, loading]);
541
+ useEffect(() => {
542
+ loadJourneys(true);
543
+ }, [options.status]);
544
+ useEffect(() => {
545
+ if (page > 1) loadJourneys();
546
+ }, [page]);
547
+ return {
548
+ journeys,
549
+ loading,
550
+ total,
551
+ hasMore,
552
+ loadMore,
553
+ refresh: () => loadJourneys(true)
554
+ };
555
+ }
556
+
557
+ /**
558
+ * useJourney - 单个旅程Hook
559
+ */
560
+ function useJourney(journeyId) {
561
+ const [journey, setJourney] = useState(null);
562
+ const [stats, setStats] = useState(null);
563
+ const [loading, setLoading] = useState(false);
564
+ const [saving, setSaving] = useState(false);
565
+ const loadJourney = useCallback(async () => {
566
+ if (!journeyId) return;
567
+ setLoading(true);
568
+ try {
569
+ const [journeyData, statsData] = await Promise.all([journeyApi.getJourney(journeyId), journeyApi.getJourneyStats(journeyId)]);
570
+ setJourney(journeyData);
571
+ setStats(statsData);
572
+ } finally {
573
+ setLoading(false);
574
+ }
575
+ }, [journeyId]);
576
+
577
+ // 保存旅程
578
+ const saveJourney = useCallback(async data => {
579
+ setSaving(true);
580
+ try {
581
+ const result = journeyId ? await journeyApi.updateJourney(journeyId, data) : await journeyApi.createJourney(data);
582
+ setJourney(result);
583
+ return result;
584
+ } finally {
585
+ setSaving(false);
586
+ }
587
+ }, [journeyId]);
588
+
589
+ // 启动旅程
590
+ const startJourney = useCallback(async () => {
591
+ if (!journeyId) return false;
592
+ try {
593
+ await journeyApi.startJourney(journeyId);
594
+ loadJourney();
595
+ return true;
596
+ } catch (e) {
597
+ return false;
598
+ }
599
+ }, [journeyId, loadJourney]);
600
+
601
+ // 暂停旅程
602
+ const pauseJourney = useCallback(async () => {
603
+ if (!journeyId) return false;
604
+ try {
605
+ await journeyApi.pauseJourney(journeyId);
606
+ loadJourney();
607
+ return true;
608
+ } catch (e) {
609
+ return false;
610
+ }
611
+ }, [journeyId, loadJourney]);
612
+
613
+ // 停止旅程
614
+ const stopJourney = useCallback(async () => {
615
+ if (!journeyId) return false;
616
+ try {
617
+ await journeyApi.stopJourney(journeyId);
618
+ loadJourney();
619
+ return true;
620
+ } catch (e) {
621
+ return false;
622
+ }
623
+ }, [journeyId, loadJourney]);
624
+ useEffect(() => {
625
+ loadJourney();
626
+ }, [journeyId]);
627
+ return {
628
+ journey,
629
+ stats,
630
+ loading,
631
+ saving,
632
+ saveJourney,
633
+ startJourney,
634
+ pauseJourney,
635
+ stopJourney,
636
+ refresh: loadJourney
637
+ };
638
+ }
639
+
640
+ /**
641
+ * useJourneyBuilder - 旅程构建器Hook
642
+ */
643
+ function useJourneyBuilder(initialData = null) {
644
+ const [nodes, setNodes] = useState(initialData?.nodes || []);
645
+ const [edges, setEdges] = useState(initialData?.edges || []);
646
+ const [selectedNode, setSelectedNode] = useState(null);
647
+
648
+ // 添加节点
649
+ const addNode = useCallback((type, data = {}) => {
650
+ const newNode = {
651
+ id: `node_${Date.now()}`,
652
+ type,
653
+ data,
654
+ position: {
655
+ x: 100,
656
+ y: nodes.length * 150
657
+ }
658
+ };
659
+ setNodes(prev => [...prev, newNode]);
660
+ return newNode;
661
+ }, [nodes.length]);
662
+
663
+ // 更新节点
664
+ const updateNode = useCallback((nodeId, data) => {
665
+ setNodes(prev => prev.map(node => node.id === nodeId ? {
666
+ ...node,
667
+ data: {
668
+ ...node.data,
669
+ ...data
670
+ }
671
+ } : node));
672
+ }, []);
673
+
674
+ // 删除节点
675
+ const deleteNode = useCallback(nodeId => {
676
+ setNodes(prev => prev.filter(node => node.id !== nodeId));
677
+ setEdges(prev => prev.filter(edge => edge.source !== nodeId && edge.target !== nodeId));
678
+ if (selectedNode === nodeId) setSelectedNode(null);
679
+ }, [selectedNode]);
680
+
681
+ // 添加连线
682
+ const addEdge = useCallback((source, target, label) => {
683
+ const newEdge = {
684
+ id: `edge_${Date.now()}`,
685
+ source,
686
+ target,
687
+ label
688
+ };
689
+ setEdges(prev => [...prev, newEdge]);
690
+ return newEdge;
691
+ }, []);
692
+
693
+ // 删除连线
694
+ const deleteEdge = useCallback(edgeId => {
695
+ setEdges(prev => prev.filter(edge => edge.id !== edgeId));
696
+ }, []);
697
+
698
+ // 导出数据
699
+ const exportData = useCallback(() => {
700
+ return {
701
+ nodes,
702
+ edges
703
+ };
704
+ }, [nodes, edges]);
705
+
706
+ // 导入数据
707
+ const importData = useCallback(data => {
708
+ setNodes(data.nodes || []);
709
+ setEdges(data.edges || []);
710
+ setSelectedNode(null);
711
+ }, []);
712
+
713
+ // 清空画布
714
+ const clear = useCallback(() => {
715
+ setNodes([]);
716
+ setEdges([]);
717
+ setSelectedNode(null);
718
+ }, []);
719
+ return {
720
+ nodes,
721
+ edges,
722
+ selectedNode,
723
+ setSelectedNode,
724
+ addNode,
725
+ updateNode,
726
+ deleteNode,
727
+ addEdge,
728
+ deleteEdge,
729
+ exportData,
730
+ importData,
731
+ clear
732
+ };
733
+ }
734
+
735
+ /**
736
+ * Journey SDK - 旅程组件
737
+ */
738
+
739
+
740
+ /**
741
+ * 状态颜色映射
742
+ */
743
+ const statusColors = {
744
+ [JourneyStatus.DRAFT]: '#6B7280',
745
+ [JourneyStatus.ACTIVE]: '#10B981',
746
+ [JourneyStatus.PAUSED]: '#F59E0B',
747
+ [JourneyStatus.COMPLETED]: '#3B82F6',
748
+ [JourneyStatus.ARCHIVED]: '#9CA3AF'
749
+ };
750
+
751
+ /**
752
+ * 动作图标映射
753
+ */
754
+ const actionIcons = {
755
+ [ActionType.SEND_EMAIL]: '📧',
756
+ [ActionType.SEND_SMS]: '📱',
757
+ [ActionType.SEND_PUSH]: '🔔',
758
+ [ActionType.SEND_NOTIFICATION]: '💬',
759
+ [ActionType.ADD_TAG]: '🏷️',
760
+ [ActionType.REMOVE_TAG]: '🚫',
761
+ [ActionType.UPDATE_PROFILE]: '👤',
762
+ [ActionType.WEBHOOK]: '🔗',
763
+ [ActionType.WAIT]: '⏱️',
764
+ [ActionType.CONDITION]: '🔀'
765
+ };
766
+
767
+ /**
768
+ * JourneyCard 组件
769
+ */
770
+ function JourneyCard({
771
+ journey,
772
+ onClick,
773
+ onStart,
774
+ onPause,
775
+ onStop,
776
+ showActions = true
777
+ }) {
778
+ const {
779
+ id,
780
+ name,
781
+ description,
782
+ status,
783
+ stats
784
+ } = journey;
785
+ const statusColor = statusColors[status] || '#6B7280';
786
+ const isActive = status === JourneyStatus.ACTIVE;
787
+ const isDraft = status === JourneyStatus.DRAFT;
788
+ const isPaused = status === JourneyStatus.PAUSED;
789
+ return /*#__PURE__*/React.createElement("div", {
790
+ className: "eco-journey-card",
791
+ onClick: () => onClick?.(journey)
792
+ }, /*#__PURE__*/React.createElement("div", {
793
+ className: "eco-journey-card-header"
794
+ }, /*#__PURE__*/React.createElement("h4", {
795
+ className: "eco-journey-card-title"
796
+ }, name), /*#__PURE__*/React.createElement("span", {
797
+ className: "eco-journey-status",
798
+ style: {
799
+ backgroundColor: `${statusColor}20`,
800
+ color: statusColor
801
+ }
802
+ }, t(status))), description && /*#__PURE__*/React.createElement("p", {
803
+ className: "eco-journey-card-desc"
804
+ }, description), stats && /*#__PURE__*/React.createElement("div", {
805
+ className: "eco-journey-stats"
806
+ }, /*#__PURE__*/React.createElement("div", {
807
+ className: "eco-journey-stat"
808
+ }, /*#__PURE__*/React.createElement("span", {
809
+ className: "eco-journey-stat-value"
810
+ }, stats.entered || 0), /*#__PURE__*/React.createElement("span", {
811
+ className: "eco-journey-stat-label"
812
+ }, t('entered'))), /*#__PURE__*/React.createElement("div", {
813
+ className: "eco-journey-stat"
814
+ }, /*#__PURE__*/React.createElement("span", {
815
+ className: "eco-journey-stat-value"
816
+ }, stats.active || 0), /*#__PURE__*/React.createElement("span", {
817
+ className: "eco-journey-stat-label"
818
+ }, t('active'))), /*#__PURE__*/React.createElement("div", {
819
+ className: "eco-journey-stat"
820
+ }, /*#__PURE__*/React.createElement("span", {
821
+ className: "eco-journey-stat-value"
822
+ }, stats.completed || 0), /*#__PURE__*/React.createElement("span", {
823
+ className: "eco-journey-stat-label"
824
+ }, t('completed'))), /*#__PURE__*/React.createElement("div", {
825
+ className: "eco-journey-stat"
826
+ }, /*#__PURE__*/React.createElement("span", {
827
+ className: "eco-journey-stat-value"
828
+ }, ((stats.conversion_rate || 0) * 100).toFixed(1), "%"), /*#__PURE__*/React.createElement("span", {
829
+ className: "eco-journey-stat-label"
830
+ }, t('conversionRate')))), showActions && /*#__PURE__*/React.createElement("div", {
831
+ className: "eco-journey-actions",
832
+ onClick: e => e.stopPropagation()
833
+ }, isDraft && /*#__PURE__*/React.createElement("button", {
834
+ className: "eco-journey-btn start",
835
+ onClick: () => onStart?.(id)
836
+ }, t('start')), isActive && /*#__PURE__*/React.createElement("button", {
837
+ className: "eco-journey-btn pause",
838
+ onClick: () => onPause?.(id)
839
+ }, t('pause')), isPaused && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("button", {
840
+ className: "eco-journey-btn resume",
841
+ onClick: () => onStart?.(id)
842
+ }, t('resume')), /*#__PURE__*/React.createElement("button", {
843
+ className: "eco-journey-btn stop",
844
+ onClick: () => onStop?.(id)
845
+ }, t('stop')))));
846
+ }
847
+
848
+ /**
849
+ * JourneyNode 组件 - 单个节点
850
+ */
851
+ function JourneyNode({
852
+ node,
853
+ selected = false,
854
+ onClick,
855
+ onDelete
856
+ }) {
857
+ const {
858
+ type,
859
+ data
860
+ } = node;
861
+ const icon = actionIcons[type] || '📦';
862
+ return /*#__PURE__*/React.createElement("div", {
863
+ className: `eco-journey-node ${type} ${selected ? 'selected' : ''}`,
864
+ onClick: () => onClick?.(node)
865
+ }, /*#__PURE__*/React.createElement("div", {
866
+ className: "eco-journey-node-icon"
867
+ }, icon), /*#__PURE__*/React.createElement("div", {
868
+ className: "eco-journey-node-content"
869
+ }, /*#__PURE__*/React.createElement("span", {
870
+ className: "eco-journey-node-type"
871
+ }, t(type)), data?.name && /*#__PURE__*/React.createElement("span", {
872
+ className: "eco-journey-node-name"
873
+ }, data.name)), onDelete && /*#__PURE__*/React.createElement("button", {
874
+ className: "eco-journey-node-delete",
875
+ onClick: e => {
876
+ e.stopPropagation();
877
+ onDelete(node.id);
878
+ }
879
+ }, "\xD7"));
880
+ }
881
+
882
+ /**
883
+ * TriggerSelector 组件 - 触发器选择
884
+ */
885
+ function TriggerSelector({
886
+ value,
887
+ onChange
888
+ }) {
889
+ const triggers = [{
890
+ type: TriggerType.EVENT,
891
+ icon: '⚡',
892
+ label: t('event')
893
+ }, {
894
+ type: TriggerType.SCHEDULE,
895
+ icon: '📅',
896
+ label: t('schedule')
897
+ }, {
898
+ type: TriggerType.SEGMENT,
899
+ icon: '👥',
900
+ label: t('segment')
901
+ }, {
902
+ type: TriggerType.MANUAL,
903
+ icon: '🖱️',
904
+ label: t('manual')
905
+ }];
906
+ return /*#__PURE__*/React.createElement("div", {
907
+ className: "eco-journey-trigger-selector"
908
+ }, triggers.map(trigger => /*#__PURE__*/React.createElement("div", {
909
+ key: trigger.type,
910
+ className: `eco-journey-trigger-option ${value === trigger.type ? 'active' : ''}`,
911
+ onClick: () => onChange?.(trigger.type)
912
+ }, /*#__PURE__*/React.createElement("span", {
913
+ className: "eco-journey-trigger-icon"
914
+ }, trigger.icon), /*#__PURE__*/React.createElement("span", {
915
+ className: "eco-journey-trigger-label"
916
+ }, trigger.label))));
917
+ }
918
+
919
+ /**
920
+ * ActionSelector 组件 - 动作选择
921
+ */
922
+ function ActionSelector({
923
+ onSelect
924
+ }) {
925
+ const actions = [{
926
+ type: ActionType.SEND_EMAIL,
927
+ icon: '📧',
928
+ label: t('sendEmail')
929
+ }, {
930
+ type: ActionType.SEND_SMS,
931
+ icon: '📱',
932
+ label: t('sendSMS')
933
+ }, {
934
+ type: ActionType.SEND_PUSH,
935
+ icon: '🔔',
936
+ label: t('sendPush')
937
+ }, {
938
+ type: ActionType.SEND_NOTIFICATION,
939
+ icon: '💬',
940
+ label: t('sendNotification')
941
+ }, {
942
+ type: ActionType.WAIT,
943
+ icon: '⏱️',
944
+ label: t('wait')
945
+ }, {
946
+ type: ActionType.CONDITION,
947
+ icon: '🔀',
948
+ label: t('condition')
949
+ }, {
950
+ type: ActionType.ADD_TAG,
951
+ icon: '🏷️',
952
+ label: t('addTag')
953
+ }, {
954
+ type: ActionType.WEBHOOK,
955
+ icon: '🔗',
956
+ label: t('webhook')
957
+ }];
958
+ return /*#__PURE__*/React.createElement("div", {
959
+ className: "eco-journey-action-selector"
960
+ }, actions.map(action => /*#__PURE__*/React.createElement("div", {
961
+ key: action.type,
962
+ className: "eco-journey-action-option",
963
+ onClick: () => onSelect?.(action.type)
964
+ }, /*#__PURE__*/React.createElement("span", {
965
+ className: "eco-journey-action-icon"
966
+ }, action.icon), /*#__PURE__*/React.createElement("span", {
967
+ className: "eco-journey-action-label"
968
+ }, action.label))));
969
+ }
970
+
971
+ /**
972
+ * JourneyList 组件
973
+ */
974
+ function JourneyList({
975
+ journeys = [],
976
+ loading = false,
977
+ onJourneyClick,
978
+ onStart,
979
+ onPause,
980
+ onStop
981
+ }) {
982
+ if (loading && journeys.length === 0) {
983
+ return /*#__PURE__*/React.createElement("div", {
984
+ className: "eco-journey-loading"
985
+ }, "\u52A0\u8F7D\u4E2D...");
986
+ }
987
+ if (journeys.length === 0) {
988
+ return /*#__PURE__*/React.createElement("div", {
989
+ className: "eco-journey-empty"
990
+ }, "\u6682\u65E0\u65C5\u7A0B");
991
+ }
992
+ return /*#__PURE__*/React.createElement("div", {
993
+ className: "eco-journey-list"
994
+ }, journeys.map(journey => /*#__PURE__*/React.createElement(JourneyCard, {
995
+ key: journey.id,
996
+ journey: journey,
997
+ onClick: onJourneyClick,
998
+ onStart: onStart,
999
+ onPause: onPause,
1000
+ onStop: onStop
1001
+ })));
1002
+ }
1003
+
1004
+ /**
1005
+ * @quantabit/journey-sdk
1006
+ * Marketing Journey SDK - Full Version
1007
+ */
1008
+
1009
+ const getJourneys = (...args) => journeyApi.getJourneys(...args);
1010
+ const getJourney = (...args) => journeyApi.getJourney(...args);
1011
+ const createJourney = (...args) => journeyApi.createJourney(...args);
1012
+ const updateJourney = (...args) => journeyApi.updateJourney(...args);
1013
+ const deleteJourney = (...args) => journeyApi.deleteJourney(...args);
1014
+ const startJourney = (...args) => journeyApi.startJourney(...args);
1015
+ const pauseJourney = (...args) => journeyApi.pauseJourney(...args);
1016
+ const stopJourney = (...args) => journeyApi.stopJourney(...args);
1017
+ const getJourneyStats = (...args) => journeyApi.getJourneyStats(...args);
1018
+ const getJourneyUsers = (...args) => journeyApi.getJourneyUsers(...args);
1019
+
1020
+ export { ActionSelector, ActionType, JourneyApiClient, JourneyCard, JourneyList, JourneyNode, JourneyStatus, SUPPORTED_LANGUAGES, TriggerSelector, TriggerType, WaitType, createJourney, deleteJourney, getJourney, getJourneyStats, getJourneyUsers, getJourneys, getLanguage, journeyApi, messages, pauseJourney, setLanguage, startJourney, stopJourney, t, updateJourney, useJourney, useJourneyBuilder, useJourneys };
1021
+ //# sourceMappingURL=index.esm.js.map