qb-pc-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,20 @@
1
+ /**
2
+ * 参考文档: https://ylh.qq.com/help_detail.html?cid=5068&pid=12808
3
+ */
4
+
5
+ const YLH_AD_CONFIG = {
6
+ // 应用ID
7
+ appId: '1212355090',
8
+
9
+ // 广告位ID
10
+ // 注意:在API调用时使用 placementId 参数名
11
+ posId: '4204613922235231'
12
+ };
13
+
14
+ // 导出配置
15
+ if (typeof module !== 'undefined' && module.exports) {
16
+ module.exports = YLH_AD_CONFIG;
17
+ } else if (typeof window !== 'undefined') {
18
+ window.YLH_AD_CONFIG = YLH_AD_CONFIG;
19
+ }
20
+
package/package.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "qb-pc-sdk",
3
+ "version": "1.0.0",
4
+ "description": "PC端广告接入项目",
5
+ "dependencies": {
6
+ "qb-pc-ad-sdk-origin": "^1.0.0"
7
+ }
8
+ }
@@ -0,0 +1,216 @@
1
+ /**
2
+ * 趣变广告 SDK 封装器
3
+ * 自动处理多级接口映射与原生渲染逻辑
4
+ */
5
+ (function(window) {
6
+ 'use strict';
7
+
8
+ // 内部常量配置
9
+ const API_CONFIG = {
10
+ INIT: 'http://test.qubiankeji.com:8084/pc/init',
11
+ POSITION: 'http://test.qubiankeji.com:8084/pc/position',
12
+ GDT_SDK_ID: 2 // 标识
13
+ };
14
+
15
+ // 内部样式,确保广告一定有默认样式,不会塌缩
16
+ const INJECT_CSS = `
17
+ .q-ad-wrapper { display: flex; flex-direction: column; width: 100%; height: 100%; background: #fff; border: 1px solid #eee; overflow: hidden; font-family: sans-serif; position: relative; }
18
+ .q-media-container { width: 100%; height: 200px; background: #000; position: relative; display: flex; align-items: center; justify-content: center; }
19
+ .q-ad-img, .q-ad-video { width: 100%; height: 100%; object-fit: cover; display: block; }
20
+ .q-content-container { padding: 12px; flex: 1; display: flex; flex-direction: column; }
21
+ .q-ad-title { font-size: 16px; font-weight: bold; color: #333; margin: 0 0 5px 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
22
+ .q-ad-desc { font-size: 12px; color: #666; margin: 0 0 10px 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
23
+ .q-cta-btn { background: #007bff; color: #fff; border: none; padding: 6px 15px; border-radius: 4px; font-size: 12px; cursor: pointer; align-self: flex-start; }
24
+ .q-ad-tag { position: absolute; right: 5px; bottom: 5px; background: rgba(0,0,0,0.3); color: #fff; font-size: 10px; padding: 2px 4px; border-radius: 2px; }
25
+ `;
26
+
27
+ class AdSDKWrapper {
28
+ constructor(config) {
29
+ this.config = Object.assign({
30
+ appId: '',
31
+ placementId: '',
32
+ container: null,
33
+ onAdLoaded: null,
34
+ onAdError: null
35
+ }, config);
36
+
37
+ this.gdtAppId = null;
38
+ this.gdtPlacementId = null;
39
+ this.currentAd = null;
40
+
41
+ this._injectStyles();
42
+
43
+ this.container = typeof this.config.container === 'string'
44
+ ? document.querySelector(this.config.container)
45
+ : this.config.container;
46
+
47
+ if (this.container) {
48
+ this._initWorkflow();
49
+ } else {
50
+ console.error('[AdSDK] 找不到容器元素');
51
+ }
52
+ }
53
+
54
+ // 注入默认 CSS
55
+ _injectStyles() {
56
+ if (!document.getElementById('q-ad-styles')) {
57
+ const style = document.createElement('style');
58
+ style.id = 'q-ad-styles';
59
+ style.textContent = INJECT_CSS;
60
+ document.head.appendChild(style);
61
+ }
62
+ }
63
+
64
+ async _initWorkflow() {
65
+ try {
66
+ // 1. 获取 ID 映射及广告位配置
67
+ const [initRes, posRes] = await Promise.all([
68
+ fetch(`${API_CONFIG.INIT}?appId=${this.config.appId}`).then(r => r.json()),
69
+ fetch(`${API_CONFIG.POSITION}?positionId=${this.config.placementId}`).then(r => r.json())
70
+ ]);
71
+
72
+ // 2. 提取 AppID
73
+ this.gdtAppId = initRes.thirdIdMap ? initRes.thirdIdMap[String(API_CONFIG.GDT_SDK_ID)] : null;
74
+
75
+ // 3. 执行广告位筛选逻辑
76
+ this.gdtPlacementId = this._selectPlacementId(posRes);
77
+
78
+ if (!this.gdtAppId || !this.gdtPlacementId) {
79
+ throw new Error('未找到匹配的(sdkId:2)配置信息');
80
+ }
81
+
82
+ this._checkAndRun();
83
+ } catch (e) {
84
+ this._handleError(e, '初始化配置失败');
85
+ }
86
+ }
87
+
88
+ /**
89
+ * 核心逻辑:选择广告位 ID
90
+ * 规则:headSetList优先;否则选positionSetList中优先级最高的
91
+ */
92
+ _selectPlacementId(data) {
93
+ // A. 优先检查 headSetList
94
+ if (data.headSetList && data.headSetList.length > 0) {
95
+ const headAd = data.headSetList.find(item => item.sdkId === API_CONFIG.GDT_SDK_ID);
96
+ if (headAd) return headAd.positionId;
97
+ }
98
+
99
+ // B. 检查 positionSetList
100
+ if (data.positionSetList && data.positionSetList.length > 0) {
101
+ const sortedList = data.positionSetList
102
+ .filter(item => item.sdkId === API_CONFIG.GDT_SDK_ID)
103
+ .sort((a, b) => b.callbackPriority - a.callbackPriority); // 按优先级从大到小排序
104
+
105
+ return sortedList.length > 0 ? sortedList[0].positionId : null;
106
+ }
107
+
108
+ return null;
109
+ }
110
+
111
+ _checkAndRun() {
112
+ let attempts = 0;
113
+ const check = () => {
114
+ if (window.GDTAdSDK) {
115
+ this._loadAd();
116
+ } else if (attempts++ < 50) {
117
+ setTimeout(check, 100);
118
+ } else {
119
+ this._handleError('SDK Load Timeout', '底层SDK加载超时');
120
+ }
121
+ };
122
+ check();
123
+ }
124
+
125
+ async _loadAd() {
126
+ try {
127
+ // 初始化底层 SDK
128
+ await window.GDTAdSDK.init({ appId: this.gdtAppId });
129
+
130
+ // 加载数据
131
+ const ads = await window.GDTAdSDK.loadNativeAdData({
132
+ placementId: this.gdtPlacementId,
133
+ count: 1
134
+ });
135
+
136
+ if (ads && ads.length > 0) {
137
+ this.renderAd(ads[0]);
138
+ } else {
139
+ this._handleError('No Ad Fill', '当前没有广告填充');
140
+ }
141
+ } catch (err) {
142
+ this._handleError(err, '拉取广告数据失败');
143
+ }
144
+ }
145
+
146
+ /**
147
+ * 渲染广告 DOM 并绑定事件
148
+ */
149
+ renderAd(ad) {
150
+ this.currentAd = ad;
151
+
152
+ // 构建 HTML 结构
153
+ this.container.innerHTML = `
154
+ <div class="q-ad-wrapper">
155
+ <div class="q-media-container">
156
+ <div class="q-ad-video" style="display:none"></div>
157
+ <img class="q-ad-img" style="display:none">
158
+ <span class="q-ad-tag">广告</span>
159
+ </div>
160
+ <div class="q-content-container">
161
+ <h3 class="q-ad-title">${ad.getTitle()}</h3>
162
+ <p class="q-ad-desc">${ad.getDescription()}</p>
163
+ <button class="q-cta-btn">${ad.getBtnText() || '查看详情'}</button>
164
+ </div>
165
+ </div>
166
+ `;
167
+
168
+ const videoEl = this.container.querySelector('.q-ad-video');
169
+ const imgEl = this.container.querySelector('.q-ad-img');
170
+ const wrapper = this.container.querySelector('.q-ad-wrapper');
171
+ const clickable = [
172
+ this.container.querySelector('.q-ad-title'),
173
+ this.container.querySelector('.q-cta-btn'),
174
+ imgEl,
175
+ videoEl
176
+ ];
177
+
178
+ // 绑定曝光和点击
179
+ ad.bindAdToView({
180
+ containerView: wrapper,
181
+ clickableElements: clickable,
182
+ adEventListener: {
183
+ onExpose: () => {
184
+ if (this.config.onAdExpose) this.config.onAdExpose();
185
+ },
186
+ onClick: () => {
187
+ if (this.config.onAdClick) this.config.onAdClick();
188
+ }
189
+ }
190
+ });
191
+
192
+ // 处理视频或图片素材
193
+ if (ad.hasVideo()) {
194
+ videoEl.style.display = 'block';
195
+ ad.bindMediaView({
196
+ mediaView: videoEl,
197
+ videoOption: { muted: true, autoplay: true }
198
+ });
199
+ } else {
200
+ imgEl.style.display = 'block';
201
+ imgEl.src = ad.getImageUrl();
202
+ }
203
+
204
+ if (this.config.onAdLoaded) this.config.onAdLoaded(ad);
205
+ }
206
+
207
+ _handleError(error, message) {
208
+ console.error(`[AdSDK Error] ${message}:`, error);
209
+ if (this.config.onAdError) {
210
+ this.config.onAdError(error, message);
211
+ }
212
+ }
213
+ }
214
+
215
+ window.AdSDK = AdSDKWrapper;
216
+ })(window);
@@ -0,0 +1,36 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Native广告接入示例</title>
7
+ <style>
8
+ body { margin: 0; padding: 20px; font-family: sans-serif; background: #f0f2f5; }
9
+ #ad-slot-1 {
10
+ width: 400px;
11
+ height: 300px;
12
+ margin: 0 auto;
13
+ background: #fff;
14
+ }
15
+ </style>
16
+ </head>
17
+ <body>
18
+ <div id="ad-slot-1"></div>
19
+
20
+ <script src="https://qzs.gdtimg.com/union/res/pc/ylh-pc-ad-sdk.v1.25.25.js"></script>
21
+ <script src="ad-sdk-wrapper.js"></script>
22
+
23
+ <script>
24
+ window.addEventListener('DOMContentLoaded', () => {
25
+ new AdSDK({
26
+ appId: '1999336062823956569',
27
+ placementId: '1999381081819709520',
28
+ container: '#ad-slot-1',
29
+ onAdLoaded: () => console.log('✅ 广告加载完成'),
30
+ onAdError: (err) => console.log('❌ 广告报错:', err),
31
+ onAdClick: () => console.log('🖱️ 用户点击了广告')
32
+ });
33
+ });
34
+ </script>
35
+ </body>
36
+ </html>
@@ -0,0 +1,34 @@
1
+ @echo off
2
+ chcp 65001 >nul
3
+ echo ========================================
4
+ echo 广告接入 - 启动本地服务器
5
+ echo ========================================
6
+ echo.
7
+
8
+ REM 检查是否安装了Node.js
9
+ where node >nul 2>&1
10
+ if %ERRORLEVEL% NEQ 0 (
11
+ echo [错误] 未检测到Node.js
12
+ echo 请先安装Node.js: https://nodejs.org/
13
+ echo.
14
+ pause
15
+ exit /b 1
16
+ )
17
+
18
+ echo [信息] 检测到Node.js
19
+ node --version
20
+ echo.
21
+
22
+ echo [信息] 正在启动HTTP服务器(已启用CORS)...
23
+ echo [信息] 服务器地址: http://localhost:8080
24
+ echo [信息] 访问地址: http://localhost:8080/src/example-simple.html
25
+ echo.
26
+ echo [提示] 按 Ctrl+C 停止服务器
27
+ echo ========================================
28
+ echo.
29
+
30
+ REM 启动服务器(启用CORS)
31
+ npx http-server -p 8080 --cors
32
+
33
+ pause
34
+