@bi-nova/ui-weapp 1.2.0 → 1.2.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bi-nova/ui-weapp",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "BI Nova SDK WeChat Mini Program Components",
5
5
  "miniprogram": "src",
6
6
  "license": "ISC",
package/src/ad/README.md CHANGED
@@ -42,6 +42,8 @@ yarn add @bi-nova/core @bi-nova/services @bi-nova/ui-weapp
42
42
  <bi-display-ad
43
43
  ad-id="ad_123456"
44
44
  type="banner"
45
+ equipment-value="{{equipmentValue}}"
46
+ user-id="{{userId}}"
45
47
  bind:load="handleAdLoad"
46
48
  bind:error="handleAdError"
47
49
  bind:close="handleAdClose"
@@ -56,16 +58,18 @@ yarn add @bi-nova/core @bi-nova/services @bi-nova/ui-weapp
56
58
 
57
59
  `bi-display-ad` 是广告组件的标准接入入口。业务侧仅需关注广告位 ID、广告类型和必要的展示控制参数。
58
60
 
59
- | 属性 | 类型 | 默认值 | 说明 |
60
- | --- | --- | --- | --- |
61
- | `ad-id` | `string` | `''` | 我方分配的广告位 ID。组件会根据该 ID 获取广告位配置并展示广告。 |
62
- | `type` | `'banner' \| 'splash'` | `'banner'` | 广告类型。仅支持 `banner` 和 `splash`。 |
63
- | `show` | `boolean` | `true` | 是否展示广告。对开屏广告的显隐控制更常用。 |
64
- | `z-index` | `number` | `999` | 开屏广告容器层级。 |
65
- | `picture-in-picture` | `boolean` | `false` | 开屏广告跳过后是否进入画中画状态。 |
66
- | `check-native-splash` | `boolean` | `true` | 开屏广告是否先检查微信系统开屏广告状态,设置为 `false` 可用于真机调试或强制展示远程开屏广告。 |
67
- | `native-splash-cache` | `boolean` | `true` | 是否缓存微信系统开屏广告承接记录,用于短时间内连续扫码时跳过残留的微信开屏状态检查。 |
68
- | `jump-seconds` | `number` | `5` | 开屏广告倒计时秒数。 |
61
+ | 属性 | 类型 | 默认值 | 说明 |
62
+ | --- | --- | --- |-------------------------------------------------------------|
63
+ | `ad-id` | `string` | `''` | 我方分配的广告位 ID。组件会根据该 ID 获取广告位配置并展示广告。 |
64
+ | `type` | `'banner' \| 'splash'` | `'banner'` | 广告类型。仅支持 `banner` 和 `splash`。 |
65
+ | `show` | `boolean` | `true` | 是否展示广告。对开屏广告的显隐控制更常用。 |
66
+ | `z-index` | `number` | `999` | 开屏广告容器层级。 |
67
+ | `picture-in-picture` | `boolean` | `false` | 开屏广告跳过后是否进入画中画状态。 |
68
+ | `check-native-splash` | `boolean` | `true` | 开屏广告是否先检查微信系统开屏广告状态,设置为 `false` 可用于真机调试或强制展示远程开屏广告。 |
69
+ | `native-splash-cache` | `boolean` | `true` | 是否缓存微信系统开屏广告承接记录,用于短时间内连续扫码时跳过残留的微信开屏状态检查。 |
70
+ | `jump-seconds` | `number` | `5` | 开屏广告倒计时秒数。 |
71
+ | `equipment-value` | `string` | `''` | 对接方真实设备标识。自营广告跳转类型为动态获取时必填 |
72
+ | `user-id` | `number` | `0` | 对接方真实用户 ID,必须传入正整数;默认值 `0` 仅表示未传入。自营广告跳转类型为动态获取时必填 |
69
73
 
70
74
  ## 广告位配置
71
75
 
@@ -150,6 +154,8 @@ getApp().globalData.biNova.clearToken()
150
154
  <bi-display-ad
151
155
  ad-id="launch_splash"
152
156
  type="splash"
157
+ equipment-value="{{equipmentValue}}"
158
+ user-id="{{userId}}"
153
159
  show="{{showSplash}}"
154
160
  z-index="{{999}}"
155
161
  picture-in-picture="{{true}}"
