my-uniapp-tools 4.2.1 → 5.0.2
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/README.md +55 -27
- package/dist/index.d.ts +1 -1
- package/dist/my-uniapp-tools.cjs.js +1 -1
- package/dist/my-uniapp-tools.esm.js +1 -1
- package/dist/navigation/index.d.ts +40 -138
- package/dist/ui/index.d.ts +3 -0
- package/dist/upload/index.d.ts +13 -151
- package/dist/utils/index.d.ts +19 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -81,8 +81,8 @@ await copyText('要复制的文本', {
|
|
|
81
81
|
showToast: true, // 是否显示提示
|
|
82
82
|
successMessage: '复制成功', // 成功提示文本
|
|
83
83
|
failMessage: '复制失败', // 失败提示文本
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
timeout: 5000 // 超时时间(ms)
|
|
85
|
+
});
|
|
86
86
|
```
|
|
87
87
|
|
|
88
88
|
### 💾 本地存储功能
|
|
@@ -240,32 +240,35 @@ clearSystemCache();
|
|
|
240
240
|
|
|
241
241
|
### 📤 文件上传功能
|
|
242
242
|
|
|
243
|
-
> **重要变更**:
|
|
243
|
+
> **重要变更**: v5.0.0 扁平化 UploadOptions,移除历史兼容层与多层嵌套配置
|
|
244
244
|
|
|
245
245
|
#### selectAndUpload(options) ⭐ 核心API
|
|
246
246
|
|
|
247
247
|
选择并上传文件(一体化业务入口)
|
|
248
248
|
|
|
249
|
-
**参数
|
|
249
|
+
**参数 UploadOptions(v5):**
|
|
250
|
+
|
|
250
251
|
- `url` (string, 必须): 上传地址
|
|
251
|
-
- `
|
|
252
|
+
- `files` (UniFile[]): 直接上传已有文件(跳过选择阶段)
|
|
253
|
+
- `type` ('image' | 'file' | 'any'): 文件类型(选择阶段),默认 'image'
|
|
252
254
|
- `count` (number): 最多选择文件数,默认 1
|
|
253
|
-
- `
|
|
254
|
-
- `
|
|
255
|
-
- `extensions` (string[]): 允许的文件扩展名,如 ['jpg', 'png']
|
|
255
|
+
- `maxSizeMB` (number): 文件体积限制(MB),`0` 表示不允许选择/上传任何文件
|
|
256
|
+
- `extensions` (string[]): 允许的文件扩展名白名单(严格模式),如 ['jpg', 'png']
|
|
256
257
|
- `fieldName` (string): 文件字段名,默认 'file'
|
|
257
258
|
- `formData` (Record<string, any>): 额外的表单数据
|
|
258
259
|
- `headers` (Record<string, string>): 自定义请求头
|
|
259
|
-
- `
|
|
260
|
-
- `
|
|
261
|
-
- `
|
|
260
|
+
- `timeoutMs` (number): 上传超时时间(ms)
|
|
261
|
+
- `autoRevokeObjectURL` (boolean): H5环境下是否自动回收 blob URL
|
|
262
|
+
- `concurrency` (number): 最大并发上传数(不传默认全并发)
|
|
263
|
+
- `signal` (AbortSignal): 取消信号(AbortController.signal)
|
|
262
264
|
- `beforeUpload` (function): 上传前拦截钩子,返回 false 跳过该文件
|
|
263
|
-
- `showToast` (boolean): 是否显示提示,默认 true
|
|
264
|
-
- `successMessage` (string): 成功提示文本
|
|
265
|
-
- `failMessage` (string): 失败提示文本
|
|
266
265
|
- `onProgress` (function): 进度回调 (file, progress) => void
|
|
266
|
+
- `showToast` (boolean): 是否显示提示,默认 true
|
|
267
|
+
- `successMessage` (string): 成功提示文本(单文件成功时)
|
|
268
|
+
- `failMessage` (string): 失败提示文本(保留字段)
|
|
267
269
|
|
|
268
270
|
**返回值**: `Promise<UploadResult[]>`
|
|
271
|
+
|
|
269
272
|
- `file` (UniFile | null): 文件信息
|
|
270
273
|
- `success` (boolean): 是否成功
|
|
271
274
|
- `statusCode` (number): HTTP状态码
|
|
@@ -278,7 +281,7 @@ const results = await selectAndUpload({
|
|
|
278
281
|
url: 'https://api.example.com/upload',
|
|
279
282
|
type: 'image',
|
|
280
283
|
count: 3,
|
|
281
|
-
|
|
284
|
+
maxSizeMB: 5,
|
|
282
285
|
formData: { userId: '123' },
|
|
283
286
|
headers: { 'Authorization': 'Bearer token' },
|
|
284
287
|
onProgress: (file, progress) => {
|
|
@@ -303,7 +306,7 @@ results.forEach((result) => {
|
|
|
303
306
|
const results = await selectAndUploadImage({
|
|
304
307
|
url: 'https://api.example.com/upload',
|
|
305
308
|
count: 1,
|
|
306
|
-
|
|
309
|
+
maxSizeMB: 5
|
|
307
310
|
});
|
|
308
311
|
```
|
|
309
312
|
|
|
@@ -335,15 +338,29 @@ const results = await selectAndUpload({
|
|
|
335
338
|
url: 'https://api.example.com/upload',
|
|
336
339
|
type: 'file',
|
|
337
340
|
extensions: ['pdf', 'doc', 'docx'],
|
|
338
|
-
|
|
341
|
+
maxSizeMB: 20
|
|
339
342
|
});
|
|
340
343
|
```
|
|
341
344
|
|
|
342
345
|
### 💳 支付(微信公众号 H5)
|
|
343
346
|
|
|
344
|
-
#### weChatOfficialAccountPayment(config,
|
|
347
|
+
#### weChatOfficialAccountPayment(config, options?)
|
|
348
|
+
|
|
349
|
+
在微信内置浏览器中调起支付,返回结构化的支付结果
|
|
350
|
+
|
|
351
|
+
**参数**:
|
|
345
352
|
|
|
346
|
-
|
|
353
|
+
- `config` (WeChatPayConfig): 微信支付配置对象
|
|
354
|
+
- `options` (WeChatPayOptions): 可选配置
|
|
355
|
+
- `reportError` (boolean): 是否上报错误到 ErrorHandler,默认 true
|
|
356
|
+
|
|
357
|
+
**返回值**: `Promise<PaymentResult>`
|
|
358
|
+
|
|
359
|
+
- `success` (boolean): 是否支付成功
|
|
360
|
+
- `status` ('success' | 'error' | 'cancel'): 支付状态
|
|
361
|
+
- `code` (string): 状态码
|
|
362
|
+
- `message` (string): 状态描述
|
|
363
|
+
- `raw` (WeChatPayResult | null): 微信原始回调数据
|
|
347
364
|
|
|
348
365
|
```javascript
|
|
349
366
|
import { weChatOfficialAccountPayment } from 'my-uniapp-tools';
|
|
@@ -354,15 +371,26 @@ const payConfig = await fetch('/api/pay/wechat/unified-order', {
|
|
|
354
371
|
body: JSON.stringify({ orderId: '123456' })
|
|
355
372
|
}).then(r => r.json());
|
|
356
373
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
)
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
374
|
+
// 调用支付(结构化返回值)
|
|
375
|
+
const result = await weChatOfficialAccountPayment(payConfig);
|
|
376
|
+
|
|
377
|
+
// 根据支付结果处理
|
|
378
|
+
if (result.success) {
|
|
379
|
+
uni.showToast({ title: '支付成功', icon: 'success' });
|
|
380
|
+
// 处理支付成功逻辑
|
|
381
|
+
} else if (result.status === 'cancel') {
|
|
382
|
+
uni.showToast({ title: '已取消支付', icon: 'none' });
|
|
383
|
+
} else {
|
|
384
|
+
uni.showToast({
|
|
385
|
+
title: result.message || '支付失败',
|
|
386
|
+
icon: 'none'
|
|
387
|
+
});
|
|
365
388
|
}
|
|
389
|
+
|
|
390
|
+
// 测试时禁用错误上报
|
|
391
|
+
const result = await weChatOfficialAccountPayment(payConfig, {
|
|
392
|
+
reportError: false
|
|
393
|
+
});
|
|
366
394
|
```
|
|
367
395
|
|
|
368
396
|
### 🛠️ 工具函数
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("@vant/area-data");class t extends Error{code;module;timestamp;constructor(e,t,n){super(t),this.name="UniAppToolsError",this.code=e,this.module=n,this.timestamp=Date.now()}}class n{static instance;errorCallbacks=[];static getInstance(){return n.instance||(n.instance=new n),n.instance}onError(e){this.errorCallbacks.push(e)}handleError(e,n){const r={code:e instanceof t?e.code:"UNKNOWN_ERROR",message:e.message,module:e instanceof t?e.module:n,timestamp:e instanceof t?e.timestamp:Date.now(),stack:e.stack};console.error(`[${r.module}] ${r.code}: ${r.message}`,r),this.errorCallbacks.forEach(e=>{try{e(r)}catch(e){console.error("Error in error callback:",e)}})}createModuleErrorHandler(e){return(n,r,s)=>{const o=new t(n,r,e);return s&&(o.stack=s.stack),this.handleError(o,e),o}}}async function r(e,t,r="ASYNC_ERROR"){try{return await e()}catch(e){return n.getInstance().createModuleErrorHandler(t)(r,`异步操作失败: ${e instanceof Error?e.message:String(e)}`,e),null}}function s(e,t,r="SYNC_ERROR",s=null){try{return e()}catch(e){return n.getInstance().createModuleErrorHandler(t)(r,`同步操作失败: ${e instanceof Error?e.message:String(e)}`,e),s}}const o=n.getInstance();let a=null,i=null,c=null;const l=e=>"weixin"===e||"alipay"===e;let u=!1;const f=()=>{if(a)return a;let e="unknown";try{"undefined"!=typeof uni&&("undefined"!=typeof wx&&wx.getSystemInfoSync?e="weixin":"undefined"!=typeof my&&my.getSystemInfoSync?e="alipay":"undefined"!=typeof window&&window.document?e="h5":"undefined"!=typeof plus&&(e="app"))}catch(t){e="weixin",e="web",e="app",e="alipay",e="h5"}return a=e,e},p=(e=!0)=>e&&c?c:s(()=>{const t=uni.getWindowInfo();return e&&(c=t),t},"system","GET_WINDOW_INFO_ERROR",null),d=()=>{if(null!==i)return i;try{const e=p();return i=e?.statusBarHeight||0,i}catch(e){return o.handleError(new t("GET_STATUS_BAR_HEIGHT_ERROR",`获取状态栏高度失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),0}},m=()=>{try{const e=f();return l(e)?uni.getMenuButtonBoundingClientRect():null}catch(e){return o.handleError(new t("GET_MENU_BUTTON_ERROR",`获取菜单按钮边界信息失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),null}},g=()=>{try{const e=f();if(l(e)){const e=m();return e?.height||44}return 44}catch(e){return o.handleError(new t("GET_NAVIGATION_BAR_HEIGHT_ERROR",`获取导航栏高度失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),44}},h=()=>{const e=f(),t=d(),n=g();return{platform:e,statusBarHeight:t,navigationBarHeight:n,totalTopHeight:t+n}},y=n.getInstance();function w(e){if(null===e||"object"!=typeof e)return e;try{if("undefined"!=typeof structuredClone)try{return structuredClone(e)}catch(e){}return JSON.parse(JSON.stringify(e))}catch(e){throw y.handleError(new t("DEEP_CLONE_ERROR",`深拷贝失败: ${e instanceof Error?e.message:String(e)}`,"utils"),"utils"),new Error(`深拷贝失败: ${e instanceof Error?e.message:String(e)}`)}}function E(e,t,n=!1){let r,s=null;const o=function(...o){const a=n&&!s;return s&&clearTimeout(s),s=setTimeout(()=>{s=null,n||(r=e.apply(this,o))},t),a&&(r=e.apply(this,o)),r};return o.cancel=()=>{s&&(clearTimeout(s),s=null)},o}function S(e,t,n={}){let r,s=null,o=0;const{leading:a=!0,trailing:i=!0}=n,c=function(...n){const c=Date.now();o||a||(o=c);const l=t-(c-o);return l<=0||l>t?(s&&(clearTimeout(s),s=null),o=c,r=e.apply(this,n)):!s&&i&&(s=setTimeout(()=>{o=a?Date.now():0,s=null,r=e.apply(this,n)},l)),r};return c.cancel=()=>{s&&(clearTimeout(s),s=null),o=0},c}const T=e.areaList,v=e.useCascaderAreaData,R=(e="",t=!1,n="none",r=2e3)=>{uni.showToast({title:e,icon:n,mask:t,duration:r})},x=n.getInstance();function _(e,t){if(!t||0===Object.keys(t).length)return e;const n=Object.entries(t).map(([e,t])=>`${encodeURIComponent(e)}=${encodeURIComponent(String(t))}`).join("&");return e+(e.includes("?")?"&":"?")+n}function A(e,n){x.handleError(new t(e,n,"navigation"),"navigation")}async function P(e){return new Promise(t=>{const n=_(e.url,e.params);uni.navigateTo({url:n,animationType:e.animationType,animationDuration:e.animationDuration,events:e.events,success:()=>t(!0),fail:e=>{A("NAVIGATE_TO_FAILED",`页面跳转失败: ${n}`),t(!1)}})})}async function b(e){return new Promise(t=>{const n=_(e.url,e.params);uni.reLaunch({url:n,success:()=>t(!0),fail:e=>{A("RELAUNCH_FAILED",`重新启动失败: ${n}`),t(!1)}})})}async function L(e="",t={}){return new Promise(n=>{const r=t.delta||1,s=t.timeout||5e3;if(getCurrentPages().length<=r)return console.warn(`[navigation] 无法返回${r}页,当前页面栈深度不足`),void n(!1);const o=setTimeout(()=>{console.warn("[navigation] 导航返回超时"),n(!1)},s);uni.navigateBack({delta:r,success:()=>{clearTimeout(o),setTimeout(()=>{try{const t=getCurrentPages();if(t.length>0){const n=t[t.length-1];n.$vm&&"function"==typeof n.$vm.init&&n.$vm.init(e)}n(!0)}catch(e){A("PAGE_CALLBACK_ERROR",`页面回调执行失败: ${e instanceof Error?e.message:String(e)}`),n(!0)}},100)},fail:e=>{clearTimeout(o),A("NAVIGATE_BACK_FAILED","导航返回失败"),n(!1)}})})}const C=E(L,300),O={showToast:!0,successMessage:"复制成功",failMessage:"复制失败",timeout:5e3},I=n.getInstance();class ${static instance;cache=new Map;maxCacheSize=100;static getInstance(){return $.instance||($.instance=new $),$.instance}isExpired(e){return!!e.ttl&&Date.now()-e.timestamp>e.ttl}set(e,n,r={}){try{if(!e||"string"!=typeof e)throw new Error("存储键不能为空");const t={value:n,timestamp:Date.now(),ttl:r.ttl},s=JSON.stringify(t);if(s.length>1048576)throw new Error("存储数据过大");if(uni.setStorageSync(e,s),this.cache.size>=this.maxCacheSize){const e=this.cache.keys().next().value;e&&this.cache.delete(e)}return this.cache.set(e,t),!0}catch(e){throw I.handleError(new t("SET_STORAGE_ERROR",`设置存储失败: ${e instanceof Error?e.message:String(e)}`,"localStorage"),"localStorage"),e}}get(e,t){try{if(!e||"string"!=typeof e)return t;if(this.cache.has(e)){const n=this.cache.get(e);return this.isExpired(n)?(this.cache.delete(e),this.remove(e),t):n.value}const n=uni.getStorageSync(e);if(!n||"string"!=typeof n)return t;const r=JSON.parse(n);let s;return s=r&&"object"==typeof r&&"value"in r&&"timestamp"in r?r:{value:r,timestamp:Date.now()},this.isExpired(s)?(this.remove(e),t):(this.cache.set(e,s),s.value)}catch(n){return console.warn(`[localStorage] 获取存储失败 [${e}]:`,n),t}}remove(e){try{return!(!e||"string"!=typeof e||(uni.removeStorageSync(e),this.cache.delete(e),0))}catch(n){return I.handleError(new t("REMOVE_STORAGE_ERROR",`删除存储失败: ${e}`,"localStorage"),"localStorage"),!1}}clear(){try{return uni.clearStorageSync(),this.cache.clear(),!0}catch(e){return I.handleError(new t("CLEAR_STORAGE_ERROR","清空存储失败","localStorage"),"localStorage"),!1}}getInfo(){try{const e=uni.getStorageInfoSync();return{keys:e.keys||[],currentSize:e.currentSize||0,limitSize:e.limitSize||0}}catch(e){return I.handleError(new t("GET_STORAGE_INFO_ERROR",`获取存储信息失败: ${e instanceof Error?e.message:String(e)}`,"localStorage"),"localStorage"),{keys:[],currentSize:0,limitSize:0}}}cleanExpired(){try{const e=this.getInfo();let t=0;return e.keys.forEach(e=>{void 0===this.get(e)&&t++}),t}catch(e){return I.handleError(new t("CLEAN_EXPIRED_ERROR",`清理过期数据失败: ${e instanceof Error?e.message:String(e)}`,"localStorage"),"localStorage"),0}}}const U=$.getInstance();function D(e,t,n={}){return U.set(e,t,n)}function N(e,t){return U.get(e,t)}function M(e){if(!e)return;const t=e.split(/[?#]/)[0].match(/\.([^./\\]+)$/);return t?t[1].toLowerCase():void 0}function k(e){if(e&&"string"==typeof e)return{"image/jpeg":"jpg","image/jpg":"jpg","image/png":"png","image/gif":"gif","image/webp":"webp","image/heic":"heic","image/heif":"heif","video/mp4":"mp4","application/pdf":"pdf","text/plain":"txt","application/zip":"zip","application/x-zip-compressed":"zip","application/msword":"doc","application/vnd.openxmlformats-officedocument.wordprocessingml.document":"docx","application/vnd.ms-excel":"xls","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":"xlsx"}[e.toLowerCase().trim()]}function j(e){const t=e.toLowerCase().replace(/^\./,"");return"jpeg"===t||"jpe"===t?"jpg":t}function F(e){return`${Date.now()}_${e}_${Math.random().toString(16).slice(2)}`}function H(e){return"string"==typeof e&&e.startsWith("blob:")}function B(e){if(H(e)&&"undefined"!=typeof URL&&"function"==typeof URL.revokeObjectURL)try{URL.revokeObjectURL(e)}catch{}}function z(e){if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return e}}function J(e){if(null==e)return"";const t=typeof e;if("string"===t||"number"===t||"boolean"===t)return String(e);if("object"===t)try{return JSON.stringify(e)}catch{return String(e)}return String(e)}function G(e){if(!e)return;const t={};return Object.keys(e).forEach(n=>{t[n]=J(e[n])}),t}class W{isShowing=!1;updateToastThrottled=null;showTitle(e){this.isShowing?this.updateToastThrottled&&this.updateToastThrottled(e):(this.showLoading(e),this.isShowing=!0,this.updateToastThrottled=S(e=>{this.isShowing&&this.showLoading(e)},200,{leading:!0,trailing:!0}))}show(e,t,n={}){const{currentIndex:r,totalCount:s,formatter:o}=n;let a;a=o?o(e,t,r,s):s&&s>1&&r?`上传中 (${r}/${s}) ${t}%`:`上传中 ${t}%`,this.showTitle(a)}hide(){if(!this.isShowing)return;try{this.updateToastThrottled?.cancel?.()}catch{}this.isShowing=!1,this.updateToastThrottled=null;const e="undefined"==typeof uni?null:uni;if(e&&"function"==typeof e.hideLoading)try{e.hideLoading()}catch{}}showLoading(e){const t="undefined"==typeof uni?null:uni;if(t&&"function"==typeof t.showLoading)try{t.showLoading({title:e,mask:!0})}catch{}}}function K(e,t){return null==t||"number"!=typeof t||!Number.isFinite(t)||t<0?{valid:!0}:e>1024*t*1024?{valid:!1,message:`文件大小不能超过 ${t}MB`}:{valid:!0}}function Y(e,t){if(0===e.length)return{success:!1,files:e,message:"未选择任何文件"};const{maxSelectFileSizeMB:n,extensions:r}=t,s=t.extensionValidationPolicy||"strict",o=null!=n,a=Array.isArray(r)&&r.length>0,i=a?new Set(r.map(e=>j(e))):null;if(o&&0===n)return{success:!1,files:e,message:"当前不允许选择文件"};let c=!1;for(const t of e){if(o&&!K(t.size,n).valid)return{success:!1,files:e,message:`部分文件大小超过 ${n}MB 限制`};if(a&&i){const e=t.ext?j(t.ext):void 0;if(e)i.has(e)||(c=!0);else if("allowNoExtension"===s);else if("mimeTypeFallback"===s){const e=k(t.mimeType),n=e?j(e):void 0;n&&i.has(n)||(c=!0)}else c=!0}}return c?{success:!1,files:e,message:`存在不支持的文件类型,仅支持:${r?.join(", ")}`}:{success:!0,files:e}}async function q(e,t,n,r){const{url:s,maxUploadFileSizeMB:o,showToast:a=!0,beforeUpload:i}=t,c=t.toast||R;if(t.signal?.aborted){const t="已取消上传";return a&&c(t,!1,"none"),Promise.resolve({file:e,success:!1,message:t})}if("function"==typeof i)try{if(!await Promise.resolve(i(e)))return t.autoRevokeObjectURL&&"h5"===e.platform&&B(e.path),{file:e,success:!1,message:"已取消上传"}}catch(n){console.error("[Upload] beforeUpload 钩子执行异常:",n);const r=n instanceof Error?`上传前检查失败: ${n.message}`:"上传前检查失败";return a&&c(r,!1,"error"),t.autoRevokeObjectURL&&"h5"===e.platform&&B(e.path),{file:e,success:!1,message:r}}if(!s){const t="上传地址不能为空";return a&&c(t,!1,"error"),Promise.resolve({file:e,success:!1,message:t})}const l=K(e.size,o);return l.valid?"h5"===e.platform&&e.raw instanceof File?function(e,t,n,r){const{url:s,fieldName:o="file",formData:a,headers:i,showToast:c=!0,successMessage:l="上传成功",failMessage:u="上传失败",onProgress:f,uploadTimeoutMs:p,autoRevokeObjectURL:d=!1,showProgressToast:m=!1,progressToastFormatter:g}=t,h=t.toast||R;if(t.signal?.aborted){const t="已取消上传";return c&&h(t,!1,"none"),Promise.resolve({file:e,success:!1,message:t})}return new Promise(y=>{let w=!1;const E=e.raw;if(!(E&&E instanceof File)){const t="H5 环境缺少原生文件对象";return c&&h(t,!1,"none"),void y({file:e,success:!1,message:t})}const S=d&&"undefined"!=typeof URL&&"function"==typeof URL.revokeObjectURL&&"string"==typeof e.path&&H(e.path),T=m&&r?.manager||null,v=new XMLHttpRequest,R=n=>{if(!w){if(w=!0,t.signal&&"function"==typeof t.signal.removeEventListener)try{t.signal.removeEventListener("abort",x)}catch{}S&&B(e.path),y(n)}},x=()=>{try{v.abort()}catch{}};if(t.signal)if(t.signal.aborted)try{v.abort()}catch{}else"function"==typeof t.signal.addEventListener&&t.signal.addEventListener("abort",x,{once:!0});const _=new FormData;_.append(o,E,e.name),a&&Object.keys(a).forEach(e=>{const t=a[e];_.append(e,J(t))}),(f||T)&&v.upload.addEventListener("progress",t=>{if(t.lengthComputable){const s=Math.round(t.loaded/t.total*100);f&&f(e,s),T&&(r?.onToastProgressUpdate?r.onToastProgressUpdate(s):T.show(e,s,{currentIndex:n>1?r?.currentIndex:void 0,totalCount:n>1?n:void 0,formatter:g}))}}),v.addEventListener("load",()=>{const t=v.status,r=t>=200&&t<300;let s=v.responseText;if(s=z(v.responseText),r)c&&1===n&&h(l,!1,"none"),R({file:e,success:!0,statusCode:t,data:s});else{const n=`上传失败,状态码:${t}`;c&&h(n,!1,"none"),R({file:e,success:!1,statusCode:t,data:s,message:n})}}),v.addEventListener("error",()=>{const t=u;c&&h(t,!1,"none"),R({file:e,success:!1,message:t})}),v.addEventListener("timeout",()=>{const t=p?`上传超时(${p}ms)`:"上传超时";c&&h(t,!1,"none"),R({file:e,success:!1,message:t})}),v.addEventListener("abort",()=>{R({file:e,success:!1,message:"上传已取消"})});try{v.open("POST",s),"number"==typeof p&&p>0&&(v.timeout=p),i&&Object.keys(i).forEach(e=>{v.setRequestHeader(e,i[e])}),v.send(_)}catch(t){const n=t instanceof Error?`上传请求失败: ${t.message}`:u;c&&h(n,!1,"none"),R({file:e,success:!1,message:n})}})}(e,t,n,r):function(e,t,n,r){const{url:s,fieldName:o="file",formData:a,headers:i,showToast:c=!0,successMessage:l="上传成功",failMessage:u="上传失败",onProgress:f,uploadTimeoutMs:p,showProgressToast:d=!1,progressToastFormatter:m}=t,g="undefined"==typeof uni?null:uni,h=t.toast||R;if(!g||"function"!=typeof g.uploadFile){const t="当前环境不支持文件上传";return c&&h(t,!1,"none"),Promise.resolve({file:e,success:!1,message:t})}if(t.signal?.aborted){const t="已取消上传";return c&&h(t,!1,"none"),Promise.resolve({file:e,success:!1,message:t})}return new Promise(y=>{let w=!1,E=null;const S=d&&r?.manager||null,T=e=>{if(!w){if(w=!0,E&&(clearTimeout(E),E=null),t.signal&&"function"==typeof t.signal.removeEventListener)try{t.signal.removeEventListener("abort",R)}catch{}y(e)}};let v=null;"number"==typeof p&&p>0&&(E=setTimeout(()=>{try{v&&"function"==typeof v.abort&&v.abort()}catch{}const t=`上传超时(${p}ms)`;c&&h(t,!1,"none"),T({file:e,success:!1,message:t})},p)),v=g.uploadFile({url:s,filePath:e.path,name:o,formData:G(a),header:i,success:t=>{let r=t.data;r=z(t.data);const s=function(e){if(e&&"number"==typeof e.statusCode)return e.statusCode;if(e&&"number"==typeof e.status)return e.status;const t="string"==typeof e?.errMsg?e.errMsg:"";return/:ok\b/i.test(t)?200:0}(t);if(s>=200&&s<300)c&&1===n&&h(l,!1,"none"),T({file:e,success:!0,statusCode:s,data:r});else{const t=s?`上传失败,状态码:${s}`:"上传失败";c&&h(t,!1,"none"),T({file:e,success:!1,statusCode:s||void 0,data:r,message:t})}},fail:t=>{const n=t?.errMsg||u;c&&h(n,!1,"none"),T({file:e,success:!1,message:n})}});const R=()=>{try{v&&"function"==typeof v.abort&&v.abort()}catch{}const t="已取消上传";c&&h(t,!1,"none"),T({file:e,success:!1,message:t})};t.signal&&(t.signal.aborted?R():"function"==typeof t.signal.addEventListener&&t.signal.addEventListener("abort",R,{once:!0})),(f||S)&&v&&"function"==typeof v.onProgressUpdate&&v.onProgressUpdate(t=>{f&&f(e,t.progress),S&&(r?.onToastProgressUpdate?r.onToastProgressUpdate(t.progress):S.show(e,t.progress,{currentIndex:n>1?r?.currentIndex:void 0,totalCount:n>1?n:void 0,formatter:m}))})})}(e,t,n,r):(a&&l.message&&c(l.message,!1,"error"),Promise.resolve({file:e,success:!1,message:l.message}))}async function V(e){const{showToast:t=!0,failMessage:n="选择文件失败"}=e,r=e.toast||R;if(e.signal?.aborted){const e="已取消上传";return t&&e&&r(e,!1,"none"),[{file:null,success:!1,message:e}]}try{const s=await async function(e){return"undefined"!=typeof document&&"undefined"!=typeof window?function(e){const{type:t="image",count:n=1,extensions:r}=e;return new Promise(s=>{if("undefined"==typeof document||"undefined"==typeof window)return void s({success:!1,files:[],message:"当前环境不支持文件选择"});const o="number"==typeof n&&Number.isFinite(n)&&n>0?Math.floor(n):1,a=document.createElement("input");a.type="file",a.multiple=o>1,"image"===t?a.accept="image/*":r&&r.length>0&&(a.accept=r.map(e=>e.startsWith(".")?e:`.${e}`).join(","));let i=!1,c=null;const l=e=>{i||(i=!0,f(),s(e))},u=()=>{l({success:!1,files:[],message:"用户取消选择"})},f=()=>{c&&(clearTimeout(c),c=null);try{a.removeEventListener("change",d)}catch{}try{a.removeEventListener("cancel",m)}catch{}try{window.removeEventListener("focus",g)}catch{}try{document.removeEventListener("visibilitychange",h)}catch{}try{window.removeEventListener("pagehide",y)}catch{}try{window.removeEventListener("beforeunload",w)}catch{}if(e.signal&&"function"==typeof e.signal.removeEventListener)try{e.signal.removeEventListener("abort",E)}catch{}try{a.parentNode&&a.parentNode.removeChild(a)}catch{}},p=t=>{if(!t||0===t.length)return void u();const n=Array.from(t).slice(0,o),r=[],s=Y(n.map((e,t)=>{const n=M(e.name),s=URL.createObjectURL(e);return r.push(s),{id:F(t),name:e.name,size:e.size,path:s,mimeType:e.type,ext:n,source:"file",platform:"h5",raw:e}}),e);s.success||r.forEach(B),l(s)},d=e=>{const t=e.target;p(t?.files)},m=()=>{u()},g=()=>{i||(c&&(clearTimeout(c),c=null),c=setTimeout(()=>{i||p(a.files)},0))},h=()=>{i||"string"==typeof document.visibilityState&&"visible"===document.visibilityState&&g()};function y(){f()}function w(){f()}function E(){u()}if(e.signal){if(e.signal.aborted)return void u();"function"==typeof e.signal.addEventListener&&e.signal.addEventListener("abort",E,{once:!0})}a.addEventListener("change",d),a.addEventListener("cancel",m),window.addEventListener("focus",g),document.addEventListener("visibilitychange",h),window.addEventListener("pagehide",y),window.addEventListener("beforeunload",w),a.style.display="none",document.body.appendChild(a),a.click()})}(e):function(e){const{type:t="image",count:n=1}=e;return new Promise(r=>{const s="undefined"==typeof uni?null:uni;if(!s)return void r({success:!1,files:[],message:"当前环境不支持文件选择"});const o=e=>{const t=function(e){const t=(e||"").trim();if(!t)return"选择文件失败";const n=t.toLowerCase();return n.includes("fail cancel")||n.includes("cancel")?"用户取消选择":/[\u4e00-\u9fff]/.test(t)?t:"选择文件失败"}(e?.errMsg);r({success:!1,files:[],message:t})},a=function(){let e="unknown";return e="h5",e="weixin",e="alipay",e="app","app"}();"image"!==t||"weixin"!==a||"function"!=typeof s.chooseMedia?"image"!==t||"function"!=typeof s.chooseImage?"function"!=typeof s.chooseMessageFile?"function"!=typeof s.chooseFile?r({success:!1,files:[],message:"当前平台不支持文件选择"}):s.chooseFile({count:n,success:t=>{const n=(Array.isArray(t.tempFiles)?t.tempFiles:[t.tempFiles]).map((e,t)=>{const n=M(e.path);return{id:F(t),name:`file_${t}`,size:e.size,path:e.path,ext:n,source:"file",platform:a,raw:e}});r(Y(n,e))},fail:o}):s.chooseMessageFile({count:n,type:"all",success:t=>{const n=t.tempFiles.map((e,t)=>{const n=M(e.name||e.path);return{id:F(t),name:e.name,size:e.size,path:e.path,ext:n,source:"file",platform:a,raw:e}});r(Y(n,e))},fail:o}):s.chooseImage({count:n,success:t=>{const n=(Array.isArray(t.tempFiles)?t.tempFiles:[t.tempFiles]).map((e,t)=>{const n=M(e.path);return{id:F(t),name:`image_${t}`,size:e.size,path:e.path,ext:n,source:"album",platform:a,raw:e}});r(Y(n,e))},fail:o}):s.chooseMedia({count:n,mediaType:["image"],success:t=>{const n=(Array.isArray(t?.tempFiles)?t.tempFiles:[]).map((e,t)=>{const n=e?.tempFilePath||e?.path||e?.filePath||"",r=M(n),s="number"==typeof e?.size?e.size:"number"==typeof e?.fileSize?e.fileSize:"number"==typeof e?.originalFileSize?e.originalFileSize:0;return{id:F(t),name:`image_${t}`,size:s,path:n,mimeType:"string"==typeof e?.type?e.type:void 0,ext:r,source:"album",platform:a,raw:e}});r(Y(n,e))},fail:o})})}(e)}(e);if(!s.success){const e=s.message||n;return t&&e&&r(e,!1,"none"),[{file:null,success:!1,message:e}]}const o=s.files;if(0===o.length)return[];if(e.signal?.aborted){const e="已取消上传";return t&&r(e,!1,"none"),[{file:null,success:!1,message:e}]}const a=o.length;return await async function(e,t,n){const r=new Array(e.length),s=t.showProgressToast?new W:null,o=t.concurrency&&t.concurrency>0?Math.min(t.concurrency,e.length):e.length;let a=0;const i=Boolean(s)&&o>1&&n>1,c=i?new Array(n).fill(0):null;let l=0,u=0;const f=()=>{if(!i||!s||!c)return;const e=Math.round(l/n);s.showTitle(`上传中 (${u}/${n}) ${e}%`)},p=(e,t)=>{if(!i||!c)return;const n=Math.max(0,Math.min(100,Math.round(t))),r=c[e]||0;r!==n&&(c[e]=n,l+=n-r)};i&&f();const d=async()=>{for(;!t.signal?.aborted;){const o=a;if(o>=e.length)break;a+=1;const l=e[o];let d={file:l,success:!1,message:"上传失败"};try{d=await q(l,t,n,{manager:s,currentIndex:o+1,onToastProgressUpdate:i&&c?e=>{p(o,e),f()}:void 0})}catch(e){console.error("[Upload] worker 未预期异常:",e);const n=e instanceof Error?`上传失败: ${e.message}`:"上传失败";(t.showToast??1)&&(t.toast||R)(n,!1,"none"),d={file:l,success:!1,message:n}}finally{r[o]=d,i&&c&&(p(o,100),u+=1,f())}}},m=[];for(let e=0;e<o;e+=1)m.push(d());try{await Promise.all(m)}finally{s&&s.hide()}if(t.signal?.aborted)for(let t=0;t<r.length;t+=1)void 0===r[t]&&(r[t]={file:e[t],success:!1,message:"已取消上传"});return r}(o,e,a)}catch(e){const s=n;return t&&s&&r(s,!1,"none"),[{file:null,success:!1,message:s}]}}const X=n.getInstance();let Q=!1,Z=null;const ee=n.getInstance(),te=n.getInstance(),ne=()=>!("undefined"==typeof navigator||!navigator.userAgent)&&navigator.userAgent.toLowerCase().includes("micromessenger"),re=()=>"undefined"!=typeof window&&"undefined"!=typeof document,se=()=>re()&&ne()&&window.wx||null,oe=(e,t=!1)=>{const n={};return e.forEach(e=>{"string"==typeof e&&""!==e.trim()&&(n[e]=t)}),n};let ae=!1,ie=null,ce=!1;const le=(e={})=>{const{timeoutMs:t=1e4}=e;if(ae||re()&&window.wx)return ae=!0,Promise.resolve(!0);if(!re())return Promise.resolve(!1);if(ie)return ie;const n=e.cdnUrls&&e.cdnUrls.length>0?e.cdnUrls:["https://res.wx.qq.com/open/js/jweixin-1.6.0.js","https://res2.wx.qq.com/open/js/jweixin-1.6.0.js"];return ie=new Promise(e=>{let r=!1,s=null,o=null,a=0;const i=t=>{r||(r=!0,s&&(clearTimeout(s),s=null),o&&o.parentNode&&o.parentNode.removeChild(o),t&&(ae=!0),ie=null,e(t))},c=()=>{if(a>=n.length)return void i(!1);if(!document.head)return void i(!1);const e=n[a];a+=1;const t=document.createElement("script");o=t,t.src=e,t.async=!0,t.onload=()=>i(!0),t.onerror=()=>{t.parentNode&&t.parentNode.removeChild(t),o=null,c()},document.head.appendChild(t)};s=setTimeout(()=>{i(!1)},t),c()}),ie};let ue=null;const fe=async(e,n={})=>{const{timeoutMs:r=1e4}=n;return ne()?ue||(ue=(async()=>{if(!await le({timeoutMs:r}))return te.handleError(new t("WECHAT_JSSDK_LOAD_FAILED","微信 JS-SDK 加载失败","weixin"),"weixin"),!1;const n=se();if(!n||"function"!=typeof n.config||"function"!=typeof n.ready||"function"!=typeof n.error)return!1;const s=n.config,o=n.ready,a=n.error,i=await new Promise(n=>{let i=!1,c=null;const l=e=>{i||(i=!0,c&&(clearTimeout(c),c=null),n(e))};c=setTimeout(()=>l(!1),r);try{s({debug:e.debug||!1,appId:e.appId,timestamp:e.timestamp,nonceStr:e.nonceStr,signature:e.signature,jsApiList:e.jsApiList}),o(()=>l(!0)),a(e=>{te.handleError(new t("WECHAT_JSSDK_CONFIG_ERROR",`微信 JS-SDK 配置错误: ${(e=>{try{return JSON.stringify(e)}catch{return String(e)}})(e)}`,"weixin"),"weixin"),l(!1)})}catch(e){te.handleError(new t("WECHAT_JSSDK_CONFIG_EXCEPTION",`微信 JS-SDK 配置异常: ${e instanceof Error?e.message:String(e)}`,"weixin"),"weixin"),l(!1)}});return ce=i,i})().finally(()=>{ue=null}),ue):(console.warn("当前不在微信环境中"),!1)},pe=e=>{const t=se();t&&(t.updateTimelineShareData?t.updateTimelineShareData(e):t.onMenuShareTimeline&&t.onMenuShareTimeline(e))},de=e=>{const t=se();t&&(t.updateAppMessageShareData?t.updateAppMessageShareData(e):t.onMenuShareAppMessage&&t.onMenuShareAppMessage(e))};class me{static instance;isConfigured=!1;config=null;initPromise=null;constructor(){}static getInstance(){return me.instance||(me.instance=new me),me.instance}async init(e){return this.initPromise||(this.config=e,this.initPromise=fe(e).then(e=>(this.isConfigured=e,e)).finally(()=>{this.initPromise=null})),this.initPromise}isReady(){return(this.isConfigured||ce)&&ne()}getConfig(){return this.config}setShareData(e){this.isReady()?(pe(e),de(e)):console.warn("微信 SDK 未就绪")}}exports.ErrorHandler=n,exports.UniAppToolsError=t,exports.VERSION="4.0.0",exports.WechatSDK=me,exports.areaList=T,exports.batchGetStorage=function(e){const t={};return e.forEach(e=>{t[e]=N(e)}),t},exports.batchSetStorage=function(e,t={}){let n=0;return Object.entries(e).forEach(([e,r])=>{D(e,r,t)&&n++}),n},exports.buildUrl=_,exports.checkWechatJSAPI=(e,n={})=>{const{timeoutMs:r=8e3}=n;return new Promise(n=>{const s=se();if(!s||"function"!=typeof s.checkJsApi)return void n(oe(e,!1));let o=!1;const a=e=>{o||(o=!0,n(e))},i=setTimeout(()=>a(oe(e,!1)),r);try{s.checkJsApi({jsApiList:e,success:t=>{clearTimeout(i),a({...oe(e,!1),...t?.checkResult||{}})}})}catch(n){clearTimeout(i),te.handleError(new t("CHECK_WECHAT_JSAPI_ERROR",`检查微信 JS-SDK API 异常: ${n instanceof Error?n.message:String(n)}`,"weixin"),"weixin"),a(oe(e,!1))}})},exports.cleanExpiredStorage=function(){return U.cleanExpired()},exports.clearStorageSync=function(e){return e?U.remove(e):U.clear()},exports.clearSystemCache=()=>{c=null},exports.configWechatJSSDK=fe,exports.copyText=async function(e,t={}){const n={...O,...t};return e&&"string"==typeof e?e.length>1e4?(n.showToast&&R("复制内容过长",!1,"error"),!1):await r(()=>new Promise(t=>{uni.setClipboardData({data:e,showToast:!1,success:()=>{n.showToast&&R(n.successMessage),t(!0)},fail:()=>{n.showToast&&R(n.failMessage),t(!1)}})}),"clipboard","COPY_TEXT_ERROR")??!1:(n.showToast&&R("复制内容不能为空",!1,"error"),!1)},exports.debounce=E,exports.deepClone=w,exports.deepMerge=function(e,t){const n=w(e);return function e(t,n){for(const r in n)if(n.hasOwnProperty(r)){const s=n[r],o=t[r];s&&"object"==typeof s&&!Array.isArray(s)&&o&&"object"==typeof o&&!Array.isArray(o)?e(o,s):t[r]=w(s)}}(n,t),n},exports.extractUrlParts=function(e){try{const t=new URL(e,"http://localhost"),n=t.pathname,r={};return t.searchParams.forEach((e,t)=>{r[t]=e}),{path:n,params:r}}catch(n){return y.handleError(new t("EXTRACT_URL_PARTS_ERROR",`无效的URL: ${e}`,"utils"),"utils"),{path:"",params:{}}}},exports.getCurrentEnv=()=>{try{const e=uni.getAccountInfoSync();return{appId:e.miniProgram?.appId||"",version:e.miniProgram?.version||"",envVersion:e.miniProgram?.envVersion||"",accountInfo:e}}catch(e){return o.handleError(new t("GET_ACCOUNT_INFO_ERROR",`获取小程序账户信息失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),{appId:"",version:"",envVersion:"",accountInfo:{}}}},exports.getCurrentPageInfo=function(){try{const e=getCurrentPages();if(0===e.length)return null;const t=e[e.length-1];return{route:t.route||"",options:t.options||{}}}catch(e){return A("GET_CURRENT_PAGE_ERROR",`获取当前页面信息失败: ${e instanceof Error?e.message:String(e)}`),null}},exports.getExtension=M,exports.getH5UrlParams=e=>{try{if("undefined"==typeof window||!window.location)throw new Error("不在 H5 浏览器环境中");const t=new URLSearchParams(window.location.search),n={};return t.forEach((e,t)=>{try{n[t]=decodeURIComponent(e)}catch(r){n[t]=e}}),console.log("🔗 H5 URL参数解析:",{fullUrl:window.location.href,searchParams:window.location.search,parsedParams:n,paramName:e}),e?n.hasOwnProperty(e)?n[e]:null:n}catch(n){return y.handleError(new t("GET_H5_URL_PARAMS_ERROR",`获取H5 URL参数失败: ${n instanceof Error?n.message:String(n)}`,"utils"),"utils"),e?null:{}}},exports.getMenuButtonBoundingClientRect=m,exports.getNavHeight=()=>h().totalTopHeight,exports.getNavigationBarHeight=g,exports.getPageStack=function(){try{return getCurrentPages().map(e=>({route:e.route||"",options:e.options||{}}))}catch(e){return A("GET_PAGE_STACK_ERROR",`获取页面栈信息失败: ${e instanceof Error?e.message:String(e)}`),[]}},exports.getPlatform=f,exports.getStatusBarHeight=d,exports.getStorage=async function(e,t){return await r(()=>new Promise(n=>{n(N(e,t))}),"localStorage","GET_STORAGE_ASYNC_ERROR")??t},exports.getStorageInfo=function(){return U.getInfo()},exports.getStorageSync=N,exports.getTopBarMetrics=h,exports.getTopNavBarHeight=()=>{const e=h();return{statusBarHeight:e.statusBarHeight,navHeight:e.totalTopHeight}},exports.injectAlipayJsSdk=(e="https://gw.alipayobjects.com/as/g/h5-lib/alipayjsapi/3.1.1/alipayjsapi.min.js")=>"undefined"!=typeof window&&window.document?Q||window.ap?(Q=!0,Promise.resolve(!0)):Z||(Z=new Promise(n=>{let r=!1,s=null,o=null,a=!1,i=null,c=null,l=null;const u=(e,a,u)=>{r||(r=!0,s&&(clearTimeout(s),s=null),o&&(clearInterval(o),o=null),i&&c&&i.removeEventListener("load",c),i&&l&&i.removeEventListener("error",l),!e&&a&&u&&X.handleError(new t(a,u,"payment"),"payment"),e&&(Q=!0),Z=null,n(e))};try{const t=(()=>{try{return new URL(e,window.location.href).href}catch{return e}})(),n=document.getElementsByTagName("script");let r=null;for(let e=0;e<n.length;e++){const s=n[e];if(s&&s.src===t){r=s;break}}const f=r??document.createElement("script");a=!r,i=f;const p=()=>{window.ap&&u(!0)},d=e=>{a&&f.parentNode&&f.parentNode.removeChild(f),u(!1,"ALIPAY_SDK_LOAD_ERROR",`支付宝 JSSDK 加载失败: ${String(e?.type||"error")}`)};if(c=p,l=d,f.addEventListener("load",p),f.addEventListener("error",d),o=setInterval(()=>{window.ap&&u(!0)},50),s=setTimeout(()=>{a&&f.parentNode&&f.parentNode.removeChild(f),u(!1,"ALIPAY_SDK_LOAD_TIMEOUT","支付宝 JSSDK 加载超时")},1e4),a){f.type="text/javascript",f.src=t,f.async=!0,f.setAttribute("data-uniapp-tools","alipay-jssdk");const e=document.head||document.body||document.documentElement||null;if(!e)return void u(!1,"ALIPAY_SDK_INJECT_ERROR","无法找到可用的 script 注入容器");e.appendChild(f)}window.ap&&u(!0)}catch(e){u(!1,"ALIPAY_SDK_INJECT_ERROR",`注入支付宝 JSSDK 发生异常: ${e instanceof Error?e.message:String(e)}`)}}),Z):(X.handleError(new t("ALIPAY_SDK_ENV_ERROR","不在浏览器环境中,无法注入支付宝 JSSDK","payment"),"payment"),Promise.resolve(!1)),exports.isWechat=ne,exports.loadWechatJSSDK=le,exports.mergeObjects=function(e,t){if(!t||0===Object.keys(t).length)return e;const n={...e};for(const r of Object.keys(e))Object.prototype.hasOwnProperty.call(t,r)&&(n[r]=t[r]);return n},exports.navigateTo=P,exports.onCheckForUpdate=()=>{if(!u)try{const e=uni.getUpdateManager();u=!0,e.onCheckForUpdate(function(e){e.hasUpdate}),e.onUpdateReady(function(t){uni.showModal({title:"更新提示",content:"新版本已经准备好,是否重启应用?",showCancel:!0,cancelText:"稍后",confirmText:"立即重启",success(t){t.confirm&&e.applyUpdate()}})}),e.onUpdateFailed(function(e){o.handleError(new t("UPDATE_DOWNLOAD_FAILED","新版本下载失败","system"),"system"),uni.showModal({title:"更新失败",content:"新版本下载失败,请检查网络连接或稍后重试",showCancel:!1,confirmText:"知道了"})})}catch(e){o.handleError(new t("CHECK_UPDATE_ERROR",`版本更新检查失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system")}},exports.reLaunch=b,exports.redirectTo=async function(e){return new Promise(t=>{const n=_(e.url,e.params);uni.redirectTo({url:n,success:()=>t(!0),fail:e=>{A("REDIRECT_TO_FAILED",`页面重定向失败: ${n}`),t(!1)}})})},exports.safeAsync=r,exports.safeNavigateTo=async function(e,t=3){for(let n=0;n<t;n++){if(await P(e))return!0;n<t-1&&(await new Promise(e=>setTimeout(e,1e3*(n+1))),console.log(`[navigation] 第${n+2}次尝试跳转...`))}return!1},exports.safeSync=s,exports.selectAndUpload=V,exports.selectAndUploadImage=async function(e){return V({...e,type:"image"})},exports.setPageIcon=(e,t="image/x-icon")=>s(()=>{const n=f();if("h5"===n||"web"===n){if("undefined"!=typeof document){document.querySelectorAll('link[rel*="icon"]').forEach(e=>e.remove());const n=document.createElement("link");return n.rel="icon",n.type=t,n.href=e,document.head.appendChild(n),!0}}else console.warn("setPageIcon 仅在H5/Web平台有效");return!1},"system","SET_PAGE_ICON_ERROR",!1),exports.setPageTitle=e=>"string"!=typeof e?(console.warn("setPageTitle: title必须是字符串"),Promise.resolve(!1)):""===e.trim()?(console.warn("setPageTitle: title不能为空"),Promise.resolve(!1)):new Promise(n=>{try{uni.setNavigationBarTitle({title:e,success:()=>{n(!0)},fail:e=>{console.warn("设置页面标题失败:",e),n(!1)}})}catch(e){o.handleError(new t("SET_PAGE_TITLE_ERROR",`setPageTitle执行异常: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),n(!1)}}),exports.setStorage=async function(e,t,n={}){return await r(()=>new Promise(r=>{r(D(e,t,n))}),"localStorage","SET_STORAGE_ASYNC_ERROR")??!1},exports.setStorageSync=D,exports.shareToFriend=de,exports.shareToTimeline=pe,exports.switchTab=async function(e){return new Promise(t=>{uni.switchTab({url:e,success:()=>t(!0),fail:n=>{A("SWITCH_TAB_FAILED",`Tab切换失败: ${e}`),t(!1)}})})},exports.throttle=S,exports.useBack=L,exports.useBackDebounced=C,exports.useBackOrHome=async function(e="",t={}){const n=getCurrentPages(),r=t.delta||1;if(n.length>r)return await L(e,t);const s=t.homePage||"pages/index/index",o=s.startsWith("/")?s:`/${s}`;return console.info(`[navigation] 页面栈深度不足,重定向到首页: ${o}`),await b({url:o,params:t.homeParams})},exports.useCascaderAreaData=v,exports.useRegions=function(){return e.useCascaderAreaData()},exports.useToast=R,exports.useTryCatch=function(e,t={}){return async(...n)=>{try{return{data:await e(...n),error:null}}catch(e){return t.onError?.(e),{data:null,error:e}}finally{t.onFinally?.()}}},exports.useWindowInfo=p,exports.validateSizeWithLimit=K,exports.weChatOfficialAccountPayment=(e,n,r)=>new Promise(o=>{s(()=>{if("undefined"==typeof window||!window.navigator)throw new Error("不在浏览器环境中,无法调用微信支付");if(!(e&&e.appId&&e.timeStamp&&e.nonceStr&&e.package&&e.paySign))throw new Error("微信支付配置参数不完整");function s(){try{window.WeixinJSBridge.invoke("getBrandWCPayRequest",e,function(e){console.log("🚀 ~ 微信支付结果:",e),"get_brand_wcpay_request:ok"===e.err_msg?(console.log("✅ 微信支付成功"),n?.(e),o(!0)):(console.warn("❌ 微信支付失败或取消:",e.err_msg),r?.(e),o(!1))})}catch(e){ee.handleError(new t("WECHAT_PAY_INVOKE_ERROR",`调用微信支付接口失败: ${e instanceof Error?e.message:String(e)}`,"payment"),"payment");const n={err_msg:"get_brand_wcpay_request:fail",err_desc:e instanceof Error?e.message:"未知错误"};r?.(n),o(!1)}}if(void 0===window.WeixinJSBridge){const e=window.document;e.addEventListener?e.addEventListener("WeixinJSBridgeReady",s,!1):e.attachEvent&&(e.attachEvent("WeixinJSBridgeReady",s),e.attachEvent("onWeixinJSBridgeReady",s))}else s();return!0},"payment","WECHAT_PAY_ERROR",!1)||o(!1)});
|
|
1
|
+
"use strict";var e=require("@vant/area-data");class t extends Error{code;module;timestamp;constructor(e,t,n){super(t),this.name="UniAppToolsError",this.code=e,this.module=n,this.timestamp=Date.now()}}class n{static instance;errorCallbacks=[];static getInstance(){return n.instance||(n.instance=new n),n.instance}onError(e){this.errorCallbacks.push(e)}handleError(e,n){const s={code:e instanceof t?e.code:"UNKNOWN_ERROR",message:e.message,module:e instanceof t?e.module:n,timestamp:e instanceof t?e.timestamp:Date.now(),stack:e.stack};console.error(`[${s.module}] ${s.code}: ${s.message}`,s),this.errorCallbacks.forEach(e=>{try{e(s)}catch(e){console.error("Error in error callback:",e)}})}createModuleErrorHandler(e){return(n,s,r)=>{const o=new t(n,s,e);return r&&(o.stack=r.stack),this.handleError(o,e),o}}}async function s(e,t,s="ASYNC_ERROR"){try{return await e()}catch(e){return n.getInstance().createModuleErrorHandler(t)(s,`异步操作失败: ${e instanceof Error?e.message:String(e)}`,e),null}}function r(e,t,s="SYNC_ERROR",r=null){try{return e()}catch(e){return n.getInstance().createModuleErrorHandler(t)(s,`同步操作失败: ${e instanceof Error?e.message:String(e)}`,e),r}}const o=n.getInstance();let a=null,i=null,c=null;const u=e=>"weixin"===e||"alipay"===e;let l=!1;const f=()=>{if(a)return a;let e="unknown";try{"undefined"!=typeof uni&&("undefined"!=typeof wx&&wx.getSystemInfoSync?e="weixin":"undefined"!=typeof my&&my.getSystemInfoSync?e="alipay":"undefined"!=typeof window&&window.document?e="h5":"undefined"!=typeof plus&&(e="app"))}catch(t){e="weixin",e="web",e="app",e="alipay",e="h5"}return a=e,e},d=(e=!0)=>e&&c?c:r(()=>{const t=uni.getWindowInfo();return e&&(c=t),t},"system","GET_WINDOW_INFO_ERROR",null),m=()=>{if(null!==i)return i;try{const e=d();return i=e?.statusBarHeight||0,i}catch(e){return o.handleError(new t("GET_STATUS_BAR_HEIGHT_ERROR",`获取状态栏高度失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),0}},p=()=>{try{const e=f();return u(e)?uni.getMenuButtonBoundingClientRect():null}catch(e){return o.handleError(new t("GET_MENU_BUTTON_ERROR",`获取菜单按钮边界信息失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),null}},g=()=>{try{const e=f();if(u(e)){const e=p();return e?.height||44}return 44}catch(e){return o.handleError(new t("GET_NAVIGATION_BAR_HEIGHT_ERROR",`获取导航栏高度失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),44}},h=()=>{const e=f(),t=m(),n=g();return{platform:e,statusBarHeight:t,navigationBarHeight:n,totalTopHeight:t+n}},y=n.getInstance();function w(e){if(null===e||"object"!=typeof e)return e;try{return"undefined"!=typeof structuredClone?structuredClone(e):JSON.parse(JSON.stringify(e))}catch(e){const n=e instanceof Error?e.message:String(e);throw y.handleError(new t("DEEP_CLONE_ERROR",`深拷贝失败: ${n}`,"utils"),"utils"),new Error(`深拷贝失败: ${n}`)}}function E(e,t,n=!1){let s,r=null;const o=function(...o){const a=n&&!r;return r&&clearTimeout(r),r=setTimeout(()=>{r=null,n||(s=e.apply(this,o))},t),a&&(s=e.apply(this,o)),s};return o.cancel=()=>{r&&(clearTimeout(r),r=null)},o}function S(e,t,n={}){let s,r=null,o=0;const{leading:a=!0,trailing:i=!0}=n,c=function(...n){const c=Date.now();o||a||(o=c);const u=t-(c-o);return u<=0||u>t?(r&&(clearTimeout(r),r=null),o=c,s=e.apply(this,n)):!r&&i&&(r=setTimeout(()=>{o=a?Date.now():0,r=null,s=e.apply(this,n)},u)),s};return c.cancel=()=>{r&&(clearTimeout(r),r=null),o=0},c}const R=e.areaList,T=e.useCascaderAreaData,_=(e="",t=!1,n="none",s=2e3)=>{uni.showToast({title:e,icon:n,mask:t,duration:s})},x=n.getInstance();let A={defaultHomePage:"/pages/index/index"};function C(e,t){if(!t)return e;const n=Object.entries(t).map(([e,t])=>`${encodeURIComponent(e)}=${encodeURIComponent(String(t))}`).join("&");return e+(e.includes("?")?"&":"?")+n}const P=C;function v(e,n,s){const r=s?.errMsg?`${n} - ${s.errMsg}`:n;x.handleError(new t(e,r,"navigation"),"navigation")}async function O(e="",t={}){return new Promise(n=>{const s=t.delta||1,r=t.timeout||5e3,o=getCurrentPages();if(o.length<=s)return console.warn(`[navigation] 无法返回${s}页,当前页面栈深度不足(当前: ${o.length})`),void n(!1);let a=!1;const i=setTimeout(()=>{a||(a=!0,console.warn("[navigation] 页面init回调执行超时"),n(!1))},r);uni.navigateBack({delta:s,success:()=>{clearTimeout(i),setTimeout(()=>{if(!a)try{const t=getCurrentPages();if(t.length>0){const n=t[t.length-1];n.$vm&&"function"==typeof n.$vm.init&&n.$vm.init(e)}a=!0,n(!0)}catch(e){v("PAGE_CALLBACK_ERROR",`页面回调执行失败: ${e instanceof Error?e.message:String(e)}`),a=!0,n(!0)}},100)},fail:e=>{clearTimeout(i),v("NAVIGATE_BACK_FAILED","导航返回失败",e),a=!0,n(!1)}})})}const I=E(O,300);function b(){try{const e=getCurrentPages();if(0===e.length)return null;const t=e[e.length-1];return{route:t.route||"",options:t.options||{}}}catch(e){return v("GET_CURRENT_PAGE_ERROR",`获取当前页面信息失败: ${e instanceof Error?e.message:String(e)}`),null}}const L=b;function N(){try{return getCurrentPages().map(e=>({route:e.route||"",options:e.options||{}}))}catch(e){return v("GET_PAGE_STACK_ERROR",`获取页面栈信息失败: ${e instanceof Error?e.message:String(e)}`),[]}}const D=N,U={showToast:!0,successMessage:"复制成功",failMessage:"复制失败",timeout:5e3},$=n.getInstance();class M{static instance;cache=new Map;maxCacheSize=100;static getInstance(){return M.instance||(M.instance=new M),M.instance}isExpired(e){return!!e.ttl&&Date.now()-e.timestamp>e.ttl}set(e,n,s={}){try{if(!e||"string"!=typeof e)throw new Error("存储键不能为空");const t={value:n,timestamp:Date.now(),ttl:s.ttl},r=JSON.stringify(t);if(r.length>1048576)throw new Error("存储数据过大");if(uni.setStorageSync(e,r),this.cache.size>=this.maxCacheSize){const e=this.cache.keys().next().value;e&&this.cache.delete(e)}return this.cache.set(e,t),!0}catch(e){throw $.handleError(new t("SET_STORAGE_ERROR",`设置存储失败: ${e instanceof Error?e.message:String(e)}`,"localStorage"),"localStorage"),e}}get(e,t){try{if(!e||"string"!=typeof e)return t;if(this.cache.has(e)){const n=this.cache.get(e);return this.isExpired(n)?(this.cache.delete(e),this.remove(e),t):n.value}const n=uni.getStorageSync(e);if(!n||"string"!=typeof n)return t;const s=JSON.parse(n);let r;return r=s&&"object"==typeof s&&"value"in s&&"timestamp"in s?s:{value:s,timestamp:Date.now()},this.isExpired(r)?(this.remove(e),t):(this.cache.set(e,r),r.value)}catch(n){return console.warn(`[localStorage] 获取存储失败 [${e}]:`,n),t}}remove(e){try{return!(!e||"string"!=typeof e||(uni.removeStorageSync(e),this.cache.delete(e),0))}catch(n){return $.handleError(new t("REMOVE_STORAGE_ERROR",`删除存储失败: ${e}`,"localStorage"),"localStorage"),!1}}clear(){try{return uni.clearStorageSync(),this.cache.clear(),!0}catch(e){return $.handleError(new t("CLEAR_STORAGE_ERROR","清空存储失败","localStorage"),"localStorage"),!1}}getInfo(){try{const e=uni.getStorageInfoSync();return{keys:e.keys||[],currentSize:e.currentSize||0,limitSize:e.limitSize||0}}catch(e){return $.handleError(new t("GET_STORAGE_INFO_ERROR",`获取存储信息失败: ${e instanceof Error?e.message:String(e)}`,"localStorage"),"localStorage"),{keys:[],currentSize:0,limitSize:0}}}cleanExpired(){try{const e=this.getInfo();let t=0;return e.keys.forEach(e=>{void 0===this.get(e)&&t++}),t}catch(e){return $.handleError(new t("CLEAN_EXPIRED_ERROR",`清理过期数据失败: ${e instanceof Error?e.message:String(e)}`,"localStorage"),"localStorage"),0}}}const k=M.getInstance();function H(e,t,n={}){return k.set(e,t,n)}function B(e,t){return k.get(e,t)}const F="上传失败",j="已取消上传",W="选择文件失败",J="用户取消选择",K=e=>`部分文件大小超过 ${e}MB 限制`,G=e=>`存在不支持的文件类型,仅支持:${e.join(", ")}`,z="当前环境不支持文件选择",Y=e=>`上传超时(${e}ms)`,V=e=>`上传请求失败: ${e}`,q=e=>`上传失败,状态码:${e}`,X={FILE_TYPE:"image",COUNT:1,SHOW_TOAST:!0};function Q(e){if(!e)return;const t=e.split(/[?#]/)[0].match(/\.([^./\\]+)$/);return t?t[1].toLowerCase():void 0}function Z(e){const t=e.toLowerCase().replace(/^\./,"");return"jpeg"===t||"jpe"===t?"jpg":t}function ee(e){return`${Date.now()}_${e}_${Math.random().toString(16).slice(2)}`}function te(e){return"string"==typeof e&&e.startsWith("blob:")}function ne(e){if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return e}}function se(e){if(null==e)return"";const t=typeof e;if("string"===t||"number"===t||"boolean"===t)return String(e);if("object"===t)try{return JSON.stringify(e)}catch{return String(e)}return String(e)}function re(e){if(!e)return;const t={};return Object.keys(e).forEach(n=>{t[n]=se(e[n])}),t}function oe(e){const t=(e||"").trim();if(!t)return"选择文件失败";const n=t.toLowerCase();return n.includes("fail cancel")||n.includes("cancel")?"用户取消选择":/[\u4e00-\u9fff]/.test(t)?t:"选择文件失败"}function ae(e,t){return null==t||"number"!=typeof t||!Number.isFinite(t)||t<0?{valid:!0}:e>1024*t*1024?{valid:!1,message:`文件大小不能超过 ${t}MB`}:{valid:!0}}function ie(e,t){return!Number.isFinite(t)||t<=0?0:"number"!=typeof e||!Number.isFinite(e)||e<=0?t:Math.min(Math.floor(e),t)}function ce(e){return{toast:e.toast||_,shouldShowToast:e.showToast??X.SHOW_TOAST}}function ue(e){return Boolean(e?.aborted)}function le(e){return[{file:null,success:!1,message:e}]}function fe(){return le(j)}async function de(e,t,n){const{url:s,files:r,type:o=X.FILE_TYPE,count:a=X.COUNT,maxSizeMB:i,extensions:c,signal:u,successMessage:l}=e,{toast:f,shouldShowToast:d}=ce(e);if(!s.trim()){const e="上传地址不能为空";return d&&f(e,!1,"none"),le(e)}if(ue(u))return d&&f(j,!1,"none"),fe();let m=r||[];if(0===m.length)try{const e=await t({type:o,count:a,extensions:c});if(!e.success)return d&&e.message&&f(e.message,!1,"none"),[{file:null,success:!1,message:e.message}];m=e.files}catch(e){const t=e instanceof Error?e.message:W;return d&&f(t,!1,"none"),le(t)}if(0===m.length)return[];const p=function(e,t){if(!e||0===e.length)return{success:!1,message:"未选择任何文件"};const{maxSizeMB:n,extensions:s}=t;if(0===n)return{success:!1,message:"当前不允许选择文件"};const r=null!=n&&"number"==typeof n&&Number.isFinite(n)&&n>0,o=Array.isArray(s)&&s.length>0;if(!r&&!o)return{success:!0};const a=o?new Set(s.map(e=>Z(e))):null;for(const t of e){if(r&&!ae(t.size,n).valid)return{success:!1,message:K(n)};if(o&&a){const e=t.ext?Z(t.ext):void 0;if(!e||!a.has(e))return{success:!1,message:G(s)}}}return{success:!0}}(m,{maxSizeMB:i,extensions:c});if(!p.success){const e=p.message||W;return d&&f(e,!1,"none"),le(e)}if(ue(u))return d&&f(j,!1,"none"),fe();const g=await async function(e,t,n,s){const{concurrency:r,signal:o,beforeUpload:a,onProgress:i,showProgressToast:c,progressToastFormatter:u}=t,{toast:l,shouldShowToast:f}=ce(t),d=new Array(e.length);let m=0;const p=e.length,g=ie(r,p),h=Boolean(c&&p>0),y="undefined"!=typeof uni?uni:null,w=Boolean(h&&y&&"function"==typeof y.showLoading&&"function"==typeof y.hideLoading),E=w,R=S((t,n)=>{if(!w)return;const s=function(e){const{files:t,index:n,pct:s,finishedCount:r,totalCount:o,progressToastFormatter:a}=e;return a?a(t[n],s,n+1,o):1===o?`上传中 ${s}%`:`上传中 (${r}/${o})`}({files:e,index:t,pct:n,finishedCount:m,totalCount:p,progressToastFormatter:u});y.showLoading({title:s,mask:!0})},200);const T=async r=>{const c=e[r];let u=null;try{if(ue(o))return u={file:c,success:!1,message:j},void(w&&R(r,0));const e=await async function(e){if(!a)return null;try{return await a(e)?null:{file:e,success:!1,message:j}}catch(t){const n=(e=>`上传前检查失败: ${e}`)(t.message||"unknown");return f&&l(n,!1,"error"),{file:e,success:!1,message:n}}}(c);if(e)return void(u=e);const d=function(e){return E?{...t,onProgress:(t,n)=>{R(e,n),i&&i(t,n)}}:t}(r);u=await s(c,d,n)}catch(e){u={file:c,success:!1,message:e.message||"Unknown error"}}finally{u||(u={file:c,success:!1,message:"Unknown error"}),d[r]=u,m++,u.success&&R(r,100)}};for(let e=0;e<p;e+=g){const t=Math.min(e+g,p),n=[];for(let s=e;s<t;s+=1)n.push(T(s));await Promise.all(n)}return w&&(R.cancel?.(),y.hideLoading()),d}(m,e,s,n);return g.filter(e=>e.success).length===g.length&&1===g.length&&d&&f(l||"上传成功",!1,"none"),g}function me(e,t,n,s,r,o,a){return{id:ee(t),name:a||`file_${t}`,size:n,path:e,ext:Q(a||e),source:s,platform:r,raw:o}}const pe="undefined"!=typeof window&&"undefined"!=typeof document&&!function(){const e="undefined"==typeof uni?null:uni;return Boolean(e&&"function"==typeof e.uploadFile)}(),ge=pe?function(e){const{type:t="image",count:n=1,extensions:s}=e;return new Promise(e=>{if("undefined"==typeof document||"undefined"==typeof window)return void e({success:!1,files:[],message:z});const r=document.createElement("input");r.type="file",r.multiple=n>1,r.style.display="none","image"===t?r.accept="image/*":s&&s.length>0&&(r.accept=s.map(e=>e.startsWith(".")?e:`.${e}`).join(","));let o=!1,a=null;const i=t=>{o||(o=!0,(()=>{a&&(clearTimeout(a),a=null),window.removeEventListener("focus",u);try{r.remove()}catch{}})(),e(t))},c=e=>{if(!e||0===e.length)return void i({success:!1,files:[],message:J});const t=Array.from(e).slice(0,n).map((e,t)=>({id:ee(t),name:e.name,size:e.size,path:URL.createObjectURL(e),mimeType:e.type,ext:Q(e.name),source:"file",platform:"h5",raw:e}));i({success:!0,files:t})};r.addEventListener("change",()=>c(r.files)),r.addEventListener("cancel",()=>i({success:!1,files:[],message:J}));const u=()=>{o||(a=window.setTimeout(()=>{o||(r.files&&0!==r.files.length?c(r.files):i({success:!1,files:[],message:J}))},300))};window.addEventListener("focus",u),document.body.appendChild(r),r.click()})}:function(e){const{type:t="image",count:n=1}=e;return new Promise(e=>{const s="undefined"==typeof uni?null:uni;if(!s)return void e({success:!1,files:[],message:z});const r=function(){if("undefined"!=typeof wx&&wx?.getSystemInfoSync)return"weixin";if("undefined"!=typeof my&&my?.getSystemInfoSync)return"alipay";if("undefined"!=typeof window&&"undefined"!=typeof document)return"h5";if("undefined"!=typeof plus)return"app";let e="unknown";return e="h5",e="weixin",e="alipay",e="app","app"}(),o=t=>{e({success:!1,files:[],message:oe(t?.errMsg)})},a=[{name:"chooseMedia(image)",when:()=>"image"===t&&"weixin"===r&&"function"==typeof s.chooseMedia,run:()=>{s.chooseMedia({count:n,mediaType:["image"],success:t=>{const n=(Array.isArray(t?.tempFiles)?t.tempFiles:[]).map((e,t)=>{const n=e.size||e.fileSize||e.originalFileSize||0;return me(e.tempFilePath,t,n,"album",r,e)});e({success:!0,files:n})},fail:o})}},{name:"chooseImage",when:()=>"image"===t&&"function"==typeof s.chooseImage,run:()=>{s.chooseImage({count:n,success:t=>{const n=(Array.isArray(t?.tempFiles)?t.tempFiles:t?.tempFiles?[t.tempFiles]:[]).map((e,t)=>me(e.path,t,e.size,"album",r,e));e({success:!0,files:n})},fail:o})}},{name:"chooseMessageFile(all)",when:()=>"function"==typeof s.chooseMessageFile,run:()=>{s.chooseMessageFile({count:n,type:"all",success:t=>{const n=(Array.isArray(t?.tempFiles)?t.tempFiles:[]).map((e,t)=>me(e.path,t,e.size,"file",r,e,e.name));e({success:!0,files:n})},fail:o})}}];for(const e of a)if(e.when())return void e.run();e({success:!1,files:[],message:"当前平台不支持文件选择"})})},he=pe?function(e,t,n){const{fieldName:s="file",formData:r,headers:o,timeoutMs:a,autoRevokeObjectURL:i}=t,{signal:c,onProgress:u}=t;return new Promise(t=>{const l=e.raw;if(!(l&&l instanceof File))return void t({file:e,success:!1,message:"H5 环境缺少原生文件对象"});const f=new XMLHttpRequest;let d=!1;const m=n=>{d||(d=!0,i&&te(e.path)&&function(e){if(te(e)&&"undefined"!=typeof URL&&"function"==typeof URL.revokeObjectURL)try{URL.revokeObjectURL(e)}catch{}}(e.path),t(n))};if(c){if(c.aborted)return void m({file:e,success:!1,message:j});c.addEventListener("abort",()=>{f.abort(),m({file:e,success:!1,message:j})},{once:!0})}f.open("POST",n),a&&a>0&&(f.timeout=a),o&&Object.keys(o).forEach(e=>{f.setRequestHeader(e,o[e])});const p=new FormData;p.append(s,l,e.name),r&&Object.keys(r).forEach(e=>{p.append(e,se(r[e]))}),f.upload.onprogress=t=>{if(t.lengthComputable&&u){const n=Math.round(t.loaded/t.total*100);u(e,n)}},f.onload=()=>{const t=f.status,n=t>=200&&t<300;let s=ne(f.responseText);m({file:e,success:n,statusCode:t,data:s,message:n?void 0:q(t)})},f.onerror=()=>m({file:e,success:!1,message:F}),f.ontimeout=()=>m({file:e,success:!1,message:Y(a||0)}),f.onabort=()=>m({file:e,success:!1,message:j});try{f.send(p)}catch(t){const n=t instanceof Error?t.message:"Unknown error";m({file:e,success:!1,message:V(n)})}})}:function(e,t,n){const{fieldName:s="file",formData:r,headers:o,timeoutMs:a}=t,{signal:i,onProgress:c}=t;return new Promise(t=>{const u="undefined"==typeof uni?null:uni;if(!u?.uploadFile)return void t({file:e,success:!1,message:"当前环境不支持文件上传"});let l=!1,f=null,d=null;const m=e=>{l||(l=!0,f&&clearTimeout(f),t(e))};a&&a>0&&(f=setTimeout(()=>{d?.abort?.(),m({file:e,success:!1,message:Y(a)})},a)),d=u.uploadFile({url:n,filePath:e.path,name:s,header:o,formData:re(r),success:t=>{const n=function(e){if(e&&"number"==typeof e.statusCode)return e.statusCode;if(e&&"number"==typeof e.status)return e.status;const t="string"==typeof e?.errMsg?e.errMsg:"";return/:ok\b/i.test(t)?200:0}(t),s=n>=200&&n<300,r=ne(t.data);m({file:e,success:s,statusCode:n,data:r,message:s?void 0:q(n)})},fail:t=>{l||m({file:e,success:!1,message:t?.errMsg||F})}}),c&&d?.onProgressUpdate&&d.onProgressUpdate(t=>{l||"number"!=typeof t.progress||c(e,t.progress)}),i&&(i.aborted?(d?.abort?.(),m({file:e,success:!1,message:j})):i.addEventListener("abort",()=>{d?.abort?.(),m({file:e,success:!1,message:j})},{once:!0}))})};async function ye(e){return de(e,ge,he)}const we=n.getInstance();let Ee=!1,Se=null;const Re=n.getInstance(),Te="WECHAT_PAY_INVALID_CONFIG",_e=n.getInstance(),xe=()=>!("undefined"==typeof navigator||!navigator.userAgent)&&navigator.userAgent.toLowerCase().includes("micromessenger"),Ae=()=>"undefined"!=typeof window&&"undefined"!=typeof document,Ce=()=>Ae()&&xe()&&window.wx||null,Pe=(e,t=!1)=>{const n={};return e.forEach(e=>{"string"==typeof e&&""!==e.trim()&&(n[e]=t)}),n};let ve=!1,Oe=null,Ie=!1;const be=(e={})=>{const{timeoutMs:t=1e4}=e;if(ve||Ae()&&window.wx)return ve=!0,Promise.resolve(!0);if(!Ae())return Promise.resolve(!1);if(Oe)return Oe;const n=e.cdnUrls&&e.cdnUrls.length>0?e.cdnUrls:["https://res.wx.qq.com/open/js/jweixin-1.6.0.js","https://res2.wx.qq.com/open/js/jweixin-1.6.0.js"];return Oe=new Promise(e=>{let s=!1,r=null,o=null,a=0;const i=t=>{s||(s=!0,r&&(clearTimeout(r),r=null),o&&o.parentNode&&o.parentNode.removeChild(o),t&&(ve=!0),Oe=null,e(t))},c=()=>{if(a>=n.length)return void i(!1);if(!document.head)return void i(!1);const e=n[a];a+=1;const t=document.createElement("script");o=t,t.src=e,t.async=!0,t.onload=()=>i(!0),t.onerror=()=>{t.parentNode&&t.parentNode.removeChild(t),o=null,c()},document.head.appendChild(t)};r=setTimeout(()=>{i(!1)},t),c()}),Oe};let Le=null;const Ne=async(e,n={})=>{const{timeoutMs:s=1e4}=n;return xe()?Le||(Le=(async()=>{if(!await be({timeoutMs:s}))return _e.handleError(new t("WECHAT_JSSDK_LOAD_FAILED","微信 JS-SDK 加载失败","weixin"),"weixin"),!1;const n=Ce();if(!n||"function"!=typeof n.config||"function"!=typeof n.ready||"function"!=typeof n.error)return!1;const r=n.config,o=n.ready,a=n.error,i=await new Promise(n=>{let i=!1,c=null;const u=e=>{i||(i=!0,c&&(clearTimeout(c),c=null),n(e))};c=setTimeout(()=>u(!1),s);try{r({debug:e.debug||!1,appId:e.appId,timestamp:e.timestamp,nonceStr:e.nonceStr,signature:e.signature,jsApiList:e.jsApiList}),o(()=>u(!0)),a(e=>{_e.handleError(new t("WECHAT_JSSDK_CONFIG_ERROR",`微信 JS-SDK 配置错误: ${(e=>{try{return JSON.stringify(e)}catch{return String(e)}})(e)}`,"weixin"),"weixin"),u(!1)})}catch(e){_e.handleError(new t("WECHAT_JSSDK_CONFIG_EXCEPTION",`微信 JS-SDK 配置异常: ${e instanceof Error?e.message:String(e)}`,"weixin"),"weixin"),u(!1)}});return Ie=i,i})().finally(()=>{Le=null}),Le):(console.warn("当前不在微信环境中"),!1)},De=e=>{const t=Ce();t&&(t.updateTimelineShareData?t.updateTimelineShareData(e):t.onMenuShareTimeline&&t.onMenuShareTimeline(e))},Ue=e=>{const t=Ce();t&&(t.updateAppMessageShareData?t.updateAppMessageShareData(e):t.onMenuShareAppMessage&&t.onMenuShareAppMessage(e))};class $e{static instance;isConfigured=!1;config=null;initPromise=null;constructor(){}static getInstance(){return $e.instance||($e.instance=new $e),$e.instance}async init(e){return this.initPromise||(this.config=e,this.initPromise=Ne(e).then(e=>(this.isConfigured=e,e)).finally(()=>{this.initPromise=null})),this.initPromise}isReady(){return(this.isConfigured||Ie)&&xe()}getConfig(){return this.config}setShareData(e){this.isReady()?(De(e),Ue(e)):console.warn("微信 SDK 未就绪")}}exports.ErrorHandler=n,exports.UniAppToolsError=t,exports.VERSION="5.0.0",exports.WechatSDK=$e,exports.areaList=R,exports.batchGetStorage=function(e){const t={};return e.forEach(e=>{t[e]=B(e)}),t},exports.batchSetStorage=function(e,t={}){let n=0;return Object.entries(e).forEach(([e,s])=>{H(e,s,t)&&n++}),n},exports.buildUrl=P,exports.checkWechatJSAPI=(e,n={})=>{const{timeoutMs:s=8e3}=n;return new Promise(n=>{const r=Ce();if(!r||"function"!=typeof r.checkJsApi)return void n(Pe(e,!1));let o=!1;const a=e=>{o||(o=!0,n(e))},i=setTimeout(()=>a(Pe(e,!1)),s);try{r.checkJsApi({jsApiList:e,success:t=>{clearTimeout(i),a({...Pe(e,!1),...t?.checkResult||{}})}})}catch(n){clearTimeout(i),_e.handleError(new t("CHECK_WECHAT_JSAPI_ERROR",`检查微信 JS-SDK API 异常: ${n instanceof Error?n.message:String(n)}`,"weixin"),"weixin"),a(Pe(e,!1))}})},exports.cleanExpiredStorage=function(){return k.cleanExpired()},exports.clearStorageSync=function(e){return e?k.remove(e):k.clear()},exports.clearSystemCache=()=>{c=null},exports.configWechatJSSDK=Ne,exports.configureNavigation=function(e){A={...A,...e}},exports.copyText=async function(e,t={}){const n={...U,...t};return e&&"string"==typeof e?e.length>1e4?(n.showToast&&_("复制内容过长",!1,"error"),!1):await s(()=>new Promise(t=>{uni.setClipboardData({data:e,showToast:!1,success:()=>{n.showToast&&_(n.successMessage),t(!0)},fail:()=>{n.showToast&&_(n.failMessage),t(!1)}})}),"clipboard","COPY_TEXT_ERROR")??!1:(n.showToast&&_("复制内容不能为空",!1,"error"),!1)},exports.debounce=E,exports.deepClone=w,exports.deepMerge=function(e,t){const n=w(e);return function e(t,n){for(const s in n)if(n.hasOwnProperty(s)){const r=n[s],o=t[s];r&&"object"==typeof r&&!Array.isArray(r)&&o&&"object"==typeof o&&!Array.isArray(o)?e(o,r):t[s]=w(r)}}(n,t),n},exports.extractUrlParts=function(e){try{const t=new URL(e,"http://localhost"),n=t.pathname,s={};return t.searchParams.forEach((e,t)=>{s[t]=e}),{path:n,params:s}}catch(n){return y.handleError(new t("EXTRACT_URL_PARTS_ERROR",`无效的URL: ${e}`,"utils"),"utils"),{path:"",params:{}}}},exports.getCurrentEnv=()=>{try{const e=uni.getAccountInfoSync();return{appId:e.miniProgram?.appId||"",version:e.miniProgram?.version||"",envVersion:e.miniProgram?.envVersion||"",accountInfo:e}}catch(e){return o.handleError(new t("GET_ACCOUNT_INFO_ERROR",`获取小程序账户信息失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),{appId:"",version:"",envVersion:"",accountInfo:{}}}},exports.getCurrentPageInfo=L,exports.getExtension=Q,exports.getH5UrlParams=e=>{try{if("undefined"==typeof window||!window.location)throw new Error("不在 H5 浏览器环境中");const t=new URLSearchParams(window.location.search),n={};return t.forEach((e,t)=>{try{n[t]=decodeURIComponent(e)}catch(s){n[t]=e}}),console.log("🔗 H5 URL参数解析:",{fullUrl:window.location.href,searchParams:window.location.search,parsedParams:n,paramName:e}),e?n.hasOwnProperty(e)?n[e]:null:n}catch(n){return y.handleError(new t("GET_H5_URL_PARAMS_ERROR",`获取H5 URL参数失败: ${n instanceof Error?n.message:String(n)}`,"utils"),"utils"),e?null:{}}},exports.getMenuButtonBoundingClientRect=p,exports.getNavHeight=()=>h().totalTopHeight,exports.getNavigationBarHeight=g,exports.getPageStack=D,exports.getPlatform=f,exports.getStatusBarHeight=m,exports.getStorage=async function(e,t){return await s(()=>new Promise(n=>{n(B(e,t))}),"localStorage","GET_STORAGE_ASYNC_ERROR")??t},exports.getStorageInfo=function(){return k.getInfo()},exports.getStorageSync=B,exports.getTopBarMetrics=h,exports.getTopNavBarHeight=()=>{const e=h();return{statusBarHeight:e.statusBarHeight,navHeight:e.totalTopHeight}},exports.injectAlipayJsSdk=(e="https://gw.alipayobjects.com/as/g/h5-lib/alipayjsapi/3.1.1/alipayjsapi.min.js")=>"undefined"!=typeof window&&window.document?Ee||window.ap?(Ee=!0,Promise.resolve(!0)):Se||(Se=new Promise(n=>{const s={settled:!1,timeoutId:null,script:null,createdByThisCall:!1},r=e=>{s.settled||(s.settled=!0,s.timeoutId&&(clearTimeout(s.timeoutId),s.timeoutId=null),e.success?Ee=!0:we.handleError(new t(e.code,e.message,"payment"),"payment"),Se=null,n(e.success))};try{let t;try{t=new URL(e,window.location.href).href}catch{return void r({success:!1,code:"ALIPAY_SDK_INVALID_URL",message:`无效的 JSSDK 地址: ${e}`})}const n=Array.from(document.getElementsByTagName("script")).find(e=>e.src===t),o=n??document.createElement("script");s.script=o,s.createdByThisCall=!n;const a=()=>{setTimeout(()=>{window.ap?r({success:!0}):r({success:!1,code:"ALIPAY_SDK_INIT_ERROR",message:"支付宝 JSSDK 加载成功但未能初始化 window.ap"})},50)},i=e=>{s.createdByThisCall&&o.parentNode&&o.parentNode.removeChild(o),r({success:!1,code:"ALIPAY_SDK_LOAD_ERROR",message:`支付宝 JSSDK 加载失败: ${String(e?.type||"error")}`})};o.addEventListener("load",a,{once:!0}),o.addEventListener("error",i,{once:!0}),s.timeoutId=setTimeout(()=>{s.createdByThisCall&&o.parentNode&&o.parentNode.removeChild(o),r({success:!1,code:"ALIPAY_SDK_LOAD_TIMEOUT",message:"支付宝 JSSDK 加载超时"})},1e4),s.createdByThisCall&&(o.type="text/javascript",o.src=t,o.async=!0,o.setAttribute("data-uniapp-tools","alipay-jssdk"),(document.head||document.body||document.documentElement).appendChild(o)),window.ap&&r({success:!0})}catch(e){r({success:!1,code:"ALIPAY_SDK_UNEXPECTED_ERROR",message:`支付宝 JSSDK 注入过程发生意外异常: ${e instanceof Error?e.message:String(e)}`})}}),Se):(we.handleError(new t("ALIPAY_SDK_ENV_ERROR","不在浏览器环境中,无法注入支付宝 JSSDK","payment"),"payment"),Promise.resolve(!1)),exports.isWechat=xe,exports.loadWechatJSSDK=be,exports.mergeObjects=function(e,t){if(!t||0===Object.keys(t).length)return e;const n={...e};for(const s of Object.keys(e))Object.prototype.hasOwnProperty.call(t,s)&&(n[s]=t[s]);return n},exports.normalizeConcurrency=ie,exports.onCheckForUpdate=()=>{if(!l)try{const e=uni.getUpdateManager();l=!0,e.onCheckForUpdate(function(e){e.hasUpdate}),e.onUpdateReady(function(t){uni.showModal({title:"更新提示",content:"新版本已经准备好,是否重启应用?",showCancel:!0,cancelText:"稍后",confirmText:"立即重启",success(t){t.confirm&&e.applyUpdate()}})}),e.onUpdateFailed(function(e){o.handleError(new t("UPDATE_DOWNLOAD_FAILED","新版本下载失败","system"),"system"),uni.showModal({title:"更新失败",content:"新版本下载失败,请检查网络连接或稍后重试",showCancel:!1,confirmText:"知道了"})})}catch(e){o.handleError(new t("CHECK_UPDATE_ERROR",`版本更新检查失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system")}},exports.safeAsync=s,exports.safeSync=r,exports.selectAndUpload=ye,exports.selectAndUploadImage=async function(e){return ye({...e,type:"image"})},exports.setPageIcon=(e,t="image/x-icon")=>r(()=>{const n=f();if("h5"===n||"web"===n){if("undefined"!=typeof document){document.querySelectorAll('link[rel*="icon"]').forEach(e=>e.remove());const n=document.createElement("link");return n.rel="icon",n.type=t,n.href=e,document.head.appendChild(n),!0}}else console.warn("setPageIcon 仅在H5/Web平台有效");return!1},"system","SET_PAGE_ICON_ERROR",!1),exports.setPageTitle=e=>"string"!=typeof e?(console.warn("setPageTitle: title必须是字符串"),Promise.resolve(!1)):""===e.trim()?(console.warn("setPageTitle: title不能为空"),Promise.resolve(!1)):new Promise(n=>{try{uni.setNavigationBarTitle({title:e,success:()=>{n(!0)},fail:e=>{console.warn("设置页面标题失败:",e),n(!1)}})}catch(e){o.handleError(new t("SET_PAGE_TITLE_ERROR",`setPageTitle执行异常: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),n(!1)}}),exports.setStorage=async function(e,t,n={}){return await s(()=>new Promise(s=>{s(H(e,t,n))}),"localStorage","SET_STORAGE_ASYNC_ERROR")??!1},exports.setStorageSync=H,exports.shareToFriend=Ue,exports.shareToTimeline=De,exports.throttle=S,exports.useBack=O,exports.useBackDebounced=I,exports.useBackOrHome=async function(e="",t={}){const n=getCurrentPages(),s=t.delta||1;if(n.length>s)return await O(e,t);const r=t.homePage||A.defaultHomePage,o=r.startsWith("/")?r:`/${r}`;return console.info(`[navigation] 页面栈深度不足,重定向到首页: ${o}`),new Promise(e=>{const n=C(o,t.homeParams);uni.reLaunch({url:n,success:()=>e(!0),fail:t=>{v("RELAUNCH_FAILED",`重新启动失败: ${n}`,t),e(!1)}})})},exports.useBuildUrl=C,exports.useCascaderAreaData=T,exports.useCurrentPageInfo=b,exports.usePageStack=N,exports.useRegions=function(){return e.useCascaderAreaData()},exports.useToast=_,exports.useWindowInfo=d,exports.validateSizeWithLimit=ae,exports.wechatH5Pay=(e,n={})=>{const{reportError:s=!0}=n;return new Promise(n=>{const r=(e,n,r=null)=>{const o=new t(e,n,"payment");return s&&Re.handleError(o,"payment"),{success:!1,status:"error",code:e,message:n,raw:r}};if(!(e?.appId&&e?.timeStamp&&e?.nonceStr&&e?.package&&e?.signType&&e?.paySign))return void n(r(Te,"微信支付配置参数不完整"));if(!e.package.startsWith("prepay_id="))return void n(r(Te,"微信支付 package 格式非法,应以 'prepay_id=' 开头"));if("undefined"==typeof window||!window.navigator)return void n(r("WECHAT_PAY_ENV_ERROR","不在浏览器环境中,无法调用微信支付"));const o=()=>{try{window.WeixinJSBridge.invoke("getBrandWCPayRequest",e,e=>{"get_brand_wcpay_request:ok"===e.err_msg?n({success:!0,status:"success",code:"WECHAT_PAY_SUCCESS",message:"支付成功",raw:e}):"get_brand_wcpay_request:cancel"===e.err_msg?n({success:!1,status:"cancel",code:"WECHAT_PAY_CANCEL",message:"用户取消支付",raw:e}):n({success:!1,status:"error",code:"WECHAT_PAY_FAIL",message:e.err_desc||"支付失败",raw:e})})}catch(e){n(r("WECHAT_PAY_INVOKE_ERROR",`调用微信支付接口失败: ${e instanceof Error?e.message:String(e)}`))}};if(void 0===window.WeixinJSBridge){const e=()=>{o(),window.document.removeEventListener("WeixinJSBridgeReady",e,!1)};window.document.addEventListener("WeixinJSBridgeReady",e,!1)}else o()})};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{areaList as e,useCascaderAreaData as t}from"@vant/area-data";class n extends Error{code;module;timestamp;constructor(e,t,n){super(t),this.name="UniAppToolsError",this.code=e,this.module=n,this.timestamp=Date.now()}}class r{static instance;errorCallbacks=[];static getInstance(){return r.instance||(r.instance=new r),r.instance}onError(e){this.errorCallbacks.push(e)}handleError(e,t){const r={code:e instanceof n?e.code:"UNKNOWN_ERROR",message:e.message,module:e instanceof n?e.module:t,timestamp:e instanceof n?e.timestamp:Date.now(),stack:e.stack};console.error(`[${r.module}] ${r.code}: ${r.message}`,r),this.errorCallbacks.forEach(e=>{try{e(r)}catch(e){console.error("Error in error callback:",e)}})}createModuleErrorHandler(e){return(t,r,s)=>{const o=new n(t,r,e);return s&&(o.stack=s.stack),this.handleError(o,e),o}}}async function s(e,t,n="ASYNC_ERROR"){try{return await e()}catch(e){return r.getInstance().createModuleErrorHandler(t)(n,`异步操作失败: ${e instanceof Error?e.message:String(e)}`,e),null}}function o(e,t,n="SYNC_ERROR",s=null){try{return e()}catch(e){return r.getInstance().createModuleErrorHandler(t)(n,`同步操作失败: ${e instanceof Error?e.message:String(e)}`,e),s}}const i=r.getInstance();let a=null,c=null,l=null;const u=()=>{l=null},f=e=>"weixin"===e||"alipay"===e;let d=!1;const m=()=>{if(a)return a;let e="unknown";try{"undefined"!=typeof uni&&("undefined"!=typeof wx&&wx.getSystemInfoSync?e="weixin":"undefined"!=typeof my&&my.getSystemInfoSync?e="alipay":"undefined"!=typeof window&&window.document?e="h5":"undefined"!=typeof plus&&(e="app"))}catch(t){e="weixin",e="web",e="app",e="alipay",e="h5"}return a=e,e},g=(e=!0)=>e&&l?l:o(()=>{const t=uni.getWindowInfo();return e&&(l=t),t},"system","GET_WINDOW_INFO_ERROR",null),p=()=>{try{const e=uni.getAccountInfoSync();return{appId:e.miniProgram?.appId||"",version:e.miniProgram?.version||"",envVersion:e.miniProgram?.envVersion||"",accountInfo:e}}catch(e){return i.handleError(new n("GET_ACCOUNT_INFO_ERROR",`获取小程序账户信息失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),{appId:"",version:"",envVersion:"",accountInfo:{}}}},h=()=>{if(!d)try{const e=uni.getUpdateManager();d=!0,e.onCheckForUpdate(function(e){e.hasUpdate}),e.onUpdateReady(function(t){uni.showModal({title:"更新提示",content:"新版本已经准备好,是否重启应用?",showCancel:!0,cancelText:"稍后",confirmText:"立即重启",success(t){t.confirm&&e.applyUpdate()}})}),e.onUpdateFailed(function(e){i.handleError(new n("UPDATE_DOWNLOAD_FAILED","新版本下载失败","system"),"system"),uni.showModal({title:"更新失败",content:"新版本下载失败,请检查网络连接或稍后重试",showCancel:!1,confirmText:"知道了"})})}catch(e){i.handleError(new n("CHECK_UPDATE_ERROR",`版本更新检查失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system")}},y=()=>{if(null!==c)return c;try{const e=g();return c=e?.statusBarHeight||0,c}catch(e){return i.handleError(new n("GET_STATUS_BAR_HEIGHT_ERROR",`获取状态栏高度失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),0}},w=()=>{try{const e=m();return f(e)?uni.getMenuButtonBoundingClientRect():null}catch(e){return i.handleError(new n("GET_MENU_BUTTON_ERROR",`获取菜单按钮边界信息失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),null}},E=()=>{try{const e=m();if(f(e)){const e=w();return e?.height||44}return 44}catch(e){return i.handleError(new n("GET_NAVIGATION_BAR_HEIGHT_ERROR",`获取导航栏高度失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),44}},S=()=>{const e=m(),t=y(),n=E();return{platform:e,statusBarHeight:t,navigationBarHeight:n,totalTopHeight:t+n}},v=()=>{const e=S();return{statusBarHeight:e.statusBarHeight,navHeight:e.totalTopHeight}},R=()=>S().totalTopHeight,T=e=>"string"!=typeof e?(console.warn("setPageTitle: title必须是字符串"),Promise.resolve(!1)):""===e.trim()?(console.warn("setPageTitle: title不能为空"),Promise.resolve(!1)):new Promise(t=>{try{uni.setNavigationBarTitle({title:e,success:()=>{t(!0)},fail:e=>{console.warn("设置页面标题失败:",e),t(!1)}})}catch(e){i.handleError(new n("SET_PAGE_TITLE_ERROR",`setPageTitle执行异常: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),t(!1)}}),_=(e,t="image/x-icon")=>o(()=>{const n=m();if("h5"===n||"web"===n){if("undefined"!=typeof document){document.querySelectorAll('link[rel*="icon"]').forEach(e=>e.remove());const n=document.createElement("link");return n.rel="icon",n.type=t,n.href=e,document.head.appendChild(n),!0}}else console.warn("setPageIcon 仅在H5/Web平台有效");return!1},"system","SET_PAGE_ICON_ERROR",!1),A=r.getInstance();function P(e){if(null===e||"object"!=typeof e)return e;try{if("undefined"!=typeof structuredClone)try{return structuredClone(e)}catch(e){}return JSON.parse(JSON.stringify(e))}catch(e){throw A.handleError(new n("DEEP_CLONE_ERROR",`深拷贝失败: ${e instanceof Error?e.message:String(e)}`,"utils"),"utils"),new Error(`深拷贝失败: ${e instanceof Error?e.message:String(e)}`)}}function b(e,t){const n=P(e);return function e(t,n){for(const r in n)if(n.hasOwnProperty(r)){const s=n[r],o=t[r];s&&"object"==typeof s&&!Array.isArray(s)&&o&&"object"==typeof o&&!Array.isArray(o)?e(o,s):t[r]=P(s)}}(n,t),n}function L(e,t){if(!t||0===Object.keys(t).length)return e;const n={...e};for(const r of Object.keys(e))Object.prototype.hasOwnProperty.call(t,r)&&(n[r]=t[r]);return n}function O(e,t,n=!1){let r,s=null;const o=function(...o){const i=n&&!s;return s&&clearTimeout(s),s=setTimeout(()=>{s=null,n||(r=e.apply(this,o))},t),i&&(r=e.apply(this,o)),r};return o.cancel=()=>{s&&(clearTimeout(s),s=null)},o}function C(e,t,n={}){let r,s=null,o=0;const{leading:i=!0,trailing:a=!0}=n,c=function(...n){const c=Date.now();o||i||(o=c);const l=t-(c-o);return l<=0||l>t?(s&&(clearTimeout(s),s=null),o=c,r=e.apply(this,n)):!s&&a&&(s=setTimeout(()=>{o=i?Date.now():0,s=null,r=e.apply(this,n)},l)),r};return c.cancel=()=>{s&&(clearTimeout(s),s=null),o=0},c}function I(e,t={}){return async(...n)=>{try{return{data:await e(...n),error:null}}catch(e){return t.onError?.(e),{data:null,error:e}}finally{t.onFinally?.()}}}const x=e=>{try{if("undefined"==typeof window||!window.location)throw new Error("不在 H5 浏览器环境中");const t=new URLSearchParams(window.location.search),n={};return t.forEach((e,t)=>{try{n[t]=decodeURIComponent(e)}catch(r){n[t]=e}}),console.log("🔗 H5 URL参数解析:",{fullUrl:window.location.href,searchParams:window.location.search,parsedParams:n,paramName:e}),e?n.hasOwnProperty(e)?n[e]:null:n}catch(t){return A.handleError(new n("GET_H5_URL_PARAMS_ERROR",`获取H5 URL参数失败: ${t instanceof Error?t.message:String(t)}`,"utils"),"utils"),e?null:{}}};function $(e){try{const t=new URL(e,"http://localhost"),n=t.pathname,r={};return t.searchParams.forEach((e,t)=>{r[t]=e}),{path:n,params:r}}catch(t){return A.handleError(new n("EXTRACT_URL_PARTS_ERROR",`无效的URL: ${e}`,"utils"),"utils"),{path:"",params:{}}}}const U=e,D=t;function M(){return t()}const N=(e="",t=!1,n="none",r=2e3)=>{uni.showToast({title:e,icon:n,mask:t,duration:r})},j=r.getInstance();function k(e,t){if(!t||0===Object.keys(t).length)return e;const n=Object.entries(t).map(([e,t])=>`${encodeURIComponent(e)}=${encodeURIComponent(String(t))}`).join("&");return e+(e.includes("?")?"&":"?")+n}function F(e,t){j.handleError(new n(e,t,"navigation"),"navigation")}async function H(e){return new Promise(t=>{const n=k(e.url,e.params);uni.navigateTo({url:n,animationType:e.animationType,animationDuration:e.animationDuration,events:e.events,success:()=>t(!0),fail:e=>{F("NAVIGATE_TO_FAILED",`页面跳转失败: ${n}`),t(!1)}})})}async function z(e){return new Promise(t=>{const n=k(e.url,e.params);uni.redirectTo({url:n,success:()=>t(!0),fail:e=>{F("REDIRECT_TO_FAILED",`页面重定向失败: ${n}`),t(!1)}})})}async function G(e){return new Promise(t=>{const n=k(e.url,e.params);uni.reLaunch({url:n,success:()=>t(!0),fail:e=>{F("RELAUNCH_FAILED",`重新启动失败: ${n}`),t(!1)}})})}async function J(e){return new Promise(t=>{uni.switchTab({url:e,success:()=>t(!0),fail:n=>{F("SWITCH_TAB_FAILED",`Tab切换失败: ${e}`),t(!1)}})})}async function B(e="",t={}){return new Promise(n=>{const r=t.delta||1,s=t.timeout||5e3;if(getCurrentPages().length<=r)return console.warn(`[navigation] 无法返回${r}页,当前页面栈深度不足`),void n(!1);const o=setTimeout(()=>{console.warn("[navigation] 导航返回超时"),n(!1)},s);uni.navigateBack({delta:r,success:()=>{clearTimeout(o),setTimeout(()=>{try{const t=getCurrentPages();if(t.length>0){const n=t[t.length-1];n.$vm&&"function"==typeof n.$vm.init&&n.$vm.init(e)}n(!0)}catch(e){F("PAGE_CALLBACK_ERROR",`页面回调执行失败: ${e instanceof Error?e.message:String(e)}`),n(!0)}},100)},fail:e=>{clearTimeout(o),F("NAVIGATE_BACK_FAILED","导航返回失败"),n(!1)}})})}async function K(e,t=3){for(let n=0;n<t;n++){if(await H(e))return!0;n<t-1&&(await new Promise(e=>setTimeout(e,1e3*(n+1))),console.log(`[navigation] 第${n+2}次尝试跳转...`))}return!1}async function W(e="",t={}){const n=getCurrentPages(),r=t.delta||1;if(n.length>r)return await B(e,t);const s=t.homePage||"pages/index/index",o=s.startsWith("/")?s:`/${s}`;return console.info(`[navigation] 页面栈深度不足,重定向到首页: ${o}`),await G({url:o,params:t.homeParams})}const Y=O(B,300);function q(){try{const e=getCurrentPages();if(0===e.length)return null;const t=e[e.length-1];return{route:t.route||"",options:t.options||{}}}catch(e){return F("GET_CURRENT_PAGE_ERROR",`获取当前页面信息失败: ${e instanceof Error?e.message:String(e)}`),null}}function V(){try{return getCurrentPages().map(e=>({route:e.route||"",options:e.options||{}}))}catch(e){return F("GET_PAGE_STACK_ERROR",`获取页面栈信息失败: ${e instanceof Error?e.message:String(e)}`),[]}}const X={showToast:!0,successMessage:"复制成功",failMessage:"复制失败",timeout:5e3};async function Q(e,t={}){const n={...X,...t};return e&&"string"==typeof e?e.length>1e4?(n.showToast&&N("复制内容过长",!1,"error"),!1):await s(()=>new Promise(t=>{uni.setClipboardData({data:e,showToast:!1,success:()=>{n.showToast&&N(n.successMessage),t(!0)},fail:()=>{n.showToast&&N(n.failMessage),t(!1)}})}),"clipboard","COPY_TEXT_ERROR")??!1:(n.showToast&&N("复制内容不能为空",!1,"error"),!1)}const Z=r.getInstance();class ee{static instance;cache=new Map;maxCacheSize=100;static getInstance(){return ee.instance||(ee.instance=new ee),ee.instance}isExpired(e){return!!e.ttl&&Date.now()-e.timestamp>e.ttl}set(e,t,r={}){try{if(!e||"string"!=typeof e)throw new Error("存储键不能为空");const n={value:t,timestamp:Date.now(),ttl:r.ttl},s=JSON.stringify(n);if(s.length>1048576)throw new Error("存储数据过大");if(uni.setStorageSync(e,s),this.cache.size>=this.maxCacheSize){const e=this.cache.keys().next().value;e&&this.cache.delete(e)}return this.cache.set(e,n),!0}catch(e){throw Z.handleError(new n("SET_STORAGE_ERROR",`设置存储失败: ${e instanceof Error?e.message:String(e)}`,"localStorage"),"localStorage"),e}}get(e,t){try{if(!e||"string"!=typeof e)return t;if(this.cache.has(e)){const n=this.cache.get(e);return this.isExpired(n)?(this.cache.delete(e),this.remove(e),t):n.value}const n=uni.getStorageSync(e);if(!n||"string"!=typeof n)return t;const r=JSON.parse(n);let s;return s=r&&"object"==typeof r&&"value"in r&&"timestamp"in r?r:{value:r,timestamp:Date.now()},this.isExpired(s)?(this.remove(e),t):(this.cache.set(e,s),s.value)}catch(n){return console.warn(`[localStorage] 获取存储失败 [${e}]:`,n),t}}remove(e){try{return!(!e||"string"!=typeof e||(uni.removeStorageSync(e),this.cache.delete(e),0))}catch(t){return Z.handleError(new n("REMOVE_STORAGE_ERROR",`删除存储失败: ${e}`,"localStorage"),"localStorage"),!1}}clear(){try{return uni.clearStorageSync(),this.cache.clear(),!0}catch(e){return Z.handleError(new n("CLEAR_STORAGE_ERROR","清空存储失败","localStorage"),"localStorage"),!1}}getInfo(){try{const e=uni.getStorageInfoSync();return{keys:e.keys||[],currentSize:e.currentSize||0,limitSize:e.limitSize||0}}catch(e){return Z.handleError(new n("GET_STORAGE_INFO_ERROR",`获取存储信息失败: ${e instanceof Error?e.message:String(e)}`,"localStorage"),"localStorage"),{keys:[],currentSize:0,limitSize:0}}}cleanExpired(){try{const e=this.getInfo();let t=0;return e.keys.forEach(e=>{void 0===this.get(e)&&t++}),t}catch(e){return Z.handleError(new n("CLEAN_EXPIRED_ERROR",`清理过期数据失败: ${e instanceof Error?e.message:String(e)}`,"localStorage"),"localStorage"),0}}}const te=ee.getInstance();function ne(e,t,n={}){return te.set(e,t,n)}function re(e,t){return te.get(e,t)}function se(e){return e?te.remove(e):te.clear()}async function oe(e,t,n={}){return await s(()=>new Promise(r=>{r(ne(e,t,n))}),"localStorage","SET_STORAGE_ASYNC_ERROR")??!1}async function ie(e,t){return await s(()=>new Promise(n=>{n(re(e,t))}),"localStorage","GET_STORAGE_ASYNC_ERROR")??t}function ae(){return te.getInfo()}function ce(){return te.cleanExpired()}function le(e,t={}){let n=0;return Object.entries(e).forEach(([e,r])=>{ne(e,r,t)&&n++}),n}function ue(e){const t={};return e.forEach(e=>{t[e]=re(e)}),t}function fe(e){if(!e)return;const t=e.split(/[?#]/)[0].match(/\.([^./\\]+)$/);return t?t[1].toLowerCase():void 0}function de(e){if(e&&"string"==typeof e)return{"image/jpeg":"jpg","image/jpg":"jpg","image/png":"png","image/gif":"gif","image/webp":"webp","image/heic":"heic","image/heif":"heif","video/mp4":"mp4","application/pdf":"pdf","text/plain":"txt","application/zip":"zip","application/x-zip-compressed":"zip","application/msword":"doc","application/vnd.openxmlformats-officedocument.wordprocessingml.document":"docx","application/vnd.ms-excel":"xls","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":"xlsx"}[e.toLowerCase().trim()]}function me(e){const t=e.toLowerCase().replace(/^\./,"");return"jpeg"===t||"jpe"===t?"jpg":t}function ge(e){return`${Date.now()}_${e}_${Math.random().toString(16).slice(2)}`}function pe(e){return"string"==typeof e&&e.startsWith("blob:")}function he(e){if(pe(e)&&"undefined"!=typeof URL&&"function"==typeof URL.revokeObjectURL)try{URL.revokeObjectURL(e)}catch{}}function ye(e){if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return e}}function we(e){if(null==e)return"";const t=typeof e;if("string"===t||"number"===t||"boolean"===t)return String(e);if("object"===t)try{return JSON.stringify(e)}catch{return String(e)}return String(e)}function Ee(e){if(!e)return;const t={};return Object.keys(e).forEach(n=>{t[n]=we(e[n])}),t}class Se{isShowing=!1;updateToastThrottled=null;showTitle(e){this.isShowing?this.updateToastThrottled&&this.updateToastThrottled(e):(this.showLoading(e),this.isShowing=!0,this.updateToastThrottled=C(e=>{this.isShowing&&this.showLoading(e)},200,{leading:!0,trailing:!0}))}show(e,t,n={}){const{currentIndex:r,totalCount:s,formatter:o}=n;let i;i=o?o(e,t,r,s):s&&s>1&&r?`上传中 (${r}/${s}) ${t}%`:`上传中 ${t}%`,this.showTitle(i)}hide(){if(!this.isShowing)return;try{this.updateToastThrottled?.cancel?.()}catch{}this.isShowing=!1,this.updateToastThrottled=null;const e="undefined"==typeof uni?null:uni;if(e&&"function"==typeof e.hideLoading)try{e.hideLoading()}catch{}}showLoading(e){const t="undefined"==typeof uni?null:uni;if(t&&"function"==typeof t.showLoading)try{t.showLoading({title:e,mask:!0})}catch{}}}function ve(e,t){return null==t||"number"!=typeof t||!Number.isFinite(t)||t<0?{valid:!0}:e>1024*t*1024?{valid:!1,message:`文件大小不能超过 ${t}MB`}:{valid:!0}}function Re(e,t){if(0===e.length)return{success:!1,files:e,message:"未选择任何文件"};const{maxSelectFileSizeMB:n,extensions:r}=t,s=t.extensionValidationPolicy||"strict",o=null!=n,i=Array.isArray(r)&&r.length>0,a=i?new Set(r.map(e=>me(e))):null;if(o&&0===n)return{success:!1,files:e,message:"当前不允许选择文件"};let c=!1;for(const t of e){if(o&&!ve(t.size,n).valid)return{success:!1,files:e,message:`部分文件大小超过 ${n}MB 限制`};if(i&&a){const e=t.ext?me(t.ext):void 0;if(e)a.has(e)||(c=!0);else if("allowNoExtension"===s);else if("mimeTypeFallback"===s){const e=de(t.mimeType),n=e?me(e):void 0;n&&a.has(n)||(c=!0)}else c=!0}}return c?{success:!1,files:e,message:`存在不支持的文件类型,仅支持:${r?.join(", ")}`}:{success:!0,files:e}}async function Te(e,t,n,r){const{url:s,maxUploadFileSizeMB:o,showToast:i=!0,beforeUpload:a}=t,c=t.toast||N;if(t.signal?.aborted){const t="已取消上传";return i&&c(t,!1,"none"),Promise.resolve({file:e,success:!1,message:t})}if("function"==typeof a)try{if(!await Promise.resolve(a(e)))return t.autoRevokeObjectURL&&"h5"===e.platform&&he(e.path),{file:e,success:!1,message:"已取消上传"}}catch(n){console.error("[Upload] beforeUpload 钩子执行异常:",n);const r=n instanceof Error?`上传前检查失败: ${n.message}`:"上传前检查失败";return i&&c(r,!1,"error"),t.autoRevokeObjectURL&&"h5"===e.platform&&he(e.path),{file:e,success:!1,message:r}}if(!s){const t="上传地址不能为空";return i&&c(t,!1,"error"),Promise.resolve({file:e,success:!1,message:t})}const l=ve(e.size,o);return l.valid?"h5"===e.platform&&e.raw instanceof File?function(e,t,n,r){const{url:s,fieldName:o="file",formData:i,headers:a,showToast:c=!0,successMessage:l="上传成功",failMessage:u="上传失败",onProgress:f,uploadTimeoutMs:d,autoRevokeObjectURL:m=!1,showProgressToast:g=!1,progressToastFormatter:p}=t,h=t.toast||N;if(t.signal?.aborted){const t="已取消上传";return c&&h(t,!1,"none"),Promise.resolve({file:e,success:!1,message:t})}return new Promise(y=>{let w=!1;const E=e.raw;if(!(E&&E instanceof File)){const t="H5 环境缺少原生文件对象";return c&&h(t,!1,"none"),void y({file:e,success:!1,message:t})}const S=m&&"undefined"!=typeof URL&&"function"==typeof URL.revokeObjectURL&&"string"==typeof e.path&&pe(e.path),v=g&&r?.manager||null,R=new XMLHttpRequest,T=n=>{if(!w){if(w=!0,t.signal&&"function"==typeof t.signal.removeEventListener)try{t.signal.removeEventListener("abort",_)}catch{}S&&he(e.path),y(n)}},_=()=>{try{R.abort()}catch{}};if(t.signal)if(t.signal.aborted)try{R.abort()}catch{}else"function"==typeof t.signal.addEventListener&&t.signal.addEventListener("abort",_,{once:!0});const A=new FormData;A.append(o,E,e.name),i&&Object.keys(i).forEach(e=>{const t=i[e];A.append(e,we(t))}),(f||v)&&R.upload.addEventListener("progress",t=>{if(t.lengthComputable){const s=Math.round(t.loaded/t.total*100);f&&f(e,s),v&&(r?.onToastProgressUpdate?r.onToastProgressUpdate(s):v.show(e,s,{currentIndex:n>1?r?.currentIndex:void 0,totalCount:n>1?n:void 0,formatter:p}))}}),R.addEventListener("load",()=>{const t=R.status,r=t>=200&&t<300;let s=R.responseText;if(s=ye(R.responseText),r)c&&1===n&&h(l,!1,"none"),T({file:e,success:!0,statusCode:t,data:s});else{const n=`上传失败,状态码:${t}`;c&&h(n,!1,"none"),T({file:e,success:!1,statusCode:t,data:s,message:n})}}),R.addEventListener("error",()=>{const t=u;c&&h(t,!1,"none"),T({file:e,success:!1,message:t})}),R.addEventListener("timeout",()=>{const t=d?`上传超时(${d}ms)`:"上传超时";c&&h(t,!1,"none"),T({file:e,success:!1,message:t})}),R.addEventListener("abort",()=>{T({file:e,success:!1,message:"上传已取消"})});try{R.open("POST",s),"number"==typeof d&&d>0&&(R.timeout=d),a&&Object.keys(a).forEach(e=>{R.setRequestHeader(e,a[e])}),R.send(A)}catch(t){const n=t instanceof Error?`上传请求失败: ${t.message}`:u;c&&h(n,!1,"none"),T({file:e,success:!1,message:n})}})}(e,t,n,r):function(e,t,n,r){const{url:s,fieldName:o="file",formData:i,headers:a,showToast:c=!0,successMessage:l="上传成功",failMessage:u="上传失败",onProgress:f,uploadTimeoutMs:d,showProgressToast:m=!1,progressToastFormatter:g}=t,p="undefined"==typeof uni?null:uni,h=t.toast||N;if(!p||"function"!=typeof p.uploadFile){const t="当前环境不支持文件上传";return c&&h(t,!1,"none"),Promise.resolve({file:e,success:!1,message:t})}if(t.signal?.aborted){const t="已取消上传";return c&&h(t,!1,"none"),Promise.resolve({file:e,success:!1,message:t})}return new Promise(y=>{let w=!1,E=null;const S=m&&r?.manager||null,v=e=>{if(!w){if(w=!0,E&&(clearTimeout(E),E=null),t.signal&&"function"==typeof t.signal.removeEventListener)try{t.signal.removeEventListener("abort",T)}catch{}y(e)}};let R=null;"number"==typeof d&&d>0&&(E=setTimeout(()=>{try{R&&"function"==typeof R.abort&&R.abort()}catch{}const t=`上传超时(${d}ms)`;c&&h(t,!1,"none"),v({file:e,success:!1,message:t})},d)),R=p.uploadFile({url:s,filePath:e.path,name:o,formData:Ee(i),header:a,success:t=>{let r=t.data;r=ye(t.data);const s=function(e){if(e&&"number"==typeof e.statusCode)return e.statusCode;if(e&&"number"==typeof e.status)return e.status;const t="string"==typeof e?.errMsg?e.errMsg:"";return/:ok\b/i.test(t)?200:0}(t);if(s>=200&&s<300)c&&1===n&&h(l,!1,"none"),v({file:e,success:!0,statusCode:s,data:r});else{const t=s?`上传失败,状态码:${s}`:"上传失败";c&&h(t,!1,"none"),v({file:e,success:!1,statusCode:s||void 0,data:r,message:t})}},fail:t=>{const n=t?.errMsg||u;c&&h(n,!1,"none"),v({file:e,success:!1,message:n})}});const T=()=>{try{R&&"function"==typeof R.abort&&R.abort()}catch{}const t="已取消上传";c&&h(t,!1,"none"),v({file:e,success:!1,message:t})};t.signal&&(t.signal.aborted?T():"function"==typeof t.signal.addEventListener&&t.signal.addEventListener("abort",T,{once:!0})),(f||S)&&R&&"function"==typeof R.onProgressUpdate&&R.onProgressUpdate(t=>{f&&f(e,t.progress),S&&(r?.onToastProgressUpdate?r.onToastProgressUpdate(t.progress):S.show(e,t.progress,{currentIndex:n>1?r?.currentIndex:void 0,totalCount:n>1?n:void 0,formatter:g}))})})}(e,t,n,r):(i&&l.message&&c(l.message,!1,"error"),Promise.resolve({file:e,success:!1,message:l.message}))}async function _e(e){const{showToast:t=!0,failMessage:n="选择文件失败"}=e,r=e.toast||N;if(e.signal?.aborted){const e="已取消上传";return t&&e&&r(e,!1,"none"),[{file:null,success:!1,message:e}]}try{const s=await async function(e){return"undefined"!=typeof document&&"undefined"!=typeof window?function(e){const{type:t="image",count:n=1,extensions:r}=e;return new Promise(s=>{if("undefined"==typeof document||"undefined"==typeof window)return void s({success:!1,files:[],message:"当前环境不支持文件选择"});const o="number"==typeof n&&Number.isFinite(n)&&n>0?Math.floor(n):1,i=document.createElement("input");i.type="file",i.multiple=o>1,"image"===t?i.accept="image/*":r&&r.length>0&&(i.accept=r.map(e=>e.startsWith(".")?e:`.${e}`).join(","));let a=!1,c=null;const l=e=>{a||(a=!0,f(),s(e))},u=()=>{l({success:!1,files:[],message:"用户取消选择"})},f=()=>{c&&(clearTimeout(c),c=null);try{i.removeEventListener("change",m)}catch{}try{i.removeEventListener("cancel",g)}catch{}try{window.removeEventListener("focus",p)}catch{}try{document.removeEventListener("visibilitychange",h)}catch{}try{window.removeEventListener("pagehide",y)}catch{}try{window.removeEventListener("beforeunload",w)}catch{}if(e.signal&&"function"==typeof e.signal.removeEventListener)try{e.signal.removeEventListener("abort",E)}catch{}try{i.parentNode&&i.parentNode.removeChild(i)}catch{}},d=t=>{if(!t||0===t.length)return void u();const n=Array.from(t).slice(0,o),r=[],s=Re(n.map((e,t)=>{const n=fe(e.name),s=URL.createObjectURL(e);return r.push(s),{id:ge(t),name:e.name,size:e.size,path:s,mimeType:e.type,ext:n,source:"file",platform:"h5",raw:e}}),e);s.success||r.forEach(he),l(s)},m=e=>{const t=e.target;d(t?.files)},g=()=>{u()},p=()=>{a||(c&&(clearTimeout(c),c=null),c=setTimeout(()=>{a||d(i.files)},0))},h=()=>{a||"string"==typeof document.visibilityState&&"visible"===document.visibilityState&&p()};function y(){f()}function w(){f()}function E(){u()}if(e.signal){if(e.signal.aborted)return void u();"function"==typeof e.signal.addEventListener&&e.signal.addEventListener("abort",E,{once:!0})}i.addEventListener("change",m),i.addEventListener("cancel",g),window.addEventListener("focus",p),document.addEventListener("visibilitychange",h),window.addEventListener("pagehide",y),window.addEventListener("beforeunload",w),i.style.display="none",document.body.appendChild(i),i.click()})}(e):function(e){const{type:t="image",count:n=1}=e;return new Promise(r=>{const s="undefined"==typeof uni?null:uni;if(!s)return void r({success:!1,files:[],message:"当前环境不支持文件选择"});const o=e=>{const t=function(e){const t=(e||"").trim();if(!t)return"选择文件失败";const n=t.toLowerCase();return n.includes("fail cancel")||n.includes("cancel")?"用户取消选择":/[\u4e00-\u9fff]/.test(t)?t:"选择文件失败"}(e?.errMsg);r({success:!1,files:[],message:t})},i=function(){let e="unknown";return e="h5",e="weixin",e="alipay",e="app","app"}();"image"!==t||"weixin"!==i||"function"!=typeof s.chooseMedia?"image"!==t||"function"!=typeof s.chooseImage?"function"!=typeof s.chooseMessageFile?"function"!=typeof s.chooseFile?r({success:!1,files:[],message:"当前平台不支持文件选择"}):s.chooseFile({count:n,success:t=>{const n=(Array.isArray(t.tempFiles)?t.tempFiles:[t.tempFiles]).map((e,t)=>{const n=fe(e.path);return{id:ge(t),name:`file_${t}`,size:e.size,path:e.path,ext:n,source:"file",platform:i,raw:e}});r(Re(n,e))},fail:o}):s.chooseMessageFile({count:n,type:"all",success:t=>{const n=t.tempFiles.map((e,t)=>{const n=fe(e.name||e.path);return{id:ge(t),name:e.name,size:e.size,path:e.path,ext:n,source:"file",platform:i,raw:e}});r(Re(n,e))},fail:o}):s.chooseImage({count:n,success:t=>{const n=(Array.isArray(t.tempFiles)?t.tempFiles:[t.tempFiles]).map((e,t)=>{const n=fe(e.path);return{id:ge(t),name:`image_${t}`,size:e.size,path:e.path,ext:n,source:"album",platform:i,raw:e}});r(Re(n,e))},fail:o}):s.chooseMedia({count:n,mediaType:["image"],success:t=>{const n=(Array.isArray(t?.tempFiles)?t.tempFiles:[]).map((e,t)=>{const n=e?.tempFilePath||e?.path||e?.filePath||"",r=fe(n),s="number"==typeof e?.size?e.size:"number"==typeof e?.fileSize?e.fileSize:"number"==typeof e?.originalFileSize?e.originalFileSize:0;return{id:ge(t),name:`image_${t}`,size:s,path:n,mimeType:"string"==typeof e?.type?e.type:void 0,ext:r,source:"album",platform:i,raw:e}});r(Re(n,e))},fail:o})})}(e)}(e);if(!s.success){const e=s.message||n;return t&&e&&r(e,!1,"none"),[{file:null,success:!1,message:e}]}const o=s.files;if(0===o.length)return[];if(e.signal?.aborted){const e="已取消上传";return t&&r(e,!1,"none"),[{file:null,success:!1,message:e}]}const i=o.length;return await async function(e,t,n){const r=new Array(e.length),s=t.showProgressToast?new Se:null,o=t.concurrency&&t.concurrency>0?Math.min(t.concurrency,e.length):e.length;let i=0;const a=Boolean(s)&&o>1&&n>1,c=a?new Array(n).fill(0):null;let l=0,u=0;const f=()=>{if(!a||!s||!c)return;const e=Math.round(l/n);s.showTitle(`上传中 (${u}/${n}) ${e}%`)},d=(e,t)=>{if(!a||!c)return;const n=Math.max(0,Math.min(100,Math.round(t))),r=c[e]||0;r!==n&&(c[e]=n,l+=n-r)};a&&f();const m=async()=>{for(;!t.signal?.aborted;){const o=i;if(o>=e.length)break;i+=1;const l=e[o];let m={file:l,success:!1,message:"上传失败"};try{m=await Te(l,t,n,{manager:s,currentIndex:o+1,onToastProgressUpdate:a&&c?e=>{d(o,e),f()}:void 0})}catch(e){console.error("[Upload] worker 未预期异常:",e);const n=e instanceof Error?`上传失败: ${e.message}`:"上传失败";(t.showToast??1)&&(t.toast||N)(n,!1,"none"),m={file:l,success:!1,message:n}}finally{r[o]=m,a&&c&&(d(o,100),u+=1,f())}}},g=[];for(let e=0;e<o;e+=1)g.push(m());try{await Promise.all(g)}finally{s&&s.hide()}if(t.signal?.aborted)for(let t=0;t<r.length;t+=1)void 0===r[t]&&(r[t]={file:e[t],success:!1,message:"已取消上传"});return r}(o,e,i)}catch(e){const s=n;return t&&s&&r(s,!1,"none"),[{file:null,success:!1,message:s}]}}async function Ae(e){return _e({...e,type:"image"})}const Pe=r.getInstance();let be=!1,Le=null;const Oe=(e="https://gw.alipayobjects.com/as/g/h5-lib/alipayjsapi/3.1.1/alipayjsapi.min.js")=>"undefined"!=typeof window&&window.document?be||window.ap?(be=!0,Promise.resolve(!0)):Le||(Le=new Promise(t=>{let r=!1,s=null,o=null,i=!1,a=null,c=null,l=null;const u=(e,i,u)=>{r||(r=!0,s&&(clearTimeout(s),s=null),o&&(clearInterval(o),o=null),a&&c&&a.removeEventListener("load",c),a&&l&&a.removeEventListener("error",l),!e&&i&&u&&Pe.handleError(new n(i,u,"payment"),"payment"),e&&(be=!0),Le=null,t(e))};try{const t=(()=>{try{return new URL(e,window.location.href).href}catch{return e}})(),n=document.getElementsByTagName("script");let r=null;for(let e=0;e<n.length;e++){const s=n[e];if(s&&s.src===t){r=s;break}}const f=r??document.createElement("script");i=!r,a=f;const d=()=>{window.ap&&u(!0)},m=e=>{i&&f.parentNode&&f.parentNode.removeChild(f),u(!1,"ALIPAY_SDK_LOAD_ERROR",`支付宝 JSSDK 加载失败: ${String(e?.type||"error")}`)};if(c=d,l=m,f.addEventListener("load",d),f.addEventListener("error",m),o=setInterval(()=>{window.ap&&u(!0)},50),s=setTimeout(()=>{i&&f.parentNode&&f.parentNode.removeChild(f),u(!1,"ALIPAY_SDK_LOAD_TIMEOUT","支付宝 JSSDK 加载超时")},1e4),i){f.type="text/javascript",f.src=t,f.async=!0,f.setAttribute("data-uniapp-tools","alipay-jssdk");const e=document.head||document.body||document.documentElement||null;if(!e)return void u(!1,"ALIPAY_SDK_INJECT_ERROR","无法找到可用的 script 注入容器");e.appendChild(f)}window.ap&&u(!0)}catch(e){u(!1,"ALIPAY_SDK_INJECT_ERROR",`注入支付宝 JSSDK 发生异常: ${e instanceof Error?e.message:String(e)}`)}}),Le):(Pe.handleError(new n("ALIPAY_SDK_ENV_ERROR","不在浏览器环境中,无法注入支付宝 JSSDK","payment"),"payment"),Promise.resolve(!1)),Ce=r.getInstance(),Ie=(e,t,r)=>new Promise(s=>{o(()=>{if("undefined"==typeof window||!window.navigator)throw new Error("不在浏览器环境中,无法调用微信支付");if(!(e&&e.appId&&e.timeStamp&&e.nonceStr&&e.package&&e.paySign))throw new Error("微信支付配置参数不完整");function o(){try{window.WeixinJSBridge.invoke("getBrandWCPayRequest",e,function(e){console.log("🚀 ~ 微信支付结果:",e),"get_brand_wcpay_request:ok"===e.err_msg?(console.log("✅ 微信支付成功"),t?.(e),s(!0)):(console.warn("❌ 微信支付失败或取消:",e.err_msg),r?.(e),s(!1))})}catch(e){Ce.handleError(new n("WECHAT_PAY_INVOKE_ERROR",`调用微信支付接口失败: ${e instanceof Error?e.message:String(e)}`,"payment"),"payment");const t={err_msg:"get_brand_wcpay_request:fail",err_desc:e instanceof Error?e.message:"未知错误"};r?.(t),s(!1)}}if(void 0===window.WeixinJSBridge){const e=window.document;e.addEventListener?e.addEventListener("WeixinJSBridgeReady",o,!1):e.attachEvent&&(e.attachEvent("WeixinJSBridgeReady",o),e.attachEvent("onWeixinJSBridgeReady",o))}else o();return!0},"payment","WECHAT_PAY_ERROR",!1)||s(!1)}),xe=r.getInstance(),$e=()=>!("undefined"==typeof navigator||!navigator.userAgent)&&navigator.userAgent.toLowerCase().includes("micromessenger"),Ue=()=>"undefined"!=typeof window&&"undefined"!=typeof document,De=()=>Ue()&&$e()&&window.wx||null,Me=(e,t=!1)=>{const n={};return e.forEach(e=>{"string"==typeof e&&""!==e.trim()&&(n[e]=t)}),n};let Ne=!1,je=null,ke=!1;const Fe=(e={})=>{const{timeoutMs:t=1e4}=e;if(Ne||Ue()&&window.wx)return Ne=!0,Promise.resolve(!0);if(!Ue())return Promise.resolve(!1);if(je)return je;const n=e.cdnUrls&&e.cdnUrls.length>0?e.cdnUrls:["https://res.wx.qq.com/open/js/jweixin-1.6.0.js","https://res2.wx.qq.com/open/js/jweixin-1.6.0.js"];return je=new Promise(e=>{let r=!1,s=null,o=null,i=0;const a=t=>{r||(r=!0,s&&(clearTimeout(s),s=null),o&&o.parentNode&&o.parentNode.removeChild(o),t&&(Ne=!0),je=null,e(t))},c=()=>{if(i>=n.length)return void a(!1);if(!document.head)return void a(!1);const e=n[i];i+=1;const t=document.createElement("script");o=t,t.src=e,t.async=!0,t.onload=()=>a(!0),t.onerror=()=>{t.parentNode&&t.parentNode.removeChild(t),o=null,c()},document.head.appendChild(t)};s=setTimeout(()=>{a(!1)},t),c()}),je};let He=null;const ze=async(e,t={})=>{const{timeoutMs:r=1e4}=t;return $e()?He||(He=(async()=>{if(!await Fe({timeoutMs:r}))return xe.handleError(new n("WECHAT_JSSDK_LOAD_FAILED","微信 JS-SDK 加载失败","weixin"),"weixin"),!1;const t=De();if(!t||"function"!=typeof t.config||"function"!=typeof t.ready||"function"!=typeof t.error)return!1;const s=t.config,o=t.ready,i=t.error,a=await new Promise(t=>{let a=!1,c=null;const l=e=>{a||(a=!0,c&&(clearTimeout(c),c=null),t(e))};c=setTimeout(()=>l(!1),r);try{s({debug:e.debug||!1,appId:e.appId,timestamp:e.timestamp,nonceStr:e.nonceStr,signature:e.signature,jsApiList:e.jsApiList}),o(()=>l(!0)),i(e=>{xe.handleError(new n("WECHAT_JSSDK_CONFIG_ERROR",`微信 JS-SDK 配置错误: ${(e=>{try{return JSON.stringify(e)}catch{return String(e)}})(e)}`,"weixin"),"weixin"),l(!1)})}catch(e){xe.handleError(new n("WECHAT_JSSDK_CONFIG_EXCEPTION",`微信 JS-SDK 配置异常: ${e instanceof Error?e.message:String(e)}`,"weixin"),"weixin"),l(!1)}});return ke=a,a})().finally(()=>{He=null}),He):(console.warn("当前不在微信环境中"),!1)},Ge=(e,t={})=>{const{timeoutMs:r=8e3}=t;return new Promise(t=>{const s=De();if(!s||"function"!=typeof s.checkJsApi)return void t(Me(e,!1));let o=!1;const i=e=>{o||(o=!0,t(e))},a=setTimeout(()=>i(Me(e,!1)),r);try{s.checkJsApi({jsApiList:e,success:t=>{clearTimeout(a),i({...Me(e,!1),...t?.checkResult||{}})}})}catch(t){clearTimeout(a),xe.handleError(new n("CHECK_WECHAT_JSAPI_ERROR",`检查微信 JS-SDK API 异常: ${t instanceof Error?t.message:String(t)}`,"weixin"),"weixin"),i(Me(e,!1))}})},Je=e=>{const t=De();t&&(t.updateTimelineShareData?t.updateTimelineShareData(e):t.onMenuShareTimeline&&t.onMenuShareTimeline(e))},Be=e=>{const t=De();t&&(t.updateAppMessageShareData?t.updateAppMessageShareData(e):t.onMenuShareAppMessage&&t.onMenuShareAppMessage(e))};class Ke{static instance;isConfigured=!1;config=null;initPromise=null;constructor(){}static getInstance(){return Ke.instance||(Ke.instance=new Ke),Ke.instance}async init(e){return this.initPromise||(this.config=e,this.initPromise=ze(e).then(e=>(this.isConfigured=e,e)).finally(()=>{this.initPromise=null})),this.initPromise}isReady(){return(this.isConfigured||ke)&&$e()}getConfig(){return this.config}setShareData(e){this.isReady()?(Je(e),Be(e)):console.warn("微信 SDK 未就绪")}}const We="4.0.0";export{r as ErrorHandler,n as UniAppToolsError,We as VERSION,Ke as WechatSDK,U as areaList,ue as batchGetStorage,le as batchSetStorage,k as buildUrl,Ge as checkWechatJSAPI,ce as cleanExpiredStorage,se as clearStorageSync,u as clearSystemCache,ze as configWechatJSSDK,Q as copyText,O as debounce,P as deepClone,b as deepMerge,$ as extractUrlParts,p as getCurrentEnv,q as getCurrentPageInfo,fe as getExtension,x as getH5UrlParams,w as getMenuButtonBoundingClientRect,R as getNavHeight,E as getNavigationBarHeight,V as getPageStack,m as getPlatform,y as getStatusBarHeight,ie as getStorage,ae as getStorageInfo,re as getStorageSync,S as getTopBarMetrics,v as getTopNavBarHeight,Oe as injectAlipayJsSdk,$e as isWechat,Fe as loadWechatJSSDK,L as mergeObjects,H as navigateTo,h as onCheckForUpdate,G as reLaunch,z as redirectTo,s as safeAsync,K as safeNavigateTo,o as safeSync,_e as selectAndUpload,Ae as selectAndUploadImage,_ as setPageIcon,T as setPageTitle,oe as setStorage,ne as setStorageSync,Be as shareToFriend,Je as shareToTimeline,J as switchTab,C as throttle,B as useBack,Y as useBackDebounced,W as useBackOrHome,D as useCascaderAreaData,M as useRegions,N as useToast,I as useTryCatch,g as useWindowInfo,ve as validateSizeWithLimit,Ie as weChatOfficialAccountPayment};
|
|
1
|
+
import{areaList as e,useCascaderAreaData as t}from"@vant/area-data";class n extends Error{code;module;timestamp;constructor(e,t,n){super(t),this.name="UniAppToolsError",this.code=e,this.module=n,this.timestamp=Date.now()}}class s{static instance;errorCallbacks=[];static getInstance(){return s.instance||(s.instance=new s),s.instance}onError(e){this.errorCallbacks.push(e)}handleError(e,t){const s={code:e instanceof n?e.code:"UNKNOWN_ERROR",message:e.message,module:e instanceof n?e.module:t,timestamp:e instanceof n?e.timestamp:Date.now(),stack:e.stack};console.error(`[${s.module}] ${s.code}: ${s.message}`,s),this.errorCallbacks.forEach(e=>{try{e(s)}catch(e){console.error("Error in error callback:",e)}})}createModuleErrorHandler(e){return(t,s,r)=>{const o=new n(t,s,e);return r&&(o.stack=r.stack),this.handleError(o,e),o}}}async function r(e,t,n="ASYNC_ERROR"){try{return await e()}catch(e){return s.getInstance().createModuleErrorHandler(t)(n,`异步操作失败: ${e instanceof Error?e.message:String(e)}`,e),null}}function o(e,t,n="SYNC_ERROR",r=null){try{return e()}catch(e){return s.getInstance().createModuleErrorHandler(t)(n,`同步操作失败: ${e instanceof Error?e.message:String(e)}`,e),r}}const i=s.getInstance();let a=null,c=null,u=null;const l=()=>{u=null},f=e=>"weixin"===e||"alipay"===e;let m=!1;const d=()=>{if(a)return a;let e="unknown";try{"undefined"!=typeof uni&&("undefined"!=typeof wx&&wx.getSystemInfoSync?e="weixin":"undefined"!=typeof my&&my.getSystemInfoSync?e="alipay":"undefined"!=typeof window&&window.document?e="h5":"undefined"!=typeof plus&&(e="app"))}catch(t){e="weixin",e="web",e="app",e="alipay",e="h5"}return a=e,e},g=(e=!0)=>e&&u?u:o(()=>{const t=uni.getWindowInfo();return e&&(u=t),t},"system","GET_WINDOW_INFO_ERROR",null),p=()=>{try{const e=uni.getAccountInfoSync();return{appId:e.miniProgram?.appId||"",version:e.miniProgram?.version||"",envVersion:e.miniProgram?.envVersion||"",accountInfo:e}}catch(e){return i.handleError(new n("GET_ACCOUNT_INFO_ERROR",`获取小程序账户信息失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),{appId:"",version:"",envVersion:"",accountInfo:{}}}},h=()=>{if(!m)try{const e=uni.getUpdateManager();m=!0,e.onCheckForUpdate(function(e){e.hasUpdate}),e.onUpdateReady(function(t){uni.showModal({title:"更新提示",content:"新版本已经准备好,是否重启应用?",showCancel:!0,cancelText:"稍后",confirmText:"立即重启",success(t){t.confirm&&e.applyUpdate()}})}),e.onUpdateFailed(function(e){i.handleError(new n("UPDATE_DOWNLOAD_FAILED","新版本下载失败","system"),"system"),uni.showModal({title:"更新失败",content:"新版本下载失败,请检查网络连接或稍后重试",showCancel:!1,confirmText:"知道了"})})}catch(e){i.handleError(new n("CHECK_UPDATE_ERROR",`版本更新检查失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system")}},y=()=>{if(null!==c)return c;try{const e=g();return c=e?.statusBarHeight||0,c}catch(e){return i.handleError(new n("GET_STATUS_BAR_HEIGHT_ERROR",`获取状态栏高度失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),0}},w=()=>{try{const e=d();return f(e)?uni.getMenuButtonBoundingClientRect():null}catch(e){return i.handleError(new n("GET_MENU_BUTTON_ERROR",`获取菜单按钮边界信息失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),null}},E=()=>{try{const e=d();if(f(e)){const e=w();return e?.height||44}return 44}catch(e){return i.handleError(new n("GET_NAVIGATION_BAR_HEIGHT_ERROR",`获取导航栏高度失败: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),44}},S=()=>{const e=d(),t=y(),n=E();return{platform:e,statusBarHeight:t,navigationBarHeight:n,totalTopHeight:t+n}},R=()=>{const e=S();return{statusBarHeight:e.statusBarHeight,navHeight:e.totalTopHeight}},_=()=>S().totalTopHeight,T=e=>"string"!=typeof e?(console.warn("setPageTitle: title必须是字符串"),Promise.resolve(!1)):""===e.trim()?(console.warn("setPageTitle: title不能为空"),Promise.resolve(!1)):new Promise(t=>{try{uni.setNavigationBarTitle({title:e,success:()=>{t(!0)},fail:e=>{console.warn("设置页面标题失败:",e),t(!1)}})}catch(e){i.handleError(new n("SET_PAGE_TITLE_ERROR",`setPageTitle执行异常: ${e instanceof Error?e.message:String(e)}`,"system"),"system"),t(!1)}}),A=(e,t="image/x-icon")=>o(()=>{const n=d();if("h5"===n||"web"===n){if("undefined"!=typeof document){document.querySelectorAll('link[rel*="icon"]').forEach(e=>e.remove());const n=document.createElement("link");return n.rel="icon",n.type=t,n.href=e,document.head.appendChild(n),!0}}else console.warn("setPageIcon 仅在H5/Web平台有效");return!1},"system","SET_PAGE_ICON_ERROR",!1),C=s.getInstance();function v(e){if(null===e||"object"!=typeof e)return e;try{return"undefined"!=typeof structuredClone?structuredClone(e):JSON.parse(JSON.stringify(e))}catch(e){const t=e instanceof Error?e.message:String(e);throw C.handleError(new n("DEEP_CLONE_ERROR",`深拷贝失败: ${t}`,"utils"),"utils"),new Error(`深拷贝失败: ${t}`)}}function O(e,t){const n=v(e);return function e(t,n){for(const s in n)if(n.hasOwnProperty(s)){const r=n[s],o=t[s];r&&"object"==typeof r&&!Array.isArray(r)&&o&&"object"==typeof o&&!Array.isArray(o)?e(o,r):t[s]=v(r)}}(n,t),n}function P(e,t){if(!t||0===Object.keys(t).length)return e;const n={...e};for(const s of Object.keys(e))Object.prototype.hasOwnProperty.call(t,s)&&(n[s]=t[s]);return n}function I(e,t,n=!1){let s,r=null;const o=function(...o){const i=n&&!r;return r&&clearTimeout(r),r=setTimeout(()=>{r=null,n||(s=e.apply(this,o))},t),i&&(s=e.apply(this,o)),s};return o.cancel=()=>{r&&(clearTimeout(r),r=null)},o}function L(e,t,n={}){let s,r=null,o=0;const{leading:i=!0,trailing:a=!0}=n,c=function(...n){const c=Date.now();o||i||(o=c);const u=t-(c-o);return u<=0||u>t?(r&&(clearTimeout(r),r=null),o=c,s=e.apply(this,n)):!r&&a&&(r=setTimeout(()=>{o=i?Date.now():0,r=null,s=e.apply(this,n)},u)),s};return c.cancel=()=>{r&&(clearTimeout(r),r=null),o=0},c}const b=e=>{try{if("undefined"==typeof window||!window.location)throw new Error("不在 H5 浏览器环境中");const t=new URLSearchParams(window.location.search),n={};return t.forEach((e,t)=>{try{n[t]=decodeURIComponent(e)}catch(s){n[t]=e}}),console.log("🔗 H5 URL参数解析:",{fullUrl:window.location.href,searchParams:window.location.search,parsedParams:n,paramName:e}),e?n.hasOwnProperty(e)?n[e]:null:n}catch(t){return C.handleError(new n("GET_H5_URL_PARAMS_ERROR",`获取H5 URL参数失败: ${t instanceof Error?t.message:String(t)}`,"utils"),"utils"),e?null:{}}};function N(e){try{const t=new URL(e,"http://localhost"),n=t.pathname,s={};return t.searchParams.forEach((e,t)=>{s[t]=e}),{path:n,params:s}}catch(t){return C.handleError(new n("EXTRACT_URL_PARTS_ERROR",`无效的URL: ${e}`,"utils"),"utils"),{path:"",params:{}}}}const x=e,$=t;function D(){return t()}const M=(e="",t=!1,n="none",s=2e3)=>{uni.showToast({title:e,icon:n,mask:t,duration:s})},U=s.getInstance();let k={defaultHomePage:"/pages/index/index"};function H(e){k={...k,...e}}function F(e,t){if(!t)return e;const n=Object.entries(t).map(([e,t])=>`${encodeURIComponent(e)}=${encodeURIComponent(String(t))}`).join("&");return e+(e.includes("?")?"&":"?")+n}const j=F;function B(e,t,s){const r=s?.errMsg?`${t} - ${s.errMsg}`:t;U.handleError(new n(e,r,"navigation"),"navigation")}async function G(e="",t={}){return new Promise(n=>{const s=t.delta||1,r=t.timeout||5e3,o=getCurrentPages();if(o.length<=s)return console.warn(`[navigation] 无法返回${s}页,当前页面栈深度不足(当前: ${o.length})`),void n(!1);let i=!1;const a=setTimeout(()=>{i||(i=!0,console.warn("[navigation] 页面init回调执行超时"),n(!1))},r);uni.navigateBack({delta:s,success:()=>{clearTimeout(a),setTimeout(()=>{if(!i)try{const t=getCurrentPages();if(t.length>0){const n=t[t.length-1];n.$vm&&"function"==typeof n.$vm.init&&n.$vm.init(e)}i=!0,n(!0)}catch(e){B("PAGE_CALLBACK_ERROR",`页面回调执行失败: ${e instanceof Error?e.message:String(e)}`),i=!0,n(!0)}},100)},fail:e=>{clearTimeout(a),B("NAVIGATE_BACK_FAILED","导航返回失败",e),i=!0,n(!1)}})})}async function W(e="",t={}){const n=getCurrentPages(),s=t.delta||1;if(n.length>s)return await G(e,t);const r=t.homePage||k.defaultHomePage,o=r.startsWith("/")?r:`/${r}`;return console.info(`[navigation] 页面栈深度不足,重定向到首页: ${o}`),new Promise(e=>{const n=F(o,t.homeParams);uni.reLaunch({url:n,success:()=>e(!0),fail:t=>{B("RELAUNCH_FAILED",`重新启动失败: ${n}`,t),e(!1)}})})}const J=I(G,300);function K(){try{const e=getCurrentPages();if(0===e.length)return null;const t=e[e.length-1];return{route:t.route||"",options:t.options||{}}}catch(e){return B("GET_CURRENT_PAGE_ERROR",`获取当前页面信息失败: ${e instanceof Error?e.message:String(e)}`),null}}const z=K;function Y(){try{return getCurrentPages().map(e=>({route:e.route||"",options:e.options||{}}))}catch(e){return B("GET_PAGE_STACK_ERROR",`获取页面栈信息失败: ${e instanceof Error?e.message:String(e)}`),[]}}const V=Y,q={showToast:!0,successMessage:"复制成功",failMessage:"复制失败",timeout:5e3};async function X(e,t={}){const n={...q,...t};return e&&"string"==typeof e?e.length>1e4?(n.showToast&&M("复制内容过长",!1,"error"),!1):await r(()=>new Promise(t=>{uni.setClipboardData({data:e,showToast:!1,success:()=>{n.showToast&&M(n.successMessage),t(!0)},fail:()=>{n.showToast&&M(n.failMessage),t(!1)}})}),"clipboard","COPY_TEXT_ERROR")??!1:(n.showToast&&M("复制内容不能为空",!1,"error"),!1)}const Q=s.getInstance();class Z{static instance;cache=new Map;maxCacheSize=100;static getInstance(){return Z.instance||(Z.instance=new Z),Z.instance}isExpired(e){return!!e.ttl&&Date.now()-e.timestamp>e.ttl}set(e,t,s={}){try{if(!e||"string"!=typeof e)throw new Error("存储键不能为空");const n={value:t,timestamp:Date.now(),ttl:s.ttl},r=JSON.stringify(n);if(r.length>1048576)throw new Error("存储数据过大");if(uni.setStorageSync(e,r),this.cache.size>=this.maxCacheSize){const e=this.cache.keys().next().value;e&&this.cache.delete(e)}return this.cache.set(e,n),!0}catch(e){throw Q.handleError(new n("SET_STORAGE_ERROR",`设置存储失败: ${e instanceof Error?e.message:String(e)}`,"localStorage"),"localStorage"),e}}get(e,t){try{if(!e||"string"!=typeof e)return t;if(this.cache.has(e)){const n=this.cache.get(e);return this.isExpired(n)?(this.cache.delete(e),this.remove(e),t):n.value}const n=uni.getStorageSync(e);if(!n||"string"!=typeof n)return t;const s=JSON.parse(n);let r;return r=s&&"object"==typeof s&&"value"in s&&"timestamp"in s?s:{value:s,timestamp:Date.now()},this.isExpired(r)?(this.remove(e),t):(this.cache.set(e,r),r.value)}catch(n){return console.warn(`[localStorage] 获取存储失败 [${e}]:`,n),t}}remove(e){try{return!(!e||"string"!=typeof e||(uni.removeStorageSync(e),this.cache.delete(e),0))}catch(t){return Q.handleError(new n("REMOVE_STORAGE_ERROR",`删除存储失败: ${e}`,"localStorage"),"localStorage"),!1}}clear(){try{return uni.clearStorageSync(),this.cache.clear(),!0}catch(e){return Q.handleError(new n("CLEAR_STORAGE_ERROR","清空存储失败","localStorage"),"localStorage"),!1}}getInfo(){try{const e=uni.getStorageInfoSync();return{keys:e.keys||[],currentSize:e.currentSize||0,limitSize:e.limitSize||0}}catch(e){return Q.handleError(new n("GET_STORAGE_INFO_ERROR",`获取存储信息失败: ${e instanceof Error?e.message:String(e)}`,"localStorage"),"localStorage"),{keys:[],currentSize:0,limitSize:0}}}cleanExpired(){try{const e=this.getInfo();let t=0;return e.keys.forEach(e=>{void 0===this.get(e)&&t++}),t}catch(e){return Q.handleError(new n("CLEAN_EXPIRED_ERROR",`清理过期数据失败: ${e instanceof Error?e.message:String(e)}`,"localStorage"),"localStorage"),0}}}const ee=Z.getInstance();function te(e,t,n={}){return ee.set(e,t,n)}function ne(e,t){return ee.get(e,t)}function se(e){return e?ee.remove(e):ee.clear()}async function re(e,t,n={}){return await r(()=>new Promise(s=>{s(te(e,t,n))}),"localStorage","SET_STORAGE_ASYNC_ERROR")??!1}async function oe(e,t){return await r(()=>new Promise(n=>{n(ne(e,t))}),"localStorage","GET_STORAGE_ASYNC_ERROR")??t}function ie(){return ee.getInfo()}function ae(){return ee.cleanExpired()}function ce(e,t={}){let n=0;return Object.entries(e).forEach(([e,s])=>{te(e,s,t)&&n++}),n}function ue(e){const t={};return e.forEach(e=>{t[e]=ne(e)}),t}const le="上传失败",fe="已取消上传",me="选择文件失败",de="用户取消选择",ge=e=>`部分文件大小超过 ${e}MB 限制`,pe=e=>`存在不支持的文件类型,仅支持:${e.join(", ")}`,he="当前环境不支持文件选择",ye=e=>`上传超时(${e}ms)`,we=e=>`上传请求失败: ${e}`,Ee=e=>`上传失败,状态码:${e}`,Se={FILE_TYPE:"image",COUNT:1,SHOW_TOAST:!0};function Re(e){if(!e)return;const t=e.split(/[?#]/)[0].match(/\.([^./\\]+)$/);return t?t[1].toLowerCase():void 0}function _e(e){const t=e.toLowerCase().replace(/^\./,"");return"jpeg"===t||"jpe"===t?"jpg":t}function Te(e){return`${Date.now()}_${e}_${Math.random().toString(16).slice(2)}`}function Ae(e){return"string"==typeof e&&e.startsWith("blob:")}function Ce(e){if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return e}}function ve(e){if(null==e)return"";const t=typeof e;if("string"===t||"number"===t||"boolean"===t)return String(e);if("object"===t)try{return JSON.stringify(e)}catch{return String(e)}return String(e)}function Oe(e){if(!e)return;const t={};return Object.keys(e).forEach(n=>{t[n]=ve(e[n])}),t}function Pe(e){const t=(e||"").trim();if(!t)return"选择文件失败";const n=t.toLowerCase();return n.includes("fail cancel")||n.includes("cancel")?"用户取消选择":/[\u4e00-\u9fff]/.test(t)?t:"选择文件失败"}function Ie(e,t){return null==t||"number"!=typeof t||!Number.isFinite(t)||t<0?{valid:!0}:e>1024*t*1024?{valid:!1,message:`文件大小不能超过 ${t}MB`}:{valid:!0}}function Le(e,t){return!Number.isFinite(t)||t<=0?0:"number"!=typeof e||!Number.isFinite(e)||e<=0?t:Math.min(Math.floor(e),t)}function be(e){return{toast:e.toast||M,shouldShowToast:e.showToast??Se.SHOW_TOAST}}function Ne(e){return Boolean(e?.aborted)}function xe(e){return[{file:null,success:!1,message:e}]}function $e(){return xe(fe)}async function De(e,t,n){const{url:s,files:r,type:o=Se.FILE_TYPE,count:i=Se.COUNT,maxSizeMB:a,extensions:c,signal:u,successMessage:l}=e,{toast:f,shouldShowToast:m}=be(e);if(!s.trim()){const e="上传地址不能为空";return m&&f(e,!1,"none"),xe(e)}if(Ne(u))return m&&f(fe,!1,"none"),$e();let d=r||[];if(0===d.length)try{const e=await t({type:o,count:i,extensions:c});if(!e.success)return m&&e.message&&f(e.message,!1,"none"),[{file:null,success:!1,message:e.message}];d=e.files}catch(e){const t=e instanceof Error?e.message:me;return m&&f(t,!1,"none"),xe(t)}if(0===d.length)return[];const g=function(e,t){if(!e||0===e.length)return{success:!1,message:"未选择任何文件"};const{maxSizeMB:n,extensions:s}=t;if(0===n)return{success:!1,message:"当前不允许选择文件"};const r=null!=n&&"number"==typeof n&&Number.isFinite(n)&&n>0,o=Array.isArray(s)&&s.length>0;if(!r&&!o)return{success:!0};const i=o?new Set(s.map(e=>_e(e))):null;for(const t of e){if(r&&!Ie(t.size,n).valid)return{success:!1,message:ge(n)};if(o&&i){const e=t.ext?_e(t.ext):void 0;if(!e||!i.has(e))return{success:!1,message:pe(s)}}}return{success:!0}}(d,{maxSizeMB:a,extensions:c});if(!g.success){const e=g.message||me;return m&&f(e,!1,"none"),xe(e)}if(Ne(u))return m&&f(fe,!1,"none"),$e();const p=await async function(e,t,n,s){const{concurrency:r,signal:o,beforeUpload:i,onProgress:a,showProgressToast:c,progressToastFormatter:u}=t,{toast:l,shouldShowToast:f}=be(t),m=new Array(e.length);let d=0;const g=e.length,p=Le(r,g),h=Boolean(c&&g>0),y="undefined"!=typeof uni?uni:null,w=Boolean(h&&y&&"function"==typeof y.showLoading&&"function"==typeof y.hideLoading),E=w,S=L((t,n)=>{if(!w)return;const s=function(e){const{files:t,index:n,pct:s,finishedCount:r,totalCount:o,progressToastFormatter:i}=e;return i?i(t[n],s,n+1,o):1===o?`上传中 ${s}%`:`上传中 (${r}/${o})`}({files:e,index:t,pct:n,finishedCount:d,totalCount:g,progressToastFormatter:u});y.showLoading({title:s,mask:!0})},200);const R=async r=>{const c=e[r];let u=null;try{if(Ne(o))return u={file:c,success:!1,message:fe},void(w&&S(r,0));const e=await async function(e){if(!i)return null;try{return await i(e)?null:{file:e,success:!1,message:fe}}catch(t){const n=(e=>`上传前检查失败: ${e}`)(t.message||"unknown");return f&&l(n,!1,"error"),{file:e,success:!1,message:n}}}(c);if(e)return void(u=e);const m=function(e){return E?{...t,onProgress:(t,n)=>{S(e,n),a&&a(t,n)}}:t}(r);u=await s(c,m,n)}catch(e){u={file:c,success:!1,message:e.message||"Unknown error"}}finally{u||(u={file:c,success:!1,message:"Unknown error"}),m[r]=u,d++,u.success&&S(r,100)}};for(let e=0;e<g;e+=p){const t=Math.min(e+p,g),n=[];for(let s=e;s<t;s+=1)n.push(R(s));await Promise.all(n)}return w&&(S.cancel?.(),y.hideLoading()),m}(d,e,s,n);return p.filter(e=>e.success).length===p.length&&1===p.length&&m&&f(l||"上传成功",!1,"none"),p}function Me(e,t,n,s,r,o,i){return{id:Te(t),name:i||`file_${t}`,size:n,path:e,ext:Re(i||e),source:s,platform:r,raw:o}}const Ue="undefined"!=typeof window&&"undefined"!=typeof document&&!function(){const e="undefined"==typeof uni?null:uni;return Boolean(e&&"function"==typeof e.uploadFile)}(),ke=Ue?function(e){const{type:t="image",count:n=1,extensions:s}=e;return new Promise(e=>{if("undefined"==typeof document||"undefined"==typeof window)return void e({success:!1,files:[],message:he});const r=document.createElement("input");r.type="file",r.multiple=n>1,r.style.display="none","image"===t?r.accept="image/*":s&&s.length>0&&(r.accept=s.map(e=>e.startsWith(".")?e:`.${e}`).join(","));let o=!1,i=null;const a=t=>{o||(o=!0,(()=>{i&&(clearTimeout(i),i=null),window.removeEventListener("focus",u);try{r.remove()}catch{}})(),e(t))},c=e=>{if(!e||0===e.length)return void a({success:!1,files:[],message:de});const t=Array.from(e).slice(0,n).map((e,t)=>({id:Te(t),name:e.name,size:e.size,path:URL.createObjectURL(e),mimeType:e.type,ext:Re(e.name),source:"file",platform:"h5",raw:e}));a({success:!0,files:t})};r.addEventListener("change",()=>c(r.files)),r.addEventListener("cancel",()=>a({success:!1,files:[],message:de}));const u=()=>{o||(i=window.setTimeout(()=>{o||(r.files&&0!==r.files.length?c(r.files):a({success:!1,files:[],message:de}))},300))};window.addEventListener("focus",u),document.body.appendChild(r),r.click()})}:function(e){const{type:t="image",count:n=1}=e;return new Promise(e=>{const s="undefined"==typeof uni?null:uni;if(!s)return void e({success:!1,files:[],message:he});const r=function(){if("undefined"!=typeof wx&&wx?.getSystemInfoSync)return"weixin";if("undefined"!=typeof my&&my?.getSystemInfoSync)return"alipay";if("undefined"!=typeof window&&"undefined"!=typeof document)return"h5";if("undefined"!=typeof plus)return"app";let e="unknown";return e="h5",e="weixin",e="alipay",e="app","app"}(),o=t=>{e({success:!1,files:[],message:Pe(t?.errMsg)})},i=[{name:"chooseMedia(image)",when:()=>"image"===t&&"weixin"===r&&"function"==typeof s.chooseMedia,run:()=>{s.chooseMedia({count:n,mediaType:["image"],success:t=>{const n=(Array.isArray(t?.tempFiles)?t.tempFiles:[]).map((e,t)=>{const n=e.size||e.fileSize||e.originalFileSize||0;return Me(e.tempFilePath,t,n,"album",r,e)});e({success:!0,files:n})},fail:o})}},{name:"chooseImage",when:()=>"image"===t&&"function"==typeof s.chooseImage,run:()=>{s.chooseImage({count:n,success:t=>{const n=(Array.isArray(t?.tempFiles)?t.tempFiles:t?.tempFiles?[t.tempFiles]:[]).map((e,t)=>Me(e.path,t,e.size,"album",r,e));e({success:!0,files:n})},fail:o})}},{name:"chooseMessageFile(all)",when:()=>"function"==typeof s.chooseMessageFile,run:()=>{s.chooseMessageFile({count:n,type:"all",success:t=>{const n=(Array.isArray(t?.tempFiles)?t.tempFiles:[]).map((e,t)=>Me(e.path,t,e.size,"file",r,e,e.name));e({success:!0,files:n})},fail:o})}}];for(const e of i)if(e.when())return void e.run();e({success:!1,files:[],message:"当前平台不支持文件选择"})})},He=Ue?function(e,t,n){const{fieldName:s="file",formData:r,headers:o,timeoutMs:i,autoRevokeObjectURL:a}=t,{signal:c,onProgress:u}=t;return new Promise(t=>{const l=e.raw;if(!(l&&l instanceof File))return void t({file:e,success:!1,message:"H5 环境缺少原生文件对象"});const f=new XMLHttpRequest;let m=!1;const d=n=>{m||(m=!0,a&&Ae(e.path)&&function(e){if(Ae(e)&&"undefined"!=typeof URL&&"function"==typeof URL.revokeObjectURL)try{URL.revokeObjectURL(e)}catch{}}(e.path),t(n))};if(c){if(c.aborted)return void d({file:e,success:!1,message:fe});c.addEventListener("abort",()=>{f.abort(),d({file:e,success:!1,message:fe})},{once:!0})}f.open("POST",n),i&&i>0&&(f.timeout=i),o&&Object.keys(o).forEach(e=>{f.setRequestHeader(e,o[e])});const g=new FormData;g.append(s,l,e.name),r&&Object.keys(r).forEach(e=>{g.append(e,ve(r[e]))}),f.upload.onprogress=t=>{if(t.lengthComputable&&u){const n=Math.round(t.loaded/t.total*100);u(e,n)}},f.onload=()=>{const t=f.status,n=t>=200&&t<300;let s=Ce(f.responseText);d({file:e,success:n,statusCode:t,data:s,message:n?void 0:Ee(t)})},f.onerror=()=>d({file:e,success:!1,message:le}),f.ontimeout=()=>d({file:e,success:!1,message:ye(i||0)}),f.onabort=()=>d({file:e,success:!1,message:fe});try{f.send(g)}catch(t){const n=t instanceof Error?t.message:"Unknown error";d({file:e,success:!1,message:we(n)})}})}:function(e,t,n){const{fieldName:s="file",formData:r,headers:o,timeoutMs:i}=t,{signal:a,onProgress:c}=t;return new Promise(t=>{const u="undefined"==typeof uni?null:uni;if(!u?.uploadFile)return void t({file:e,success:!1,message:"当前环境不支持文件上传"});let l=!1,f=null,m=null;const d=e=>{l||(l=!0,f&&clearTimeout(f),t(e))};i&&i>0&&(f=setTimeout(()=>{m?.abort?.(),d({file:e,success:!1,message:ye(i)})},i)),m=u.uploadFile({url:n,filePath:e.path,name:s,header:o,formData:Oe(r),success:t=>{const n=function(e){if(e&&"number"==typeof e.statusCode)return e.statusCode;if(e&&"number"==typeof e.status)return e.status;const t="string"==typeof e?.errMsg?e.errMsg:"";return/:ok\b/i.test(t)?200:0}(t),s=n>=200&&n<300,r=Ce(t.data);d({file:e,success:s,statusCode:n,data:r,message:s?void 0:Ee(n)})},fail:t=>{l||d({file:e,success:!1,message:t?.errMsg||le})}}),c&&m?.onProgressUpdate&&m.onProgressUpdate(t=>{l||"number"!=typeof t.progress||c(e,t.progress)}),a&&(a.aborted?(m?.abort?.(),d({file:e,success:!1,message:fe})):a.addEventListener("abort",()=>{m?.abort?.(),d({file:e,success:!1,message:fe})},{once:!0}))})};async function Fe(e){return De(e,ke,He)}async function je(e){return Fe({...e,type:"image"})}const Be=s.getInstance();let Ge=!1,We=null;const Je=(e="https://gw.alipayobjects.com/as/g/h5-lib/alipayjsapi/3.1.1/alipayjsapi.min.js")=>"undefined"!=typeof window&&window.document?Ge||window.ap?(Ge=!0,Promise.resolve(!0)):We||(We=new Promise(t=>{const s={settled:!1,timeoutId:null,script:null,createdByThisCall:!1},r=e=>{s.settled||(s.settled=!0,s.timeoutId&&(clearTimeout(s.timeoutId),s.timeoutId=null),e.success?Ge=!0:Be.handleError(new n(e.code,e.message,"payment"),"payment"),We=null,t(e.success))};try{let t;try{t=new URL(e,window.location.href).href}catch{return void r({success:!1,code:"ALIPAY_SDK_INVALID_URL",message:`无效的 JSSDK 地址: ${e}`})}const n=Array.from(document.getElementsByTagName("script")).find(e=>e.src===t),o=n??document.createElement("script");s.script=o,s.createdByThisCall=!n;const i=()=>{setTimeout(()=>{window.ap?r({success:!0}):r({success:!1,code:"ALIPAY_SDK_INIT_ERROR",message:"支付宝 JSSDK 加载成功但未能初始化 window.ap"})},50)},a=e=>{s.createdByThisCall&&o.parentNode&&o.parentNode.removeChild(o),r({success:!1,code:"ALIPAY_SDK_LOAD_ERROR",message:`支付宝 JSSDK 加载失败: ${String(e?.type||"error")}`})};o.addEventListener("load",i,{once:!0}),o.addEventListener("error",a,{once:!0}),s.timeoutId=setTimeout(()=>{s.createdByThisCall&&o.parentNode&&o.parentNode.removeChild(o),r({success:!1,code:"ALIPAY_SDK_LOAD_TIMEOUT",message:"支付宝 JSSDK 加载超时"})},1e4),s.createdByThisCall&&(o.type="text/javascript",o.src=t,o.async=!0,o.setAttribute("data-uniapp-tools","alipay-jssdk"),(document.head||document.body||document.documentElement).appendChild(o)),window.ap&&r({success:!0})}catch(e){r({success:!1,code:"ALIPAY_SDK_UNEXPECTED_ERROR",message:`支付宝 JSSDK 注入过程发生意外异常: ${e instanceof Error?e.message:String(e)}`})}}),We):(Be.handleError(new n("ALIPAY_SDK_ENV_ERROR","不在浏览器环境中,无法注入支付宝 JSSDK","payment"),"payment"),Promise.resolve(!1)),Ke=s.getInstance(),ze="WECHAT_PAY_INVALID_CONFIG",Ye=(e,t={})=>{const{reportError:s=!0}=t;return new Promise(t=>{const r=(e,t,r=null)=>{const o=new n(e,t,"payment");return s&&Ke.handleError(o,"payment"),{success:!1,status:"error",code:e,message:t,raw:r}};if(!(e?.appId&&e?.timeStamp&&e?.nonceStr&&e?.package&&e?.signType&&e?.paySign))return void t(r(ze,"微信支付配置参数不完整"));if(!e.package.startsWith("prepay_id="))return void t(r(ze,"微信支付 package 格式非法,应以 'prepay_id=' 开头"));if("undefined"==typeof window||!window.navigator)return void t(r("WECHAT_PAY_ENV_ERROR","不在浏览器环境中,无法调用微信支付"));const o=()=>{try{window.WeixinJSBridge.invoke("getBrandWCPayRequest",e,e=>{"get_brand_wcpay_request:ok"===e.err_msg?t({success:!0,status:"success",code:"WECHAT_PAY_SUCCESS",message:"支付成功",raw:e}):"get_brand_wcpay_request:cancel"===e.err_msg?t({success:!1,status:"cancel",code:"WECHAT_PAY_CANCEL",message:"用户取消支付",raw:e}):t({success:!1,status:"error",code:"WECHAT_PAY_FAIL",message:e.err_desc||"支付失败",raw:e})})}catch(e){t(r("WECHAT_PAY_INVOKE_ERROR",`调用微信支付接口失败: ${e instanceof Error?e.message:String(e)}`))}};if(void 0===window.WeixinJSBridge){const e=()=>{o(),window.document.removeEventListener("WeixinJSBridgeReady",e,!1)};window.document.addEventListener("WeixinJSBridgeReady",e,!1)}else o()})},Ve=s.getInstance(),qe=()=>!("undefined"==typeof navigator||!navigator.userAgent)&&navigator.userAgent.toLowerCase().includes("micromessenger"),Xe=()=>"undefined"!=typeof window&&"undefined"!=typeof document,Qe=()=>Xe()&&qe()&&window.wx||null,Ze=(e,t=!1)=>{const n={};return e.forEach(e=>{"string"==typeof e&&""!==e.trim()&&(n[e]=t)}),n};let et=!1,tt=null,nt=!1;const st=(e={})=>{const{timeoutMs:t=1e4}=e;if(et||Xe()&&window.wx)return et=!0,Promise.resolve(!0);if(!Xe())return Promise.resolve(!1);if(tt)return tt;const n=e.cdnUrls&&e.cdnUrls.length>0?e.cdnUrls:["https://res.wx.qq.com/open/js/jweixin-1.6.0.js","https://res2.wx.qq.com/open/js/jweixin-1.6.0.js"];return tt=new Promise(e=>{let s=!1,r=null,o=null,i=0;const a=t=>{s||(s=!0,r&&(clearTimeout(r),r=null),o&&o.parentNode&&o.parentNode.removeChild(o),t&&(et=!0),tt=null,e(t))},c=()=>{if(i>=n.length)return void a(!1);if(!document.head)return void a(!1);const e=n[i];i+=1;const t=document.createElement("script");o=t,t.src=e,t.async=!0,t.onload=()=>a(!0),t.onerror=()=>{t.parentNode&&t.parentNode.removeChild(t),o=null,c()},document.head.appendChild(t)};r=setTimeout(()=>{a(!1)},t),c()}),tt};let rt=null;const ot=async(e,t={})=>{const{timeoutMs:s=1e4}=t;return qe()?rt||(rt=(async()=>{if(!await st({timeoutMs:s}))return Ve.handleError(new n("WECHAT_JSSDK_LOAD_FAILED","微信 JS-SDK 加载失败","weixin"),"weixin"),!1;const t=Qe();if(!t||"function"!=typeof t.config||"function"!=typeof t.ready||"function"!=typeof t.error)return!1;const r=t.config,o=t.ready,i=t.error,a=await new Promise(t=>{let a=!1,c=null;const u=e=>{a||(a=!0,c&&(clearTimeout(c),c=null),t(e))};c=setTimeout(()=>u(!1),s);try{r({debug:e.debug||!1,appId:e.appId,timestamp:e.timestamp,nonceStr:e.nonceStr,signature:e.signature,jsApiList:e.jsApiList}),o(()=>u(!0)),i(e=>{Ve.handleError(new n("WECHAT_JSSDK_CONFIG_ERROR",`微信 JS-SDK 配置错误: ${(e=>{try{return JSON.stringify(e)}catch{return String(e)}})(e)}`,"weixin"),"weixin"),u(!1)})}catch(e){Ve.handleError(new n("WECHAT_JSSDK_CONFIG_EXCEPTION",`微信 JS-SDK 配置异常: ${e instanceof Error?e.message:String(e)}`,"weixin"),"weixin"),u(!1)}});return nt=a,a})().finally(()=>{rt=null}),rt):(console.warn("当前不在微信环境中"),!1)},it=(e,t={})=>{const{timeoutMs:s=8e3}=t;return new Promise(t=>{const r=Qe();if(!r||"function"!=typeof r.checkJsApi)return void t(Ze(e,!1));let o=!1;const i=e=>{o||(o=!0,t(e))},a=setTimeout(()=>i(Ze(e,!1)),s);try{r.checkJsApi({jsApiList:e,success:t=>{clearTimeout(a),i({...Ze(e,!1),...t?.checkResult||{}})}})}catch(t){clearTimeout(a),Ve.handleError(new n("CHECK_WECHAT_JSAPI_ERROR",`检查微信 JS-SDK API 异常: ${t instanceof Error?t.message:String(t)}`,"weixin"),"weixin"),i(Ze(e,!1))}})},at=e=>{const t=Qe();t&&(t.updateTimelineShareData?t.updateTimelineShareData(e):t.onMenuShareTimeline&&t.onMenuShareTimeline(e))},ct=e=>{const t=Qe();t&&(t.updateAppMessageShareData?t.updateAppMessageShareData(e):t.onMenuShareAppMessage&&t.onMenuShareAppMessage(e))};class ut{static instance;isConfigured=!1;config=null;initPromise=null;constructor(){}static getInstance(){return ut.instance||(ut.instance=new ut),ut.instance}async init(e){return this.initPromise||(this.config=e,this.initPromise=ot(e).then(e=>(this.isConfigured=e,e)).finally(()=>{this.initPromise=null})),this.initPromise}isReady(){return(this.isConfigured||nt)&&qe()}getConfig(){return this.config}setShareData(e){this.isReady()?(at(e),ct(e)):console.warn("微信 SDK 未就绪")}}const lt="5.0.0";export{s as ErrorHandler,n as UniAppToolsError,lt as VERSION,ut as WechatSDK,x as areaList,ue as batchGetStorage,ce as batchSetStorage,j as buildUrl,it as checkWechatJSAPI,ae as cleanExpiredStorage,se as clearStorageSync,l as clearSystemCache,ot as configWechatJSSDK,H as configureNavigation,X as copyText,I as debounce,v as deepClone,O as deepMerge,N as extractUrlParts,p as getCurrentEnv,z as getCurrentPageInfo,Re as getExtension,b as getH5UrlParams,w as getMenuButtonBoundingClientRect,_ as getNavHeight,E as getNavigationBarHeight,V as getPageStack,d as getPlatform,y as getStatusBarHeight,oe as getStorage,ie as getStorageInfo,ne as getStorageSync,S as getTopBarMetrics,R as getTopNavBarHeight,Je as injectAlipayJsSdk,qe as isWechat,st as loadWechatJSSDK,P as mergeObjects,Le as normalizeConcurrency,h as onCheckForUpdate,r as safeAsync,o as safeSync,Fe as selectAndUpload,je as selectAndUploadImage,A as setPageIcon,T as setPageTitle,re as setStorage,te as setStorageSync,ct as shareToFriend,at as shareToTimeline,L as throttle,G as useBack,J as useBackDebounced,W as useBackOrHome,F as useBuildUrl,$ as useCascaderAreaData,K as useCurrentPageInfo,Y as usePageStack,D as useRegions,M as useToast,g as useWindowInfo,Ie as validateSizeWithLimit,Ye as wechatH5Pay};
|
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 导航工具函数
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* 4. 移除性能监控(在开发环境手动测量即可)
|
|
9
|
-
* 5. 简化代码逻辑,提升可维护性
|
|
10
|
-
* 6. v4.0.0: 函数重新排序,抽取公共错误处理,补充详细注释
|
|
11
|
-
*/
|
|
12
|
-
/**
|
|
13
|
-
* 页面跳转选项
|
|
4
|
+
* 设计原则:
|
|
5
|
+
* - 消除重复:通用包装器统一处理
|
|
6
|
+
* - 明确语义:超时是等回调,不是等API
|
|
7
|
+
* - 避免竞态:保存初始状态,不重复查询
|
|
14
8
|
*/
|
|
15
9
|
export interface NavigateOptions {
|
|
16
10
|
url: string;
|
|
@@ -19,121 +13,39 @@ export interface NavigateOptions {
|
|
|
19
13
|
animationDuration?: number;
|
|
20
14
|
events?: Record<string, Function>;
|
|
21
15
|
}
|
|
22
|
-
/**
|
|
23
|
-
* 返回导航配置选项
|
|
24
|
-
*/
|
|
25
16
|
export interface BackOptions {
|
|
26
17
|
delta?: number;
|
|
27
18
|
timeout?: number;
|
|
28
19
|
}
|
|
29
|
-
/**
|
|
30
|
-
* 返回上一页或跳转首页选项
|
|
31
|
-
*/
|
|
32
20
|
export interface BackOrHomeOptions extends BackOptions {
|
|
33
21
|
homePage?: string;
|
|
34
22
|
homeParams?: Record<string, any>;
|
|
35
23
|
}
|
|
24
|
+
interface NavigationConfig {
|
|
25
|
+
defaultHomePage: string;
|
|
26
|
+
}
|
|
36
27
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* @param url 基础URL路径
|
|
40
|
-
* @param params URL查询参数对象
|
|
41
|
-
* @returns 完整的URL字符串
|
|
42
|
-
*
|
|
43
|
-
* @example
|
|
44
|
-
* buildUrl('/pages/detail/detail', { id: 123, type: 'product' })
|
|
45
|
-
* // 返回: '/pages/detail/detail?id=123&type=product'
|
|
46
|
-
*/
|
|
47
|
-
export declare function buildUrl(url: string, params?: Record<string, any>): string;
|
|
48
|
-
/**
|
|
49
|
-
* 跳转到指定页面(保留当前页面)
|
|
50
|
-
*
|
|
51
|
-
* @param options 导航选项
|
|
52
|
-
* @param options.url 目标页面路径(必填)
|
|
53
|
-
* @param options.params URL参数对象
|
|
54
|
-
* @param options.animationType 窗口显示动画效果
|
|
55
|
-
* @param options.animationDuration 窗口动画持续时间(毫秒)
|
|
56
|
-
* @param options.events 页面间通信接口
|
|
57
|
-
* @returns Promise<boolean> 返回 true 表示跳转成功,false 表示失败
|
|
58
|
-
*
|
|
59
|
-
* @example
|
|
60
|
-
* // 基础跳转
|
|
61
|
-
* await navigateTo({ url: '/pages/detail/detail' });
|
|
62
|
-
*
|
|
63
|
-
* // 带参数跳转
|
|
64
|
-
* await navigateTo({
|
|
65
|
-
* url: '/pages/detail/detail',
|
|
66
|
-
* params: { id: 123, type: 'product' }
|
|
67
|
-
* });
|
|
68
|
-
*
|
|
69
|
-
* // 带动画效果跳转
|
|
70
|
-
* await navigateTo({
|
|
71
|
-
* url: '/pages/detail/detail',
|
|
72
|
-
* animationType: 'slide-in-right',
|
|
73
|
-
* animationDuration: 300
|
|
74
|
-
* });
|
|
75
|
-
*/
|
|
76
|
-
export declare function navigateTo(options: NavigateOptions): Promise<boolean>;
|
|
77
|
-
/**
|
|
78
|
-
* 重定向到指定页面(关闭当前页面)
|
|
79
|
-
*
|
|
80
|
-
* @param options 导航选项
|
|
81
|
-
* @param options.url 目标页面路径(必填)
|
|
82
|
-
* @param options.params URL参数对象
|
|
83
|
-
* @returns Promise<boolean> 返回 true 表示重定向成功,false 表示失败
|
|
84
|
-
*
|
|
85
|
-
* @example
|
|
86
|
-
* // 重定向到登录页
|
|
87
|
-
* await redirectTo({ url: '/pages/login/login' });
|
|
88
|
-
*
|
|
89
|
-
* // 带参数重定向
|
|
90
|
-
* await redirectTo({
|
|
91
|
-
* url: '/pages/result/result',
|
|
92
|
-
* params: { status: 'success', orderId: '12345' }
|
|
93
|
-
* });
|
|
94
|
-
*/
|
|
95
|
-
export declare function redirectTo(options: NavigateOptions): Promise<boolean>;
|
|
96
|
-
/**
|
|
97
|
-
* 重新启动到指定页面(关闭所有页面)
|
|
98
|
-
*
|
|
99
|
-
* @param options 导航选项
|
|
100
|
-
* @param options.url 目标页面路径(必填)
|
|
101
|
-
* @param options.params URL参数对象
|
|
102
|
-
* @returns Promise<boolean> 返回 true 表示重启成功,false 表示失败
|
|
103
|
-
*
|
|
28
|
+
* 配置导航模块
|
|
104
29
|
* @example
|
|
105
|
-
*
|
|
106
|
-
* await reLaunch({ url: '/pages/index/index' });
|
|
107
|
-
*
|
|
108
|
-
* // 登录成功后重启应用
|
|
109
|
-
* await reLaunch({
|
|
110
|
-
* url: '/pages/home/home',
|
|
111
|
-
* params: { user: 'john' }
|
|
112
|
-
* });
|
|
30
|
+
* configureNavigation({ defaultHomePage: '/pages/home/home' });
|
|
113
31
|
*/
|
|
114
|
-
export declare function
|
|
32
|
+
export declare function configureNavigation(config: Partial<NavigationConfig>): void;
|
|
33
|
+
export declare function useBuildUrl(url: string, params?: Record<string, any>): string;
|
|
115
34
|
/**
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* @param url Tab页面路径
|
|
119
|
-
* @returns Promise<boolean> 返回 true 表示切换成功,false 表示失败
|
|
120
|
-
*
|
|
121
|
-
* @example
|
|
122
|
-
* // 切换到首页Tab
|
|
123
|
-
* await switchTab('/pages/index/index');
|
|
124
|
-
*
|
|
125
|
-
* // 切换到我的Tab
|
|
126
|
-
* await switchTab('/pages/user/user');
|
|
35
|
+
* @deprecated 请使用 useBuildUrl 替代(符合 Vue composable 命名约定)
|
|
127
36
|
*/
|
|
128
|
-
export declare
|
|
37
|
+
export declare const buildUrl: typeof useBuildUrl;
|
|
129
38
|
/**
|
|
130
39
|
* 返回上一页
|
|
131
40
|
*
|
|
132
41
|
* @param params 返回上一页时传入的参数(会调用目标页面的 init 方法)
|
|
133
42
|
* @param options 导航选项
|
|
134
43
|
* @param options.delta 返回的页面数,默认1
|
|
135
|
-
* @param options.timeout
|
|
136
|
-
* @returns Promise<boolean> 返回 true 表示导航成功,false
|
|
44
|
+
* @param options.timeout 回调执行超时时间(毫秒),默认5000(注意:这不是导航API本身的超时)
|
|
45
|
+
* @returns Promise<boolean> 返回 true 表示导航成功,false 表示失败(页面栈不足或回调超时)
|
|
46
|
+
*
|
|
47
|
+
* @description
|
|
48
|
+
* 注意:timeout 参数并非导航API本身的超时(navigateBack是同步的),而是等待"页面切换完成 + init回调执行"的超时。
|
|
137
49
|
*
|
|
138
50
|
* @example
|
|
139
51
|
* // 基础返回
|
|
@@ -145,32 +57,10 @@ export declare function switchTab(url: string): Promise<boolean>;
|
|
|
145
57
|
* // 返回两层页面
|
|
146
58
|
* await useBack('', { delta: 2 });
|
|
147
59
|
*
|
|
148
|
-
* //
|
|
60
|
+
* // 设置回调执行超时时间
|
|
149
61
|
* await useBack('', { timeout: 3000 });
|
|
150
62
|
*/
|
|
151
63
|
export declare function useBack(params?: any, options?: BackOptions): Promise<boolean>;
|
|
152
|
-
/**
|
|
153
|
-
* 安全的页面跳转(带重试机制)
|
|
154
|
-
*
|
|
155
|
-
* @param options 导航选项
|
|
156
|
-
* @param maxRetries 最大重试次数,默认3次
|
|
157
|
-
* @returns Promise<boolean> 返回 true 表示跳转成功,false 表示所有重试都失败
|
|
158
|
-
*
|
|
159
|
-
* @description
|
|
160
|
-
* 当页面跳转失败时,会自动重试指定次数。
|
|
161
|
-
* 重试间隔会逐渐增加:第1次等待1秒,第2次等待2秒,第3次等待3秒
|
|
162
|
-
*
|
|
163
|
-
* @example
|
|
164
|
-
* // 使用默认重试次数(3次)
|
|
165
|
-
* const success = await safeNavigateTo({ url: '/pages/detail/detail' });
|
|
166
|
-
*
|
|
167
|
-
* // 自定义重试次数
|
|
168
|
-
* const success = await safeNavigateTo(
|
|
169
|
-
* { url: '/pages/detail/detail' },
|
|
170
|
-
* 5 // 最多重试5次
|
|
171
|
-
* );
|
|
172
|
-
*/
|
|
173
|
-
export declare function safeNavigateTo(options: NavigateOptions, maxRetries?: number): Promise<boolean>;
|
|
174
64
|
/**
|
|
175
65
|
* 返回上一页,若页面栈不足则重定向到首页
|
|
176
66
|
*
|
|
@@ -178,7 +68,7 @@ export declare function safeNavigateTo(options: NavigateOptions, maxRetries?: nu
|
|
|
178
68
|
* @param options 导航选项
|
|
179
69
|
* @param options.delta 返回的页面数,默认1
|
|
180
70
|
* @param options.timeout 超时时间(毫秒),默认5000
|
|
181
|
-
* @param options.homePage
|
|
71
|
+
* @param options.homePage 首页路径,默认使用全局配置(可通过 configureNavigation 设置)
|
|
182
72
|
* @param options.homeParams 首页参数
|
|
183
73
|
* @returns Promise<boolean> 返回 true 表示操作成功,false 表示失败
|
|
184
74
|
*
|
|
@@ -186,12 +76,13 @@ export declare function safeNavigateTo(options: NavigateOptions, maxRetries?: nu
|
|
|
186
76
|
* 智能返回函数:
|
|
187
77
|
* - 如果页面栈深度足够,执行正常返回
|
|
188
78
|
* - 如果页面栈深度不足(如只有1个页面),则重定向到首页
|
|
79
|
+
* - 首页路径优先级:传入的 homePage > 全局配置 > 默认值 '/pages/index/index'
|
|
189
80
|
*
|
|
190
81
|
* @example
|
|
191
|
-
* //
|
|
82
|
+
* // 基础使用(页面栈不足时跳转到全局配置的首页)
|
|
192
83
|
* await useBackOrHome();
|
|
193
84
|
*
|
|
194
|
-
* //
|
|
85
|
+
* // 自定义首页路径(临时覆盖全局配置)
|
|
195
86
|
* await useBackOrHome('', {
|
|
196
87
|
* homePage: '/pages/home/home',
|
|
197
88
|
* homeParams: { from: 'auto' }
|
|
@@ -211,7 +102,9 @@ export declare function useBackOrHome(params?: any, options?: BackOrHomeOptions)
|
|
|
211
102
|
* // 在按钮点击事件中使用
|
|
212
103
|
* <button @click="useBackDebounced()">返回</button>
|
|
213
104
|
*/
|
|
214
|
-
export declare const useBackDebounced: typeof useBack
|
|
105
|
+
export declare const useBackDebounced: typeof useBack & {
|
|
106
|
+
cancel: () => void;
|
|
107
|
+
};
|
|
215
108
|
/**
|
|
216
109
|
* 获取当前页面信息
|
|
217
110
|
*
|
|
@@ -220,7 +113,7 @@ export declare const useBackDebounced: typeof useBack;
|
|
|
220
113
|
* @returns {any} options 当前页面的参数对象
|
|
221
114
|
*
|
|
222
115
|
* @example
|
|
223
|
-
* const pageInfo =
|
|
116
|
+
* const pageInfo = useCurrentPageInfo();
|
|
224
117
|
* if (pageInfo) {
|
|
225
118
|
* console.log('当前页面路由:', pageInfo.route);
|
|
226
119
|
* console.log('当前页面参数:', pageInfo.options);
|
|
@@ -232,10 +125,14 @@ export declare const useBackDebounced: typeof useBack;
|
|
|
232
125
|
* // options: { id: '123', type: 'product' }
|
|
233
126
|
* // }
|
|
234
127
|
*/
|
|
235
|
-
export declare function
|
|
128
|
+
export declare function useCurrentPageInfo(): {
|
|
236
129
|
route: string;
|
|
237
130
|
options: any;
|
|
238
131
|
} | null;
|
|
132
|
+
/**
|
|
133
|
+
* @deprecated 请使用 useCurrentPageInfo 替代(符合 Vue composable 命名约定)
|
|
134
|
+
*/
|
|
135
|
+
export declare const getCurrentPageInfo: typeof useCurrentPageInfo;
|
|
239
136
|
/**
|
|
240
137
|
* 获取页面栈信息
|
|
241
138
|
*
|
|
@@ -246,7 +143,7 @@ export declare function getCurrentPageInfo(): {
|
|
|
246
143
|
* 数组索引0是最底层的页面,最后一个元素是当前页面。
|
|
247
144
|
*
|
|
248
145
|
* @example
|
|
249
|
-
* const stack =
|
|
146
|
+
* const stack = usePageStack();
|
|
250
147
|
* console.log('页面栈深度:', stack.length);
|
|
251
148
|
* console.log('第一个页面:', stack[0]);
|
|
252
149
|
* console.log('当前页面:', stack[stack.length - 1]);
|
|
@@ -258,7 +155,12 @@ export declare function getCurrentPageInfo(): {
|
|
|
258
155
|
* // { route: 'pages/detail/detail', options: { id: '123' } }
|
|
259
156
|
* // ]
|
|
260
157
|
*/
|
|
261
|
-
export declare function
|
|
158
|
+
export declare function usePageStack(): Array<{
|
|
262
159
|
route: string;
|
|
263
160
|
options: any;
|
|
264
161
|
}>;
|
|
162
|
+
/**
|
|
163
|
+
* @deprecated 请使用 usePageStack 替代(符合 Vue composable 命名约定)
|
|
164
|
+
*/
|
|
165
|
+
export declare const getPageStack: typeof usePageStack;
|
|
166
|
+
export {};
|
package/dist/ui/index.d.ts
CHANGED
package/dist/upload/index.d.ts
CHANGED
|
@@ -1,162 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* 多端文件上传工具 (Refactored)
|
|
3
|
+
* @description
|
|
4
|
+
* 统一对外入口,基于运行时环境检测实现平台代码分离
|
|
5
|
+
*
|
|
6
|
+
* 核心重构目标:
|
|
7
|
+
* 1. H5/Uni 平台实现分离,保证对外 API 行为一致
|
|
8
|
+
* 2. 简化配置参数结构 (UploadOptions)
|
|
9
|
+
* 3. 移除过度抽象 (Settler)
|
|
5
10
|
*/
|
|
6
|
-
import {
|
|
7
|
-
/**
|
|
8
|
-
* 单个文件的统一描述结构
|
|
9
|
-
* 将各平台返回值规整成统一的 UniFile,方便业务使用
|
|
10
|
-
*/
|
|
11
|
-
export interface UniFile {
|
|
12
|
-
/** 文件唯一标识(由本工具生成) */
|
|
13
|
-
id: string;
|
|
14
|
-
/** 文件名 */
|
|
15
|
-
name: string;
|
|
16
|
-
/** 文件大小(字节) */
|
|
17
|
-
size: number;
|
|
18
|
-
/** 本地临时路径 / H5 对象 URL */
|
|
19
|
-
path: string;
|
|
20
|
-
/** MIME 类型(如果可用) */
|
|
21
|
-
mimeType?: string;
|
|
22
|
-
/** 文件扩展名(不带点,例如:jpg、png) */
|
|
23
|
-
ext?: string;
|
|
24
|
-
/** 文件来源(相册、相机、本地文件等) */
|
|
25
|
-
source?: 'camera' | 'album' | 'file' | 'chat' | 'unknown';
|
|
26
|
-
/** 运行平台(仅作标记使用) */
|
|
27
|
-
platform?: 'weixin' | 'alipay' | 'h5' | 'app' | 'unknown';
|
|
28
|
-
/** 平台原始返回对象,保留以备高级用法 */
|
|
29
|
-
raw?: unknown;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* 选择 + 上传 一体化配置
|
|
33
|
-
*/
|
|
34
|
-
export interface SelectAndUploadOptions {
|
|
35
|
-
/** 上传服务器地址 */
|
|
36
|
-
url: string;
|
|
37
|
-
/** 选择的文件类型 */
|
|
38
|
-
type?: 'image' | 'file' | 'any';
|
|
39
|
-
/** 最多可以选择的文件数量 */
|
|
40
|
-
count?: number;
|
|
41
|
-
/** 选择阶段:单个文件允许的最大体积(MB),超出则认为选择失败 */
|
|
42
|
-
maxSelectFileSizeMB?: number;
|
|
43
|
-
/** 上传阶段:单个文件允许的最大体积(MB),超出则不会发起上传请求 */
|
|
44
|
-
maxUploadFileSizeMB?: number;
|
|
45
|
-
/** 允许的文件扩展名(不带点,例如:['jpg','png']) */
|
|
46
|
-
extensions?: string[];
|
|
47
|
-
/**
|
|
48
|
-
* 选择阶段扩展名校验策略(默认 strict,保持向后兼容)
|
|
49
|
-
* @description
|
|
50
|
-
* - strict:无扩展名或不在白名单中则判定失败(旧行为)
|
|
51
|
-
* - mimeTypeFallback:无扩展名时尝试用 `mimeType` 推断扩展名再校验
|
|
52
|
-
* - allowNoExtension:无扩展名时跳过扩展名校验(风险:可能放行不期望文件)
|
|
53
|
-
*/
|
|
54
|
-
extensionValidationPolicy?: 'strict' | 'mimeTypeFallback' | 'allowNoExtension';
|
|
55
|
-
/** 表单字段名,后端通过此字段接收文件 */
|
|
56
|
-
fieldName?: string;
|
|
57
|
-
/**
|
|
58
|
-
* 额外的表单字段
|
|
59
|
-
* @description
|
|
60
|
-
* - H5:通过 FormData.append 发送,值会被序列化为字符串(对象/数组默认 JSON.stringify)
|
|
61
|
-
* - 小程序/App:通过 uni.uploadFile 的 formData 发送,值同样会被序列化为字符串以保持一致性
|
|
62
|
-
*/
|
|
63
|
-
formData?: Record<string, unknown>;
|
|
64
|
-
/** HTTP 请求头 */
|
|
65
|
-
headers?: Record<string, string>;
|
|
66
|
-
/** 单次最大并发上传数量(默认与文件数相同,即全部并行) */
|
|
67
|
-
concurrency?: number;
|
|
68
|
-
/** 上传超时(毫秒),超时将中止上传并返回失败结果 */
|
|
69
|
-
uploadTimeoutMs?: number;
|
|
70
|
-
/**
|
|
71
|
-
* H5 环境下是否在上传结束后自动释放 `URL.createObjectURL` 创建的对象 URL
|
|
72
|
-
* @description
|
|
73
|
-
* - 默认 false:保持旧行为不变(部分业务可能在上传后仍需要用 path 预览)
|
|
74
|
-
* - 若业务不再需要该 blob URL,建议开启以减少长时间使用下的内存占用
|
|
75
|
-
*/
|
|
76
|
-
autoRevokeObjectURL?: boolean;
|
|
77
|
-
/**
|
|
78
|
-
* 上传前拦截钩子
|
|
79
|
-
* 返回 false 或 Promise<false> 将跳过该文件的上传,并在结果中标记为失败(不弹 toast)
|
|
80
|
-
*/
|
|
81
|
-
beforeUpload?: (file: UniFile) => boolean | Promise<boolean>;
|
|
82
|
-
/** 是否显示 toast 提示,默认 true */
|
|
83
|
-
showToast?: boolean;
|
|
84
|
-
/** 上传成功的提示信息(仅单文件上传时生效) */
|
|
85
|
-
successMessage?: string;
|
|
86
|
-
/** 上传失败的默认提示信息 */
|
|
87
|
-
failMessage?: string;
|
|
88
|
-
/** 上传进度回调 */
|
|
89
|
-
onProgress?: (file: UniFile, progress: number) => void;
|
|
90
|
-
/**
|
|
91
|
-
* 是否显示上传进度 Toast,默认 false
|
|
92
|
-
* @description
|
|
93
|
-
* - 开启后会使用 uni.showLoading 显示上传进度
|
|
94
|
-
* - 单文件上传显示 "上传中 XX%"
|
|
95
|
-
* - 多文件上传显示 "上传中 (X/总数) XX%"
|
|
96
|
-
* - 进度更新会自动节流(200ms),避免性能问题
|
|
97
|
-
*/
|
|
98
|
-
showProgressToast?: boolean;
|
|
99
|
-
/**
|
|
100
|
-
* 自定义进度 Toast 内容生成函数
|
|
101
|
-
* @param file 当前上传的文件
|
|
102
|
-
* @param progress 上传进度(0-100)
|
|
103
|
-
* @param currentIndex 当前文件索引(从1开始,多文件上传时有值)
|
|
104
|
-
* @param totalCount 总文件数(多文件上传时有值)
|
|
105
|
-
* @returns 要显示的 Toast 文案
|
|
106
|
-
* @example
|
|
107
|
-
* progressToastFormatter: (file, progress, currentIndex, totalCount) => {
|
|
108
|
-
* if (totalCount && totalCount > 1) {
|
|
109
|
-
* return `正在上传 ${file.name} (${currentIndex}/${totalCount}) ${progress}%`;
|
|
110
|
-
* }
|
|
111
|
-
* return `上传中 ${progress}%`;
|
|
112
|
-
* }
|
|
113
|
-
*/
|
|
114
|
-
progressToastFormatter?: (file: UniFile, progress: number, currentIndex?: number, totalCount?: number) => string;
|
|
115
|
-
/** 可选的取消信号(支持 AbortController.signal),上传在收到 signal.aborted 时会中止 */
|
|
116
|
-
signal?: AbortSignal;
|
|
117
|
-
/**
|
|
118
|
-
* 可注入的 toast 函数,默认使用内部 `useToast`,用于降低与 UI 的耦合,便于测试
|
|
119
|
-
* 类型与 `useToast` 保持一致
|
|
120
|
-
*/
|
|
121
|
-
toast?: typeof useToast;
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* 单个文件的上传结果
|
|
125
|
-
*/
|
|
126
|
-
export interface UploadResult {
|
|
127
|
-
/** 对应的文件,选择阶段失败时为 null */
|
|
128
|
-
file: UniFile | null;
|
|
129
|
-
/** 是否上传成功 */
|
|
130
|
-
success: boolean;
|
|
131
|
-
/** HTTP 状态码(如果有) */
|
|
132
|
-
statusCode?: number;
|
|
133
|
-
/** 服务器返回的数据(成功或失败时的响应体) */
|
|
134
|
-
data?: unknown;
|
|
135
|
-
/** 提示信息 */
|
|
136
|
-
message?: string;
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* 根据文件名或路径提取扩展名(不带点)
|
|
140
|
-
*/
|
|
141
|
-
export declare function getExtension(path: string): string | undefined;
|
|
142
|
-
/**
|
|
143
|
-
* 将文件大小(字节)与 MB 限制进行比较
|
|
144
|
-
* @param size 文件大小(字节)
|
|
145
|
-
* @param maxMB 限制(MB)
|
|
146
|
-
*/
|
|
147
|
-
export declare function validateSizeWithLimit(size: number, maxMB?: number): {
|
|
148
|
-
valid: boolean;
|
|
149
|
-
message?: string;
|
|
150
|
-
};
|
|
11
|
+
import { UploadOptions, UploadResult } from './types';
|
|
151
12
|
/**
|
|
152
13
|
* 选择并上传文件(业务一体化入口)
|
|
153
14
|
* @param options 选择与上传配置
|
|
154
|
-
* @returns 每个文件对应的上传结果列表
|
|
155
15
|
*/
|
|
156
|
-
export declare function selectAndUpload(options:
|
|
16
|
+
export declare function selectAndUpload(options: UploadOptions): Promise<UploadResult[]>;
|
|
157
17
|
/**
|
|
158
18
|
* 选择并上传图片的便捷方法
|
|
159
19
|
* 等价于在 selectAndUpload 中指定 type: 'image'
|
|
160
20
|
* @param options 业务配置
|
|
161
21
|
*/
|
|
162
|
-
export declare function selectAndUploadImage(options: Omit<
|
|
22
|
+
export declare function selectAndUploadImage(options: Omit<UploadOptions, 'type'>): Promise<UploadResult[]>;
|
|
23
|
+
export * from './types';
|
|
24
|
+
export { getExtension, normalizeConcurrency, validateFileSize as validateSizeWithLimit } from './utils';
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { useCascaderAreaData as vantUseCascaderAreaData } from '@vant/area-data';
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* @description H5 环境优先使用 structuredClone
|
|
6
|
+
* 高性能深拷贝(uni-app 多端兼容)
|
|
7
|
+
* @description H5 环境优先使用 structuredClone,降级为 JSON 序列化
|
|
8
8
|
*/
|
|
9
9
|
export declare function deepClone<T>(obj: T): T;
|
|
10
10
|
/**
|
|
@@ -18,26 +18,30 @@ export declare function deepMerge<T extends Record<string, any>>(target: T, sour
|
|
|
18
18
|
export declare function mergeObjects<T extends Record<string, any>, U extends Record<string, any>>(base: T, incoming: U): T;
|
|
19
19
|
/**
|
|
20
20
|
* 防抖函数
|
|
21
|
+
* @description 延迟执行,重复触发则重置定时器
|
|
22
|
+
* @param func 要防抖的函数
|
|
23
|
+
* @param wait 延迟时间(毫秒)
|
|
24
|
+
* @param immediate 是否立即执行(首次触发时)
|
|
25
|
+
* @returns 防抖包装后的函数,附带 cancel 方法
|
|
21
26
|
*/
|
|
22
|
-
export declare function debounce<T extends (...args: any[]) => any>(func: T, wait: number, immediate?: boolean): T
|
|
27
|
+
export declare function debounce<T extends (...args: any[]) => any>(func: T, wait: number, immediate?: boolean): T & {
|
|
28
|
+
cancel: () => void;
|
|
29
|
+
};
|
|
23
30
|
/**
|
|
24
31
|
* 节流函数
|
|
32
|
+
* @description 限制执行频率,确保在时间窗口内只执行一次
|
|
33
|
+
* @param func 要节流的函数
|
|
34
|
+
* @param wait 时间窗口(毫秒)
|
|
35
|
+
* @param options.leading 是否在时间窗口开始时执行(默认 true)
|
|
36
|
+
* @param options.trailing 是否在时间窗口结束时执行(默认 true)
|
|
37
|
+
* @returns 节流包装后的函数,附带 cancel 方法
|
|
25
38
|
*/
|
|
26
39
|
export declare function throttle<T extends (...args: any[]) => any>(func: T, wait: number, options?: {
|
|
27
40
|
leading?: boolean;
|
|
28
41
|
trailing?: boolean;
|
|
29
|
-
}): T
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
* @returns 包装后的执行函数,返回 Promise<{ data, error }>
|
|
33
|
-
*/
|
|
34
|
-
export declare function useTryCatch<T extends (...args: any[]) => any>(fn: T, options?: {
|
|
35
|
-
onError?: (error: unknown) => void;
|
|
36
|
-
onFinally?: () => void;
|
|
37
|
-
}): (...args: Parameters<T>) => Promise<{
|
|
38
|
-
data: Awaited<ReturnType<T>> | null;
|
|
39
|
-
error: unknown;
|
|
40
|
-
}>;
|
|
42
|
+
}): T & {
|
|
43
|
+
cancel: () => void;
|
|
44
|
+
};
|
|
41
45
|
export interface UrlParams {
|
|
42
46
|
[key: string]: string;
|
|
43
47
|
}
|