diff --git a/java-mall-app-shop-admin/.hbuilderx/launch.json b/java-mall-app-shop-admin/.hbuilderx/launch.json index 7f1f4d4..678c74b 100644 --- a/java-mall-app-shop-admin/.hbuilderx/launch.json +++ b/java-mall-app-shop-admin/.hbuilderx/launch.json @@ -10,9 +10,13 @@ "default" : { "launchtype" : "local" }, + "h5" : { + "launchtype" : "local" + }, "mp-weixin" : { "launchtype" : "local" }, + "provider" : "aliyun", "type" : "uniCloud" }, { diff --git a/java-mall-app-shop-admin/manifest.json b/java-mall-app-shop-admin/manifest.json index 85cafdd..422d691 100644 --- a/java-mall-app-shop-admin/manifest.json +++ b/java-mall-app-shop-admin/manifest.json @@ -65,20 +65,21 @@ "sdkConfigs" : { "maps" : {}, "push" : { - "unipush" : { - "offline" : true, - "fcm" : {}, - "honor" : {}, - "meizu" : {}, - "mi" : {}, - "vivo" : {}, - "oppo" : {}, - "hms" : {} - }, "igexin" : { "appid" : "KXgzOaKSzd5HG3p9IPaVa8", "appkey" : "neXXX9r1Tc7gMxN2PIcHA1", "appsecret" : "aQQys9eufd8KHH1Y0kfQm6" + }, + "unipush" : { + "version" : "2", + "offline" : true, + "hms" : {}, + "oppo" : {}, + "vivo" : {}, + "mi" : {}, + "meizu" : {}, + "honor" : {}, + "fcm" : {} } } }, diff --git a/java-mall-app-shop-admin/pages/audit/shop2.vue b/java-mall-app-shop-admin/pages/audit/shop2.vue index 4e7722d..e999cc1 100644 --- a/java-mall-app-shop-admin/pages/audit/shop2.vue +++ b/java-mall-app-shop-admin/pages/audit/shop2.vue @@ -468,6 +468,9 @@ import { import navBar from "@/components/uni-nav-bar/uni-nav-bar"; import tuiRadio from "@/components/tui-radio/tui-radio.vue"; import tuiRadioGroup from "@/components/tui-radio-group/tui-radio-group.vue"; +import { compressImg } from '@/utils/tool.js' + + const orcImgTypeConf = { FR_ID_CARD_FRONT: "FR_ID_CARD_FRONT", FR_ID_CARD_BEHIND: "FR_ID_CARD_BEHIND", @@ -546,6 +549,10 @@ export default { license_type_name: "", orcTimeout: null, action: "", + limitType: ['png', 'jpg', 'jpeg'], //允许的图片后缀 + fileMaxSize: 1 * 1024 * 1024, // 超出1M开启压缩 + maxSize:5 * 1024 * 1024, //图片最大不能超过20M + fileMinSize: 5 * 1024, // 最小为5KB fileList: [], fileList2: [], fileList3: [], @@ -711,8 +718,46 @@ export default { overSize(e) { uni.$u.toast("上传图片大小不能超过8MB!"); }, + compressImage(url) { + return new Promise((reslove, reject) => { + const tempFilePath = url //url是选中图片的路径 + uni.compressImage({ + src: tempFilePath, + quality: 90, //压缩的程度 + success: (res) => { + reslove(res.tempFilePath) //压缩成功返回的路径 + }, + fail: (error) => { + console.log('压缩失败', error) + } + }) + }) + }, + async handerCompressImg(source, compressionRatio) { + let that = this; + return new Promise((resolve, reject) => { + compressImg(source.url, compressionRatio, source.type, compressRes => { + resolve(compressRes); + }) + }).then((res) => { + source.size = res.size + // window.URL.revokeObjectURL(source.url) // 删除被压缩的缓存文件,这里注意,如果是相册选择上传,可能会删除相册的图片 + source.url = res.source + source.thumb = res.source + return source + }).catch(err => { + console.log('图片压缩失败', err) + }) + }, async getOcrText(filePath, file, type) { + return new Promise(async (resolve, reject) => { + + //#ifdef APP-PLUS + filePath = await this.compressImage(filePath); + //#endif + + const batchNoRes = await batchNoApi(filePath, file, type); const batchNo = batchNoRes.batchNo; const formData = new FormData(); @@ -739,10 +784,125 @@ export default { }, 1000); }); }, - //营业执照 - async afterRead(e, type) { - const item = e.file; - const imgUrl = item.url; + /**判断文件类型是否正确 */ + isAssetTypeAnImage(ext) { + const str = ext.split('.')[1]; + return this.limitType.indexOf(str.toLowerCase()) !== -1; + }, + getCompressionRatio(fileSize) { + const multiple = (fileSize / this.fileMaxSize).toFixed(2); + let compressionRatio = 1; + if (multiple > 5) { + compressionRatio = 0.5 + } else if (multiple > 4) { + compressionRatio = 0.6 + } else if (multiple > 3) { + compressionRatio = 0.7 + } else if (multiple > 2) { + compressionRatio = 0.8 + } else if (multiple > 1) { + compressionRatio = 0.9 + } else { + compressionRatio = 2 + } + return compressionRatio; + }, + translate(imgSrc, scale) { + //imgSrc:图片的路径 + //scale:缩放比例 0-1之间 + return new Promise((reslove, reject) => { + var img = new Image(); //创建Image对象生成一个标签 + img.src = imgSrc; //将图片路径赋给标签的src + img.onload = () => {//onload在图片加载成功后触发,在onload中完成压缩功能 + var h = img.height/2; // 获取原本图片的宽高 + var w = img.width/2; //默认按比例压缩,根据需求修改 + var canvas = document.createElement('canvas');//创建画布 + var ctx = canvas.getContext('2d'); //设置为2d效果 + var width = document.createAttribute("width"); //创建属性节点 + width.nodeValue = w; //设置属性值 + var height = document.createAttribute("height"); + height.nodeValue = h; + canvas.setAttributeNode(width); //设置画布宽高 + canvas.setAttributeNode(height); + ctx.drawImage(img, 0, 0, w,h);//将图片贴到画布上 + //img:图片 0,0:粘贴的位置 w,h:粘贴图片的大小 + var base64 = canvas.toDataURL('image/png', scale); + //'image/png':压缩返回图片的类型 scale:图片质量 + //如果要base64的流,可以直接将结果返回了 + canvas = null; //清除画布 + var blob = this.base64ToBlob(base64); //需要二进制流调用该方法拿到 + let blobUrl = window.URL.createObjectURL(blob);//blob地址 + reslove(blobUrl) + } + }) + }, + // base64转Blob + base64ToBlob(base64) { + var arr = base64.split(','), + mime = arr[0].match(/:(.*?);/)[1], + bstr = atob(arr[1]), + n = bstr.length, + u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + return new Blob([u8arr], { + type: mime, + }); + }, + // 上传图片 + async afterRead(event, type) { + var item = event.file; + + console.log("压缩前:",item.url); + + + var a = await this.translate(item.url,0.9) + + item.url = a; + + + + + // let lists = [].concat(event.file); + // let fileListLen = this[`fileList${event.name}`].length; + // for (let index in lists) { + // const fileItem = lists[index]; + // const fileSize = fileItem.size; + // const fileName = fileItem.name ?? ''; + // if(!this.isAssetTypeAnImage(fileItem.name)) { + // this.$.msg('不允许该文件类型上传'); + // return false + // } + // console.log('文件大小',fileSize); + // if (fileSize > this.fileMaxSize) { + // const compressionRatio = this.getCompressionRatio(fileSize); + // if (compressionRatio > 1) { + // uni.$u.toast("上传图片大小不能超过5MB!"); + + // return false + // } + // // 超出1M自动压缩图片 + // item = await this.handerCompressImg(fileItem, compressionRatio) + + // if (fileItem.size > this.maxSize) { + // uni.$u.toast("上传图片大小不能超过5MB!"); + // return false + // } + // } + // if (fileItem.size < this.fileMinSize) { + // uni.$u.toast("上传图片大小不能超过5MB!"); + // return false + // } + // } + + + + console.log("压缩后:",item.url); + + var imgUrl = item.url; + + const group = { url: imgUrl, @@ -769,7 +929,7 @@ export default { this.fileList6.push(group); break; } - + console.log(imgUrl) let res = await UploadFilePromise(imgUrl); if (res && res.status == 200) { diff --git a/java-mall-app-shop-admin/pages/audit/shop3.vue b/java-mall-app-shop-admin/pages/audit/shop3.vue index 247d5cc..72a567d 100644 --- a/java-mall-app-shop-admin/pages/audit/shop3.vue +++ b/java-mall-app-shop-admin/pages/audit/shop3.vue @@ -172,6 +172,7 @@ import { batchNoApi, imgOcrResultApi } from "../../api/upload"; import { mapState } from "vuex"; import { throttle, debounce } from "lodash"; import navBar from "@/components/uni-nav-bar/uni-nav-bar"; +import { compressImg } from '@/utils/tool.js' const orcImgTypeConf = { FR_ID_CARD_FRONT: "FR_ID_CARD_FRONT", @@ -230,6 +231,10 @@ export default { }, ], }, + limitType: ['png', 'jpg', 'jpeg'], //允许的图片后缀 + fileMaxSize: 1 * 1024 * 1024, // 超出1M开启压缩 + maxSize:5 * 1024 * 1024, //图片最大不能超过20M + fileMinSize: 5 * 1024, // 最小为5KB }; }, computed: { @@ -254,9 +259,68 @@ export default { uni.navigateBack(); }, overSize(e) { - uni.$u.toast("上传图片大小不能超过8MB!"); + uni.$u.toast("上传图片大小不能超过5MB!"); + }, + compressImage(url) { + return new Promise((reslove, reject) => { + const tempFilePath = url //url是选中图片的路径 + uni.compressImage({ + src: tempFilePath, + quality: 90, //压缩的程度 + success: (res) => { + reslove(res.tempFilePath) //压缩成功返回的路径 + }, + fail: (error) => { + console.log('压缩失败', error) + } + }) + }) + }, + async handerCompressImg(source, compressionRatio) { + let that = this; + return new Promise((resolve, reject) => { + compressImg(source.url, compressionRatio, source.type, compressRes => { + resolve(compressRes); + }) + }).then((res) => { + source.size = res.size + // window.URL.revokeObjectURL(source.url) // 删除被压缩的缓存文件,这里注意,如果是相册选择上传,可能会删除相册的图片 + source.url = res.source + source.thumb = res.source + return source + }).catch(err => { + console.log('图片压缩失败', err) + }) + }, + /**判断文件类型是否正确 */ + isAssetTypeAnImage(ext) { + const str = ext.split('.')[1]; + return this.limitType.indexOf(str.toLowerCase()) !== -1; + }, + getCompressionRatio(fileSize) { + const multiple = (fileSize / this.fileMaxSize).toFixed(2); + let compressionRatio = 1; + if (multiple > 5) { + compressionRatio = 0.5 + } else if (multiple > 4) { + compressionRatio = 0.6 + } else if (multiple > 3) { + compressionRatio = 0.7 + } else if (multiple > 2) { + compressionRatio = 0.8 + } else if (multiple > 1) { + compressionRatio = 0.9 + } else { + compressionRatio = 2 + } + return compressionRatio; }, getOcrText(filePath, file, type) { + + //#ifdef APP-PLUS + filePath = await this.compressImage(filePath); + //#endif + return new Promise(async (resolve, reject) => { this.loading = true; @@ -313,14 +377,46 @@ export default { console.log("bankCard", ocr); }, - async afterRead(e) { - const item = e.file; + async afterRead(event) { + var item = event.file; const imgUrl = item.url; const group = { url: imgUrl, }; + let lists = [].concat(event.file); + let fileListLen = this[`fileList${event.name}`].length; + for (let index in lists) { + const group = lists[index]; + const fileSize = group.size; + const fileName = group.name ?? ''; + if(!this.isAssetTypeAnImage(group.name)) { + this.$.msg('不允许该文件类型上传'); + return false + } + console.log('文件大小',fileSize); + if (fileSize > this.fileMaxSize) { + const compressionRatio = this.getCompressionRatio(fileSize); + if (compressionRatio > 1) { + this.$.msg('文件' + fileName + '大于5M'); + return false + } + // 超出1M自动压缩图片 + item = await this.handerCompressImg(item, compressionRatio) + + if (item.size > this.maxSize) { + this.$.msg('文件' + fileName + '压缩后超出20M') + return false + } + } + if (item.size < this.fileMinSize) { + this.$.msg('文件' + fileName + '不能小于5KB'); + return false + } + + } + console.log(e); this.currentBankFile = { diff --git a/java-mall-app-shop-admin/pages/order/order.vue b/java-mall-app-shop-admin/pages/order/order.vue index e8afe91..adc82da 100644 --- a/java-mall-app-shop-admin/pages/order/order.vue +++ b/java-mall-app-shop-admin/pages/order/order.vue @@ -161,8 +161,8 @@ {{ item.order_pickup_num_str }} - 备注: - {{ item.buyer_info.order_message }} + 备注: + {{ item.buyer_info.order_message }} @@ -962,18 +962,6 @@ export default { }, onLoad() {}, onShow() { - let accountDashboard = uni.getStorageSync("accountDashboard"); - let auditInfo = uni.getStorageSync("auditInfo"); - - if (accountDashboard) { - this.shopNmae = accountDashboard.store_info.store_name; - this.logoUrl = accountDashboard.store_info.store_logo; - } else { - this.getAccountDashboard(); - } - if (!auditInfo) { - this.getAuditInfo(); - } this.getOrderList(); }, @@ -993,7 +981,22 @@ export default { // }, methods: { async getOrderList() { + + let accountDashboard = uni.getStorageSync("accountDashboard"); + let auditInfo = uni.getStorageSync("auditInfo"); + + if (accountDashboard) { + this.shopNmae = accountDashboard.store_info.store_name; + this.logoUrl = accountDashboard.store_info.store_logo; + } else { + await this.getAccountDashboard(); + } + if (!auditInfo) { + await this.getAuditInfo(); + } + this.showOrderLoading = true; + console.log(this.accountInfo) this.params = { storeId: this.accountInfo.store_info.store_id, keyword: this.keyword, diff --git a/java-mall-app-shop-admin/uniCloud-aliyun/cloudfunctions/push/index.js b/java-mall-app-shop-admin/uniCloud-aliyun/cloudfunctions/push/index.js new file mode 100644 index 0000000..6cea0f4 --- /dev/null +++ b/java-mall-app-shop-admin/uniCloud-aliyun/cloudfunctions/push/index.js @@ -0,0 +1,160 @@ +'use strict'; +const uniPush = uniCloud.getPushManager({ + appId: "__UNI__95F809F" +}); +const db = uniCloud.database(); +const pushLogCollection = db.collection('push_logs'); // 假设存在 push_logs 集合用于记录推送日志 + +// 验证设备 ID 是否有效 +const isValidDeviceId = (deviceId) => { + return typeof deviceId ==='string' && deviceId.trim()!== ''; +}; + +exports.main = async (event) => { + try { + let obj = JSON.parse(event.body); + + // 检查发送者和接收者信息 + if (!obj.senderId ||!obj.receiverId) { + const errorMsg = '缺少发送者或接收者信息'; + // 记录错误日志 + await pushLogCollection.add({ + senderId: obj.senderId, + receiverId: obj.receiverId, + title: obj.title, + content: obj.content, + status: 'failed', + errorCode: 400, + errorMsg: errorMsg, + timestamp: new Date(), + requestBody: obj + }); + return { + code: 400, + msg: errorMsg + }; + } + + // 如果 category 不是对象,将其移除 + if (typeof obj.category!== 'object') { + delete obj.category; + } + + // 从数据库中获取接收者的设备标识 + if (typeof obj.receiverId!== 'string' || obj.receiverId.trim() === '') { + const errorMsg = '接收者 ID 无效'; + // 记录错误日志 + await pushLogCollection.add({ + senderId: obj.senderId, + receiverId: obj.receiverId, + title: obj.title, + content: obj.content, + status: 'failed', + errorCode: 400, + errorMsg: errorMsg, + timestamp: new Date(), + requestBody: obj + }); + return { + code: 400, + msg: errorMsg + }; + } + const receiverDevices = await db.collection('opendb-device') + .where({ userId: obj.receiverId }) + .get(); + + console.log('接收者 ID:', obj.receiverId); + console.log('查询到的设备信息原始数据:', receiverDevices.data); // 打印原始数据 + + if (receiverDevices.data.length === 0) { + const errorMsg = `未找到接收者(ID: ${obj.receiverId})的设备信息`; + // 记录错误日志 + await pushLogCollection.add({ + senderId: obj.senderId, + receiverId: obj.receiverId, + title: obj.title, + content: obj.content, + status: 'failed', + errorCode: 404, + errorMsg: errorMsg, + timestamp: new Date(), + requestBody: obj + }); + return { + code: 404, + msg: errorMsg + }; + } + const pushClientIds = "设备id"; + // console.log(pushClientIds); + const validDeviceIds = ["设备id"]; + validDeviceIds.push(); + const invalidDeviceIds = []; + if (validDeviceIds.length === 0) { + const errorMsg = `接收者(ID: ${obj.receiverId})的所有设备 ID 均无效,无效的 ID 包括: ${invalidDeviceIds.join(', ')}`; + // 记录错误日志 + await pushLogCollection.add({ + senderId: obj.senderId, + receiverId: obj.receiverId, + title: obj.title, + content: obj.content, + status: 'failed', + errorCode: 400, + errorMsg: errorMsg, + timestamp: new Date(), + requestBody: obj + }); + return { + code: 400, + msg: errorMsg + }; + } + const res = await uniPush.sendMessage({ + "push_clientid": validDeviceIds, + "title": obj.title, + "content": obj.content, + "payload": obj.payload, + "force_notification": true, + "request_id": obj.request_id, + "options": obj.options + }); + + // 记录成功日志 + await pushLogCollection.add({ + senderId: obj.senderId, + receiverId: obj.receiverId, + title: obj.title, + content: obj.content, + status:'success', + pushResult: res, + timestamp: new Date(), + requestBody: obj + }); + return { + code: 200, + msg: '消息推送成功', + data: res + }; + } catch (error) { + console.error('消息推送出错:', error); + // 记录异常错误日志 + await pushLogCollection.add({ + senderId: event.senderId, + receiverId: event.receiverId, + title: event.title, + content: event.content, + status: 'failed', + errorCode: 500, + errorMsg: '消息推送失败', + errorDetail: error.message, + timestamp: new Date(), + requestBody: event.body + }); + return { + code: 500, + msg: '消息推送失败', + error: error.message + }; + } +}; \ No newline at end of file diff --git a/java-mall-app-shop-admin/uniCloud-aliyun/cloudfunctions/push/package.json b/java-mall-app-shop-admin/uniCloud-aliyun/cloudfunctions/push/package.json new file mode 100644 index 0000000..b471ec2 --- /dev/null +++ b/java-mall-app-shop-admin/uniCloud-aliyun/cloudfunctions/push/package.json @@ -0,0 +1,10 @@ +{ + "name": "test", + "version": "1.0.0", + "description": "", + "main": "index.js", + "extensions": { + "uni-cloud-push": {} + }, + "author": "" +} \ No newline at end of file diff --git a/java-mall-app-shop-admin/uniCloud-aliyun/database/JQL查询.jql b/java-mall-app-shop-admin/uniCloud-aliyun/database/JQL查询.jql new file mode 100644 index 0000000..35d21de --- /dev/null +++ b/java-mall-app-shop-admin/uniCloud-aliyun/database/JQL查询.jql @@ -0,0 +1,12 @@ +// 本文件用于,使用JQL语法操作项目关联的uniCloud空间的数据库,方便开发调试和远程数据库管理 +// 编写clientDB的js API(也支持常规js语法,比如var),可以对云数据库进行增删改查操作。不支持uniCloud-db组件写法 +// 可以全部运行,也可以选中部分代码运行。点击工具栏上的运行按钮或者按下【F5】键运行代码 +// 如果文档中存在多条JQL语句,只有最后一条语句生效 +// 如果混写了普通js,最后一条语句需是数据库操作语句 +// 此处代码运行不受DB Schema的权限控制,移植代码到实际业务中注意在schema中配好permission +// 不支持clientDB的action +// 数据库查询有最大返回条数限制,详见:https://uniapp.dcloud.net.cn/uniCloud/cf-database.html#limit +// 详细JQL语法,请参考:https://uniapp.dcloud.net.cn/uniCloud/jql.html + +// 下面示例查询uni-id-users表的所有数据 +db.collection('uni-id-users').get(); diff --git a/java-mall-app-shop-admin/uni_modules/uni-config-center/changelog.md b/java-mall-app-shop-admin/uni_modules/uni-config-center/changelog.md new file mode 100644 index 0000000..5af5257 --- /dev/null +++ b/java-mall-app-shop-admin/uni_modules/uni-config-center/changelog.md @@ -0,0 +1,6 @@ +## 0.0.3(2022-11-11) +- 修复 config 方法获取根节点为数组格式配置时错误的转化为了对象的Bug +## 0.0.2(2021-04-16) +- 修改插件package信息 +## 0.0.1(2021-03-15) +- 初始化项目 diff --git a/java-mall-app-shop-admin/uni_modules/uni-config-center/package.json b/java-mall-app-shop-admin/uni_modules/uni-config-center/package.json new file mode 100644 index 0000000..0798109 --- /dev/null +++ b/java-mall-app-shop-admin/uni_modules/uni-config-center/package.json @@ -0,0 +1,81 @@ +{ + "id": "uni-config-center", + "displayName": "uni-config-center", + "version": "0.0.3", + "description": "uniCloud 配置中心", + "keywords": [ + "配置", + "配置中心" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "", + "type": "unicloud-template-function" + }, + "directories": { + "example": "../../../scripts/dist" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "u", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "u" + } + } + } + } +} diff --git a/java-mall-app-shop-admin/uni_modules/uni-config-center/readme.md b/java-mall-app-shop-admin/uni_modules/uni-config-center/readme.md new file mode 100644 index 0000000..0bd8ac4 --- /dev/null +++ b/java-mall-app-shop-admin/uni_modules/uni-config-center/readme.md @@ -0,0 +1,93 @@ +# 为什么使用uni-config-center + +实际开发中很多插件需要配置文件才可以正常运行,如果每个插件都单独进行配置的话就会产生下面这样的目录结构 + +```bash +cloudfunctions +└─────common 公共模块 + ├─plugin-a // 插件A对应的目录 + │ ├─index.js + │ ├─config.json // plugin-a对应的配置文件 + │ └─other-file.cert // plugin-a依赖的其他文件 + └─plugin-b // plugin-b对应的目录 + ├─index.js + └─config.json // plugin-b对应的配置文件 +``` + +假设插件作者要发布一个项目模板,里面使用了很多需要配置的插件,无论是作者发布还是用户使用都是一个大麻烦。 + +uni-config-center就是用了统一管理这些配置文件的,使用uni-config-center后的目录结构如下 + +```bash +cloudfunctions +└─────common 公共模块 + ├─plugin-a // 插件A对应的目录 + │ └─index.js + ├─plugin-b // plugin-b对应的目录 + │ └─index.js + └─uni-config-center + ├─index.js // config-center入口文件 + ├─plugin-a + │ ├─config.json // plugin-a对应的配置文件 + │ └─other-file.cert // plugin-a依赖的其他文件 + └─plugin-b + └─config.json // plugin-b对应的配置文件 +``` + +使用uni-config-center后的优势 + +- 配置文件统一管理,分离插件主体和配置信息,更新插件更方便 +- 支持对config.json设置schema,插件使用者在HBuilderX内编写config.json文件时会有更好的提示(后续HBuilderX会提供支持) + +# 用法 + +在要使用uni-config-center的公共模块或云函数内引入uni-config-center依赖,请参考:[使用公共模块](https://uniapp.dcloud.net.cn/uniCloud/cf-common) + +```js +const createConfig = require('uni-config-center') + +const uniIdConfig = createConfig({ + pluginId: 'uni-id', // 插件id + defaultConfig: { // 默认配置 + tokenExpiresIn: 7200, + tokenExpiresThreshold: 600, + }, + customMerge: function(defaultConfig, userConfig) { // 自定义默认配置和用户配置的合并规则,不设置的情况侠会对默认配置和用户配置进行深度合并 + // defaudltConfig 默认配置 + // userConfig 用户配置 + return Object.assign(defaultConfig, userConfig) + } +}) + + +// 以如下配置为例 +// { +// "tokenExpiresIn": 7200, +// "passwordErrorLimit": 6, +// "bindTokenToDevice": false, +// "passwordErrorRetryTime": 3600, +// "app-plus": { +// "tokenExpiresIn": 2592000 +// }, +// "service": { +// "sms": { +// "codeExpiresIn": 300 +// } +// } +// } + +// 获取配置 +uniIdConfig.config() // 获取全部配置,注意:uni-config-center内不存在对应插件目录时会返回空对象 +uniIdConfig.config('tokenExpiresIn') // 指定键值获取配置,返回:7200 +uniIdConfig.config('service.sms.codeExpiresIn') // 指定键值获取配置,返回:300 +uniIdConfig.config('tokenExpiresThreshold', 600) // 指定键值获取配置,如果不存在则取传入的默认值,返回:600 + +// 获取文件绝对路径 +uniIdConfig.resolve('custom-token.js') // 获取uni-config-center/uni-id/custom-token.js文件的路径 + +// 引用文件(require) +uniIDConfig.requireFile('custom-token.js') // 使用require方式引用uni-config-center/uni-id/custom-token.js文件。文件不存在时返回undefined,文件内有其他错误导致require失败时会抛出错误。 + +// 判断是否包含某文件 +uniIDConfig.hasFile('custom-token.js') // 配置目录是否包含某文件,true: 文件存在,false: 文件不存在 +``` \ No newline at end of file diff --git a/java-mall-app-shop-admin/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js b/java-mall-app-shop-admin/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js new file mode 100644 index 0000000..00ba62f --- /dev/null +++ b/java-mall-app-shop-admin/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js @@ -0,0 +1 @@ +"use strict";var t=require("fs"),r=require("path");function e(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var n=e(t),o=e(r),i="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};var u=function(t){var r={exports:{}};return t(r,r.exports),r.exports}((function(t,r){var e="__lodash_hash_undefined__",n=9007199254740991,o="[object Arguments]",u="[object Function]",c="[object Object]",a=/^\[object .+?Constructor\]$/,f=/^(?:0|[1-9]\d*)$/,s={};s["[object Float32Array]"]=s["[object Float64Array]"]=s["[object Int8Array]"]=s["[object Int16Array]"]=s["[object Int32Array]"]=s["[object Uint8Array]"]=s["[object Uint8ClampedArray]"]=s["[object Uint16Array]"]=s["[object Uint32Array]"]=!0,s[o]=s["[object Array]"]=s["[object ArrayBuffer]"]=s["[object Boolean]"]=s["[object DataView]"]=s["[object Date]"]=s["[object Error]"]=s[u]=s["[object Map]"]=s["[object Number]"]=s[c]=s["[object RegExp]"]=s["[object Set]"]=s["[object String]"]=s["[object WeakMap]"]=!1;var l="object"==typeof i&&i&&i.Object===Object&&i,h="object"==typeof self&&self&&self.Object===Object&&self,p=l||h||Function("return this")(),_=r&&!r.nodeType&&r,v=_&&t&&!t.nodeType&&t,d=v&&v.exports===_,y=d&&l.process,g=function(){try{var t=v&&v.require&&v.require("util").types;return t||y&&y.binding&&y.binding("util")}catch(t){}}(),b=g&&g.isTypedArray;function j(t,r,e){switch(e.length){case 0:return t.call(r);case 1:return t.call(r,e[0]);case 2:return t.call(r,e[0],e[1]);case 3:return t.call(r,e[0],e[1],e[2])}return t.apply(r,e)}var w,O,m,A=Array.prototype,z=Function.prototype,M=Object.prototype,x=p["__core-js_shared__"],C=z.toString,F=M.hasOwnProperty,U=(w=/[^.]+$/.exec(x&&x.keys&&x.keys.IE_PROTO||""))?"Symbol(src)_1."+w:"",S=M.toString,I=C.call(Object),P=RegExp("^"+C.call(F).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),T=d?p.Buffer:void 0,q=p.Symbol,E=p.Uint8Array,$=T?T.allocUnsafe:void 0,D=(O=Object.getPrototypeOf,m=Object,function(t){return O(m(t))}),k=Object.create,B=M.propertyIsEnumerable,N=A.splice,L=q?q.toStringTag:void 0,R=function(){try{var t=vt(Object,"defineProperty");return t({},"",{}),t}catch(t){}}(),G=T?T.isBuffer:void 0,V=Math.max,W=Date.now,H=vt(p,"Map"),J=vt(Object,"create"),K=function(){function t(){}return function(r){if(!xt(r))return{};if(k)return k(r);t.prototype=r;var e=new t;return t.prototype=void 0,e}}();function Q(t){var r=-1,e=null==t?0:t.length;for(this.clear();++r-1},X.prototype.set=function(t,r){var e=this.__data__,n=nt(e,t);return n<0?(++this.size,e.push([t,r])):e[n][1]=r,this},Y.prototype.clear=function(){this.size=0,this.__data__={hash:new Q,map:new(H||X),string:new Q}},Y.prototype.delete=function(t){var r=_t(this,t).delete(t);return this.size-=r?1:0,r},Y.prototype.get=function(t){return _t(this,t).get(t)},Y.prototype.has=function(t){return _t(this,t).has(t)},Y.prototype.set=function(t,r){var e=_t(this,t),n=e.size;return e.set(t,r),this.size+=e.size==n?0:1,this},Z.prototype.clear=function(){this.__data__=new X,this.size=0},Z.prototype.delete=function(t){var r=this.__data__,e=r.delete(t);return this.size=r.size,e},Z.prototype.get=function(t){return this.__data__.get(t)},Z.prototype.has=function(t){return this.__data__.has(t)},Z.prototype.set=function(t,r){var e=this.__data__;if(e instanceof X){var n=e.__data__;if(!H||n.length<199)return n.push([t,r]),this.size=++e.size,this;e=this.__data__=new Y(n)}return e.set(t,r),this.size=e.size,this};var it,ut=function(t,r,e){for(var n=-1,o=Object(t),i=e(t),u=i.length;u--;){var c=i[it?u:++n];if(!1===r(o[c],c,o))break}return t};function ct(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":L&&L in Object(t)?function(t){var r=F.call(t,L),e=t[L];try{t[L]=void 0;var n=!0}catch(t){}var o=S.call(t);n&&(r?t[L]=e:delete t[L]);return o}(t):function(t){return S.call(t)}(t)}function at(t){return Ct(t)&&ct(t)==o}function ft(t){return!(!xt(t)||function(t){return!!U&&U in t}(t))&&(zt(t)?P:a).test(function(t){if(null!=t){try{return C.call(t)}catch(t){}try{return t+""}catch(t){}}return""}(t))}function st(t){if(!xt(t))return function(t){var r=[];if(null!=t)for(var e in Object(t))r.push(e);return r}(t);var r=yt(t),e=[];for(var n in t)("constructor"!=n||!r&&F.call(t,n))&&e.push(n);return e}function lt(t,r,e,n,o){t!==r&&ut(r,(function(i,u){if(o||(o=new Z),xt(i))!function(t,r,e,n,o,i,u){var a=gt(t,e),f=gt(r,e),s=u.get(f);if(s)return void rt(t,e,s);var l=i?i(a,f,e+"",t,r,u):void 0,h=void 0===l;if(h){var p=Ot(f),_=!p&&At(f),v=!p&&!_&&Ft(f);l=f,p||_||v?Ot(a)?l=a:Ct(j=a)&&mt(j)?l=function(t,r){var e=-1,n=t.length;r||(r=Array(n));for(;++e-1&&t%1==0&&t0){if(++r>=800)return arguments[0]}else r=0;return t.apply(void 0,arguments)}}(pt);function jt(t,r){return t===r||t!=t&&r!=r}var wt=at(function(){return arguments}())?at:function(t){return Ct(t)&&F.call(t,"callee")&&!B.call(t,"callee")},Ot=Array.isArray;function mt(t){return null!=t&&Mt(t.length)&&!zt(t)}var At=G||function(){return!1};function zt(t){if(!xt(t))return!1;var r=ct(t);return r==u||"[object GeneratorFunction]"==r||"[object AsyncFunction]"==r||"[object Proxy]"==r}function Mt(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=n}function xt(t){var r=typeof t;return null!=t&&("object"==r||"function"==r)}function Ct(t){return null!=t&&"object"==typeof t}var Ft=b?function(t){return function(r){return t(r)}}(b):function(t){return Ct(t)&&Mt(t.length)&&!!s[ct(t)]};function Ut(t){return mt(t)?tt(t,!0):st(t)}var St,It=(St=function(t,r,e){lt(t,r,e)},ht((function(t,r){var e=-1,n=r.length,o=n>1?r[n-1]:void 0,i=n>2?r[2]:void 0;for(o=St.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,r,e){if(!xt(e))return!1;var n=typeof r;return!!("number"==n?mt(e)&&dt(r,e.length):"string"==n&&r in e)&&jt(e[r],t)}(r[0],r[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++ec.call(t,r);class f{constructor({pluginId:t,defaultConfig:r={},customMerge:e,root:n}){this.pluginId=t,this.defaultConfig=r,this.pluginConfigPath=o.default.resolve(n||__dirname,t),this.customMerge=e,this._config=void 0}resolve(t){return o.default.resolve(this.pluginConfigPath,t)}hasFile(t){return n.default.existsSync(this.resolve(t))}requireFile(t){try{return require(this.resolve(t))}catch(t){if("MODULE_NOT_FOUND"===t.code)return;throw t}}_getUserConfig(){return this.requireFile("config.json")}config(t,r){if(!this._config){const t=this._getUserConfig();this._config=Array.isArray(t)?t:(this.customMerge||u)(this.defaultConfig,t)}let e=this._config;return t?function(t,r,e){if("number"==typeof r)return t[r];if("symbol"==typeof r)return a(t,r)?t[r]:e;const n="string"!=typeof(o=r)?o:o.split(".").reduce(((t,r)=>(r.split(/\[([^}]+)\]/g).forEach((r=>r&&t.push(r))),t)),[]);var o;let i=t;for(let t=0;tparseInt(e)):void 0}function o(e,t){const n=r(e),i=r(t);return n?i?function(e,t){const n=Math.max(e.length,t.length);for(let i=0;ir)return 1;if(n=e)throw new Error("Config error, tokenExpiresThreshold should be less than tokenExpiresIn");t>e/2&&console.warn(`Please check whether the tokenExpiresThreshold configuration is set too large, tokenExpiresThreshold: ${t}, tokenExpiresIn: ${e}`)}get customToken(){return this.uniId.interceptorMap.get("customToken")}isTokenInDb(e){return o(e,"1.0.10")>=0}async getUserRecord(){if(this.userRecord)return this.userRecord;const e=await C.doc(this.uid).get();if(this.userRecord=e.data[0],!this.userRecord)throw{errCode:n.ACCOUNT_NOT_EXISTS};switch(this.userRecord.status){case void 0:case 0:break;case 1:throw{errCode:n.ACCOUNT_BANNED};case 2:throw{errCode:n.ACCOUNT_AUDITING};case 3:throw{errCode:n.ACCOUNT_AUDIT_FAILED};case 4:throw{errCode:n.ACCOUNT_CLOSED}}if(this.oldTokenPayload){if(this.isTokenInDb(this.oldTokenPayload.uniIdVersion)){if(-1===(this.userRecord.token||[]).indexOf(this.oldToken))throw{errCode:n.CHECK_TOKEN_FAILED}}if(this.userRecord.valid_token_date&&this.userRecord.valid_token_date>1e3*this.oldTokenPayload.iat)throw{errCode:n.TOKEN_EXPIRED}}return this.userRecord}async updateUserRecord(e){await C.doc(this.uid).update(e)}async getUserPermission(){if(this.userPermission)return this.userPermission;const e=(await this.getUserRecord()).role||[];if(0===e.length)return this.userPermission={role:[],permission:[]},this.userPermission;if(e.includes("admin"))return this.userPermission={role:e,permission:[]},this.userPermission;const t=await T.where({role_id:I.in(e)}).get(),n=(i=t.data.reduce((e,t)=>(t.permission&&e.push(...t.permission),e),[]),Array.from(new Set(i)));var i;return this.userPermission={role:e,permission:n},this.userPermission}async _createToken({uid:e,role:t,permission:i}={}){if(!t||!i){const e=await this.getUserPermission();t=e.role,i=e.permission}let r={uid:e,role:t,permission:i};if(this.uniId.interceptorMap.has("customToken")){const n=this.uniId.interceptorMap.get("customToken");if("function"!=typeof n)throw new Error("Invalid custom token file");r=await n({uid:e,role:t,permission:i})}const o=Date.now(),{tokenSecret:s,tokenExpiresIn:c,maxTokenLength:a=10}=this.config,u=g({...r,uniIdVersion:"1.0.18"},s,{expiresIn:c}),d=await this.getUserRecord(),l=(d.token||[]).filter(e=>{try{const t=this._checkToken(e);if(d.valid_token_date&&d.valid_token_date>1e3*t.iat)return!1}catch(e){if(e.errCode===n.TOKEN_EXPIRED)return!1}return!0});return l.push(u),l.length>a&&l.splice(0,l.length-a),await this.updateUserRecord({last_login_ip:this.clientInfo.clientIP,last_login_date:o,token:l}),{token:u,tokenExpired:o+1e3*c}}async createToken({uid:e,role:t,permission:i}={}){if(!e)throw{errCode:n.PARAM_REQUIRED,errMsgValue:{param:"uid"}};this.uid=e;const{token:r,tokenExpired:o}=await this._createToken({uid:e,role:t,permission:i});return{errCode:0,token:r,tokenExpired:o}}async refreshToken({token:e}={}){if(!e)throw{errCode:n.PARAM_REQUIRED,errMsgValue:{param:"token"}};this.oldToken=e;const t=this._checkToken(e);this.uid=t.uid,this.oldTokenPayload=t;const{uid:i}=t,{role:r,permission:o}=await this.getUserPermission(),{token:s,tokenExpired:c}=await this._createToken({uid:i,role:r,permission:o});return{errCode:0,token:s,tokenExpired:c}}_checkToken(e){const{tokenSecret:t}=this.config;let i;try{i=k(e,t)}catch(e){if("TokenExpiredError"===e.name)throw{errCode:n.TOKEN_EXPIRED};throw{errCode:n.CHECK_TOKEN_FAILED}}return i}async checkToken(e,{autoRefresh:t=!0}={}){if(!e)throw{errCode:n.CHECK_TOKEN_FAILED};this.oldToken=e;const i=this._checkToken(e);this.uid=i.uid,this.oldTokenPayload=i;const{tokenExpiresThreshold:r}=this.config,{uid:o,role:s,permission:c}=i,a={role:s,permission:c};if(!s&&!c){const{role:e,permission:t}=await this.getUserPermission();a.role=e,a.permission=t}if(!r||!t){const e={code:0,errCode:0,...i,...a};return delete e.uniIdVersion,e}const u=Date.now();let d={};1e3*i.exp-u<1e3*r&&(d=await this._createToken({uid:o}));const l={code:0,errCode:0,...i,...a,...d};return delete l.uniIdVersion,l}}var m=Object.freeze({__proto__:null,checkToken:async function(e,{autoRefresh:t=!0}={}){return new E({uniId:this}).checkToken(e,{autoRefresh:t})},createToken:async function({uid:e,role:t,permission:n}={}){return new E({uniId:this}).createToken({uid:e,role:t,permission:n})},refreshToken:async function({token:e}={}){return new E({uniId:this}).refreshToken({token:e})}});const w=require("uni-config-center")({pluginId:"uni-id"});class x{constructor({context:e,clientInfo:t,config:n}={}){this._clientInfo=e?function(e){return{appId:e.APPID,platform:e.PLATFORM,locale:e.LOCALE,clientIP:e.CLIENTIP,deviceId:e.DEVICEID}}(e):t,this._config=n,this.config=this._getOriginConfig(),this.interceptorMap=new Map,w.hasFile("custom-token.js")&&this.setInterceptor("customToken",require(w.resolve("custom-token.js")));this._i18n=uniCloud.initI18n({locale:this._clientInfo.locale,fallbackLocale:"zh-Hans",messages:JSON.parse(JSON.stringify(d))}),d[this._i18n.locale]||this._i18n.setLocale("zh-Hans")}setInterceptor(e,t){this.interceptorMap.set(e,t)}_t(...e){return this._i18n.t(...e)}_parseOriginConfig(e){return Array.isArray(e)?e:e[0]?Object.values(e):e}_getOriginConfig(){if(this._config)return this._config;if(w.hasFile("config.json")){let e;try{e=w.config()}catch(e){throw new Error("Invalid uni-id config file\n"+e.message)}return this._parseOriginConfig(e)}try{return this._parseOriginConfig(require("uni-id/config.json"))}catch(e){throw new Error("Invalid uni-id config file")}}_getAppConfig(){const e=this._getOriginConfig();return Array.isArray(e)?e.find(e=>e.dcloudAppid===this._clientInfo.appId)||e.find(e=>e.isDefaultConfig):e}_getPlatformConfig(){const e=this._getAppConfig();if(!e)throw new Error(`Config for current app (${this._clientInfo.appId}) was not found, please check your config file or client appId`);let t;switch(["app-plus","app-android","app-ios"].indexOf(this._clientInfo.platform)>-1&&(this._clientInfo.platform="app"),"h5"===this._clientInfo.platform&&(this._clientInfo.platform="web"),this._clientInfo.platform){case"web":t="h5";break;case"app":t="app-plus"}const n=[{tokenExpiresIn:7200,tokenExpiresThreshold:1200,passwordErrorLimit:6,passwordErrorRetryTime:3600},e];t&&e[t]&&n.push(e[t]),n.push(e[this._clientInfo.platform]);const i=Object.assign(...n);return["tokenSecret","tokenExpiresIn"].forEach(e=>{if(!i||!i[e])throw new Error(`Config parameter missing, ${e} is required`)}),i}_getConfig(){return this._getPlatformConfig()}}for(const e in m)x.prototype[e]=m[e];function y(e){const t=new x(e);return new Proxy(t,{get(e,t){if(t in e&&0!==t.indexOf("_")){if("function"==typeof e[t])return(n=e[t],function(){let e;try{e=n.apply(this,arguments)}catch(e){if(a(e))return c.call(this,e),e;throw e}return i(e)?e.then(e=>(a(e)&&c.call(this,e),e),e=>{if(a(e))return c.call(this,e),e;throw e}):(a(e)&&c.call(this,e),e)}).bind(e);if("context"!==t&&"config"!==t)return e[t]}var n}})}x.prototype.createInstance=y;const O={createInstance:y};module.exports=O; diff --git a/java-mall-app-shop-admin/uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/package.json b/java-mall-app-shop-admin/uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/package.json new file mode 100644 index 0000000..7003ea0 --- /dev/null +++ b/java-mall-app-shop-admin/uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/package.json @@ -0,0 +1,20 @@ +{ + "name": "uni-id-common", + "version": "1.0.18", + "description": "uni-id token生成、校验、刷新", + "main": "index.js", + "homepage": "https:\/\/uniapp.dcloud.io\/uniCloud\/uni-id-common.html", + "repository": { + "type": "git", + "url": "git+https:\/\/gitee.com\/dcloud\/uni-id-common.git" + }, + "author": "DCloud", + "license": "Apache-2.0", + "dependencies": { + "uni-config-center": "file:..\/..\/..\/..\/..\/uni-config-center\/uniCloud\/cloudfunctions\/common\/uni-config-center" + }, + "origin-plugin-dev-name": "uni-id-common", + "origin-plugin-version": "1.0.18", + "plugin-dev-name": "uni-id-common", + "plugin-version": "1.0.18" +} \ No newline at end of file diff --git a/java-mall-app-shop-admin/utils/tool.js b/java-mall-app-shop-admin/utils/tool.js new file mode 100644 index 0000000..37adb74 --- /dev/null +++ b/java-mall-app-shop-admin/utils/tool.js @@ -0,0 +1,75 @@ +/** + * 图片压缩 + * imgSrc 地址 + * scale 压缩质量 0-1 + * type 文件类型 + */ +export function compressImg (imgSrc, scale, type, callback) { + // uni.$u.toast('压缩中') + var img = new Image(); + img.src = imgSrc; + img.onload = function() { + var that = this; + var h = (img.height * scale).toFixed(0); // 默认按质量比例压缩 + var w = (img.width * scale).toFixed(0); + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext('2d'); + var width = document.createAttribute("width"); + width.nodeValue = w; + var height = document.createAttribute("height"); + height.nodeValue = h; + canvas.setAttributeNode(width); + canvas.setAttributeNode(height); + ctx.drawImage(that, 0, 0, w, h); + var base64 = canvas.toDataURL('image/jpeg', scale); //压缩比例 + canvas = null; + if (type == 'base64') { + let data = { + size: getBase64Size(base64), + type: type, + source: base64 + } + callback(base64); + } else { + let blob = base64ToBlob(base64); + console.log('压缩后的大小', blob.size); + const blobUrl = window.URL.createObjectURL(blob); //blob地址 + blob.source = blobUrl + callback(blob); + } + } +}; +/**base转Blob */ +export function base64ToBlob (base64) { + var arr = base64.split(','), + mime = arr[0].match(/:(.*?);/)[1], + bstr = atob(arr[1]), + n = bstr.length, + u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + return new Blob([u8arr], { + type: mime + }); +}; +/**获取base64的文件大小 */ +export function getBase64Size () { + let size = 0; + if (base64Str) { // 获取base64图片byte大小 + const equalIndex = base64Str.indexOf('='); // 获取=号下标 + if (equalIndex > 0) { + const str = base64Str.substring(0, equalIndex); // 去除=号 + const strLength = str.length; + const fileLength = strLength - (strLength / 8) * 2; // 真实的图片byte大小 + size = Math.floor(fileLength); // 向下取整 + } else { + const strLength = base64Str.length; + const fileLength = strLength - (strLength / 8) * 2; + size = Math.floor(fileLength); // 向下取整 + } + } else { + size = null; + } + return size +}; \ No newline at end of file