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