drgame-cc 1.0.18 → 1.0.20
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/drscript/ExitWin.ts
CHANGED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { ActionType, Reporter } from "./ad-sdk/ad-sdk";
|
|
2
|
+
|
|
3
|
+
export enum GameAnalyticsPlatform {
|
|
4
|
+
XiaomiTv = "xiaomi",
|
|
5
|
+
Lewo = "lewo",
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export enum AnalyticsEvent {
|
|
9
|
+
GameLoading = "game_loading",
|
|
10
|
+
StartGameButton = "start_game_button",
|
|
11
|
+
WatchVideoContinueButton = "watch_video_continue_button",
|
|
12
|
+
ReplayButton = "replay_button",
|
|
13
|
+
RewardVideoAd = "reward_video_ad",
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export enum AnalyticsAction {
|
|
17
|
+
Exposure = "exposure",
|
|
18
|
+
Click = "click",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface GameAnalyticsConfig {
|
|
22
|
+
platform?: GameAnalyticsPlatform | string;
|
|
23
|
+
app_item?: string;
|
|
24
|
+
content_type?: string;
|
|
25
|
+
content_id?: string;
|
|
26
|
+
content_title?: string;
|
|
27
|
+
user_id?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface AnalyticsEventDefinition {
|
|
31
|
+
elementPosition: string;
|
|
32
|
+
exposureEventName?: string;
|
|
33
|
+
clickEventName?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const APP_ITEM_BY_PLATFORM: { [platform: string]: string } = {
|
|
37
|
+
xiaomi: "25",
|
|
38
|
+
lewo: "29",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const REPORT_URL = "https://sup.daoran.tv/bi-api/api/game/lewo/batch";
|
|
42
|
+
|
|
43
|
+
export default class GameAnalytics {
|
|
44
|
+
private static initialized: boolean = false;
|
|
45
|
+
private static loadingReported: boolean = false;
|
|
46
|
+
private static reportedExposures: { [event: string]: boolean } = {};
|
|
47
|
+
|
|
48
|
+
private static readonly definitions: { [event: string]: AnalyticsEventDefinition } = {
|
|
49
|
+
game_loading: {
|
|
50
|
+
elementPosition: "game_loading",
|
|
51
|
+
exposureEventName: "game_loading_expose",
|
|
52
|
+
},
|
|
53
|
+
start_game_button: {
|
|
54
|
+
elementPosition: "start_game_button",
|
|
55
|
+
exposureEventName: "start_game_expose",
|
|
56
|
+
clickEventName: "start_game_click",
|
|
57
|
+
},
|
|
58
|
+
watch_video_continue_button: {
|
|
59
|
+
elementPosition: "watch_video_continue_button",
|
|
60
|
+
exposureEventName: "watch_video_continue_expose",
|
|
61
|
+
clickEventName: "watch_video_continue_click",
|
|
62
|
+
},
|
|
63
|
+
replay_button: {
|
|
64
|
+
elementPosition: "replay_button",
|
|
65
|
+
exposureEventName: "replay_expose",
|
|
66
|
+
clickEventName: "replay_click",
|
|
67
|
+
},
|
|
68
|
+
reward_video_ad: {
|
|
69
|
+
elementPosition: "reward_video_ad",
|
|
70
|
+
exposureEventName: "ad_expose",
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
public static init(config: GameAnalyticsConfig = {}): void {
|
|
75
|
+
if (this.initialized) {
|
|
76
|
+
if (config.user_id !== undefined) this.setUserId(config.user_id);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const platform = config.platform || GameAnalyticsPlatform.XiaomiTv;
|
|
82
|
+
Reporter.init({
|
|
83
|
+
report_url: REPORT_URL,
|
|
84
|
+
app_item: config.app_item || this.getAppItem(platform),
|
|
85
|
+
content_type: config.content_type || "独立游戏",
|
|
86
|
+
content_id: config.content_id || "rexueqiangshou",
|
|
87
|
+
content_title: config.content_title || "热血枪手",
|
|
88
|
+
});
|
|
89
|
+
this.initialized = true;
|
|
90
|
+
if (config.user_id !== undefined) this.setUserId(config.user_id);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.warn("[GameAnalytics] init failed", error);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public static setUserId(userId: string): void {
|
|
97
|
+
this.init();
|
|
98
|
+
if (!this.initialized) return;
|
|
99
|
+
try {
|
|
100
|
+
Reporter.setCommonInfo({ user_id: userId || "" });
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.warn("[GameAnalytics] set user id failed", error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public static reportLoadingOnce(): void {
|
|
107
|
+
if (this.loadingReported) return;
|
|
108
|
+
this.loadingReported = true;
|
|
109
|
+
this.report(AnalyticsEvent.GameLoading, AnalyticsAction.Exposure);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
public static reportExposureOnce(event: AnalyticsEvent): void {
|
|
113
|
+
if (this.reportedExposures[event]) return;
|
|
114
|
+
this.reportedExposures[event] = true;
|
|
115
|
+
this.report(event, AnalyticsAction.Exposure);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public static report(
|
|
119
|
+
event: AnalyticsEvent,
|
|
120
|
+
action: AnalyticsAction,
|
|
121
|
+
adRequestId?: string
|
|
122
|
+
): void {
|
|
123
|
+
this.init();
|
|
124
|
+
if (!this.initialized) return;
|
|
125
|
+
|
|
126
|
+
const definition = this.definitions[event];
|
|
127
|
+
const eventName = definition && action === AnalyticsAction.Exposure
|
|
128
|
+
? definition.exposureEventName
|
|
129
|
+
: definition && definition.clickEventName;
|
|
130
|
+
if (!definition || !eventName) {
|
|
131
|
+
console.warn("[GameAnalytics] unsupported event/action", event, action);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const reportItem: any = {
|
|
137
|
+
element_position: definition.elementPosition,
|
|
138
|
+
action_type: action === AnalyticsAction.Exposure
|
|
139
|
+
? ActionType.Exposure
|
|
140
|
+
: ActionType.Click,
|
|
141
|
+
event_name: eventName,
|
|
142
|
+
};
|
|
143
|
+
if (event === AnalyticsEvent.RewardVideoAd) {
|
|
144
|
+
reportItem.ad_request_id = adRequestId || "";
|
|
145
|
+
}
|
|
146
|
+
Reporter.report(reportItem);
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.warn("[GameAnalytics] report failed", error);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static getAppItem(platform: string): string {
|
|
153
|
+
const normalizedPlatform = (platform || "").toLowerCase();
|
|
154
|
+
const appItem = APP_ITEM_BY_PLATFORM[normalizedPlatform];
|
|
155
|
+
if (appItem) return appItem;
|
|
156
|
+
console.warn(
|
|
157
|
+
"[GameAnalytics] unknown platform, fallback to Xiaomi TV app_item=25",
|
|
158
|
+
platform
|
|
159
|
+
);
|
|
160
|
+
return APP_ITEM_BY_PLATFORM[GameAnalyticsPlatform.XiaomiTv];
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
import { BtnExtra } from "./BtnExtra";
|
|
3
3
|
import TvUi from "./core/TvUi";
|
|
4
4
|
import { EVideoScene } from "./Define";
|
|
5
|
+
import GameAnalytics, { AnalyticsAction, AnalyticsEvent, GameAnalyticsPlatform } from "./GameAnalytics";
|
|
5
6
|
import { showRewardVideo } from "./Info";
|
|
6
7
|
import { Loader } from "./Loader";
|
|
7
8
|
import ToastManager from "./toast/ToastManager";
|
|
8
|
-
|
|
9
|
+
import { Util } from "./Util";
|
|
9
10
|
/** 平台适配器,名字有点长防止和Platform,Adapter冲突 */
|
|
10
11
|
export class PlatformAdapter {
|
|
11
12
|
private static readonly cpId = "xhbj";
|
|
@@ -13,10 +14,13 @@ export class PlatformAdapter {
|
|
|
13
14
|
private static readonly designWidth = 1920;
|
|
14
15
|
private static readonly designHeight = 1080;
|
|
15
16
|
/** 初始化 */
|
|
16
|
-
public static async init() {
|
|
17
|
+
public static async init(cnName: string) {
|
|
18
|
+
var platform = GameAnalyticsPlatform.XiaomiTv;//平台由sdk处理
|
|
19
|
+
var appItem = GameAnalytics.getAppItem(platform);
|
|
20
|
+
var contentId = Util.getChineseInitials(cnName);
|
|
17
21
|
await ToastManager.Inst.init();
|
|
18
22
|
TvUi.init({
|
|
19
|
-
cpId:
|
|
23
|
+
cpId: contentId,
|
|
20
24
|
version: this.version,
|
|
21
25
|
designWidth: this.designWidth,
|
|
22
26
|
designHeight: this.designHeight,
|
|
@@ -27,7 +31,7 @@ export class PlatformAdapter {
|
|
|
27
31
|
defaultIconKey: "default"
|
|
28
32
|
},
|
|
29
33
|
adSdk: {
|
|
30
|
-
platform:
|
|
34
|
+
platform: platform
|
|
31
35
|
},
|
|
32
36
|
ads: {
|
|
33
37
|
reward: {
|
|
@@ -56,6 +60,15 @@ export class PlatformAdapter {
|
|
|
56
60
|
}
|
|
57
61
|
}
|
|
58
62
|
});
|
|
63
|
+
|
|
64
|
+
GameAnalytics.init({
|
|
65
|
+
platform: GameAnalyticsPlatform.XiaomiTv,
|
|
66
|
+
app_item: appItem,
|
|
67
|
+
content_type: "游戏", // 游戏(乐窝的游戏,这个字段都固定上报游戏)
|
|
68
|
+
content_id: contentId, // 游戏ID(具体乐窝的游戏ID)
|
|
69
|
+
content_title: znName, // 游戏名(具体的乐窝游戏名)
|
|
70
|
+
});
|
|
71
|
+
|
|
59
72
|
}
|
|
60
73
|
|
|
61
74
|
/**
|
|
@@ -72,7 +85,7 @@ export class PlatformAdapter {
|
|
|
72
85
|
* 注册按钮事件,有BtnExtra组件会自动切换按钮图片
|
|
73
86
|
* @param button 按钮组件
|
|
74
87
|
*/
|
|
75
|
-
public static registerButton(button: cc.
|
|
88
|
+
public static registerButton(button: cc.Node) {
|
|
76
89
|
var sprite = button.getComponent(cc.Sprite);
|
|
77
90
|
var btnExtra = button.getComponent(BtnExtra);
|
|
78
91
|
var onFocus = () => {
|
|
@@ -95,8 +108,8 @@ export class PlatformAdapter {
|
|
|
95
108
|
*/
|
|
96
109
|
public static registerButtonByName(name: string, parent: cc.Node = null) {
|
|
97
110
|
if (!parent) parent = cc.director.getScene();
|
|
98
|
-
let button = this.findChildByName(parent, name)
|
|
99
|
-
|
|
111
|
+
let button = this.findChildByName(parent, name);
|
|
112
|
+
|
|
100
113
|
this.registerButton(button);
|
|
101
114
|
}
|
|
102
115
|
|
|
@@ -108,13 +121,12 @@ export class PlatformAdapter {
|
|
|
108
121
|
*/
|
|
109
122
|
public static focusButtonByName(name: string, parent: cc.Node = null) {
|
|
110
123
|
if (!parent) parent = cc.director.getScene();
|
|
111
|
-
let button = this.findChildByName(parent, name)
|
|
112
|
-
|
|
113
|
-
TvUi.focus.focus(button.node);
|
|
124
|
+
let button = this.findChildByName(parent, name);
|
|
125
|
+
TvUi.focus.focus(button);
|
|
114
126
|
}
|
|
115
127
|
|
|
116
|
-
public static focusButton(btn: cc.
|
|
117
|
-
TvUi.focus.focus(btn
|
|
128
|
+
public static focusButton(btn: cc.Node) {
|
|
129
|
+
TvUi.focus.focus(btn);
|
|
118
130
|
}
|
|
119
131
|
|
|
120
132
|
/**
|
|
@@ -143,6 +155,7 @@ export class PlatformAdapter {
|
|
|
143
155
|
public static showWindow(window: cc.Node) {
|
|
144
156
|
TvUi.focus.pushScope(window.uuid, window);
|
|
145
157
|
TvUi.focus.registerButtons(window);
|
|
158
|
+
this.findBtnExtra(window);
|
|
146
159
|
}
|
|
147
160
|
|
|
148
161
|
/** 关闭界面取消注册按钮事件 */
|
|
@@ -153,8 +166,8 @@ export class PlatformAdapter {
|
|
|
153
166
|
|
|
154
167
|
/** 刷新界面按钮事件, 用于界面按钮变化(列表,下拉)后,需要刷新按钮事件 */
|
|
155
168
|
public static refreshWindow(window: cc.Node) {
|
|
156
|
-
cc.Node.EventType.TOUCH_START
|
|
157
169
|
TvUi.focus.registerButtons(window);
|
|
170
|
+
this.findBtnExtra(window);
|
|
158
171
|
}
|
|
159
172
|
|
|
160
173
|
public static async showExitWin() {
|
|
@@ -164,6 +177,18 @@ export class PlatformAdapter {
|
|
|
164
177
|
exitWin.setPosition(cc.v2(cc.winSize.width / 2, cc.winSize.height / 2));
|
|
165
178
|
}
|
|
166
179
|
|
|
180
|
+
private static findBtnExtra(node: cc.Node) {
|
|
181
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
182
|
+
var child = node.children[i];
|
|
183
|
+
if (child.isValid === false || !child.activeInHierarchy) continue;
|
|
184
|
+
let btnExtra = child.getComponent(BtnExtra);
|
|
185
|
+
if (btnExtra) {
|
|
186
|
+
this.registerButton(child);
|
|
187
|
+
}
|
|
188
|
+
this.findBtnExtra(child);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
167
192
|
/** 设置启动页进度条 */
|
|
168
193
|
public static setProgress(progress: number, tip: string) {
|
|
169
194
|
if (window["setProgress"]) window["setProgress"](progress, tip);
|
|
@@ -173,4 +198,14 @@ export class PlatformAdapter {
|
|
|
173
198
|
public static closeLoading() {
|
|
174
199
|
if (window["closeLoading"]) window["closeLoading"]();
|
|
175
200
|
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* 上报事件
|
|
204
|
+
* @param event 事件类型
|
|
205
|
+
* @param action 事件操作 曝光or点击 默认点击
|
|
206
|
+
* @param adRequestId 广告请求ID
|
|
207
|
+
*/
|
|
208
|
+
public static report(event: AnalyticsEvent, action: AnalyticsAction = AnalyticsAction.Click, adRequestId?: string) {
|
|
209
|
+
GameAnalytics.report(event, action, adRequestId);
|
|
210
|
+
}
|
|
176
211
|
}
|
package/drscript/Util.ts
ADDED
|
@@ -68,6 +68,25 @@ var Reporter = {
|
|
|
68
68
|
this._commonInfo.device_id = supersetLewo.createDeviceId();
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
supersetLewo.initUserInfo({
|
|
72
|
+
os_type: "", // 系统类型安卓
|
|
73
|
+
os_version: "", // 安卓版本15
|
|
74
|
+
app_version: "1.0.0", // APP版本号
|
|
75
|
+
app_item: config.app_item, // 渠道编码
|
|
76
|
+
app_name: config.content_title, // APP展示名称
|
|
77
|
+
app_project: config.content_id, // 产品内部编码
|
|
78
|
+
province: "", // 省份编码
|
|
79
|
+
city: "", // 城市编码
|
|
80
|
+
uid: "", // 登录用户UID,未登录填空""
|
|
81
|
+
user_id: "", // 会员/游客ID,无则填空""
|
|
82
|
+
device_id: this._commonInfo.device_id, // 设备唯一ID,没有或不传则自动生成
|
|
83
|
+
device_brand: "", // 手机品牌小写
|
|
84
|
+
device_model: "", // 手机完整型号
|
|
85
|
+
network_type: "", // 蜂窝流量网络
|
|
86
|
+
carrier: "" // 运营商
|
|
87
|
+
// device_id 不传,内部自动生成UUID填充,无需手动传入
|
|
88
|
+
});
|
|
89
|
+
|
|
71
90
|
this._initialized = true;
|
|
72
91
|
console.log('[Reporter] Initialized, reportUrl:', supersetLewo.config.reportUrl);
|
|
73
92
|
},
|
|
@@ -1,35 +1,47 @@
|
|
|
1
1
|
var supersetLewo = (function () {
|
|
2
|
-
// ==========
|
|
2
|
+
// ========== 私有常量与缓存(闭包私有,外部不可访问) ==========
|
|
3
|
+
// 设备ID本地存储Key:localStorage + cookie共用
|
|
3
4
|
var STORAGE_KEY = 'analytics.device_id.uuid_v4';
|
|
5
|
+
// 内存缓存设备UUID,避免重复读取存储
|
|
4
6
|
var memoryCache = null;
|
|
7
|
+
// 全局缓存用户/设备公共信息,上报顶层user字段统一复用
|
|
8
|
+
var globalUserInfo = {};
|
|
9
|
+
|
|
10
|
+
var initInfoFlag = false;
|
|
5
11
|
|
|
6
12
|
/**
|
|
7
|
-
* 生成标准 UUID v4
|
|
8
|
-
*
|
|
13
|
+
* 生成标准 UUID v4 设备唯一标识
|
|
14
|
+
* 优先级:原生crypto.randomUUID > crypto.getRandomValues > Math.random伪随机兜底
|
|
15
|
+
* @returns {string} 小写标准UUID v4字符串
|
|
9
16
|
*/
|
|
10
17
|
function createUuidV4() {
|
|
18
|
+
// 浏览器原生高性能UUID接口
|
|
11
19
|
if (globalThis.crypto?.randomUUID) {
|
|
12
20
|
return globalThis.crypto.randomUUID().toLowerCase();
|
|
13
21
|
}
|
|
14
|
-
|
|
22
|
+
// 支持加密随机字节,手动构造v4规范UUID
|
|
15
23
|
if (globalThis.crypto?.getRandomValues) {
|
|
16
24
|
var bytes = new Uint8Array(16);
|
|
17
25
|
globalThis.crypto.getRandomValues(bytes);
|
|
18
|
-
// UUID v4
|
|
26
|
+
// UUID v4 固定版本位 0x40、变种位 0x80
|
|
19
27
|
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
20
28
|
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
21
|
-
|
|
29
|
+
// 字节转两位十六进制字符串
|
|
22
30
|
var hex = Array.from(bytes, function (val) {
|
|
23
31
|
return val.toString(16).padStart(2, '0');
|
|
24
32
|
}).join('');
|
|
33
|
+
// 拼接标准UUID分隔格式
|
|
25
34
|
return hex.slice(0, 8) + '-' + hex.slice(8, 12) + '-' +
|
|
26
35
|
hex.slice(12, 16) + '-' + hex.slice(16, 20) + '-' + hex.slice(20);
|
|
27
36
|
}
|
|
28
|
-
|
|
29
|
-
// 最低降级:Math.random 伪随机(熵低,仅统计场景兜底)
|
|
37
|
+
// 最低兼容兜底:Math.random生成伪随机UUID(熵较低,仅无加密API场景使用)
|
|
30
38
|
return generatePseudoUuid();
|
|
31
39
|
}
|
|
32
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Math.random 伪随机UUID生成器,兼容极老浏览器
|
|
43
|
+
* @returns {string} 伪随机UUID v4格式字符串
|
|
44
|
+
*/
|
|
33
45
|
function generatePseudoUuid() {
|
|
34
46
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
35
47
|
var r = (Math.random() * 16) | 0;
|
|
@@ -39,254 +51,259 @@ var supersetLewo = (function () {
|
|
|
39
51
|
}
|
|
40
52
|
|
|
41
53
|
/**
|
|
42
|
-
*
|
|
54
|
+
* 安全读取Cookie,自动转义正则特殊字符,防止匹配失效
|
|
55
|
+
* @param {string} name cookie键名
|
|
56
|
+
* @returns {string|null} cookie值,无则返回null
|
|
43
57
|
*/
|
|
44
58
|
function getCookie(name) {
|
|
45
59
|
try {
|
|
60
|
+
// 转义 . * + ? $ 等正则特殊符号
|
|
46
61
|
var escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
47
62
|
var reg = new RegExp('(^| )' + escapedName + '=([^;]+)');
|
|
48
63
|
var match = document.cookie.match(reg);
|
|
49
64
|
return match ? match[2] : null;
|
|
50
65
|
} catch (e) {
|
|
66
|
+
// cookie读取异常直接返回空
|
|
51
67
|
return null;
|
|
52
68
|
}
|
|
53
69
|
}
|
|
54
70
|
|
|
55
71
|
/**
|
|
56
|
-
*
|
|
72
|
+
* 设置持久化Cookie,有效期1年,自动适配HTTPS Secure标识
|
|
73
|
+
* @param {string} name cookie键名
|
|
74
|
+
* @param {string} value cookie存储值
|
|
57
75
|
*/
|
|
58
76
|
function setCookie(name, value) {
|
|
59
77
|
try {
|
|
60
78
|
var isHttps = window.location.protocol === 'https:';
|
|
61
79
|
var parts = [
|
|
62
80
|
name + '=' + value,
|
|
63
|
-
'max-age=31536000',
|
|
64
|
-
'path=/',
|
|
65
|
-
'SameSite=Lax'
|
|
81
|
+
'max-age=31536000', // 有效期365天
|
|
82
|
+
'path=/', // 全站生效
|
|
83
|
+
'SameSite=Lax' // 防跨站劫持
|
|
66
84
|
];
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
85
|
+
// HTTPS环境追加Secure标识
|
|
86
|
+
if (isHttps) parts.push('Secure');
|
|
70
87
|
document.cookie = parts.join(';');
|
|
71
|
-
} catch (e) {
|
|
72
|
-
|
|
88
|
+
} catch (e) { }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 时间格式化工具,统一输出 yyyy-MM-dd HH:mm:ss
|
|
93
|
+
* @returns {string} 格式化后的标准时间字符串
|
|
94
|
+
*/
|
|
95
|
+
function formatTime() {
|
|
96
|
+
var date_t = new Date();
|
|
97
|
+
var y_t = date_t.getFullYear();
|
|
98
|
+
var m_t = String(date_t.getMonth() + 1).padStart(2, '0');
|
|
99
|
+
var d_t = String(date_t.getDate()).padStart(2, '0');
|
|
100
|
+
var h_t = String(date_t.getHours()).padStart(2, '0');
|
|
101
|
+
var min_t = String(date_t.getMinutes()).padStart(2, '0');
|
|
102
|
+
var sec_t = String(date_t.getSeconds()).padStart(2, '0');
|
|
103
|
+
return y_t + "-" + m_t + "-" + d_t + " " + h_t + ":" + min_t + ":" + sec_t;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 填充单条埋点事件默认字段,缺失字段自动补空/默认行为类型,自动填充事件时间
|
|
108
|
+
* @param {Object} eventItem 业务传入的单条埋点原始参数
|
|
109
|
+
* @returns {Object} 补全默认值后的标准事件对象
|
|
110
|
+
*/
|
|
111
|
+
function fillEventDefault(eventItem) {
|
|
112
|
+
// 事件字段默认模板,对齐后端data数组字段规范
|
|
113
|
+
var defaultEvent = {
|
|
114
|
+
element_position: "", // 产品定义元素位置编码(唯一标识)
|
|
115
|
+
position_name: "", // 元素位置中文名称
|
|
116
|
+
page_code: "", // OMS后台页面编码,无则空字符串
|
|
117
|
+
page_name: "", // OMS后台页面名称,无则空字符串
|
|
118
|
+
floor_id: "", // OMS后台楼层ID
|
|
119
|
+
floor_name: "", // OMS后台楼层名称
|
|
120
|
+
element_type: "", // 元素枚举:page/vlist/plist/res/act/link等
|
|
121
|
+
element_name: "", // 元素内部名称/标题
|
|
122
|
+
content_id: "", // 最小颗粒度内容ID(游戏/视频ID)
|
|
123
|
+
content_title: "", // 内容标题名称
|
|
124
|
+
ext_attr1: "", // 扩展属性1,存放自定义附属信息
|
|
125
|
+
ext_attr2: "", // 扩展属性2,存放附属ID类参数
|
|
126
|
+
action_type: "曝光", // 行为枚举:曝光/点击/开始播放/结束播放/分享/订购/启动/退出/切后台
|
|
127
|
+
action_value: "", // 行为附属值:播放时长填秒数、订购填金额(单位分)、无附属数据填空
|
|
128
|
+
event_time: "" // 事件发生时间,不传则自动生成当前标准时间
|
|
129
|
+
};
|
|
130
|
+
// 业务参数覆盖默认模板
|
|
131
|
+
var merged = Object.assign({}, defaultEvent, eventItem);
|
|
132
|
+
// 未传入时间自动填充当前客户端时间
|
|
133
|
+
if (!merged.event_time) merged.event_time = formatTime();
|
|
134
|
+
return merged;
|
|
73
135
|
}
|
|
74
136
|
|
|
75
|
-
// ==========
|
|
137
|
+
// ========== 对外暴露公共API ==========
|
|
76
138
|
return {
|
|
77
|
-
//
|
|
139
|
+
// 全局埋点配置项
|
|
78
140
|
config: {
|
|
79
|
-
//
|
|
80
|
-
reportUrl: '
|
|
81
|
-
|
|
82
|
-
//
|
|
83
|
-
defaultHeaders: [
|
|
84
|
-
// { name: 'md5', value: "GYWmhK2MfuQtDc9Cj8Fbw9hGoJwQ+f3WTgHRahD1TRiA6TpexZSORQ==" }
|
|
85
|
-
],
|
|
86
|
-
defaultContentType: 'application/json;charset=UTF-8',
|
|
87
|
-
// 默认行为类型
|
|
88
|
-
defaultActionType: '曝光'
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
// ===================== 公共上报字段模板(全部改为下划线字段,对齐后端接口图片参数) =====================
|
|
92
|
-
defaultReportItem: {
|
|
93
|
-
user_id: '', // 用户唯一标识(需要用户登录,产生UID)
|
|
94
|
-
device_id: '', // 设备唯一标识(设备号,如果无,则需要生成)
|
|
95
|
-
app_item: '', // 渠道,如29,x5
|
|
96
|
-
content_type: '游戏', // 游戏(乐窝的游戏,这个字段都固定上报游戏)
|
|
97
|
-
content_id: '', // 游戏ID(具体乐窝的游戏ID)
|
|
98
|
-
content_title: '', // 游戏名(具体的乐窝游戏名)
|
|
99
|
-
element_position: '', // 元素位置(埋点范围表对应的 元素位置列)
|
|
100
|
-
action_type: '', // 曝光/点击
|
|
101
|
-
event_name: '', // 具体事件名(新增,友盟需要按照上面表格传值,通过元素位置和行为生成事件名字)
|
|
102
|
-
event_time: '', // 客户端事件时间(格式建议:yyyy-MM-dd HH:mm:ss)
|
|
103
|
-
ad_request_id: '' // 广告请求ID,仅广告相关事件需要
|
|
141
|
+
reportUrl: 'https://sup.daoran.tv/bi-api/api/game/lewo/batch', // 批量上报接口地址
|
|
142
|
+
// reportUrl: '/bi-api/api/game/lewo/batch', // 批量上报接口地址
|
|
143
|
+
defaultHeaders: [], // 默认全局请求头数组
|
|
144
|
+
defaultContentType: 'application/json;charset=UTF-8' // 请求体类型
|
|
104
145
|
},
|
|
105
146
|
|
|
106
|
-
// ===================== 工具方法 =====================
|
|
107
147
|
/**
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* @
|
|
148
|
+
* 设置全局用户/设备公共信息(上报顶层user对象,全局复用)
|
|
149
|
+
* 页面初始化、登录、切换渠道、切换网络时调用一次即可
|
|
150
|
+
* @param {Object} userObj 用户设备公共参数集合
|
|
151
|
+
* userObj字段说明:
|
|
152
|
+
* os_type: 操作系统类型 android / ios 全小写
|
|
153
|
+
* os_version: 系统版本纯数字,如15、17.1
|
|
154
|
+
* app_version: APP完整版本号 7.3.0
|
|
155
|
+
* app_item: 渠道编码/项目编码
|
|
156
|
+
* app_name: APP展示名称
|
|
157
|
+
* app_project: 产品内部短编码
|
|
158
|
+
* province: 省份数字编码
|
|
159
|
+
* city: 城市数字编码
|
|
160
|
+
* uid: 登录用户全局UID,游客/未登录填空字符串
|
|
161
|
+
* user_id: 会员ID / cocos游客ID,无则空
|
|
162
|
+
* device_brand: 设备品牌全小写 huawei/xiaomi/apple
|
|
163
|
+
* device_model: 设备完整型号
|
|
164
|
+
* network_type: 网络类型 wifi / cellular(蜂窝流量)
|
|
165
|
+
* carrier: 运营商 移动/联通/电信/广电/未知
|
|
166
|
+
* device_id: 可选,不传内部自动生成UUID v4设备标识
|
|
111
167
|
*/
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
//
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
merged[key] = item[key] !== undefined ? item[key] : defaultItem[key];
|
|
119
|
-
}
|
|
168
|
+
initUserInfo: function (userObj) {
|
|
169
|
+
if (initInfoFlag) { return }
|
|
170
|
+
initInfoFlag = true;
|
|
171
|
+
// 未传入设备ID时,自动生成持久化UUID填充
|
|
172
|
+
if (!userObj.device_id) {
|
|
173
|
+
userObj.device_id = this.createDeviceId();
|
|
120
174
|
}
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
175
|
+
// 合并覆盖全局缓存,保留旧字段,新参数覆盖
|
|
176
|
+
globalUserInfo = Object.assign({}, globalUserInfo, userObj);
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
// 1. 异步加载 H5 专属 SDK
|
|
180
|
+
(function (w, d, s, q, i) {
|
|
181
|
+
w[q] = w[q] || [];
|
|
182
|
+
var f = d.getElementsByTagName(s)[0],
|
|
183
|
+
j = d.createElement(s);
|
|
184
|
+
j.async = true;
|
|
185
|
+
j.id = 'beacon-aplus';
|
|
186
|
+
// ✅ 使用 H5 网页专属 SDK 地址
|
|
187
|
+
j.src = 'https://d.alicdn.com/alilog/mlog/aplus/' + i + '.js';
|
|
188
|
+
f.parentNode.insertBefore(j, f);
|
|
189
|
+
})(window, document, 'script', 'aplus_queue', '203467608');
|
|
190
|
+
|
|
191
|
+
// ========= 基础配置 =========
|
|
192
|
+
// 2. 设置 AppKey (请确保与友盟后台 H5/Web 应用的 AppKey 一致)
|
|
193
|
+
aplus_queue.push({
|
|
194
|
+
action: 'aplus.setMetaInfo',
|
|
195
|
+
arguments: ['appKey', '6a55f95f6f259537c7c966c8'] // 替换你的Umini AppKey
|
|
196
|
+
});
|
|
197
|
+
// 3. 声明终端类型为 PC (关键配置)
|
|
198
|
+
aplus_queue.push({
|
|
199
|
+
action: 'aplus.setMetaInfo',
|
|
200
|
+
arguments: ['aplus-terminal', 'pc']
|
|
201
|
+
});
|
|
202
|
+
// 4. 采集模式配置
|
|
203
|
+
// 传统多页网站(PC)建议改为 'AUTO';如果是 Vue/React 单页应用(SPA)保持 'MAN'
|
|
204
|
+
aplus_queue.push({
|
|
205
|
+
action: 'aplus.setMetaInfo',
|
|
206
|
+
arguments: ['aplus-waiting', 'AUTO']
|
|
207
|
+
});
|
|
208
|
+
// 调试模式,上线务必改为false
|
|
209
|
+
aplus_queue.push({
|
|
210
|
+
action: 'aplus.setMetaInfo',
|
|
211
|
+
arguments: ['DEBUG', false]
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// ✅【必须补充】显式初始化SDK
|
|
215
|
+
aplus_queue.push({
|
|
216
|
+
action: 'aplus.init'
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// ⚠️【重点】aplus-idtype 说明
|
|
220
|
+
// 如果你使用业务自己device_id/uuid:值填 uuid
|
|
221
|
+
// 微信openid:openid;支付宝:alipay_id;字节:anonymousid
|
|
222
|
+
// 暂时不确定类型,可以先注释这一行,避免配置错误
|
|
223
|
+
/*
|
|
224
|
+
aplus_queue.push({
|
|
225
|
+
action: 'aplus.setMetaInfo',
|
|
226
|
+
arguments: ['aplus-idtype', 'uuid']
|
|
227
|
+
});
|
|
228
|
+
*/
|
|
229
|
+
} catch (e) {
|
|
230
|
+
|
|
124
231
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
232
|
+
|
|
233
|
+
try {
|
|
234
|
+
// 设置用户唯一ID(登录/游客都可以设置)
|
|
235
|
+
var u_user_id = userObj.uid || userObj.device_id || '';
|
|
236
|
+
// console.log('u_user_id', userObj, u_user_id)
|
|
237
|
+
aplus_queue.push({
|
|
238
|
+
action: 'aplus.setMetaInfo',
|
|
239
|
+
arguments: ['userId', u_user_id]
|
|
240
|
+
});
|
|
241
|
+
} catch (e) {
|
|
242
|
+
|
|
128
243
|
}
|
|
129
|
-
|
|
130
|
-
return merged;
|
|
244
|
+
|
|
131
245
|
},
|
|
132
246
|
|
|
133
247
|
/**
|
|
134
|
-
*
|
|
248
|
+
* 获取当前全局缓存的user公共信息(拷贝返回,防止外部篡改缓存)
|
|
249
|
+
* @returns {Object} 完整user公参对象
|
|
135
250
|
*/
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
var y_t = date_t.getFullYear();
|
|
139
|
-
var m_t = date_t.getMonth() + 1;
|
|
140
|
-
m_t = m_t < 10 ? "0" + m_t : m_t;
|
|
141
|
-
var d_t = date_t.getDate();
|
|
142
|
-
d_t = d_t < 10 ? "0" + d_t : d_t;
|
|
143
|
-
var h_t = date_t.getHours();
|
|
144
|
-
h_t = h_t < 10 ? "0" + h_t : h_t;
|
|
145
|
-
var min_t = date_t.getMinutes();
|
|
146
|
-
min_t = min_t < 10 ? "0" + min_t : min_t;
|
|
147
|
-
var sec_t = date_t.getSeconds();
|
|
148
|
-
sec_t = sec_t < 10 ? "0" + sec_t : sec_t;
|
|
149
|
-
return y_t + "-" + m_t + "-" + d_t + " " + h_t + ":" + min_t + ":" + sec_t;
|
|
251
|
+
getUserInfo: function () {
|
|
252
|
+
return Object.assign({}, globalUserInfo);
|
|
150
253
|
},
|
|
151
254
|
|
|
152
|
-
// ===================== 设备ID相关新增方法 =====================
|
|
153
255
|
/**
|
|
154
|
-
*
|
|
155
|
-
*
|
|
256
|
+
* 获取或生成持久化设备唯一ID
|
|
257
|
+
* 读取优先级:内存缓存 > localStorage > cookie > 新建UUID
|
|
258
|
+
* @returns {string} 小写标准UUID v4 device_id
|
|
156
259
|
*/
|
|
157
260
|
createDeviceId: function () {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
// 1. 尝试从 LocalStorage 读取
|
|
261
|
+
// 内存存在直接返回,减少存储读取
|
|
262
|
+
if (memoryCache) return memoryCache;
|
|
263
|
+
// 第一步读取localStorage
|
|
163
264
|
try {
|
|
164
|
-
var
|
|
165
|
-
if (
|
|
166
|
-
|
|
167
|
-
memoryCache = existing.toLowerCase();
|
|
265
|
+
var storageId = localStorage.getItem(STORAGE_KEY);
|
|
266
|
+
if (storageId?.trim()) {
|
|
267
|
+
memoryCache = storageId.toLowerCase();
|
|
168
268
|
return memoryCache;
|
|
169
269
|
}
|
|
170
|
-
} catch (e) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
memoryCache = existingCookie.toLowerCase();
|
|
178
|
-
// 尝试同步回 LocalStorage
|
|
179
|
-
try {
|
|
180
|
-
localStorage.setItem(STORAGE_KEY, memoryCache);
|
|
181
|
-
} catch (e) {
|
|
182
|
-
}
|
|
270
|
+
} catch (e) { }
|
|
271
|
+
// 第二步读取cookie
|
|
272
|
+
var cookieId = getCookie(STORAGE_KEY);
|
|
273
|
+
if (cookieId?.trim()) {
|
|
274
|
+
memoryCache = cookieId.toLowerCase();
|
|
275
|
+
// 同步写入localStorage,双存储统一
|
|
276
|
+
try { localStorage.setItem(STORAGE_KEY, memoryCache); } catch (e) { }
|
|
183
277
|
return memoryCache;
|
|
184
278
|
}
|
|
185
|
-
|
|
186
|
-
// 3. 重新生成并存储
|
|
279
|
+
// 无存储记录,新建UUID并持久化
|
|
187
280
|
var newId = createUuidV4();
|
|
188
281
|
memoryCache = newId;
|
|
189
|
-
|
|
190
|
-
try {
|
|
191
|
-
localStorage.setItem(STORAGE_KEY, newId);
|
|
192
|
-
} catch (e) {
|
|
193
|
-
}
|
|
282
|
+
try { localStorage.setItem(STORAGE_KEY, newId); } catch (e) { }
|
|
194
283
|
setCookie(STORAGE_KEY, newId);
|
|
195
|
-
|
|
196
284
|
return newId;
|
|
197
285
|
},
|
|
198
286
|
|
|
199
287
|
/**
|
|
200
|
-
*
|
|
288
|
+
* 重置清除本地全部设备ID缓存(退出账号/清除游客标识场景使用)
|
|
289
|
+
* 清空内存、localStorage、cookie三处存储
|
|
201
290
|
*/
|
|
202
291
|
resetDeviceId: function () {
|
|
203
292
|
memoryCache = null;
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
293
|
+
// 删除本地存储
|
|
294
|
+
try { localStorage.removeItem(STORAGE_KEY); } catch (e) { }
|
|
295
|
+
// 过期销毁cookie
|
|
208
296
|
try {
|
|
209
297
|
var isHttps = window.location.protocol === 'https:';
|
|
210
|
-
var cookieParts = [
|
|
211
|
-
|
|
212
|
-
'max-age=0',
|
|
213
|
-
'path=/',
|
|
214
|
-
'SameSite=Lax'
|
|
215
|
-
];
|
|
216
|
-
if (isHttps) {
|
|
217
|
-
cookieParts.push('Secure');
|
|
218
|
-
}
|
|
298
|
+
var cookieParts = [STORAGE_KEY + '=', 'max-age=0', 'path=/', 'SameSite=Lax'];
|
|
299
|
+
if (isHttps) cookieParts.push('Secure');
|
|
219
300
|
document.cookie = cookieParts.join(';');
|
|
220
|
-
} catch (e) {
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
|
|
224
|
-
// ===================== 核心上报方法 =====================
|
|
225
|
-
/**
|
|
226
|
-
* 单次日志上报
|
|
227
|
-
* @param {Object} obj 下划线格式的上报数据
|
|
228
|
-
*/
|
|
229
|
-
superBatchReport: function (obj) {
|
|
230
|
-
var mergedItem = this.mergeReportItem(obj);
|
|
231
|
-
// 已为下划线字段,直接上报,移除驼峰转译逻辑
|
|
232
|
-
var dataObj = {
|
|
233
|
-
data: [mergedItem]
|
|
234
|
-
};
|
|
235
|
-
this.supersetAjax(dataObj);
|
|
301
|
+
} catch (e) { }
|
|
236
302
|
},
|
|
237
303
|
|
|
238
304
|
/**
|
|
239
|
-
*
|
|
240
|
-
* @param {
|
|
241
|
-
* @param {Object} commonInfo 可选-公共字段(设备信息,统一填充到所有条目)
|
|
242
|
-
*/
|
|
243
|
-
batchReporting: function (dataList, commonInfo) {
|
|
244
|
-
console.log('BatchReporting', dataList);
|
|
245
|
-
var exposureFlag = false;
|
|
246
|
-
for (var i = 0; i < dataList.length; i++) {
|
|
247
|
-
var item = dataList[i];
|
|
248
|
-
if (item.exposureFlag) {
|
|
249
|
-
exposureFlag = true;
|
|
250
|
-
break;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (!exposureFlag) {
|
|
255
|
-
var dataObj = {
|
|
256
|
-
"data": []
|
|
257
|
-
};
|
|
258
|
-
commonInfo = commonInfo || {};
|
|
259
|
-
|
|
260
|
-
for (var i = 0; i < dataList.length; i++) {
|
|
261
|
-
var item = dataList[i];
|
|
262
|
-
dataList[i].exposureFlag = true;
|
|
263
|
-
|
|
264
|
-
// 合并公共字段 + 当前条目字段
|
|
265
|
-
var reportItem = {};
|
|
266
|
-
for (var cKey in commonInfo) {
|
|
267
|
-
if (commonInfo.hasOwnProperty(cKey)) {
|
|
268
|
-
reportItem[cKey] = commonInfo[cKey];
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
for (var iKey in item) {
|
|
272
|
-
if (item.hasOwnProperty(iKey)) {
|
|
273
|
-
reportItem[iKey] = item[iKey];
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// 合并默认值,直接下划线结构推入数组
|
|
278
|
-
var mergedItem = this.mergeReportItem(reportItem);
|
|
279
|
-
dataObj.data.push(mergedItem);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
console.log(dataObj);
|
|
283
|
-
this.supersetAjax(dataObj);
|
|
284
|
-
}
|
|
285
|
-
},
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* 上报请求封装
|
|
289
|
-
* @param {Object} dataObj 完整的请求体
|
|
305
|
+
* 上报请求中转封装,调用底层ES5 ajax
|
|
306
|
+
* @param {Object} dataObj 完整上报报文 {user:{}, data:[]}
|
|
290
307
|
*/
|
|
291
308
|
supersetAjax: function (dataObj) {
|
|
292
309
|
this.ajax({
|
|
@@ -296,17 +313,17 @@ var supersetLewo = (function () {
|
|
|
296
313
|
dataType: 'json',
|
|
297
314
|
headers: [],
|
|
298
315
|
success: function (xhr, rsp) {
|
|
299
|
-
|
|
316
|
+
// 上报成功回调,业务可自行扩展
|
|
300
317
|
},
|
|
301
318
|
error: function (xhr, rsp) {
|
|
302
|
-
|
|
319
|
+
console.error('[supersetLewo 埋点上报失败]', rsp);
|
|
303
320
|
}
|
|
304
321
|
});
|
|
305
322
|
},
|
|
306
323
|
|
|
307
324
|
/**
|
|
308
|
-
*
|
|
309
|
-
* @param {Object} config
|
|
325
|
+
* ES5 底层原生XMLHttpRequest AJAX封装(还原最初版本逻辑,无Promise/Beacon)
|
|
326
|
+
* @param {Object} config 请求配置对象
|
|
310
327
|
*/
|
|
311
328
|
ajax: function (config) {
|
|
312
329
|
var url = config.url;
|
|
@@ -320,6 +337,7 @@ var supersetLewo = (function () {
|
|
|
320
337
|
var fnError = config.error || function () { };
|
|
321
338
|
var xmlhttp;
|
|
322
339
|
|
|
340
|
+
// 兼容IE低版本XMLHttpRequest
|
|
323
341
|
if (window.XMLHttpRequest) {
|
|
324
342
|
xmlhttp = new XMLHttpRequest();
|
|
325
343
|
} else {
|
|
@@ -330,16 +348,14 @@ var supersetLewo = (function () {
|
|
|
330
348
|
if (xmlhttp.readyState == 4) {
|
|
331
349
|
var rsp = xmlhttp.responseText || xmlhttp.responseXML;
|
|
332
350
|
var parseError = false;
|
|
333
|
-
//
|
|
351
|
+
// JSON解析异常捕获,防止页面报错
|
|
334
352
|
if (dataType == 'json' && typeof rsp == 'string') {
|
|
335
353
|
try {
|
|
336
354
|
rsp = JSON.parse(rsp);
|
|
337
355
|
} catch (e) {
|
|
338
356
|
parseError = true;
|
|
339
|
-
return;
|
|
340
357
|
}
|
|
341
358
|
}
|
|
342
|
-
|
|
343
359
|
if (parseError) {
|
|
344
360
|
fnError(xmlhttp, rsp);
|
|
345
361
|
} else if (xmlhttp.status == 200) {
|
|
@@ -351,61 +367,185 @@ var supersetLewo = (function () {
|
|
|
351
367
|
};
|
|
352
368
|
|
|
353
369
|
xmlhttp.open(type, url, dataAsync);
|
|
370
|
+
// 追加自定义请求头
|
|
354
371
|
for (var i = 0; i < headers.length; ++i) {
|
|
355
372
|
xmlhttp.setRequestHeader(headers[i].name, headers[i].value);
|
|
356
373
|
}
|
|
357
374
|
xmlhttp.setRequestHeader('Content-Type', contentType);
|
|
375
|
+
// 对象转JSON字符串发送
|
|
358
376
|
data = JSON.stringify(data);
|
|
359
377
|
xmlhttp.send(data);
|
|
360
|
-
}
|
|
378
|
+
},
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* 单条埋点事件上报
|
|
382
|
+
* @param {Object} eventParam 单条事件埋点参数,字段对齐data数组规范
|
|
383
|
+
*/
|
|
384
|
+
superBatchReport: function (eventParam) {
|
|
385
|
+
// 填充缺失默认字段与事件时间
|
|
386
|
+
var eventItem = fillEventDefault(eventParam);
|
|
387
|
+
// 组装标准上报报文
|
|
388
|
+
var reportBody = {
|
|
389
|
+
user: this.getUserInfo(), // 全局公共用户设备信息
|
|
390
|
+
data: [eventItem] // 单事件数组
|
|
391
|
+
};
|
|
392
|
+
this.supersetAjax(reportBody);
|
|
393
|
+
|
|
394
|
+
// return
|
|
395
|
+
|
|
396
|
+
try {
|
|
397
|
+
var action_type = eventParam.action_type == '点击' ? 'CLICK' : 'EXPOSURE'
|
|
398
|
+
var eventName = eventParam.element_position + '_' + action_type
|
|
399
|
+
|
|
400
|
+
// console.log('um-action_type', action_type)
|
|
401
|
+
// console.log('um-eventName', eventName)
|
|
402
|
+
// console.log('um-aplus_queue', aplus_queue)
|
|
403
|
+
aplus_queue.push({
|
|
404
|
+
action: 'aplus.record',
|
|
405
|
+
// 第二个参数事件类型:CLICK / EXPOSURE / PAGE等,常规点击用CLICK
|
|
406
|
+
arguments: [eventName, action_type, eventParam]
|
|
407
|
+
});
|
|
408
|
+
} catch (e) {
|
|
409
|
+
console.log("superBatchReport-umeng error", e)
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* 批量多条埋点事件上报(一次性上报多个行为,减少请求次数)
|
|
415
|
+
* @param {Array} eventList 多条埋点事件对象数组
|
|
416
|
+
*/
|
|
417
|
+
batchReporting: function (eventList) {
|
|
418
|
+
// 非数组/空数组直接终止上报
|
|
419
|
+
if (!Array.isArray(eventList) || eventList.length === 0) return;
|
|
420
|
+
// 批量填充每条事件默认参数
|
|
421
|
+
var filledData = [];
|
|
422
|
+
for (var i = 0; i < eventList.length; i++) {
|
|
423
|
+
filledData.push(fillEventDefault(eventList[i]));
|
|
424
|
+
}
|
|
425
|
+
// 组装批量上报报文
|
|
426
|
+
var reportBody = {
|
|
427
|
+
user: this.getUserInfo(),
|
|
428
|
+
data: filledData
|
|
429
|
+
};
|
|
430
|
+
this.supersetAjax(reportBody);
|
|
431
|
+
},
|
|
432
|
+
|
|
361
433
|
};
|
|
362
434
|
})();
|
|
363
435
|
|
|
364
|
-
//
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
436
|
+
// ===================== 使用示例(带详细注释) =====================
|
|
437
|
+
/**
|
|
438
|
+
* 示例1:页面初始化/登录后 设置全局用户设备公共信息,初始化友盟埋点SDK
|
|
439
|
+
* 仅需初始化一次,后续所有superBatchReport/batchReporting自动携带user参数
|
|
440
|
+
*/
|
|
441
|
+
// console.log("initUserInfo");
|
|
442
|
+
/*supersetLewo.initUserInfo({
|
|
443
|
+
os_type: "windows", // 系统类型安卓
|
|
444
|
+
os_version: "1", // 安卓版本15
|
|
445
|
+
app_version: "1.0.0", // APP版本号
|
|
446
|
+
app_item: "", // 渠道编码
|
|
447
|
+
app_name: "", // APP展示名称
|
|
448
|
+
app_project: "", // 产品内部编码
|
|
449
|
+
province: "100", // 省份编码
|
|
450
|
+
city: "", // 城市编码
|
|
451
|
+
uid: "", // 登录用户UID,未登录填空""
|
|
452
|
+
user_id: "", // 会员/游客ID,无则填空""
|
|
453
|
+
device_id: "", // 设备唯一ID,没有或不传则自动生成
|
|
454
|
+
device_brand: "", // 手机品牌小写
|
|
455
|
+
device_model: "", // 手机完整型号
|
|
456
|
+
network_type: "", // 蜂窝流量网络
|
|
457
|
+
carrier: "" // 运营商
|
|
458
|
+
// device_id 不传,内部自动生成UUID填充,无需手动传入
|
|
377
459
|
});*/
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
460
|
+
console.log("initUserInfo", supersetLewo.getUserInfo());
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* 示例2:单条埋点上报 - 首页曝光事件
|
|
464
|
+
* 调用superBatchReport,仅传入当前事件独有字段,公共user自动拼接
|
|
465
|
+
*/
|
|
466
|
+
|
|
467
|
+
/*setTimeout(function () {
|
|
468
|
+
supersetLewo.superBatchReport({
|
|
469
|
+
element_position: "Main_Start", // 元素位置编码
|
|
470
|
+
position_name: "游戏主页", // 中文位置名称
|
|
471
|
+
page_code: "", // OMS后台页面编码,无则空
|
|
472
|
+
page_name: "", // OMS后台页面名称,无则空
|
|
473
|
+
element_type: "page", // 元素类型页面
|
|
474
|
+
element_name: "gamestart", // 元素标识名
|
|
475
|
+
content_id: "10001", // 当前页面绑定内容ID
|
|
476
|
+
content_title: "我和美女有个约会", // 内容标题
|
|
477
|
+
action_type: "曝光", // 行为:曝光
|
|
478
|
+
action_value: "", // 行为值,时长填秒数,订购填金额(单位:分);无时间跨度行为填空
|
|
479
|
+
event_time: '' // event_time不传,内部自动生成当前时间
|
|
480
|
+
});
|
|
481
|
+
}, 2000);*/
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* 示例3:单条埋点上报 - 游戏卡片点击事件
|
|
486
|
+
*/
|
|
487
|
+
/*
|
|
488
|
+
supersetLewo.superBatchReport({
|
|
489
|
+
element_position: "Game_Card_List",
|
|
490
|
+
position_name: "游戏列表卡片",
|
|
491
|
+
element_type: "vlist",
|
|
492
|
+
element_name: "game_item",
|
|
493
|
+
content_id: "10002",
|
|
494
|
+
content_title: "开心消消乐",
|
|
495
|
+
action_type: "点击",
|
|
496
|
+
action_value: ""
|
|
497
|
+
});
|
|
498
|
+
*/
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* 示例4:批量埋点上报,一次性上报曝光+点击两条事件,减少http请求
|
|
502
|
+
* 调用batchReporting,传入事件数组
|
|
503
|
+
*/
|
|
504
|
+
/*
|
|
505
|
+
supersetLewo.batchReporting([
|
|
506
|
+
// 第一条:首页曝光
|
|
382
507
|
{
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
element_position: '3',
|
|
390
|
-
action_type: '曝光',
|
|
391
|
-
event_name: '4',
|
|
392
|
-
ad_request_id: '',
|
|
393
|
-
event_time: '',
|
|
508
|
+
element_position: "Main_Start",
|
|
509
|
+
position_name: "游戏主页",
|
|
510
|
+
element_type: "page",
|
|
511
|
+
content_id: "10001",
|
|
512
|
+
content_title: "我和美女有个约会",
|
|
513
|
+
action_type: "曝光"
|
|
394
514
|
},
|
|
515
|
+
// 第二条:游戏卡片点击
|
|
395
516
|
{
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
element_position: '3',
|
|
403
|
-
action_type: '曝光',
|
|
404
|
-
event_name: '4',
|
|
405
|
-
ad_request_id: '',
|
|
406
|
-
event_time: '',
|
|
517
|
+
element_position: "Game_Card_List",
|
|
518
|
+
position_name: "游戏列表卡片",
|
|
519
|
+
element_type: "vlist",
|
|
520
|
+
content_id: "10002",
|
|
521
|
+
content_title: "开心消消乐",
|
|
522
|
+
action_type: "点击"
|
|
407
523
|
}
|
|
408
|
-
])
|
|
524
|
+
]);
|
|
525
|
+
*/
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* 示例5:播放结束埋点(携带播放时长action_value,单位秒)
|
|
529
|
+
*/
|
|
530
|
+
/*
|
|
531
|
+
supersetLewo.superBatchReport({
|
|
532
|
+
element_position: "Game_Play_Page",
|
|
533
|
+
position_name: "游戏播放页",
|
|
534
|
+
element_type: "page",
|
|
535
|
+
content_id: "10003",
|
|
536
|
+
content_title: "夏日沙滩派对",
|
|
537
|
+
action_type: "结束播放",
|
|
538
|
+
action_value: "125" // 播放总时长125秒
|
|
539
|
+
});
|
|
540
|
+
*/
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* 示例6:清除游客设备ID(切换账号/清除本地标识使用)
|
|
544
|
+
*/
|
|
545
|
+
/*
|
|
546
|
+
supersetLewo.resetDeviceId();
|
|
547
|
+
*/
|
|
548
|
+
|
|
409
549
|
|
|
410
550
|
// CommonJS 模块导出(不改动上方 IIFE 逻辑)
|
|
411
551
|
if (typeof module !== 'undefined' && module.exports) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drgame-cc",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.20",
|
|
4
4
|
"description": "道然游戏适配包",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -32,8 +32,9 @@
|
|
|
32
32
|
"rimraf": "^5.0.0"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"
|
|
36
|
-
"
|
|
35
|
+
"fs-extra": "^11.2.0",
|
|
36
|
+
"pinyin-pro": "^3.28.2",
|
|
37
|
+
"typescript": "^5.0.0"
|
|
37
38
|
},
|
|
38
39
|
"peerDependencies": {
|
|
39
40
|
"typescript": "^5.0.0"
|