my-uniapp-tools 1.0.12 → 1.0.14
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 +688 -477
- package/dist/index.d.ts +1 -0
- package/dist/my-uniapp-tools.cjs.js +568 -39
- package/dist/my-uniapp-tools.cjs.js.map +1 -1
- package/dist/my-uniapp-tools.esm.js +560 -40
- package/dist/my-uniapp-tools.esm.js.map +1 -1
- package/dist/system/index.d.ts +21 -0
- package/dist/upload/index.d.ts +153 -0
- package/package.json +72 -73
- package/OPTIMIZATION_REPORT.md +0 -278
|
@@ -1331,6 +1331,72 @@ const getTopNavBarHeight = () => {
|
|
|
1331
1331
|
};
|
|
1332
1332
|
}
|
|
1333
1333
|
};
|
|
1334
|
+
/**
|
|
1335
|
+
* 修改浏览器标题
|
|
1336
|
+
* @param title 新的页面标题
|
|
1337
|
+
* @description 动态修改浏览器标签页显示的标题,仅在H5/Web平台有效
|
|
1338
|
+
* @example
|
|
1339
|
+
* // 修改页面标题
|
|
1340
|
+
* setPageTitle('新的页面标题')
|
|
1341
|
+
*/
|
|
1342
|
+
const setPageTitle = (title) => {
|
|
1343
|
+
return safeSync(() => {
|
|
1344
|
+
const platform = getPlatform();
|
|
1345
|
+
// 只在H5/Web平台执行
|
|
1346
|
+
if (platform === 'h5' || platform === 'web') {
|
|
1347
|
+
// #ifdef H5 || WEB
|
|
1348
|
+
if (typeof document !== 'undefined') {
|
|
1349
|
+
document.title = title;
|
|
1350
|
+
console.log('页面标题已更新为:', title);
|
|
1351
|
+
return true;
|
|
1352
|
+
}
|
|
1353
|
+
// #endif
|
|
1354
|
+
}
|
|
1355
|
+
else {
|
|
1356
|
+
console.warn('setPageTitle 仅在H5/Web平台有效');
|
|
1357
|
+
}
|
|
1358
|
+
return false;
|
|
1359
|
+
}, 'system', 'SET_PAGE_TITLE_ERROR', false);
|
|
1360
|
+
};
|
|
1361
|
+
/**
|
|
1362
|
+
* 修改浏览器图标(favicon)
|
|
1363
|
+
* @param iconUrl 新的图标URL地址
|
|
1364
|
+
* @param iconType 图标类型,默认为 'image/x-icon'
|
|
1365
|
+
* @description 动态修改浏览器标签页显示的图标,仅在H5/Web平台有效
|
|
1366
|
+
* @example
|
|
1367
|
+
* // 修改页面图标
|
|
1368
|
+
* setPageIcon('https://example.com/new-icon.ico')
|
|
1369
|
+
* // 或使用PNG格式
|
|
1370
|
+
* setPageIcon('https://example.com/new-icon.png', 'image/png')
|
|
1371
|
+
*/
|
|
1372
|
+
const setPageIcon = (iconUrl, iconType = 'image/x-icon') => {
|
|
1373
|
+
return safeSync(() => {
|
|
1374
|
+
const platform = getPlatform();
|
|
1375
|
+
// 只在H5/Web平台执行
|
|
1376
|
+
if (platform === 'h5' || platform === 'web') {
|
|
1377
|
+
// #ifdef H5 || WEB
|
|
1378
|
+
if (typeof document !== 'undefined') {
|
|
1379
|
+
// 移除现有的favicon链接
|
|
1380
|
+
const existingLinks = document.querySelectorAll('link[rel*="icon"]');
|
|
1381
|
+
existingLinks.forEach(link => link.remove());
|
|
1382
|
+
// 创建新的favicon链接
|
|
1383
|
+
const link = document.createElement('link');
|
|
1384
|
+
link.rel = 'icon';
|
|
1385
|
+
link.type = iconType;
|
|
1386
|
+
link.href = iconUrl;
|
|
1387
|
+
// 添加到head中
|
|
1388
|
+
document.head.appendChild(link);
|
|
1389
|
+
console.log('页面图标已更新为:', iconUrl);
|
|
1390
|
+
return true;
|
|
1391
|
+
}
|
|
1392
|
+
// #endif
|
|
1393
|
+
}
|
|
1394
|
+
else {
|
|
1395
|
+
console.warn('setPageIcon 仅在H5/Web平台有效');
|
|
1396
|
+
}
|
|
1397
|
+
return false;
|
|
1398
|
+
}, 'system', 'SET_PAGE_ICON_ERROR', false);
|
|
1399
|
+
};
|
|
1334
1400
|
|
|
1335
1401
|
/**
|
|
1336
1402
|
* 本地存储相关工具函数(优化版本)
|
|
@@ -1687,46 +1753,500 @@ function batchGetStorage(keys) {
|
|
|
1687
1753
|
return result;
|
|
1688
1754
|
}
|
|
1689
1755
|
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1756
|
+
/**
|
|
1757
|
+
* 文件上传相关工具函数
|
|
1758
|
+
* 支持微信小程序、支付宝小程序、H5多端兼容
|
|
1759
|
+
*/
|
|
1760
|
+
/**
|
|
1761
|
+
* 默认上传配置
|
|
1762
|
+
*/
|
|
1763
|
+
const DEFAULT_UPLOAD_CONFIG = {
|
|
1764
|
+
name: 'file',
|
|
1765
|
+
maxSize: 10, // 10MB
|
|
1766
|
+
allowedTypes: ['jpg', 'jpeg', 'png', 'gif', 'webp'],
|
|
1767
|
+
showToast: true,
|
|
1768
|
+
timeout: 60000, // 60秒
|
|
1769
|
+
successMessage: '上传成功',
|
|
1770
|
+
failMessage: '上传失败'
|
|
1771
|
+
};
|
|
1772
|
+
/**
|
|
1773
|
+
* 默认选择文件配置
|
|
1774
|
+
*/
|
|
1775
|
+
const DEFAULT_CHOOSE_CONFIG = {
|
|
1776
|
+
type: 'image',
|
|
1777
|
+
count: 1,
|
|
1778
|
+
sizeType: ['original', 'compressed'],
|
|
1779
|
+
sourceType: ['album', 'camera'],
|
|
1780
|
+
extension: [],
|
|
1781
|
+
maxSize: 10, // 10MB
|
|
1782
|
+
showToast: true,
|
|
1783
|
+
failMessage: '选择文件失败'
|
|
1784
|
+
};
|
|
1785
|
+
/**
|
|
1786
|
+
* 验证文件大小和类型
|
|
1787
|
+
* @param filePath 文件路径
|
|
1788
|
+
* @param config 配置
|
|
1789
|
+
* @returns 验证结果
|
|
1790
|
+
*/
|
|
1791
|
+
function validateFile(filePath, config) {
|
|
1792
|
+
if (!filePath) {
|
|
1793
|
+
return { valid: false, message: '文件路径不能为空' };
|
|
1794
|
+
}
|
|
1795
|
+
// 验证文件类型
|
|
1796
|
+
if (config.allowedTypes && config.allowedTypes.length > 0) {
|
|
1797
|
+
const fileExtension = filePath.split('.').pop()?.toLowerCase();
|
|
1798
|
+
if (!fileExtension || !config.allowedTypes.includes(fileExtension)) {
|
|
1799
|
+
return {
|
|
1800
|
+
valid: false,
|
|
1801
|
+
message: `不支持的文件类型,仅支持:${config.allowedTypes.join(', ')}`
|
|
1802
|
+
};
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
return { valid: true };
|
|
1806
|
+
}
|
|
1807
|
+
/**
|
|
1808
|
+
* 验证文件大小
|
|
1809
|
+
* @param fileSize 文件大小(字节)
|
|
1810
|
+
* @param maxSize 最大大小(MB)
|
|
1811
|
+
* @returns 验证结果
|
|
1812
|
+
*/
|
|
1813
|
+
function validateFileSize(fileSize, maxSize) {
|
|
1814
|
+
if (!maxSize)
|
|
1815
|
+
return { valid: true };
|
|
1816
|
+
const maxSizeBytes = maxSize * 1024 * 1024;
|
|
1817
|
+
if (fileSize > maxSizeBytes) {
|
|
1818
|
+
return {
|
|
1819
|
+
valid: false,
|
|
1820
|
+
message: `文件大小不能超过 ${maxSize}MB`
|
|
1821
|
+
};
|
|
1822
|
+
}
|
|
1823
|
+
return { valid: true };
|
|
1824
|
+
}
|
|
1825
|
+
/**
|
|
1826
|
+
* 检查平台是否支持指定的文件选择类型
|
|
1827
|
+
*/
|
|
1828
|
+
const isPlatformSupported = (type) => {
|
|
1829
|
+
// #ifdef MP-WEIXIN
|
|
1830
|
+
if (type === 'messagefile') {
|
|
1831
|
+
return typeof uni.chooseMessageFile === 'function';
|
|
1832
|
+
}
|
|
1833
|
+
// #endif
|
|
1834
|
+
if (type === 'local') {
|
|
1835
|
+
// #ifdef H5
|
|
1836
|
+
return true; // H5支持本地文件选择
|
|
1837
|
+
// #endif
|
|
1838
|
+
}
|
|
1839
|
+
// image类型所有平台都支持
|
|
1840
|
+
if (type === 'image') {
|
|
1841
|
+
return true;
|
|
1842
|
+
}
|
|
1843
|
+
return false;
|
|
1844
|
+
};
|
|
1845
|
+
/**
|
|
1846
|
+
* 选择文件
|
|
1847
|
+
* @param config 选择配置
|
|
1848
|
+
* @returns Promise<ChooseFileResult> 选择结果
|
|
1849
|
+
*/
|
|
1850
|
+
// #ifdef H5
|
|
1851
|
+
/**
|
|
1852
|
+
* 创建H5文件选择的input元素, 并处理文件选择回调
|
|
1853
|
+
* @param {ChooseFileConfig} config - 文件选择的配置
|
|
1854
|
+
* @param {(res: ChooseFileResult) => void} resolve - Promise的resolve函数
|
|
1855
|
+
* @private
|
|
1856
|
+
*/
|
|
1857
|
+
function _createH5FileInput(config, resolve) {
|
|
1858
|
+
const input = document.createElement('input');
|
|
1859
|
+
input.type = 'file';
|
|
1860
|
+
input.multiple = config.count > 1;
|
|
1861
|
+
if (config.type === 'image') {
|
|
1862
|
+
input.accept = 'image/*';
|
|
1863
|
+
}
|
|
1864
|
+
else if (config.extension.length > 0) {
|
|
1865
|
+
input.accept = config.extension.map(ext => (ext.startsWith('.') ? ext : `.${ext}`)).join(',');
|
|
1866
|
+
}
|
|
1867
|
+
input.onchange = (event) => {
|
|
1868
|
+
const files = event.target.files;
|
|
1869
|
+
if (files && files.length > 0) {
|
|
1870
|
+
const tempFiles = Array.from(files).map(file => {
|
|
1871
|
+
/**
|
|
1872
|
+
* @description 创建一个临时的对象URL。
|
|
1873
|
+
* 注意:这个URL在不再需要时,建议调用 URL.revokeObjectURL() 来释放内存,以避免内存泄漏。
|
|
1874
|
+
*/
|
|
1875
|
+
const path = URL.createObjectURL(file);
|
|
1876
|
+
return {
|
|
1877
|
+
path,
|
|
1878
|
+
size: file.size,
|
|
1879
|
+
name: file.name,
|
|
1880
|
+
type: file.type,
|
|
1881
|
+
file // H5 only
|
|
1882
|
+
};
|
|
1883
|
+
});
|
|
1884
|
+
const normalizedTempFiles = tempFiles.map(file => ({
|
|
1885
|
+
path: file.path,
|
|
1886
|
+
size: file.size,
|
|
1887
|
+
}));
|
|
1888
|
+
resolve({
|
|
1889
|
+
success: true,
|
|
1890
|
+
tempFilePaths: tempFiles.map(f => f.path),
|
|
1891
|
+
tempFiles: normalizedTempFiles,
|
|
1892
|
+
type: config.type
|
|
1893
|
+
});
|
|
1894
|
+
}
|
|
1895
|
+
else {
|
|
1896
|
+
// 用户取消了文件选择
|
|
1897
|
+
resolve({
|
|
1898
|
+
success: false,
|
|
1899
|
+
message: '用户取消选择',
|
|
1900
|
+
type: config.type
|
|
1901
|
+
});
|
|
1902
|
+
}
|
|
1903
|
+
// 从DOM中移除input元素以进行清理
|
|
1904
|
+
document.body.removeChild(input);
|
|
1905
|
+
};
|
|
1906
|
+
// 触发文件选择对话框
|
|
1907
|
+
input.style.display = 'none';
|
|
1908
|
+
document.body.appendChild(input);
|
|
1909
|
+
input.click();
|
|
1910
|
+
}
|
|
1911
|
+
// #endif
|
|
1912
|
+
async function chooseFile(config = {}) {
|
|
1913
|
+
const monitor = PerformanceMonitor.getInstance();
|
|
1914
|
+
monitor.start('chooseFile', 'upload', { count: config.count, type: config.type });
|
|
1915
|
+
const finalConfig = { ...DEFAULT_CHOOSE_CONFIG, ...config };
|
|
1916
|
+
let actualType = finalConfig.type;
|
|
1917
|
+
// 检查平台支持,不支持则降级到image
|
|
1918
|
+
if (!isPlatformSupported(actualType)) {
|
|
1919
|
+
actualType = 'image';
|
|
1920
|
+
console.warn(`当前平台不支持${finalConfig.type}类型,已降级为image类型`);
|
|
1921
|
+
}
|
|
1922
|
+
const result = await safeAsync(() => new Promise((resolve) => {
|
|
1923
|
+
const failCallback = (err) => {
|
|
1924
|
+
const message = err.errMsg || finalConfig.failMessage;
|
|
1925
|
+
if (finalConfig.showToast) {
|
|
1926
|
+
useToast(message, false, 'error');
|
|
1927
|
+
}
|
|
1928
|
+
resolve({ success: false, message, type: actualType });
|
|
1929
|
+
};
|
|
1930
|
+
// #ifdef H5
|
|
1931
|
+
if (actualType === 'image' || actualType === 'local') {
|
|
1932
|
+
_createH5FileInput(finalConfig, resolve);
|
|
1933
|
+
return;
|
|
1934
|
+
}
|
|
1935
|
+
// #endif
|
|
1936
|
+
// #ifdef MP-WEIXIN
|
|
1937
|
+
if (actualType === 'messagefile') {
|
|
1938
|
+
uni.chooseMessageFile({
|
|
1939
|
+
count: finalConfig.count,
|
|
1940
|
+
type: 'all',
|
|
1941
|
+
success: (res) => {
|
|
1942
|
+
// chooseMessageFile 返回的 tempFiles 结构是标准的,直接使用
|
|
1943
|
+
resolve({
|
|
1944
|
+
success: true,
|
|
1945
|
+
tempFilePaths: res.tempFiles.map(f => f.path),
|
|
1946
|
+
tempFiles: res.tempFiles,
|
|
1947
|
+
type: 'messagefile'
|
|
1948
|
+
});
|
|
1949
|
+
},
|
|
1950
|
+
fail: failCallback
|
|
1951
|
+
});
|
|
1952
|
+
}
|
|
1953
|
+
else
|
|
1954
|
+
// #endif
|
|
1955
|
+
if (actualType === 'image') {
|
|
1956
|
+
// #ifndef H5
|
|
1957
|
+
uni.chooseImage({
|
|
1958
|
+
count: finalConfig.count,
|
|
1959
|
+
sizeType: finalConfig.sizeType,
|
|
1960
|
+
sourceType: finalConfig.sourceType,
|
|
1961
|
+
success: (res) => {
|
|
1962
|
+
const tempFilePaths = Array.isArray(res.tempFilePaths) ? res.tempFilePaths : [res.tempFilePaths];
|
|
1963
|
+
const tempFilesArr = Array.isArray(res.tempFiles) ? res.tempFiles : [res.tempFiles];
|
|
1964
|
+
// 规范化 tempFiles
|
|
1965
|
+
const tempFiles = tempFilesArr.map((file, index) => ({
|
|
1966
|
+
path: tempFilePaths[index], // 确保 path 存在
|
|
1967
|
+
size: file.size,
|
|
1968
|
+
}));
|
|
1969
|
+
resolve({
|
|
1970
|
+
success: true,
|
|
1971
|
+
tempFilePaths,
|
|
1972
|
+
tempFiles,
|
|
1973
|
+
type: 'image'
|
|
1974
|
+
});
|
|
1975
|
+
},
|
|
1976
|
+
fail: failCallback
|
|
1977
|
+
});
|
|
1978
|
+
// #endif
|
|
1979
|
+
}
|
|
1980
|
+
else if (actualType === 'local') {
|
|
1981
|
+
// #ifndef H5
|
|
1982
|
+
if (typeof uni.chooseFile === 'function') {
|
|
1983
|
+
uni.chooseFile({
|
|
1984
|
+
count: finalConfig.count,
|
|
1985
|
+
extension: finalConfig.extension,
|
|
1986
|
+
success: (res) => {
|
|
1987
|
+
const tempFilePaths = Array.isArray(res.tempFilePaths) ? res.tempFilePaths : [res.tempFilePaths];
|
|
1988
|
+
const tempFilesArr = Array.isArray(res.tempFiles) ? res.tempFiles : [res.tempFiles];
|
|
1989
|
+
// 规范化 tempFiles
|
|
1990
|
+
const tempFiles = tempFilesArr.map((file, index) => ({
|
|
1991
|
+
path: tempFilePaths[index],
|
|
1992
|
+
size: file.size,
|
|
1993
|
+
}));
|
|
1994
|
+
resolve({
|
|
1995
|
+
success: true,
|
|
1996
|
+
tempFilePaths,
|
|
1997
|
+
tempFiles,
|
|
1998
|
+
type: 'local'
|
|
1999
|
+
});
|
|
2000
|
+
},
|
|
2001
|
+
fail: failCallback
|
|
2002
|
+
});
|
|
2003
|
+
}
|
|
2004
|
+
else {
|
|
2005
|
+
resolve({
|
|
2006
|
+
success: false,
|
|
2007
|
+
message: '当前平台不支持选择本地文件',
|
|
2008
|
+
type: actualType
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
2011
|
+
// #endif
|
|
2012
|
+
}
|
|
2013
|
+
}).then((res) => {
|
|
2014
|
+
// 仅当成功时验证文件大小
|
|
2015
|
+
if (!res.success || !res.tempFiles || !finalConfig.maxSize) {
|
|
2016
|
+
return res;
|
|
2017
|
+
}
|
|
2018
|
+
const invalidFiles = res.tempFiles.filter((file) => {
|
|
2019
|
+
const sizeValidation = validateFileSize(file.size, finalConfig.maxSize);
|
|
2020
|
+
return !sizeValidation.valid;
|
|
2021
|
+
});
|
|
2022
|
+
if (invalidFiles.length > 0) {
|
|
2023
|
+
const message = `部分文件大小超过 ${finalConfig.maxSize}MB 限制`;
|
|
2024
|
+
if (finalConfig.showToast) {
|
|
2025
|
+
useToast(message, false, 'error');
|
|
2026
|
+
}
|
|
2027
|
+
// 保留已选择的文件,但标记为失败
|
|
2028
|
+
return {
|
|
2029
|
+
...res,
|
|
2030
|
+
success: false,
|
|
2031
|
+
message,
|
|
2032
|
+
};
|
|
2033
|
+
}
|
|
2034
|
+
return res;
|
|
2035
|
+
}), 'upload', 'CHOOSE_FILE_ERROR');
|
|
2036
|
+
monitor.end('chooseFile');
|
|
2037
|
+
return result || { success: false, message: '选择文件失败', type: actualType };
|
|
2038
|
+
}
|
|
2039
|
+
/**
|
|
2040
|
+
* 选择图片(向后兼容)
|
|
2041
|
+
* @param config 选择配置
|
|
2042
|
+
* @returns Promise<ChooseImageResult> 选择结果
|
|
2043
|
+
*/
|
|
2044
|
+
async function chooseImage(config = {}) {
|
|
2045
|
+
const result = await chooseFile({ ...config, type: 'image' });
|
|
2046
|
+
return {
|
|
2047
|
+
success: result.success,
|
|
2048
|
+
tempFilePaths: result.tempFilePaths,
|
|
2049
|
+
tempFiles: result.tempFiles,
|
|
2050
|
+
message: result.message
|
|
2051
|
+
};
|
|
2052
|
+
}
|
|
2053
|
+
/**
|
|
2054
|
+
* 上传文件
|
|
2055
|
+
* @param filePath 文件路径
|
|
2056
|
+
* @param config 上传配置
|
|
2057
|
+
* @param onProgress 进度回调
|
|
2058
|
+
* @returns Promise<UploadResult> 上传结果
|
|
2059
|
+
*/
|
|
2060
|
+
async function uploadFile(filePath, config, onProgress) {
|
|
2061
|
+
const monitor = PerformanceMonitor.getInstance();
|
|
2062
|
+
monitor.start('uploadFile', 'upload', { filePath });
|
|
2063
|
+
const finalConfig = { ...DEFAULT_UPLOAD_CONFIG, ...config };
|
|
2064
|
+
// 验证必要参数
|
|
2065
|
+
if (!finalConfig.url) {
|
|
2066
|
+
const message = '上传地址不能为空';
|
|
2067
|
+
if (finalConfig.showToast) {
|
|
2068
|
+
useToast(message, false, 'error');
|
|
2069
|
+
}
|
|
2070
|
+
monitor.end('uploadFile');
|
|
2071
|
+
return { success: false, message };
|
|
2072
|
+
}
|
|
2073
|
+
// 验证文件
|
|
2074
|
+
const fileValidation = validateFile(filePath, finalConfig);
|
|
2075
|
+
if (!fileValidation.valid) {
|
|
2076
|
+
if (finalConfig.showToast) {
|
|
2077
|
+
useToast(fileValidation.message, false, 'error');
|
|
2078
|
+
}
|
|
2079
|
+
monitor.end('uploadFile');
|
|
2080
|
+
return { success: false, message: fileValidation.message };
|
|
2081
|
+
}
|
|
2082
|
+
const result = await safeAsync(() => new Promise((resolve) => {
|
|
2083
|
+
const uploadTask = uni.uploadFile({
|
|
2084
|
+
url: finalConfig.url,
|
|
2085
|
+
filePath,
|
|
2086
|
+
name: finalConfig.name,
|
|
2087
|
+
formData: finalConfig.formData,
|
|
2088
|
+
header: finalConfig.header,
|
|
2089
|
+
timeout: finalConfig.timeout,
|
|
2090
|
+
success: (res) => {
|
|
2091
|
+
let data;
|
|
2092
|
+
try {
|
|
2093
|
+
data = JSON.parse(res.data);
|
|
2094
|
+
}
|
|
2095
|
+
catch {
|
|
2096
|
+
data = res.data;
|
|
2097
|
+
}
|
|
2098
|
+
if (res.statusCode === 200) {
|
|
2099
|
+
if (finalConfig.showToast) {
|
|
2100
|
+
useToast(finalConfig.successMessage, false, 'success');
|
|
2101
|
+
}
|
|
2102
|
+
resolve({
|
|
2103
|
+
success: true,
|
|
2104
|
+
data,
|
|
2105
|
+
tempFilePath: filePath,
|
|
2106
|
+
statusCode: res.statusCode
|
|
2107
|
+
});
|
|
2108
|
+
}
|
|
2109
|
+
else {
|
|
2110
|
+
const message = `上传失败,状态码:${res.statusCode}`;
|
|
2111
|
+
if (finalConfig.showToast) {
|
|
2112
|
+
useToast(message, false, 'error');
|
|
2113
|
+
}
|
|
2114
|
+
resolve({
|
|
2115
|
+
success: false,
|
|
2116
|
+
message,
|
|
2117
|
+
statusCode: res.statusCode
|
|
2118
|
+
});
|
|
2119
|
+
}
|
|
2120
|
+
},
|
|
2121
|
+
fail: (err) => {
|
|
2122
|
+
const message = err.errMsg || finalConfig.failMessage;
|
|
2123
|
+
if (finalConfig.showToast) {
|
|
2124
|
+
useToast(message, false, 'error');
|
|
2125
|
+
}
|
|
2126
|
+
resolve({
|
|
2127
|
+
success: false,
|
|
2128
|
+
message,
|
|
2129
|
+
tempFilePath: filePath
|
|
2130
|
+
});
|
|
2131
|
+
}
|
|
2132
|
+
});
|
|
2133
|
+
// 监听上传进度
|
|
2134
|
+
if (onProgress && uploadTask) {
|
|
2135
|
+
uploadTask.onProgressUpdate((res) => {
|
|
2136
|
+
onProgress({
|
|
2137
|
+
progress: res.progress,
|
|
2138
|
+
totalBytesSent: res.totalBytesSent,
|
|
2139
|
+
totalBytesExpectedToSend: res.totalBytesExpectedToSend
|
|
2140
|
+
});
|
|
2141
|
+
});
|
|
2142
|
+
}
|
|
2143
|
+
}), 'upload', 'UPLOAD_FILE_ERROR');
|
|
2144
|
+
monitor.end('uploadFile');
|
|
2145
|
+
return result || { success: false, message: '上传文件失败' };
|
|
2146
|
+
}
|
|
2147
|
+
/**
|
|
2148
|
+
* 选择并上传文件(一体化功能)
|
|
2149
|
+
* @param config 上传配置
|
|
2150
|
+
* @param chooseConfig 选择文件配置
|
|
2151
|
+
* @param onProgress 进度回调
|
|
2152
|
+
* @returns Promise<UploadResult[]> 上传结果数组
|
|
2153
|
+
*/
|
|
2154
|
+
async function chooseAndUploadFile(config, chooseConfig = {}, onProgress) {
|
|
2155
|
+
const monitor = PerformanceMonitor.getInstance();
|
|
2156
|
+
monitor.start('chooseAndUploadFile', 'upload');
|
|
2157
|
+
// 选择文件
|
|
2158
|
+
const chooseResult = await chooseFile(chooseConfig);
|
|
2159
|
+
if (!chooseResult.success || !chooseResult.tempFilePaths) {
|
|
2160
|
+
monitor.end('chooseAndUploadFile');
|
|
2161
|
+
return [{ success: false, message: chooseResult.message || '选择文件失败' }];
|
|
2162
|
+
}
|
|
2163
|
+
// 批量上传
|
|
2164
|
+
const uploadPromises = chooseResult.tempFilePaths.map(filePath => uploadFile(filePath, config, onProgress));
|
|
2165
|
+
const results = await Promise.all(uploadPromises);
|
|
2166
|
+
monitor.end('chooseAndUploadFile');
|
|
2167
|
+
return results;
|
|
2168
|
+
}
|
|
2169
|
+
/**
|
|
2170
|
+
* 选择并上传图片(向后兼容)
|
|
2171
|
+
* @param config 上传配置
|
|
2172
|
+
* @param chooseConfig 选择图片配置
|
|
2173
|
+
* @param onProgress 进度回调
|
|
2174
|
+
* @returns Promise<UploadResult[]> 上传结果数组
|
|
2175
|
+
*/
|
|
2176
|
+
async function chooseAndUploadImage(config, chooseConfig = {}, onProgress) {
|
|
2177
|
+
return chooseAndUploadFile(config, { ...chooseConfig, type: 'image' }, onProgress);
|
|
2178
|
+
}
|
|
2179
|
+
/**
|
|
2180
|
+
* 检查是否支持文件上传
|
|
2181
|
+
* @returns boolean 是否支持
|
|
2182
|
+
*/
|
|
2183
|
+
function isUploadSupported() {
|
|
2184
|
+
return typeof uni !== 'undefined' &&
|
|
2185
|
+
typeof uni.chooseImage === 'function' &&
|
|
2186
|
+
typeof uni.uploadFile === 'function';
|
|
2187
|
+
}
|
|
2188
|
+
/**
|
|
2189
|
+
* 获取文件信息
|
|
2190
|
+
* @param filePath 文件路径
|
|
2191
|
+
* @returns Promise<{size: number, type?: string}> 文件信息
|
|
2192
|
+
*/
|
|
2193
|
+
async function getFileInfo(filePath) {
|
|
2194
|
+
return await safeAsync(() => new Promise((resolve, reject) => {
|
|
2195
|
+
uni.getFileInfo({
|
|
2196
|
+
filePath,
|
|
2197
|
+
digestAlgorithm: 'md5', // 明确指定算法,虽然默认是md5
|
|
2198
|
+
success: (res) => {
|
|
2199
|
+
const result = res;
|
|
2200
|
+
resolve({
|
|
2201
|
+
size: result.size,
|
|
2202
|
+
digest: result.digest
|
|
2203
|
+
});
|
|
2204
|
+
},
|
|
2205
|
+
fail: reject
|
|
2206
|
+
});
|
|
2207
|
+
}), 'upload', 'GET_FILE_INFO_ERROR');
|
|
2208
|
+
}
|
|
2209
|
+
|
|
2210
|
+
// 核心功能
|
|
2211
|
+
|
|
2212
|
+
// 版本信息
|
|
2213
|
+
const VERSION = '1.0.8';
|
|
2214
|
+
|
|
2215
|
+
// 初始化函数
|
|
2216
|
+
async function initUniAppTools(config = {}) {
|
|
2217
|
+
const {
|
|
2218
|
+
enablePerformanceMonitor = false,
|
|
2219
|
+
enableErrorHandler = true,
|
|
2220
|
+
logLevel = 'warn'
|
|
2221
|
+
} = config;
|
|
2222
|
+
|
|
2223
|
+
if (enableErrorHandler) {
|
|
2224
|
+
const { ErrorHandler } = await Promise.resolve().then(function () { return errorHandler; });
|
|
2225
|
+
const errorHandler$1 = ErrorHandler.getInstance();
|
|
2226
|
+
|
|
2227
|
+
// 设置全局错误监听
|
|
2228
|
+
if (enablePerformanceMonitor) {
|
|
2229
|
+
errorHandler$1.onError((error) => {
|
|
2230
|
+
console.log(`[UniAppTools] ${error.module} - ${error.code}: ${error.message}`);
|
|
2231
|
+
});
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
if (enablePerformanceMonitor) {
|
|
2236
|
+
const { PerformanceMonitor } = await Promise.resolve().then(function () { return performance$1; });
|
|
2237
|
+
const monitor = PerformanceMonitor.getInstance();
|
|
2238
|
+
|
|
2239
|
+
// 定期输出性能报告
|
|
2240
|
+
setInterval(() => {
|
|
2241
|
+
const report = monitor.getReport();
|
|
2242
|
+
if (report.slowest.length > 0) {
|
|
2243
|
+
console.log('[UniAppTools] 性能报告:', report);
|
|
2244
|
+
}
|
|
2245
|
+
}, 60000); // 每分钟输出一次
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2248
|
+
console.log(`[UniAppTools] v${VERSION} 初始化完成`);
|
|
1729
2249
|
}
|
|
1730
2250
|
|
|
1731
|
-
export { ErrorHandler, PerformanceMonitor, UniAppToolsError, VERSION, batchGetStorage, batchSetStorage, cleanExpiredStorage, clearClipboard, clearNavigationQueue, clearStorageSync, copyText, debounce, deepClone, deepMerge, getCurrentEnv, getCurrentPageInfo, getMenuButtonBoundingClientRect, getNavHeight, getPageStack, getPlatform, getStatusBarHeight, getStorage, getStorageInfo, getStorageSync, getTopNavBarHeight, initUniAppTools, isClipboardSupported, measurePerformance, mergeObjects, navigateTo, onCheckForUpdate, reLaunch, readClipboard, redirectTo, safeAsync, safeNavigateTo, safeSync, setStorage, setStorageSync, switchTab, throttle, useBack, useBackDebounced, useBackOrHome, useDeepCopyByObj, useToast, useWindowInfo };
|
|
2251
|
+
export { ErrorHandler, PerformanceMonitor, UniAppToolsError, VERSION, batchGetStorage, batchSetStorage, chooseAndUploadFile, chooseAndUploadImage, chooseFile, chooseImage, cleanExpiredStorage, clearClipboard, clearNavigationQueue, clearStorageSync, copyText, debounce, deepClone, deepMerge, getCurrentEnv, getCurrentPageInfo, getFileInfo, getMenuButtonBoundingClientRect, getNavHeight, getPageStack, getPlatform, getStatusBarHeight, getStorage, getStorageInfo, getStorageSync, getTopNavBarHeight, initUniAppTools, isClipboardSupported, isUploadSupported, measurePerformance, mergeObjects, navigateTo, onCheckForUpdate, reLaunch, readClipboard, redirectTo, safeAsync, safeNavigateTo, safeSync, setPageIcon, setPageTitle, setStorage, setStorageSync, switchTab, throttle, uploadFile, useBack, useBackDebounced, useBackOrHome, useDeepCopyByObj, useToast, useWindowInfo };
|
|
1732
2252
|
//# sourceMappingURL=my-uniapp-tools.esm.js.map
|