From 84d5bc157fcc5b35c5948ced39789f3acb0e355d Mon Sep 17 00:00:00 2001 From: zpc Date: Thu, 31 Jul 2025 20:06:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/utils.js | 295 ++++++++++++ manifest.json | 2 +- pages/index/index.vue | 367 ++++++++++----- uni_modules/uni-notice-bar/changelog.md | 22 + .../uni-notice-bar/uni-notice-bar.vue | 423 ++++++++++++++++++ uni_modules/uni-notice-bar/package.json | 90 ++++ uni_modules/uni-notice-bar/readme.md | 13 + .../pages/index/index.js.map | 1 + .../uni-transition/uni-transition.js.map | 1 + .../dist/dev/.sourcemap/mp-weixin/app.js.map | 2 +- .../.sourcemap/mp-weixin/common/utils.js.map | 1 + .../.sourcemap/mp-weixin/common/vendor.js.map | 2 +- .../mp-weixin/pages/index/index.js.map | 2 +- .../uni-notice-bar/uni-notice-bar.js.map | 1 + .../components/uni-popup/uni-popup.js.map | 2 +- .../uni-transition/createAnimation.js.map | 2 +- .../uni-transition/uni-transition.js.map | 2 +- unpackage/dist/dev/mp-weixin/common/utils.js | 173 +++++++ unpackage/dist/dev/mp-weixin/common/vendor.js | 53 ++- .../dist/dev/mp-weixin/pages/index/index.js | 323 +++++++++---- .../dist/dev/mp-weixin/pages/index/index.json | 1 + .../dist/dev/mp-weixin/pages/index/index.wxml | 2 +- .../dist/dev/mp-weixin/pages/index/index.wxss | 14 +- .../dist/dev/mp-weixin/project.config.json | 2 +- .../dev/mp-weixin/project.private.config.json | 7 - .../uni-notice-bar/uni-notice-bar.js | 204 +++++++++ .../uni-notice-bar/uni-notice-bar.json | 4 + .../uni-notice-bar/uni-notice-bar.wxml | 1 + .../uni-notice-bar/uni-notice-bar.wxss | 101 +++++ .../components/uni-popup/uni-popup.wxml | 2 +- 30 files changed, 1883 insertions(+), 232 deletions(-) create mode 100644 common/utils.js create mode 100644 uni_modules/uni-notice-bar/changelog.md create mode 100644 uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue create mode 100644 uni_modules/uni-notice-bar/package.json create mode 100644 uni_modules/uni-notice-bar/readme.md create mode 100644 unpackage/dist/dev/.sourcemap/mp-weixin-devtools/pages/index/index.js.map create mode 100644 unpackage/dist/dev/.sourcemap/mp-weixin-devtools/uni_modules/uni-transition/components/uni-transition/uni-transition.js.map create mode 100644 unpackage/dist/dev/.sourcemap/mp-weixin/common/utils.js.map create mode 100644 unpackage/dist/dev/.sourcemap/mp-weixin/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.js.map create mode 100644 unpackage/dist/dev/mp-weixin/common/utils.js delete mode 100644 unpackage/dist/dev/mp-weixin/project.private.config.json create mode 100644 unpackage/dist/dev/mp-weixin/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.js create mode 100644 unpackage/dist/dev/mp-weixin/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.json create mode 100644 unpackage/dist/dev/mp-weixin/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.wxml create mode 100644 unpackage/dist/dev/mp-weixin/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.wxss diff --git a/common/utils.js b/common/utils.js new file mode 100644 index 0000000..f301bb5 --- /dev/null +++ b/common/utils.js @@ -0,0 +1,295 @@ +// /** +// * 获取文件大小(Promise封装) +// * @param {string} filePath +// * @returns {Promise} 文件字节数 +// */ +// const getFileSize = (filePath) => { +// return new Promise(resolve => { +// uni.getFileInfo({ +// filePath, +// success: (res) => resolve(res.size), +// fail: () => resolve(Infinity) +// }); +// }); +// }; + + +/** + * 获取文件大小(兼容新版API) + * @param {string} filePath + * @returns {Promise} 文件字节数 + */ +const getFileSize = async (filePath) => { + try { + const res = await new Promise((resolve, reject) => { + + wx.getFileSystemManager().getFileInfo({ + filePath, + success: resolve, + fail: reject + }); + }); + return res.size || Infinity; + } catch (err) { + console.error('获取文件大小失败:', err); + return Infinity; + } + }; + +/** + * 执行图片压缩(Promise封装) + * @param {string} src + * @param {number} quality + * @returns {Promise} 压缩后的临时路径 + */ +const doCompressImage = (src, quality) => { + return new Promise(resolve => { + uni.compressImage({ + src, + quality, + success: (res) => resolve(res.tempFilePath), + fail: () => resolve(src) // 失败返回原路径 + }); + }); +}; + +/** + * 智能图片压缩(支持多平台) + * @param {string} tempFilePath - 图片临时路径 + * @param {number} maxSize - 目标最大字节数(默认500KB) + * @param {number} [initialQuality=80] - 初始压缩质量(1-100) + * @returns {Promise} 压缩后的临时路径 + */ +export const compressImage = async (tempFilePath, maxSize = 500 * 1024, initialQuality = 80) => { + let quality = initialQuality; + let compressedPath = tempFilePath; + let currentSize = Infinity; + + // 二分法压缩参数 + let low = 10; + let high = initialQuality; + + while (low <= high) { + quality = Math.floor((low + high) / 2); + + // 使用提取的Promise方法 + compressedPath = await doCompressImage(tempFilePath, quality); + currentSize = await getFileSize(compressedPath); + + if (currentSize <= maxSize) { + low = quality + 1; // 尝试更高质量 + } else { + high = quality - 1; // 降低质量 + } + + if (high - low < 5) break; // 安全阀 + } + + // 最终强制压缩(如果仍未达标) + if (currentSize > maxSize) { + compressedPath = await doCompressImage(tempFilePath, 10); + } + + return compressedPath; +}; + + +/** + * 精准图片压缩(优化版) + * @param {string} tempFilePath - 图片临时路径 + * @param {number} targetSize - 目标字节数(默认500KB) + * @param {number} [initialQuality=85] - 初始压缩质量(1-100) + * @returns {Promise<{path: string, quality: number, iterations: number, finalSize: number}>} + */ +export const preciseCompress = async (tempFilePath, targetSize = 500 * 1024, initialQuality = 85) => { + let quality = initialQuality; + let compressedPath = tempFilePath; + let currentSize = Infinity; + let iterations = 0; + const maxIterations = 10; // 增加最大迭代次数 + const history = []; // 记录每次压缩结果用于分析 + + // 首先检查原图大小,如果已经满足直接返回 + const originalSize = await getFileSize(tempFilePath); + if (originalSize <= targetSize) { + return { path: tempFilePath, quality: 100, iterations: 0, finalSize: originalSize }; + } + + // 智能预测初始质量范围(新增) + const predictQualityRange = (originalSize, targetSize) => { + const ratio = targetSize / originalSize; + if (ratio > 0.8) return { low: 70, high: 95 }; + if (ratio > 0.5) return { low: 45, high: 75 }; + if (ratio > 0.3) return { low: 25, high: 50 }; + if (ratio > 0.1) return { low: 10, high: 30 }; + return { low: 5, high: 15 }; // 极限压缩 + }; + + const { low: predictedLow, high: predictedHigh } = predictQualityRange(originalSize, targetSize); + let low = predictedLow; + let high = Math.min(predictedHigh, initialQuality); + + console.log(`预测质量范围: ${low}-${high} (原图${(originalSize/1024).toFixed(2)}KB → 目标${(targetSize/1024).toFixed(2)}KB)`); + + // 动态调整二分法边界(优化版) + const adjustBounds = (currentQuality, currentSize, targetSize) => { + const sizeRatio = currentSize / targetSize; + const qualityDelta = Math.max(2, Math.floor(currentQuality * 0.1)); // 动态调整幅度 + + if (sizeRatio > 2.5) { + return { lowDelta: -qualityDelta * 2, highDelta: -qualityDelta }; + } else if (sizeRatio > 1.5) { + return { lowDelta: -qualityDelta, highDelta: -Math.floor(qualityDelta / 2) }; + } else if (sizeRatio > 1.1) { + return { lowDelta: -3, highDelta: -1 }; + } else { + return { lowDelta: -1, highDelta: 0 }; + } + }; + + let bestResult = null; // 记录最佳结果 + + while (iterations < maxIterations && low <= high) { + iterations++; + quality = Math.floor((low + high) / 2); + + // 跳过已经测试过的quality值 + if (history.some(item => item.quality === quality)) { + break; + } + + compressedPath = await doCompressImage(tempFilePath, quality); + currentSize = await getFileSize(compressedPath); + history.push({ quality, size: currentSize }); + + console.log(`第${iterations}次尝试: quality=${quality} → ${(currentSize / 1024).toFixed(2)}KB (目标${(targetSize/1024).toFixed(2)}KB)`); + + // 更新最佳结果 + if (!bestResult || Math.abs(currentSize - targetSize) < Math.abs(bestResult.size - targetSize)) { + bestResult = { quality, size: currentSize, path: compressedPath }; + } + + // 精准匹配检查(容差范围调整为3%) + if (Math.abs(currentSize - targetSize) < targetSize * 0.03) { + console.log('✅ 达到精准匹配,提前结束'); + break; + } + + if (currentSize > targetSize) { + const { lowDelta, highDelta } = adjustBounds(quality, currentSize, targetSize); + high = Math.max(5, quality + highDelta); // 确保不会低于最小值 + } else { + low = quality + 1; // 当小于目标时,尝试更高质量 + } + + // 收敛检查 + if (high - low <= 1) break; + } + + // 如果最佳结果仍然超标,尝试极限压缩 + if (bestResult && bestResult.size > targetSize * 1.1) { + console.log('🔥 尝试极限压缩...'); + const extremePath = await doCompressImage(tempFilePath, 5); + const extremeSize = await getFileSize(extremePath); + console.log(`极限压缩结果: quality=5 → ${(extremeSize / 1024).toFixed(2)}KB`); + + if (extremeSize < bestResult.size) { + bestResult = { quality: 5, size: extremeSize, path: extremePath }; + } + } + + const finalResult = bestResult || { quality: 10, size: currentSize, path: compressedPath }; + + console.log(`🎯 最终结果:quality=${finalResult.quality} → ${(finalResult.size / 1024).toFixed(2)}KB` + + `(迭代${iterations}次,压缩率${((1 - finalResult.size / originalSize) * 100).toFixed(1)}%)`); + + return { + path: finalResult.path, + quality: finalResult.quality, + iterations, + finalSize: finalResult.size + }; +}; + + + +/** +* 图片转Base64(兼容多平台) +* @param {string} filePath - 图片临时路径 +* @returns {Promise} Base64字符串(带data:image/前缀) +*/ +export const imageToBase64 = (filePath) => { + return new Promise((resolve, reject) => { + // 先获取图片类型 + uni.getImageInfo({ + src: filePath, + success: (info) => { + const type = info.type || 'jpeg'; + // 读取文件为Base64 + uni.getFileSystemManager().readFile({ + filePath, + encoding: 'base64', + success: (res) => resolve(`data:image/${type};base64,${res.data}`), + fail: reject + }); + }, + fail: () => { + // 类型获取失败时默认jpeg + uni.getFileSystemManager().readFile({ + filePath, + encoding: 'base64', + success: (res) => resolve(`data:image/jpeg;base64,${res.data}`), + fail: reject + }); + } + }); + }); +}; + +/** + * 完整处理流程(智能判断是否压缩): + * 选择图片 → 检查大小 → 按需压缩 → 转Base64 + * @returns {Promise<{ base64: string, path: string, compressed: boolean }>} + */ +export const processImage = async (maxSize = 500 * 1024) => { + // 1. 选择图片 + const chooseRes = await new Promise(resolve => { + uni.chooseImage({ + count: 1, + sizeType: ['original', 'compressed'], + success: resolve, + fail: () => resolve(null) + }); + }); + if (!chooseRes) throw new Error('选择图片失败'); + + const tempFilePath = chooseRes.tempFilePaths[0]; + let finalPath = tempFilePath; + let isCompressed = false; + + // 2. 检查文件大小 + const fileSize = await getFileSize(tempFilePath); + console.log(`原图大小: ${(fileSize / 1024).toFixed(2)}KB`); + + // 3. 按需压缩 + if (fileSize > maxSize) { + console.log('🔄 开始智能压缩...'); + const compressResult = await preciseCompress(tempFilePath, maxSize); + finalPath = compressResult.path; + isCompressed = true; + + // 验证压缩结果 + console.log(`✅ 压缩完成: ${(fileSize / 1024).toFixed(2)}KB → ${(compressResult.finalSize / 1024).toFixed(2)}KB` + + ` (节省${((1 - compressResult.finalSize / fileSize) * 100).toFixed(1)}%)`); + } + + // 4. 转换为Base64 + const base64 = await imageToBase64(finalPath); + console.log(`📄 Base64长度: ${base64.length} 字符`); + + return { + base64, // Base64字符串 + path: finalPath, // 最终文件路径(可能是原图或压缩图) + compressed: isCompressed // 是否经过压缩 + }; +}; \ No newline at end of file diff --git a/manifest.json b/manifest.json index 88d5c77..2ca5050 100644 --- a/manifest.json +++ b/manifest.json @@ -50,7 +50,7 @@ "quickapp" : {}, /* 小程序特有相关 */ "mp-weixin" : { - "appid" : "", + "appid" : "wx595ec949c6efd72b", "setting" : { "urlCheck" : false }, diff --git a/pages/index/index.vue b/pages/index/index.vue index c37e875..1df2c8f 100644 --- a/pages/index/index.vue +++ b/pages/index/index.vue @@ -2,10 +2,11 @@ - + - 免费领取 + 设备专属权益兑换 - + @@ -76,24 +77,28 @@ style="border-bottom: 0.86px solid #000; margin-left: 50rpx; width: 350rpx;" /> - + - + style="width: 150rpx; height:150rpx; background-color: gainsboro; margin-left: 30rpx; margin-right: 20rpx; position: relative;"> + - - - - + + 拍摄并上传清晰的产品铭牌信息用于辅助审核,通过后立即发货 - - 提交 + + + 关闭 + + + 提交 + @@ -121,130 +126,286 @@ style="width: 100%; height: 460rpx; margin-top: 30rpx; overflow-y: auto; font-size: 25rpx; align-items: center;"> - - {{item.name}} - {{item.phone}} + {{ item.name }} + {{ item.phone }} - {{item.time}} + {{ item.time }} - - {{item.address}} - + {{ item.address }} - - - - - - - \ No newline at end of file diff --git a/uni_modules/uni-notice-bar/changelog.md b/uni_modules/uni-notice-bar/changelog.md new file mode 100644 index 0000000..aa1d627 --- /dev/null +++ b/uni_modules/uni-notice-bar/changelog.md @@ -0,0 +1,22 @@ +## 1.2.3(2025-04-14) +- 新增 左侧自定义插槽,可自定义文字或图标 +## 1.2.2(2023-12-20) +- 修复动态绑定title时,滚动速度不一致的问题 +## 1.2.1(2022-09-05) +- 新增 属性 fontSize,可修改文字大小。 +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-notice-bar](https://uniapp.dcloud.io/component/uniui/uni-notice-bar) +## 1.1.1(2021-11-09) +- 新增 提供组件设计资源,组件样式调整 +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.9(2021-05-12) +- 新增 组件示例地址 +## 1.0.8(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 1.0.7(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.6(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue b/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue new file mode 100644 index 0000000..81416d9 --- /dev/null +++ b/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue @@ -0,0 +1,423 @@ + + + + + diff --git a/uni_modules/uni-notice-bar/package.json b/uni_modules/uni-notice-bar/package.json new file mode 100644 index 0000000..1c9135b --- /dev/null +++ b/uni_modules/uni-notice-bar/package.json @@ -0,0 +1,90 @@ +{ + "id": "uni-notice-bar", + "displayName": "uni-notice-bar 通告栏", + "version": "1.2.3", + "description": "NoticeBar 通告栏组件,常用于展示公告信息,可设为滚动公告", + "keywords": [ + "uni-ui", + "uniui", + "通告栏", + "公告", + "跑马灯" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y", + "app-harmony": "u", + "app-uvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-notice-bar/readme.md b/uni_modules/uni-notice-bar/readme.md new file mode 100644 index 0000000..fb2ede2 --- /dev/null +++ b/uni_modules/uni-notice-bar/readme.md @@ -0,0 +1,13 @@ + + +## NoticeBar 通告栏 +> **组件名:uni-notice-bar** +> 代码块: `uNoticeBar` + + +通告栏组件 。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-notice-bar) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/unpackage/dist/dev/.sourcemap/mp-weixin-devtools/pages/index/index.js.map b/unpackage/dist/dev/.sourcemap/mp-weixin-devtools/pages/index/index.js.map new file mode 100644 index 0000000..4e803fd --- /dev/null +++ b/unpackage/dist/dev/.sourcemap/mp-weixin-devtools/pages/index/index.js.map @@ -0,0 +1 @@ +{"version":3,"names":["uniNoticeBar","_sfc_main","components","onLoad","userId","common_vendor","index","getStorageSync","login","data","imagePath","name","phone","workUnit","address","createTime","number","model","recordList","time","methods","request","url","method","Promise","resolve","reject","header","timeout","success","res","__f__","statusCode","Error","concat","fail","err","wxLogin","provider","onlyAuthorize","_success","_asyncToGenerator2","_regeneratorRuntime2","mark","_callee","wrap","_callee$","_context","prev","next","code","stop","_x","apply","arguments","_this","_callee2","wxCode","_callee2$","_context2","sent","setStorageSync","user_id","message","t0","openReceivePop","$refs","receivePop","open","closeReceivePop","close","openRecordPop","_this2","_callee3","_callee3$","_context3","loadRecordList","recordPop","_callee4","_callee4$","_context4","error","closeRecordPop","seleImg","_this3","chooseMedia","count","mediaType","sizeType","tempFilePaths","validateForm","trim","showToast","title","icon","submitForm","_this4","_callee5","formData","_callee5$","_context5","abrupt","showLoading","setTimeout","hideLoading","clearForm","wx","createPage","MiniProgramPage"],"sources":["index.vue","cGFnZXMvaW5kZXgvaW5kZXgudnVl"],"sourcesContent":["