@@ -232,11 +238,13 @@ Page({
232
238
  | `BI_BANNER_CUSTOM_MEDIA_LOAD_FAIL` | Banner 自定义图片加载失败。 |
233
239
  | `BI_BANNER_NAVIGATE_MINI_PROGRAM_FAIL` | Banner 自定义广告跳转其他小程序失败。 |
234
240
  | `BI_BANNER_NAVIGATE_FAIL` | Banner 自定义广告跳转内部页面失败。 |
241
+ | `BI_BANNER_API_REQUEST_FAIL` | Banner 接口型自营广告请求失败。 |
235
242
  | `BI_SPLASH_WECHAT_AD_LOAD_FAIL` | 微信开屏广告加载失败。 |
236
243
  | `BI_SPLASH_CUSTOM_MEDIA_LOAD_TIMEOUT` | 开屏自定义素材加载超时。 |
237
244
  | `BI_SPLASH_CUSTOM_MEDIA_LOAD_FAIL` | 开屏自定义素材加载失败。 |
238
245
  | `BI_SPLASH_NAVIGATE_MINI_PROGRAM_FAIL` | 开屏自定义广告跳转其他小程序失败。 |
239
246
  | `BI_SPLASH_NAVIGATE_FAIL` | 开屏自定义广告跳转内部页面失败。 |
247
+ | `BI_SPLASH_API_REQUEST_FAIL` | 开屏接口型自营广告请求失败。 |
240
248
 
241
249
  自研素材加载失败或超时时,Banner 与开屏广告会额外返回以下统一字段:
242
250
 
@@ -3,7 +3,7 @@
3
3
  * @Author wutao
4
4
  * @Date 2026-04-10
5
5
  * @LastEditors wutao
6
- * @LastEditTime 2026-08-14 16:23:04
6
+ * @LastEditTime 2026-09-03 17:38:00
7
7
  */
8
8
  const {
9
9
  navigateCustomAd
@@ -14,7 +14,9 @@ Component({
14
14
  unitId: { type: String, value: '' },
15
15
  customAd: { type: Object, value: null },
16
16
  priority: { type: String, value: 'wechat-first' },
17
- adIntervals: { type: Number, value: 30 }
17
+ adIntervals: { type: Number, value: 30 },
18
+ equipmentValue: { type: String, value: '' },
19
+ userId: { type: Number, value: 0 }
18
20
  },
19
21
  data: {
20
22
  isWechatAd: false,
@@ -514,7 +516,13 @@ Component({
514
516
  },
515
517
  resolveEventDetail: (provider, event, extraDetail) => this.resolveEventDetail(provider, event, extraDetail),
516
518
  miniProgramErrorCode: 'BI_BANNER_NAVIGATE_MINI_PROGRAM_FAIL',
517
- navigateErrorCode: 'BI_BANNER_NAVIGATE_FAIL'
519
+ navigateErrorCode: 'BI_BANNER_NAVIGATE_FAIL',
520
+ apiRequestErrorCode: 'BI_BANNER_API_REQUEST_FAIL',
521
+ apiRequestParams: {
522
+ configId: this.properties.customAd && this.properties.customAd.configId,
523
+ equipmentValue: this.properties.equipmentValue,
524
+ userId: this.properties.userId
525
+ }
518
526
  })
519
527
  }
520
528
  }
@@ -3,7 +3,7 @@
3
3
  * @Author wutao
4
4
  * @Date 2026-04-10
5
5
  * @LastEditors wutao
6
- * @LastEditTime 2026-08-13 11:28:34
6
+ * @LastEditTime 2026-09-03 18:00:19
7
7
  */
8
8
  const SUPPORTED_TYPES = ['banner', 'splash']
9
9
  /** 微信系统开屏广告承接记录的本地缓存键前缀,用于按 appId 和广告位隔离缓存 */
@@ -27,7 +27,9 @@ Component({
27
27
  pictureInPicture: { type: Boolean, value: false },
28
28
  checkNativeSplash: { type: Boolean, value: true },
29
29
  nativeSplashCache: { type: Boolean, value: true },
30
- jumpSeconds: { type: Number, value: 5 }
30
+ jumpSeconds: { type: Number, value: 5 },
31
+ equipmentValue: { type: String, value: '' },
32
+ userId: { type: Number, value: 0 }
31
33
  },
32
34
  data: {
33
35
  resolvedType: 'banner',
@@ -64,7 +66,7 @@ Component({
64
66
  show: nextShow
65
67
  })
66
68
  },
67
- 'adId, adOptions, sdkKey, autoLoad'(nextAdId) {
69
+ 'adId, adOptions, sdkKey, autoLoad, userId'(nextAdId) {
68
70
  this.syncNativeSplashCheck()
69
71
 
70
72
  if (!nextAdId) {
@@ -195,14 +197,22 @@ Component({
195
197
  ? this.properties.adOptions
196
198
  : {}
197
199
  const appId = this.getMiniProgramAppId()
198
-
199
- return {
200
+ const userId = this.properties.userId
201
+ const requestOptions = {
200
202
  ...adOptions,
201
203
  adId: this.properties.adId,
202
204
  placementId: adOptions.placementId || this.properties.adId,
203
205
  appId: adOptions.appId || appId,
204
206
  type: this.data.resolvedType
205
207
  }
208
+
209
+ if (Number.isInteger(userId) && userId > 0) {
210
+ requestOptions.userId = userId
211
+ } else {
212
+ delete requestOptions.userId
213
+ }
214
+
215
+ return requestOptions
206
216
  },
207
217
 
208
218
  /**
@@ -4,6 +4,8 @@
4
4
  unit-id="{{resolvedUnitId}}"
5
5
  custom-ad="{{resolvedCustomAd}}"
6
6
  priority="{{resolvedPriority}}"
7
+ equipment-value="{{equipmentValue}}"
8
+ user-id="{{userId}}"
7
9
  ad-intervals="{{adIntervals}}"
8
10
  bind:load="handleLoad"
9
11
  bind:error="handleError"
@@ -19,6 +21,8 @@
19
21
  unit-id="{{resolvedUnitId}}"
20
22
  custom-ad="{{resolvedCustomAd}}"
21
23
  priority="{{resolvedPriority}}"
24
+ equipment-value="{{equipmentValue}}"
25
+ user-id="{{userId}}"
22
26
  show="{{resolvedShow}}"
23
27
  z-index="{{zIndex}}"
24
28
  picture-in-picture="{{pictureInPicture}}"
@@ -3,7 +3,7 @@
3
3
  * @Author wutao
4
4
  * @Date 2026-04-10
5
5
  * @LastEditors wutao
6
- * @LastEditTime 2026-08-18 11:38:13
6
+ * @LastEditTime 2026-09-03 17:38:00
7
7
  */
8
8
  const {
9
9
  navigateCustomAd
@@ -18,7 +18,9 @@ Component({
18
18
  zIndex: { type: Number, value: 999 },
19
19
  pictureInPicture: { type: Boolean, value: false },
20
20
  checkNativeSplash: { type: Boolean, value: true },
21
- jumpSeconds: { type: Number, value: 5 }
21
+ jumpSeconds: { type: Number, value: 5 },
22
+ equipmentValue: { type: String, value: '' },
23
+ userId: { type: Number, value: 0 }
22
24
  },
23
25
  data: {
24
26
  isWechatAd: false,
@@ -812,7 +814,13 @@ Component({
812
814
  },
813
815
  resolveEventDetail: (provider, event, extraDetail) => this.resolveEventDetail(provider, event, extraDetail),
814
816
  miniProgramErrorCode: 'BI_SPLASH_NAVIGATE_MINI_PROGRAM_FAIL',
815
- navigateErrorCode: 'BI_SPLASH_NAVIGATE_FAIL'
817
+ navigateErrorCode: 'BI_SPLASH_NAVIGATE_FAIL',
818
+ apiRequestErrorCode: 'BI_SPLASH_API_REQUEST_FAIL',
819
+ apiRequestParams: {
820
+ configId: customAd.configId,
821
+ equipmentValue: this.properties.equipmentValue,
822
+ userId: this.properties.userId
823
+ }
816
824
  })
817
825
  },
818
826
 
package/src/ad/utils.js CHANGED
@@ -3,13 +3,13 @@
3
3
  * @Author wutao
4
4
  * @Date 2026-04-17
5
5
  * @LastEditors wutao
6
- * @LastEditTime 2026-08-17 14:59:58
6
+ * @LastEditTime 2026-09-07 17:00:17
7
7
  */
8
8
 
9
9
  /**
10
10
  * 获取跳转目标类型
11
11
  * @param {Record<string, any> | null | undefined} customAd 自定义广告数据
12
- * @returns {'miniProgram' | 'internal' | 'web' | 'none'}
12
+ * @returns {'miniProgram' | 'internal' | 'web' | 'api' | 'none'}
13
13
  */
14
14
  function getNavigationType(customAd) {
15
15
  if (!customAd) return 'none'
@@ -20,6 +20,7 @@ function getNavigationType(customAd) {
20
20
  if (normalizedActionType === 'miniprogram') return 'miniProgram'
21
21
  if (normalizedActionType === 'internal') return 'internal'
22
22
  if (normalizedActionType === 'web') return 'web'
23
+ if (normalizedActionType === 'api') return 'api'
23
24
  if (normalizedActionType === 'none') return 'none'
24
25
 
25
26
  if (customAd.appId || customAd.targetAppId || customAd.miniProgramAppId || customAd.jumpAppId) {
@@ -70,7 +71,7 @@ function getMiniProgramOpenMode(customAd) {
70
71
  }
71
72
 
72
73
  /**
73
- * 获取 Web 跳转地址
74
+ * 获取 Web 跳转地址或接口请求地址
74
75
  * @param {Record<string, any> | null | undefined} customAd 自定义广告数据
75
76
  * @returns {string}
76
77
  */
@@ -79,6 +80,76 @@ function getWebUrl(customAd) {
79
80
  return customAd.action && customAd.action.url || customAd.url || customAd.jumpUrl || customAd.webUrl || customAd.h5Url || ''
80
81
  }
81
82
 
83
+ /**
84
+ * 判断接口查询参数是否已提供有效值
85
+ * @param {unknown} value 参数值
86
+ * @returns {boolean}
87
+ */
88
+ function hasQueryParamValue(value) {
89
+ return value !== undefined && value !== null && value !== ''
90
+ }
91
+
92
+ /**
93
+ * 向接口地址追加查询参数,并保留原有查询参数和哈希片段
94
+ * @param {string} url 接口地址
95
+ * @param {Record<string, string | number>} params 查询参数
96
+ * @returns {string}
97
+ */
98
+ function appendUrlQueryParams(url, params) {
99
+ const hashIndex = url.indexOf('#')
100
+ const hash = hashIndex >= 0 ? url.slice(hashIndex) : ''
101
+ const baseUrl = hashIndex >= 0 ? url.slice(0, hashIndex) : url
102
+ const query = Object.keys(params)
103
+ .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(String(params[key]))}`)
104
+ .join('&')
105
+
106
+ if (!query) return url
107
+
108
+ const separator = baseUrl.includes('?')
109
+ ? /[?&]$/.test(baseUrl) ? '' : '&'
110
+ : '?'
111
+
112
+ return `${baseUrl}${separator}${query}${hash}`
113
+ }
114
+
115
+ /**
116
+ * 处理接口型广告的请求结果
117
+ * @param {WechatMiniprogram.RequestSuccessCallbackResult} response 请求响应
118
+ * @param {Record<string, any>} context 广告点击上下文
119
+ * @returns {void}
120
+ */
121
+ function handleApiResponse(response, context) {
122
+ const responseData = response && response.data && typeof response.data === 'object'
123
+ ? response.data
124
+ : null
125
+ const responseBody = responseData && responseData.body && typeof responseData.body === 'object'
126
+ ? responseData.body
127
+ : null
128
+ const appId = String(responseBody && responseBody.appId || '').trim()
129
+ const path = String(responseBody && responseBody.url || '').trim().replace(/^\/+/, '')
130
+ const responseCode = String(responseData && responseData.code || '')
131
+
132
+ if (responseCode !== '200' || !appId || !path) {
133
+ context.onError({
134
+ ...context.resolveEventDetail(context.actionDetail.provider, null),
135
+ errCode: context.apiRequestErrorCode || 'BI_CUSTOM_AD_API_REQUEST_FAIL',
136
+ errMsg: responseData && responseData.message || '广告接口响应异常'
137
+ })
138
+ return
139
+ }
140
+
141
+ navigateCustomAd({
142
+ ...context,
143
+ customAd: {
144
+ action: {
145
+ type: 'miniProgram',
146
+ appId,
147
+ path
148
+ }
149
+ }
150
+ })
151
+ }
152
+
82
153
  /**
83
154
  * 执行自定义广告跳转
84
155
  * @param {Object} options 跳转参数
@@ -89,6 +160,8 @@ function getWebUrl(customAd) {
89
160
  * @param {(provider: 'wechat' | 'custom', event?: Record<string, any> | null, extraDetail?: Record<string, any>) => Record<string, any>} options.resolveEventDetail 事件合并方法
90
161
  * @param {string} options.miniProgramErrorCode 小程序跳转失败错误码
91
162
  * @param {string} options.navigateErrorCode 内部页面跳转失败错误码
163
+ * @param {string} [options.apiRequestErrorCode] 接口请求失败错误码
164
+ * @param {{configId?: number | string, equipmentValue?: string, userId?: number}} [options.apiRequestParams] 接口请求查询参数
92
165
  * @returns {void}
93
166
  */
94
167
  function navigateCustomAd(options) {
@@ -99,7 +172,9 @@ function navigateCustomAd(options) {
99
172
  onError,
100
173
  resolveEventDetail,
101
174
  miniProgramErrorCode,
102
- navigateErrorCode
175
+ navigateErrorCode,
176
+ apiRequestErrorCode,
177
+ apiRequestParams
103
178
  } = options
104
179
 
105
180
  if (!customAd) return
@@ -107,7 +182,7 @@ function navigateCustomAd(options) {
107
182
  const targetType = getNavigationType(customAd)
108
183
  const appId = getNavigationAppId(customAd)
109
184
  const path = getNavigationPath(customAd)
110
- const webUrl = getWebUrl(customAd)
185
+ const actionUrl = getWebUrl(customAd)
111
186
 
112
187
  if (targetType === 'miniProgram' && appId) {
113
188
  const miniProgramOpenMode = getMiniProgramOpenMode(customAd)
@@ -152,10 +227,57 @@ function navigateCustomAd(options) {
152
227
  return
153
228
  }
154
229
 
155
- if (targetType === 'web' && webUrl) {
230
+ if (targetType === 'web' && actionUrl) {
156
231
  onOpenWebview({
157
232
  ...actionDetail,
158
- url: webUrl
233
+ url: actionUrl
234
+ })
235
+ return
236
+ }
237
+
238
+ if (targetType === 'api' && actionUrl) {
239
+ if (typeof wx === 'undefined' || typeof wx.request !== 'function') return
240
+
241
+ const requestParams = apiRequestParams || {}
242
+ const requiredParamNames = ['configId', 'equipmentValue', 'userId']
243
+ const invalidParamNames = requiredParamNames.filter((name) => {
244
+ const value = requestParams[name]
245
+
246
+ if (name === 'userId') {
247
+ return !Number.isInteger(value) || value <= 0
248
+ }
249
+
250
+ return !hasQueryParamValue(value)
251
+ })
252
+
253
+ if (invalidParamNames.length) {
254
+ onError({
255
+ ...resolveEventDetail(actionDetail.provider, null),
256
+ errCode: apiRequestErrorCode || 'BI_CUSTOM_AD_API_REQUEST_FAIL',
257
+ errMsg: `接口型广告缺少必要参数或参数值无效:${invalidParamNames.join('、')}`
258
+ })
259
+ return
260
+ }
261
+
262
+ const requestUrl = appendUrlQueryParams(actionUrl, {
263
+ configId: requestParams.configId,
264
+ equipmentValue: requestParams.equipmentValue,
265
+ userId: requestParams.userId
266
+ })
267
+
268
+ wx.request({
269
+ url: requestUrl,
270
+ method: 'GET',
271
+ success: (response) => {
272
+ handleApiResponse(response, options)
273
+ },
274
+ fail: (error) => {
275
+ onError({
276
+ ...resolveEventDetail(actionDetail.provider, null),
277
+ errCode: apiRequestErrorCode || 'BI_CUSTOM_AD_API_REQUEST_FAIL',
278
+ errMsg: error && error.errMsg || '广告接口请求失败'
279
+ })
280
+ }
159
281
  })
160
282
  }
161
283
  }
@@ -166,5 +288,6 @@ module.exports = {
166
288
  getNavigationPath,
167
289
  getMiniProgramOpenMode,
168
290
  getWebUrl,
291
+ appendUrlQueryParams,
169
292
  navigateCustomAd
170
293
  }