From 1358e52fdb0b20dee0b1b8f18e89ea041ea5f9d1 Mon Sep 17 00:00:00 2001 From: weicw <594098497@qq.com> Date: Tue, 7 Nov 2023 17:11:57 +0800 Subject: [PATCH] 1107 --- .gitignore | 3 + App.vue | 55 + LICENSE.md | 21 + README.md | 498 ++ app.config.js | 136 + changelog.md | 1548 ++++ changelog.new.md | 8 + common/css/app.scss | 28 + common/css/common.css | 2075 +++++ common/css/uni.scss | 73 + common/function/myPubFunction.js | 15 + components/category-bar/category-bar.vue | 320 + components/common-footer/common-footer.vue | 20 + components/common-header/common-header.vue | 117 + .../custom-form-section.vue | 68 + components/page-nav/page-nav.vue | 20 + components/right-bar/right-bar.vue | 180 + components/top-bar/top-bar.vue | 138 + .../vk-data-input-editor.vue | 1005 +++ index.html | 22 + main.js | 60 + manifest.json | 105 + package-lock.json | 464 ++ package.json | 96 + pages.json | 102 + pages/auth/login/login.vue | 612 ++ pages/auth/register/register.vue | 629 ++ pages/company/company.vue | 34 + pages/enquiry/components/template.vue | 184 + pages/enquiry/list.vue | 254 + pages/enquiry/release.vue | 234 + pages/error/404/404.vue | 49 + pages/index/index.vue | 76 + pages/spot/goods/detail.vue | 497 ++ pages/spot/goods/goods.vue | 320 + pages/spot/release/release.vue | 175 + pages/user/components/business-card.vue | 211 + pages/user/components/personal.vue | 309 + pages/user/user.vue | 61 + .../80705c8b12d05d0ff67a2758749ef09c.jpg | Bin 0 -> 77644 bytes static/images/cc-top.png | Bin 0 -> 186 bytes static/images/cl1.png | Bin 0 -> 18091 bytes static/images/cl3.png | Bin 0 -> 18117 bytes static/images/cl4.png | Bin 0 -> 19551 bytes static/images/cl5.png | Bin 0 -> 18168 bytes static/images/cl6.png | Bin 0 -> 18187 bytes static/images/dowm.png | Bin 0 -> 229 bytes static/images/dowm2.png | Bin 0 -> 212 bytes static/images/home1.png | Bin 0 -> 31642 bytes static/images/home2.png | Bin 0 -> 30567 bytes static/images/home3.png | Bin 0 -> 29095 bytes static/images/icon1.png | Bin 0 -> 18462 bytes static/images/iconsmall.png | Bin 0 -> 191713 bytes static/images/lg1.png | Bin 0 -> 18240 bytes static/images/lg10.png | Bin 0 -> 95939 bytes static/images/lg11.png | Bin 0 -> 95853 bytes static/images/lg12.png | Bin 0 -> 95742 bytes static/images/lg13.png | Bin 0 -> 17991 bytes static/images/lg15.png | Bin 0 -> 15294 bytes static/images/lg2.png | Bin 0 -> 18307 bytes static/images/lg3.png | Bin 0 -> 18383 bytes static/images/lg4.png | Bin 0 -> 17986 bytes static/images/lg5.png | Bin 0 -> 18281 bytes static/images/lg6.png | Bin 0 -> 18185 bytes static/images/lg7.png | Bin 0 -> 17984 bytes static/images/lg8.png | Bin 0 -> 18234 bytes static/images/lg9.png | Bin 0 -> 95914 bytes static/images/login-bg.jpg | Bin 0 -> 346154 bytes static/images/logo-left.png | Bin 0 -> 19869 bytes static/images/logo-left2.png | Bin 0 -> 20261 bytes static/images/logo-small.png | Bin 0 -> 37432 bytes static/images/logo.png | Bin 0 -> 42298 bytes static/images/tt1.png | Bin 0 -> 20231 bytes static/images/wx.png | Bin 0 -> 20438 bytes static/images/后台编辑器05.jpg | Bin 0 -> 135991 bytes static/images/后台编辑器06.jpg | Bin 0 -> 193253 bytes static/images/后台编辑器061.jpg | Bin 0 -> 346886 bytes static/images/后台编辑器07.jpg | Bin 0 -> 101650 bytes static/images/后台编辑器071.jpg | Bin 0 -> 23553 bytes static/images/后台编辑器072.jpg | Bin 0 -> 24963 bytes static/images/后台编辑器073.jpg | Bin 0 -> 25529 bytes static/images/后台编辑器074.jpg | Bin 0 -> 23005 bytes static/images/后台编辑器075.jpg | Bin 0 -> 24113 bytes store/index.js | 133 + store/modules/$app.js | 60 + store/modules/$user.js | 50 + template.h5.html | 32 + uni.scss | 2 + .../fadada_verify_notify/index.js | 23 + .../fadada_verify_notify/package.json | 7 + .../cloudfunctions/router/config.js | 12 + .../cloudfunctions/router/dao/config.js | 7 + .../cloudfunctions/router/dao/index.js | 29 + .../router/dao/modules/userDao.js | 621 ++ .../cloudfunctions/router/index.js | 7 + .../cloudfunctions/router/middleware/index.js | 29 + .../router/middleware/modules/addAdminLog.js | 63 + .../middleware/modules/customFilter1.js | 22 + .../middleware/modules/customFilter2.js | 19 + .../middleware/modules/registerInitFilter.js | 46 + .../modules/returnUserInfoFilter.js | 82 + .../router/node_modules/.package-lock.json | 40 + .../node_modules/crypto-js/CONTRIBUTING.md | 28 + .../router/node_modules/crypto-js/LICENSE | 24 + .../router/node_modules/crypto-js/README.md | 275 + .../router/node_modules/crypto-js/aes.js | 234 + .../router/node_modules/crypto-js/blowfish.js | 471 ++ .../router/node_modules/crypto-js/bower.json | 39 + .../node_modules/crypto-js/cipher-core.js | 895 +++ .../router/node_modules/crypto-js/core.js | 807 ++ .../node_modules/crypto-js/crypto-js.js | 6657 +++++++++++++++++ .../crypto-js/docs/QuickStartGuide.wiki | 470 ++ .../node_modules/crypto-js/enc-base64.js | 136 + .../node_modules/crypto-js/enc-base64url.js | 148 + .../router/node_modules/crypto-js/enc-hex.js | 18 + .../node_modules/crypto-js/enc-latin1.js | 18 + .../node_modules/crypto-js/enc-utf16.js | 149 + .../router/node_modules/crypto-js/enc-utf8.js | 18 + .../router/node_modules/crypto-js/evpkdf.js | 134 + .../node_modules/crypto-js/format-hex.js | 66 + .../node_modules/crypto-js/format-openssl.js | 18 + .../router/node_modules/crypto-js/hmac-md5.js | 18 + .../node_modules/crypto-js/hmac-ripemd160.js | 18 + .../node_modules/crypto-js/hmac-sha1.js | 18 + .../node_modules/crypto-js/hmac-sha224.js | 18 + .../node_modules/crypto-js/hmac-sha256.js | 18 + .../node_modules/crypto-js/hmac-sha3.js | 18 + .../node_modules/crypto-js/hmac-sha384.js | 18 + .../node_modules/crypto-js/hmac-sha512.js | 18 + .../router/node_modules/crypto-js/hmac.js | 143 + .../router/node_modules/crypto-js/index.js | 18 + .../node_modules/crypto-js/lib-typedarrays.js | 76 + .../router/node_modules/crypto-js/md5.js | 268 + .../router/node_modules/crypto-js/mode-cfb.js | 80 + .../crypto-js/mode-ctr-gladman.js | 116 + .../router/node_modules/crypto-js/mode-ctr.js | 58 + .../router/node_modules/crypto-js/mode-ecb.js | 40 + .../router/node_modules/crypto-js/mode-ofb.js | 54 + .../node_modules/crypto-js/package.json | 70 + .../node_modules/crypto-js/pad-ansix923.js | 49 + .../node_modules/crypto-js/pad-iso10126.js | 44 + .../node_modules/crypto-js/pad-iso97971.js | 40 + .../node_modules/crypto-js/pad-nopadding.js | 30 + .../node_modules/crypto-js/pad-pkcs7.js | 18 + .../node_modules/crypto-js/pad-zeropadding.js | 47 + .../router/node_modules/crypto-js/pbkdf2.js | 145 + .../node_modules/crypto-js/rabbit-legacy.js | 190 + .../router/node_modules/crypto-js/rabbit.js | 192 + .../router/node_modules/crypto-js/rc4.js | 139 + .../node_modules/crypto-js/ripemd160.js | 267 + .../router/node_modules/crypto-js/sha1.js | 150 + .../router/node_modules/crypto-js/sha224.js | 80 + .../router/node_modules/crypto-js/sha256.js | 199 + .../router/node_modules/crypto-js/sha3.js | 326 + .../router/node_modules/crypto-js/sha384.js | 83 + .../router/node_modules/crypto-js/sha512.js | 326 + .../node_modules/crypto-js/tripledes.js | 779 ++ .../router/node_modules/crypto-js/x64-core.js | 304 + .../node_modules/uni-config-center/index.js | 1 + .../uni-config-center/package.json | 9 + .../uni-config-center/uni-id/config.json | 70 + .../alipay/alipayCertPublicKey_RSA2.crt | 3 + .../uni-pay/alipay/alipayRootCert.crt | 15 + .../uni-pay/alipay/appCertPublicKey.crt | 3 + .../alipay/【重要】这里放支付宝证书.md | 5 + .../uni-config-center/uni-pay/config.js | 128 + .../uni-config-center/uni-pay/wxpay/wxpay.p12 | 0 .../wxpay/【重要】这里放微信支付证书.md | 3 + .../uni-config-center/vk-unicloud/index.js | 141 + .../uni-config-center/【重要】请先看这里.md | 73 + .../router/node_modules/uni-id/LICENSE.md | 201 + .../router/node_modules/uni-id/index.js | 1 + .../node_modules/uni-config-center/index.js | 1 + .../uni-config-center/package.json | 9 + .../uni-config-center/uni-id/config.json | 70 + .../alipay/alipayCertPublicKey_RSA2.crt | 3 + .../uni-pay/alipay/alipayRootCert.crt | 15 + .../uni-pay/alipay/appCertPublicKey.crt | 3 + .../alipay/【重要】这里放支付宝证书.md | 5 + .../uni-config-center/uni-pay/config.js | 128 + .../uni-config-center/uni-pay/wxpay/wxpay.p12 | 0 .../wxpay/【重要】这里放微信支付证书.md | 3 + .../uni-config-center/vk-unicloud/index.js | 141 + .../uni-config-center/【重要】请先看这里.md | 73 + .../router/node_modules/uni-id/package.json | 16 + .../node_modules/vk-unicloud/LICENSE.md | 201 + .../router/node_modules/vk-unicloud/index.js | 1 + .../node_modules/vk-unicloud/package.json | 16 + .../cloudfunctions/router/package-lock.json | 30 + .../cloudfunctions/router/package.json | 29 + .../cloudfunctions/router/router.param.json | 14 + .../admin/enquiry/attributes/sys/add.js | 35 + .../admin/enquiry/attributes/sys/delete.js | 29 + .../admin/enquiry/attributes/sys/getList.js | 29 + .../admin/enquiry/attributes/sys/update.js | 37 + .../service/admin/enquiry/template/sys/add.js | 35 + .../admin/enquiry/template/sys/delete.js | 29 + .../admin/enquiry/template/sys/getList.js | 29 + .../admin/enquiry/template/sys/update.js | 37 + .../router/service/admin/kong/sys/add.js | 34 + .../router/service/admin/kong/sys/delete.js | 29 + .../router/service/admin/kong/sys/getList.js | 29 + .../router/service/admin/kong/sys/update.js | 40 + .../router/service/admin/select/kh/user.js | 96 + .../router/service/admin/setting_config.js | 83 + .../service/admin/site_config/sys/detail.js | 25 + .../service/admin/site_config/sys/update.js | 29 + .../service/admin/spot/category/sys/add.js | 66 + .../service/admin/spot/category/sys/delete.js | 29 + .../admin/spot/category/sys/getList.js | 29 + .../admin/spot/category/sys/getTree.js | 45 + .../service/admin/spot/category/sys/update.js | 67 + .../admin/spot/category/util/formRules.js | 59 + .../service/admin/spot/goods/sys/add.js | 38 + .../service/admin/spot/goods/sys/delete.js | 29 + .../service/admin/spot/goods/sys/getList.js | 29 + .../service/admin/spot/goods/sys/getTree.js | 45 + .../service/admin/spot/goods/sys/update.js | 35 + .../admin/spot/goods/util/formRules.js | 59 + .../app-upgrade-center/sys/addUpdate.js | 162 + .../system/app-upgrade-center/sys/delete.js | 34 + .../system/app-upgrade-center/sys/getList.js | 31 + .../app-upgrade-center/util/formRules.js | 83 + .../service/admin/system/app/sys/add.js | 100 + .../admin/system/app/sys/createPublishHtml.js | 22 + .../service/admin/system/app/sys/delete.js | 31 + .../service/admin/system/app/sys/getInfo.js | 26 + .../service/admin/system/app/sys/getList.js | 31 + .../service/admin/system/app/sys/update.js | 98 + .../app/util/createPublishHtml/index.js | 214 + .../createPublishHtml/lib/art-template.js | 2 + .../app/util/createPublishHtml/template.html | 241 + .../admin/system/app/util/formRules.js | 72 + .../service/admin/system/menu/sys/add.js | 87 + .../service/admin/system/menu/sys/adds.js | 74 + .../admin/system/menu/sys/bindPermission.js | 33 + .../service/admin/system/menu/sys/delete.js | 40 + .../service/admin/system/menu/sys/getAll.js | 31 + .../admin/system/menu/sys/getCascader.js | 57 + .../service/admin/system/menu/sys/update.js | 87 + .../admin/system/menu/sys/updateBase.js | 43 + .../admin/system/menu/util/formRules.js | 80 + .../admin/system/permission/sys/add.js | 96 + .../admin/system/permission/sys/delete.js | 39 + .../admin/system/permission/sys/getAll.js | 30 + .../admin/system/permission/sys/update.js | 97 + .../admin/system/permission/sys/updateBase.js | 40 + .../system/permission/sys/updateCategory.js | 34 + .../system/permission/sys/updateLevel.js | 34 + .../admin/system/permission/util/formRules.js | 46 + .../service/admin/system/role/sys/add.js | 58 + .../service/admin/system/role/sys/bindMenu.js | 49 + .../admin/system/role/sys/bindPermission.js | 40 + .../service/admin/system/role/sys/delete.js | 28 + .../service/admin/system/role/sys/getList.js | 63 + .../service/admin/system/role/sys/update.js | 50 + .../admin/system/role/sys/updateBase.js | 37 + .../admin/system/role/util/formRules.js | 43 + .../service/admin/system/user/sys/add.js | 93 + .../system/user/sys/batchUpdateAppLogin.js | 78 + .../system/user/sys/batchUpdateInviterUid.js | 42 + .../system/user/sys/batchUpdateStatus.js | 40 + .../service/admin/system/user/sys/bindRole.js | 29 + .../service/admin/system/user/sys/delete.js | 32 + .../service/admin/system/user/sys/getList.js | 54 + .../admin/system/user/sys/resetPassword.js | 27 + .../service/admin/system/user/sys/update.js | 102 + .../admin/system/user/util/formRules.js | 81 + .../admin/system_uni/admin-log/sys/getList.js | 32 + .../system_uni/components-dynamic/sys/add.js | 61 + .../components-dynamic/sys/delete.js | 32 + .../components-dynamic/sys/getList.js | 32 + .../components-dynamic/sys/update.js | 69 + .../admin/system_uni/global-data/sys/add.js | 59 + .../system_uni/global-data/sys/delete.js | 33 + .../system_uni/global-data/sys/getList.js | 32 + .../system_uni/global-data/sys/update.js | 52 + .../system_uni/global-data/util/formRules.js | 64 + .../system_uni/pay-orders/sys/afreshNotice.js | 117 + .../system_uni/pay-orders/sys/getList.js | 29 + .../uni-id-files/categories/kh/getList.js | 33 + .../uni-id-files/categories/sys/add.js | 51 + .../uni-id-files/categories/sys/delete.js | 30 + .../uni-id-files/categories/sys/update.js | 57 + .../uni-id-files/files/kh/delete.js | 60 + .../uni-id-files/files/kh/getList.js | 40 + .../uni-id-files/files/kh/update.js | 64 + .../system_uni/uni-id-log/sys/getList.js | 66 + .../router/service/admin/后台PC管理端.md | 17 + .../client/enquiry/attributes/pub/getList.js | 43 + .../client/enquiry/attributes/pub/getOne.js | 44 + .../service/client/enquiry/sheet/kh/add.js | 63 + .../client/enquiry/template/pub/getList.js | 42 + .../router/service/client/fadada.js | 196 + .../router/service/client/order/kh/test.js | 23 + .../router/service/client/order/pub/test.js | 23 + .../router/service/client/pub.test.js | 105 + .../client/spot/category/pub/getList.js | 27 + .../client/spot/category/pub/getTree.js | 42 + .../client/spot/goods/kh/addCooperate.js | 69 + .../service/client/spot/goods/kh/addUpdate.js | 46 + .../client/spot/goods/kh/getSelfOne.js | 28 + .../client/spot/goods/pub/getDetail.js | 75 + .../service/client/spot/goods/pub/getList.js | 72 + .../service/client/user/kh/setBusinessCard.js | 23 + .../router/service/client/user/kh/test.js | 23 + .../router/service/client/user/pub/test.js | 23 + .../service/client/小程序、h5、APP客户端.md | 11 + .../cloudfunctions/router/service/muban.js | 35 + .../router/service/muban_easy.js | 23 + .../router/service/muban_object.js | 67 + .../plugs/baidu/client/pub/getAccessToken.js | 21 + .../baidu/client/pub/ocr/business_license.js | 29 + .../plugs/baidu/client/pub/ocr/idcard.js | 29 + .../client/pub/getComponentsDynamicData.js | 37 + .../components_dynamic/client/pub/init.js | 138 + .../components_dynamic/client/pub/update.js | 29 + .../router/service/plugs/插件.md | 15 + .../template/db_api/pub/Promise.all.js | 54 + .../router/service/template/db_api/pub/add.js | 40 + .../service/template/db_api/pub/adds.js | 50 + .../router/service/template/db_api/pub/avg.js | 27 + .../service/template/db_api/pub/count.js | 33 + .../router/service/template/db_api/pub/del.js | 33 + .../service/template/db_api/pub/deleteById.js | 25 + .../service/template/db_api/pub/findById.js | 33 + .../template/db_api/pub/findByWhereJson.js | 38 + .../router/service/template/db_api/pub/geo.js | 33 + .../service/template/db_api/pub/getList.js | 73 + .../service/template/db_api/pub/groupCount.js | 38 + .../router/service/template/db_api/pub/max.js | 27 + .../router/service/template/db_api/pub/min.js | 27 + .../service/template/db_api/pub/sample.js | 27 + .../service/template/db_api/pub/select.js | 30 + .../service/template/db_api/pub/select2.js | 50 + .../service/template/db_api/pub/selects.js | 51 + .../template/db_api/pub/selects_geo.js | 47 + .../template/db_api/pub/selects_getOne.js | 48 + .../db_api/pub/selects_inviter_uid.js | 45 + .../template/db_api/pub/selects_mode_2.js | 43 + .../template/db_api/pub/selects_mode_3.js | 44 + .../router/service/template/db_api/pub/sum.js | 29 + .../service/template/db_api/pub/tree.js | 36 + .../service/template/db_api/pub/update.js | 30 + .../template/db_api/pub/updateAndReturn.js | 63 + .../service/template/db_api/pub/updateById.js | 29 + .../router/service/template/db_api/sys/add.js | 33 + .../service/template/db_api/sys/delete.js | 30 + .../service/template/db_api/sys/getList.js | 30 + .../service/template/db_api/sys/update.js | 39 + .../openapi/alipay/pub/code2Session.js | 30 + .../openapi/alipay/pub/getMiniCode.js | 24 + .../openapi/douyin/pub/code2Session.js | 34 + .../openapi/douyin/pub/getMiniCode.js | 46 + .../openapi/douyin/pub/imgSecCheck.js | 38 + .../openapi/douyin/pub/msgSecCheck.js | 36 + .../template/openapi/qq/pub/code2Session.js | 32 + .../template/openapi/qq/pub/imgSecCheck.js | 39 + .../template/openapi/qq/pub/msgSecCheck.js | 36 + .../openapi/weixin/pub/getTemplateList.js | 27 + .../openapi/weixin/pub/imgSecCheck.js | 39 + .../openapi/weixin/pub/msgSecCheck.js | 48 + .../openapi/weixin/pub/sendMessage.js | 45 + .../openapi/weixin/pub/sendTemplateMessage.js | 59 + .../openapi/weixin/pub/sendUniformMessage.js | 59 + .../service/template/test/pub/addition.js | 32 + .../template/test/pub/findGoodsInfo.js | 202 + .../template/test/pub/temporaryCache.js | 36 + .../router/service/template/云函数示例模板.md | 11 + .../router/service/user/kh/acceptInvite.js | 25 + .../router/service/user/kh/addUploadRecord.js | 75 + .../router/service/user/kh/bindAlipay.js | 24 + .../router/service/user/kh/bindEmail.js | 23 + .../router/service/user/kh/bindMobile.js | 23 + .../router/service/user/kh/bindNewEmail.js | 72 + .../router/service/user/kh/bindNewMobile.js | 70 + .../router/service/user/kh/bindQQ.js | 23 + .../router/service/user/kh/bindWeixin.js | 24 + .../service/user/kh/getAlipayMiniCode.js | 25 + .../router/service/user/kh/getInvitedUser.js | 34 + .../router/service/user/kh/getMenu.js | 30 + .../router/service/user/kh/getMyUserInfo.js | 16 + .../router/service/user/kh/getQQMiniCode.js | 45 + .../service/user/kh/getWeixinMPqrcode.js | 57 + .../service/user/kh/getWeixinMPscheme.js | 41 + .../router/service/user/kh/getWeixinMPurl.js | 38 + .../router/service/user/kh/resetPwd.js | 24 + .../router/service/user/kh/setAvatar.js | 37 + .../service/user/kh/setCertification.js | 60 + .../service/user/kh/setUserInviteCode.js | 32 + .../router/service/user/kh/unbindAlipay.js | 24 + .../router/service/user/kh/unbindEmail.js | 25 + .../router/service/user/kh/unbindMobile.js | 25 + .../router/service/user/kh/unbindQQ.js | 23 + .../router/service/user/kh/unbindWeixin.js | 24 + .../router/service/user/kh/updatePwd.js | 26 + .../router/service/user/kh/updateUser.js | 32 + .../router/service/user/pub/checkToken.js | 27 + .../router/service/user/pub/checkVersion.js | 152 + .../service/user/pub/code2SessionAlipay.js | 37 + .../service/user/pub/code2SessionWeixin.js | 41 + .../router/service/user/pub/getPhoneNumber.js | 23 + .../user/pub/getUserInfoByInviteCode.js | 36 + .../router/service/user/pub/login.js | 55 + .../router/service/user/pub/loginByAlipay.js | 55 + .../router/service/user/pub/loginByEmail.js | 56 + .../router/service/user/pub/loginByQQ.js | 58 + .../router/service/user/pub/loginBySms.js | 95 + .../service/user/pub/loginByUniverify.js | 74 + .../router/service/user/pub/loginByWeixin.js | 58 + .../user/pub/loginByWeixinPhoneNumber.js | 99 + .../router/service/user/pub/logout.js | 24 + .../router/service/user/pub/register.js | 61 + .../service/user/pub/resetPasswordByEmail.js | 52 + .../service/user/pub/resetPasswordByMobile.js | 52 + .../router/service/user/pub/sendEmailCode.js | 112 + .../router/service/user/pub/sendSmsCode.js | 86 + .../router/service/user/sys/encryptPwd.js | 28 + .../router/service/user/sys/setVerifyCode.js | 27 + .../router/service/user/util/login_log.js | 72 + .../router/service/user/统一用户中心.md | 12 + .../router/service/逻辑层目录说明.md | 47 + .../cloudfunctions/router/util/pubFunction.js | 95 + .../cloudfunctions/router/util/urlrewrite.js | 15 + uniCloud-aliyun/database/JQL查询.jql | 12 + uniCloud-aliyun/database/db_init.json | 939 +++ uni_modules/uni-config-center/changelog.md | 6 + uni_modules/uni-config-center/package.json | 81 + uni_modules/uni-config-center/readme.md | 93 + .../common/uni-config-center/index.js | 1 + .../common/uni-config-center/package.json | 9 + .../uni-config-center/uni-id/config.json | 70 + .../alipay/alipayCertPublicKey_RSA2.crt | 3 + .../uni-pay/alipay/alipayRootCert.crt | 15 + .../uni-pay/alipay/appCertPublicKey.crt | 3 + .../alipay/【重要】这里放支付宝证书.md | 5 + .../uni-config-center/uni-pay/config.js | 128 + .../uni-config-center/uni-pay/wxpay/wxpay.p12 | 0 .../wxpay/【重要】这里放微信支付证书.md | 3 + .../uni-config-center/vk-unicloud/index.js | 141 + .../uni-config-center/【重要】请先看这里.md | 73 + uni_modules/uni-id/changelog.md | 111 + uni_modules/uni-id/package.json | 85 + uni_modules/uni-id/readme.md | 33 + .../cloudfunctions/common/uni-id/LICENSE.md | 201 + .../cloudfunctions/common/uni-id/index.js | 1 + .../node_modules/uni-config-center/index.js | 1 + .../uni-config-center/package.json | 9 + .../uni-config-center/uni-id/config.json | 70 + .../alipay/alipayCertPublicKey_RSA2.crt | 3 + .../uni-pay/alipay/alipayRootCert.crt | 15 + .../uni-pay/alipay/appCertPublicKey.crt | 3 + .../alipay/【重要】这里放支付宝证书.md | 5 + .../uni-config-center/uni-pay/config.js | 128 + .../uni-config-center/uni-pay/wxpay/wxpay.p12 | 0 .../wxpay/【重要】这里放微信支付证书.md | 3 + .../uni-config-center/vk-unicloud/index.js | 141 + .../uni-config-center/【重要】请先看这里.md | 73 + .../cloudfunctions/common/uni-id/package.json | 16 + uni_modules/vk-unicloud/changelog.md | 1248 +++ .../vk-data-verification-code.vue | 320 + uni_modules/vk-unicloud/index.js | 7 + uni_modules/vk-unicloud/package.json | 86 + uni_modules/vk-unicloud/readme.md | 572 ++ .../common/vk-unicloud/LICENSE.md | 201 + .../common/vk-unicloud/index.js | 1 + .../common/vk-unicloud/package.json | 16 + .../vk_modules/vk-unicloud-page/index.js | 190 + .../libs/function/aliyunOSSUtil.js | 274 + .../libs/function/debounce.js | 34 + .../libs/function/deepClone.js | 23 + .../libs/function/deepMerge.js | 30 + .../vk-unicloud-page/libs/function/index.js | 2430 ++++++ .../vk-unicloud-page/libs/function/modal.js | 326 + .../libs/function/permission.js | 33 + .../libs/function/queryParams.js | 60 + .../libs/function/setClipboardData.js | 51 + .../libs/function/throttle.js | 37 + .../libs/function/timeUtil.js | 642 ++ .../libs/function/treeUtil.js | 93 + .../libs/function/updateManager.js | 61 + .../libs/function/vk.filters.js | 63 + .../vk-unicloud-page/libs/function/vk.h5.js | 60 + .../libs/function/vk.importObject.js | 59 + .../libs/function/vk.localStorage.js | 131 + .../libs/function/vk.navigate.js | 462 ++ .../libs/function/vk.request.js | 434 ++ .../libs/function/vk.sessionStorage.js | 146 + .../libs/function/weixin-js-sdk.js | 890 +++ .../libs/install/console.log.js | 18 + .../vk-unicloud-page/libs/mixin/mixin.js | 40 + .../libs/openapi/baidu/index.js | 170 + .../vk-unicloud-page/libs/openapi/index.js | 14 + .../vk-unicloud-page/libs/store/libs/error.js | 25 + .../libs/store/mixin/mixin.js | 67 + .../vk-unicloud-callFunctionUtil.js | 1040 +++ .../vk-unicloud/vk-unicloud-user-center.js | 1068 +++ uni_modules/vk-uview-ui/changelog.md | 150 + .../u-action-sheet/u-action-sheet.vue | 246 + .../components/u-alert-tips/u-alert-tips.vue | 260 + .../u-avatar-cropper/u-avatar-cropper.vue | 290 + .../components/u-avatar-cropper/weCropper.js | 1256 ++++ .../components/u-avatar/u-avatar.vue | 270 + .../components/u-back-top/u-back-top.vue | 153 + .../components/u-badge/u-badge.vue | 216 + .../components/u-button/u-button.vue | 661 ++ .../components/u-calendar/u-calendar.vue | 666 ++ .../u-car-keyboard/u-car-keyboard.vue | 267 + .../vk-uview-ui/components/u-card/u-card.vue | 300 + .../components/u-cell-group/u-cell-group.vue | 70 + .../components/u-cell-item/u-cell-item.vue | 317 + .../u-checkbox-group/u-checkbox-group.vue | 178 + .../components/u-checkbox/u-checkbox.vue | 336 + .../u-circle-progress/u-circle-progress.vue | 227 + .../vk-uview-ui/components/u-col/u-col.vue | 157 + .../u-collapse-item/u-collapse-item.vue | 206 + .../components/u-collapse/u-collapse.vue | 100 + .../u-column-notice/u-column-notice.vue | 238 + .../components/u-count-down/u-count-down.vue | 175 + .../components/u-count-down/utils.js | 62 + .../components/u-count-to/u-count-to.vue | 266 + .../components/u-divider/u-divider.vue | 159 + .../u-dropdown-item/u-dropdown-item.vue | 166 + .../components/u-dropdown/u-dropdown.vue | 299 + .../components/u-empty/u-empty.vue | 193 + .../components/u-field/u-field.vue | 402 + .../components/u-form-item/u-form-item.vue | 509 ++ .../vk-uview-ui/components/u-form/u-form.vue | 148 + .../u-full-screen/u-full-screen.vue | 52 + .../vk-uview-ui/components/u-gap/u-gap.vue | 54 + .../components/u-grid-item/u-grid-item.vue | 127 + .../vk-uview-ui/components/u-grid/u-grid.vue | 109 + .../vk-uview-ui/components/u-icon/u-icon.vue | 369 + .../components/u-image/u-image.vue | 283 + .../u-index-anchor/u-index-anchor.vue | 89 + .../components/u-index-list/u-index-list.vue | 315 + .../components/u-input/u-input.vue | 465 ++ .../components/u-keyboard/u-keyboard.vue | 285 + .../components/u-lazy-load/u-lazy-load.vue | 254 + .../u-line-progress/u-line-progress.vue | 147 + .../vk-uview-ui/components/u-line/u-line.vue | 84 + .../vk-uview-ui/components/u-link/u-link.vue | 89 + .../u-loading-page/u-loading-page.vue | 25 + .../components/u-loading/u-loading.vue | 108 + .../components/u-loadmore/u-loadmore.vue | 204 + .../vk-uview-ui/components/u-mask/u-mask.vue | 137 + .../u-message-input/u-message-input.vue | 327 + .../components/u-modal/u-modal.vue | 339 + .../components/u-navbar/u-navbar.vue | 315 + .../components/u-no-network/u-no-network.vue | 233 + .../components/u-notice-bar/u-notice-bar.vue | 273 + .../components/u-number-box/u-number-box.vue | 476 ++ .../u-number-keyboard/u-number-keyboard.vue | 170 + .../components/u-parse/u-parse.vue | 673 ++ .../components/u-picker/u-picker.vue | 932 +++ .../components/u-popup/u-popup.vue | 485 ++ .../u-radio-group/u-radio-group.vue | 177 + .../components/u-radio/u-radio.vue | 277 + .../vk-uview-ui/components/u-rate/u-rate.vue | 293 + .../components/u-read-more/u-read-more.vue | 191 + .../components/u-row-notice/u-row-notice.vue | 270 + .../vk-uview-ui/components/u-row/u-row.vue | 85 + .../components/u-search/u-search.vue | 357 + .../components/u-section/u-section.vue | 155 + .../components/u-select/u-select.vue | 458 ++ .../components/u-skeleton/u-skeleton.vue | 199 + .../components/u-slider/u-slider.vue | 290 + .../components/u-steps/u-steps.vue | 200 + .../components/u-sticky/u-sticky.vue | 166 + .../components/u-subsection/u-subsection.vue | 402 + .../u-swipe-action/u-swipe-action.vue | 256 + .../components/u-swiper-indicator.vue | 135 + .../u-swiper-plus/u-swiper-plus.vue | 529 ++ .../components/u-swiper/u-swiper.vue | 341 + .../components/u-switch/u-switch.vue | 191 + .../components/u-tabbar/u-tabbar.vue | 375 + .../components/u-table/u-table.vue | 85 + .../u-tabs-swiper/u-tabs-swiper.vue | 489 ++ .../vk-uview-ui/components/u-tabs/u-tabs.vue | 399 + .../vk-uview-ui/components/u-tag/u-tag.vue | 295 + .../vk-uview-ui/components/u-td/u-td.vue | 66 + .../vk-uview-ui/components/u-th/u-th.vue | 62 + .../u-time-line-item/u-time-line-item.vue | 83 + .../components/u-time-line/u-time-line.vue | 43 + .../components/u-toast/u-toast.vue | 220 + .../components/u-top-tips/u-top-tips.vue | 121 + .../vk-uview-ui/components/u-tr/u-tr.vue | 25 + .../components/u-trees/CssHandler.js | 100 + .../components/u-trees/MpHtmlParser.js | 581 ++ .../vk-uview-ui/components/u-trees/config.js | 80 + .../components/u-trees/u-trees.vue | 534 ++ .../components/u-upload/u-upload.vue | 728 ++ .../u-verification-code.vue | 175 + .../components/u-waterfall/u-waterfall.vue | 199 + .../components/vk-uview-ui/vk-uview-ui.vue | 15 + uni_modules/vk-uview-ui/iconfont.css | 910 +++ uni_modules/vk-uview-ui/index.js | 149 + uni_modules/vk-uview-ui/index.scss | 23 + .../vk-uview-ui/libs/address/areas.json | 1 + .../vk-uview-ui/libs/address/citys.json | 1 + .../vk-uview-ui/libs/address/provinces.json | 1 + uni_modules/vk-uview-ui/libs/config/config.js | 15 + uni_modules/vk-uview-ui/libs/config/zIndex.js | 20 + uni_modules/vk-uview-ui/libs/css/color.scss | 155 + uni_modules/vk-uview-ui/libs/css/common.scss | 176 + .../libs/css/style.components.scss | 7 + .../vk-uview-ui/libs/css/style.h5.scss | 8 + .../vk-uview-ui/libs/css/style.mp.scss | 72 + .../vk-uview-ui/libs/css/style.nvue.scss | 3 + .../vk-uview-ui/libs/css/style.vue.scss | 175 + .../vk-uview-ui/libs/function/$parent.js | 18 + .../vk-uview-ui/libs/function/addStyle.js | 42 + .../vk-uview-ui/libs/function/addUnit.js | 8 + uni_modules/vk-uview-ui/libs/function/bem.js | 4 + .../vk-uview-ui/libs/function/color.js | 37 + .../libs/function/colorGradient.js | 134 + .../vk-uview-ui/libs/function/debounce.js | 29 + .../vk-uview-ui/libs/function/deepClone.js | 23 + .../vk-uview-ui/libs/function/deepMerge.js | 30 + .../vk-uview-ui/libs/function/getParent.js | 47 + uni_modules/vk-uview-ui/libs/function/guid.js | 41 + uni_modules/vk-uview-ui/libs/function/md5.js | 385 + .../vk-uview-ui/libs/function/queryParams.js | 58 + .../vk-uview-ui/libs/function/random.js | 10 + .../vk-uview-ui/libs/function/randomArray.js | 7 + .../vk-uview-ui/libs/function/route.js | 122 + uni_modules/vk-uview-ui/libs/function/sys.js | 9 + uni_modules/vk-uview-ui/libs/function/test.js | 287 + .../vk-uview-ui/libs/function/throttle.js | 34 + .../vk-uview-ui/libs/function/timeFormat.js | 51 + .../vk-uview-ui/libs/function/timeFrom.js | 47 + .../vk-uview-ui/libs/function/toast.js | 9 + uni_modules/vk-uview-ui/libs/function/trim.js | 15 + .../vk-uview-ui/libs/function/type2icon.js | 35 + uni_modules/vk-uview-ui/libs/mixin/mixin.js | 86 + uni_modules/vk-uview-ui/libs/mixin/mpShare.js | 18 + uni_modules/vk-uview-ui/libs/request/index.js | 169 + uni_modules/vk-uview-ui/libs/store/index.js | 19 + .../vk-uview-ui/libs/util/async-validator.js | 1356 ++++ uni_modules/vk-uview-ui/libs/util/emitter.js | 64 + uni_modules/vk-uview-ui/package.json | 82 + uni_modules/vk-uview-ui/readme.md | 125 + uni_modules/vk-uview-ui/theme.scss | 38 + 643 files changed, 84924 insertions(+) create mode 100644 .gitignore create mode 100644 App.vue create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 app.config.js create mode 100644 changelog.md create mode 100644 changelog.new.md create mode 100644 common/css/app.scss create mode 100644 common/css/common.css create mode 100644 common/css/uni.scss create mode 100644 common/function/myPubFunction.js create mode 100644 components/category-bar/category-bar.vue create mode 100644 components/common-footer/common-footer.vue create mode 100644 components/common-header/common-header.vue create mode 100644 components/custom-form-section/custom-form-section.vue create mode 100644 components/page-nav/page-nav.vue create mode 100644 components/right-bar/right-bar.vue create mode 100644 components/top-bar/top-bar.vue create mode 100644 components/vk-data-input-editor/vk-data-input-editor.vue create mode 100644 index.html create mode 100644 main.js create mode 100644 manifest.json create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 pages.json create mode 100644 pages/auth/login/login.vue create mode 100644 pages/auth/register/register.vue create mode 100644 pages/company/company.vue create mode 100644 pages/enquiry/components/template.vue create mode 100644 pages/enquiry/list.vue create mode 100644 pages/enquiry/release.vue create mode 100644 pages/error/404/404.vue create mode 100644 pages/index/index.vue create mode 100644 pages/spot/goods/detail.vue create mode 100644 pages/spot/goods/goods.vue create mode 100644 pages/spot/release/release.vue create mode 100644 pages/user/components/business-card.vue create mode 100644 pages/user/components/personal.vue create mode 100644 pages/user/user.vue create mode 100644 static/images/80705c8b12d05d0ff67a2758749ef09c.jpg create mode 100644 static/images/cc-top.png create mode 100644 static/images/cl1.png create mode 100644 static/images/cl3.png create mode 100644 static/images/cl4.png create mode 100644 static/images/cl5.png create mode 100644 static/images/cl6.png create mode 100644 static/images/dowm.png create mode 100644 static/images/dowm2.png create mode 100644 static/images/home1.png create mode 100644 static/images/home2.png create mode 100644 static/images/home3.png create mode 100644 static/images/icon1.png create mode 100644 static/images/iconsmall.png create mode 100644 static/images/lg1.png create mode 100644 static/images/lg10.png create mode 100644 static/images/lg11.png create mode 100644 static/images/lg12.png create mode 100644 static/images/lg13.png create mode 100644 static/images/lg15.png create mode 100644 static/images/lg2.png create mode 100644 static/images/lg3.png create mode 100644 static/images/lg4.png create mode 100644 static/images/lg5.png create mode 100644 static/images/lg6.png create mode 100644 static/images/lg7.png create mode 100644 static/images/lg8.png create mode 100644 static/images/lg9.png create mode 100644 static/images/login-bg.jpg create mode 100644 static/images/logo-left.png create mode 100644 static/images/logo-left2.png create mode 100644 static/images/logo-small.png create mode 100644 static/images/logo.png create mode 100644 static/images/tt1.png create mode 100644 static/images/wx.png create mode 100644 static/images/后台编辑器05.jpg create mode 100644 static/images/后台编辑器06.jpg create mode 100644 static/images/后台编辑器061.jpg create mode 100644 static/images/后台编辑器07.jpg create mode 100644 static/images/后台编辑器071.jpg create mode 100644 static/images/后台编辑器072.jpg create mode 100644 static/images/后台编辑器073.jpg create mode 100644 static/images/后台编辑器074.jpg create mode 100644 static/images/后台编辑器075.jpg create mode 100644 store/index.js create mode 100644 store/modules/$app.js create mode 100644 store/modules/$user.js create mode 100644 template.h5.html create mode 100644 uni.scss create mode 100644 uniCloud-aliyun/cloudfunctions/fadada_verify_notify/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/fadada_verify_notify/package.json create mode 100644 uniCloud-aliyun/cloudfunctions/router/config.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/dao/config.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/dao/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/dao/modules/userDao.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/middleware/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/middleware/modules/addAdminLog.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/middleware/modules/customFilter1.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/middleware/modules/customFilter2.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/middleware/modules/registerInitFilter.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/middleware/modules/returnUserInfoFilter.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/.package-lock.json create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/CONTRIBUTING.md create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/LICENSE create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/README.md create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/aes.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/blowfish.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/bower.json create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/cipher-core.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/core.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/crypto-js.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/docs/QuickStartGuide.wiki create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-base64.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-base64url.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-hex.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-latin1.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-utf16.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-utf8.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/evpkdf.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/format-hex.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/format-openssl.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-md5.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-ripemd160.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha1.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha224.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha256.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha3.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha384.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha512.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/lib-typedarrays.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/md5.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-cfb.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-ctr-gladman.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-ctr.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-ecb.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-ofb.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/package.json create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-ansix923.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-iso10126.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-iso97971.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-nopadding.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-pkcs7.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-zeropadding.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pbkdf2.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/rabbit-legacy.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/rabbit.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/rc4.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/ripemd160.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha1.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha224.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha256.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha3.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha384.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha512.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/tripledes.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/x64-core.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-config-center/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-config-center/package.json create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-config-center/uni-id/config.json create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-config-center/uni-pay/alipay/alipayCertPublicKey_RSA2.crt create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-config-center/uni-pay/alipay/alipayRootCert.crt create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-config-center/uni-pay/alipay/appCertPublicKey.crt create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-config-center/uni-pay/alipay/【重要】这里放支付宝证书.md create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-config-center/uni-pay/config.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-config-center/uni-pay/wxpay/wxpay.p12 create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-config-center/uni-pay/wxpay/【重要】这里放微信支付证书.md create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-config-center/vk-unicloud/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-config-center/【重要】请先看这里.md create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/LICENSE.md create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/node_modules/uni-config-center/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/node_modules/uni-config-center/package.json create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/node_modules/uni-config-center/uni-id/config.json create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/node_modules/uni-config-center/uni-pay/alipay/alipayCertPublicKey_RSA2.crt create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/node_modules/uni-config-center/uni-pay/alipay/alipayRootCert.crt create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/node_modules/uni-config-center/uni-pay/alipay/appCertPublicKey.crt create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/node_modules/uni-config-center/uni-pay/alipay/【重要】这里放支付宝证书.md create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/node_modules/uni-config-center/uni-pay/config.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/node_modules/uni-config-center/uni-pay/wxpay/wxpay.p12 create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/node_modules/uni-config-center/uni-pay/wxpay/【重要】这里放微信支付证书.md create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/node_modules/uni-config-center/vk-unicloud/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/node_modules/uni-config-center/【重要】请先看这里.md create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/package.json create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/vk-unicloud/LICENSE.md create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/vk-unicloud/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/node_modules/vk-unicloud/package.json create mode 100644 uniCloud-aliyun/cloudfunctions/router/package-lock.json create mode 100644 uniCloud-aliyun/cloudfunctions/router/package.json create mode 100644 uniCloud-aliyun/cloudfunctions/router/router.param.json create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/attributes/sys/add.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/attributes/sys/delete.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/attributes/sys/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/attributes/sys/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/template/sys/add.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/template/sys/delete.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/template/sys/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/template/sys/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/add.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/delete.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/select/kh/user.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/setting_config.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/site_config/sys/detail.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/site_config/sys/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/add.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/delete.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/getTree.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/util/formRules.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/add.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/delete.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/getTree.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/util/formRules.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/addUpdate.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/delete.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/util/formRules.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/add.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/createPublishHtml.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/delete.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/getInfo.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/lib/art-template.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/template.html create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/formRules.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/add.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/adds.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/bindPermission.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/delete.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/getAll.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/getCascader.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/updateBase.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/util/formRules.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/add.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/delete.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/getAll.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateBase.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateCategory.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateLevel.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/util/formRules.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/add.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/bindMenu.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/bindPermission.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/delete.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/updateBase.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/util/formRules.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/add.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/batchUpdateAppLogin.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/batchUpdateInviterUid.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/batchUpdateStatus.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/bindRole.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/delete.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/resetPassword.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/util/formRules.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/admin-log/sys/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/add.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/delete.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/add.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/delete.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/util/formRules.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/pay-orders/sys/afreshNotice.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/pay-orders/sys/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/kh/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/add.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/delete.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/delete.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-log/sys/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/admin/后台PC管理端.md create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/enquiry/attributes/pub/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/enquiry/attributes/pub/getOne.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/enquiry/sheet/kh/add.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/enquiry/template/pub/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/fadada.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/order/kh/test.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/order/pub/test.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/pub.test.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/spot/category/pub/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/spot/category/pub/getTree.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/kh/addCooperate.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/kh/addUpdate.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/kh/getSelfOne.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/pub/getDetail.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/pub/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/user/kh/setBusinessCard.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/user/kh/test.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/user/pub/test.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/client/小程序、h5、APP客户端.md create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/muban.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/muban_easy.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/muban_object.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/getAccessToken.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/ocr/business_license.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/ocr/idcard.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/getComponentsDynamicData.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/init.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/plugs/插件.md create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/Promise.all.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/add.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/adds.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/avg.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/count.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/del.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/deleteById.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/findById.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/findByWhereJson.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/geo.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/groupCount.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/max.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/min.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/sample.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/select.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/select2.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_geo.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_getOne.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_inviter_uid.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_mode_2.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_mode_3.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/sum.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/tree.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/updateAndReturn.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/updateById.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/add.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/delete.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/getList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/update.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/openapi/alipay/pub/code2Session.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/openapi/alipay/pub/getMiniCode.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/openapi/douyin/pub/code2Session.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/openapi/douyin/pub/getMiniCode.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/openapi/douyin/pub/imgSecCheck.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/openapi/douyin/pub/msgSecCheck.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/code2Session.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/imgSecCheck.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/msgSecCheck.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/getTemplateList.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/imgSecCheck.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/msgSecCheck.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendMessage.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendTemplateMessage.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendUniformMessage.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/addition.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/findGoodsInfo.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/temporaryCache.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/template/云函数示例模板.md create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/acceptInvite.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/addUploadRecord.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindAlipay.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindEmail.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindMobile.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindNewEmail.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindNewMobile.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindQQ.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindWeixin.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/getAlipayMiniCode.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/getInvitedUser.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/getMenu.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/getMyUserInfo.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/getQQMiniCode.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPqrcode.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPscheme.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPurl.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/resetPwd.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/setAvatar.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/setCertification.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/setUserInviteCode.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindAlipay.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindEmail.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindMobile.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindQQ.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindWeixin.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/updatePwd.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/kh/updateUser.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/checkToken.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/checkVersion.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/code2SessionAlipay.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/code2SessionWeixin.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/getPhoneNumber.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/getUserInfoByInviteCode.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/login.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByAlipay.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByEmail.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByQQ.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginBySms.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByUniverify.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByWeixin.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByWeixinPhoneNumber.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/logout.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/register.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/resetPasswordByEmail.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/resetPasswordByMobile.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/sendEmailCode.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/pub/sendSmsCode.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/sys/encryptPwd.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/sys/setVerifyCode.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/util/login_log.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/user/统一用户中心.md create mode 100644 uniCloud-aliyun/cloudfunctions/router/service/逻辑层目录说明.md create mode 100644 uniCloud-aliyun/cloudfunctions/router/util/pubFunction.js create mode 100644 uniCloud-aliyun/cloudfunctions/router/util/urlrewrite.js create mode 100644 uniCloud-aliyun/database/JQL查询.jql create mode 100644 uniCloud-aliyun/database/db_init.json create mode 100644 uni_modules/uni-config-center/changelog.md create mode 100644 uni_modules/uni-config-center/package.json create mode 100644 uni_modules/uni-config-center/readme.md create mode 100644 uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js create mode 100644 uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/package.json create mode 100644 uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json create mode 100644 uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-pay/alipay/alipayCertPublicKey_RSA2.crt create mode 100644 uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-pay/alipay/alipayRootCert.crt create mode 100644 uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-pay/alipay/appCertPublicKey.crt create mode 100644 uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-pay/alipay/【重要】这里放支付宝证书.md create mode 100644 uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-pay/config.js create mode 100644 uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-pay/wxpay/wxpay.p12 create mode 100644 uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-pay/wxpay/【重要】这里放微信支付证书.md create mode 100644 uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/vk-unicloud/index.js create mode 100644 uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/【重要】请先看这里.md create mode 100644 uni_modules/uni-id/changelog.md create mode 100644 uni_modules/uni-id/package.json create mode 100644 uni_modules/uni-id/readme.md create mode 100644 uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/LICENSE.md create mode 100644 uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/index.js create mode 100644 uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/uni-config-center/index.js create mode 100644 uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/uni-config-center/package.json create mode 100644 uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/uni-config-center/uni-id/config.json create mode 100644 uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/uni-config-center/uni-pay/alipay/alipayCertPublicKey_RSA2.crt create mode 100644 uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/uni-config-center/uni-pay/alipay/alipayRootCert.crt create mode 100644 uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/uni-config-center/uni-pay/alipay/appCertPublicKey.crt create mode 100644 uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/uni-config-center/uni-pay/alipay/【重要】这里放支付宝证书.md create mode 100644 uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/uni-config-center/uni-pay/config.js create mode 100644 uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/uni-config-center/uni-pay/wxpay/wxpay.p12 create mode 100644 uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/uni-config-center/uni-pay/wxpay/【重要】这里放微信支付证书.md create mode 100644 uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/uni-config-center/vk-unicloud/index.js create mode 100644 uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/uni-config-center/【重要】请先看这里.md create mode 100644 uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package.json create mode 100644 uni_modules/vk-unicloud/changelog.md create mode 100644 uni_modules/vk-unicloud/components/vk-data-verification-code/vk-data-verification-code.vue create mode 100644 uni_modules/vk-unicloud/index.js create mode 100644 uni_modules/vk-unicloud/package.json create mode 100644 uni_modules/vk-unicloud/readme.md create mode 100644 uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/LICENSE.md create mode 100644 uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/index.js create mode 100644 uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/package.json create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/index.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/aliyunOSSUtil.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/debounce.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/deepClone.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/deepMerge.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/index.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/modal.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/permission.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/queryParams.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/setClipboardData.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/throttle.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/timeUtil.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/treeUtil.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/updateManager.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.filters.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.h5.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.importObject.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.localStorage.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.navigate.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.request.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.sessionStorage.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/weixin-js-sdk.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/install/console.log.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/mixin/mixin.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/openapi/baidu/index.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/openapi/index.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/store/libs/error.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/store/mixin/mixin.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/vk-unicloud/vk-unicloud-callFunctionUtil.js create mode 100644 uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/vk-unicloud/vk-unicloud-user-center.js create mode 100644 uni_modules/vk-uview-ui/changelog.md create mode 100644 uni_modules/vk-uview-ui/components/u-action-sheet/u-action-sheet.vue create mode 100644 uni_modules/vk-uview-ui/components/u-alert-tips/u-alert-tips.vue create mode 100644 uni_modules/vk-uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue create mode 100644 uni_modules/vk-uview-ui/components/u-avatar-cropper/weCropper.js create mode 100644 uni_modules/vk-uview-ui/components/u-avatar/u-avatar.vue create mode 100644 uni_modules/vk-uview-ui/components/u-back-top/u-back-top.vue create mode 100644 uni_modules/vk-uview-ui/components/u-badge/u-badge.vue create mode 100644 uni_modules/vk-uview-ui/components/u-button/u-button.vue create mode 100644 uni_modules/vk-uview-ui/components/u-calendar/u-calendar.vue create mode 100644 uni_modules/vk-uview-ui/components/u-car-keyboard/u-car-keyboard.vue create mode 100644 uni_modules/vk-uview-ui/components/u-card/u-card.vue create mode 100644 uni_modules/vk-uview-ui/components/u-cell-group/u-cell-group.vue create mode 100644 uni_modules/vk-uview-ui/components/u-cell-item/u-cell-item.vue create mode 100644 uni_modules/vk-uview-ui/components/u-checkbox-group/u-checkbox-group.vue create mode 100644 uni_modules/vk-uview-ui/components/u-checkbox/u-checkbox.vue create mode 100644 uni_modules/vk-uview-ui/components/u-circle-progress/u-circle-progress.vue create mode 100644 uni_modules/vk-uview-ui/components/u-col/u-col.vue create mode 100644 uni_modules/vk-uview-ui/components/u-collapse-item/u-collapse-item.vue create mode 100644 uni_modules/vk-uview-ui/components/u-collapse/u-collapse.vue create mode 100644 uni_modules/vk-uview-ui/components/u-column-notice/u-column-notice.vue create mode 100644 uni_modules/vk-uview-ui/components/u-count-down/u-count-down.vue create mode 100644 uni_modules/vk-uview-ui/components/u-count-down/utils.js create mode 100644 uni_modules/vk-uview-ui/components/u-count-to/u-count-to.vue create mode 100644 uni_modules/vk-uview-ui/components/u-divider/u-divider.vue create mode 100644 uni_modules/vk-uview-ui/components/u-dropdown-item/u-dropdown-item.vue create mode 100644 uni_modules/vk-uview-ui/components/u-dropdown/u-dropdown.vue create mode 100644 uni_modules/vk-uview-ui/components/u-empty/u-empty.vue create mode 100644 uni_modules/vk-uview-ui/components/u-field/u-field.vue create mode 100644 uni_modules/vk-uview-ui/components/u-form-item/u-form-item.vue create mode 100644 uni_modules/vk-uview-ui/components/u-form/u-form.vue create mode 100644 uni_modules/vk-uview-ui/components/u-full-screen/u-full-screen.vue create mode 100644 uni_modules/vk-uview-ui/components/u-gap/u-gap.vue create mode 100644 uni_modules/vk-uview-ui/components/u-grid-item/u-grid-item.vue create mode 100644 uni_modules/vk-uview-ui/components/u-grid/u-grid.vue create mode 100644 uni_modules/vk-uview-ui/components/u-icon/u-icon.vue create mode 100644 uni_modules/vk-uview-ui/components/u-image/u-image.vue create mode 100644 uni_modules/vk-uview-ui/components/u-index-anchor/u-index-anchor.vue create mode 100644 uni_modules/vk-uview-ui/components/u-index-list/u-index-list.vue create mode 100644 uni_modules/vk-uview-ui/components/u-input/u-input.vue create mode 100644 uni_modules/vk-uview-ui/components/u-keyboard/u-keyboard.vue create mode 100644 uni_modules/vk-uview-ui/components/u-lazy-load/u-lazy-load.vue create mode 100644 uni_modules/vk-uview-ui/components/u-line-progress/u-line-progress.vue create mode 100644 uni_modules/vk-uview-ui/components/u-line/u-line.vue create mode 100644 uni_modules/vk-uview-ui/components/u-link/u-link.vue create mode 100644 uni_modules/vk-uview-ui/components/u-loading-page/u-loading-page.vue create mode 100644 uni_modules/vk-uview-ui/components/u-loading/u-loading.vue create mode 100644 uni_modules/vk-uview-ui/components/u-loadmore/u-loadmore.vue create mode 100644 uni_modules/vk-uview-ui/components/u-mask/u-mask.vue create mode 100644 uni_modules/vk-uview-ui/components/u-message-input/u-message-input.vue create mode 100644 uni_modules/vk-uview-ui/components/u-modal/u-modal.vue create mode 100644 uni_modules/vk-uview-ui/components/u-navbar/u-navbar.vue create mode 100644 uni_modules/vk-uview-ui/components/u-no-network/u-no-network.vue create mode 100644 uni_modules/vk-uview-ui/components/u-notice-bar/u-notice-bar.vue create mode 100644 uni_modules/vk-uview-ui/components/u-number-box/u-number-box.vue create mode 100644 uni_modules/vk-uview-ui/components/u-number-keyboard/u-number-keyboard.vue create mode 100644 uni_modules/vk-uview-ui/components/u-parse/u-parse.vue create mode 100644 uni_modules/vk-uview-ui/components/u-picker/u-picker.vue create mode 100644 uni_modules/vk-uview-ui/components/u-popup/u-popup.vue create mode 100644 uni_modules/vk-uview-ui/components/u-radio-group/u-radio-group.vue create mode 100644 uni_modules/vk-uview-ui/components/u-radio/u-radio.vue create mode 100644 uni_modules/vk-uview-ui/components/u-rate/u-rate.vue create mode 100644 uni_modules/vk-uview-ui/components/u-read-more/u-read-more.vue create mode 100644 uni_modules/vk-uview-ui/components/u-row-notice/u-row-notice.vue create mode 100644 uni_modules/vk-uview-ui/components/u-row/u-row.vue create mode 100644 uni_modules/vk-uview-ui/components/u-search/u-search.vue create mode 100644 uni_modules/vk-uview-ui/components/u-section/u-section.vue create mode 100644 uni_modules/vk-uview-ui/components/u-select/u-select.vue create mode 100644 uni_modules/vk-uview-ui/components/u-skeleton/u-skeleton.vue create mode 100644 uni_modules/vk-uview-ui/components/u-slider/u-slider.vue create mode 100644 uni_modules/vk-uview-ui/components/u-steps/u-steps.vue create mode 100644 uni_modules/vk-uview-ui/components/u-sticky/u-sticky.vue create mode 100644 uni_modules/vk-uview-ui/components/u-subsection/u-subsection.vue create mode 100644 uni_modules/vk-uview-ui/components/u-swipe-action/u-swipe-action.vue create mode 100644 uni_modules/vk-uview-ui/components/u-swiper-plus/components/u-swiper-indicator.vue create mode 100644 uni_modules/vk-uview-ui/components/u-swiper-plus/u-swiper-plus.vue create mode 100644 uni_modules/vk-uview-ui/components/u-swiper/u-swiper.vue create mode 100644 uni_modules/vk-uview-ui/components/u-switch/u-switch.vue create mode 100644 uni_modules/vk-uview-ui/components/u-tabbar/u-tabbar.vue create mode 100644 uni_modules/vk-uview-ui/components/u-table/u-table.vue create mode 100644 uni_modules/vk-uview-ui/components/u-tabs-swiper/u-tabs-swiper.vue create mode 100644 uni_modules/vk-uview-ui/components/u-tabs/u-tabs.vue create mode 100644 uni_modules/vk-uview-ui/components/u-tag/u-tag.vue create mode 100644 uni_modules/vk-uview-ui/components/u-td/u-td.vue create mode 100644 uni_modules/vk-uview-ui/components/u-th/u-th.vue create mode 100644 uni_modules/vk-uview-ui/components/u-time-line-item/u-time-line-item.vue create mode 100644 uni_modules/vk-uview-ui/components/u-time-line/u-time-line.vue create mode 100644 uni_modules/vk-uview-ui/components/u-toast/u-toast.vue create mode 100644 uni_modules/vk-uview-ui/components/u-top-tips/u-top-tips.vue create mode 100644 uni_modules/vk-uview-ui/components/u-tr/u-tr.vue create mode 100644 uni_modules/vk-uview-ui/components/u-trees/CssHandler.js create mode 100644 uni_modules/vk-uview-ui/components/u-trees/MpHtmlParser.js create mode 100644 uni_modules/vk-uview-ui/components/u-trees/config.js create mode 100644 uni_modules/vk-uview-ui/components/u-trees/u-trees.vue create mode 100644 uni_modules/vk-uview-ui/components/u-upload/u-upload.vue create mode 100644 uni_modules/vk-uview-ui/components/u-verification-code/u-verification-code.vue create mode 100644 uni_modules/vk-uview-ui/components/u-waterfall/u-waterfall.vue create mode 100644 uni_modules/vk-uview-ui/components/vk-uview-ui/vk-uview-ui.vue create mode 100644 uni_modules/vk-uview-ui/iconfont.css create mode 100644 uni_modules/vk-uview-ui/index.js create mode 100644 uni_modules/vk-uview-ui/index.scss create mode 100644 uni_modules/vk-uview-ui/libs/address/areas.json create mode 100644 uni_modules/vk-uview-ui/libs/address/citys.json create mode 100644 uni_modules/vk-uview-ui/libs/address/provinces.json create mode 100644 uni_modules/vk-uview-ui/libs/config/config.js create mode 100644 uni_modules/vk-uview-ui/libs/config/zIndex.js create mode 100644 uni_modules/vk-uview-ui/libs/css/color.scss create mode 100644 uni_modules/vk-uview-ui/libs/css/common.scss create mode 100644 uni_modules/vk-uview-ui/libs/css/style.components.scss create mode 100644 uni_modules/vk-uview-ui/libs/css/style.h5.scss create mode 100644 uni_modules/vk-uview-ui/libs/css/style.mp.scss create mode 100644 uni_modules/vk-uview-ui/libs/css/style.nvue.scss create mode 100644 uni_modules/vk-uview-ui/libs/css/style.vue.scss create mode 100644 uni_modules/vk-uview-ui/libs/function/$parent.js create mode 100644 uni_modules/vk-uview-ui/libs/function/addStyle.js create mode 100644 uni_modules/vk-uview-ui/libs/function/addUnit.js create mode 100644 uni_modules/vk-uview-ui/libs/function/bem.js create mode 100644 uni_modules/vk-uview-ui/libs/function/color.js create mode 100644 uni_modules/vk-uview-ui/libs/function/colorGradient.js create mode 100644 uni_modules/vk-uview-ui/libs/function/debounce.js create mode 100644 uni_modules/vk-uview-ui/libs/function/deepClone.js create mode 100644 uni_modules/vk-uview-ui/libs/function/deepMerge.js create mode 100644 uni_modules/vk-uview-ui/libs/function/getParent.js create mode 100644 uni_modules/vk-uview-ui/libs/function/guid.js create mode 100644 uni_modules/vk-uview-ui/libs/function/md5.js create mode 100644 uni_modules/vk-uview-ui/libs/function/queryParams.js create mode 100644 uni_modules/vk-uview-ui/libs/function/random.js create mode 100644 uni_modules/vk-uview-ui/libs/function/randomArray.js create mode 100644 uni_modules/vk-uview-ui/libs/function/route.js create mode 100644 uni_modules/vk-uview-ui/libs/function/sys.js create mode 100644 uni_modules/vk-uview-ui/libs/function/test.js create mode 100644 uni_modules/vk-uview-ui/libs/function/throttle.js create mode 100644 uni_modules/vk-uview-ui/libs/function/timeFormat.js create mode 100644 uni_modules/vk-uview-ui/libs/function/timeFrom.js create mode 100644 uni_modules/vk-uview-ui/libs/function/toast.js create mode 100644 uni_modules/vk-uview-ui/libs/function/trim.js create mode 100644 uni_modules/vk-uview-ui/libs/function/type2icon.js create mode 100644 uni_modules/vk-uview-ui/libs/mixin/mixin.js create mode 100644 uni_modules/vk-uview-ui/libs/mixin/mpShare.js create mode 100644 uni_modules/vk-uview-ui/libs/request/index.js create mode 100644 uni_modules/vk-uview-ui/libs/store/index.js create mode 100644 uni_modules/vk-uview-ui/libs/util/async-validator.js create mode 100644 uni_modules/vk-uview-ui/libs/util/emitter.js create mode 100644 uni_modules/vk-uview-ui/package.json create mode 100644 uni_modules/vk-uview-ui/readme.md create mode 100644 uni_modules/vk-uview-ui/theme.scss diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8bbff90 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.hbuilderx +/node_modules +/unpackage diff --git a/App.vue b/App.vue new file mode 100644 index 0000000..ac01cf9 --- /dev/null +++ b/App.vue @@ -0,0 +1,55 @@ + + + diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..9461fd6 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 VK + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2e9a3ce --- /dev/null +++ b/README.md @@ -0,0 +1,498 @@ +### uniCloud云函数路由框架研究Q群:22466457 如有问题或建议可以在群内讨论。 +### 插件名称:`vk-unicloud-router` +### 作者:VK + +## 序 +##### 如果你热爱编程,想快速入门云开发,欢迎使用`vk-unicloud`系列开发框架 +##### 无需转变开发习惯,0成本上手云开发。 +##### 框架内置了众多API、工具包,为你的业务扫平障碍。使你的项目刚起步进度就是50%(微信登录、短信、验证码、缓存、生成小程序码等等) +##### 从此你又get一个新技能,只需用js,轻松搞定前后台整体业务。 +##### 完整框架项目地址: +##### `client端`框架地址: [https://ext.dcloud.net.cn/plugin?id=2204](https://ext.dcloud.net.cn/plugin?id=2204) +##### `admin端`框架地址:[https://ext.dcloud.net.cn/plugin?id=5043](https://ext.dcloud.net.cn/plugin?name=vk-unicloud-admin) +##### `client端`框架文档:[点击查看](https://vkdoc.fsq.pub/client/) +##### `admin端`框架文档:[点击查看](https://vkdoc.fsq.pub/admin/) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +## 主要功能 以及 对开发者的价值 + +#### 1、实现云函数路由模式(同时支持对云对象的路由) +* 1.1、路由模式不使用任何第三方包,兼容性强,运行稳定 +* 1.2、减少云函数数量,云函数有个数限制(用一个云函数即可实现多个云函数效果) +* 1.3、部分通用的代码块可以放在公共区执行,具有公共函数的效果,增加代码复用率,便于维护。 +* 1.4、可以在开发环境和生产环境中任意切换,开发时,用开发环境,开发过程中不会影响到线上环境。(具体切换方法在文档最后) +* 1.5、美化云函数请求过程中的日志排版,使请求日志一目了然。(再也不用为日志分散,难找而头疼) +* 1.6、可以强制关闭云端服务(适用于需要临时关闭后端服务的情况,如腾讯云迁移数据到阿里云时需要先关闭服务,否则迁移过程中会有新数据产生) + +#### 2、实现 `全局过滤器`,过滤非法请求。您无需关心用户角色权限问题。 + +#### 3、众多现成的 `JS API`,让您无需重复造轮子。(持续增加中) + +#### 4、众多现成的 `云函数 API`,为您的业务扫平障碍,让您可以专注于自身业务开发。(微信登录、短信、验证码、缓存、生成小程序码等等)(持续增加中) + +#### 5、全面支持 `url化` 的云函数请求,您无需关心url化后参数的获取问题 + +#### 6、已集成 `uni-id` 当前版本: `3.3.28`(已支持真实发送邮箱验证码和短信验证码) +* 6.1、由于每个应用基本都会用上用户系统,官方建议所有 `uniCloud` 应用均使用 `uni-id` 作为用户体系, +有了统一的账户规范,并且围绕这套账户规范,有各种各样插件,那么开发者可以随意整合这些插件,让数据连同。 + +* 6.2、同时方便其他用户使用 `unicloud` 插件发布者发布的前后端一体插件,只需要导入一个云函数即可。 +(如导入一个社区插件,可能要导入几十个云函数,而使用此云函数路由后,只需导入一个云函数,且已集成 `uni-id`,打通账号体系)。 + +#### 7、在 `uni-id` 基础上升级为 `vk.userCenter` 用户中心API 通过this.vk.userCenter 即可调用 [传送门](https://vkdoc.fsq.pub/client/vk.userCenter.html) + +#### 8、封装 `uni.callFunction` 和 `uni.request` 使之合二为一 通过this.vk.callFunction 调用 + +#### 9、`vk.baseDao` 数据库API,使小白也能轻松上手对数据库的调用。 [传送门](https://vkdoc.fsq.pub/client/uniCloud/db/api.html) + +#### 10、`vk.baseDao.selects` 数据库万能连表查询API [传送门](https://vkdoc.fsq.pub/client/uniCloud/db/selects.html) + +#### 11、`商品SKU选择器组件`(打造uni插件市场功能最全的SKU选择器组件)[传送门](https://ext.dcloud.net.cn/plugin?id=2848) + +#### 12、对 `Vuex` 进行了深度封装(支持持久化),现在可以很方便的使用Vuex进行读取和储存。[传送门](https://vkdoc.fsq.pub/client/pages/vuex.html) + +#### 13、自定义过滤器(在业务云函数执行之前(或之后),统一拦截,进行过滤后再放行,支持设置多个过滤器,并按指定顺序执行)[传送门](https://vkdoc.fsq.pub/client/uniCloud/middleware/filter.html) + +#### 14、支持设置需要登录的页面列表或不需要登录的页面列表(通过本地token检测,无网络请求,支持通配符写法)[传送门](https://vkdoc.fsq.pub/client/pages/config.html) + +#### 15、支持设置可以被分享的页面列表或禁止分享的页面列表(支持通配符写法)[传送门](https://vkdoc.fsq.pub/client/pages/config.html) + +#### 16、`vk.localStorage` 封装本地缓存的curd,同时具有监听缓存被更新和被删除的功能。[传送门](https://vkdoc.fsq.pub/client/pages/localStorage.html) + +#### 17、美化云函数请求过程中的日志排版,使请求日志一目了然。 + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/4a44fbf8-6b5e-43a6-b443-51a108dec125.png) + +#### 18、可以 `强制关闭` 云端服务(适用于需要临时关闭后端服务的情况,如腾讯云迁移数据到阿里云时需要先关闭服务,否则迁移过程中会有新数据产生) + +#### 19、全局数据缓存API,现在可以很方便的在云函数中使用缓存。 [传送门](https://vkdoc.fsq.pub/client/uniCloud/cache/cache.html) + +#### 20【全网首家】云函数URL化之URL重写 [传送门](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/urlrewrite.html) + +#### 21、千人群交流开发心得,助你避坑,作者亲自在群内解答框架使用问题,让你轻松上手 `uniCloud云开发`。 + +#### 22、其他好处… + +### 目前已集成的服务端API + +#### 1、微信小程序服务端API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html) + +#### 2、微信公众号服务端API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin-h5.html) + +#### 3、百度开放平台服务端API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/baidu.html) + +#### 4、短信发送 [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/sms.html) + +#### 5、邮箱发送 [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/mail.html) + +#### 6、Redis [传送门](https://vkdoc.fsq.pub/vk-redis/) + +##### 插件部分API功能体验地址 + +![插件首页体验地址](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-vk-cloud-router-test/51de83e0-e9ae-11ea-81ea-f115fe74321c.png?x-oss-process=image/resize,h_250 "插件首页体验地址") + +## 快速上手 - 安装步骤 + +## 后端(云函数端)安装步骤 +打开 `uniCloud/cloudfunctions` 目录 + +#### 前置工作:修改云函数全局配置文件(用到微信登录的必须要配置)[微信小程序配置详细教程](https://vkdoc.fsq.pub/client/question/q12.html) +#### 注意: +* 1、开发微信小程序和APP微信登录需要额外配置 manifest.json 以及 uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json 这2个配置文件,且改动配置后需要重新上传 公共模块 和 router 函数。 +* 2、若你的电脑没有安装 Node.js,则无法使用 npm 命令。 +* 3、Node.js 安装包及源码下载地址为:[https://nodejs.org/en/download/](https://nodejs.org/en/download/) +* 4、Node.js 安装教程:[https://www.runoob.com/nodejs/nodejs-install-setup.html](https://www.runoob.com/nodejs/nodejs-install-setup.html) + +查看 `uni-id/config.json` 代码格式 [点击查看](https://vkdoc.fsq.pub/client/uniCloud/config/uni-id.html) + + +#### 正式安装 + +直接右键`uniCloud`目录 点击 `运行云服务空间初始化向导` 即可 + +## 前端(页面端)安装步骤 + +### 自 `client` 端框架 `2.6.0` 起,不再内置任何 UI 框架,你可以选择自己喜欢的 UI 组件库进行开发。 + +### 集成 `vk-uview-ui`(vue2.0版) + +___若不想集成 `vk-uview-ui` 可跳过此处___ + +适合开发:H5、App(vue版本)、微信小程序、支付宝小程序(其他小程序未验证) + +> 插件市场导入 `vk-uview-ui` 框架:[点击前往](https://ext.dcloud.net.cn/plugin?id=6692) + +* 1、main.js 引入 vk-uview-ui + +```js +import uView from './uni_modules/vk-uview-ui'; +Vue.use(uView); +``` + +* 2、App.vue 引入基础样式(注意style标签需声明scss属性支持) + +```html + +``` + +* 3、uni.scss 引入全局 scss 变量文件 + +```css +@import "@/uni_modules/vk-uview-ui/theme.scss"; +``` + + +### 集成 `vk-uview-ui`(vue3.0版) + +___若不想集成 `vk-uview-ui` 可跳过此处___ + +适合开发:H5、App(vue版本)、微信小程序(其他小程序未验证) + +> 插件市场导入 `vk-uview-ui` 框架:[点击前往](https://ext.dcloud.net.cn/plugin?id=6692) + +不建议把老项目 升级到 Vue3.0 (升级非常麻烦,建议新项目才考虑是否使用Vue3.0) + +___注意:目前(2020-11-18) `uniapp` 的 `Vue3.0` 版本只兼容:H5、App、微信小程序___ + +* 1、前置步骤:修改 `manifest.json` 内的 `vue` 版本为 `vue3` +* 2、项目根目录新增 `index.html` 文件,文件代码为 +```html + + + + + + + + + + + + +
+ +
+ + + +``` + +* 3、main.js 引入 vk-uview-ui + +```js +// 引入 uView UI +import uView from './uni_modules/vk-uview-ui'; + +import { createSSRApp } from 'vue' + +export function createApp() { + const app = createSSRApp(App) + + // 使用 uView UI + app.use(uView) + + return { app } +} + +``` + +* 4、App.vue 引入基础样式(注意style标签需声明scss属性支持) + +```html + +``` + +* 5、uni.scss 引入全局 scss 变量文件 + +```css +@import "@/uni_modules/vk-uview-ui/theme.scss"; +``` + + +### 集成 `uview-ui`(nvue2.0版) + +___若不想集成 `uview-ui` 可跳过此处___ + +适合开发:App(nvue版本),如果你只开发App,推荐用这个UI + +> 插件市场导入 `uview-ui` 框架:[点击前往](https://ext.dcloud.net.cn/plugin?id=1593) + +* 1、main.js 引入 uview-ui + +```js +import uView from './uni_modules/uview-ui'; +Vue.use(uView); +``` + +* 2、App.vue 引入基础样式(注意style标签需声明scss属性支持) + +```html + +``` + +* 3、uni.scss 引入全局 scss 变量文件 + +```css +@import "@/uni_modules/uview-ui/theme.scss"; +``` + +### 集成 `uview-ui`(nvue3.0版) + +别想了,uniapp官方也还没支持。 + +### 组件库并不限制只能从以上选择,理论上支持任何UI组件库进行开发。 + +### 卸载 `uView1` 的步骤 + +* 1、main.js 删除 uView1 + +```js +import uView from 'uview-ui' +Vue.use(uView); +``` + +* 2、App.vue 删除基础样式 + +```html + +``` + +* 3、uni.scss 删除全局 scss 变量文件 + +```css +@import "uview-ui/theme.scss"; +``` + +* 4、pages.json 删除 easycom 规则 + +```js +"easycom": { + "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue", +}, +``` + +* 5、package.json 删除 uview-ui 依赖 + +```js +"dependencies": { + "uview-ui": "^1.8.3" +}, +``` + +* 6、package-lock.json 删除 uview-ui 依赖 + +```js +"dependencies": { + "uview-ui": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-1.8.3.tgz", + "integrity": "sha512-DqKc+qRrOZLPcyfWv4b0HspSS9n1Cd6BbgKiYEv9rjTAnWoqJV7rXsvWqZdr5iKGP5EMNbNS741GLNw4sIHbpw==" + } +} +``` + +### 完整安装文档:[查看完整安装文档](https://vkdoc.fsq.pub/client/quickstart.html) + +## 云函数框架目录结构 + +``` +. +├── common─────────────────# 自定义官方公共模块包 +│ └── config──────────────────# 全局配置公共模块 +│ └── uni-id──────────────────# uni-id官方公共模块 +│ └── vk-unicloud─────────────# vk-unicloud公共模块 +├── router─────────────────# 正式环境云函数主入口(函数路由器) +│ └── dao──────────────────# dao层(数据库交互公共API) +│ └── middleware───────────# 中间层(过滤器、拦截器) +│ └── node_modules─────────# npm包 +│ └── service──────────────# 逻辑层(用于写业务逻辑) +│ ── └── 逻辑层目录结构在下方单独展示 +│ └── util─────────────────# 工具包 +│ ── └── pubFunction.js───────# 公共函数包 +│ ── └── smsUtil.js───────────# 全局过滤器 +│ └── config.js────────────# 入口函数初始化配置 +│ └── index.js─────────────# 入口函数 +│ └── package.json─────────# 第三方依赖配置文件(若使用npm,自动生成) +└─└── package-lock.json────# 第三方依赖配置文件(若使用npm,自动生成) +. +├── router-test───────────────# 函数路由(开发测试环境) +│ └── ...─────────# ... +│ └── ...─────────# ... +└── └── ...─────────# ... +``` + +### 逻辑层目录结构 +#### `router/service` 目录为逻辑层 +#### 以下的目录并非强制性,只是建议,便于统一开发规范。 + +``` +. +├── service──────────────────────# 逻辑层(用于写业务逻辑) +│ └── admin────────────────# 后台管理端逻辑(admin框架开发中。。。) +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ └── client───────────────# 客户端逻辑(H5、小程序、APP) +│ ── └── user─────────────────# 用户服务(自己系统的逻辑) +│ ──── └── kh───────────────────# kh函数为必须登录后才能访问的函数 +│ ──── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ──── └── util─────────────────# 用户服务专用的工具包 +│ ── └── order────────────────# 订单服务(自己系统的逻辑) +│ ──── └── kh───────────────────# kh函数为必须登录后才能访问的函数 +│ ──── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ──── └── util─────────────────# 订单服务专用的工具包 +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ └── common───────────────# 公共逻辑(公共接口) +│ ── └── xxxxxxxxxxxxxxxx─────# +│ ── └── xxxxxxxxxxxxxxxx─────# +│ ── └── xxxxxxxxxxxxxxxx─────# +│ └── user─────────────────# 统一用户中心服务(已集成uniID)(用户中心作为核心,且为了方便插件升级,故与admin和client平级) +│ ── └── kh───────────────────# kh函数为必须登录后才能访问的函数(客户端用户) +│ ── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ── └── sys──────────────────# sys函数为后端管理人员才能访问的函数(商家后台工作人员) +│ ── └── util─────────────────# 统一用户中心服务专用的工具包 +│ └── plugs───────────────# 插件逻辑(插件专用)(会陆续新增一些实用性插件给开发者使用,如微信小程序发送订阅消息等等) +│ ──└── plugs-A───────────────────# 插件A +│ ────└── admin───────────────────# 插件A admin端 +│ ────└── client──────────────────# 插件A client端 +│ ──└── plugs-B───────────────────# 插件B +│ ────└── admin───────────────────# 插件B admin端 +│ ────└── client──────────────────# 插件B client端 +│ └── template─────────────# 云函数模板(插件内的云函数写法模板) +│ ── └── db_api───────────────# 数据库接口调用模板 +│ └── muban.js─────────────# 云函数模板(新建一个云函数应复制粘贴这个文件) +│ └── muban_easy.js────────# 云函数模板(简易版) +└───────────────────────────────── +``` + + +## 云函数service模板文件示例 +```js +module.exports = { + /** + * 此函数名称 + * @url user/sys/test1 前端调用的url参数地址 + * @description 此函数描述 + * @params {Object} data 请求参数 + * @params {String} uniIdToken 用户token + * @params {String} userInfo 当前登录用户信息(同理,是可信任的)(只有kh函数才带此参数) + * @params {Object} util 公共工具包 + * @params {Object} filterResponse 过滤器返回的数据 + * @params {Object} originalParam 原始请求参数(包含了原始event和context) + * data 请求参数 说明 + * @params {String} uid 当前登录用户id,若用户已登录且token有效,则data中会带uid参数 + * (此参数是后端过滤器通过token获取并添加到data中的,是可信任的)(只有kh函数才带此参数) + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} +``` +#### 成功时返回 +```js +// 注意:所有成功请求必须返回code:0 code为其他值,代表失败,如兑换失败,您的积分不足! +// 如成功时返回 res.code = 0 表示执行成功; +return { + code : 0, + msg : '兑换成功!' +} +``` +#### 失败时返回 +```js +return { + code : -1, + msg : '兑换失败,您的积分不足!' +} + +``` + +## this.vk.callFunction函数的参数说明 +```js +/** + * 云函数请求封装 - 统一入口 + * @description 通过云函数路由,1个云函数实现多个云函数的效果。 + * @params {String} url 请求路径,该路径实为router云函数的service目录下的路径 + * @params {Object} data 请求参数 + * @params {String} title 遮罩层提示语,为空或不传则代表不显示遮罩层。 + * @params {Boolean} isRequest 是否使用云函数url化地址访问云函数,默认false + * @params {Boolean} needAlert 为true代表请求错误时,会有alert弹窗提示。默认为true + * @params {Function} success 请求成功时,执行的回调函数 + * @params {Function} fail 请求失败时,执行的回调函数 + * @params {Function} complete 无论请求成功与否,都会执行的回调函数 + */ +``` + + +## 前端调用云函数示例 + +```js + +this.vk.callFunction({ + url: 'user/kh/setAvatar', + title:'请求中...', + data:{ + avatar: "https://xxxxxxx.jpg" + }, + success(data) { + // 修改成功 + } +}); + +``` + +## 云函数url化方式调用云函数示例 + +[点击查看『云函数url化』方式调用云函数示例](https://vkdoc.fsq.pub/client/pages/callFunctionForUrl.html) + +## 前端非法token拦截器 + +[点击查看『前端非法token拦截器』](https://vkdoc.fsq.pub/client/pages/interceptor1.html) + +## vk.baseDao数据库API + +[点击查看『vk.baseDao』数据库API](https://vkdoc.fsq.pub/client/uniCloud/db/api.html) + +## 设置全局请求参数 + +[点击查看『设置全局请求参数』](https://vkdoc.fsq.pub/client/pages/updateRequestGlobalParam.html) + +## 列表渲染前后端一体模板 + +[点击查看『列表渲染』前后端一体模板](https://vkdoc.fsq.pub/client/pages/list.html) + +## 商品SKU选择器组件 + +[点击查看『商品SKU选择器组件』](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=2912199&doc_id=975983) + +## 如何切换 正式环境 和 开发环境 + +[点击查看如何『切换正式环境和开发环境』](https://vkdoc.fsq.pub/client/question/q1.html) + +## 本插件更新步骤 +[点击查看本插件『更新步骤』](https://vkdoc.fsq.pub/client/changeGuide.html) + +## uniCloud云函数路由框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 \ No newline at end of file diff --git a/app.config.js b/app.config.js new file mode 100644 index 0000000..9ddc687 --- /dev/null +++ b/app.config.js @@ -0,0 +1,136 @@ +// 引入自定义公共函数 +import myPubFunction from '@/common/function/myPubFunction.js' +export default { + // 开发模式启用调式模式(请求时会打印日志) + debug: process.env.NODE_ENV !== 'production', + // 主云函数名称 + functionName: "router", + // 登录页面路径 + login: { + url: '/pages/auth/login/login' + }, + // 首页页面路径 + index: { + url: '/pages/index/index' + }, + // 404 Not Found 错误页面路径 + error: { + url: '/pages/error/404/404' + }, + // 前端默认时区(中国为8) + targetTimezone:8, + // 日志风格 + logger: { + colorArr: [ + "#0095f8", + "#67C23A" + ] + }, + /** + * app主题颜色 + * vk.getVuex('$app.color.main') + * vk.getVuex('$app.color.secondary') + */ + color: { + main: "#ff4444", + secondary: "#555555" + }, + // 需要检查是否登录的页面列表 + checkTokenPages: { + /** + * 如果 mode = 0 则代表自动检测 + * 如果 mode = 1 则代表list内的页面需要登录,不在list内的页面不需要登录 + * 如果 mode = 2 则代表list内的页面不需要登录,不在list内的页面需要登录 + * 注意1: list内是通配符表达式,非正则表达式 + * 注意2: 需要使用 vk.navigateTo 代替 uni.navigateTo 进行页面跳转才会生效 + * 注意3: 想要让 tabbar 页面必须登录才能访问,则需要手动在页面的onLoad里加 vk.pubfn.checkLogin(); + * 在无需登录的页面上执行kh或sys函数,也会自动判断是否登录,未登录会自动跳登录页面,登录成功后会自动返回本来要跳转的页面。 + */ + mode: 2, + list: [ + "/pages_template/*", + "/pages/auth/*", + "/pages/index/*", + "/pages/error/*" + ] + }, + // 需要检查是否可以分享的页面列表(仅小程序有效) + checkSharePages: { + /** + * 如果 mode = 0 则不做处理 + * 如果 mode = 1 则代表list内的页面可以被分享,不在list内的页面不可以被分享 + * 如果 mode = 2 则代表list内的页面不可以被分享,不在list内的页面可以被分享 + * 注意: list内是通配符表达式,非正则表达式 + */ + mode: 0, + // ['shareAppMessage', 'shareTimeline'], + menus: ['shareAppMessage'], + list: [ + "/pages/index/*", + "/pages/goods/*", + "/pages_template/*", + ] + }, + // 静态文件的资源URL地址 + staticUrl: { + // Logo + logo: '/static/logo.png', + }, + // 自定义公共函数,myPubFunction内的函数可通过vk.myfn.xxx() 调用 + myfn: myPubFunction, + // 第三方服务配置 + service: { + // 密钥和签名信息 (由于签名的获取比较麻烦,建议初学者使用上传到unicloud的方案,上传到阿里云OSS是给有特殊需求的用户使用) + // 相关文档 : https://help.aliyun.com/document_detail/31925.html?spm=a2c4g.11186623.6.1757.b7987d9czoFCVu + aliyunOSS: { + // 密钥和签名信息 + uploadData: { + OSSAccessKeyId: "", + policy: "", + signature: "", + }, + // oss上传地址 + action: "https://xxx.oss-cn-hangzhou.aliyuncs.com", + // 根目录名称 + dirname: "test", + // oss外网访问地址,也可以是阿里云cdn地址 + host: "https://xxx.xxx.com", + // 上传时,是否按用户id进行分组储存 + groupUserId: true, + // 是否默认上传到阿里云OSS + isDefault: false + } + }, + // 全局异常码,可以自定义提示结果 + globalErrorCode: { + // 阿里云10秒非正常超时,其实请求还在执行(且一般已经成功了,但前端接受不到成功结果) + "cloudfunction-unusual-timeout": "请求超时,但请求还在执行,请重新进入页面。", + // 请求超时(真正的请求超时) + "cloudfunction-timeout": "请求超时,请重试!", + // 不在预期内的异常(如数据库异常、云函数编译异常等) + "cloudfunction-system-error": "网络开小差了!" + }, + // 自定义拦截器 + interceptor: { + + // login:function(obj){ + // let { vk, params, res } = obj; + // //console.log("params:",params); + // //console.log("res:",res); + // if(!params.noAlert){ + // vk.alert(res.msg); + // } + // console.log("跳自己的登录页面"); + // // 上方代码可自己修改,写成你自己的逻辑处理。 + // }, + + // fail:function(obj){ + // let { vk, params, res } = obj; + // //console.log("params:",params); + // //console.log("res:",res); + // return false;// 返回false则取消框架内置fail的逻辑,返回true则会继续执行框架内置fail的逻辑 + // // 上方代码可自己修改,写成你自己的逻辑处理。 + // } + + } +} diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..de49f53 --- /dev/null +++ b/changelog.md @@ -0,0 +1,1548 @@ +## 2.15.3(2023-09-25) +* 【修复】`短信发送` 接口当uni-id配置成多端隔离(数组形式)会报错的bug +* 【修复】`vk.importObject` 部分情况下会报错的问题 +* 【优化】如果当前运行的微信小程序是体验版,但没有点HBX的【发行】菜单发布,则提示开发者请点【发行】按钮 +* 【优化】`$hasRole`函数的功能 [传送门](https://vkdoc.fsq.pub/client/jsapi.html#hasrole) +* 【优化】`vk.pubfn.timeFormat` 支持显示时区,完整格式为 `yyyy-MM-ddThh:mm:ssZ` +* 【优化】其他细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +## 2.15.2(2023-08-15) +* 【重要】新增地图相关的API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/map.html) +* 【修复】`vk.baseDao.sample` 在腾讯云空间最大只能取20条的bug +* 【优化】`vk.pubfn.test` 新增参数 `allowEmpty` 控制是否允许为空 [传送门](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-test-%E6%A3%80%E6%B5%8B%E6%96%87%E6%9C%AC%E6%A0%BC%E5%BC%8F) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +## 2.15.1(2023-07-20) +* 1、【重要】为了安全性考虑,调整前端的 `vk.request` API,需要手动指定 `uniIdToken: true` 才会在请求头中自动添加 `uni-id-token` +* 2、【优化】前端 `vk.request` 当满足响应规范时,会自动保存 `token` 和 `userInfo` 以及token失效跳登录页面 +* 3、【优化】新增 `vk.baseDao.setById`(根据ID判断存在则修改,不存在则添加,此为原子操作,非查询再判断) +* 4、【优化】`user/pub/sendEmailCode` 发送邮件验证码新增针对同一个邮箱每天的次数限制(默认30次,可在函数内修改默认次数) +* 5、【优化】`user/pub/sendSmsCode` 发送短信验证码新增针对同一个手机号每天的次数限制(默认12次,可在函数内修改默认次数) + + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +## 2.15.0(2023-07-04) +* 1、【重要】注册接口统一去除前端的role参数(需替换目录 `router/service/user/pub`) +* 2、【修复】云端表单验证不支持a.b的问题 +* 3、【新增】`vk.sessionStorage` 本地会话缓存,仅h5可用 +* 4、【优化】`vk.uploadFile` 新增参数 `cloudPathAsRealPath` 默认为true,代表支持阿里云目录 +* 5、【优化】`vk.uploadFile` 新增参数 `cloudDirectory` 可以设置上传至指定的云端目录 +* 6、【优化】`vk.request` 新增 `interceptor` 参数(该参数仅前端调用时生效)[传送门](https://vkdoc.fsq.pub/client/jsapi.html#vk-request-%E8%AF%B7%E6%B1%82http%E6%8E%A5%E5%8F%A3) +* 7、【优化】发送邮件验证码新增参数判断 +* 8、【优化】云函数、云对象404时的错误提示 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +## 2.14.3(2023-06-09) +* 1、【新增】支付宝小程序api [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/alipay.html) +* 2、【修复】因 `2.14.2` 更新导致的支付宝小程序报错问题。 +* 3、【优化】注册接口前端全局防抖 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +## 2.14.2(2023-06-01) +* 1、【优化】`user/kh/addUploadRecord` 细节 +* 2、【优化】`vk.importObject` 支持 `importObjectOptions` 参数 [传送门](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#uni-vk-importobject%E7%9A%84%E9%AB%98%E7%BA%A7%E7%94%A8%E6%B3%95) +* 3、【优化】vuex模块化支持多级目录 +* 4、【优化】微信公众号登录后不能跳回登录前页面的问题。 +* 5、【调整】`vk.pubfn.test(str, 'username')` 检测的长度调整为3-32位 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +## 2.14.1(2023-05-17) +* 1、【新增】QQ小程序API [详情](https://vkdoc.fsq.pub/client/uniCloud/plus/qq.html#%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6) +* 2、【新增】抖音小程序API [详情](https://vkdoc.fsq.pub/client/uniCloud/plus/douyin.html) +* 3、【优化】`vk.pubfn.formValidate` [详情](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/formRules.html#rules%E8%AF%A6%E8%A7%A3) +* 4、【优化】`vk.crypto.aes.encrypt` 和 `vk.crypto.aes.decrypt` 新增 `mode` 参数,支持切换为加密算法,方便兼容java、php等后端语言加解密 [详情](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/crypto.html#%E5%9C%A8%E4%BA%91%E5%87%BD%E6%95%B0%E5%8A%A0%E5%AF%86-java%E6%88%96php%E7%AD%89%E5%85%B6%E4%BB%96%E5%90%8E%E7%AB%AF%E8%AF%AD%E8%A8%80%E8%A7%A3%E5%AF%86) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +## 2.13.6(2023-04-23) +* 1、【新增】支付订单admin端API `admin/system_uni/pay-orders/sys/*` +* 2、【优化】`vk.baseDao.selects` 当getCount为false时,hasMore永远是false的bug + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +## 2.13.5(2023-03-20) +* 1、【修复】云函数内调用 `vk.callFunction` 可能会报错的bug +* 2、【修复】微信公众号万能API不支持上传媒体图片的问题 [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin-h5.html#%E5%A6%82%E4%BD%95%E8%B0%83%E7%94%A8%E4%B8%8A%E4%BC%A0%E4%B8%B4%E6%97%B6%E7%B4%A0%E6%9D%90%E6%8E%A5%E5%8F%A3) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +## 2.13.4(2023-02-12) +* 1、【修复】云函数内调用 `vk.callFunction` 可能会报错的bug +* 2、【修复】微信公众号万能API不支持上传媒体图片的问题 [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin-h5.html#%E5%A6%82%E4%BD%95%E8%B0%83%E7%94%A8%E4%B8%8A%E4%BC%A0%E4%B8%B4%E6%97%B6%E7%B4%A0%E6%9D%90%E6%8E%A5%E5%8F%A3) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +## 2.13.2(2023-01-19) +* 1、【调整】router云函数运行内存调整为512M(实测512M即可达到最优性能) +* 2、【新增】微信最新版头像和昵称获取示例,详见:/pages_template/uni-id/weixin/set-user-info.vue +* 3、【优化】升级微信小程序文本检测API `vk.openapi.weixin.security.msgSecCheck` 至2.0版本 [传送门 - 微信文档](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/sec-center/sec-check/msgSecCheck.html) +* 4、【修复】`微信公众号万能API调用接口` 在调用部分接口时可能会报错的问题 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.13.1(2022-12-29) +* 1、【调整】url化后token的请求头从 `uni_id_token` 改为 `uni-id-token`(新版阿里云不支持 `uni_id_token` 请求头) +* 2、【修复】`vk.openapi.weixin.h5.request` 接口无法在阿里云空间中自动使用代理的问题。 +* 3、【修复】`vk.pubfn.getOffsetTime` 接口在云端月偏移量计算在可能会出错的问题。 +* 4、【优化】其他一些兼容性问题。 + + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.12.4(2022-12-13) +* 1、【优化】新版阿里云空间通过代理请求微信公众号API细节处理 +* 2、【优化】`vk.pubfn.getCommonTime()` API内部细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.12.3(2022-11-24) +* 1、【优化】部分报错提示文本 +* 2、【优化】其他一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.12.2(2022-11-05) +* 1、【优化】新增 cancelAddTimeStr 配置,用于单独取消 _add_time_str +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/0092145a-8169-475d-83c5-c873ae8d0c05.png) +* 2、【优化】部分API的报错提示 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.12.1(2022-10-07) +* 1、【重要】vk实例初始化代码调整(因HBX更新导致本地运行时,不同的云函数环境目前没有隔离(云端无此问题,只有本地运行有此问题),从而导致HBX本地运行时,A云函数和B云函数复用了同一个vk实例,而更新后,vk实例在不同云函数内会隔离) + +`router/index.js` 代码修改(注意:如果你只使用一个router,则不修改也没有问题) + +```js +'use strict'; +// 注意:此为云函数路由入口文件,请勿修改此文件代码,你自己的云函数逻辑应写在service目录下 +const vk = require('vk-unicloud'); // vk-unicloud 工具包 +vk.init(require('./config.js')); +exports.main = async (event, context) => { + return await vk.router({ event, context, vk }); +}; +``` + +修改为 + +```js +'use strict'; +// 注意:此为云函数路由入口文件,请勿修改此文件代码,你自己的云函数逻辑应写在service目录下 +const vkCloud = require('vk-unicloud'); // 引入 vk-unicloud +const vk = vkCloud.createInstance(require('./config.js')); // 通过 vkCloud.createInstance 创建 vk 实例 +exports.main = async (event, context) => { + return await vk.router({ event, context, vk }); +}; +``` + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.12.0(2022-10-07) +* 1、【重要】vk实例初始化代码调整(因HBX更新导致本地运行时,不同的云函数环境目前没有隔离(云端无此问题,只有本地运行有此问题),从而导致HBX本地运行时,A云函数和B云函数复用了同一个vk实例,而更新后,vk实例在不同云函数内会隔离) + +`router/index.js` 代码修改(注意:如果你只使用一个router,则不修改也没有问题) + +```js +'use strict'; +// 注意:此为云函数路由入口文件,请勿修改此文件代码,你自己的云函数逻辑应写在service目录下 +const vk = require('vk-unicloud'); // vk-unicloud 工具包 +vk.init(require('./config.js')); +exports.main = async (event, context) => { + return await vk.router({ event, context, vk }); +}; +``` + +修改为 + +```js +'use strict'; +// 注意:此为云函数路由入口文件,请勿修改此文件代码,你自己的云函数逻辑应写在service目录下 +const vkCloud = require('vk-unicloud'); // 引入 vk-unicloud +const vk = vkCloud.createInstance(require('./config.js')); // 通过 vkCloud.createInstance 创建 vk 实例 +exports.main = async (event, context) => { + return await vk.router({ event, context, vk }); +}; +``` + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.11.13(2022-09-29) +* 1、【修复】升级HBX后带来的部分兼容性问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.11.12(2022-09-26) +* 1、【重要】微信公众号万能API调用接口支持在阿里云空间执行(自动使用阿里云代理模式)[传送门 - 阿里云固定IP设置](https://uniapp.dcloud.net.cn/uniCloud/cf-functions.html#aliyun-eip) +* 2、【修复】`vk.crypto.aes.encrypt`、`vk.crypto.aes.decrypt` 在非 `router` 目录结构的云函数中运行可能会报错的问题。 +* 3、【优化】`vk.pubfn.getCurrentPage()` API 在最新版HBX上的兼容性。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.11.11(2022-09-20) +* 1、【修复】`vk.baseDao.getTableData` 的查询条件某个字段的值指定为null时,可能会报错的问题。 +* 2、【优化】小程序在首次启动时,自动检测当前是否有最新版本,如有,则一键更新到最新版本。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.11.10(2022-09-19) +* 1、【修复】`vk.baseDao.getTableData` 的查询条件某个字段的值指定为null时,可能会报错的问题。 +* 2、【优化】小程序在首次启动时,自动检测当前是否有最新版本,如有,则一键更新到最新版本。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.11.9(2022-09-13) +* 1、【优化】其他细节 + + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.11.8(2022-09-12) +* 1、【优化】前端使用 `vk.request` 请求时,若本地缓存中有 `uni_id_token`,则请求头会带上 `uni_id_token` 的值 +* 2、【优化】`router` 函数 `url化后`,若没有直接传 `uni_id_token` 参数,则会尝试从请求头中获取 `uni_id_token` +* 3、【优化】其他细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.11.7(2022-09-08) +* 1、【修复】`vk.baseDao.getTableData` 内使用 `_.geoNear` 无效的问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.11.6(2022-09-05) +* 1、【优化】一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.11.5(2022-08-29) +* 1、【重要】新增 `监听token更新` API [传送门](https://vkdoc.fsq.pub/client/vk.userCenter.html?t=20220829#vk-onrefreshtoken-%E7%9B%91%E5%90%ACtoken%E6%9B%B4%E6%96%B0%E4%BA%8B%E4%BB%B6) +* 2、【优化】`云对象` 新增 `this.getUniCloudRequestId`(获取当前请求id)[传送门](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#this-getunicloudrequestid-%E8%8E%B7%E5%8F%96%E5%BD%93%E5%89%8D%E8%AF%B7%E6%B1%82id) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.11.4(2022-08-26) +* 1、【优化】`vk.pubfn.getCommonTime` 更新文档 [传送门](https://vkdoc.fsq.pub/client/jsapi.html?t=20220825#vk-pubfn-getcommontime-%E8%8E%B7%E5%8F%96%E6%97%B6%E9%97%B4%E8%8C%83%E5%9B%B4) +* 2、【优化】其他细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.11.3(2022-08-22) +* 1、【优化】一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.11.2(2022-08-22) +* 1、【重要】前端 `微信登录` 、 `微信获取openid` 等接口不再返回 `sessionKey` 取而代之的是返回 `encryptedKey`(加密后的数据,云函数解密后可获得 `sessionKey`) +* 2、【重要】新增配置 `vk.crypto.aes` 用于返回给前端加密数据时的加密密钥 + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/a4ca3d72-358e-4437-8766-d0b14e269697.png) + +* 3、【新增】`vk.crypto.aes.encrypt` 用于加密数据 +* 4、【新增】`vk.crypto.aes.decrypt` 用于解密数据 + +```js +// 加密数据 +let encryptedKey = vk.crypto.aes.encrypt({ + data: { + sessionKey: "XXXXX" + } +}); +console.log('encryptedKey: ', encryptedKey) + +// 解密 sessionKey 示例 +let decryptedRes = vk.crypto.aes.decrypt({ + data: encryptedKey, // 待解密的原文 +}); +console.log('decryptedRes: ', decryptedRes) +let sessionKey = decryptedRes.sessionKey; +console.log('sessionKey: ', sessionKey) +``` + +**特别注意** + +* 1、本次更新需要替换 `router/service/user/pub/` 目录 + +* 2、如果你使用了 `使用微信小程序绑定的手机号一键登录` 的API,则请看此处调整代码 [传送门](https://vkdoc.fsq.pub/client/vk.userCenter.html?t=20220822#vk-usercenter-loginbyweixinphonenumber-%E9%80%9A%E8%BF%87%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%BB%91%E5%AE%9A%E7%9A%84%E6%89%8B%E6%9C%BA%E5%8F%B7%E7%99%BB%E5%BD%95) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.11.1(2022-08-22) +* 1、【重要】前端 `微信登录` 、 `微信获取openid` 等接口不再返回 `sessionKey` 取而代之的是返回 `encryptedKey`(加密后的数据,云函数解密后可获得 `sessionKey`) +* 2、【重要】新增配置 `vk.crypto.aes` 用于返回给前端加密数据时的加密密钥 +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/a4ca3d72-358e-4437-8766-d0b14e269697.png) +* 3、【新增】`vk.crypto.aes.encrypt` 用于加密数据 +* 4、【新增】`vk.crypto.aes.decrypt` 用于解密数据 +```js +// 加密数据 +let encryptedKey = vk.crypto.aes.encrypt({ + data: { + sessionKey: "XXXXX" + } +}); +console.log('encryptedKey: ', encryptedKey) + +// 解密 sessionKey 示例 +let decryptedRes = vk.crypto.aes.decrypt({ + data: encryptedKey, // 待解密的原文 +}); +console.log('decryptedRes: ', decryptedRes) +let sessionKey = decryptedRes.sessionKey; +console.log('sessionKey: ', sessionKey) +``` +**特别注意** + +* 1、本次更新需要替换 `router/service/user/pub/` 目录 + +* 2、如果你使用了 `使用微信小程序绑定的手机号一键登录` 的API,则请看此处调整代码 [传送门](https://vkdoc.fsq.pub/client/vk.userCenter.html?t=20220822#vk-usercenter-loginbyweixinphonenumber-%E9%80%9A%E8%BF%87%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%BB%91%E5%AE%9A%E7%9A%84%E6%89%8B%E6%9C%BA%E5%8F%B7%E7%99%BB%E5%BD%95) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.11.0(2022-08-22) +* 1、【重要】前端 `微信登录` 、 `微信获取openid` 等接口不再返回 `sessionKey` 取而代之的是返回 `encryptedKey`(加密后的数据,云函数解密后可获得 `sessionKey`) +* 2、【重要】新增配置 `vk.crypto.aes` 用于返回给前端加密数据时的加密密钥 +* 3、【新增】`vk.crypto.aes.encrypt` 用于加密数据 +* 4、【新增】`vk.crypto.aes.decrypt` 用于解密数据 +```js +// 加密数据 +let encryptedKey = vk.crypto.aes.encrypt({ + data: { + sessionKey: "XXXXX" + } +}); +console.log('encryptedKey: ', encryptedKey) + +// 解密 sessionKey 示例 +let decryptedRes = vk.crypto.aes.decrypt({ + data: encryptedKey, // 待解密的原文 +}); +console.log('decryptedRes: ', decryptedRes) +let sessionKey = decryptedRes.sessionKey; +console.log('sessionKey: ', sessionKey) +``` +**特别注意** + +本次更新需要替换 `router/service/user/pub/` 目录 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.10.12(2022-08-20) +* 1、【优化】一些细节 + + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.10.11(2022-08-19) +* 1、【优化】发送短信验证码接口和组件新增参数 `checkUserExist` : 是否需要检测手机号对应的账号是否存在,默认false:不检测 设置为true:会检测,如果检测到用户不存在,则不发短信。(如通过手机号找回密码的业务,如果手机号都未注册,则没有必要发短信)(需要替换文件:`router/service/user/pub/sendSmsCode.js`) +* 2、【修复】数据库API,`_.geoNear` 部分情况下会失效的问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.10.10(2022-08-15) +* 1、【优化】一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.10.9(2022-08-15) +* 1、【优化】一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.10.8(2022-08-13) +* 1、【调整】根据手机验证码重置账号密码的短信验证 `type` 从 `reset` 改为 `reset-pwd`(与unicloud官方对齐) +* 2、【调整】根据邮箱验证码重置账号密码的邮件验证 `type` 从 `reset` 改为 `reset-pwd`(与unicloud官方对齐) +* 3、【修复】vk.pubfn.test("aaahttps://www.baidu.com","url") 会返回 true 的bug + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.10.7(2022-07-30) +* 1、【优化】云对象 `this.getCloudInfo()` 内增加 `functionName`、`functionType` [传送门](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#this-getcloudinfo-%E8%8E%B7%E5%8F%96%E4%BA%91%E7%AB%AF%E4%BF%A1%E6%81%AF) +* 2、【优化】云对象 `this.getClientInfo()` 内增加 `source` [传送门](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#this-getclientinfo-%E8%8E%B7%E5%8F%96%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%BF%A1%E6%81%AF) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.10.6(2022-07-28) +* 1、【新增】`uni-id` 配置 `removeDcloudAppid` 默认false,若设置true,则注册成功后,会自动删除 `dcloud_appid` 字段,以达到禁用隔离不同端用户的功能。(需配合中间件registerInitFilter) +* 2、【新增】`vk.openapi.weixin.urllink.generate` 云函数生成小程序url链接API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html#%E8%8E%B7%E5%8F%96%E5%B0%8F%E7%A8%8B%E5%BA%8Furl%E9%93%BE%E6%8E%A5) +* 3、【新增】`vk.userCenter.getWeixinMPurl` 前端直接生成小程序url链接API [传送门](https://vkdoc.fsq.pub/client/vk.userCenter.html#vk-usercenter-getweixinmpurl-%E7%94%9F%E6%88%90%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8Furl%E9%93%BE%E6%8E%A5) +* 4、【优化】`vk.openapi.weixin.wxacode.getUnlimited` 和 `vk.openapi.weixin.urlscheme.generate` 支持参数 `env_version` [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html#%E8%8E%B7%E5%8F%96%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%A0%81) + + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.10.5(2022-07-23) +* 1、【优化】一些细节。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.10.4(2022-07-21) +* 1、【优化】一些细节。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.10.3(2022-07-21) +* 1、【优化】一些细节。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.10.2(2022-07-20) +* 1、【修复】`_.geoNear` 和 `lastWhereJson` 同时使用时报错的bug +* 2、【优化】一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.10.1(2022-07-18) +* 1、`vk.pubfn.batchRun` 新增另外一种调用方式。[传送门](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-batchrun) +* 2、新增 `vk.uploadFile` 代替 `vk.callFunctionUtil.uploadFile`(保留旧写法) [传送门](https://vkdoc.fsq.pub/client/pages/uploadFile.html) + + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.10.0(2022-07-09) +* 1、【优化】`vk.baseDao.update` `vk.baseDao.updateById` `vk.baseDao.updateAndReturn` API的 `dataJson` 参数若有 `_id`,则自动忽略 `_id`(因_id不可修改,原先是直接报错) +* 2、【优化】其他细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.9.9(2022-07-04) +* 1、【新增】微信小程序服务端万能API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html#%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E4%B8%87%E8%83%BDapi%E8%B0%83%E7%94%A8%E6%8E%A5%E5%8F%A3) +* 2、【新增】微信公众号服务端万能API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin-h5.html) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.9.8(2022-06-28) +* 1、【重要】新增安全规则:未标记 `isCloudObject:true` 的对象定义为私有对象(如 `service/user/util/login_log.js`),前端禁止访问(只能被云函数/云对象 `require` 方式调用)。 +* 2、【重要】`client端` 默认自带 `admin端` 需要的函数和菜单权限表数据,方便 `admin` 一键绑定 `client` 项目(不再需要复制admin项目内的文件了)。 +* 3、【优化】`万能连表` 支持使用数组下标对应的值进行连表,如用户表根据inviter_uid的第一个值进行连表达到只查出第一个上级用户信息的效果 [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/selects.html#%E5%9C%BA%E6%99%AF11) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.9.7(2022-06-22) +* 1、【新增】云函数专用api `vk.pubfn.randomAsync`(异步)产生指定位数的不重复随机数(支持任意字符,s默认纯数字)[点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-randomasync) +* 2、【新增】数据库表内的字段重命名api [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/question.html#%E5%A6%82%E4%BD%95%E6%9B%B4%E6%94%B9%E5%AD%97%E6%AE%B5%E5%90%8D) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.9.6(2022-06-16) +* 1、【优化】一些细节。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.9.5(2022-06-16) +* 1、【无更新】配合测试,开发者无需更新到此版本(与2.9.4版本一致) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.9.4(2022-06-15) +* 1、【升级】`uni-id` 至 `3.3.23` +* 2、【调整】`vk.getVuex` 当数据不存在时,返回值由 `undefined` 调整为 `空字符串`(undefined在部分平台会有问题) +* 3、【优化】示例代码的细节问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.9.3(2022-06-15) +* 1、【升级】`uni-id` 至 `3.3.23` +* 2、【调整】`vk.getVuex` 当数据不存在时,返回值由 `undefined` 调整为 `空字符串`(undefined在部分平台会有问题) +* 3、【优化】示例代码的细节问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.9.2(2022-06-11) +* 1、【重要】`uni-id` 新增配置参数 `"preferedWebPlatform": "h5",`,用于解决因HBX3.4.14版本导致的 `h5` 变为 `web` 带来的一系列问题。(完美兼容,你无需改自己的逻辑代码了) +* 2、【调整】`vk.getVuex` 当数据不存在时,返回值由 `空字符串` 调整为 `undefined` + + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.9.1(2022-06-08) +* 1、【优化】`云对象` 的内置api `this.getClientInfo` 可以获取到更多信息(uni.getSystemInfo返回的客户端信息) +* 2、【优化】`云函数` 的 `originalParam.context` 可以获取到更多信息(uni.getSystemInfo返回的客户端信息) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.9.0(2022-06-07) +* 1、【新增】`vk.callFunction` api [点击查看详情](https://vkdoc.fsq.pub/client/question/question.html#%E4%BA%91%E5%87%BD%E6%95%B0-%E4%BA%91%E5%AF%B9%E8%B1%A1-%E4%B8%AD%E5%A6%82%E4%BD%95%E8%B0%83%E7%94%A8%E5%8F%A6%E4%B8%80%E4%B8%AA%E4%BA%91%E5%87%BD%E6%95%B0-%E4%BA%91%E5%AF%B9%E8%B1%A1) +> * 1.1、支持在云对象中请求其他云对象内的函数。 +> * 1.2、支持在云对象中请求云函数。 +> * 1.3、支持在云函数内请求其他云函数。 +> * 1.4、支持在云函数内请求云对象内的函数。 +* 2、【优化】`pub` 类型的函数无需 `need_user_info:true`,也能从token中解析并获取到uid(无数据库请求,不影响性能) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.8.13(2022-06-02) +* 1、【修复】`云对象` 模式下 `sys类型函数` 在非admin目录下时,请求会提示 `need_user_info` 的问题。 +* 2、【优化】为了兼容DCloud推出的uniCloud响应体规范,请求后的返回值会自动加上errCode和errMsg,其中errCode=code,errMsg=msg + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.8.12(2022-06-02) +* 1、【修复】`云对象` 模式下 `sys类型函数` 在非admin目录下时,请求会提示 `need_user_info` 的问题。 +* 2、【优化】为了兼容DCloud推出的uniCloud响应体规范,请求后的返回值会自动加上errCode和errMsg,其中errCode=code,errMsg=msg + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.8.11(2022-05-28) +* 1、【修复】无法 `alt+左键` 跳转到组件源代码文件的bug。(只需删除 `pages.json` 内的空 `easycom` 规则即可,此为造成无法识别组件的原因。) +* 2、【修复】无法自动识别组件标签的bug。(只需删除 `pages.json` 内的空 `easycom` 规则即可,此为造成无法识别组件的原因。) +* 3、【修复】`interceptor.login` 前端自定义login拦截器,在某些情况下无法正常拦截的问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.8.10(2022-05-28) +* 1、【修复】当 `云对象` 在 `service` 层根目录时,`pub.对象名.js` pub权限失效的问题。 +* 2、【优化】其他一些细节。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.8.9(2022-05-26) +* 1、【优化】`vk.baseDao.selects` 和 `vk.baseDao.getTableData` API新增 `lastSortArr` 参数,用于聚合后再排序。 +* 注意:`lastWhereJson` 和 `lastSortArr` 在数据量大的情况下是有性能问题的,(建议主表的where条件中先进行筛选,如只查本季度数据,只要主表过滤完后数据量不大,则没有性能问题。) +* 2、【修复】`lastWhereJson` 后,返回的 `total` 不准确的问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.8.8(2022-05-25) +* 1、【升级】`uni-id` 3.3.21 +* 2、【优化】`javascript代码块提示` [查看详情](https://vkdoc.fsq.pub/client/codeTips.html) +* 3、【优化】示例页面的一些细节。 +* 4、【优化】vuex自动加载模块(无需手动引入模块)(需要替换 `/store/index.js` 文件) + + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.8.7(2022-05-25) +* 1、【优化】`javascript代码块提示` [查看详情](https://vkdoc.fsq.pub/client/codeTips.html) +* 2、【优化】示例页面的一些细节。 +* 3、【优化】vuex自动加载模块(无需手动引入模块)(需要替换 `/store/index.js` 文件) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.8.6(2022-05-14) +* 1、【升级】`uni-id` 3.3.18 +* 2、【新增】`vk.pubfn.getFileType(url)` 根据文件url获取文件类型 +* 3、【新增】`vk.pubfn.getFileSuffix(url)` 根据文件url获取文件后缀名 +* 4、【新增】`vk.pubfn.checkFileSuffix(url,["png", "jpg", "jpeg", "gif", "bmp", "svg"])` 根据文件url判断是否满足指定后缀名中的任意1个 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.8.5(2022-05-05) +* 1、【重要】vk实例对象已调整为页面内置对象,vk实例对象内的api在任意地方都可以直接通过vk.xxx()使用,不再需要 this.vk.xxx() 或 uni.vk.xxx() 的方式来调用。 +* 2、【重要】vk实例对象已调整为云函数内置对象,vk实例对象内的api在任意地方都可以直接通过vk.xxx()使用,不再需要 this.vk.xxx() 或 uniCloud.vk.xxx() 的方式来调用。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.8.4(2022-04-28) +* 1、【新增】`vk.openapi.weixin.uniformMessage.send` 小程序转公众号消息模板接口 [点击查看](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html#%E5%B0%8F%E7%A8%8B%E5%BA%8F%E8%BD%AC%E5%85%AC%E4%BC%97%E5%8F%B7%E6%A8%A1%E6%9D%BF%E6%B6%88%E6%81%AF) +* 2、【新增】`vk.openapi.weixin.h5.templateMessage.send` 公众号消息模板接口 [点击查看](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html#%E5%8D%95%E7%8B%AC%E5%85%AC%E4%BC%97%E5%8F%B7%E6%A8%A1%E6%9D%BF%E6%B6%88%E6%81%AF) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.8.3(2022-04-21) +* 1、【重要】`uni-id` 配置新增 `tokenMaxLimit` 每个账户的最大token数量,0为不限,淘汰策略:新的淘汰旧的(注意,即使设置为0,框架也会自动淘汰已过期的token)[点击查看](https://vkdoc.fsq.pub/client/uniCloud/config/uni-id.html) +* 2、【重要】微信登录支持多小程序:如果使用多小程序登录,则同一用户(同一个微信号)在不同小程序登录时,会分别创建不同的用户(除非小程序绑定在同一个开放平台下) +* 3、【新增】全局参数 `targetTimezone` 可设置默认时区(中国为8,8代表东8区,-8代表西8区) + +> [查看前端全局配置](https://vkdoc.fsq.pub/client/pages/config.html) + +> [查看云函数全局配置](https://vkdoc.fsq.pub/client/uniCloud/config/vk-unicloud.html) + +* 4、【新增】全局参数 `functionNameToUrl` 和 `isRequestDefault` [点击查看](https://vkdoc.fsq.pub/client/pages/callFunctionForUrl.html#%E6%B3%A8%E6%84%8F-%E4%BA%91%E5%87%BD%E6%95%B0url%E5%8C%96%E6%96%B9%E5%BC%8F%E8%B0%83%E7%94%A8%E9%9C%80%E8%A6%81%E9%85%8D%E7%BD%AE%E4%BD%A0%E7%9A%84%E4%BA%91%E5%87%BD%E6%95%B0url%E8%B7%AF%E5%BE%84%E5%9C%B0%E5%9D%80) +* 5、【优化】微信注册时支持新增自定义字段,如:nickname和avatar等。 +* 6、【优化】当云函数全局配置文件出错时,优化报错提示。 + +**本次更新除了常规升级框架外,还需要下载最新版框架示例项目,从最新版中复制 以下文件 替换 你项目中的对应文件。** + +* 1、`router/middleware/modules/returnUserInfoFilter.js` (此为用户登录注册全局中间件) +* 2、`router/service/user/pub/loginByWeixin.js` (此为微信登录云函数) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.8.2(2022-04-21) +* 1、【重要】`uni-id` 配置新增 `tokenMaxLimit` 每个账户的最大token数量,0为不限,淘汰策略:新的淘汰旧的(注意,即使设置为0,框架也会自动淘汰已过期的token)[点击查看](https://vkdoc.fsq.pub/client/uniCloud/config/uni-id.html) +* 2、【重要】微信登录支持多小程序:如果使用多小程序登录,则同一用户(同一个微信号)在不同小程序登录时,会分别创建不同的用户(除非小程序绑定在同一个开放平台下) +* 3、【新增】全局参数 `targetTimezone` 可设置默认时区(中国为8,8代表东8区,-8代表西8区) + +> [查看前端全局配置](https://vkdoc.fsq.pub/client/pages/config.html) + +> [查看云函数全局配置](https://vkdoc.fsq.pub/client/uniCloud/config/vk-unicloud.html) + +* 4、【新增】全局参数 `functionNameToUrl` 和 `isRequestDefault` [点击查看](https://vkdoc.fsq.pub/client/pages/callFunctionForUrl.html#%E6%B3%A8%E6%84%8F-%E4%BA%91%E5%87%BD%E6%95%B0url%E5%8C%96%E6%96%B9%E5%BC%8F%E8%B0%83%E7%94%A8%E9%9C%80%E8%A6%81%E9%85%8D%E7%BD%AE%E4%BD%A0%E7%9A%84%E4%BA%91%E5%87%BD%E6%95%B0url%E8%B7%AF%E5%BE%84%E5%9C%B0%E5%9D%80) +* 5、【优化】微信注册时支持新增自定义字段,如:nickname和avatar等。 +* 6、【优化】当云函数全局配置文件出错时,优化报错提示。 + +**本次更新除了常规升级框架外,还需要下载最新版框架示例项目,从最新版中复制 以下文件 替换 你项目中的对应文件。** + +* 1、`router/middleware/modules/returnUserInfoFilter.js` (此为用户登录注册全局中间件) +* 2、`router/service/user/pub/loginByWeixin.js` (此为微信登录云函数) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.8.1(2022-04-14) +* 1、【新增】前端请求多服务空间的极简方式(通过配置直接指定调用环境)[点击查看](https://vkdoc.fsq.pub/client/question/q9.html#%E6%96%B9%E5%BC%8F%E4%BA%8C) +* 2、【新增】`vk.userCenter.resetPasswordByEmail`(根据邮箱证码重置账号密码) [点击查看](https://vkdoc.fsq.pub/client/vk.userCenter.html#vk-usercenter-resetpasswordbyemail-%E6%A0%B9%E6%8D%AE%E9%82%AE%E7%AE%B1%E8%AF%81%E7%A0%81%E9%87%8D%E7%BD%AE%E8%B4%A6%E5%8F%B7%E5%AF%86%E7%A0%81) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.8.0(2022-04-01) +* 1、【重要】新增 `云对象` 路由模式 [什么是云对象?](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html) +* 2、【重要】自此,在VK框架中,可以做到云对象和云函数同时存在。即在VK框架中,同时支持 `云对象路由模式` 和 `云函数路由模式`。 +* 3、【新增】本地运行支持云对象 [点击查看](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#%E6%9C%AC%E5%9C%B0%E8%BF%90%E8%A1%8C) + + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.7.6(2022-03-26) +* 1、【优化】一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.7.5(2022-03-22) +* 1、【新增】`vk.userCenter.bindNewMobile` 换绑新的手机号接口 [查看详情](https://vkdoc.fsq.pub/client/vk.userCenter.html#vk-usercenter-bindnewmobile-%E6%8D%A2%E7%BB%91%E6%89%8B%E6%9C%BA%E5%8F%B7) +* 2、【新增】`vk.userCenter.bindNewEmail` 换绑新的邮箱接口 [查看详情](https://vkdoc.fsq.pub/client/vk.userCenter.html#vk-usercenter-bindnewemail-%E6%8D%A2%E7%BB%91%E9%82%AE%E7%AE%B1) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 2.7.4(2022-03-21) +* 1、【优化】H5环境下,微信登录、微信绑定、微信解绑API,使之自动识别微信公众号环境(h5-weixin)的配置。 +注意:微信公众号的 `uni-id` 配置属性是 `h5-weixin`,非 `h5`。 +* 2、【新增】新增微信公众号登录、注册、绑定、解绑、获取openid的调用示例。 演示页面地址:`/pages_template/uni-id/weixin/h5-weixin` +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.7.3(2022-03-18) +* 1、【优化】一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.7.2(2022-03-14) +* 1、【修复】`vk.navigateTo` 以 ./ 开头时 如:vk.navigateTo("./order-list") 判断是否需要登录不准确的问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.7.1(2022-03-14) +* 1、【优化】`app.config.js` 中的 `checkTokenPages` 检测页面是否需要登录支持 首页(启动页)的检测 +* 2、【优化】其他细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.7.0(2022-02-26) +###【重要】由于uni官方限制自定义表不可以用 `opendb-` 和 `uni-` 开头,故以下数据库表名只能进行调整 + +* 1、`opendb-components-dynamic` 改为 `vk-components-dynamic` +* 2、`opendb-global-data` 改为 `vk-global-data` +* 3、`uni-id-files` 改为 `vk-files` +* 4、`uni-id-files-categories` 改为 `vk-files-categories` + +___更改表名势必会对老项目产生影响。___ + +### 老项目更新注意事项: +* 1、老项目更新后,还需要从 `unicloud控制台` 把表名改成对应的新表名 +* 2、在项目代码中全局搜索旧表名,替换成新表名 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.6.9(2022-02-24) +* 1、【优化】`万能连表` 支持副表外键是数组类型(只要数组内任意元素与主表外键匹配即可)[点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/selects.html#%E5%9C%BA%E6%99%AF6) +* 2、【优化】其他一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.6.8(2022-01-08) +* 1、【修复】`vk.openapi.weixin.security.imgSecCheck` 图片安全检测失效的问题 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.6.7(2021-12-24) +* 1、【修复】`vk.pubfn.priceFilter` 、`vk.pubfn.percentageFilter` 、`vk.pubfn.discountFilter` 部分情况下,默认值不生效的问题。 +* 2、【修复】`vk.pubfn.string2Number` 会将空字符串转为0的问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.6.6(2021-12-14) +* 1、【优化】一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.6.5(2021-12-14) +* 1、【优化】一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.6.4(2021-12-10) +* 1、【修复】少数情况下,http请求可能获取不到数据的问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.6.3(2021-12-07) +* 1、【优化】上传api的url自动去除原文件名的中文部分。 +* 2、【修复】公众号登录可能会获取不到昵称和头像的问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.6.2(2021-12-04) +* 1、【新增】`vk.baseDao` 内api支持连接其他服务空间的数据库 [点击查看](https://vkdoc.fsq.pub/client/question/q9.html#%E4%BA%91%E5%87%BD%E6%95%B0%E7%AB%AF%E8%AF%B7%E6%B1%82%E5%A4%9A%E6%9C%8D%E5%8A%A1%E7%A9%BA%E9%97%B4%E7%A4%BA%E4%BE%8B%E4%BB%A3%E7%A0%81) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.6.1(2021-11-26) +* 1、【新增】`await vk.pubfn.batchRun` 批量循环并发执行异步函数(云函数内专用, 使用场景: 批量发送短信、邮件、消息通知等。)[点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-batchrun) +* 2、【优化】qq 登录问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.6.0(2021-11-19) +* 1、【重要】移除了内置的 `npm` 方式安装的 `uView` 组件库,开发者可以选择自己喜欢的组件库进行开发。[点击查看](https://vkdoc.fsq.pub/client/quickstart.html#%E8%87%AA-client%E7%AB%AF%E6%A1%86%E6%9E%B6-2-6-0-%E8%B5%B7-%E4%B8%8D%E5%86%8D%E5%86%85%E7%BD%AE%E4%BB%BB%E4%BD%95-ui-%E6%A1%86%E6%9E%B6-%E4%BD%A0%E5%8F%AF%E4%BB%A5%E9%80%89%E6%8B%A9%E8%87%AA%E5%B7%B1%E5%96%9C%E6%AC%A2%E7%9A%84-ui-%E7%BB%84%E4%BB%B6%E5%BA%93%E8%BF%9B%E8%A1%8C%E5%BC%80%E5%8F%91%E3%80%82) +* 2、【重要】移除内置组件 `vk-u-goods-sku-popup`(推荐 `vk-data-goods-sku-popup` 代替)[点击查看](https://ext.dcloud.net.cn/plugin?id=2848) +* 3、【重要】移除内置组件 `vk-u-number-box`(推荐 `u-number-box` 代替) +* 4、【重要】移除内置组件 `vk-u-grid-button` +* 5、【重要】移除内置组件 `vk-u-swiper` +* 6、【重要】重构内置组件 `vk-u-verification-code` 并改名为 `vk-data-verification-code` + +如想要继续使用这些组件,可以把这些组件复制到项目根目录的 `components` 目录(没有则新建)(目录名和组件名需一致,如 `vk-u-grid-button/vk-u-grid-button`) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.5.6(2021-11-13) +* 1、【新增】`vk.pubfn.getOffsetTime` 获得指定时间偏移 year年 month月 day天 hours时 minutes分 seconds秒前或后的时间戳 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getoffsettime-%E8%8E%B7%E5%BE%97%E6%8C%87%E5%AE%9A%E6%97%B6%E9%97%B4%E5%81%8F%E7%A7%BB-year%E5%B9%B4-month%E6%9C%88-day%E5%A4%A9-hours%E6%97%B6-minutes%E5%88%86-seconds%E7%A7%92%E5%89%8D%E6%88%96%E5%90%8E%E7%9A%84%E6%97%B6%E9%97%B4%E6%88%B3) +* 2、【优化】一些细节 +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.5.5(2021-11-10) +* 1、【升级】`uni-id` 为 `3.3.9` 去除重复的 `context.xxx` 未找到的提示语 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.5.4(2021-11-10) +* 1、【优化】前端请求云函数的一处细节。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.5.3(2021-11-09) +* 1、【优化】`vk.pubfn.base64ToFile` 支持 APP 环境执行 +* 2、【优化】`vk.pubfn.fileToBase64` 支持 APP 环境执行 +* 3、【修复】`vk.baseDao.adds` 无返回值的问题。 +* 4、【修复】`vk.baseDao.selects` 当 `localKey` 为 `a.b.c` 这样的形式时会报错的问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.5.2(2021-11-02) +* 1、【新增】`vk.h5` 前端API接口(H5专用的一些接口,只有H5环境时,才有该对象,不会增大小程序的包体积) +* 2、【新增】`vk.h5.wx`(wx为公众号js_sdk接口) [微信小程序环境内js_sdk文档](https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html) [微信公众号环境内js_sdk文档](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html) +* 3、【新增】`vk.navigateToHome` 跳转到首页 (app.config.js 的 index.url) +* 4、【新增】`vk.navigateToLogin` 跳转到登录页 (app.config.js 的 login.url) +* 5、【修复】`vk.callFunctionUtil.updateRequestGlobalParam` 全局公共请求参数的一处逻辑问题。 +* 6、【优化】登录注册模板细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.5.1(2021-11-02) +* 1、【新增】`vk.h5` 前端API接口(H5专用的一些接口,只有H5环境时,才有该对象,不会增大小程序的包体积) +* 2、【新增】`vk.h5.wx`(wx为公众号js_sdk接口) [微信小程序环境内js_sdk文档](https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html) [微信公众号环境内js_sdk文档](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html) +* 3、【新增】`vk.navigate.navigateToHome` 跳转到首页 +* 4、【新增】`vk.navigate.navigateToLogin` 跳转到登录页 +* 5、【修复】`vk.callFunctionUtil.updateRequestGlobalParam` 全局公共请求参数的一处逻辑问题。 +* 6、【优化】登录注册模板细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.5.0(2021-11-02) +* 1、【新增】`vk.h5` 前端API接口(H5专用的一些接口,只有H5环境时,才有该对象,不会增大小程序的包体积) +* 2、【新增】`vk.h5.wx`(wx为公众号js_sdk接口) [微信小程序环境内js_sdk文档](https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html) [微信公众号环境内js_sdk文档](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html) +* 3、【新增】`vk.navigate.navigateToHome` 跳转到首页 +* 4、【新增】`vk.navigate.navigateToLogin` 跳转到登录页 +* 5、【修复】`vk.callFunctionUtil.updateRequestGlobalParam` 全局公共请求参数的一处逻辑问题。 +* 6、【优化】登录注册模板细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.8(2021-10-30) +* 1、【优化】`vk.pubfn.hidden(str, first, last);` 的 `first` 和 `last` 默认为0 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-hidden-%E5%B0%86%E6%89%8B%E6%9C%BA%E5%8F%B7%E3%80%81%E8%B4%A6%E5%8F%B7%E7%AD%89%E9%9A%90%E8%97%8F%E4%B8%AD%E9%97%B4%E5%AD%97%E6%AE%B5) +* 2、【优化】其他一些细节 +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.7(2021-10-26) +* 1、【优化】在 `template` 模板中使用 `vk.pubfn`(可以用简写法 `$fn` 代替 `vk.pubfn`) +* 2、【优化】其他细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.6(2021-10-25) +* 1、【优化】`vk.userCenter` 接口细节,现在参数 `loading:true` 或 `loading:false` 均可以关闭 `loading提示框` + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.5(2021-10-16) +* 1、【优化】当获取小程序码错误时,增加微信返回的错误提示。 +* 2、【优化】当配置文件编译错误时,增加对应的错误提示。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.4(2021-10-15) +* 1、【优化】当 `router/util/pubFunction.js` 内的代码出现编译错误时,控制台能打印编译错误信息。 +* 2、【优化】其他一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.3(2021-10-08) +* 1、【新增】vk.userCenter 用户中心API的文档 [点击查看](https://vkdoc.fsq.pub/client/vk.userCenter.html) +* 2、【优化】一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.2(2021-09-30) +* 1、【优化】`vk.pubfn.string2Number` 新增第二位参数option +```js +/** + * 将能转成数字的字符串转数字(支持字符串、对象、数组) + * @param {Any} obj + * @param {Object} option 哪些格式需要排除 + * 默认排除 + * mobile:true 手机号,如 15200000001 + * idCard:true 身份证,如 330154202109301214 + * startFrom0:true 第一位是0,且长度大于1的,同时第二位不是.的字符串 如 01,057189101254 + */ +vk.pubfn.string2Number(obj, option); +``` + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.1(2021-09-30) +* 1、【新增】`vk.pubfn.string2Number` 将能转成数字的字符串值转Number类型(支持字符串、对象、数组)(深度遍历) +* 2、【优化】`vk.callFunctionUtil.updateRequestGlobalParam` 设置全局请求参数 `regExp` 参数支持数组(满足数组内任意正则即算匹配) [点击查看](https://vkdoc.fsq.pub/client/pages/updateRequestGlobalParam.html) + + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.0(2021-09-28) +* 1、【重要】支持微信公众号登录(有头像和昵称)详情见示例项目:`pages_template/openapi/h5-weixin/h5-weixin` +* 2、【优化】APP使用微信登录时,有头像和昵称 详情见示例项目:`pages_template/uni-id/weixin/weixin` + +公众号配置文件在 `uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json` + +```js +"h5-weixin": { + "oauth": { + "weixin": { + "appid": "微信公众号appid", + "appsecret": "微信公众号appsecret" + } + } +}, +``` +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.3.5(2021-09-27) +* 1、【新增】`vk.pubfn.snake2camelJson` 对象内的属性名 - 蛇形转驼峰 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-snake2cameljson-%E5%AF%B9%E8%B1%A1%E5%86%85%E7%9A%84%E5%B1%9E%E6%80%A7%E5%90%8D-%E8%9B%87%E5%BD%A2%E8%BD%AC%E9%A9%BC%E5%B3%B0) +* 2、【新增】`vk.pubfn.camel2snakeJson` 对象内的属性名 - 驼峰转蛇形 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-camel2snakejson-%E5%AF%B9%E8%B1%A1%E5%86%85%E7%9A%84%E5%B1%9E%E6%80%A7%E5%90%8D-%E9%A9%BC%E5%B3%B0%E8%BD%AC%E8%9B%87%E5%BD%A2) +* 3、【新增】`vk.pubfn.snake2camel` 字符串 - 蛇形转驼峰 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-snake2camel-%E5%AD%97%E7%AC%A6%E4%B8%B2-%E8%9B%87%E5%BD%A2%E8%BD%AC%E9%A9%BC%E5%B3%B0) +* 4、【新增】`vk.pubfn.camel2snake` 字符串 - 驼峰转蛇形 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-camel2snake-%E5%AD%97%E7%AC%A6%E4%B8%B2-%E9%A9%BC%E5%B3%B0%E8%BD%AC%E8%9B%87%E5%BD%A2) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.3.4(2021-09-18) +* 1、【优化】一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.3.3(2021-09-16) +* 1、【优化】一些细节问题 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.3.2(2021-09-08) +* 1、【升级】`uni-id` 至 3.3.6 (修复邀请码可能重复的Bug) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.3.1(2021-09-08) +* 1、【优化】一些细节 +* 2、【修复】`user/kh/updateUser` 问题。 +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.3.0(2021-09-06) +* 1、【新增】`vk.baseDao.updateAndReturn` API [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/api.html#%E6%9B%B4%E6%96%B0%E5%B9%B6%E8%BF%94%E5%9B%9E%E6%9B%B4%E6%96%B0%E5%90%8E%E7%9A%84%E6%95%B0%E6%8D%AE-%E5%8E%9F%E5%AD%90%E6%93%8D%E4%BD%9C) +* 2、【新增】`vk.pubfn.getDayOffsetStartAndEnd` 获得相对当前时间的偏移 count 天的起止日期(日的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getdayoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E5%A4%A9%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 3、【新增】`vk.pubfn.getMonthOffsetStartAndEnd` 获得相对当前时间的偏移 count 月的起止日期(月的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getmonthoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E6%9C%88%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 4、【新增】`vk.pubfn.getYearOffsetStartAndEnd`获得相对当前时间的偏移 count 年的起止日期(年的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getyearoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E5%B9%B4%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 5、【新增】`vk.pubfn.sleep` 进程等待(主要用于在云函数中需要故意等待几秒的情况)[点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-sleep-%E8%BF%9B%E7%A8%8B%E5%BC%BA%E5%88%B6%E7%AD%89%E5%BE%85-%E4%BC%91%E7%9C%A0) +* 6、【新增】`app.config.js` 新增参数 `globalErrorCode` 可以修改全局异常的提示信息 [点击查看](https://vkdoc.fsq.pub/client/pages/config.html) +* 7、【新增】`javascript代码块提示.json` 最近新增的api的代码提示 [点击查看](https://vkdoc.fsq.pub/client/codeTips.html) +* 8、【优化】`vk.baseDao.selects`新增参数`addFields` [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/question.html#%E5%88%86%E7%BB%84count) +* 9、【优化】`vk.pubfn.timeFormat` 等API,当参数time为字符串时间戳时的特殊处理 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-timeformat-%E6%97%A5%E6%9C%9F%E6%A0%BC%E5%BC%8F%E5%8C%96) +* 10、【修复】腾讯云的图片上传无法回显图片的问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.2.4(2021-08-06) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 【优化】一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.2.3(2021-08-05) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【修复】因`uni-id`配置隔离导致的微信`vk.openapi.weixin` API 兼容性问题。 +#### 2、【新增】`vk.pubfn.isArray` 判断变量是否是数组类型 +#### 3、【新增】`vk.pubfn.isObject` 判断变量是否是对象类型 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.2.2(2021-08-04) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`uni-id` 至 `3.3.3` + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.2.1(2021-08-04) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`uni-id` 至 `3.3.2` +#### 2、【新增】云函数内表单验证文档 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4313370&doc_id=975983) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.2.0(2021-07-28) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 【新增】前端 `vk.callFunction` 支持请求其他服务空间的云函数 +```js +const myCloud = uniCloud.init({ + provider: 'aliyun', + spaceId: 'xxxx-yyy', + clientSecret: 'xxxx' +}); +vk.callFunction({ + url: 'template/db_api/pub/count', + title:'请求中...', + unicloud: myCloud, + success(data) { + console.log(data); + } +}); +``` + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.1.7(2021-07-28) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 【新增】前端 `vk.callFunction` 支持请求其他服务空间的云函数 +```js +const myCloud = uniCloud.init({ + provider: 'aliyun', + spaceId: 'xxxx-yyy', + clientSecret: 'xxxx' +}); +vk.callFunction({ + url: 'template/db_api/pub/count', + title:'请求中...', + unicloud: myCloud, + success(data) { + console.log(data); + } +}); +``` + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.1.6(2021-07-22) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【修复】常用的 vk.baseDao `javascript代码块提示`(有部分错误的问题:少,号的问题)(在编辑器输入dao.即可弹出代码提示)[点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4019184&doc_id=975983) +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/fe965ad9-e9ed-44fc-ad0b-5bc286988e09.png) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.1.5(2021-07-22) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【优化】新增常用的 vk.baseDao `javascript代码块提示` (在编辑器输入dao.即可弹出代码提示)[点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4019184&doc_id=975983) +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/fe965ad9-e9ed-44fc-ad0b-5bc286988e09.png) +#### 2、【优化】文档 [查看文档](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=2912167&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.1.4(2021-07-12) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 【修复】已知问题 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.1.3(2021-07-12) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【修复】首次使用框架,上传部署后访问云函数可能会出现 `createInstance is undefined` 的问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.1.2(2021-07-12) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【修复】连表查询时,因`lastWhereJson`而导致`getCount`错误的问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.1.1(2021-07-12) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【修复】连表查询时,因`lastWhereJson`而导致`getCount`错误的问题。 + + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.1.0(2021-07-09) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要调整】删除了`config`公共模块,升级为`uni-config-center`模式 [点击查看升级教程](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4219337&doc_id=975983) +#### 1、【重要调整】删除了`config`公共模块,升级为`uni-config-center`模式 [点击查看升级教程](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4219337&doc_id=975983) +#### 1、【重要调整】删除了`config`公共模块,升级为`uni-config-center`模式 [点击查看升级教程](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4219337&doc_id=975983) + + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.0.8(2021-07-07) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 【修复】已知bug + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +### 如果你觉得框架对你有用,可以在下方进行评论。 + + + +## 2.0.7(2021-06-28) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【修复】`user/kh/getMenu`云函数获取菜单错误的bug。 +#### 2、【修复】db_init.json `opendb-global-data`表`expired_at`索引设置错误 "MgoIsUnique": true 改为 "MgoIsUnique": false(需要把索引删除后重新创建,选择非唯一索引) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +### 如果你觉得框架对你有用,可以在下方进行评论。 + + + +## 2.0.6(2021-06-28) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【优化】`vk.pubfn.timeFormat` 若参数不符合规则,则原值显示。 +#### 2、【优化】`vk.pubfn.random` 新增第三个参数`arr` (产生的随机数不会和此数组的任意一项重复) [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3268613&doc_id=975983) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论。 + + + +## 2.0.5(2021-06-16) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【修复】`vk.baseDao.add` 因hbx 3.1.18版本导致的本地运行时 `_add_time_str` 错误的问题。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论。 + + + +## 2.0.4(2021-06-10) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【新增】`onActionIntercepted`(被中间件拦截时执行) 和 `onActionError`(云函数执行异常时执行) 类型中间件 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3035637&doc_id=975983) +#### 2、【优化】过滤器 `timeFilter`、`dateDiff` 能正确识别10位数时间戳和13位时间戳。[点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3269404&doc_id=975983) +#### 3、【优化】`vk.baseDao.sample` 支持 `fieldJson`参数 [点击查看数据API](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3065608&doc_id=975983) +#### 4、【修复】`返回树状结构`时最后一级子节点没有继承主表`foreignDB`属性的bug。[查询返回树状结构文档](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3906510&doc_id=975983) +#### 5、【优化】`vk.callFunctionUtil.uploadFile` 自动识别文件类型,无需传`fileType`参数 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论。 + +## 2.0.3(2021-05-31) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【新增】`vk.callFunctionUtil.uploadFile` 新增参数 `file`,`needSave` 若needSave=true,则文件URL会保存到数据库。(会显示在admin端的素材管理中) +#### 2、【优化】`vk.baseDao.selects` 和 `vk.baseDao.select` 新增两个属性`getOne` 、 `getMain` [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4054561&doc_id=975983) +#### 3、【修复】`vk.callFunctionUtil.uploadFile` 上传视频时后缀名可能会错误的问题。 +#### 4、【优化】`云函数URL化` 路由模式下,URL重写支持只允许部分云函数可被访问。(可以做到只暴露指定的API接口,增加URL化后的安全性) +#### `router/util/urlrewrite.js`文件配置内容如下 [点击URL重写规则](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3916806&doc_id=975983) +```js +/** + * URL重写 + * 如让 https://xxx.bspapp.com/http/router/aaa 指向云函数 template/db_api/pub/select + */ +module.exports = { + "rule":{ + "^findById/(.+)": "template/db_api/pub/findById?_id=$1", + "^aaa$": "template/db_api/pub/select" + }, + "config":{ + // 当设置为true时,只有符合url重写规则内的云函数才可以被url化访问。 + "accessOnlyInRule":false + } +}; +``` + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.0.2(2021-05-21) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【新增】`vk.callFunctionUtil.uploadFile` 新增参数 `file`,`needSave` 若needSave=true,则文件URL会保存到数据库。(会显示在admin端的素材管理中) +#### 2、【调整】`vk.baseDao.getTableData` 默认排序规则调整为`_id`降序,之前是`_add_time`降序 +#### 3、【优化】`vk.baseDao.getTableData` 和 `vk.baseDao.selects` 连表查询逻辑。 +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.0.1(2021-05-21) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +####【优化】`vk.baseDao` API的查询性能。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.0.0(2021-05-15) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【优化】用户角色权限,支持admin使用 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4003879&doc_id=975983) +#### 2、`vk-unicloud-admin`开发框架已正式上线 +#### 至此,`vk-unicloud` 系列如下,可以满足开发完整系统。 +##### `client端`框架地址:`https://ext.dcloud.net.cn/plugin?id=2204` [点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +##### `admin端`框架地址:`https://ext.dcloud.net.cn/plugin?name=vk-unicloud-admin` [点击查看](https://ext.dcloud.net.cn/plugin?name=vk-unicloud-admin) +##### `client端`框架文档:`https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=2912167&doc_id=975983` [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=2912167&doc_id=975983) +##### `admin端`框架文档:`https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4003875&doc_id=975983` [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4003875&doc_id=975983) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.9.2(2021-04-23) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3541759&doc_id=975983) +#### 2、【重要】【新增】 `pages-dev.json` 机制,写法与`pages.json` 相同,但里面的页面只有运行(开发)环境时才会被HBX打包,发行(正式)环境下不会被HBX打包进去。[点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3928718&doc_id=975983) +```js +可以将一些测试页面写在 `pages-dev.json`内,这些测试页面在正式发布时是不会被HBX打包到源码里的。 +``` +#### 3、【重要】【新增】阿里云和unicloud短信聚合API (阿里云短信的实现不依赖阿里云SDK核心库,无需`npm install @alicloud/pop-core`)[点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/%E4%B8%8A%E4%BC%A0%20%E4%BA%91%E5%82%A8%E5%AD%98%E6%88%96%E9%98%BF%E9%87%8C%E4%BA%91OSS?sort_id=3673784) + +#### 4、【重要】【废弃】原目录`util/smsUtil.js`(使用新的`vk.system.smsUtil.sendSms`聚合短信发送接口,且比之前的写法更优雅) + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 + +## 1.9.1(2021-04-19) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3541759&doc_id=975983) +#### 2、【重要】【全网首家】`云函数url化` 支持以纯链接形式访问路由后的云函数 如: `https://xxx.bspapp.com/http/router/client/user/pub/findGoodsInfo?id=1` +#### 3、【重要】【全网首家】`云函数url化` 支持URL重写 [点击查看URL重写详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3916806&doc_id=975983) +#### 4、【优化】`vk.selects` 支持主表外键是数组的情况下(如`uni-id-users`表的`role`字段)连表查出`roleList` [点击查看场景5](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3028633&doc_id=975983) + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 + +## 1.9.0(2021-04-15) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3541759&doc_id=975983) +#### 2、【重要】`vk.selects` 支持返回树状结构 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3906510&doc_id=975983) +#### 3、【新增】`vk.pubfn.deepClone` 深度克隆(与`vk.pubfn.copyObject`的区别:可以克隆函数) +#### 4、【优化】`vk.setData` 内部逻辑 +#### 5、【优化】`使用帮助/代码快捷提示/javascript代码块提示.json` 代码块有更新 (将文件内的代码复制到 hbx 工具 - 代码块设置 - javascript代码块) + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 + +## 1.8.14(2021-04-13) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3541759&doc_id=975983) +#### 2、【修复】`console.log`在小程序端可能会无法打印出代码所在位置的问题。 +#### 3、【优化】云函数中 `vk.request`新增参数`needOriginalRes` 默认为`false`,若为`true`,则会返回原始数据(包含请求头等数据) +#### 4、【调整】`vk.request`默认的`header`与官方对其(之前默认是`{"content-type": "application/json; charset=UTF-8"}`) +#### 5、【优化】`uni-id` 模式调整为:兼容单实例多并发模式 + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 + +## 1.8.13(2021-04-07) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3541759&doc_id=975983) +#### 2、【优化】`vk.baseDao.selects` 支持`_.geoNear`API(将记录按照离给定点从近到远输出。)[点击查看万能连表场景4](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3028633&doc_id=975983) +``` +官方原生语法中,连表查询和非连表查询在使用`_.geoNear`时用较大差别; +而 vk.baseDao.selects(万能连表)写法跟 vk.baseDao.select(单表查询) 写法保持统一,使上手更简单。 +``` +#### 3、【优化】如需要在云函数中主动抛出异常,且能让前端框架自动识别后进行alert弹窗提示,则可使用以下方式 +```js +// 注意: 必须以msg:为前缀,否则框架无法识别(只支持字符串) +throw new Error("msg:这里是错误的提示"); +``` +#### 4、【新增】`app.config.js` 新增 `tokenExpiredAutoDelete` 属性,默认`true` 若设为`false`,则`token`失效时,依然保留前端的`token缓存`。 + + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 + +## 1.8.12(2021-03-27) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3541759&doc_id=975983) +#### 2、【新增】`百度开放平台API接口` (营业执照识别、身份证识别等) [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3803034&doc_id=975983) +#### 3、【优化】`kh`目录下的函数默认会获取 `userInfo`(当前登录用户信息),如果此云函数不需要用户信息,可以在前端多传一个参数`need_user_info:false` 可以减少一次数据库查询(加快响应速度)(快100ms左右) [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3790840&doc_id=975983) +#### 4、【优化】`returnUserInfoFilter` 过滤器的内部逻辑 +#### 5、【优化】`vk.callFunction` 新增参数 `needAlert`(默认为true) 来代替 `noAlert`(默认为false) 二选一即可(建议后面都使用`needAlert`参数,它更语义化) + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 + +## 1.8.11(2021-03-24) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3541759&doc_id=975983) +#### 2、【新增】`vk.pubfn.timeUtil.isLeapYear` 判断是否是闰年 +#### 3、【新增】`vk.pubfn.timeUtil.isQingming` 判断是否是清明节 +#### 4、【新增】清明节灰色页面实现方案 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3782115&doc_id=975983) +```js +/** + * 判断是否是闰年 + * @params {Number | Date} year 需要计算的年份或时间,默认使用当前时间的年份 + */ +vk.pubfn.timeUtil.isLeapYear(2021); +/** + * 判断是否是清明节 + * @params {Object} date 时间对象 + */ +vk.pubfn.timeUtil.isQingming(new Date()); +``` + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 + +## 1.8.10(2021-03-23) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/1.8%E4%BB%A5%E4%B8%8B%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%E8%87%B31.8%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97%20%E5%8D%87%E7%BA%A7%E6%88%90%20uni_modules%E7%89%88%E6%9C%AC?sort_id=3541759) +#### 2、【优化】新增`app`环境中直接保存用户微信昵称和头像的使用示例。`/pages_template/uni-id/weixin/weixin` +#### 3、【修复】`vuex`储存值为0时,会变成`空字符串`的问题。 + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 + +## 1.8.9(2021-03-20) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】升级至`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/1.8%E4%BB%A5%E4%B8%8B%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%E8%87%B31.8%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97%20%E5%8D%87%E7%BA%A7%E6%88%90%20uni_modules%E7%89%88%E6%9C%AC?sort_id=3541759) +#### 2、【优化】`vk.userCenter.code2SessionWeixin` 的内部逻辑。使之可以正确的和`vk.userCenter.loginByWeixinPhoneNumber` 搭配使用 +#### #### 效果:使用微信手机号一键登录后,同时绑定微信openid和mobile + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 + +## 1.8.8(2021-03-19) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】升级至`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/1.8%E4%BB%A5%E4%B8%8B%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%E8%87%B31.8%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97%20%E5%8D%87%E7%BA%A7%E6%88%90%20uni_modules%E7%89%88%E6%9C%AC?sort_id=3541759) +#### 2、【修复】微信小程序服务端API在保存`token`时,缓存时间错误的问题。 +#### 3、【修复】`vk.callFunctionUtil.uploadFile` 上传视频返回`.png`的问题 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3673784&doc_id=975983) +#### 4、【新增】APP本机号码一键登录API `vk.userCenter.loginByUniverify` +```js +示例页面:/pages_template/uni-id/univerify/univerify +``` + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 + +## 1.8.7(2021-03-19) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】升级至`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/1.8%E4%BB%A5%E4%B8%8B%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%E8%87%B31.8%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97%20%E5%8D%87%E7%BA%A7%E6%88%90%20uni_modules%E7%89%88%E6%9C%AC?sort_id=3541759) +#### 2、【优化】在安装了`vuex`后,移除了名为`uni_id_user_info`的本地缓存(重复了)(`userInfo`使用`vk.getVuex('$user.userInfo')`获取) +#### 3、【修复】微信小程序服务端API在获取`token`时,没有正确使用缓存的问题。 +#### 4、【新增】APP本机号码一键登录API `vk.userCenter.loginByUniverify` +```js +示例页面:/pages_template/uni-id/univerify/univerify +``` + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 + +## 1.8.6(2021-03-12) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】升级至`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/1.8%E4%BB%A5%E4%B8%8B%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%E8%87%B31.8%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97%20%E5%8D%87%E7%BA%A7%E6%88%90%20uni_modules%E7%89%88%E6%9C%AC?sort_id=3541759) +#### 2、【重要】现在可以在js文件中直接通过 `uni.vk` 来使用 `vk` 对象内的API +#### 3、【新增】`app.config.js` 新增参数 `checkSharePages` 控制页面是否可以被小程序分享 +#### 4、【优化】发行模式下,`console.log` 将不会打印任何日志。 +```js +若发行模式下需要强制打印,可用 `vk.log` 代替 `console.log` +``` +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 +## 1.8.5(2021-03-10) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】升级至`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/1.8%E4%BB%A5%E4%B8%8B%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%E8%87%B31.8%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97%20%E5%8D%87%E7%BA%A7%E6%88%90%20uni_modules%E7%89%88%E6%9C%AC?sort_id=3541759) +#### 2、【新增】`vk.callFunctionUtil.uploadFile` 支持前端直传至`阿里云oss` [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3673784&doc_id=975983) +#### 3、【新增】`app.config.js` 新增 `myfn` 参数,可用来拓展自定义公共函数 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3673929&doc_id=975983) + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 + +## 1.8.4(2021-03-06) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】升级至`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/1.8%E4%BB%A5%E4%B8%8B%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%E8%87%B31.8%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97%20%E5%8D%87%E7%BA%A7%E6%88%90%20uni_modules%E7%89%88%E6%9C%AC?sort_id=3541759) +#### 2、【新增】`vk.openapi.weixin.subscribeMessage.send` 微信小程序发送订阅消息 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3569379&doc_id=975983) +``` +示例页面:/pages_template/openapi/weixin/sendMessage/sendMessage +``` +#### 3、【优化】`vk.baseDao.add` 和 `vk.baseDao.adds` 新增参数 `cancelAddTime` 为`true`,则不会有`_add_time`和`_add_time_str`字段生成 +#### 4、【优化】`vk.baseDao.add` 和 `vk.baseDao.adds` 支持添加自定义 `_id` +#### 5、【优化】`vk.setVuex` 和 `vk.setData` 的赋值逻辑 +``` +需替换:/store/index.js 文件 +``` +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 +## 1.8.3(2021-03-04) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】升级至`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/1.8%E4%BB%A5%E4%B8%8B%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%E8%87%B31.8%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97%20%E5%8D%87%E7%BA%A7%E6%88%90%20uni_modules%E7%89%88%E6%9C%AC?sort_id=3541759) +#### 2、【重要】`vuex` 的使用方式有较大更新。(有性能提升)[点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3654596&doc_id=975983) + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 +## 1.8.2(2021-03-01) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】升级至`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/1.8%E4%BB%A5%E4%B8%8B%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%E8%87%B31.8%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97%20%E5%8D%87%E7%BA%A7%E6%88%90%20uni_modules%E7%89%88%E6%9C%AC?sort_id=3541759) +#### 2、【修复】`vk.baseDao.deleteById` 会报`vk is not defined`的错误。 +#### 3、【重要】公共模块`config` 的默认`passwordSecret`和`tokenSecret`调整为与`uni-id`默认`config`一致 +```js +`tokenSecret`一致的好处:兼容clientDB +注意:如您目前的项目已上线,请谨慎修改passwordSecret(tokenSecret已上线的项目也可以修改)。 +``` +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 +## 1.8.1(2021-02-23) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】升级至`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/1.8%E4%BB%A5%E4%B8%8B%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%E8%87%B31.8%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97%20%E5%8D%87%E7%BA%A7%E6%88%90%20uni_modules%E7%89%88%E6%9C%AC?sort_id=3541759) +#### 2、【优化】`vk.baseDao.selects` 支持副表与副表的副表进行连表 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3028633&doc_id=975983) +``` +1.1、支持无限张副表和主表进行连接(横向无限张表) +1.2、支持副表与副表的副表进行连接(竖向无限层连接) +``` +#### 3、【新增】微信小程序服务端API [点击查看文档](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3569379&doc_id=975983) + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 + +## 1.8.0(2021-02-07) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】升级至`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/1.8%E4%BB%A5%E4%B8%8B%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%E8%87%B31.8%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97%20%E5%8D%87%E7%BA%A7%E6%88%90%20uni_modules%E7%89%88%E6%9C%AC?sort_id=3541759) +#### 2、【重要】本次更新文件有重大改动,升级成功后将变成`uni_modules`版本,下次更新框架只需要在hbx编译器中一键更新。 +#### 3、【新增】【小程序API】`vk.userCenter.loginByWeixinPhoneNumber` 前端可以使用微信小程序一键进行手机号登录 +#### 4、【新增】【小程序API】`vk.userCenter.getPhoneNumber` 前端一键获取微信小程序绑定的手机号 +#### 5、【新增】【小程序API】`vk.openapi.weixin.decrypt.getPhoneNumber` 云函数解析微信小程序绑定的手机号 +#### 6、【新增】【小程序API】`vk.userCenter.getWeixinMPqrcode` 前端一键生成带参数的小程序码 +#### 7、【新增】【小程序API】`vk.userCenter.getWeixinMPscheme` 前端一键生成带参数的小程序scheme码(支持从手机短信跳转到小程序) +#### 8、【优化】`middleware/modules/returnUserInfoFilter` 中间件的处理逻辑。 +#### 9、【优化】`javascript代码块提示.json` 输入`vk.`可以快速提示代码块 `根目录/使用帮助/代码快捷提示` + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 diff --git a/changelog.new.md b/changelog.new.md new file mode 100644 index 0000000..9268594 --- /dev/null +++ b/changelog.new.md @@ -0,0 +1,8 @@ +* 【修复】`短信发送` 接口当uni-id配置成多端隔离(数组形式)会报错的bug +* 【修复】`vk.importObject` 部分情况下会报错的问题 +* 【优化】如果当前运行的微信小程序是体验版,但没有点HBX的【发行】菜单发布,则提示开发者请点【发行】按钮 +* 【优化】`$hasRole`函数的功能 [传送门](https://vkdoc.fsq.pub/client/jsapi.html#hasrole) +* 【优化】`vk.pubfn.timeFormat` 支持显示时区,完整格式为 `yyyy-MM-ddThh:mm:ssZ` +* 【优化】其他细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 \ No newline at end of file diff --git a/common/css/app.scss b/common/css/app.scss new file mode 100644 index 0000000..d1128a0 --- /dev/null +++ b/common/css/app.scss @@ -0,0 +1,28 @@ +/* 这里是你自己写的全局css样式 */ +@import "@/common/css/common.css"; +/* #ifdef H5 */ +.uni-mask, +.uni-modal, +uni-toast, +uni-modal, +.uni-actionsheet { + z-index: 999999 !important; +} +/* #endif */ + + +/* 改变主题色变量 */ +$--color-primary: #A92924; + +/* 改变 icon 字体路径变量,必需 */ +$--font-path: '~element-ui/lib/theme-chalk/fonts'; + +@import "~element-ui/packages/theme-chalk/src/index"; + +.el-input.is-disabled .el-input__inner { + color: #333333 !important; +} + +.vk-data-form .bar-title{ + display: block; +} \ No newline at end of file diff --git a/common/css/common.css b/common/css/common.css new file mode 100644 index 0000000..bab411b --- /dev/null +++ b/common/css/common.css @@ -0,0 +1,2075 @@ +/* CSS Document */ +/*去除浏览器默认样式*/ +* { + box-sizing: border-box; + border: 0; + padding: 0; + margin: 0; +} + +.layui-carousel-arrow { + border-radius: 0 !important +} + +* { + margin: 0; + padding: 0; + font-family: -apple-system, BlinkMacSystemFont, PingFang SC, Hiragino Sans GB, Roboto, Arial, Microsoft YaHei, sans-serif; + /* color: #333; */ +} + +* { + margin: 0px; + padding: 0px; + border: none; + outline: none; +} + +address, caption, cite, code, dfn, em, th, var, i, b { + font-style: normal; + font-weight: normal; +} + +*:before, *:after { + box-sizing: border-box; +} + +*, *:before, *:after { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +html, body, div, p, ul, li, dl, dt, dd, h1, h2, h3, h4, h5, h6, form, input, select, .button, textarea, iframe, table, th, td { + margin: 0; + padding: 0; +} + +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button{ + -webkit-appearance: none !important; +} +input[type="number"]{ + -moz-appearance:textfield; +} + +img { + border: 0 none; + vertical-align: top; +} +.button{ + cursor: pointer; + text-align: center; + vertical-align: middle; + display: table-cell; +} +body, input, select, .button, textarea { + font-size: 13px; +} + +textarea:disabled { + cursor: not-allowed; +} + +li { + list-style: none; +} + +.arial { + font-family: arial; +} + +.song { + font-family: "\5b8b\4f53"; +} + +input[type=button], input[type=submit], input[type=reset] { + cursor: pointer +} + +button { + cursor: pointer +} + +input[type=text], input[type=password], input[type=file], textarea { + -webkit-border-radius: 0; + -webkit-appearance: normal +} + +textarea { + overflow: auto; + resize: none +} + +body { + background: #f4f4f4; + color: #000; + line-height: 1.5; + margin: 0 auto; + width: 100%; +} + +html { + -webkit-text-size-adjust: none; +} + +a { + color: #646464; + text-decoration: none; +} + +a * { + *cursor: pointer +} + +a { + blr: expression(this.onFocus=this.blur()); +} + +a:hover { + text-decoration: none !important; + outline: none; +} + +a:focus { + outline: none; +} + +.fixed:after, .clearfix:after, .cf:after { + content: "."; + display: block; + clear: both; + height: 0; + visibility: hidden; + overflow: hidden +} + +.fixed, .clearfix, .cf { + zoom: 1 +} + +.clear:after, .global-clearfix:after { + content: ""; + display: block; + visibility: hidden; + height: 0; + clear: both; +} + +.clearfix:after { + content: "."; + display: block; + height: 0; + clear: both; + visibility: hidden; + font-size: 0; + line-height: 0; +} + +.clearfix { + *zoom: 1; +} + +.clear, .global-clearfix { + zoom: 1; +} + +.fl, .fr { + display: inline; + float: left; +} + +.fr { + float: right +} + +.center { + text-align: center; +} + +.hidden02 { + display: none; +} + +table { + border-collapse: collapse; + border-spacing: 0 +} + +caption, th { + text-align: left +} + +th { + font-weight: normal +} + + +a { + blr: expression(this.onFocus=this.blur()) +} + +a * { + *cursor: pointer +} + +:focus { + outline: none +} + +i { + font-style: normal; +} + +img { + overflow: hidden; +} + +body { + min-width: 1200px; + word-wrap: break-word; + color: #000; +} + +.group-wagbar { + height: 32px; + background: #fafafa; + position: relative; + z-index: 99; + border-bottom: 1px solid #f1f1f1; + line-height: 1.5; + color: #656565; + font-size: 12px; + font-family: -apple-system, BlinkMacSystemFont, Hiragino Sans GB, Microsoft YaHei, sans-serif; +} + +.group-wagbar .group-inner { + width: 1200px; + margin: 0 auto; +} + +.mod-welcome { + display: inline-block; + font-size: 0; +} + +.mod-welcome .app-download { + position: relative; + margin: 0 16px 0 10px; + padding-left: 20px; + height: 32px; + line-height: 32px; + color: #656565; + display: inline-block; + vertical-align: middle; + font-size: 12px; +} + +.group-wagbar .group-inner a { + color: #656565; +} + +.mod-welcome .welcome-item { + display: inline-block; + height: 32px; + line-height: 32px; + vertical-align: middle; + font-size: 12px; +} + +.mod-welcome .slogan { + margin-right: 10px; +} + +.mod-welcome .welcome-item.login-register { + +} + +.mod-welcome .login { + margin-right: 8px; +} + +.mod-welcome .login, .mod-welcome .register { + font-size: 12px; +} + +.group-wagbar .group-inner a, .mod-tools a, a, a:hover { + text-decoration: none; +} + +.group-wagbar .group-inner a.login, .group-wagbar .group-inner a:hover, .mod-welcome .welcome-item .menu-bd .user-info.active .name, .mod-welcome .welcome-item .menu-bd.show .user-info .name { + color: #a92924; +} + +.group-wagbar .group-inner a { + color: #656565; +} + +.mod-tools { + float: right; +} + +ol, ul { + list-style: none; +} + +.mod-tools .tool-item { + position: relative; + text-align: center; + height: 32px; +} + +.mod-tools li { + float: left; +} + +.mod-tools .bar-title { + display: block; + height: 32px; + line-height: 32px; + color: #959595; + padding: 0px 10px; + position: relative; +} + +.group-wagbar .group-inner a, .mod-tools a, a, a:hover { + text-decoration: none; +} + +.wag-icon, em, i { + font-style: normal; +} + +.mod-tools .bar-title i { + -webkit-transition: -webkit-transform .3s; + -o-transition: transform .3s; + transition: transform .3s; + transition: transform .3s, -webkit-transform .3s; + background: url(/static/images/dowm.png) 50% no-repeat; + -webkit-background-size: contain; + background-size: contain; + display: inline-block; + width: 10px; + height: 4px; + margin-left: 7px; + vertical-align: 2px; +} + +.mod-tools .bar-content { + display: none; + position: absolute; + top: 32px; + right: 0; + width: 100%; + padding: 12px 0; + background: #fff; + -webkit-box-shadow: 0 0 16px 0 hsla(0, 0%, 77.3%, .5); + box-shadow: 0 0 16px 0 hsla(0, 0%, 77.3%, .5); + text-align: left; +} + +.mod-tools .bar-content dd { + height: 32px; + line-height: 32px; + text-align: center; +} + +.mod-tools .bar-content dd a { + display: block; + padding: 0 8px; +} + +.mod-tools .bar-content a { + color: #656565; +} + +.mod-tools .bar-title:hover { + color: #a92924 +} + +.mod-tools .tool-item:hover { + z-index: 3; + -webkit-box-shadow: 0 0 16px 0 hsla(0, 0%, 77.3%, .5); + box-shadow: 0 0 16px 0 hsla(0, 0%, 77.3%, .5); +} + +.mod-tools .tool-item:hover .bar-title i { + background-image: url(/static/images/dowm2.png); + -webkit-transform: rotate(-180deg); + -ms-transform: rotate(-180deg); + transform: rotate(-180deg); +} + +.mod-tools .tool-item:hover .bar-title { + background: #fff; + z-index: 1; + color: #a92924; +} + +.mod-tools .tool-item:hover .bar-content { + display: block; +} + +.mod-tools .bar-content dd a:hover { + background: #f5f5f5; +} + +.mod-tools .bar-content a:hover { + color: #a92924; +} + +.tool-item2 span { + background: url(/static/images/icon1.png) left center no-repeat; + padding-left: 25px; + display: block; + background-size: 17px; +} + +h1, h2, h3, h4, h5 { + font-weight: 400; +} + +.bar-head { + transition: top .3s ease-out; +} + +.group-head { + width: 100%; + position: relative; + z-index: 98; + background: #fff; + color: #656565; + font-family: -apple-system, BlinkMacSystemFont, Hiragino Sans GB, Microsoft YaHei, sans-serif; + transition: top .3s ease-out; +} + +.group-head.sticky { + position: fixed; + z-index: 29899; + left: 0; + top: 0; + width: 100%; + -webkit-animation: slowDown-data-v-707b4ed9 .4s ease-in-out; + animation: slowDown-data-v-707b4ed9 .4s ease-in-out; + background-color: #fff; + box-shadow: 0 2px 10px rgba(0, 0, 0, .2); +} + +.group-head { + position: relative; + z-index: 98; + background: #fff; + line-height: 1.5; + color: #656565; + font-size: 12px; + font-family: -apple-system, BlinkMacSystemFont, Hiragino Sans GB, Microsoft YaHei, sans-serif; + -webkit-transition: top .3s ease-out; + -o-transition: top .3s ease-out; + transition: top .3s ease-out; +} + +.group-head .group-inner { + width: 1200px; + margin: 0 auto; + margin-bottom: 15px; +} + +.mod-logo { + height: 100%; + float: left; + +} + +.group-head .group-inner a { + color: #656565; + text-decoration: none; +} + +.mod-logo .logo { + display: block; + width: 250px; + margin-top: 20px; +} + +.mod-logo .logo img { + height: 82px; + max-width: 100%; +} + +.mod-mini-search { + float: left; + margin: 18px 0 0 60px; + width: 505px; + position: relative; + z-index: 1; + box-sizing: border-box; + transition: top .3s ease-out; +} + +.mod-menu { + float: left; + line-height: 60px; +} + +.mod-menu .hrd { + position: relative; + float: left; + margin: 30px 0 0 16px; + display: inline-block; + border-radius: 2px; +} + +.mod-mini-search .mod-hot-query { + white-space: nowrap; + overflow: hidden; + font-size: 0; +} + +.mod-mini-search .mod-hot-query li { + display: inline-block; + padding: 5px 8px; + font-size: 12px; +} + +.group-head .group-inner a { + color: #656565; + text-decoration: none; +} + +.hrd-landing img { + height: 19px; + width: 194px; + display: block; + vertical-align: middle; + text-align: center; + margin-top: 30px; +} + +.hrd-landing { + height: 33px; + display: block; + vertical-align: middle; + text-align: center; + line-height: 33px; +} + +.group-head:not(.fixed):not(.top) .mod-download-icon { + float: right; + margin: 15px 0px 0 0; +} + +.group-head .mod-download-icon .download { + display: block; +} + +.group-head:not(.fixed):not(.top) .mod-download-icon .download { + padding-top: 0px; + margin: 0 auto; +} + +.group-nav { + background: #fff; +} + +.first-level-nav { + border-bottom: 2px solid #a92924; +} + +.group-nav .mod-nav .first-level-nav ul { + margin: 0 auto; + padding-left: 0px; +} + +.group-nav .mod-nav .navigation-bottom { + width: 1200px; + height: 40px; + margin: 0px auto; +} + +.group-nav .mod-nav ul li { + position: relative; +} + +.group-nav .linkNav ul li .nav, .group-nav .linkNav ul li a { + display: block; + font-size: 15px; + line-height: 40px; + color: #353535; + font-weight: 400; +} + +.group-nav .mod-nav .first-level-nav ul li.nav.act a, .second-level-nav .sub-nav-wraper .sub-nav a:hover, .second-level-nav .sub-nav-wraper .sub-nav.act a { + color: #a92924; +} + +.group-nav .mod-nav .entry, .login-info { + float: right; + width: 209px; + overflow: hidden; + position: relative; + text-align: center; +} + +.group-nav .mod-nav .entry .entry-link { + width: 100%; + height: 32px; + vertical-align: middle; + line-height: 32px; + padding: 0; + font-size: 16px; + font-weight: 300; + color: #fff; +} + +.group-nav .mod-nav .entry .entry-link img { + vertical-align: middle; + display: block; + height: 18px; + line-height: 32px; + margin-top: 10px; + width: 172px; +} + +.group-nav .mod-nav ul li.nav a:hover { + color: #a92924; + background: #fdf1f1 +} + +.group-head .group-inner a:hover { + color: #a92924; + text-decoration: none +} + + +.group-nav .mod-nav ul li.nav .navigator:hover { + color: #a92924; + background: #fdf1f1 +} + +.group-head .group-inner .navigator:hover { + color: #a92924; + text-decoration: none +} +.navigation-wrap * { + box-sizing: border-box; +} + +.navigation-top .searchBar .searchBar-tab { + overflow: hidden; + +} + +.navigation-top .searchBar .searchBar-tab li { + padding: 5px 10px; + float: left; + cursor: pointer; +} + +.navigation-top .searchBar .button { + float: left; + width: 90px; + height: 36px; + line-height: 36px; + background: #d0111b; + border: 0; + color: #fff; + font-size: 14px; + cursor: pointer; + outline: none; +} + +.navigation-top .searchBar .preventButton { + position: absolute; + z-index: -1000; + top: -1000px; +} + + + +.navigation-top .searchBar .searchBar-input .searchBar-input-list { + position: absolute; + width: 100%; + max-height: 258px; + overflow: auto; + z-index: 22; + background: #fff; + border: 1px solid #dbdbdb; + overflow: auto; + box-shadow: 0 0 15px rgba(0, 0, 0, 0.1); +} + +.navigation-top .searchBar .searchBar-input input { + width: 390px; + height: 36px; + border: 2px solid #d0111b; + border-right: 0; + padding: 0 10px; + font-size: 13px; + outline: none; +} + +button, input, select, textarea { + font-size: 100%; +} + +.navigation-top .searchBar .searchBar-tab li { + padding: 5px 10px; + float: left; + cursor: pointer; + font-size: 14px; +} + +.navigation-top .searchBar .searchBar-tab li.active { + background: #d0111b; + color: #fff; +} + +.navigation-top .searchBar .searchBar-input { + + position: relative; +} + +.searchBar-input-inner { + float: left; +} + +.navigation-bottom .classification { + float: left; + width: 220px; + height: 40px; + cursor: pointer; + position: relative; +} + +.navigation-bottom .linkNav { + float: left; + width: 760px; + overflow: hidden; +} + +.navigation-bottom .classification .classification-text { + line-height: 42px; + color: #fff; + font-size: 15px; + text-align: center; + background: #a92924; +} + +.icon-nav-menu { + width: 36px; + height: 34px; + vertical-align: middle; + margin-right: 15px; +} + +.icon-nav { + display: inline-block; + background: url(/static/images/icon2.png) no-repeat center center; +} + +.navigation-bottom .linkNav ul li { + -webkit-box-flex: 1; + -webkit-flex: 1; + flex: 1; + min-width: 0; + text-align: center; +} + +.group-nav .linkNav ul { + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + align-items: center; + position: relative; + width: 100%; +} + +.slideMain { + position: relative; +} + +#bannerSwiper img { + width: 100%; + overflow: hidden; +} + +.callbacks_nav { + left: 60px; +} + +.callbacks_nav.next { + right: 60px; +} + +#slide .pagination { + position: absolute; + left: 0; + text-align: center; + bottom: 0px; + width: 100%; + z-index: 999; +} + +#slide .swiper-pagination-bullet { + display: inline-block; + width: 10px; + height: 7px; + opacity: 1; + border-radius: 10px; + background: white; + margin: 0 3px; + cursor: pointer; + transition: width 0.3s ease-in-out; +} + +#slide .swiper-pagination-bullet-active { + background: #a92924; + width: 38px; +} + +.slideBannerWrap { + width: 100%; + text-align: center; + position: relative; +} + +#slide .pagination { + margin: 10px 0px; +} + +#slide .arrow-left { + background: url(/static/images/banner_arrow.png) no-repeat left top; + position: absolute; + left: 20px; + top: 50%; + transform: translate(20px, -50%); + width: 70px; + height: 70px; + z-index: 999; + display: none; +} + +#slide .arrow-right { + background: url(/static/images/banner_arrow.png) no-repeat left bottom; + position: absolute; + right: 20px; + top: 50%; + transform: translate(-20px, -50%); + width: 70px; + height: 70px; + z-index: 999; + display: none; +} + +#slideBannerWrap:hover #slide .arrow-right { + display: block; +} + +#slideBannerWrap:hover #slide .arrow-left { + display: block; +} + +.navigation-bottom .classification .banner-left { + width: 220px; + background: #fff; + float: left; + position: relative; + z-index: 101; +} + +.cate-menu { + height: 500px; + overflow: hidden; + width: 100%; +} + +/* rslides */ +.rslides { + position: relative; + list-style: none; + overflow: hidden; + width: 100%; + padding: 0; + margin: 0; +} + +.rslides li { + -webkit-backface-visibility: hidden; + position: absolute; + display: none; + width: 100%; + left: 0; + top: 0; +} + +.rslides li a { + text-align: center; + margin: 0px auto; + height: 365px; + width: 760px; + position: relative; +} + +.rslides img { + display: block; + height: auto; + float: left; + width: 100%; + border: 0; +} + +/*pager*/ +.callbacks_tabs.callbacks1_tabs { + position: absolute; + z-index: 100; + margin-bottom: 0px; + bottom: 10px; + left: 0px; + right: 0px; + text-align: center; + margin: 0px auto; +} + +.callbacks_tabs.callbacks1_tabs li { + display: inline-block; + width: 23px; + height: 8px; + margin-left: 10px; + border-radius: 10px; + background: #fff; + position: relative; +} + +.callbacks_tabs.callbacks1_tabs li.callbacks_here { + width: 45px; + background: #a92924; +} + +.callbacks_tabs.callbacks1_tabs li a { + display: none; +} + +/* Callback example */ +.callbacks_container { + + position: relative; + width: 100%; + max-width: 100%; + text-align: center; +} + +.callbacks { + position: relative; + list-style: none; + overflow: hidden; + width: 100%; + padding: 0; + margin: 0; +} + +.callbacks li { + position: absolute; + width: 100%; + left: 0; + top: 0; +} + +.callbacks img { + display: block; + position: relative; + z-index: 1; + height: auto; + width: 100%; + border: 0; +} + +.callbacks .caption { + display: block; + position: absolute; + z-index: 2; + font-size: 20px; + text-shadow: none; + color: #fff; + background: #000; + background: rgba(0, 0, 0, .8); + left: 0; + right: 0; + bottom: 0; + padding: 10px 20px; + margin: 0; + max-width: none; +} + +.callbacks_nav { + position: absolute; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + top: 50%; + left: 0; + opacity: 0.6; + z-index: 3; + text-indent: -9999px; + overflow: hidden; + text-decoration: none; + height: 61px; + width: 38px; + background: transparent url("/static/images/themes.gif") no-repeat left top; + margin-top: -30px; + display: none; +} + +.callbacks_container:hover .callbacks_nav { + display: block; +} + +.callbacks_nav:active { + opacity: 1.0; +} + +.callbacks_nav.next { + left: auto; + background-position: right top; + right: 0; +} + +.zghome-nav-display { + display: block !important +} + +.part-category-bg { + position: absolute; + height: 20px; + background: #fff; + z-index: 3; + top: 40px; + width: 125px; +} + +.part-category { + position: relative; + width: 100%; + background: #fff; + box-sizing: border-box; +} + +.part-category { + display: block; + box-shadow: 0 0 16px 0 hsla(0, 0%, 77%, .5); +} + +.part-category .cate-menu ul li .cate-menu-icon { + position: absolute; + left: 3px; + top: 14px; + width: 34px; + height: 24px; +} + +.cate-icon-1 { + background: url(/static/images/icon6.png) no-repeat center center; +} +.cate-icon-2 { + background: url(/static/images/icon3.png) no-repeat center center; +} +.cate-icon-3 { + background: url(/static/images/icon4.png) no-repeat center center; +} +.cate-icon-4 { + background: url(/static/images/icon5.png) no-repeat center center; +} +.cate-icon-5 { + background: url(/static/images/icon7.png) no-repeat center center; +} +.cate-icon-6 { + background: url(/static/images/icon19.png) no-repeat center center; +} + + + +.part-category .cate-menu ul li h2 { + margin-bottom: 6px; + font-size: 0; + color: #353535; +} + +.part-category .cate-menu ul li h2 a { + color: #353535; + font-weight: 500; +} + +.part-category .cate-menu ul li h2 .separator, .part-category .cate-menu ul li h2 a { + font-size: 16px; +} + +.cate-menu ul li { + position: relative; + padding: 13px 9px 2px 35px; +} + +.part-category .cate-menu ul li .cate-item { + overflow: hidden; + margin-left: -16px; + font-size: 0; +} + +.part-category .cate-menu ul li .cate-item a, .part-category .cate-menu ul li .cate-item span { + margin: 0 0 0 16px; + line-height: 25px; + display: inline-block; + font-size: 12px; +} + +a:hover { + color: #a92924; +} + +.navigator:hover { + color: #a92924; +} + +.part-category .cate-menu ul li h2 .separator, .part-category .cate-menu ul li h2 a { + font-size: 16px; +} + +.part-category .cate-menu ul li h2 a { + color: #353535; + line-height: 1.5; + font-weight: 500; + display: inline-block; +} + +.part-category .cate-menu ul li.act { + position: relative; + z-index: 1; + -webkit-transition: .1s; + -o-transition: .1s; + transition: .1s; +} + +.part-category .cate-cont { + display: none; + position: absolute; + top: 0; + left: 219px; + width: 725px; + height: 500px; +} + +.part-category .cate-cont.current { + display: block; +} + +.part-category .cate-cont .item-main { + display: none; +} + +.part-category .cate-cont .item-main.current { + display: block; + -webkit-transition: .1s; + -o-transition: .1s; + transition: .1s; + overflow-y: scroll; +} + +.part-category .cate-cont .item-main .part-hot-word { + width: 466px; + height: 432px; + float: left; + margin: 24px 32px; +} + +.part-category .cate-cont .item-main .part-hot-word .item { + margin-bottom: 40px; +} + +.part-category .cate-cont .item-main .part-hot-word .title { + border-bottom: 1px solid #f1f1f1; + padding-bottom: 8px; + margin-bottom: 16px; +} + +.part-category .cate-cont .item-main .part-hot-word .title h2 { + font-size: 14px; + display: inline-block; +} + +.part-category .cate-cont .item-main .part-hot-word .title h2 a { + color: #353535; + font-size: 16px; + font-weight: 700; +} + +.part-category .cate-cont .item-main .part-hot-word .title .more { + float: right; + color: #959595; + font-size: 12px; +} + +.part-category .cate-cont .item-main .part-hot-word .title .more i { + color: #c5c5c5; +} + +.part-category .cate-cont .item-main .part-hot-word .cont { + margin-left: -16px; + overflow: hidden; +} + +.part-category .cate-cont .item-main .part-hot-word .cont a { + display: inline-block; + line-height: 2; + margin: 0 0 3px 16px; + color: #656565; + font-size: 12px; +} + +.part-category .cate-cont .item-main .part-logo-cont { + width: 175px; + height: 500px; + float: right; + background: #fafafa; +} + +.part-category .cate-cont .item-main .part-logo-cont a { + display: block; + height: 240px; + padding: 0px 15px 0px 20px; + overflow: hidden; + position: relative +} + +.part-category .cate-cont .item-main .part-logo-cont a h2 { + line-height: 2; + padding-top: 20px; + color: #333; + text-align: left; + font-size: 16px; +} + +.part-category .cate-cont .item-main .part-logo-cont a p { + text-align: left; + color: #a92924; + font-size: 12px; + margin-bottom: 15px; + height: 60px; + overflow: hidden; +} + +.part-category .cate-cont .item-main .part-logo-cont a:first-child { + border-bottom: 1px solid #ddd +} + +.part-category .cate-cont::-webkit-scrollbar { + display: none; +} +.part-category .cate-cont { + overflow-y: scroll; + background: #fff; + -webkit-box-shadow: 5px 1px 16px 0 hsla(0, 0%, 77.3%, .5); + box-shadow: 5px 1px 16px 0 hsla(0, 0%, 77.3%, .5); +} + +.part-category .cate-menu ul li.act { + -webkit-box-shadow: 0 0 16px 0 hsla(0, 0%, 77.3%, .5); + box-shadow: 0 0 16px 0 hsla(0, 0%, 77.3%, .5); + background: #fff; + z-index: 888 +} + +.part-category .cate-cont .item-main { + position: absolute; + left: 0px; + top: 0px; + opacity: 0.9; + -moz-opacity: 0.9; + filter: alpha(opacity=90); + overflow-y: scroll; +} + +.part-category .cate-cont .item-main .part-hot-word .cont a:hover { + color: #a92924; +} + +.bannerRight { + float: right; + width: 250px; + height: 430px; + margin-top: 0px; + background: #fff; + z-index: 2; + position: relative; +} + +.section-head .section-banner .banner-me .me-login { + height: 111px; + overflow: hidden; +} + +.mod-manage { + width: 220px; + background: #fff; + float: right; + position: relative; + z-index: 3; +} + +.login-head { + text-align: center; +} + +.me-login { + padding: 15px 10px 10px; +} + +.login-head { + width: 100%; + text-align: center; + margin: 0px auto; + margin: 0px 0px 10px; +} + +.login-head img { + height: 33px; + max-width: 100%; +} + +#banner_right_login { + background: url(/static/images/icon8.png) no-repeat 57px center; + display: block; + color: #a92924; + padding-left: 30px; + text-align: center; + width: 100%; + font-size: 14px; + line-height: 30px; +} + +.runlings { + text-align: center; + width: 100%; + font-weight: bold; + color: #000; + font-size: 18px; + line-height: 2; +} + +.me-tab { + margin-bottom: 2px; +} + +.me-tab-text { + height: 28px; + line-height: 28px; + text-align: center; + margin-bottom: 12px; + +} + +.me-tab-text li { + float: left; + text-align: center; + width: 50%; + background: #fff; + + border-width: 0; +} + +.me-tab-text li.active { + background: #fff; + border-color: transparent; +} + +.me-tab-text li a { + display: block; + color: #333; + text-align: center; + font-size: 14px; + border-bottom: 2px solid #fff +} + +.me-tab-text li.active a { + color: #a92924; + border-bottom: 2px solid #a92924 +} + +.me-tab .me-step { + margin-top: 12px; + text-align: center; + font-size: 12px; +} + +.me-tab .me-step dl { + display: block; + text-align: center; + color: #999; + float: left; + width: 33.3%; +} + +.me-tab .me-step dl dt { + height: 31px; + position: relative; +} + +.iconNew { + display: inline-block; + width: 20px; + height: 23px; + vertical-align: middle; + overflow: hidden; +} + +.iconNew-step-arrow { + position: absolute; + left: 63px; + top: 13px; +} + +.iconNew-step-arrow { + width: 16px; + height: 20px; + vertical-align: baseline; +} + +.me-tab-text { + padding: 0px 13px; +} + +.me-tab .me-step dl.dowslf3 { + width: 100%; + position: relative; +} + +.me-tab .me-step dl.dowslf3 i { + float: right; +} + +.iconNew-step-arrow2 { + position: absolute; + right: 25px; + top: 9px; +} + +.me-tab .me-step dl dt img { + max-width: 100%; +} + +.me-tab-content { + height: 190px; + overflow: hidden; + width: 100%; + border-bottom: 1px solid #ddd; + margin-bottom: 16px; +} + +.wartchar { + display: block; + padding: 0px 10px 14px; +} + +.wartcharlist { + text-align: center; + font-size: 13px; + overflow: hidden; + float: left; + width: 50%; +} + +.group-inner3 { + width: 753px; + overflow: hidden; + margin: 10px auto; + text-align: center; +} + +.group-inner3-list { + width: 251px; + text-align: center; + + float: left; + -webkit-transition: all .2s linear; + -o-transition: all .2s linear; + transition: all .2s linear; +} + +.group-inner3-list a { + margin: 0px 4px; + background: #d8edff; + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + align-items: center; + position: relative; + height: 125px; + padding: 8px; + -webkit-transition: all .2s linear; + -o-transition: all .2s linear; + transition: all .2s linear; +} + +.group-inner3-listleft { + -webkit-box-flex: 1; + -webkit-flex: 1; + flex: 1; + min-width: 0; + text-align: left; + font-size: 12px; +} + +.group-inner3-listleft h2 { + font-weight: normal; + line-height: 2; + font-size: 18px; +} + +.group-inner3-listleft p { + font-weight: normal; + font-size: 12px; + text-align: left; +} + +.group-inner3-list:nth-child(1) a { + background: #d8edff +} + +.group-inner3-list:nth-child(2) a { + background: #ffe2e1 +} + +.group-inner3-list:nth-child(3) a { + background: #ffe9ae +} + +.group-inner3-list:nth-child(1) a h2 { + color: #387be1 +} + +.group-inner3-list:nth-child(2) a h2 { + color: #c3534f +} + +.group-inner3-list:nth-child(3) a h2 { + color: #e7a200 +} + +.group-inner3-listright { + height: 99px; + width: 90px; + line-height: 90px; + text-align: center; + vertical-align: middle; + overflow: hide; +} + +.group-inner3-listright img { + vertical-align: middle; + max-width: 100%; +} + +.group-inner3-list:hover a { + -webkit-box-shadow: 0 0 16px 0 hsla(0, 0%, 77.3%, .5); + box-shadow: 0 0 16px 0 hsla(0, 0%, 77.3%, .5); +} + +.group-inner3-list:hover .navigator { + -webkit-box-shadow: 0 0 16px 0 hsla(0, 0%, 77.3%, .5); + box-shadow: 0 0 16px 0 hsla(0, 0%, 77.3%, .5); +} + +.new-w1180 { + width: 1200px; + margin: 0 auto; +} + +.section-title { + text-align: center; + margin: 20px 0; + position: relative; +} + +.section-title .title-topic { + line-height: 48px; +} + +.section-title .line { + border-top: 1px solid #DFDFDF; + position: absolute; + top: 50%; + width: 100%; +} + +.section-title .title-topic img { + vertical-align: middle; + padding: 0 13px; + background: #f4f4f4; + position: relative; + z-index: 1; + height: 29px; +} + +.login-ingon { + background: url(/static/images/icon8.png) left center no-repeat; + padding-left: 24px; + padding-right: 8px; + font-size: 12px; +} + +.page-wrapper { + text-align: center; + margin-top: 35px; + margin-bottom: 12px; +} + +.fe-page { + display: inline-block; +} + +.fe-page { + color: #959595; + font-size: 12px; +} + +.fe-page .fe-page-linkBox, .fe-page .fe-page-operateBox { + float: left; + display: inline; +} + +.fe-page .fe-page-linkBox .fe-page-next.disabled, .fe-page .fe-page-linkBox .fe-page-next.disabled:hover, .fe-page .fe-page-linkBox .fe-page-prev.disabled, .fe-page .fe-page-linkBox .fe-page-prev.disabled:hover { + border-color: #fff; + background: #fff; + color: #e5e5e5; + cursor: default; + border: 1px solid #dadada; +} + +.fe-page .fe-page-linkBox .fe-page-item, .fe-page .fe-page-linkBox .fe-page-next, .fe-page .fe-page-linkBox .fe-page-omit, .fe-page .fe-page-linkBox .fe-page-prev { + float: left; + display: inline; + margin-left: 8px; + padding: 0 6px; + height: 30px; + line-height: 32px; + min-width: 30px; + border: 1px solid #dadada; + background: #fff; + text-align: center; + font-size: 12px; + color: #656565; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} + +.fe-page .fe-page-linkBox .fe-page-item.active, .fe-page .fe-page-linkBox .fe-page-item:hover { + border: 1px solid #a92924; + background: #a92924; + color: #fff; + cursor: pointer; +} + +.fe-page .fe-page-operateBox { + margin-left: 40px; +} + +.fe-page .fe-page-operateBox .fe-page-btn, .fe-page .fe-page-operateBox .fe-page-input, .fe-page .fe-page-operateBox .fe-page-span { + float: left; + display: inline; + height: 32px; + line-height: 32px; +} + +.fe-page .fe-page-operateBox .fe-page-input { + margin-left: 8px; + margin-right: 8px; + border: 1px solid #dadada; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + -o-box-sizing: border-box; + box-sizing: border-box; + width: 64px; + + background: #fff; + text-align: center; + color: #656565; + vertical-align: middle; + outline: 0; +} + +.fe-page .fe-page-operateBox .fe-page-btn { + margin-left: 24px; + padding: 0; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + -o-box-sizing: border-box; + box-sizing: border-box; + width: 64px; + border: 1px solid #dadada; + background: #fff; + color: #656565; + cursor: pointer; +} + +.fe-page .fe-page-operateBox .fe-page-input:focus { + border-color: #a92924; + padding: 0 3px +} + +.YellowPageAdvg { + margin-left: -17px; +} + +.YellowPageAdvg a { + margin-left: 17px; + float: left; + width: 591px; +} + +.mod-popup { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 100002 !important; + overflow: hidden; + display: none; +} + +div.mod-modal { + background: rgba(53, 53, 53, .6); +} + +.mod-modal { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + background: #000; + opacity: .5; + z-index: 100001; + display: none; +} + +.mod-popup .mod-dialog { + position: absolute; + left: 50%; + top: 50%; + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-transform: translateX(-50%) translateY(-50%); + transform: translateX(-50%) translateY(-50%); + border: 2px; + background: #fff; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, .3); + box-shadow: 0 1px 3px rgba(0, 0, 0, .3); +} + +.component-dialog { + width: 484px; + box-sizing: border-box; +} + +.auth-dialog .component-dialog-title, .common-seller-dialog .component-dialog-title, .trans-period-dialog .component-dialog-title { + font-size: 14px; + color: #656565; +} + +.component-dialog .title-content { + position: relative; + height: 48px; + line-height: 48px; +} + +.component-dialog .icon { + display: inline-block; + background: url(/static/images/new2x.png) center center no-repeat; + background-size: 222px 72px; + background-position: -84px; +} + +.component-dialog .icon.icon-close { + position: absolute; + right: 32px; + top: 17px; + width: 14px; + height: 14px; + background-position: 0 0; + cursor: pointer; +} + +.component-btn { + width: 100%; + margin: 0 auto; + overflow: hidden; + padding: 0 32px; + box-sizing: border-box; + text-align: center; +} + +.component-btn.confirm .HRtext { + color: #fff; + background: #a92924; + position: relative; + height: 40px; + line-height: 40px; + display: inline-block; + width: 165px; + margin-bottom: 30px; + text-align: center; + font-size: 15px; + font-weight: 300; + border: 1px solid #a92924; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.component-dialog .icon.icon-v2 { + width: 64px !important; + height: 64px !important; + text-align: center; + margin: 0px auto; + display: block; + +} + +.component-dialog-title { + position: relative; + height: 48px; + line-height: 48px; + width: 100%; + margin: 0 auto; + overflow: hidden; + padding: 0 32px; + box-sizing: border-box; +} + +.coopart-goods { + width: 100%; + border-top: 1px solid #f1f1f1; + padding-top: 30px; + margin: 34px auto 32px; +} + +.auth-dialog .tips { + margin-top: 16px; + font-size: 18px; + font-weight: 500; + text-align: center; +} + +.auth-dialog .sub-tips, .auth-dialog .tips { + line-height: 2; + color: #353535; +} + +/*图片弹窗*/ +.imgtc { + cursor: pointer; + position: fixed; + width: 100%; + height: 100%; + overflow: hidden; + text-align: center; + top: 0px; + left: 0; + display: none; + z-index: 11111; + background: rgba(255, 255, 255, .8); +} + +.imgtc img { + width: auto; + max-width: 360px; + max-height: 360px; + height: auto; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); +} + +input:disabled { + cursor: not-allowed; +} + +.layui-input { + font-size: 12px; +} + +.layui-form-select dl dd { + font-size: 12px; +} + +.layui-carousel-ind ul { + display: none !important; +} + +.pagination { + float: left; + display: inline; +} + +.pagination li { + float: left; + display: inline; + margin-left: 8px; + padding: 0 6px; + height: 30px; + line-height: 32px; + min-width: 30px; + border: 1px solid #dadada; + background: #fff; + text-align: center; + font-size: 12px; + color: #656565; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} + +.pagination li a { + display: block; +} + +.pagination li:hover { + border: 1px solid #a92924; + background: #a92924; + color: #fff; + cursor: pointer; +} + +.pagination li:hover a { + color: #fff; +} + +.pagination li.active { + border: 1px solid #a92924; + background: #a92924; + color: #fff; + cursor: pointer; +} + +.pagination li.active span { + color: #fff; +} + +.pagination li.disabled { + border-color: #fff; + background: #fff; + color: #e5e5e5; + cursor: default; + border: 1px solid #dadada; +} + +.agreement_dialogs { + position: fixed; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; + width: 100%; + height: 100%; + z-index: 19891017; + text-align: center; + display: none; + background-color: rgba(35, 35, 35, 0.4); + -webkit-transition: all 0.5s linear; + transition: all 0.5s linear; +} + +.agreement_dialogs .dialog_lay_1syd { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + display: inline-block; + width: 750px; + color: #656565; + font-size: 12px; + line-height: 20px; + background-color: #fff; + text-align: left; + vertical-align: middle; + -webkit-transition: all 0.2s linear; + transition: all 0.2s linear; +} + +.agreement_dialogs .dialog_foot_1hHfr { + height: 80px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + border-top: 1px solid #d5d5d5; + margin: 0; + text-align: center; +} + +.agreement_dialogs .dialog_minorBtn_1u8nf { + display: inline-block; + -webkit-box-sizing: border-box; + box-sizing: border-box; + border: 1px #316ccb solid; + padding: 0 30px; + height: 40px; + background: #a92924; + background: linear-gradient(90deg, #f0242e, #d0111a); + line-height: 40px; + cursor: pointer; + font-size: 16px; + vertical-align: top; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + color: #fff; + border-color: #fff; +} + +.agreement_titley { + height: 55px; + line-height: 55px; + font-size: 16px; + color: #666; + text-align: center; + border-bottom: 1px solid #d5d5d5; + font-weight: 400; +} + +.agreement_content { + padding: 23px 32px; +} + +.con-subhead { + font-size: 14px; + + font-weight: 500; + color: #333; + margin-bottom: 16px; +} + +.con-content { + height: 240px; + overflow-y: scroll; + line-height: 2; + font-size: 13px; +} + + +.page-nav{ + width: 1200px; + margin: 0px auto; + padding: 20px 0; +} \ No newline at end of file diff --git a/common/css/uni.scss b/common/css/uni.scss new file mode 100644 index 0000000..a7c31fe --- /dev/null +++ b/common/css/uni.scss @@ -0,0 +1,73 @@ +// 这里是uni-app内置的常用样式变量 + +// uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 +// 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App + + +// 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 + +// 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 + + +// 颜色变量 + +// 行为相关颜色 +$uni-color-primary: #007aff; +$uni-color-success: #4cd964; +$uni-color-warning: #f0ad4e; +$uni-color-error: #dd524d; + +// 文字基本颜色 +$uni-text-color:#333; // 基本色 +$uni-text-color-inverse:#fff; // 反色 +$uni-text-color-grey:#999; // 辅助灰色,如加载更多的提示信息 +$uni-text-color-placeholder: #808080; +$uni-text-color-disable:#c0c0c0; + +// 背景颜色 +$uni-bg-color:#ffffff; +$uni-bg-color-grey:#f8f8f8; +$uni-bg-color-hover:#f1f1f1; //点 击状态颜色 +$uni-bg-color-mask:rgba(0, 0, 0, 0.4); // 遮罩颜色 + +// 边框颜色 +$uni-border-color:#e4e7ed; + +// 尺寸变量 + +// 文字尺寸 +$uni-font-size-sm:24rpx; +$uni-font-size-base:28rpx; +$uni-font-size-lg:32rpx; + +// 图片尺寸 +$uni-img-size-sm:40rpx; +$uni-img-size-base:52rpx; +$uni-img-size-lg:80rpx; + +// Border Radius +$uni-border-radius-sm: 4rpx; +$uni-border-radius-base: 6rpx; +$uni-border-radius-lg: 12rpx; +$uni-border-radius-circle: 50%; + +// 水平间距 +$uni-spacing-row-sm: 10px; +$uni-spacing-row-base: 20rpx; +$uni-spacing-row-lg: 30rpx; + +// 垂直间距 +$uni-spacing-col-sm: 8rpx; +$uni-spacing-col-base: 16rpx; +$uni-spacing-col-lg: 24rpx; + +// 透明度 +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 + +// 文章场景相关 +$uni-color-title: #2C405A; // 文章标题颜色 +$uni-font-size-title:40rpx; +$uni-color-subtitle: #555555; // 二级标题颜色 +$uni-font-size-subtitle:36rpx; +$uni-color-paragraph: #3F536E; // 文章段落颜色 +$uni-font-size-paragraph:30rpx; diff --git a/common/function/myPubFunction.js b/common/function/myPubFunction.js new file mode 100644 index 0000000..87a7a33 --- /dev/null +++ b/common/function/myPubFunction.js @@ -0,0 +1,15 @@ +/** + * 自定义公共函数 + */ +var myfn = {}; +/** + * 测试函数test1 + * vk.myfn.test1(); + */ +myfn.test1 = function(obj = {}) { + let vk = uni.vk; + console.log("执行了自定义公共函数test1"); + return obj; +}; + +export default myfn; diff --git a/components/category-bar/category-bar.vue b/components/category-bar/category-bar.vue new file mode 100644 index 0000000..7cb5d05 --- /dev/null +++ b/components/category-bar/category-bar.vue @@ -0,0 +1,320 @@ + + + + + \ No newline at end of file diff --git a/components/common-footer/common-footer.vue b/components/common-footer/common-footer.vue new file mode 100644 index 0000000..efb44ff --- /dev/null +++ b/components/common-footer/common-footer.vue @@ -0,0 +1,20 @@ + + + + + \ No newline at end of file diff --git a/components/common-header/common-header.vue b/components/common-header/common-header.vue new file mode 100644 index 0000000..91a804a --- /dev/null +++ b/components/common-header/common-header.vue @@ -0,0 +1,117 @@ + + + + + \ No newline at end of file diff --git a/components/custom-form-section/custom-form-section.vue b/components/custom-form-section/custom-form-section.vue new file mode 100644 index 0000000..b80e789 --- /dev/null +++ b/components/custom-form-section/custom-form-section.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/components/page-nav/page-nav.vue b/components/page-nav/page-nav.vue new file mode 100644 index 0000000..b93dc5c --- /dev/null +++ b/components/page-nav/page-nav.vue @@ -0,0 +1,20 @@ + + + + + \ No newline at end of file diff --git a/components/right-bar/right-bar.vue b/components/right-bar/right-bar.vue new file mode 100644 index 0000000..3a104e7 --- /dev/null +++ b/components/right-bar/right-bar.vue @@ -0,0 +1,180 @@ + + + + + \ No newline at end of file diff --git a/components/top-bar/top-bar.vue b/components/top-bar/top-bar.vue new file mode 100644 index 0000000..642dc70 --- /dev/null +++ b/components/top-bar/top-bar.vue @@ -0,0 +1,138 @@ + + + + + \ No newline at end of file diff --git a/components/vk-data-input-editor/vk-data-input-editor.vue b/components/vk-data-input-editor/vk-data-input-editor.vue new file mode 100644 index 0000000..f5fcb3e --- /dev/null +++ b/components/vk-data-input-editor/vk-data-input-editor.vue @@ -0,0 +1,1005 @@ + + + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..1e33b82 --- /dev/null +++ b/index.html @@ -0,0 +1,22 @@ + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 0000000..f379376 --- /dev/null +++ b/main.js @@ -0,0 +1,60 @@ + + + + +import Vue from 'vue' +import App from './App' +import store from './store' +import config from '@/app.config.js' + +// 引入 elementUI +import elementUI from "element-ui"; +// import 'element-ui/lib/theme-chalk/index.css'; +Vue.use(elementUI); + +// 引入 高性能表格UI 组件 +import UmyUi from 'umy-ui' +import 'umy-ui/lib/theme-chalk/index.css'; +Vue.use(UmyUi); + +// 引入 vk 实例 +import vk from 'uni_modules/vk-unicloud'; +Vue.use(vk); + +// 初始化 vk框架 +Vue.prototype.vk.init({ + Vue, // Vue实例 + config, // 配置 +}); + +// 引入 vkAdminUI 组件 +import vkAdminUI from 'vk-unicloud-admin-ui'; +import 'vk-unicloud-admin-ui/theme/index.css'; +Vue.use(vkAdminUI); + +// 自动注册全局组件(必须加在Vue.use(vkAdminUI);的后面) +const modulesFiles = require.context('./components', true, /\.vue$/); +modulesFiles.keys().map((modulePath, index) => { + const moduleNames = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1'); + const moduleSplit = moduleNames.split("/"); + const moduleName = moduleSplit[0]; + if (moduleSplit.length === 2 && moduleName === moduleSplit[1]) { + const value = modulesFiles(modulePath); + let moduleItem = value.default; + Vue.component(moduleName, moduleItem); + } +}); + +// 引入 自定义全局css 样式 +import '@/common/css/app.scss'; + +Vue.config.productionTip = false + +App.mpType = 'app' + + +const app = new Vue({ + store, + ...App +}) +app.$mount() diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..d38bff6 --- /dev/null +++ b/manifest.json @@ -0,0 +1,105 @@ +{ + "name" : "jinjiuxin-mobile", + "appid" : "__UNI__8BFD66E", + "description" : "", + "versionName" : "1.0.0", + "versionCode" : "100", + "transformPx" : false, + "app-plus" : { + "usingComponents" : true, + "nvueCompiler" : "uni-app", + "compilerVersion" : 3, + "splashscreen" : { + "alwaysShowBeforeRender" : true, + "waiting" : true, + "autoclose" : true, + "delay" : 0 + }, + "modules" : {}, + "distribute" : { + "android" : { + "permissions" : [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + "ios" : {}, + "sdkConfigs" : {} + } + }, + "quickapp" : {}, + "mp-weixin" : { + "appid" : "", + "setting" : { + "urlCheck" : false, + "es6" : false, + "postcss" : true, + "minified" : true, + "checkSiteMap" : false + }, + "usingComponents" : true, + "lazyCodeLoading" : "requiredComponents", + "permission" : { + "scope.userLocation" : { + "desc" : "方便自动填写地址" + } + } + }, + "mp-alipay" : { + "usingComponents" : true + }, + "mp-baidu" : { + "usingComponents" : true, + "setting" : { + "urlCheck" : false + } + }, + "mp-toutiao" : { + "usingComponents" : true, + "setting" : { + "urlCheck" : false, + "minified" : true, + "postcss" : true, + "es6" : false + } + }, + "uniStatistics" : { + "enable" : false + }, + "h5" : { + "title" : "", + "template" : "template.h5.html", + "devServer" : { + "disableHostCheck" : true + } + }, + "vueVersion" : "2", + "mp-qq" : { + "setting" : { + "urlCheck" : false, + "minified" : true, + "postcss" : true, + "es6" : false + } + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..2fabd4b --- /dev/null +++ b/package-lock.json @@ -0,0 +1,464 @@ +{ + "name": "vk-unicloud-router", + "version": "2.15.3", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "vk-unicloud-router", + "version": "2.15.3", + "license": "MIT", + "dependencies": { + "element-ui": "2.15.13", + "lodash": "^4.17.21", + "umy-ui": "1.1.6", + "vk-unicloud-admin-ui": "^1.17.45" + }, + "engines": { + "HBuilderX": "^3.1.2" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "peer": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "2.7.15", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.15.tgz", + "integrity": "sha512-FCvIEevPmgCgqFBH7wD+3B97y7u7oj/Wr69zADBf403Tui377bThTjBvekaZvlRr4IwUAu3M6hYZeULZFJbdYg==", + "peer": true, + "dependencies": { + "@babel/parser": "^7.18.4", + "postcss": "^8.4.14", + "source-map": "^0.6.1" + } + }, + "node_modules/async-validator": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-1.8.5.tgz", + "integrity": "sha512-tXBM+1m056MAX0E8TL2iCjg8WvSyXu0Zc8LNtYqrVeyoL3+esHRZ4SieE9fKQyyU09uONjnMEjrNBMqT0mbvmA==", + "dependencies": { + "babel-runtime": "6.x" + } + }, + "node_modules/babel-helper-vue-jsx-merge-props": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz", + "integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==" + }, + "node_modules/babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", + "dependencies": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "hasInstallScript": true + }, + "node_modules/csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", + "peer": true + }, + "node_modules/deepmerge": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", + "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/element-ui": { + "version": "2.15.13", + "resolved": "https://registry.npmjs.org/element-ui/-/element-ui-2.15.13.tgz", + "integrity": "sha512-LJoatEYX6WV74FqXBss8Xfho9fh9rjDSzrDrTyREdGb1h1R3uRvmLh5jqp2JU137aj4/BgqA3K06RQpQBX33Bg==", + "dependencies": { + "async-validator": "~1.8.1", + "babel-helper-vue-jsx-merge-props": "^2.0.0", + "deepmerge": "^1.2.0", + "normalize-wheel": "^1.0.1", + "resize-observer-polyfill": "^1.5.0", + "throttle-debounce": "^1.0.1" + }, + "peerDependencies": { + "vue": "^2.5.17" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/normalize-wheel": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz", + "integrity": "sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA==" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "peer": true + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, + "node_modules/sortablejs": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.10.2.tgz", + "integrity": "sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A==" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/throttle-debounce": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-1.1.0.tgz", + "integrity": "sha512-XH8UiPCQcWNuk2LYePibW/4qL97+ZQ1AN3FNXwZRBNPPowo/NRU5fAlDCSNBJIYCKbioZfuYtMhG4quqoJhVzg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/umy-table": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/umy-table/-/umy-table-1.1.8.tgz", + "integrity": "sha512-yqPMFwZ6MUNqI73KamsNKBTbHRA7VuVZDEWobaySghtf4n/s7INuTNQoADB/ROVK57WOXr99Xpnol0aMqGlASA==", + "dependencies": { + "async-validator": "~1.8.1", + "deepmerge": "^1.2.0", + "normalize-wheel": "^1.0.1", + "resize-observer-polyfill": "^1.5.0", + "throttle-debounce": "^1.0.1", + "vuedraggable": "^2.23.2", + "xe-utils": "^3.0.0-beta.12" + }, + "peerDependencies": { + "vue": ">= 2.6.0 < 3", + "xe-utils": ">= 3" + } + }, + "node_modules/umy-ui": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/umy-ui/-/umy-ui-1.1.6.tgz", + "integrity": "sha512-wX0S29B5sFn8q0MvU9PEl8DGZeQmZXOJlLrwaCJ2UHiIQZCANWgXMBjjQgpaequ1gRZ8BekEu7Sn7hJccm9YMQ==", + "dependencies": { + "async-validator": "~1.8.1", + "deepmerge": "^1.2.0", + "normalize-wheel": "^1.0.1", + "resize-observer-polyfill": "^1.5.0", + "throttle-debounce": "^1.0.1", + "umy-table": "1.1.8", + "vuedraggable": "^2.23.2", + "xe-utils": "^3.0.0-beta.12" + }, + "peerDependencies": { + "vue": ">= 2.6.0 < 3", + "xe-utils": ">= 3" + } + }, + "node_modules/vk-unicloud-admin-ui": { + "version": "1.17.46", + "resolved": "https://registry.npmjs.org/vk-unicloud-admin-ui/-/vk-unicloud-admin-ui-1.17.46.tgz", + "integrity": "sha512-VJvi8Gm3mfZOFEilIrZ1bSoi192ov9hPzSFzkR6l62pqJ3UEwgjTr5L2gQqxw4twb+y5qDmWZPS4dQMwya+iiQ==" + }, + "node_modules/vue": { + "version": "2.7.15", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.15.tgz", + "integrity": "sha512-a29fsXd2G0KMRqIFTpRgpSbWaNBK3lpCTOLuGLEDnlHWdjB8fwl6zyYZ8xCrqkJdatwZb4mGHiEfJjnw0Q6AwQ==", + "peer": true, + "dependencies": { + "@vue/compiler-sfc": "2.7.15", + "csstype": "^3.1.0" + } + }, + "node_modules/vuedraggable": { + "version": "2.24.3", + "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.24.3.tgz", + "integrity": "sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g==", + "dependencies": { + "sortablejs": "1.10.2" + } + }, + "node_modules/xe-utils": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/xe-utils/-/xe-utils-3.5.13.tgz", + "integrity": "sha512-ORT6ghCRk0mUVavMBxetcPzUPskS6NGfntzpWazJ86e+XU0uK4HwHfDhN/jKATiyInrOH5RwQo9SO/+DB8XeBw==" + } + }, + "dependencies": { + "@babel/parser": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "peer": true + }, + "@vue/compiler-sfc": { + "version": "2.7.15", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.15.tgz", + "integrity": "sha512-FCvIEevPmgCgqFBH7wD+3B97y7u7oj/Wr69zADBf403Tui377bThTjBvekaZvlRr4IwUAu3M6hYZeULZFJbdYg==", + "peer": true, + "requires": { + "@babel/parser": "^7.18.4", + "postcss": "^8.4.14", + "source-map": "^0.6.1" + } + }, + "async-validator": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-1.8.5.tgz", + "integrity": "sha512-tXBM+1m056MAX0E8TL2iCjg8WvSyXu0Zc8LNtYqrVeyoL3+esHRZ4SieE9fKQyyU09uONjnMEjrNBMqT0mbvmA==", + "requires": { + "babel-runtime": "6.x" + } + }, + "babel-helper-vue-jsx-merge-props": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz", + "integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==" + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" + }, + "csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", + "peer": true + }, + "deepmerge": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", + "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==" + }, + "element-ui": { + "version": "2.15.13", + "resolved": "https://registry.npmjs.org/element-ui/-/element-ui-2.15.13.tgz", + "integrity": "sha512-LJoatEYX6WV74FqXBss8Xfho9fh9rjDSzrDrTyREdGb1h1R3uRvmLh5jqp2JU137aj4/BgqA3K06RQpQBX33Bg==", + "requires": { + "async-validator": "~1.8.1", + "babel-helper-vue-jsx-merge-props": "^2.0.0", + "deepmerge": "^1.2.0", + "normalize-wheel": "^1.0.1", + "resize-observer-polyfill": "^1.5.0", + "throttle-debounce": "^1.0.1" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "peer": true + }, + "normalize-wheel": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz", + "integrity": "sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA==" + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "peer": true + }, + "postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "peer": true, + "requires": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, + "sortablejs": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.10.2.tgz", + "integrity": "sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "peer": true + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "peer": true + }, + "throttle-debounce": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-1.1.0.tgz", + "integrity": "sha512-XH8UiPCQcWNuk2LYePibW/4qL97+ZQ1AN3FNXwZRBNPPowo/NRU5fAlDCSNBJIYCKbioZfuYtMhG4quqoJhVzg==" + }, + "umy-table": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/umy-table/-/umy-table-1.1.8.tgz", + "integrity": "sha512-yqPMFwZ6MUNqI73KamsNKBTbHRA7VuVZDEWobaySghtf4n/s7INuTNQoADB/ROVK57WOXr99Xpnol0aMqGlASA==", + "requires": { + "async-validator": "~1.8.1", + "deepmerge": "^1.2.0", + "normalize-wheel": "^1.0.1", + "resize-observer-polyfill": "^1.5.0", + "throttle-debounce": "^1.0.1", + "vuedraggable": "^2.23.2", + "xe-utils": "^3.0.0-beta.12" + } + }, + "umy-ui": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/umy-ui/-/umy-ui-1.1.6.tgz", + "integrity": "sha512-wX0S29B5sFn8q0MvU9PEl8DGZeQmZXOJlLrwaCJ2UHiIQZCANWgXMBjjQgpaequ1gRZ8BekEu7Sn7hJccm9YMQ==", + "requires": { + "async-validator": "~1.8.1", + "deepmerge": "^1.2.0", + "normalize-wheel": "^1.0.1", + "resize-observer-polyfill": "^1.5.0", + "throttle-debounce": "^1.0.1", + "umy-table": "1.1.8", + "vuedraggable": "^2.23.2", + "xe-utils": "^3.0.0-beta.12" + } + }, + "vk-unicloud-admin-ui": { + "version": "1.17.46", + "resolved": "https://registry.npmjs.org/vk-unicloud-admin-ui/-/vk-unicloud-admin-ui-1.17.46.tgz", + "integrity": "sha512-VJvi8Gm3mfZOFEilIrZ1bSoi192ov9hPzSFzkR6l62pqJ3UEwgjTr5L2gQqxw4twb+y5qDmWZPS4dQMwya+iiQ==" + }, + "vue": { + "version": "2.7.15", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.15.tgz", + "integrity": "sha512-a29fsXd2G0KMRqIFTpRgpSbWaNBK3lpCTOLuGLEDnlHWdjB8fwl6zyYZ8xCrqkJdatwZb4mGHiEfJjnw0Q6AwQ==", + "peer": true, + "requires": { + "@vue/compiler-sfc": "2.7.15", + "csstype": "^3.1.0" + } + }, + "vuedraggable": { + "version": "2.24.3", + "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.24.3.tgz", + "integrity": "sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g==", + "requires": { + "sortablejs": "1.10.2" + } + }, + "xe-utils": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/xe-utils/-/xe-utils-3.5.13.tgz", + "integrity": "sha512-ORT6ghCRk0mUVavMBxetcPzUPskS6NGfntzpWazJ86e+XU0uK4HwHfDhN/jKATiyInrOH5RwQo9SO/+DB8XeBw==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..f7eaa79 --- /dev/null +++ b/package.json @@ -0,0 +1,96 @@ +{ + "id": "vk-cloud-router", + "displayName": "【开箱即用】vk-unicloud-router - 云函数路由模式开发框架 - 已集成uni-id 框架内置了众多API、工具包,为你的业务扫平障碍。", + "version": "2.15.3", + "description": "这是一个unicloud快速开发框架+项目模板(已包含核心库)支持URL化,众多现成API供你使用(登录、注册、短信、微信百度服务端API等等)为你的业务扫平障碍。内置小白也能轻松上手的数据库API。", + "keywords": [ + "vk-unicloud-router", + "云函数路由、云对象路由", + "vk云开发", + "内置uni-id、uview、数据库baseDao", + "内置众多API、工具包、支持微信公众号登录、微信小程序、app登录等" + ], + "main": "main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "VK", + "license": "MIT", + "repository": "https://gitee.com/vk-uni/vk-uni-cloud-router", + "name": "vk-unicloud-router", + "dependencies": { + "element-ui": "2.15.13", + "lodash": "^4.17.21", + "umy-ui": "1.1.6", + "vk-unicloud-admin-ui": "^1.17.45" + }, + "engines": { + "HBuilderX": "^3.1.2" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "370725567" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "无" + }, + "npmurl": "https://vkdoc.fsq.pub/client/", + "type": "unicloud-template-project" + }, + "uni_modules": { + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "u", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y", + "钉钉": "y", + "快手": "y", + "飞书": "y", + "京东": "y" + }, + "快应用": { + "华为": "y", + "联盟": "y" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/pages.json b/pages.json new file mode 100644 index 0000000..6d60585 --- /dev/null +++ b/pages.json @@ -0,0 +1,102 @@ +{ + "pages": [ + { + "path": "pages/index/index", + "style": { + "navigationBarTitleText": "金久信钢城" + } + }, + { + "path": "pages/error/404/404", + "style": { + "navigationBarTitleText": "404" + } + } + ,{ + "path" : "pages/auth/register/register", + "style" : + { + "navigationBarTitleText": "注册", + "enablePullDownRefresh": false + } + + } + ,{ + "path" : "pages/auth/login/login", + "style" : + { + "navigationBarTitleText": "登录", + "enablePullDownRefresh": false + } + + } + ,{ + "path" : "pages/spot/release/release", + "style" : + { + "navigationBarTitleText": "发布现货", + "enablePullDownRefresh": false + } + + } + ,{ + "path" : "pages/spot/goods/goods", + "style" : + { + "navigationBarTitleText": "现货市场", + "enablePullDownRefresh": false + } + + } + ,{ + "path" : "pages/user/user", + "style" : + { + "navigationBarTitleText": "个人中心", + "enablePullDownRefresh": false + } + + }, + { + "path" : "pages/spot/goods/detail", + "style" : + { + "navigationBarTitleText" : "", + "enablePullDownRefresh" : false + } + }, + { + "path" : "pages/company/company", + "style" : + { + "navigationBarTitleText" : "黄页", + "enablePullDownRefresh" : false + } + }, + { + "path" : "pages/enquiry/release", + "style" : + { + "navigationBarTitleText" : "发布询价", + "enablePullDownRefresh" : false + } + }, + { + "path" : "pages/enquiry/list", + "style" : + { + "navigationBarTitleText" : "询价", + "enablePullDownRefresh" : false + } + } + ], + "globalStyle": { + "navigationBarTextStyle": "black", + "navigationBarTitleText": "金久信钢城", + "navigationStyle": "custom", + // #ifndef MP-ALIPAY + "navigationBarBackgroundColor": "#F8F8F8", + // #endif + "backgroundColor": "#F8F8F8" + } +} diff --git a/pages/auth/login/login.vue b/pages/auth/login/login.vue new file mode 100644 index 0000000..a9ab763 --- /dev/null +++ b/pages/auth/login/login.vue @@ -0,0 +1,612 @@ + + + + + \ No newline at end of file diff --git a/pages/auth/register/register.vue b/pages/auth/register/register.vue new file mode 100644 index 0000000..d906166 --- /dev/null +++ b/pages/auth/register/register.vue @@ -0,0 +1,629 @@ + + + + + \ No newline at end of file diff --git a/pages/company/company.vue b/pages/company/company.vue new file mode 100644 index 0000000..c4b48f5 --- /dev/null +++ b/pages/company/company.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/pages/enquiry/components/template.vue b/pages/enquiry/components/template.vue new file mode 100644 index 0000000..4e4c576 --- /dev/null +++ b/pages/enquiry/components/template.vue @@ -0,0 +1,184 @@ + + + + + \ No newline at end of file diff --git a/pages/enquiry/list.vue b/pages/enquiry/list.vue new file mode 100644 index 0000000..caff475 --- /dev/null +++ b/pages/enquiry/list.vue @@ -0,0 +1,254 @@ + + + + + diff --git a/pages/enquiry/release.vue b/pages/enquiry/release.vue new file mode 100644 index 0000000..9c62d68 --- /dev/null +++ b/pages/enquiry/release.vue @@ -0,0 +1,234 @@ + + + + + \ No newline at end of file diff --git a/pages/error/404/404.vue b/pages/error/404/404.vue new file mode 100644 index 0000000..cdd49ce --- /dev/null +++ b/pages/error/404/404.vue @@ -0,0 +1,49 @@ + + + + \ No newline at end of file diff --git a/pages/index/index.vue b/pages/index/index.vue new file mode 100644 index 0000000..efccd04 --- /dev/null +++ b/pages/index/index.vue @@ -0,0 +1,76 @@ + + + + + \ No newline at end of file diff --git a/pages/spot/goods/detail.vue b/pages/spot/goods/detail.vue new file mode 100644 index 0000000..44556dc --- /dev/null +++ b/pages/spot/goods/detail.vue @@ -0,0 +1,497 @@ + + + + + \ No newline at end of file diff --git a/pages/spot/goods/goods.vue b/pages/spot/goods/goods.vue new file mode 100644 index 0000000..1f789dc --- /dev/null +++ b/pages/spot/goods/goods.vue @@ -0,0 +1,320 @@ + + + + + diff --git a/pages/spot/release/release.vue b/pages/spot/release/release.vue new file mode 100644 index 0000000..43865e0 --- /dev/null +++ b/pages/spot/release/release.vue @@ -0,0 +1,175 @@ + + + + + \ No newline at end of file diff --git a/pages/user/components/business-card.vue b/pages/user/components/business-card.vue new file mode 100644 index 0000000..3924895 --- /dev/null +++ b/pages/user/components/business-card.vue @@ -0,0 +1,211 @@ + + + + + \ No newline at end of file diff --git a/pages/user/components/personal.vue b/pages/user/components/personal.vue new file mode 100644 index 0000000..3b85330 --- /dev/null +++ b/pages/user/components/personal.vue @@ -0,0 +1,309 @@ + + + + + \ No newline at end of file diff --git a/pages/user/user.vue b/pages/user/user.vue new file mode 100644 index 0000000..58d81a0 --- /dev/null +++ b/pages/user/user.vue @@ -0,0 +1,61 @@ + + + + + \ No newline at end of file diff --git a/static/images/80705c8b12d05d0ff67a2758749ef09c.jpg b/static/images/80705c8b12d05d0ff67a2758749ef09c.jpg new file mode 100644 index 0000000000000000000000000000000000000000..644ac201e28c99e4bfd2c48652323b62a5778885 GIT binary patch literal 77644 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 literal 0 HcmV?d00001 diff --git a/static/images/cc-top.png b/static/images/cc-top.png new file mode 100644 index 0000000000000000000000000000000000000000..fdb16cea5c0b38d185311c082beb1031667d4d5d GIT binary patch literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jh-%!Ar`%NFD&Fe3T75p|hT;}acVR3uKA-jlEp=*bk;$OW5zb5(boBm(6{!s_x`Ukx7>4)}x za8faOSbk>3M-#uijk*)pzxa4SRyJ?xr-K&z59&#I&eY-Va0^m9&s_Or%a$k63|cu} lOb^dTXFljTt>5T+FCtZ~Qs~a>%|OR6c)I$ztaD0e0svu#NNNB8 literal 0 HcmV?d00001 diff --git a/static/images/cl1.png b/static/images/cl1.png new file mode 100644 index 0000000000000000000000000000000000000000..a967600d09c6c64d7e24c340547a236114f32547 GIT binary patch literal 18091 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 literal 0 HcmV?d00001 diff --git a/static/images/cl3.png b/static/images/cl3.png new file mode 100644 index 0000000000000000000000000000000000000000..925fc820c8927d00f39b82e7fa959d0177465596 GIT binary patch literal 18117 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 literal 0 HcmV?d00001 diff --git a/static/images/cl4.png b/static/images/cl4.png new file mode 100644 index 0000000000000000000000000000000000000000..36941959e9d5705d4d95d76023a00d04f188fc72 GIT binary patch literal 19551 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 literal 0 HcmV?d00001 diff --git a/static/images/cl5.png b/static/images/cl5.png new file mode 100644 index 0000000000000000000000000000000000000000..7c29a597fe94c95f06af2b6017dc84e4b4c07c9a GIT binary patch literal 18168 zcmeI3d00%*|Hp3&TBNjyLSvGBnypf!rd<=IOgo}!mKx1wW?CjBOGH#u(khC?h-@Wo z5}{2|s3<8(rIIAVZz`0F`T0G+@9&S_^UOTY%)OuUIiL5r=XE~k+;iu7?tc3r75f}_0Ps~|O5@O#f$OHy!Tm$G5`eBCpq}LMh(uuHVu;Hoz0%~X2sHW0#Hr9)LjL)lL|)w!X5=h zliMMoGS12>(-Uz{CA(^6a7m#pDT{KvOb>*v3v=3_|5l?h{p$9>p6>3?k3Z+NC$x);E zc3RK-+b6&J^fIB?d3{Y^^A3tj0t#!Ydg?c|wbedv8AKqRjX@+DBwrhSZ4cYM}d~tP)PS%EHDhK*p_vhF{ZA*FA@rNzu-HT~a z?AU?o(>VG?I?7)T;P167T61m6)iPR9&|5L_uxYL}et=0(KkT5I>|sE`O9#ap1c0c* zp$L0K!$!aPjqbkFc7&`K%QxNu1*0jF~$I1SPfs=O9@`z||8Ji~1BVRxM7I~ZHp;Lrw> zPmv9GA*chx2lA|t(K|1#m3SoXYjXXJhT4HUDV%Dqj=X#D(UU&aYFFkO1z$UvUcLIY zFBjN;Ae{2W;66)_{jO>YN@oz;Ty>ozbcu6Zm;0%x7bO#Vq~?o<1uJz) zZQP?!OxqP1Y2|9;YJNtmOY@3iu9S=P?mfujh0v%oc2~3l6^BX!JTY03t}FQq-p-pl zFIj8j!f8sIqHy!4-8<5{MrNK?B+6RW+6UKwgQYp7VQUnqi8c#5BkA{^w@O_K=0jo+ zXGh9M+8z0P?^bKJGUj$@i;eWj`S`SG#Z|gw<2K1t$5Cc+DQDMKWF$Y5Iva{PzRsGS z;%5(c*q5QC;~TG4kubx&EDe@g`yig`MIH2pcW`s1pY5J&8T%l%#^?2vj`oh-@BOFB z?UmbIit}7F%V*ZsS?M#gXTjraPEUFm8+X?c@ff8Z=XFf}7}Lph$%iG|R1V))jKRb> z#{|W+pLKNNI2qUS&dNHTbCN%|(Rusnl}?xKUuH-@nsKf+V~*2}486=sygxp|zH05J z)PhZ4c6}nsUD_M6GG#9=)sdKeXV#&4Gwz_seXeG8Y-fqiWj@DjJ=b3v>ay{h^jX~x zzSYLToO71KryQmvz1mVCHtkMUbFabE#8s8^D&;D-!X#kEu&lbx=PBod&M&VItS_kd z>}Ge*=AR)P*?<-tO~y zsT-h*rSO@vJ^4D%$&EgS1WzieA+03sc5A`nifEsBN^bR)hure=yUQB+Px$w`!VPK@ zeUb?UPxBgv4~3kvOuW4+OfRhTX#LS`Ws{ED9v$Q#bH+OJoClmA^R4SPbS~?p*SXN_ z)m;*%CSVfEuAMobaK6MZf!?Itq8zcfX7PXnqaN8c+$GZ$-!-}0-~-`<)(85BsyXGe z73b8g;I7!l=K7ZV(O7w%X)kncWt3#x>TvN=_d3Bz>ep30y*jc?G1f0u)q$RVAf0hM zuq>uc?QL$&)rSMA2{#fN&p)L3aIZ_Y2<>Vd%;kv~;-NMP?^#g7Lb-&b(D0NP|! zpczyb6c;pQIQjF6Pi0>sJ{G>XN>CmJb zli^dbDrQrq<=iybQOqLMcj`k#bfed@_-d8=Qb{W7)ITB07ud|Ln;yQmN~%dAh_h7d&#(MH^j^yKGUu(onbpi>D``$5If6)lZQ^O&C1SM zWq9OOl5@-l{bwt-n}71&Yq!$(4qDm{zm#`)){*O){kF~)bLnlx;^@x-?3zmG_E%Up;Ey{lQkvAx?jT3N6H@I`s-Z(|+0v8~B-}0qbY3 z56Hpg4-2U32P``O;l3Ix!j1_sSTV@7G-?st{sGPCc7rYu7vP zSfU!UiO=Gn$^3Y6WzMS>mo=Mew+-;<_4UtJW#8}a#C4{1GWdgTg%?)kZ#J!cu(wz4 zyn5fEHuX*PRnNI60yhtYS6r#MUm>AO(CuDdevRMo?u1_IhrpyA?q$wj&Y#OJc)Fmz zuJD=v*8XX`=cufB-V@!GcXerii%-7g_5nuC+g;Bh)I8O53tt62%dzseyPX`d_0-lW zA1r%1H*=Y^#tVgom!#=l2l? z8gErJ#qG!*km|(omeybjefh9ddWzAB{GQhbQ-X=D||`tkyIVLh{xJXqH4VwlN&Z`-+|y654JPn(NsIgdX+)^})PH$1<&*rI9ap|)k&EcfA3cgZs&2W- z_e_)Cm;5#Q+rxb?YOKnwYBg7C9*RiP&`_6C%YR3zjCzrNDP5`RevtDwUMJ^Vd()Se z&#S9khoAJy4uw?}X7V!n**)hnE?`PEOEvN;c}9JwhtF3wZ12hG$!#jl*N9s*Z1UB< zzxorgH2s0yAhvzm*J1eJp8n5THOJ8afO$f7bmh9*+F*!Gx;BBt^dxHs&{=|QC;%85 z2e1f4A2Ju>N%o>LjG#R?3ZW1x$q4GAYm2aDnUlS#xIi}9A#jZ&G0=x-K!O@$Wefu_ z0s%UiOMnE>X$%e~zz903ixHfU6vLsA(JEXYBdF;}gAi9+dx$xcO@`=d>%xc#qz+`c zfi_YXsiTiv20eOM8V)KR(@|zU>QNZxm*?o z4)^!>*Y-ziGud8nq=A6}9D#zPP%uFa7>CE;5&~chj^>!i4;>3KhsdU~xKt(sGNMcH zWcqTApwN+qety39i_ZGl5QFoboq!@dfWU$ywGr^Y1ligO52Mrn7|G#U`U$S&d(ZyZ zAjgr%BE#`y4%3%SBwPBC8C=ajT?FgLbHtzJe!BnK3li~XB+Hjg8wE@v!pSr;UC<^+ z5QqF@AGlP?_~87~g%QtRn3IC$8T6zBSHVEH^;t=q@Mfj&}0b@ZY2@m_*-^6!R&?eLwx%&TU6MvBT zttlLpBS;&wsOVG);+jQk!({e1xcjq;fOgz&$&;qOgm2ut`esnJ@07vV4|Tz>+a zZ0aS*iT`FAjtTx60aiAIkF3cw>i@wQa0q_?yAk-eDfIt+1jcih=uKdFkx5wikF@_=RFDYWB!{8RX|F^4~&0N%Al8=VdPoC3Js3(GIZB3#1xfV?7HARxj`5ia3;Kwc3p5D?*}2$yg^Ag>4) z2#9b~giAOdkXM8Y1Vp$g!X=y!$ScAH0wUZL;S$aVmvBBHuLu_ih;UPcOE@2p zSA+`$M7Sx!C7ch)E5Zc=BHR?=63z$Y72yH_5pIfb3Fiayig1B|2scHzg!2J;MYupf zgqtEF=>KITT{m^K2lBu#} zbNh3C$Qf_V`5rP7i}ysnIsggnP*lIU%0f1byUum8tojOdS@qQ`=b z&f+HCVtAF#qX>S~=;{#gCGGm~f^0rZyhR%q)fW`Y^+F#0un{UisQ+-y5O1 z#j~_`8(VJIgBM5HtCkpELmuqocR0#5z(Vv3<9pUdoLI5~u0!d6ADXjm$6DjbS-S=a z-zF8b`05)LrO)gMjYaGedoSs~AMWPSj?{amD(@lN)H}=g)^k$c68#c|H8NYO>2mp5 z>$iTWRJ~;Ql@yLIz5($=s}`dBBGh*JrXo+kGTR^T2yzUMooUK6TS$4(C%Hv>M|DVT cf*9~kcV*fP*~J$|ULm%&Tw{@G=CSL)07A4N3IG5A literal 0 HcmV?d00001 diff --git a/static/images/cl6.png b/static/images/cl6.png new file mode 100644 index 0000000000000000000000000000000000000000..b72b01a34d9fccfed1584768dd66a13496dbf1cd GIT binary patch literal 18187 zcmeI3c{J4D|Ht2!3T4TXA{iq-mBwtyOpKjTL}Ra1V`ea!Ei;x;NsIPEC0Qd%idID; zRHBF|K0=Wt2_Yd-{l-%CuIAV8{Jy_Ge&@`bGt29~?(2Eq_iX7={pOb(On z&16BW&CDPyU#2IOMgf4px_E~G*AqkYaE(J0X=l^g-fK~`T>w-)U93dL?X1jkfVfvi z*0?D2fP}NW!rVB#(}UgB68QK7&5290y-W@rSa;ZIgZ_KfhSZxof_l2UNB$kjZI5do zE$3E9hs>4LjCgZ)3xFYn8enTx!|d=69_57yE8v?%Au?}D?|IEA0)So-ZeTFys?n&> z6(%4Iu&T8e%ND=>wkOA4(*=M;08LQY_Sr(=1fWFQu|ysynGalbxIvZxP67apyWJED zT$BX5K3d~u0JUi+8We%rvkTM2fTKb{^b)JZ!p3)i%}%=r%Y_T>0g36xP;JqI%R(V; zw@_BXA$cX+}6wjQW+2D}@G-O=^p ziR&bu1`QwP>W>;PN=ULVF;H13F?)8mhDTB!qUA8|8~Qb~>2UBM&-=ALs2A88V;r4P zki6&1RwBdyGT~Tzsi-NEG1RX9wK#O=mt#vSn{}>jSgvrW&-GxoJ=C_Cdz%npuJ$Oh zS+-**s!#RQ7x5DTl0f=CyMi^hX5B2M6$HN*5DTICNI2lvB{D9w%lWW01x+#vus zkv|+}tR)0IiAre!fZVt9H(WTWX!B4E0L&A2ExT$mYfhnjdVy42p-OInqA+o$x$&IE z1qL#vGh0IzN+iucWwOAr09z}1^Qwqa;@p_mGMR-)eaZGF*$uloS&B0^&ri5FKX;$F zs7Z;K98nE>V6MlpT4=eLV)QXlC=su7JR}9uaX@}8w5Y^4ML5lLON2XK{R7Nb9&>bq z@#paR5(w(h=%HLI&F3h96Ck{sYFV79(h6BaAd#5=7X+En#J=-ZLYe`VY(z0*A@N>$^{9;9x5F4$#i1j!CR2=u^S3wO0l*L<(G zNG(BQ<3Cbzn@->tOFcT?x<*1xBOGNt+u8?TkB6l=q~NM#sBt!$o#FIHuUf^fhonQI zBC^7z!|jfbJi6bSC66sS&}<`qb}=F4r0gnPicy>Bxicu!=){X_pQI%`7rS@>duE+A zJ<;DD?yx^iPRB1s<4Np1v(gk;a`n>~suy+08{Wam5r4U7kww(gs4AbgvpU*4_IwPO zBe_pC;Rn*JXptwkt$DmW{+l zI!6XawqJB~VmldCb1%+zyyPT(X`}Ow^OjCG>|4^rpU=Bgou=Y+Cr$5iIU#@$W?!*( zQ}W$SUv_^cNnYOKp) zOde2t*HhC|sk#E8Bc>O=fQHm3^_GQ`-uj%TW>@y^eSKkWsdrAq1MlQY>*Rm3HQ(>| zYS9f;#CfJO7kZ@YyrMMt7!W>YA#-dffYpBkHb zuRpvUzR`c9+s2W+MRqshG!tqN^pg4q>zndQw{6Da3@M+>J4A2~al&VU&g{Q?{w}o9 z@UD7rO>lJZtkHy#m7hz$gni0?&HXU1Z_SL&LWM$YLV3HCcHI#15m6P57CkphcgE2f zcV@!p;1o>fh)cSu`kr7GD1J~LCZQX=md8{oJQj;rSf~6MQKo6LsAlf5eHCJjGQrIA z!!{jdx5N%KSGu#VZb#7KMl3jfTfN`b*}Udedc}*aFJPFHaVO)F z36j)PnOgrMvX*4od1`5$kZk3?p+8nWvH$TFcMv|R+wnSC0 zciy>7F>+HnEB(UdPggCo-!!|d*;KuKfJ?8dd$lU-ad#)aGo_P}KIE2vWmVo5lj^7Y zdL=WI`;N9LZ=$by#Yqaii|+Qr6uU znsqh#F9WvqOYKonSox~wWLNG@tw0x_Jc}IzjH>s$Uxq1pDCgwA34WPv6<}AC5Vq~y zwpoJ~J)K)POj^U0{QT?Ubb{W|MR+W$EjEN%7uy{ZaFexenbbX#w!(iJ&u`z>V*fU& z{C>mzCymiNvj)UE@m#GcY`$MQESa8Yn3UJ^_DFKP%0?BdyIJ3Ydyp+8zhd1mmxRRl zC5C;&t-DXOq>@t;;@21%K96qT4%v)G`?#-l&+{^?NH9|5ytm2PH1w$dReP9wZ!YU2 zbjYJ#BWrbr;blXsVAhw{_$%v~os^-{ZWn{goR7AhD=T}R?fkr@pql;fr+>BG&v5g4 z9(E~bF*IK;%+|;m_~bv>tr#Hj-loAlC@k>G=-s+6?`D0Lez!C8>orONz3J2Dg3T58 z-K2Y@#P=tBJ^Ag~{?}DjWmeVdmg+~t;#F0ZC6)3%kjqcJPQ9KgSMfO5`5U*BeW|_i zOY_L;3fIxv-r2*4EAlUM)B1gTE~Q<;7ONMl=9Y5}`_7MMl-KX*$?nN%EY4GnUNUO@ z)xN*-GpRWBsofB+ef!r@_|V?|5sj)dXaK<0QXO46uC_K<5|ge?Br`oI+JSTy?-&XI z21bD_BFTrsfp}27s0>4B&z*cIgi1Dqy6D;>Y*}U$Zz?{>m*Nn##*q}{L&A`uMmPzB zKrByyPT>$Cfpi*!jSVz}j_YE1pU0ZvP{?=}j*lVKWNbi)tF1l6jOj~(=xXc2NC>13 zWCcbWsf*OnM=pn;5J)r}frcZ|FeD0#z+jQOkjV!WC&Bw<;7j(z63i_phvQj>P;U;0 zg@wZd0s^!H(ArF2FE|o|!N3tHI0^;h^?N&MIKTToG^T**Rfz&^Qjd>=*##3Qpg$#K4hc)x15IIa=M<$boo5-@M zUr)RrPfJ{=3^Fr-z0?2>?me~CQ$iGTB8P%QAy5byLJx*UI3ibI(P%6Jt%cCXA`sI= zCVGN2Yqw-T$RJUy&2hZBYg4IYEScg- zMo>sd7>a~M!8~+z&@iG71_SfZ)6qxikvxeW9>noU{v7^`v^kUHHmAfQwBEyS9#=*a* z?e~ViTeOL#{CPipuQ0#vKZ76NNk3|Y39o{UZBzEo$uPc6O^IGVw~k%*Wa@k`8fc8J zrJkNX#>~_dWub>enwXfITcGqzEit-i9eo|s-{;yy>(BZI@V~pdX_GKx(wM%sOfm(B zo*q5bJOy!D6z^X@`-wmOaBPB=Da6{sOb?0C(}SV3k<(?S^_!+cCSg69zH}l7N2L?J zC~y|T%K$#rIIZW{mob)CD0!QfI9{N5>c6ys`@4=6JeuEl{}m_%?*T`Sy-tQscY{OS z_=iq+gF~kxofuRO4mCL%sCin{*ogr<&e?%?xTWBDQv)}Fd)re3DKuAeD({PpJyx!f zx|1tFKw$Ct!^^25}O{*$U8 zEx{llApA`MF8+K#UI8u;5dNkB7k@q=uK*Va2!B(6i$5QbSAYuyguf}k#h(wzE5HQ; z!rv6&;?D=<72pB^;cp6X@#h2b3UGmd@HYjx`11jI1-L*!_?rS;{P}>q0$d;<{7nHa z{(L}Q0WJ^_{-yvIe?B0u02c@de^Y>qKOc}+fC~hKzbU}QpAX0@zy$)r-xT2D&j;ic z-~s{RZwhen=L7NzaDjmEHwC!(^8tAUxIjSon*voT%YO4; zSm-I#!+g4a@n^_}B=v|YiFsR(WX(7-lBhZosMKswv&W@H=H@Uo_1Zp(lcBD=4mRbp z5=y#^Q2K|TuQ9u0>C`)Sw8#?IqO-{2rQ4{<`d;Mr0!q?)tzvN{(#wP0O)aNk{`D_w zEq0VYv>epyQ-OsZ`IfZw8Zv}gIMSzFij>Pp%GWN`YVd#;f08#`J0c&v?}kWO)9Uw& zzZ$clpIf}2d7JJG3%ej^=zet8aq}G?gVb^e3(U}a71J)XW3&%(NK)tex|>vTHf!bL s_RcgYb(6lYquFmzJ@ZZ3|3k?5<*Ki#6t#O*ilUFKCl85dZ)H literal 0 HcmV?d00001 diff --git a/static/images/dowm.png b/static/images/dowm.png new file mode 100644 index 0000000000000000000000000000000000000000..0b1b6a2395c493f1bdfd757ca3e3f14201e981d5 GIT binary patch literal 229 zcmeAS@N?(olHy`uVBq!ia0vp^LO{&H!3-o1$Hvb9Qf2`@A+A9B)TvX)jvYG+20+Hy zvu7_{xN!CARUjJ(fWi<4kUW0;__=fEfFeH|mv05?6f6ny3uaJ!dh6^i5nj%h_m3S6 z@X?gYR0>Q6O8R=bIEHXs4?P*pbwEMD`C^E>?ESR=vvp-zU;gEs!!TE3OaF@)oK@`I{d2Y^6udqbnMzQ75gT9zmA zRcZ$g%vjF-#OSrEQHQNj0t3_J=S`*O9HcZ}g#TmFU|~|fe>Sm!;a$0Og9^h^7lH6_ TsR{FeW-@rX`njxgN@xNA7=K5* literal 0 HcmV?d00001 diff --git a/static/images/home1.png b/static/images/home1.png new file mode 100644 index 0000000000000000000000000000000000000000..ad592eaef87c170f521bd0c20aca8483d5118191 GIT binary patch literal 31642 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≈B2PJ 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 literal 0 HcmV?d00001 diff --git a/static/images/home2.png b/static/images/home2.png new file mode 100644 index 0000000000000000000000000000000000000000..cf964ea9bd49e989532c533d3b2e461c990197bb GIT binary patch literal 30567 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 I1J`~31;5a_OaK4? literal 0 HcmV?d00001 diff --git a/static/images/iconsmall.png b/static/images/iconsmall.png new file mode 100644 index 0000000000000000000000000000000000000000..84f82d6c35887820cbf67e48c9dd6de4d2541f8b GIT binary patch literal 191713 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 I&MBb@0LDP0&;S4c literal 0 HcmV?d00001 diff --git a/static/images/lg1.png b/static/images/lg1.png new file mode 100644 index 0000000000000000000000000000000000000000..13c0683e272c380177736bca05db2c7846ce09c9 GIT binary patch literal 18240 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 literal 0 HcmV?d00001 diff --git a/static/images/lg10.png b/static/images/lg10.png new file mode 100644 index 0000000000000000000000000000000000000000..fc4781500cfee663ca011b35eb7d8fc83061df0b GIT binary patch literal 95939 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 BQwab7 literal 0 HcmV?d00001 diff --git a/static/images/lg11.png b/static/images/lg11.png new file mode 100644 index 0000000000000000000000000000000000000000..9a8478443193703083bae227d5e98bfbb19283c7 GIT binary patch literal 95853 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 A&j0`b literal 0 HcmV?d00001 diff --git a/static/images/lg12.png b/static/images/lg12.png new file mode 100644 index 0000000000000000000000000000000000000000..5a9c4f92fa4ae1a7939247396b4004b9452f337c GIT binary patch literal 95742 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 literal 0 HcmV?d00001 diff --git a/static/images/lg13.png b/static/images/lg13.png new file mode 100644 index 0000000000000000000000000000000000000000..9afbea074b6235fbd63c343e8c7e88f5dcd1061a GIT binary patch literal 17991 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 IvFpzN0u4UaW&i*H literal 0 HcmV?d00001 diff --git a/static/images/lg15.png b/static/images/lg15.png new file mode 100644 index 0000000000000000000000000000000000000000..d823713caf8f024ab177225d48e783c5e00a1806 GIT binary patch literal 15294 zcmeI3TZkJ~7{}9#Rl~MaDBV>lou*i|buzbHcBV;6F1y{JY1iGAX2FM^%$#J0CNt^G zY?G}|_CYJfB9v9Z2Oo zznj(%?RY#CQohoc%1*iToT8eIDA3FbjJ6w1)H@VP9ced#dI~yB1=e&U9r@+P#}P)? z(vcJK5?^ZO;fg+Y)`E*?k1eTZPpPsNIg$yd+6oeAKnF1GM%}QLb~@teD(Kp6<|2&O z#W|IZWZeOoa%rB)n-*l^(KxH}LX1huQ6VnGriEu1kryP6mpDOU1ySK;MTj%qPb3pY zS1C)YDhq|#?r_LTM^+rCsc>AY)rz*HsA<(WL6&8X7dcU6Q4iK$GaS%n4SRn_q^DDW zwrc53M>h?|)ddxE)k#Mp?m+!dcU_HUe;~u|vO^TPHfVA}l;_3-l}hBWMq^~8?aZ7( zGwH5uXvB$_LxW7;d`nEChJV^^W6{fRVJt-1$TQ#n|N z4K${W;)IcFaP+FbIRi^@J!6N1ZGB9b>*<7fsnFS>6v{s(Z$aRg){<$~Go37(@2#52 z=b5KY=!Ryt?59&4-rL`5UkDa}12ZBo@+_ZZd2vaIDe;67Pafi@6`l`>bb4YMC6x9W zaKJ`X2KwSUrlwcdHl*VB9MmY4l%iofz))eakU?vY>bj;($ApShl|{A!;}uqxVk!&7 zB+qJc6;4AaNEI>WEpjk?NV;IEt8NN(r8Oj-6jT`Jc^;`IAq(R%i3OSJKLyV9a8fs3rQR=J(QVJ!OS7sLB>A}{Xqpo}9q6sV; zx~DK5=^evFYZ|o_=Qjp= zx;JA56-snyfmfiA`cNC*zw8#g`l{DoPVj=ra{?;+=-%js2Hkk*GC4Hp#zXzc7YyCW zh~3e!=0KGD#GrVb7tzBl%%G*=O?dBly$$Q-f{t!%wp*^z?aB+m+egMN`*8xAogWx* zbOSrN6?g*ma=6oqo^R2kHP?T(9!l^2J>q^|_$#`fs+blX1Oq}gDK0V}%u8`$K*%P= zMdpKfDJ~2M*`&D0d@wJ?g#jU(6c?Ef=B2nWAY_x`BJ;t#6c+}BY*JigKA4x{!hn!X zii^w#^HN+G5VA>ek@;X=iVFimHYqMLAIwW}VL-?x#YN_Wc_}Uo2-&2#$b2v_#f1SO zn-mwB59Xz~Fd$@;;v)0Gyc8D(gltk=WImXe;=+KCO^S=m2lG-~7!a~aagq68UWy9? zLN+NbG9S!KabZBnCdEbOgLx?~3<%kzxX64kFU5rcA)7>8VgGGaXrNbATj*WXSKrXS zLGQ7?UMysnrq&yu?+b5!e&@FDkGJ3YHMINE7nRA0#D(nE7I{vfk!V- a?mhm&)UyZ5>6hF$Y>P9;3RiL`&;14MCX;gj literal 0 HcmV?d00001 diff --git a/static/images/lg2.png b/static/images/lg2.png new file mode 100644 index 0000000000000000000000000000000000000000..1cae1ff1f4d47de63455f883ff7f09bd41c1c7d7 GIT binary patch literal 18307 zcmeI3c|26#|Hm&{P$UVFOe1|1V;1|wWH=6 zloA90K*$tph+`jDOn&(nuz!nsf(Yz`03GYd0DwiyCcivDT!JJ32%3`&46Ll&XiOTz zjYfx<8W=$6o-`K{nFs(r4T;t)hsY6eOv?yyiJgA^;EfpaegG<$!CxxkcuwRbfIlQ6 zs#_csENCaTd}#vKw&*~uAT}|$Jy{{!Rqt5vmJr)*n(t(r(r)kd8|d#JdogyuJE42L z(zj|!;8M}G5nbop0WDmRHo9Im%o1DlI5&`YIkt5kM5L>%&~<(>01Wc^`UEhqZye{j zMgw>Odad#r(UP`r2Xm~}+5?aXpcN|Gy@)3q2b3z?l!^hRlE8KAo6dqj6abKY_vk}` zOF}^3M^nsvpgujaNdl-pw=$g{IKczNDwwR{)x8JovfYnU;w>lyk~4In%JT}Y@&r2G zL7DId=FSJaLmk4G=S*h7 z=_U_+EIv2kF-U`ARu8pI+&|7c4-m1a8fe(r*;&U&FX6fFmG68w?$w#-VwMT`37ozCVWUWZ`5skG5rLjpdry%UXogTU@M-PkJy zDF?sq##6no;zGO2=IJA;Bi(WnB|-bXhOVn_SG}=KY5B1shojk6Q1cSsySNC$)sLgw zMSJ$4hGb8D6^LXB0U3ua3oPy|yj?~v2zbZC8zSsb;|=Hre1IL7S`-0@xT>OjM*tu) ze>6;2kq4-VNqr3f_uoivyBH;5_J|(<43qb-zpl4%@dL4p0^x)QGWQE4c<~Dibr-KG z&=%2O&=I&&@T}x1y%jbE==yoLuk%SIFO6#xx%B|4Db(F6x@~_iU1Gs5$)rNb`-cVQ z>6P*?!>>jMFLes7hgR}S#D>m;;<2hH15+VA!D5@C#igF9yy^Px5!dYjM|^MneRETm+sw*vQoz$B{Qm-s!O&9o;v4IEp=;^PT-w$Y1RL} z@nQmdkA)HftC7Mk$6w;N9Y12U>!^d&+7fX>r-PbZm>NOGLBo5wbU_k+fPW2dNZ_(Q z{vC%z3dsk;!%ZB_91JeX_sQK7&EdBfICuzI_zyJlqU9}lKhe=5A1CyUa0lazweME1 zTAd`n;~(K=J0r1cgdd;mun=4=AC59zWa@!!#KKaoQ!zCnqy)3Iz2TI{uR8cM12Z5o z5n16&!YxmZJ$~4cC5A2zZZ{J+w+5FQCAvwCxUqBI`7CuSk>3S^KEmq3ns&gPt;oJOyzx0q*yUf&*p;U~kwJISN1H4v)&>ftNMNKL|Ec{t&X$7xb__28kli%ZMgaw3Y{QmRc;{>fhZ?uhGa zH6IC#O9pMFQ-g>r@ z()RI-s!#T^$Gt;{uAX>l}!0c zQJK08%nf@ynO^1IWcvNy)HcRnFF?PtR&@%Q4JuDql?Z!Xs<-g|k>TsdC)@%D#019~3^M;zLBm%mO-i%%>3 z5Z(>n;l0Cg$5`$v%bN*nlj;zZ(#E2#t+{3XyU-XN;+M)EKFlKw?-{={NAfP@L0fe4 z0!{6@QCJ0PVu4 zSx@;L{@_*rt1K-)_ET&D_l#QL4-6a2#{Z4IK(gKYn*Zqx&6C zZ`TZWGLB5>i_Z?szLdS+=g4QHp%_u-vNZzzM>~q@i*$~@X7F~C<5Utl;%rVa30FIt z&fS&h>ZvSCVre_7Ifn1i3_2|ulew|;AVl8^E@|1BMm3jN_Wn?Okfl-HxfAC$-^j|| zqjwN zq*J#PUm&s+vMgN`6(fZ@e7h)5q$7_!8R?K4WqfE{P7X4wPPv7ezQK?$8o3?ns0PZTrR{~f~Abyj>~cOAr02- zEpsc&JoVM8-2rF&-rcw9eJJi=&H3{NiU;gfqtl}vmr<{N+;W$&93Sm$JK!EuyVY*r zdWqcS3h4j&hBcrx7b;`XV{n0(C}(g)|38TY;S5WHDkmv|JtTpcfH!DhX;kO zNDrOpl-^0%^on`b&wV(w;#S3z3O+TwTL0GaI~k4d&#I?<@=M&ez0B_GmCIRqFV{BI z-Dh<>zM#P;lxeR$o$GMdf`I7&IkXrT-f9P+Um{O%7;x4 zD_UarWexN9Vto~B(D_~&uoOzN&e`07H^);FWp>Dz{N(nQp^XGhvjxK&hE(NW^-cfaIdD1s8oETTMD~8Aug=hg@hg>$dk3-ya#~7qWn&e_btkMo zRDU6qq&>A9!F2DL7>AD>`Y*+Rws<;O9Zma)xfi2x|MF z*#Zkg5<3 zEoGz{QdJYF1VJH?DsY4f9H|0BqRz__NG&ZbI06Mnp32r@V497du1Hj=?K@@8MjOwWGX zAj8I&PK4u#44RiGfoSASq%!4xcMpOJcS6B5h)AR=QIkLj3^86T$9P9|AR4L;JyEMBk*@q=>Pi&%;qk^4Nr9?I%DA9 z)AoD8-woRIQ2sohzApp6&OhxR_ayZ9`LD-b!6v6EY7>x`uZp%btF1I|lR=XKVK6mWW|@4O|4SZAJ1Sk{t|5>>C?n za=AvS&BTBmzYTQ!Q{WuOOyG2K&DnxZCGm7AdxOi~Tf={Bu7AnzA2*5rDuF3x;FUM?;W5Y8qS7iT^oFBcaG2xpUvi!&dPmx~JogtN)T#hDMt%f$r( z!rA2F;>-u+<>CSX;cRkoapnW^a&duxa5lNPIP(E{xwt?;IGbEtocVyfTwEX^oJ}q+ z&U`>#E-nxd&L$TZXFeb=7Z(T!XOoMIGarzbiwgvVv&qH9nGeXz#RUSw+2rEl%m?J< z;sOETY;tjN<^%F_ae;tvHo3Ss^8tCexIjQSn_OI+`GCA!Tp%EvO)f6Zd_Z0}?CYvTD*GK(7W-vXufli!>=#)f1T4-R z0Q}?uAn+gnjDBMudjP--0RV4zvEP9`4FD3flRJxz0f496)KJgHr{Pwej)%==kp-=; zEWUM0OxyAK-kTs&(y#-P&kHTY%;eP98)DbEpT8X)9OSUVl#rIMYlsvP6BCVAFjcIV zG*T5Q?P@45?4&o}JHvOREHP|EM^=R)+=)8s>QHD&e#Bb$vHJV zFeQ%hAEpaj6C`hJZ@pA6*sO4vZ;Hb}_Dls{B>sB@+tAUeFTW z9@vH9x41K?CG$D6gC36yi`sE~&BZqPSMB~qCt}Q;7dP6DKS)w{Z87@**Bi_!$`8%I zE>%GnL50+=ucJHZu36@A*)UO?bYTnbxLicx0Hav5iI=H@ySMb4boS|%-gM!R8*XHy zmD?VAPt?Rc_?nu_x_7d(smOH@(qFh}FFGWsK;`0?vohUVxZNegaGSX1-rU!1exI)y z?y`7mP3ew-ZifcvVOs}DGhIv@`_3m(!vUxoPqISZ{g`|lfZrvr zV0=4bkF?92xwF!6&bM|vlE$U)d6BuSz}sZsp7r~kH|o7rZOOU3Ex5O*XZZ1OQD<7` zNDa4kX4ou+rLnJ$`2zY55eAq>)o451t-HlxqH}R=;t=^)l{dU4ZUaD{7&j=CbIxc) zi!Z549))jmH+|N&*K(faGPCOGJ&Y0iMp`4w|B6H-Jo@F;q*u?2Jg5 z`xTU>XjriX5D?`SGt<};2un8AtO6iX+t&6rd31C%h%w7W&iR-6^JS_jJExuANk&|&B1-ZmK5XU zyt1sFU$)@s0cRYdIxEFZk@Ue%wXfw7+rLCDuX~|$exv5xef@5G3+$mb<=m?dvF3~K zCcIGS+K%d1P5dHtC{PyQ?Y1kky)ylBCABQ{t%&G;Ik)-%z&P|h?0}L?EFkZ#gW?VX zz@gHiXk!f#pgJl0B>)utJAdQJctz_wk^o?y8NTA2$@Cf5=kUtp(ypr%l_`qirkyK2M5{Ke(I&opykgh#*)o__yH-#l0^Q%+3w8${*%CVff zwg38afNlGt2w`Bi5Ej;(SDJ?CZN9b@vyF{Z2DsC$S<|>zE;Cm&Pi0%)Y z{YG;0F8LeO9WgPMZq{yQC)MAmT~a8Nbd}n<3wh%o=%JH#m(+t5hHeFUVa~_6t>!I# zyLi#!4E4?b$j$aRgj*taH?G}Qda-&8%1Xw{57&%?WjkhL>*XnF)=Rr%Xm_8rOI`@$ zL6TzgV`j$K#SP!R*`7ZKb9>JVYpG*P9J1pT)}Tp79pcB2piGl9PpzxY&3GtzY7gef zdMjFHfIZwXGIzF)e~Nl_>O8Z`Y*^N#`zaJ}%AgOti&H4|bmtg?M2 zA#jH5ZrPpXIIm?3{1${P$eEwN0G@1pLgGPEa)lG(F-kev`|!-e3}?3$A6IOh8+%V7 z0h8d85Sq|=%E_7SZ1jkGO2+B5^UTwmUACQA?R?SxWv37)1Yr}=1H`W0X z!^#2h5Nk&>_9-%t97|4rwWV4_?#}tPKK&)&GZ2b4KwI3Rj6CIt}vpo*}wKR_5q=r+a)z{Z$Pf=X`ST& z?L*dp;_Kdq-a6Hl2pvh?m<3d%9-*%)hVZZ7VM;+=->&B;XI1(X#@_PDsdU^fw0Y`ch^3BK_={G5FruFE5#D7%(Nc&i; zQngS)rC}9k)m9eAzbb&rEb7jFu5&Z@R_@I%S8rwSqwMteXvGt2V=5Jr0+JLRX*v6H z=tqJp6FQXM7S>;WFp!mcEwv@@3GLz2D#P2`P7m8?r7GXubknfc4a|%*zCS}xOkD>#k8dv4G3CA^Q{eS#g!qR7_1@bb4`~R_6}C`Nbr%!k`pD+ zR>Kmt(1y_D(CH%?!>c}5eu@56`kec2Ucaq`r^t1Y4w2$;rSOYleqyTP$>PVSqa_YX zT$=`;ft_nQLrT_Nm34?wrua^Ih@jo#t(j6c_nu_>-1W+z5migA7d6a^+FdKzDj&)? zF=X9UbwzSdn*32rD>M5FQly$)Z0=firuFRL|b_TaC92_r7F{c2ZNc)7n#<5;=r3 z9WBSMD!%Hfsmus8a7VkxY}Jc6tdMlUsADI@)E++Ht|NzTqcZ#5uG9!Si;`mpkF7hO zU$Dj??p3-=!biQQtG1ba_StQ>+W(HWl%0bHH+DhXRkimvF6Ir-c(qTqJb~%Qr^Tmb zIml8HFKIkRx^r^g%_{IK(n}hQ^UvA60D2JW($B&z7>~Pgd$c?{SNk8*p{Z+zTd;-zA*Ei|W z2AAzC6capnOy0>epU$l=c=f{7*5lFE0WPhn>Dik6dp+H_?(A+lZ_vH;?3!XEe^Yc>BgoaS*kaoNz5eZvr_oAY%7vw`LZ22`2HM@uhz>a( zGX0}PZ?`XpL2Wr(T6#f>=Ae6U5e~!bNDX5&rS_x*US_UeA$P;1L z&CQmZ)vd|f^9Llmaa@ghOsPK)mPN}nJX+lQ?}4mzmCY)aCHdb%dyy{*{^jUs*Nn{c zWrqDj?K=*=%pvAvq}v)9K1^=m4qA^S`)yjcso2}BHp57f^VT}wWAN_#XPwcT`ihtz zpo3n`>iKK)49^%^hBCiA$DQ54=q3$T_P83H;e4>^URBroVEbp^vPbO4pB`&%I>IgP zz4JynpT6|z!UFZeflmP+dlUnu-&(h93XTpsJ5tj0<@NN>Ghc7N^z}TcjMnzav&^&h zru)oZIjP8uukqg=L_V*#tg?Khwp#6Abh@glvaC|^J7UeD=Q$U0X4l>eb@|5aW}ohC z{qkaXZLQl#W1q~>{@T(r+}!u9-qX2fG39FIszo(i!~PQ^c{R=3dJB3BTg!`8lb4Mc zf3<&K_nAc~j_y(B5mMPzZ%+2z5o37wsj%|`w{esP$R6g zK@f&7KqGPRkRTeB&c*~8LdSG5{LiD!a42M~3&+n8YBD+?#LdPYV#Z*RAZRT#jDSGu zKvwE&A<;-3J)|ZCg+OY<5!!I1HVlcvAoMXvG-Tod#Y*!(8L)_CjDz{=iQ)K`A=HP% zVPfF$z`#JQKy57s%Nvf=*Vl(5P;e9q#_s`RbLkv>5RA@N8yESmV@_fdSQI9Q!k|M& zb@5&de~uv(Iy%sg$Hcs7%pU{M*%R#e6yZU5CLF1Sfd3)L#zt@$jrQ9}Hpe1>e#CPr83#`XAK)0j1`^D!P5yOD|0M=?phQI5ku0~ z)6vseNrd5vD|KN6eH{c$pWvkpLm=?lNIVHe#-qk3`E&R$(&h|;|7Z$KNE7+e`uchZ zJ#7LKM)pFjgdvGKUNAirf(#=N$!G#v52;Hg|B#*%{)@C7i+>QNePrx=#s2PYs;nm>*u_PXEwp5SL&+Ag>S?2#8=)h)XaZkXMKc1VpeY#3h&y$ScGJ0wUNH;u6dUFZIFH+_0YG%VmAQ#iP!lh)cE8P*`FD(J z(+MN%yAqGz^*Vz)X%ZKaij!6+640yi-EbGP;zw|e2aG(|=qN9@UY>j1OLKXAHEy}Z zrff3jePdB4=IPt3MlJ6j<_~@hE$ze>_YQK8u$}T;TE)6QMGlwEYMvuywWN&V>D<0M ze0iGzGj_*O-^)!YsS*v%n`KS{Q3~fE6eQ&$SFr%r_!z|nk%*&F! zx$Sdy*zWAry2+fF!L?SG8^0N5;!>j0B9r%Q*vEQlOXG>PhIyA2TZeqUj%q_Qvr>%# zIb4dkT%>7;`r2AKk&dPANs*gHnyG4gbpo#C6kX&7B=}RqG|J38UDuYV)ZE&bPW^Ir z^X`H0Y^h9Wmp+r1UN3qmjxLfFcOr~kd}@{_oLLd@BtYVDtWG+2E@|B~+b7Rx*SxMR z?NT~-$@PNjtUytXuvlh9QSXc}m9jOSj;l34Kx3|c`gC>nD+8|(kM7e;`cw|baM0_E g7wDy+ca@3(47Cmxb}y`C^v-B23tRIurk*?g3sgdlC;$Ke literal 0 HcmV?d00001 diff --git a/static/images/lg4.png b/static/images/lg4.png new file mode 100644 index 0000000000000000000000000000000000000000..0a9c22cbb022fb5d88d5f4dd30b22108f81e0cb8 GIT binary patch literal 17986 zcmeI4dpOhY|Ht1B70Mww6v>+MshDk;SS-g(IpsK&G_x^wY8y65N@s-zemo_v?PX?)!e+uls)A+jYI|bF{aX zmQs-d06^LXYw5(lD)Zm-B&PHK)WU@Nn{EU062B2&cV3YAtg-X5K-36{CV%?1j=>*s=AJ!2y?R6D^{pX2-Q8cFeaUN2 zX&muuA`T)qD6Orbe<_xN4)5Q zNVvxhU2DAbQ2JsXs%rbKnz6ziv@Ga#UQp~>4@sWrYtYUt{kigP*fUM zp0K7`Pa!Anu}biV-lpb-&37o5&GE`huvMVPE5D-T_f@K+e9hr_QUjwN{K#B62CPFd%C^Q0E5tH4b~~ z)k~(YlX@I79LY5tF

$-0^|2+I*>*GrJdiAJ0d;iNt))NoN9#j+fz3&# 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 ahCp$I{cgod&8o47ac!*ZEiagF+VNjhX#7n8 literal 0 HcmV?d00001 diff --git a/static/images/lg5.png b/static/images/lg5.png new file mode 100644 index 0000000000000000000000000000000000000000..176c190bcf37b0d49c6076498f3473732af28056 GIT binary patch literal 18281 zcmeI3c{r5c`^O*KCrg%4LPaA!6=N1lOpKjTM0V}7GR)S@SVko++J$UcTT~)xk3_Ut zvPDRiP?m&{B>eDtfB z;s5|h+F~r7xJPB~S5fpY?r-4&*G=4m7z5+U0sslQiLU^VkTf3v#O=uz7LJbIbT*yk zO=qauT3Dzum~;}ELIi-o#$@LJkEqdk=+;r9w3~Uu;FUPaE&!sIDOw`qd0OTefZZ!2 zYx*$sfVi9d+&M`Y*9W`n#4*VSUYuN-<7IZ}z`Db(8w}p4G^gFz5j4=>|LN(cyzZp# z@k&mWbjTc8jmWOkK7gT9s1d3`CENk?pfo>3a4x1zSXHL0?4Fm%LjV{Q;sge>FPn@D zT%rSl0HaQOiEMHE*FCw88t#B{sBMz8+|F1H4KD3KHfYT~G~{tG#}Q&*%(>+hX}P#G z=7ns}PUMhE>}Rp407)QopF`oAo3n0|Q3`|K2nZgQ@~H6#OoNA^N0cNY0U0k{Bxe)= zq6)^sO*I98inuc`0U+U{LSs;FDeyo|IOChR3_{L=+rIT|K+GVcaMHonSx5;kU)yq)$Ys>tUd-L=5 zi3yvPh{|CXqYli$9c_SAiYmk(6^39jy2nD!sP-I?UkiCy!aO6GZtfGg5u^4N%9J+@ z+hF=JqNzj`d1(Alo(&>;*VVN`wSs=8x6Z359V$A>s%Gm-Zw!e&?OUyMeUWj<&C_Ys zt6%xCfgOjA;zOztQlul#up5r-x7u>hLrJ4}9=_8<&n;XJztCfa|6Jw56zqWL62ZeE za($wk_R8F&?2d@A@v!r-IIrHPc3n1C)Lm@PUc|k>AyMZYuB!*hjy(v(p{_)DSZ8Xy zS-fa*iu$I%rQ|k8VU|dh9_v^mzF0j1X)9sti)q3@&p4k!*T|5Q>@<2KsHM+4M6ZTq zs>VfTM@UCF9Q#yyzav{7_3*$8JF(MCoX$kcuF@l#bPAt6fi#alnX$GaJ*8GO;{fW! zI$P>Ve@B?}{&YEAzXbJ)#CaBFXP~Kdj}ypVhsz;c~%M`obo+9p|iFuQ|R<7pt9jp)P%)>+N*?tV*W_k*z+0FA86E8mSPo%cWzmN}KRKWI z3uG78uVk;>&Sd+Q`%@Tsy=U5W@25XVzu)8TrR;Tzl{~DcaBg)(nQWYYoPsko?NA!+ zL{M2wr_!6;nj23>QWI|{HeY;3t!*hcez@bpCwuKg<c&rP557dc!@(nzU?Q%jm2tZ&ON+qMOTHYR?o>=8m2p#@I_o!Ecp+#N`( z@g23``r!EBS>q|6R(>q|9R8u8o%43y&>E2~0(S*E1@d<(?Ybu9E2JVEFMM{Eo=BL; z?Z05N(R0mbi%EK_Fr(;&3U8Ii@H)+2S_##2ABiTQSPjL=vgMYD^&jkb(D1Fgx^p`0^x7-g zIjfA0btSvSyfB>mHpUumno9|_t4_V{l;tQj&klB8GjRR< z^?^BGPM_B^%2&I$qAh>cFUgh29O z&5knfva7M59bb4jxxV$`G`~ISw5R6mSqshG?z%DQ(WPaytas~f;pbvw2(AM@adqq6 zb}mjf>$Z<@sEv)!S7kry@5S_<>7`|kdKO$-mG5I#_juo+ zFp`~)b~NjJ2#fOeZF`h`_40s z#`=PmfNjH4dlt@J`FtR{FYktCpu2Cr)s7Kb&70jV;Yv8=+=8y)mK>V^hleTQ+sZM@xsFcZY8r%wxQR zjN+QqvsYg<&N8+MW_)hPTv|`>C61Q$yBlS(-`V%BtR8r>^P^8;9qZ|br`j7&aPkL= z`joS28Z8TQ)N@BZ_`mO02oQf`*Ss+(Jn+)^oyO0vXML1@z4Q8)E5t%-+lMWMTdMAR zN)Jeh?N9j<{q@QI_8OaVn>saXwXpDH6%}PkrTn*q%Bc3Vt7&pokAmI4a(Y=8x?4ZL z__VspW4vKdV(f5LK^7-{m^pAE{SvBJtym?ml4Cq{Zv0|p(~g0hf!x;Oe3kg6w!f6O1A5diHR8h6T}^j0s{AorBi6;Ddbeh6IQSTHGiQ z#TB3u*;v&;Duu>E1sX#pby3{&iDDQ;b+QWE*BD|p(V(h_y`!oHok>*H)7FFH;Rs#T z6^7afJ%p|SLQ541N9e%dIxvI|6oEv+4N(X^)o&jNTAX`k#3YbVPL|f+n&Vo=5N|e{ zfr7yT0s^!HbhPPAFBrnm&=3Yk!jMQPw+58Op|P=nP#Q~ZO60qaC6R?^k{N6=ou)dW zi^b9X*v1gZL_nkBKK*`4eeuwclL?R?Y%C2=w6#QYyR1zn6HtaYL!1s) zZw1s4ufGDSudj=PVo9VGP&jb~+&~{k)WhNQCcF1@_%G6ybiCih$bXY2aHaKh2m}KH zi3r8P4Go}%Bwc-|;R-wns)Hlx>FXm%`bZM?yY!6kU!)zF-2E>NOPNt;;_CmWP5egY zm!>de7B^!!Gct*rPm`;QGjZ$BrQaPC^5iPPz%p6HiOFXS`9Ax8EGs`&jft4aNsPkc zC)O7V?T>jrr88OO&k8I$i5-At z63x803Gok8Z%Xjz2(YpdY+@azkpB+`fQ9w{-{Jpv^XLCH{^_j6dt+%{L;@Q2Jz>8W z{JRmG8poe!()R`6*O_PZ<0gdqKJ(4EYuCgCW&NB9lM~b&>-BT##AScWoA1koj-j5l zzP^E>g}FJ>N*{qRGqbd`Lh74a8|vxk8t9t;KGCL1f7UmG{kyB1(FqGWh0e666NqS? znbFh5(-3DwasTFXocfm!&2q9aSGBdW&_@{R>qC*+h?z1o>dnw0;87$xlZs`d$yBTt z5yqf-8NsFtXVjdy`=Yo@BzMMQCzmF!`Y&bR`W_QY9mQ|5{t6_V`+*@Qe!qpzbb~`Z zd56w)gF~kyU1?-C8u_g?Q1OhYi7f(ZlCv{+H%mlwy9O=-*LEZa5-A>*WbQ4EHL*}5 zSA2^BJANDJIU|sJ_nd5OGH{0DTi{f3&De8JCh=4$cSp`!-<>LYY;cfD9@#X{a@^OKH@HY9lc=G{y`M5wpc$<7&y!n8xFn-9p##{~ky+vMZo z%?IS=;{pNUZSryP<^%Hbae;vFHu<=C^8tDJxIjR7n|xfn`GCB9Tp%F4O+GH(d_Z14 zE)WpjCLb4XJ|Hh27YGP%laGrxACQ-i3j~C>$rG3O^!uqq8uz8t0PfqT;T-mL?whNs zc#M-h00gN6K*$~d82idS_5gq%8~|Q#;lA{G8~_yP$2LE-1^|J(ww7itfsJ|fW(U@+ zm7g_uBECvc^4>j?o0D8*=#upkK1d05#js;bJsXxPOURyGVo%wZ5L!+uTIK0+Ilh8o z7k|$7e0=D!y-TBx3_MG6uNv;!*7`JW;M3Dy|4QT0@qt_2dE2zZwn~(W7kKuCx=J2+ z(=NEFO(^%qz9r+*`|>W7e>fO}$A3`jUyex13h7&aMEOxky}N1bIiD-5XRWoqc~g$? zH-5af5)**a$mo`;ca6R#9PVr-DQz)^{w$_>&xEjl$XMP>;z$)fL;R{z3Qi#Lvdfmd zS)VeNN2uFrSqKkgpsJMSsb$EoylissYuK0NrEd)m^%}Oc_(!%B?xHV-uaRf$D>;#a=vvEN zN4o0EJJ;7T9c~F3EFA5`NJyVpyx<6Geo=T|N2>tPWVdrS)@~hS;+%+ zNo7d@0HiH&rg;9V68|}0d?pBRuhFUI2raxSeM z6}iX&L;+^4#uE9GmaoBiHcK4=NF>kb~;d>5!Ivw)Tb=S5C@Kk0CCIBmxvnP1YGU+;8%+l-2sv_4WSy-in2w5 zoUfzIMT7FE1HMO{B4iC+fuK0!)#U(0PZTg&G^augVkwr4s3~mDaAAhz;zWR=vgnG~ z4Kcg9gX2U9)_PsAo`QqKrfMOR9y!dkKu;?^EZevwngG+mRofxx3Nugc34>|5|H!ILh*(H zAgXXA+;Ei$P!XH<5&&+!nz!}baV5+9;s9Wpyl3SlqnWdAD`XbQB-~zjt4K+dFvHYv z){-K9IpY~^K?@{L&xOW*B=#Zo{d)g|QUS zN46S%jA$%{pbm{5x@C?$zURs&vB#o5hBwZsDj&L^%&z8W$!-gZN%5{$zPiXD=z2mxzW1 z&FK-}zEAEBb#Fw3xs#=n$vO2NwX5=Z;*Ju*`;d2*L8H!DUsd;)AGybM!(5JVT9>)> z&EiFilhn5_lbPcZgJ~~P9pbUG$yEu6g&w>}3#XgFy@qRV4tFtTk zz27Y9{nEiDIJf2Vz31 z8WZgh9T?qt-p-zFzqXclUdrx*z3heU4gqJ^+5cnnGDG6=+zYiC3+-=a=ww&o{qW&7 zRhwK=3tT?${YaF)vOi>9@_t;Z9Wm$r{3DC!-baxKoQ&&O4r1M_y-!%VZMibiW9d8n zlZr2Vr=_h4`@DOmd!&0}$BqgSnfsTU`_WGm)>kgBl&;(f6N9aVU9R)Wa?c9P(rxf> zC}?o&W%bVO?QZDvVI~?Tu1*}p&@jV35_vj#oAN^P8hxr>WB(;~^SUGk9}dcNJ*ze! zq`glaRC?W4*H^8oi_j9+iI`7C>Jj_PBZ#lOPf&8J`}eh+n_cFa7kSS!wb~+eS?9~u5QY#&wS8x z6kVI(okS>jdaH5tNXQwpgyQvKI$Ejz&h|81|6PcTGVarUfoTr zbEMj+IL6P4$HbRiKbIAsb|GpK@O+^Hz6Si`LzYdl`4T96eM#PO}r=X)B%G5K$%{>l>?NOG`hL zPCw;e7TvD=Ca>n&zk{jqH{+YKp3)vaD>o<(xbVqJBVOgfwz~#>M(_KFomzL4zf4Sz zPrvgnq7%N|cf0fUPx*_i|4CSyREMCIHs0IPoL{!n6@xV(f2`~h!`{b=p7K8xT5z@i z`of?>%J<5Cj5%U&PofbFk%uMa+ zN2cGL0iT6cG@d0P?X1d*ViYO8RT&{_HhHW*S*`d`JW+A8%11=`Qp-hkvybkt5`Q5V z$T&M<*;RgB{6Mog^+2vFWqzE}NPxnMm8kO?uQy$_)`s$H}r$qK&(7x&Ju~V^5A~nRaI`t|(+eT)tCH&kf z?v{C5xVgA|+~&ucFWkSp9#NCpJ9k%p#3h^DOaIj8a-9d7p@n8Q=cqtxkCRw_d!aw@2~8HD}J4tlI0S6`gVXK^Z;!{pK4)MM5;mzRxSR zc8kOAl}gbrnas>{*&i;g%k5}&+~`ufYmi54Xn4Lp=V5O*t~;%po;mDXcyWEcmr?Db z{r%EeDg#H_Ra|K6pL0(8dkr3~xLWbBLQI>W-MgjydS>I>(>kd`{)xM{l{tLQx{y=w zbZJ9f;WNLT?_`1(Dz16ncf9A;wN+e4?|id>L3+)bz0bmx-Bj`lI|85On)_K7Cx!1k zvvcNQvIvJ^w#NrC8sd9T`dwpgUMX|OsQvb`7iV|vd};IQ zbmiTqyA?0ucIOO=cjI`gYA}U9nXpt^vcc*6zE_7+6Blk@XkL)>HLwr)lIT;S9qyQv zoVeUzV5Dtt)XQ{IdQ#%XwFZylns~#OqjBEbHf_uIFsVvftHgO@nd372;NA1i@NNCK znD3#(ZjI_W8?p?t4a@_XpIdMjw=lZN!)3jW`q`ZKR^4l=`~Kbi(W|JI{p7C;7&*X`6pI_u^-VJ{gJ7q%X(6{u|m-V_t4vtF}(Es*1F7{##OIR7?7m^f^@z10BBdy4e>x zUwm%;w4usrw7y?zB&@11o0sv9)psG|BBn&GMDRhoH$NamKY*~ra>Sv+{hYS8k2tv z1pxiETqc3&P3Az{$Q~5B0krRCArwL(89*Jitq@jB6S5}-=g%VB`fs!&`g;@6Bh7XHKHuELZIcmSV2qJOdl3?959IpCsWBZ z{+Mij9P+nw;85Hr7w4xbjCuYz9GOe`L)e&SB5XVrCRRwFpMMw=7MZ|duq|iwWKlTcJIJo!ZQcntzO$i(_7KK0|Ui$S3=D8wp+9tMG! zA~Mkvq+!KRdlG>|_#2g<`hs;BB#JxluT&;`{;XkTg|VQsIRrY9Y+;J!&s~E;Az{#N zC>B7iJH$9j;Sqlv#pi!DI5(!Pz)zKr8b#*nrOHT>^McSIhKM2za)G2+&uKs^I z#BXGN845>X^HYa6C8hX@HC|?H$vb{-{qCSr#>)khz+#ifcA)|E`!@VhUw)L2v6%7Q zj3E%m3JsPxmaAlvKK!TF$;jM5AM;eQ^(&y!3Sl<*T$Pi)Oy(}plR)<%ld$mb zY5Tq5?-p%hDSzHi-^;+S`%nMJXA+2jvm^?*cfG|gG3q`nVOoRbd1-bwKcW$w2XhBYZI+M>+8e+?&_vY!h}I(u&fv) zGL~QaCZi{tCm~LW;{WPrGx4JzmW?+zhFF-H=pfNLIxv(5a;nUfep7TvM2tIwMI&&q z6dJ*U3}@0k^x>0@Q+kel7-RT_lD}yQ;{}SZ{!1IUztdR3qxy{Z*F_=t4>)q{@3+vY zZg8lx;LxdVaOh;DJ)OeAqP~p=YMv4`c4EMcbGGFlZpm2w)WA*P-Zm62nd)Rp;eW8P z$I3N|zh>hxV8?F*ou>q9PYs;n_!c;kTvLvq<4HWx%0J-p&(`oChwESR`^SgGfAY=b zjQ*3VAT8k_ARvNGAuhpuKwcp(5D>wp5SL&+Ag>S?2#8=)h)XaZkXMKc1VpeY#3h&y z$ScGJ0wUNH;u6dUv2;Rcf$d23axXxgM z7!tTY;Nl$?oC49)I~WGZJpeh-ns&;Ft7W08bPUv2)OJR<(;cXW_Sx;!mkOyi_xE;W zEJG~2^5Nd5IW1MEXPNcWD;$xIEdgg{Tt2K{Adm65^ET&_s$=YiSM`f#l+HAS`Ka43 zxm|^Leh%&od;B$I84tTJ`h-F;MeHV}nYQ>-q1h(SD6fvr6O^JzjkYcABP#1}%)M>S zbdh>Kzs4@R{&k;Ek5g`jVlh&I8QR#t+I6Lwr0g;Gz>pi~Z?*n}sg91n24axidh z>*6cww&~%K9Y`CoSpn6d^80OzWbcwNZbjj>N4~Q5zp>96S|O7lmHyS8TX;@v*Ivqk w&?Wi%SDEd`ht?_#$2>h0_=Ib*H&7O64s&T3*!0kM?4Du^vyGEygUCFB6k28AUYqHpVOrvo$lAQAyfUXpyWbN@}!y zE0V1u$`(aJS+XQ#DO*X;prX5)=lfjG@A>1ou9@o^_k7OheBS4r*ZG`tpPB2r9k$zG zDJ!EY0|0=m71kUlxGImmrKSu1HmrD_Ah<{~v94?Ykjoo;i$$!IQv(1Q8;Y5kot+nh z!(e+cm=G&7GYFH#AXBI$0N~cd+55Yk9Gr)#A0){;nO67Qh@|cTpc;IsLIv0J3MT;k zJ_SXS{QZYyoaQRcj>S6W1y{;o;|?_?EKB!XbL7yb5XUVB@73#)Z|@4|?&|vd;&WzO zY}-gFuS`B@w&K#`t>?V~L)?BNbhUbzEjI6QR*<+7wm}l2&|37sb6P$C^hofyft>5B zN5rl%0C9j>sl7z8pz-V847;Vy0OUB(099<8DHe_c3bh>y=K_WEf$R4F5M_W<06^vK zG=&0}Wr5C*R+wo(b;`*)WuW@}f)pv>m>3YX%yNmi$vwc`aSu*QJof>Rz&C+vOXgk` z3v#`KvJ?->ng;lVx`fM{xC22^rdq`S#6TP{TQsLc0%9$ZfT+l6NO5ECPsfS@xkV8r zk?SjT=B7tHRrT-dX=qy9^niN96tBEofh^q&jg5@an1gMTur8ei0II{~_eTv@hqtvh zH@1@7sNEm)&yV`_Frb*lz4fD+N5v%pg$-rhHEt~}RT9hsvFpA$J}H}l8YjT3et4@+ zt#raBnWq86Av}W-lST38>d@BR|Hyu3;G#uhE5BfTz%)9s)(1-!esHw6??&~ipZ+3!(q9(fAF$2caA(HtB5H2ndol44IhP7Qz$EYk?5OI@tDh|2mYRTKzB~%k;M>i_mx{oxFZEH~6vZsToJl%bM{Db+K z2c#v}6iUs(FGe4l?GaiHEtOJ^3YCQ7vAQRMk|6De=5B=M7qXJXQ%t>&Z^df#!B}$* zk8Lse6kb~hK^+-6l4*%NwddwWiRa?JCU-BXs~&ljz%J+L%5M!iecq>B_0}TepgZT2 z%h$j4j?4r7~U>>2xMb9ZrkFe0?Z$Blq+<1Jq)DrQK zpgEmV+x96upazGBTe?`gm|fEB)VQUXA>}N+cOUY>U(l16Y;S1>C=TawJ@bJ6*SnyjVIFTo|9Qe3A;THPXf;VjBDD&g|Rl9c%8QkM^* z&u+4!CHUFF?GL8R(e;hiEQy(CR+I!wtb7_x@uUoT!P_|*(y#U|vWR>dS>f|`MtfWP z-jDvXWDm&hEx>v#Q}I#Rp^`j5O$8oheR0~e$f!aG#0!*Kl;;`wGYm(U6$2}FDjk2K z7=ey(iU^EoyX@e|c3fS_yFAn3ilh9MZBDx`u66v!?oEpH^LbY)Qx-bjOVPhtiu1>X z*_CZ{OU!or68woEd-K5lwFw8Xi4KIcM=Hk_&wGR-^}3i=v7972w0zFkcx=8o+-dDM z?X#L6e22BY8T&GsPd-kLYu#QVCimz@LyzIh*mb3gOJz%Uz$9R+VK=J0Q^~1;seji5 z)MVFqbg{bTb#>Hq`!eH9;R~O8MVG;?=a5@9lUnw{wMu%?XSu$ z`)MB&`<35yS9O=G|BcX<(hpamA`J*V#o>gvK4&QDCU$~d0ql~`_-_*eSU z_Xj=S=y8=XWIkho2VeI!sm{j;??FM;CgmmNH)k&|Ipq^g&M3e2j8j}(s8z?W=0ENX zHLQ&FiN|NZ%&Z+bw*P`fZ2r0s{g8swHK%tLO*?IKdXRs{3FE|b>UVmHVzb9$HI0DeGofHqLJ zuy}#u!m3rARXbT6-(o*1GqWS9QTJg=UdqFEXHPZHbL_Yedde5qhZiYE`b8?+(~^%Q z)6WJJMYO2CWltUod4UQAu;OWN~S#m4!&u6(x9j!}EO^`UY1nvXq$E=}8u-^3-y zBtQ5N-Ui?1x6O6i=d4Ax|HLkhuR_oYYx6cYWEJgjM`MghpGw;$Fpn_eX9Lb2%)Xcn ztvAlr2&@W>3Y;+#|9RD?qAy`XIgPx&dA%E^xr^NwYZ1%Zqq^rG2_Fe{$tcMSGxVk% zn|5zHd=^H@be6QNt2*l>BUiakZJ3}_=cyH4uJlAIPHB_cCq(g5>qS+wLl2Zm)hh%t zE)H9_7vGUO)L=sD#d#^q}<1>3g^bhb(#{6*+U3NOv7>&a2KdKKzC)-bRhqiEWN{IL#qk zZK*qdSGl#lv?$)+$W_lZe5b+wGm4QnSGVkinA*YT+qNXrZ5Gby+ZVIn)*}1-vGW^m zq@}MjI?)>E6ft1%YSk{YPhJOX*ZMxvk+#LH<_g{)cw}wiMMc9?d0ZJ!!NDm zZl1rHn~u%GZhEd$Pab_YtT8iq-p;J>>vrka|EW&ry7o3eb1d%7(+IIw_SZ&k#bpq= zl%9%RMP5ZWPk*s%a=|(FdGqS}LUDU5E?h8M8SJbZk#g#B5&i1NO?L@O_z0q7w|8Xa zW~bdNlq1~uO#Y>-L)X`)w>CL%aI4(e&!g4Uyk3{~q^kqlk<>xw54z@DTbJd%rt;~5 z9@$j2-eWClZnSl;Ip+er`$J1^l{_ht(8KF>Z7#mUukAahpEwW@w|i@m)0fmMY1uEA z)>P%Z^55}6Ztp^+Rj<2Gb!OgP$#wS0ve?y6uXrE)DooWwEhDEj@Kw5{ziobe*p3T3 zW(-(#cX)Fc)VgaqIX9(gIQ?UbuxMsWOc0|crYqY2HgnSoxd&@n?*CPPap#UVc5ly> zKCF9KQXjQDtzW7G%UfB2&hh2L5@`v>=d!xr9!-o}xNV_jcG}m#ZsZ$+Z-HKzb9_SF zGUMLi=HQcWl8MRjaT`_}KaZ;84O)*x`E1>|HOteiEPk~z=e>2B+u-95uiL`5_GB_Y zLI*u+HPhCo8ecWG3}k+3#9rIX=pYRibvYYd<$Sd1SXJKrZ1*Sc+)DO~p%>a)&+@Xm zA9bpw(U-njkgl20Kjb&irR*>B-nwpUKp6MhNOsMacQZc8zuSFl^ad%H)-dFr>t6QI zRlZwJ`e6L%sjtrtHda^`TUKhU)i@Rwr>?FhtD4nEEIrwnd^34Y*^@x0ue=WSmA3jX zO`q47xr|iz%p49W%el%+`M~PFl5!1Qpi!WnS;{l+y*QFuTDz+|y*s16AWJ=J*@(%g z-G}l|go5O!wu6|qouec0!F?Y-YgU}q0RZ$Iih~Qs#l{*PjM1}`Rn@eK~j-dcx zw3^Gr6MRSR934uk+7f*}#Q8Y5%G zMGFLIBn}?JrBUf@G}jn9u8S6Y9xH}JA>&mzKE}{BV+}%FZ0sOr3>FEZr>zGgAdtF{ zzYVpKdPrRZq!t8)K842eP`4ADqE$hQ|1BO~}^#3GW>IP6mAe`6=02P^yL)e&SB5XVrCT7S;kbh`1775Q`upAf+DrO?f zCcixizC0~+rqGEDfA(@CIJoxYR8I<#%<&u&28BQ&Uoy3K4BU zMk2{XJrYbGML@xHk-EAt1Ehxs423tqqx8u7NCJ6ckUxk2B5lqf_>Se!H)*0knoQC& zAQ3(EVIC-bLl^?3YY6l3FeJhZ5M+XZ9@5YNLDC)PCy<^J{)@CNOK=dT*ps&ZT>9NXrHpSEOgxKC8e4_N(C^Fe$NutT`xuKE zU(IMdVQizp5XN$qL^Oi`R65zMACcd}D8EkNzoR^%KPCLnZTNeU=)w|yLTbF$pGDXV zGRGg!BCYWhMwD&_xR4%m3V|J@AyyCwAheFi3Tm*9n`dyKlx#DME^-ukd~+s5D?*}2$yg^Ag>4)2#9b~ zgiAOdkXM8Y1Vp$g!X=y!$ScAH0wUZL;S$aVmvBBHuLu_ih;UPcOE@2pSA+`$ zM7Sx!C7ch)E5Zc=BHR?=63z$Y72yH_5pIfb3Fiayig1B|2scHzg!2J;MYupfgqtE< z!uf!_B3vLK!c7q_;e0?|5iSrA;id?ea6TZf2p0&5a8ra!I3JK#gbM^jxGBOVoDaw= z!UX~%+!TsSX7Wi-5?%0kr@!Di&gr_>P&RhztW(lAHQzJzOy02TB@iZ=j&&bw&kka(OIFMAGur8(Q)+Aj+d#% z@sB0T@<-QmHJ{lysE=hvj5Ir3okr;cgr_a)_;R2MxQ zVmF4}Zo1c_)2Q5pNeSs&Hx%!{AHfY7zxS3q9IbA8_u|kOjp7`~wMws#+Lk9u*FaxK zzpEX1o;g#U@G4x@s(Hz*J5pEX`kEX*xao-V7QJ`MEg83Vh7R=ie|h>PzdNaW zyoOb~Fnp23^5d`5`~iK3eFms!%2BqM(uW1%{L+{SuIl!~blP$8qv$VyTLclRTAYrBDGJfN`fS2=bhc*1gB|s|M7@{Fqe1$LE z{Wj8)KfGWL5ESVaz0lYT2v0CwQw6B#@dIW{B&!8ftOZix^+j!&p0s_r7(Sr5GNw9i zL%pU{Zp>qa;P-=V9ZNe(NY_lUva7@i!kv($xI|S+Ot*k_%>n>W7^}NCp=T7`{kpUL zHKCg{@UbjyB4CgTK`$L@oyb4RF9?WltQ~0b?CNS1pq2Aw2NnfnZU&lM0Ke8T56x!b z)J-CfL&uJ=^u~>sq@1;@Fi=`7GJk%*n)lfP_^Tu6Z<_7Ywj*I99PdPP=peA|v~faK zaeBnpZCFas6^F>~Np~S?dQv0AQZFdv&(Syao59*u`Q=_muLBW%;pl&5ai< zD>e`}o!c3{Smdl+tcko+G3uG%t!x2>)J3P;#c$q2=!tf>No?8OOOu`JC6`hnm%m?F z(4<0061x<2aFKW9Gf0h)Y(k_U1dGu+5q?gk=b)55q^yE|jz81X|F{Q6^*xj>rGIRT z@#pB~3Kitx@x%F+h*P_-+Y9`|A835%qO!u_2dRuYrq)7_@Yu9~I)$4{48w1yWz=nW z6UYR19*)F?*CE6RN1tQ296ey+b;wO&dASU(%T3!QN*kx-rW+)!Se$|#5L(86BwVsj zXzO0_64IXNXiGP1H?xaseX2Jl@`PN4BlaRnRzOZ(w7sboDlt|X;*Gi%?Y54+{N2(e zOHdYo9 za%zwr%<({`q*mZ*wdzC}v&wVO^oGZ$iN3^9KUfblPxwW|5{tOUarFUj=Jj;E`of$iaS0Vp@TW+{1mF0D@l$47;^F=WT zw%yv%jB$y;CLAXuzus2OC-&f4+o1mQr1dpRYeZ|dLj|Bl&})tUS%j>xEZwHirotxg zetN%5e{a)3AT8NAc}?;#ii{c!6wcGhv(MX?*Bn^;7X1X*%jyvxel#rB^P? zhsdG{Z0cffw$@90OMn5^n}}>aS9-3jvv5`Qsesdjyt3^P9(y?K^LgRJQ(z&XMxirq~^ob7E~`N7?Z%Xcv~tu**}nRpXZ4HNE6USCXBg zYvO`LRAS}ri&=?Tr9p}0R;doDs8#i=h8-zQh`#YYk-pP?bNls2up??CKpY zjcb`}chH%ERY4?Le($+r$^X2lGA!G9`HPK4qT)l3`-TH19|uR>I<{54O3p~kDEScG z4ci*D)qU%if+e;$l9s15!pRlQrJLIdDz|%~(1!TWH9Z382Wb8?p=S;hUMPgL8WyUC zHHIaG%^Oeovi5W3*QifL?X34QLmTIK@!jL=;w#v#u=|EUfPk`Kg5ddi+H;Q0xjPrO z04;60Kv>jWnSPR5Ec;$@45!)RyXJJA^dq5U=}n5C;Z@76mozSl++QoyDjr6?FlOCT zbzA6Qn9bP9L$4V8-K5i+Nu8&iVwt!rT`g&M zWMB8xRHg(QxNEyd@6g*9FA;a$s4GIn)D9+R+m%7FQIdSWH*ue>MPb^pH2Z5gx$6y1 zyiRtB8PR*OcBk2Azx}rB0v~7!+d8PTj?168qx!+d#k}z)yY~6E=TQAqNvD$19Yl$- zH`SlQb5`cq64cdCigvPIlOHLbJn(3=Q+15-p;?-=&$=%Cro$CGF&S&vMfH%)a+^bP zF$I`S|7f-nCf<&z&fg=mqaZrlE;swev)mB(p*Bd7#a$WIBaX7c8VC=EJf9HaVExWY zzsl>eU+p^F9Gu_#vs&IqIz-f;KX0bK$5ksP^VGvi%9W3s?%<@cF+R=%{&5YPU3RUO zjqzmD*cY#S%3hcIy2Ev&XTy$R7P+bE<@%gQ{k@ppbG;PysC&`X^#%SW4UhK^ie@Pe z9qUr`B(HzTJR9mi99ey{`cbujHdecTbJcBj^ZT)y>pi{AgvrtHBlKN1NWYbpua!efBSIU_AZwRKw#8t6<ys=e>Na6nA> zK+43aZ%+=i*IQOuHmI&sJr7qR?)~sZt^SNA0H7p^PHs#$8*3DfO4h*oP`&XQA!Hio7zzLeMjts5iy~3ykqD_CtPR%PTvP&gcdOfL2&|* z@l32r2$@7-ph65GQ*lw8&y&S4h{{wIW`H5YWU@gOHyb+@Gb$agqOG9~#laC;D!Td_ z2yKLx9%79O5{}S>!8KtBO(+71g6pFY+A7~)5VQ#AlL6g_fO0Tj_q{oeWeD+OGHECn zEI2q=BUn>|O812!^!4>&a3l;;RHuXdh+~dt;OImelSrkgOvc4} zQv;cX5XfXhKVRR+MW+31h{E{JjzbX^f~CO_8gSTOL^d|uWn}Unl?q$xf=I2fLUCvzkWPUjJS>;mn__m7|Q zU%K(r{nybmiG-QS`9(YF`Kt^cLi~$t(lafaN`>heGT`JN%8ZW3GO2VYDwTwu&a#rP~duFO<0^!ZEOgtJ1N5Y|S9jGSU389BVYNND~>To?296l?^ zbWKnU8&2B$V42u|6Xln>;5bwtB7ya*Kuf+E8zVu0B*>TMGx()6>#{>gpo&ynQ%*_aR`X2KlS}x6tNPT;OC5eGl!!39avq zL+JQuVWHld2rVdHTgw~jP0-PWA_+LSj<&vz7F?I`BlIl!Z=r4JoP#h0OPW<@viJYf zCjJoSx27;e1}Ak`vr>waSX0}KBYxYjr9T`b;?#CQ!_pb}$yI0w`LPUt?k_*Lk4eqc zYDQsklN${hH<_z=9|PDgr8C|7sr)V@{yu^Kj`DQ;S@OTP5$uPja7*~o>*>cf@ca5R@WG)7R5}^UL=(waUp$OP@il5S5uLS&+m-&+F} z&r(g^Y^R|*a?XW#G-qhwB5-XxVhEn(W=`bX6Bv^_9g;H>QyQ@2k3#oZLao`tS&r|* z>2#WPdYjrJrb{_zL(Z`j_VZl&+wSpmfBjE>m>JQ3GAbw*uMrRs?j{cxcRnC54;Kgs zcaw*UJ0FmjhYJLRyUD}Foe#*%!vzAu-Q?lo&Ijb>;Q|5SZt`$(=L7QcaDjkuH+i_Y z^8tBzxIjR-n><|H`GCAUTp%FaO&%`pd_Z0vE)WpzCJz^PJ|Hg-7YGPm|24fq-x~dAPXq0eN}2KtQ;g zJY3xQfV@0hARydL9xm>DKwcg$5D@Mr4;ObnATJLW2nctRhl@KOke7!G1cbZE!^NEs z$jie80>a(oic4hXNl!e5^LS@4=Q&QTg9{Ql&w#4nFb*~V5UK_M;Sm5Z_KkDx0f0a_ z0KE0$JU$xF`3EM{6P{)30DvE3Wp3gW(!_4qaM5O))ZD?==aJ&?7vHhMuCs5(8Do~( zZxy&Iza9~7ZQdDU`A{`bl_lCDb^gu%gbLNUDFTQ0Zm~GEySJgtr@txa%R93%|EDi| z*|%y&zg->9a^CR7$qPC%CJDImpBw`9#i?)rM^43Ly)zlgwkRbu;)g|*5i7Pe)d{B)yG$~c}S3h z*(U94*T)Atead;|B{SF#%e&NURH58-z0*-qPwf7UmQl+pqPV8+A@^+fYg2ihbwHX& z{&mGQUY`3a;};Fo!VO;9dbw}AT@`g!3oaOllG!Frc<@!XOf>19%_l>kSSH+9B&R`a Q@*!j^i;d=2OuhE}7m&4i?*IS* literal 0 HcmV?d00001 diff --git a/static/images/lg9.png b/static/images/lg9.png new file mode 100644 index 0000000000000000000000000000000000000000..cd6d1bb239f8663958ced7926adf8ad1cda359f9 GIT binary patch literal 95914 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 TBbVURbZwXH5MLASd&K_(Owmju literal 0 HcmV?d00001 diff --git a/static/images/login-bg.jpg b/static/images/login-bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a62114c7cb7c0c8f4ac6a82ad64381fbf7d553d1 GIT binary patch literal 346154 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 c^(vq(MB$hen3y_`w{!ysq#eU^L=Dw<*D^QfC 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 DQn#Tf-f`j=n?c=S=XL6$m`y;UV8yn2 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%0D$jEi@XqG5 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 P7TcvB|IX7lewh6i{1q?f literal 0 HcmV?d00001 diff --git a/static/images/logo-left.png b/static/images/logo-left.png new file mode 100644 index 0000000000000000000000000000000000000000..e026f087a7c4d39c23fb6d0b0fc1d55176996f64 GIT binary patch literal 19869 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 literal 0 HcmV?d00001 diff --git a/static/images/logo-left2.png b/static/images/logo-left2.png new file mode 100644 index 0000000000000000000000000000000000000000..7b5344fdaa42bf234b935fa182aca43135fb03d3 GIT binary patch literal 20261 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 literal 0 HcmV?d00001 diff --git a/static/images/logo-small.png b/static/images/logo-small.png new file mode 100644 index 0000000000000000000000000000000000000000..6d2a87f30e4f1f22dd6660729d98569d748572df GIT binary patch literal 37432 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 z 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 M07*qoM6N<$g6=$v3;+NC literal 0 HcmV?d00001 diff --git a/static/images/logo.png b/static/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..74736fda4041535380624ab447c548bb7f5efff8 GIT binary patch literal 42298 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 DfP_){ literal 0 HcmV?d00001 diff --git a/static/images/wx.png b/static/images/wx.png new file mode 100644 index 0000000000000000000000000000000000000000..63530c0b272dbe94f285767079c3c7411cbbc19a GIT binary patch literal 20438 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 z z-36=9ugl{CZcbaYCM&I}Ei}hQJZPKf7m5<@lc}4LxaqQO9o#G?%Wz5Kra2osb-Is6 z#>eQZNi7fbxXw$nQy$U2n({)-_C?~`^Ec&VAsCvxCq5r$fm~pll9!Qx999v1rb@eo zODw>l`e0btqBIwWeP}_UsUg$ZoM+7G3Gb}*AMTlJKdVqE^T8$VjQ)xfH)V5WP#{pr zo)Ba_mTA8Atd@7tp8UpMIv-e`ukily9LRrG`((yR1d<|fCMKxuzjzHh5XU00SSQkf$1POm?i5aUbb z=7=t@jF@7Xd)xJ!2m39n1US|cVJfv{IwL$LyrpkV4ZkAjBhDD|&3Lm%-q~_^ecJDp zEnKAaaV(nvQ?!@4iOcli(R$Qg-_7-&zM=Mtv-jr4stPmC?HP%*KHzz3(tZlJI#E(x z_NG&0iJht%$yXvY*aE+1t!B4!Dm@3fSN$5jV7DpLqeI=uxkSECSIfdvMa-1^MbwTQ ziwMHfksa)mkG^Df>(Ge&ldQp8a|>^pji~THy<&RoI178(o`>oRQ>SfY2i68zJSi(X zvnIP+44`f=xAUH~He{XJ(5T4q*k8rSAP_s0bv`D%FQeR|I$_{qEq1m*U&S>BzGo<$ zKS}*Xe}8LNPBuOV-P#3;=_!jI_LkGXyc2#eWx)M)XL$GK(;SQ30kPGE0`+qS)4cB1 z*vTi?Ah(mTO&^&~sOW38ugf@`+n8cL4K6ya;t*=6QH@Qt0_T-dRW@O*Wq*J@}gH)03TMNheJXtZ`tkB zC}}Sb;mdu`U>^Q}lYyhLqa9)X4q;y9B9X<^Y~l1Vbi?(OkLNOLM5{tglFy5JPuJJe zvF7QW?|OX3Vm%mY^6isO3~}A1Yf=at(6+dm^d#qUW(*J2C1}ycy}@%w){lQKst&UR zrool(dIGaYy#`y2B?9ZXioA6L2Xf!1-F+0|idl;o^;BL6&SIP|!Z{alc89CKk7ooQ z1A8fa862d1VKOAkZm-dRj+O86Xr*A$ZkXvR-VEHv zR#E^zF^%qyswueBwn>S8(dA*+ZRs!cHDBiW-O|Z!!^V^30n;Z?U%ALKUP?F=VoWp3 zp5=VCD|-9Ik~-$jmj2^)z*4V0bE0hRF~g^B;8vz@KQLlKi9c2X>Z&>_6-wuW{}%?! Bp3DFM literal 0 HcmV?d00001 diff --git a/static/images/后台编辑器05.jpg b/static/images/后台编辑器05.jpg new file mode 100644 index 0000000000000000000000000000000000000000..071708327b90b9190908632e552306f272765092 GIT binary patch literal 135991 zcmeFa1z1$w_Aq{i?nVTqyE`PLyE_CCh9M+|7(x(6MMXhDKtNPLq+2>9loUk}Bt%M3 z8tIOi{~3(e_ulu$|M%Vdec$tZ9-cX8?X}n5d+pw9?X@@P59mp9JM|zpX8_RG2lxO0 zAOP?oQ~)*zLBKx%!T{hN!vNq2IrS612;uoog9Xxv0^l291b@B|v16D9gkvJy0G#h( zGr{jWfGj%*0JtfBe3hNxjxZJ@S2zOh=L+{`QB`H(v2^otf(QEX0%9U!BC;YfvSOkv zB4=bJMP)@r!8ov=K>pzE3D%GJaTuRq|A4V*K|0KX2f_YMi}!0jAWVPc1H$!dKCmD^ z;(!QY{fwK8`&)E?7Wf5AzB&H(4Iw2aCM6@KAS0uoAtNKB!Mw<5 zz6GKDcOpQ)04NCnW8eukgbl!=gkV!b&|_dGiO{VOMUYEe$ngU*jCrsD2o?@59zFpf z5iwZ#fA)j`SlB;2DF6r#1RDzn3l|@c02iA?9Q35b#$lxr#Z@+Tpl0*ADuzcBn_jBI z&OvMP(otN(_gb$iK4+Zi>f{>KPx8dmvT!c7crz#U<_v@sU7z_BY`y$?%X|ON8yejA zGjCKRwDy15%&Ke~nBKB*4!D_^UDZA~vn{P@=@J-`lvCX?G`m9yU}1sW;vDmYkB2LH z%mS+@6%NRO4;wYE*wt7X3WKAJlYcjS zS8-Gcz{S%`<~-x0b6fIVfc?@oax_YD4mmF&@Nl_+Y2;L_^NeUW75yt})LjLuv#Ew3 z$<%wUOwQMC*guEw%Ixb6FQMvE;hS=3U}^#ln3(V@_j@)uEv8g2p!CyhI?U;BRDN}D z0RnRw216fDiFW(t9dK63eYHTv?5!O5dwwzZkDni|Q1gsN$)Vy+B`6c$eXfbDlsBy5 zP?8LNAMG1KM?SCCiUtrR+aZd}>S>#bn-7uY!)U-)01c$0fy{S;9Sg-(Lzao{7W11{ z7x6vHUB|ypWR4)`6~%}5CGnwKxdEfEE6GPBR<&JnO7c*ojX5(Jx@)A{3s@@jAB>*=v{UVKo3+I6)TZjWO`97rmd2jb!*pe@9bSkQespT`cR{43Th8_8 zx{pPF>hK86bCTsgWPhjs;j9C*)r;~xMEzrik^uholU5_iZ;%V2#rxzam7J}>%(3vk zVbe0ZeNEY!AtR;)m7Wlv(zdr{Jt}EkHV8|1>EM_NF3o*3z>8Jr>~vvj+3$n(xq!Or z6U_c$X){N{*$Ko=xGfwv#mRf8s7CVtl>fdzGGY3h#?jh9_3XfXG+;)Weh{wu@nh;v z<#f?z)c`6uUWC6h*J{@3^CMVy?uSpxer-7sa`4*cp-rE9vmR@dpSDH(jVmmen(EY)=Rn$Kko-f@`q7WXx;9Qb)Q?J@v>gnc|m7Jq^r z+11iNS_0$Nn4Of>XcXsNAu4(*95j%j;>B%2Qkf%9cQ#adUog@2ouZ;=>Zctv;7PkR z+9lUExL+)I2@m@Mg#GK17aew6(^>|9@s*qpdd&{u($2r<+c^27^>+)gB zTe0U3YXS9%Cz5lF|cWiF&TR-N? zr4XdgoSPe#Eyqyy!lEwhXX?N3p<@y${37%gskLyZbBDO6*BGf=e8!`(iPsj?+}dg* zw&rmiAKd+<8b)r;BvS!k8Rz^gV;|Wb-M6os$mv)Uzd%pcm5NDz&~@2suLNr}q+tI< z*j-!slOiEBxCp(Pt9e9cS+NbyU9a4d3A$o3v2tum(p1dAu|l8tplV%qvRVrp>RK7It*2ODy{fi@NKp`~8SxvKRSCpGHks?qAHW zTypGtPM>t9*oWQYF1ceyg*abg^eNL9Y3w>`*mVxPYN=G}*GL0k+X9N4v}oYL#Io*E z5OR(m4Tv_477X=1%NOf0@_AdLs1dNfGJQroSc)3D*R1IW?U|{|9hjIKU)lO_S8z(< zjmsawGH#xHO#nz1m5t$DAvb9w+IJSbMDofD9O$2^!j{=bu^DSK4;mvAB%^%NtU0h@ zbuqgg=>t-F`l;!c4^N-Zi11=E4ea%f04~f0O1|~p7lMv7L`i2mZhDY7L+hAhL&Apq zmQO8}ZpSX1-}$<4fLt!JafOLj#Mg1@t>#xVEe3~4508H=BFXmfQ;lx_8nU<(cF3vn zmCctz6lWk@3pKojgxWu6hF!;#bG@b=!T=dL7_iE+uvD(-=aZ11sP2P2>E7NiJe=q* z8BO}I|Cq2bewoaB^AgItY3%vNkw%yc>atF~P-c&w99KrU^Exl7&{guo6_=*XyC3i3 z)@#-}y?;O9??PkQSWs2}46xCM2fWALIbEU^$8G#dsrHWN{jaWGi%u_Y%Q2-bCG2PS z*>OaurK%8dy;%1xmE~5OPo_^^_8P2s_@Z*8ATLI+v#O4tebb|wYr+%_h*)UA2i7mh z-i{ly!7B=Sf`ac`dRWZ6pI^FJgD)|hD;tw;L#Dyy^UCu<;(K$}dsh3^j3dfka9=7h-NU!#5Br4bl>KV zrn!7XQeo&2^HOTP&4H6(Pc9-2xa`bh8oaNTxDf`ZugT>9Nn zq%ke*+*S-xanXU`*2wdaivb$Fb5%pn?Cr<`(12w~zMtaD;PYr;mWqRPfZ(;->NQvE z;+{dbdA%`aPTGEjc?hpe;xfRB+Czpqi*kLNund$o1xx9ansal{O8Q#;dch zCpHtoQN-kcAK7;fbxBj3(}!v9T;z-G`r2gyv3IjnT*N`BJ~3^Mr`lu0rB>%>BNVb` zY#F9-Uci|LF2cX@cpnjGNx2-pR0O65-eY}+{IX|pX2tAd==YmC z7hlZxbiXcPtgKrcS(JU)zEj&=Zmd%hy4L-%##mm=plb25+ z;|h&`tPqRNsvFit4A@0yt>6$_pL(SDc&xAg+B}th3W7P_qPRT5{qbOwvb)WSzoEx6 zS%{L5*VuULa(50twSdJ?#enr#LspYPllk+&P+|9kJHht4w#@FuLII!b7znVT&<%v{ zFM}RqEMvz*&Ea!64KFU6OMkkMT4LeTQ8*o0h|TUg4oFtd9|=F%skE+UdZgD-Hg|Vy zQmsOo?+FgX{0d|(3+q7~VTJ{PE-azH1r|*LRjci00pv%G48nlq&RoxwzU}#nn~na5 zZ{LpI*%oU*p^)C?9U*ZWCy3(O5(%AFfP$uv5TZ0&`)+qYT1q8t(RC8TnG`fY4@X@N zmc`@VFhB!$s?oq%1);pT%gu;5Z4O?JIBgwmjyMw#zMmPV&8dj)pO>9IEJ-+WM$XnH z&`#avA)9^szGGeWp!6`!T@MXB2_tSZQTE$1nQg2*k~h53w9k8aDefVX*VPvdbayPG z0rl;Qq)3jZ@W#QqiGqoBb>>rw8`DuUi1^aO35_Pn!w;y{!^|VIxIJ@De(n7{&h>n4 z-oN~yhtXf@+ZU{^mjQ6)V zVZH_qo-i|YD>D%FEwOI_jC|p6XHyu$-`mjfA{6w*b!Byxj%q}DVFCk0-aq|8*Kt4< z4}{lu9!MPh-8>L(UdNGu{)ETWs`}Qt-|{bqi2_RyeEpF}s$cSG=#6lLd-;L>bQnri zZ-mzmwgFWSN8g_g6Bj@IpAJ=DFV#OBUWh*&dX64`KYa{b5CK0O>Yg5IKOJDn{Smba z)ZOKK*1wetV4|s_3UY(djQ}Q2EG$lNe@7+wCyev>(e(BDJDiHg-_xo1I+>Y!AvD-c zJTSHS^HK3|V)-k)iJu4J7;hBhp=1TLUilV+C;$dUz$^9wvi$j&Of3C%?bx-B1K3X-p#lFkRwjy93>S z({2HkpY8h_8zw)S?{Q}E{5;&CFh2_qJxm9L{3#vWV?Pj01^)1l9olNYq=oO|3-|Z_ z6ABOR>*nJ2b8J;N#l&uSj058!b?`^PHDO*bUk3!t2}A&9m%M*W21MV8F&K=G_O~hF zzny<bS@5eAl@B{rP zVnSEAZ?Lk5o6C=qBL9|otsiKx0Pvk)&JO;^!!BU}%op(&BKx-@ z`?n(dw<7zuBKx-@`?n(dw<7zuBKx-@`?n(dw<7zuBKx-@`-fT^J^W3+WCbNi05AoA zpiT%>Ed$Dc695Ms0T{pn7y+&zi~xUr$B;KjLG>>vSO8V<4upJw9u~_LFv8cj*VJwnDl7dhXQ3)35GeV-0q7pKq0xV)8qT<3L z;=-chf}&!wptYK)B+K`Q4NT3~$ywG!P2+o7pi6=6d!_;d1BC*`h2Xv}!lGx+oDmig z6BZK_1StglE_opwf&{(%*nh;J2J?gZx*hAqSuinzI$wW;0vpKbw=8&i|BUu8%jy?G zef@t<>gkCofa7TW5b6P7D*vn!{4g33VH21i+}{@pQxAZ7A=rNecY^*5>kaCJj&te+ z6^41hJV7!)uo6XoCguIZ4)AA?Kjq`6_i@c*67ZH)^@TZr8gMgE`~9P${@85!)tc}Z zau}#DhbgdO%nJoYWCX=T&3>2{@`KifA|l^N^}$x)1S;15Jz}_%oAafAhg4r*R@=)D z;ot>@X{#x)fq4*eb90h)l9GZtJBv#RI>?Ah3QC`m5EVQlCJhsGaB^~%kcNtjNy$hb z^96=igG2o>h4&-86Byo6OiWTl3hH+g`1~?3rzT;H_U~N9oW z|9eg1zsC6YB89p-c)7s9;Z&FnlNDji!1Jv_g#Wg#j{SZaq<)ZtBOeC*Ipm)GF*N@E z{w{&vCGfihewV=S68K#L{|}YGA3__<3tUT)1pP*)HZ0bvqfGZRpT#*qgPZ;`nC0z3W!Bfw2`kQPvd zdtW-{%*Z~jQ;le zr=Gvi{WB0#x8M9XjF0OKa-!=G+#ezTz`>t_h9;mf4)(o2aE{3UP<;acPJa9Y$MFPI zR9pvus-9o+a{|*|ev!i6U{E1Uf&P5{CBaY1e+>MRo)9LzpRx{%+BYi%7EG&#f>s6o zzAS#AA_K-E__vMte;n`^wtnG5zy#(D^M!%(CyNEx%0TNau)4jR+%N(ai<{S0su?q*>CM0 zghBt~_n%%^F`yI6&&`DegH|;$V}bhn24LWCmJpz|BoU~oq5=ybAaEJD3fu&ufO|j!@DNA?GJ!mx7$^g(fqLL2&sF zs&HCy-s4Q-tm2?>NpVl(^5e?lYU5hry5I)l-o#DB&Bm?7ZNnYFoyOh9!^1m)$BieA zr-f&YcM&fH?+#uHUJ2d{yk5M|cw6}R`1JVv_zL)j_zw68{G0g6_=WgQ_w5K$6w z6Dbgx5nUv@O7wuJn5d0tlxTyPn3#?D46!k>8}Sw52gJ{aUlC6d?~zcE@R6vJ*pm2@ zM3dx@ydW7S*&rn)N-^hRSVT;YHVtDYE^0|bvShTKru$5dO!Lgt%x9V1nC~+;F)y&tvM957usmRCWm#oC z&8o%f&zjEK&3eGb&1TMajje=jjGc&GhTWO{K6^9!DhD%%KF4K_0*;TIgq$**uAE7n z9h^H{++3Di5nR<=bKEDnwYh`23%EylNO=@_e0ZMn^z-8J%J91LrtrSw!{U?VbLD%) z*Tav+FU9Z1pTgfOfGcoDz)Rq%z>pw`Ab9FYut0E9=!B4-&^4iIp=DtXVH@FC;SOPx zh@^;zNT$e$D3z#==rz$g(RDFCF{s!hv3_w^i(LwR4;*=7*l9N)l(yTJC@Qw6H>JQb&HP|#K zYD2a2v{!YcbwYJobxCwhbsy?Z>GA3L>ecCE>Femn>yH|68h9C08v=&fhVh1DM%+d| zM$e7$jE#&R8PAxAnp`&NFr_xNH_bQQHd8T+F&i=GG50rbwjj5#waByBu~f5+v;1Tw zY!zzt#+t#}&AP@0-^Riw+h*&W`niO2)3%bfH*E*)xb1@MI?pql_c-5RPj2sEUw#4i zg5`z$3x^Jd4o@An9JL)EJFY@ip-Iq1Cncx*PV+DYSR8EDS;0BZdCo<_CEjJ;Rnaxk zb;(WD?V;P+MXifz7kAtZ-E-X09+n;@o&=s3JZrtEyxhH7;Y{!#c&|6V_f79lKC(Uu zKC8aEzS({dKRdq~1P!>D>hkCDzu`X_a5mskz;2*LV0jQ_kXKOGCB93yFUC66P4zjATb%M^0bSypnsB=&JkGx7S3j#a-JBw+yel&UpRG z_0KmnZxq}lyXkv#C_*kG?H0~0w_Dw}#cwCyMnyVBzK#-!N{l+Z1HJS5uISwdchS+# z(cLjpF{$_P?s?rCj8%-yjiZbUj{6+1A76E!<$mP-%>?^|&P0jCv?QV=|D;b3^d8hC zb0ptOK78o3qmsv`AK!kwlj4-pm#UOnoW__ImA3!H?a7C9&Gf3LTu&1-@G=52 zW-=`@JF;Z5^0FDSqq2{3ymCI}n&h_TN$2I|pU#gdz$)-Bm@l*~d{?AaR8uTioL+LG zBUU!>4nn4GTpM~a+&ht3eJkhmDH7yRgkJnRjbvm)t_ptYkF&SYMbli>MEZL zJocS?iL=bJd2?cO_469@?-tH2OfPyb9xUDbO8NEiGS70w ziqcBgs@3ZBn(rEV{muscM$V?hX7iTO*7&yP_Q6i%F8yxqp3GjyzUBVxLEs_&;e#XI zqdJr>Y834WnoR$3E?)^;5PUnA|LxQ}=8c8sW#dHD`qX^&2h$fvz_r?k8ksRaCaN z^$&cR-rPz|%Fd~(ZtoZznwj0+al06FDfrgy$Op*}bMx|RYU^HgzWy-$ac+KLcW<8( z051{%ixCeS2OAF`AL0hGObOty;!=s?DX$tk;A3tR0Iw2wNg&osGs(WDLTf^JLfo;> zm*ZM6uxO z+4YUht?eC<%!0c&@vKm&d1IOq~^lZw*CX(jH zPXJ%a=Uw(S7C9%(g5M&NSjGfO_*|u3yl%$HaI%D4&{lAvR+Y}4IG^G6BqNri;MIdM+ug)-#di%#`yDF1RvDWY8?atINr}!mFZ6on=K5Quib?DY*KH&B z&=9V%qfaoc`YM(C0Rlim^t1Gs^m{?!=SIR#p@CaW>W51EJbM#FPhxntq&YkBa0ePw zIkJr-EcH*xOGBXW0KcIULGsw^KT*4$~YPvd(<^6a`E+mYzpE9 zGgUA^rTqy~L>lT9Cem1_VCQ`2ViZ>QhZwbB0azSKLmw*DvPWgT&x_T7_nemF!!pYg zLWRu~VO`MLj{1X8xUhwivFc?&k-B4Yzz(|9G~W@p<9|J`J>JK^t?h~rYK==pQ~97y z-$IBmWh2|VJzi|Oej*Zf*m3HxH3&s`%e>E`FsX4;o=V`#MEfC;wD%Nk9v{o*TZ2Gr zyMnKQUQ!9{Pp)V_yHym0Bq8tM&Zp;>pZ2;H{I*+c3qPwiG02;Qyf8VTw;%CS&O);gBe74YL(KoahcQuxA?X}@gS*=g(_94_pQBz2dDXcn!7~h{40Rw zsrkm6uXe!uEf7=4jQvA?;jqW3$G!EgDCmP%<#<%FSH17nd?mogJ{iwKNt-=uF1s<< zSOcxJPAX)y>|)ez&mZmHy3|2iSWKYZ_#q=zL+f6E*>efM_0dMKxWS%*HHti4Wp@G_LBh3AVl-#VAHhZnnR+P$kxS@GNQDqI2_2ou_GD>qF749=kobRkg2GN@c3*O6Oi~=~J zg*?zXCnlD`?TMSbR9{@Ne$!u> zKHa&W7Qt~}z?V2cI<~&^?gf>OQCUS*+sv;yWyD4A-pbub@i@Z?-VUHe`ec(=#_)l> zW1;jln+W&Ot>A_p%Yy&zCu6|eWsN&i^qkrgMRoz=`QyLih)*)9?)rqM1P zPkgPG<67$d#WHL5OSaZYua_J`zkH?dD;p~&WNvHSLy#jA5a&u)GUYhVu`SBudgW@l zQc>iz{4x!a2pLMzCu+)?K$gqsyp}4fME5Jz0d?1 zM6qHoI&WnN_25v-0zB;ctZ_cjZeo3q{isMB^-wZoVX=uEzH3Bh>|H;WRA;>yUHnMu z%N;M*XOU;?CO7XHO+Ao^6S>RL#*(h}DL0D&o+#62M(4Z{0vZ3heP_qk&3@4! zNvGLXP>+cp9{=Nu<4@v@EG@Lb(}?LLpmUo9-) zuP*mcu~9Kmz@eTo;LaSl6-J@Jx*52@+~0V9PC763fiqL4vq9!rb|%%68gfG9Nx75F zzT2$PW|hH{G5U5Kg*?q|(+2s3JNH)&Yb`9KrInN3nPurgu>k{7{2Qvw#*f*c%M}EsuGiclc92c`@#u2<*T!YYu6mSFBj8?e?FN?7h&oZxc(`p zDDLDC;>LqvGvYYyHF+YtC!7Nu9yo^=eP0z@Y()tPyuN=uF8CGBz=JT-#?msw3`0vF z=kX#J?#@v99vM8r_~08+MDn^+kteinaw_v?HDAb288tWM(CMV-<8U9=Wg?Phm-A}h zF^#;=LlKZ#dS!99pL>gYxM6U8dBxv#=#uZpzDzXpO?$Cu;9Vh@w$9Gqv(tlwm!<8l9K3FNS%Q351fMv3g$Cv< zkb7AnC}!%_S~O6Th6V=tbCG+KvrW~*hKGSi)ApZ+n&vF3S5QvKO@770K9DW)+q<@C zVAK!|EYkKX9V^v%cxc%)xu!^*c5oXF968oSfcFqEh5S(oL}O(1tGoH3d)@|NgH?4Q&(S;Oegptxq^`oTYPl17TvPf^W%6;FPjv2#?szc zQj$JR`)uD%#Uh^92B0e_OW1Z{aMB3Llv_v%CY0YIRGGP06ITIhesH8=uqb(v{9_ zKED>+n4Hb7<2QCzIWAhjbG775n3GXua0OOq((nvv=A70tYk|p7Q0h9uK(tCWyN)p> zdvmx(kO+I<;I3bWC8_ZpgAeWCeIEICteet9D=lcCq%r?UCiqf^f`~J-{$7cYlZX5a z$;9oM2jWFsXDoHq#(k#(buQM#74!t<9rY6_%#g!Qowu6aIpdy0B5_VIm&D8onFfQJFxtP>9RM^qoyYI0Ov-c`2h2+de z92(&0vQq54W7QvNxF>96w3q7A`37a^Uv)58Q`>Hu_R;?0GF^e50gmTz1zBXw&SF{p zK|r{s7_@H1-))W6G@E|XK9xEO*s4>J+B5XM=E4w;;S52XE=FHb{=dX7L3Qn1^ z9KFqQ_Zihv8ek(h>4vL9cnuFXZ75JjR`K16rGoFgp|ZGl_YqfTO$CD9^t4XR;2!@ErS7*9XHwEP0p(pcLs)wy$$s3TRv)B zo@{-6U87ma%zN-2?J3a~B1!vjc%eu9-1~u1>*@mQ&UJeYzivpB(|EdLa|~7M(;IQD zw~ch%ydUu81k##yQk7}w+-BG|>9{!(n^Fx8$!k-gA&@h)df|WQiu-$s|9gr5Tcr9e zQvE8zTDadUZ?{+oQ11-Yd9|Cf(Us6Iz)jXeugI{@$J^*f+?M;fBr~nEFq$`GgEirt z)2%{bXJFLZ9PS-)PUjtr4~SvEl`ALpI<541!0_h0e-Bh4cO0Li6NX@-FpJx zvfW*!{)l%WTWrAXMd9@WpR=FTog(^D7b+jZ!_|9vt94SME1FH0Os>_pxl(r_ifacx ze@eRnHxOZNiO5Ig)K#a5JfR1Z?SV*X7e*`pNqi{=@)Et zdX+6@ms0tK2KeZ0)`>$>`+VCPr*0uQ_zg~CT`-`&LtSCPJ9eaWzM(O35B5mQJaW`j zy_rVmv5LxL0#;>_6z!8)R-F&ncs|E&fmiE@?%JY6QTJsX=6bSIc(=|C5sF2a2A|(b zW+%(ef3sIk7ndX4_nM=HL;O<>%!x%E=UTE^&4p6pyUOCu^YDg87Cc^)uWYxHAs${J_wxDn&@Hn(Z3r~ojp9kD4 z``w{Q!jw?9P4fN|W?Q-o(gSpR=^b_2)=|c=@%u;re*A9=832Y zzB8FJXQ0D1p|0Rj+cKuxf?h$`Lly(vy{>I_96c$+Q)HjXEnnGkIq~`t-x|a1i(DCd z0oc*MqNraRt`MBlHJ<4%GSB*IjQHiEx1RLLSc2%w9S_{1neMNZTZu+T>O>^D zaRzGotVEN_iNEfjp1d4GgkL|on&uCU89cvV?skt|km#tW`6_!lfjIYDWfsKCxuOqy zazi5jnSHO^lrYw&Er;>4rqu_t$fJmhyV~_l>)psh^~D%G|Fwa$bF5@`g zdgO<18OrUnTn5uSvu11fK3dfD?hK!flQ736_~~nWItw?52-)c8=j}Gj+8H|`hU}?* zWt9rfNhTasKI?K}=1FOqatqyd^<>s{MZ9%dgo+bS;$jzwt}I?{uc)7Q#*OupHeT1T zUkJFQATd8KeA~om))sZ2HmG3oB=j||x=x=_X1w03B)(gj@m|VRo>kQ*r!DTs-@biy z+D>?!_<5Cpo$o;L-e%@~HWh#VEBzP9#V&3u1Z>f*uJ$k`l;tQNaqo}E@FL375xz5z zGv+@gWnY?JET8c~h&HlE&5&r2oIN?~A3H$YY%J7KsvfN}eyYCojmX=ER#q$(1b=IB zT*m2xQpK`6F_(+PcZ4@=OX_QCSowk)`z0nejXvt!#=?0S4)CZtXxq9FEgIdcOrLH+?@26Qh$6lE*D|xF=){4;G7xcFLVF? z85~+3;U}jhRGwbG@BnCwBnow*_6Z%?=@yPcBiO6wX#r3D|+PHyzI|Ygl!ab&w`BH66?~ z3C-6sOfI63g(drL>n>;-mPdPaKHH+>otF0_?5a)6`EVT#@Z-rv7+JQNn?`7hMj{3I zo@(4qdlQ;oQu+M!yI2&qhb zZl98h94_HUai+!`sc(|6@h?c5%HnIkuU|}irg!7!X9a<`j1DP_`w?W!XW4Z%HLrG@ zWmM^RyPiv>bzfqoMo0Pvx1Y`u+&p2Rp>GtfbD#RE{TMZHflW4o;pLq-&%S={^s|lo zIJi{z-W?G^?ZFy{pyh3*DYBb+VUf<@J;zYI&Qf?-bku|ucJuQX_2F4DNekzvm&NH8 z&k9HSSMT}jB*e)I81Q+>UVU|zx_5H5yJ?|jZAN`N6cpO}6FjZ?wm&JnVE6(baNd#x zg|_qzP-wGBt$3ZVWDSoIxQr-Y`T}UYVnUWXr%S~! zuKxil=7D>mv{W@>iqCN=yz23LgwX2`M;XKiBV1T@FHy8)4-_s;+V}^zAD(Kk+n4A( z^QOSMN&s7a(}lBvdBZE+smq2_r0uq&k%L6G4T+YiIsDQ>hK5y~Qs#t@(Ybr6fwgp1 zf}oP_o=kY(g$q8PhwNCECKe0>0~6;9G%BlozckaN)R~w$Xy1PUJl0CR-Fz1fWKZlG zq~+h)c_6aTV{#@5f9|}-P4#&C7H^vckCtTaJEtDZzb6+n*092oAIkO244-cDVw?_5 z9;fbi^41wFjYa7V#ZHeJW7k=L}!)Rg4I3O<`>@&=_m+prU@YI zGw5Mr?OLzr#`WatKjy#A^LRgK-u*&ifLi2v?Jj_I!&rQ})?Mn(&4(1RU8!}m2D>ZK z4r$J0=f_LV6>LLZ@}34hDd@%NlU}x0j{LK2)&JDRZGQ`XWEEIga>#XN0u4BPY@~t< zAC`l|2ci6*pZa~syQb8qNiH_PxTa=+YAn|W8ymk!ljAs@m9S{;IeBc&olOAg%K z&q)#m_uV6!rqzufPZmM`at_Kr!FhA?LpP&+_|zuFRE+^YPK_7ujVV!%%`J(IcE>ng z=zXy|*-{G&(AwpaIR_7gTDZZp{f|~QggS9flvi;)SXS98^|nCU1H!>JQIFoc{`kE@ zo-NNtPn}5A)5v+ssG6Ia%wyLHWum>!XTZQ_SWBv9cLkZ~3Ec8q?&`F*%fEuZYxoLv z_G3@?8&ui75yI;35n~hY6(dM$We!QOjx+Kp-@`i2UCsSZi_2~c=dE6i$+b8#GQFie zI=!Hw5aTR=A~lMnWA)`JvlnXqR6Sx(Ul+}&Qs*^Ze-w=+AT5QOcGsbjC*tLZy?T1J z@cwvAuIJ$ElMX}UmS0E6p5X8#u$tmuz`F2BOR~IUvS^nBanRchZ4Mq9tnbhs6l$1M z?S4b);H{Mm7wCR%oSk7)X?-zYi5sStdsTQ@qY!)DV$8F}t4(>xpc=3H>U3Z5(Lgw3 zRjAQvLnQ+zCyOO{>ZwS<*q3mtjKAL${x`b)Uy_)P$D@Iz`H3jQ zqp3}Bck+TwBlbFS&wU&TR!QT-S4{7a^UY%`a!q^Yk{BQuF{psX#6gbL$dzS zvv#KsL@%L^5#+6AZNvDUXR_z)5=sv==ys~~aQ(v%`4~llUp7~)Y+c4`uD#?SN$A_hI zXo-}j$g^AUKie@c%`R95O2vBdu6Yu?o~TPTA{$0!@ios9L-C z9m{?TmzVpD_fEE%-+p(YvSKe>%uHnvDU>RU%}E1GG8A1n<-oEB&zv69_r)ej6-3lf5mAuaHpkr4N{u}iwjaE?)fb~1%Ke6sZm!*0uQX1q zPCA}!MJm56|D42Dg5NVzNwqGaMRktO!~rD@<;u&ccv1+GuSServ9(LiDdXyM3z zwAp`kSo%o8+U4jAXvoCJ)iB48Ds<_MKv9LIAeWdUHbxrIfWWq5tKq?1NdQP|`e?fgxe+mEl=CKWeFh&!BSY4V(vmi^R2TbuH9s~b)QfQN;8220=Z^_NU{5^|+;BkISP5F1+v5HQDsz zo1%QVJ``=0%(Na-NT5*5Wb-Ak7``Lr!}pEhFf*m_c}SuKVp^~M*_dUC#z z=gTEqyK}FXofJlvru&{v4-zuBwC-(!){~Ad9*UNU`Xj|d?3`Y?%7|-JsTJ6`I&&O2 zcQedAx3sl&m38%1RrMJeX-~UpYiepmoi8Lls4|$7C3xrF8!A~rhnD0{&L#FAa4&%foAp=jEmrZkRpr@ zL<1iJO0GY81Gd~*G|+1KqCfV-%8^1c{OF4$3dL(Wmxd~Q-=~S9K79l15JlunubQS# zAX^Pzn2^0k1M|~e$Q9O=J!3N$8F!_N|7`ZoTWP^ZK}%YP&_JA~0&<#(@kQ7I67d`j zcv-$K!>=~njR$T1>hT)+{tKDT59vc5rO2(hfhn912Zw%Q%NJqbTrU{Xv!l54-WvNO z`H{@IhFP#U__B*4!ihTm9g(*{vArDi_Vz+NYR$I;)&4;m>l`Sx2;?*9UKQV@V zXEZ;j2`A=23j7y1$QAe0rfvCl8S+uZJ!kf}_ABjW_zMxJG~JRl8?ar+TC}{p0sW^F z>OY%o|I+VbC>mIC_@W4^LkHdoqY?|y{l7cg@6PtSv;FVsYylg@XrIk`#WNIm=Hy z6hY3&9_l0aIQ)iC#*?G?%Q-u`P21C#3s^!BXyCS(;=v2|sr-LS0s7Bog1__2&uQRB z1Hd}B78VHrVrvPpcy}$8%JP^5_fAK?*NMYEYb^FB+ zzTy^z5Ptwq(RsWqEtC^+=-(}-HR5w!P#?H?!z$2%i9}vg;e3w4pA2{{kat~<9#Ic) zA5Bfi9Nm59g;TwVvNjAxHW8(UJpdOGd(SrfP$qWPjkutxnI1C=GfmGEt(r}I<^frr}3AW56dZMN_IY5V{fT~0!7x)ZV~de)_-AzRCyK+>^xfsW#QR{Ij~4{ z&C!GZxh|b7EUBr1wC**djuj;U6k+yZXXvpW;} z(mWyyZZLbJyqGqWC@rk=UT||LeRth|;;gfxft6wGqq+!vDZ=EkZ0eY)n)@d!6}+r& zUPSWmKQ}({?#^^F+1TBh;0Dd`-Uz$k;i1b70|K1`OZXh0J{ahBeJIf_8yD=YHx+d> z3%cQDQ#v4}5K^BWeQ80}wfq+oPy{f}M9ZZ+u1JnkP*N%?e#TuS!A?7H*KK25Io zJ_}nX#&d&P7L!!#MEm9W3#|E?MEv!Aw?!Z9pIe{<{~>sJYT*1=4JPmEc+&PYttU4T zEh$_UaoJY}y9*cyak}CJ8_uUk^+pusBhB~ZauO=X=z2nB-_j>>Pp0U!uXPQ@`3X_S z&7|f(ygMC5*uHkr^+Ms@@q$oMi!lzCns-dW4Qk>vhh_@uFumjlbwv;NS>w`jtQrlr zu=~g3-@}&LqC4;EDyoWdHD`v?Mdpx35}1@35k26%_qA5e;PF;)Oi7loQA5yzy@l*f zZ;25-Gtac%K<^Sa>#Uw4#oV&+ovGbWPp*I{`UEPC_BoL~DlH8fAuNi(K&jb+{@}fT zplYEmX_ZD5$_-kA!pI6JjC{2xluklf_kilVlB;>_r4#!hViO0i+>Z`Ta(WeytaCDB zKy4r>csbZGDa0aM!IPJ_(ynAO=759T8*tniSDjdYn%nI?c;y!jvvRei`hI9ks02vG z&IYnWgy_io|JZx)uqMBBYZx1dAV}|^RO!76M5NcyoAfHZw@{)YNbkJ_sUh?t3P_PA z(uEK}1(6N`MM?xBg!ge~&Xn_;GiToO&CECFdi{$lJR#4+&ffQ4>t6T0_Pz}%$)#is zhu5ojxLrT3Aqa88=}SxVz_%xE>FrAOXArOjWOZ)*DEhHg^XLl!u7Lm30l>jB4gMM=_klJnD&QC~ zkeG4x3EC`;{)FixM4#(b3)SoPjw#nAxzA>q3DB|_ND_=F(Y7s;1U}$h^~gY7S8j%0 zq~U9gENyTSq*JHkkKLP96MI0LR1#sY))i63-!%j#PG4`qc}=z`IDgxL1T6a-+JRk9ewW6UcKXMoKH*Ab%q zYH~@EFKo`ZV(cfSo1FNwtZ#GjXM9G)llQpVRF063T=rHMVBynn9T{P4djBZt6a#r8 zs2&2U$%K{f1MOAV4D_r4)&uzo_F4J|!T=*lJ3{V=p5HF0On5%W=l|TyH_4^6yg0Bn zHSHPg!qy|FSKJuLGe{RkJK3p7x7Djc!zwcXetmO83*AunEC7yRBHCKi^|@B_(Lm$d zvRH1=)&Bi6dOorHAGn3--)@k6z83t5lrI(Ad5=`PGY}(DjbZ?{e?;M>i4axfhFR5Z zZ&(xtEbpLYz&G^BNl~$-LDq~b4?Y&%y#^~ut9_!C)~vwiD*J-D-axg6#i*;yP1xPK z#0n-Sg#qD@9L%5`>dLT{J^KOL?ycHV4`YkCZT-fyId2($e9>nuoRr3S#!8V~2p8>I7Y_Hx^dEEp~iZ|6{#tfUz_VP#BAGCfD;-;%@k_=Dl#U|3=BZdGBBpzOBt&7|sz5gkRW2fii9kg-#RI?bCUWmEIkSEHUg{~lS@PMDssRkmhZgiD}4F9f3D zS`Z(U*1gh_+!q3mmfHfe((wnnvrX)SjoIWlxwCy-EO}srE#;qTE+QMN21oOV=-&~Y)bY6%e0Dq;d36;7srpEWmaKDs z^#nsxB~5@LiHL~Vpmp`xQLWWX-OmhUhGfQ1&=pbiHFXJR?a7Xusgyj@hv6sEJI^tB zkZes*zzxBg$H4*y02|jaJ~n+AZM0NXaqlF3cbPxXGXW4+R;^0 z4fx`d|IcZKJ}jSpM{dFhoQAi)4? zm@FoKEP44`olWo38zphmge?Zc4r|fo(c3Ta%=R?efrS$r#=n0{z0&G`h6EVBA2{J zfy44H06`9k$_0X#=Fcr=4k)3(0yp^sm@WyJ=CdbzEmNLg*J`OyQ3H2%Ql*b(;kv=o z*JuC~0bpo5;$aOtTTeq8&9kX0@a&{q+%n`|@?&m?kv_GbFhKqunO6a3-Dx^}q{#1vA?IZX7g zRz!MC>CMg6Dz39WR-CuE0j@?lu|#LFOce}dcUo`c)o9)dz)$DjkX1!~XPb%0`rH;I z=-7cw^X6-dcDfc+TQ)L2XE;LH`o;D6cRPCyv$%LtlS#C(!Wj>hQC+&~0W~q#Jmljqpt$`(SmtNy`j&yze3>Y>h5NRAi z{h=n3u^H8Ek`b;rWR_eSqMs|msgJYF5U$C5QlSs0vh}fOwq#~yuZZe*D)skO8S0<{ zW@6PNnXxTDPRDM|Pf6S9R1?;-f`)~1+uBbf5Vp{UFI#su|6SrIh}C)s{?vIHR?C10cL5Y^NWo00q8K^^7_l z8v@|hlNUgGU0Ws@%g=RqfI<%nu*HBGl;!-9N{g=2j)4aD;R*n3Dh4jmW9_H6L=O5M z**E2Sb2E5|8(6fk37@WfPbLAh0==d<)Ac0j;#9|IBk}=02a%?R)|-h}*#LMc59u_L zJGKFkOTcj+K;zXm>Q77iT1gkcU$dcKhEI&|e&0IBBX@uvJ)9jd`g0Z2K)`l1B=q)Y z)Jd}V%CwoipsgC$fbdSA(G@Bx5z&}FO*u{0n|!Y=W2Qd>Y6WN+I5=GuERtPBwcFv=e656l3CMp=|5(Po7H|+w^VbHG0QIjhffjIpmi2C407pm9%EKfsDN%!v^>*nr&IKE!sB`014SSNm3n%<_eF(ly>S zJTX!v<576AT`y<#%!?Pt)oC_nmQ6o2jZ4`S;+xF&wx}=iDWH)K@Votas^_WmHSR`Y zp+)kFD09^~d>1x-b5KyQ%iG{i&Kvvy%649;uSllud5r9TqSxvs_Ml zB2w)$-Rs%0=n5)}R%+e^IVJ{!S%ASel zQr>n0l1`O#Sl3g9cDmX2q%41QDSh2YCv^OnI2b32oCn`_9;J_#)sH8Rdr4DKQa{=% zewm6;W2Z+g-S0LrJ^k~)IumnI zB&Ahf8PMkw>WBFodAIO2XbY^H8Q(1`6+~kMOR*teb*R-ukfjfY-G>Lj-f93(GYw~o;5&vQIyNS?ienF9 z&BPVk@`R_ojK~b{ooxg4hwCyA%CbsH`^yG=G1qBEhSpNSMw<6!zFu)OJp_iE&I%rJ zGhA?srn2VaE$?6O=tB(I2t*k9|n+KrwXG2^Q- z(le);9_B}5*gIu#oP|u=Oe!=PqDe$K`=o}#qhqlS#GQ{gRnW3?IviTUxevSxRQNRN z1@#BO*F7XNMXyb86gxSl;Jr$&M)l1UE$gL(b2yE=9tk1snmY(Nezgnmpz)|d0%LGQ=Nj?ZTxq%vudGWPjVGvM<^8D5Js z8+`gfwSj{%Sg5NMR&N0O|3AUiKUR>dvYwe(TH5k_g;cFh*v*Cr%5$LTN8^k9jIYSk zB{=2f;T>xXi zDJxsn+IB;vlSbT6ZRWBu*+33b=zzIe$cBv0IeG0Xn+yG0$tw&&z|MErlHN3P;rOxt zi~6#zm;xC?cg)3%5cKXDETYfEL`?dv&9iD{y&iGZq>b9TUJ46`G`?e%X?L6TVc&u z)zcBu*D_CY^5BFuC#)0v0X!VCuk5o&xLv+SZ3?!GCtFRF$rhBEM%TM|2=^!Tk-e@WdKawAx<+dtV3eSX>mRJJEs4#sVBW+E(^e^yc)hV6Nu$0s1iwwa7FRnVXI0vGoV*k+gwBE- z_8`NyC&NOgp(piY6allMhb)(Xdi;E$(ZMJqhtr`9mz()FYRWC}GiSQGxF6Nm#N12{ zdD#viV6z47Q)xd{aJ%vGV;mD5XS&3C0)X+)6iBKdjwK_(Z``)t&?y&I`kaVN)5=PD zQW@x77ofZQ+)IGYNEfNeUdMWS1_)iYMX^>v7~yGH(W-nQ*7EJiYnuh-5veX$pw#yI zYhiP6e&rag_YfTvuP*6DW?rhYlf1C3zD(n=Smy>JPa|fu-duPG* zuQBTaB_xy@f=xM+U5yCekID3m-n7rlo8)S&`zS0)rKG)2^09=UL83 z0vz=6;ZT%)E)?0V)bz=5D)2+nE6#5*~e1c}?d2QvL$^giIGeqPl{PZ0~{aLx=MK z*e+716c?|41_bTS{{(9lvs|20%VEZO#y|8m26E=^>jQxq+_RUUc%k2=QA^+%(pdk+ zYQT91l+|PY;7~Y|GG{(T82-gmR~MSdy!!JAS|I06>-< z`u-&r0L`HmKn+FXy721=pz>-&nA!ClFG4&8WC%LMT0-MyPs`%|Tp6o;gk8f}&yuR= zYIIkc@gm2GP<2JN(_*QH_Bk_Q(xH^u!gi*yeYYF(7&&E0$HY*b-IvyA#BfVtv_psI>$?Z@<1k)^N?tu zsfwXIA{*j}rn#l>pUhCKMJ5buwU^Tvmm0t)1;>hu^Qmh;RL>Ne?>X&NuO|M+F8u0_ zR3fWLGq8Jd1a~9628y1U8HhoW&>I>umdcZ#Dh=08d)w|yt=AP#t0Se*-jBd~9FV14 z5!WhNxjb4}nIXQpdhSRQn`AZ`!z@r1P=t71$aT1&S9o@B)mrOQ2{tvh;6Bg0&r|Ao z*!u-}(jL@A0)lb2hZH&02%e>2D?$WZG{0}7iptBRsvc5%T#ilef%FuW_hDPMx-a+0 zaTwUOgsTiUVw~#o;^k*dmNKbdHyrO3aArXgG_R*!brey2L6tftom%j=5rEw*wN|xQ zOd^*3@BnRa3mf@Xj&HQkc`U@5)3M_|+*`nL=y(j@Ym~ATqRAf^P}aL%>@M-d2!*PC zO-E0YSYrYr(g3<@$}Iujc*pS?3`?bHT7iHR zkOMk?L2>=MIIH4yekMZ^trk)a#WMXXu|+6!vn+HrTiu6L!>!=Jx)RHxd8X1|<>Q&c zc#c=Jzxw=!?U}-`CwF5oG|j$SXgyD+ve1f-eQ}MP+9+*Y&Z-=Yh-eB>Wk0l^9Jirs zzW(}P))0c2bdQ8pV_gpnZF0&b>_^3XmZuL%W0g0;3Jp1}`C3WWQvF^5nxcv*O3;cs zT*RNEve3VF#4CTR>53eO+uB<<+rC7->VB7RYu34ys%j5i9}eW0UI2)Ev78EI4HF8h zI9$-4?8=&2t>G04kcg~!KSH%dVB8*%3-6DX&S<`DnBz9V#1Sq>(W0ShK-@wm=A>q1 zcHi3ojiK*~4w#sgklXUAd>=_S(kU~#;IQQhid{2peyV$r#T4!M0ZmLnT~#^&EihcI z3e(|{RV3E%&Aek1$CW}&)?YG@fyBuhVMLFcF%E#FW`;RN6=8{*!fB zF{-D)zPP^_Q8p^YM1v7B(Hd=-VB+nUK=rXU=u=C`*Bcc>IJSdKI`18(wwI#lJz=%@ zcMMgO>koHx8t3~Ie; zTYxZ+;LY)s0FULo&=~X+uqb=8msDVR-Mhvee)4z1Zi-ZxA!18Dsc%OiW;)EHB8d3)-aSRGzCVXBKGX;Dq*-WveF!%vC!Y;PwK9%lO z07{op`y3{3X;ubD;qw=r2_GKGF1H$87clGH<6BAF|HP%I9sLfTsjW_#`P^4T;o6VJ zH)TADc#J?k!$v+a{Fb9a64XeJ&wqpGg>xTolapOOpF=^*Q+3NHc0M6g{sx^)jP8dA z@K@~a8V&CNqKa7e(zMERo;WNt$$v&Cp##??7WT#!GroKRm4VX=!ObsFIj3%@?vJQn z8)%6}B^o|>MrwjsDQ7N%aJ(B%*f5(S$^N_`TZ`uR8Er$q;?o-h%kx`ynO$xXA&tj>r+-;o_fPAMEc@!Ee*zX`O&pyIaIH%8)D{H! zI8~%;KNHqBRRf>e*~*11oxVDqw#jfN8(*9mz7-4PzPTCWRP#00bexX9e^Fo{pK0I( zR`K&SG__lgh*t%;FCS1**F$CfFUk7P#M9KGbtLbnAI#{{cI3trRrCpASNlc$g^eZ- zjIK_n#+q>ifg9`|EC883!BZ-1_2a3Hdh?v{u(ncRd-1JD&cqTHs)T3(ZVnF#$ahnAw4Gs>?>4@Bddp7pl_*)|%W9M}G`b+<19K*}Y{)b~LTiK& zi7T-?liwQWMb_o(`yUZ!RTSN}2@o~5GxNGu-B20VRizO!yZ$7h;fYh?BLKv~cg=D~ zX7CB(1BlrCdFA|rrkUjuG2pV??&&VuVJ4~3V`j5H(L=gLp3fn!am_dSn_ox*-pI_s%KYMF?x&l}JVp6MQ{L;P|@UK$7` ze6fC7E-oj)WstPt?qgd~7AN(rbbsqZ?pCV2<@eAH;BmUaoj1q*&D?I3CzoQF47Ne{ znxe@R!ISjCTfD+rcVry85)XfHEunzsMkX*;$&e0C0;9_l8llYaC72lwx2onme4pF? zQL@@v$&v)Uq23GvHzYk=t1AUhB{(Cd4==I2*-v6h-4C>UTup}4j$26y>z$cFvG*Hh z&0Jq%8U}LYx!rV+ja2jPw?Y`G%%Hk&w$kxbfT#OXFWCX=>{ zCXe2^za5oTiD=lghxe=#lOvRpbUpapu$^j*KNPbd)@ZxvX3)ltC|`gd1%`vhKnPbl zi}}i$?m*a{;$zff!l|76Dhp>$e4PbQg8hF)kL&_?h#Eu`cJ^dNdc2-|j7hI=6U((_ zAh|K2B%jYV5}Y^j)Y+m3CR%9h7fJQt!K06aJ#2l5Z!5yL*WeCz8tG_^Fow5mjzFaf zO2M46I?OjToiH@Rw>xQC=~}(icfcu^=u|U3wW6=C+Zqi@-^vl?Rf^oORZF>PWK&F9 zJ-xW;ToJBxc(8q^I48)gT|7@FzyMWwprikmHp_mv?LKK){*7lN;yJ6^9L5BwnkDwY z^0Ks^N?Oqyl7b(Y>kYg6DY%@*yRcieRflWIQ_cw|+56PDCWpJS`;t~pbeg(_{ILdw zd)G896q>%@ikcqUZyS!fA!lJHZ8mkUi~$HbP|}Wz)g{bT?ffWQGlqt+ZwbSavS*d- z|B>w+Pi}PXjhu4Ais>4&xHh%0dh%L9*RgtG(?9^9mA9>&55C84*z4o{r^yX zRzg>R;K`SC$})GMyH8f@=%{itQhx&=EC|W{fTI0a!7~c4O|7QhxMGe>eM+Ob1~nD^R41#SGA z(2k_L#9zZqKUxDHI1R|cKlh1$WYxl77S#PuU;XptN*>DqILzXGbce2N{AoJ}KYe=r z=y({xAgo@O_pc1PI&?E13Me5pB*_evsn?{w)?H=$Sr`Jh4YrIBx7Lofeg4JhzHzUV z9e6Z-4o{r@I{+7wq7~j6(g{Q!xi;pNvyA!>g%gZue!r_aJAZrujkyZE1At2ZQ;E~? zXjvFJ&qIR1@@#+gL{syFvt@ix7U@rxLhv=p;3KqQO%p(60_}p9&@)I}cXphVy^Ceq zRn({}y@@BVUkc{?bps64pU)N%lDx4G>z*Tvs@HWIXDZAQ?jbM{TYg2S? zj5g|0To@Z=|A9_mW#r|kEk?0-Jyzxisrtj?sZ>D4jdP6!=$X_Dci@Z#tkJv0gX$uP zOOD&Odb4l~jOxSXTqK;1i)>6PbZvOJ!}En#PVXwBM;KvSSy}!Xxn@Vmxek9qU~N+M z?i({ag6RZ=1eY_SX82Ab11PS%?PKfxSE$uJySN zA_nw4&KJ4u9_-MO0^*jz)acmsPGpk*y_cwZZJE@JZjxQF5$$);t*4?+^RHs;TF=Z1 zx~@NdsrT)axuW|7yY};^?FzOs{JCi zWEPRf)k5=`vmFN0vj**MiMC?GQ}iA6QU2JxWI^L+<*{1+n1DI=*76$?^RAbx1WqxK zqV`ugGBmT+IWK>ehK4*Ys+=*C+N5O!JZmlAhH;?2_l`1eCjeBNB80!!!jQ_&c{z%J;6E-?lCtl%?Xex_$YSGYi+;J-iQLoc^WrR{%rQN+H z+CPuX%p})mdc>&3R9jqti=8UN(9px^Ks@b6RivLgP#pLauJatnBDGi=wlsCR7;8hj zTPhzVuRD@6XbKrL&}617^b6$I)GidhV5zRhX#9qTqH^KBGFHW9^}+C>zdZ`gFAZ2} zqX%{OaB#gt`?535{%)eA+VxQe`G8sGUf)6w5;rea0(aMVuFt3dLsOK>{ee%>2{U8Y zxpHaK;A?D|j`lRwDBp-Inb<8F#NnC2xO_%qL3iv6r@?H|fIQ;-%Q@k8PUbc8SBd9d zFc~n(PPe4>fSLEiZtuSIyErS0fh0nIFE|{@S=EBO&vs;=p5vWh+kyJ!DHQa4@*m0- z|B|Wvov;2iU0%-)s(Mc@2?0gZHlPy<7Ch3EsJK^YzShHK#*w~J>5bTMy~_JGr?^(_ipuL7YLxc@2`R~JGf30d+CcQB ziEo5qJg+mXT;U3ro?Fvt3uQ*m&hz?q`eF2K2XmKddwpG_=MjN@4Q;xB+)#n>DyMU< zmFDcexxS;x((A3IVh$PFhIr&2Q0omCZ8=fg)KcZ0d1q8b-i0L$Y?yom0E+>n7r2mp zOHzGfGfQ*0q6i-R*lr}*wskG=R=m+N(jKX85Nl{Beq4j03J9R`HB>v$maW;jZ}8z$ zy}@R(xTyz+V~GIa~8Aah=~! zu(Knr9{@Wh>myA{X^S;6T!=9OG*#b7=(!Q1Dg%lQfxPn4^3<0@F=QPMtLAYXHjFT2}`gB3nEDO;{4EWd!&j-d|==I?_ z_R(l3rj92^WEGKCz)JFH9xUA@$clTR_Y%Mw@u;qh)$y19M?(JHm16qK(u$&|@B@ep zPppe0G_CIGjd=HlOvmR9w9Hzt~e7RPQ5RRi5<#&Juyp*93Ebg}T+V^3gPMieR? zDr_|)41<+uvo!05rJ^syt!sUGyq=WmWHFKEQxyi5n&sq3(h_DYkFiAw9vrA7%E%@p zwkSU|0`SR51#`@qV{Ch`!PCbk~$IOw>!9QeAtO47w(; zD%JS$;}A!eI2rtVv=3ebqftK%t{Rrl#T*oO6888-T*}AI8Fm`mt`;EE~{&s`S!TL;T8;Bcum{zFSCJ&xb38>59;k9uAiOf=h6yNJ4n$KoEjKvL~+0i~^VL0(w z)QvolDZ-PpDkk`|NgP4Q^4$Xms9&FE<)Awu3EnKN(EU->yza$B2T~O2nS8eOatn~~ zV*QKm;CLfNWy}4=JE~O9L&KTVMdI}8Yhb4DZ}WRTZ2LLU11wY@V4VCA=V^`%qek|+>ZCTcvt3bYqq?~zfB_#h}^~$s%ld; zW10+FX<^G6dYXhC>EI3q>!2(R>#l{LYjUDRk>=W^hHDcZYBV>kmw+6074On8HAqPpmB0k5h5SAZALgm|@N(0l7!hcfYVBM#Z))VM4{)*-h5lXrA zt%}tAv361h0(3;2N5zPg@(&lFCRKBt`iE{)bylY;kdPUYW}vU+V%ek7#^wcJ_(B7`X)g}x{P(;p9z<2)tCs?Vld=WStI zV%DE;8>^zl_U(jM{7t(x{5a*9@WsJK>_djPC{&33JU?vSp`r#VASnC3or13RZF(1Q zMl*^M_1%gm?em_OXOD)#V3cIQfogB4^vDc(0P78EAX5EY?ni%I(|czyzm2HfqeZT)n~^uch7*Mu#j5;I9}`hG@k#=QvP(?zx;>){#Sp6b^h`e`Qb75sK&(eBJ&iZta740>$O3aZ^VDw*Bc$Qy4>{CON;k z%oo=V)-(^5Wb)LHK#fhLi2nxb2Jv7@bHsyTpn%wUE5O6bZfjjK_Fj{r4F)ymf2^!@ zI2zG6q;0^i1?>eGh5qbcEZ0A*+CTl!17o&<&Oy;_z%hgnqzC;@+Ajs}0PRlzhPcqK zyp%hf0B@=01Ns!RpleFAomZf!1T2v1=mjI|&mzC!LW6)lyussGpgV}_>kM=YJqn~G zIDT5;xJ&uyo&D)Xf8a@f_QUY#-z;?ea!UCXI{t4%$8VY6pODsXul?&-;cuSee<~pT ztrh(DU;C{s(f>0}DZfQCzdXQxd4TK09{~y< zUo3=s*y$BHf?&_@(?3Ti*ahBzwBHVYA92R?VZwAY(sIkqB-($xjGMux-?gxSHBR*h zO$3|uk)$lpn``*9VRt-<{2Y%Jz~AdYqN7Y(&3Y%dt?0Wz={X*! z`OM%w;A|u#y}N2wbUI#i7+Vi*a$1MZwI`qE27RlCHU=#NlB1vB8xRKUV12r|(Vgl9 zJ&=J;adzT{@_}}KJ2YtDaj~}(H?SBpdp0%!babKsXPJXi7)}|uJPP#Ns^uO1;PiAp zi?0M6U$UXsj(+>Fp(oVN=Xj#tjJGCr_wstyw& zhngSJCJs9vAAzSBv&oHZTQfx`r+XdX)k#W=j0uu#yd-D^yuJLykE2W;YL-jfx{;rC z`nFZ*!0vb8_Wlba3|$%RA0DScMZR8BPw}}-%VtZ4G>)2#D1fWB-09#u3)xY~fW$ zyROoQbf%iAUwYLv)Ivvv9l1r5;*i?U=zs){RbC&bUW0rDk=&pHO>0K#UlN;-V z`^j}wW~tgQ{yhVx~$F}mxHtTZnF9x`7j`tUG>x0enVC8G+q=q zYaWS96-z%$mlVYfOhZ>kx}!pW`&PL>zEynpyVm@~4;nonUJKx;cE1aps&s$#3?9TG zcH+2sI>&Pu17dVz0LzKU?h^3QZnxhJx4w}8MZ?~9pG;0b{}jSQe?951G5s}9UmfeV zZ7xn)>xN4Ns7{-hwKt-5;L}BVXDX^0hywwK{-!RbEanRt52}UGUX!)~2KRnELns~T z@vqH)6sw`d#RA7}EXV6%jA5=B)<<^&#cA2BhVdG?IAm z5)|&}d?GU@>funL`uaN;l|M7Z`;9Bzw8@z>)-`g5pdtc}^+k-6rr4kjO&!H@+pm$u zcCzg6xF*wHHV`{3(Oyq?K2d(Lz3oO`aKL-|rRqHjZfO6~mS9b>YfN(P>w54TJBD3N zWh*+QOj_BONV2Lxy*tU1*2{wA?0OLbv>iTgF8d6!sQTVC(&fXu2n0bjkv~M9>4Z@2 z`Cf;wXy{K&)&@kD{}R5n{DN=4faWit`ELOAD@-ls$8O0woEus} z=ETiCz-Cf+;fcZ0y|UNr87hu9yxw=d_%tigeZ?#s?&BF<;m=OE^@xgK*9zjNHMM>S zSB+SnNB$1(U9_{a0V`kYF#FpvQvHnSR7}nj684tXL<7QqT#j|wfBew6J4pLUz;ro8zV*AO! za$UXejTJN=RfJ=Yj6S)L#$DPA4WXMr<(+*|e;;oBzzhIq5K0sU9zk<%8*h6s6g^*Ug%GLJ+W*H@avEofHpIwfDWo*ICa3eYIGMDsU3Qj7Q})Zm;?YP zI068i(x+OWuU_Is*wQ8fT!7!=kf`+uVE*>b1>o#DD}W7iJ80i!7og&UpxCEpW9xvI zvti&}AQw;zIL}lisqNpeCSy94LU_ z-$@1#DUhESf_DR?oe{^$awM5Iai;hF5|A=z+g;7AKOH~E+Y|!;@2@faHKzZxd8&K= z9Pj$AX)tiyuUGd+9>rJ{{pY~<6BqM3TYvYi7ko8ZK`?RW2*V2!_gvi?z& z{?dva_vY0}IMX>^a_4S<3xj=$y{G(U=`NPmO>n(C2WJlAKM@={lH2cYL+8$xntWVJ z>hOpB47&OaFIW#%%3R1k?P05@8Lf0AT5%2sA4dPfna9H`FHtSfBi?JWhHl_aBze zzg1`dtOWG;2UY$0rvDwkX#?Y1Nj9yTgVfw{$fYSQqTUvyD)qPPi5=UQ~Gpg~s(+9vA66bicd;ssVRRK<4Nz4F_3$zCOpDv3k>k%9D+{_|GIYpa}p)#XC z14m2zEWOnE+X2M-{C5>bzvk1w<9yPGimVj~iZ7)t<&@o;>_kJNE{#Tm2^2qvcTE-p zjiKrXp85kK5x0*6S@TyyJFolO#B3x)>@PObOb3VmtZD^3>wbQ-w9HwDuQqVjB2MOB zhh#3^qXIrS>qc@l(yyTeyFoHR7)Zh~9v)r;J>H)hKK{!+@AoJD{F*TTjuYnRx59NG zVBULROeaAT*VoDX1+4olBxT5r;9e-%$#)r`e}aSV6}Me3h%)TX4edR-)#AFlVQnj2 zPeQMrt$oAtfvcx^{a=r!;3p2P8rSJ(SW&zlC1-VfAymBm%SL=X8+; z=1b5YTW0>t5~uF--xqtZZbO%qH{FmhX_G9OS7=SawbO~Gjggciw4%oLbD4|}=gPGO ztRA;NU^z3R0{1-_cylkN!MX_C6jqBjjgsGQ`wQntd zJK^SBcr@=v>Z-YFu7WOencl(@M)_|^8vpQXraV=MN<1FNvUq?_H6LtPpY1H_@OSuMW%EkQ0JK|05mMms)yH%d0AC zE8sOHl}U9;wbT_^RhctttBJF|O(NviQarEj_T5wlZo9EWOt2L(!`hQEZ{wH0l zWI)qY)`L6QYPCeG&H{!yh5H?d*n^?E&GLkg$A^1AKk2WswY&NSeq(+;a5TrKzYLQi zFUCG}Bq=p&P&G9~Az8{Z07x z_x~L^9((=;1Q*cl9Q5YQ3UKm}Lax;ep(EiTP~kVgg5`OJKMo5ZXKRI7`8I8Cb?o^#R{Ut&uz&>rEm7X3u-3Yw8n+K zVTu3TLT02tK_{`m*dWSw{Z3@xWvNU;^;8ATd=oS8;{J?EkIM?oHb}Uj)_)iC#g|(J zsFD<^%rS#_B?8{jZ`%+{uLvy zkQ2(l$WBiYDBn;dGpoeP>o9F+@KmyGU|T$N-0$+07nF)>toj;(HHl9yJyz&dV7K7~ zZv>@&P^W#>Ch&DNOe4JnQvs+EinC{+4F>17N$19-3Cs(*caUZmAQbYX@ zno12dg&2Djn0fGXz!M9w38$tS>Y1+K21mo31dc?sGf}SQmDCf_8ZMJHVN6Z6kt~&s%k}&Gj^%njRyc$JkoyvLUm7mD>QOG8_b#I?V)NJi=@Nm}!>RzxY=4DO^b$CB_ zSGd+brl^JMqVUbfym~vTfBCFcAn~z zTqz$i3>|XC-_4jRKDc_9Q0?`FhnFh#56b0i(8-FT6*SZG$s6+qa5E%bHq!cmM)SFb9YLaK3t*^uE$yPO1>YE9PrH)>xOZl;&yg5u z5MC~PTnZkM+xZ?M?ns$fvOb2&OlBNR#a;*zA{VUl55>~kBgJKC{^tudYPCftMy7vUTNay(X4f4ky7s0r;`3&GKR_z)paxJURFr; zBek=A-YQ&}s!9(;rBpUeFuylAG9`K(l(u_iEHW?8m{Il8x_qdsd0w`jJ_jROnou5Y|+4s0CkRccc0W+#&-;#s9-DqB#FQnjWN~X)>^+dO!xiK zZVyl9bsMI@)+19t_Wdx_tB?L2iBIQ)<5mVA+({04mHTRjMhemVh=DRa&QK=iI~@U; zie$7u(LXN2o=8BqKiR8wmHw|JZNdYQNB~5S@N`7 zKa?tW5=?(-c0|jJ{sOmqQ7hUm?RtOC)E$esrE!i2;Y=?2+!lwll?tk(@1UXXYnMaO z6F*gqKioyVfRy#EkDSRp@Zr7*lNs8>+a|ID%kt8hE+nVT7`TyfF4bJ{xqJ(v#MjR? z4)OkOsDJ@^!f7(El!F_rZUt`g5JB#;sp%}>@%WHc+9%!w(RXCV*~phbsoI)r+paOn%eG91AvHC&;#cO}Y_k#u+0-c=sEnJcJ?7qy=0i>OJyS{uVhJ;^ z$H}TCYe-|Q#u!35+Z=gxug^=Dm!}zzI3!-LHWs-FV^v?idO7IbCttM0T} zcex(}CPY}bXuTLd2of}Z<@d_rd9CK-+M9%^GP_!KEn=;^wF})Jy7vIVyG=_Uiavh3 zcrrA!aq`CN98bjlOb-<0yL*;=M1*@oagLXkbdDDV$kc#!`~V2ICaezFbg!^MH@M_Z zS0n+sTNqba^iw(h5d|pXgn;C$3hk|jwm_GG6Q6u@fTJl zcjEb3FQ9rq0Zge%yO&IU^E4AssWG4gT?<;p^;7G{EkWmcq5FD^->MhCSRcdB@#ZVI zL6|THuhZ3y?gAiLe834pQT)`U&+)vwcWgl?w|9??cE8u38l2;OHJ~iQc8N&heEk;3 zMWH9@Ea=#usywvS`nyokX-3c~&(RMP95--iFLxaH%$knj98X$$cZ06`bSN34^s{6W zG%xsr7L3!lgQE&Pt3Jo0JjeTyF~EhZPe?q+D=0WRNLa)<3}Q=u)~K_5r8!IB0)$0C zKD^e61D0eQ^laEJ9q>PVqXLNPI-!3y(xJZw`qx1J-80%SYr?7xN)F3gEm)a$-##{) zvT2jNX=@rCFxEPFvNwbRaYx%4rkNONuj%V*^1&?hL_HGe5^J92lZg5httU#9SG~Jj zMh<;Y7)jBay=IyDRU3m09Nk#cX)h~h+pmk&kHJ&dy{P^{jY-@QRwPro;J*n{#!esK z7$HTCRzD2jZ~8EO`nhjhI!YlnthG{DVg1A^Z~ED&z5gM`hjeZ3c|-ueYWmIek-R&Jd!04gKHh4p7e5?U z(&p4vS_*%9UZ$?|OzHoy_ugSmz1zAdiV7k{1*C&YFVbshO7A@sY0?#tB1H%#6zNTR zlOjE#gGf<&69^zAp;+j}1e6+q0P#%MZ{NN4Dtn*3?m6o`_daL+;p0O{n3>=FzA@f0 z#yj4TNLqM%mp#heB0a?D5U57sFXO1O)ipNZAu>)H6@#}AcQBK{m`*L8T`WRfdPSVd z(#-6hsvp=1wu@KZZgZN=iwxzA;DK)Y@X2%~gT>7l}Pa>vP@vFy4G=?%R{(JzhiV z8t%H=C#PFQibj@E9UeQpp{L?!r4w(XXs+B^3+Ew2rCkBpOD@Z~qM?875_+M3Hfv!3 zOXy#w^I|6~h^mMetesW6qO`qyppvfZ|r1JgShK2N2Lc6GjJt?SV4 zL5dFDZ-rfWW}kAHR{6Q@>zicAY=FlvBFWEGpN}9Llnu2J0c11J=OvXynck1x8`qs( zPq5ScL9=+I`h*^4<3i-GMs3>N8|Cm{%5eM+^F|lp42w)y7o(0Sl>3+%%30tvX{CLP zxv)6Pzj|P+yf&jzL3T}U!0lZW2%A+4=QwrioWEs?PD+p*Cslr|rJi=5c-gG{*bQPe zV(wW&D1r12byy?ys&GeU=bC2%B{7xmIN{ovFB^d6+rf0rx!xXuCeXTIES<E{@X4w71fbG12MGiop3Od~r&7LQ~gp7{>2rjhU ze%@B}Qv@Jm<}d!n;X8W(L~Xwh{n_Jt@QXeg=_61efPsUL4r)FV9J>$i{>H#8Ke*2mp?I#N-yr<2zCh5)%u^uHu*Kg{ z{7ra0q9zO}o>K??K3CQRp2Z^`D#9FPA#{^X{%i{<=jIBXlm02f2m**94s3+D&fgfk z4#41^rx_%_h}=o^6%SGh34ZxdL^k2YAJIkU01#aOBvh4!KVk4$XuQ<IyzgD*KUn~3PJcovQWb*KEp7Msteq4x4|X8`arw% zWO1j6=TL?Q>!J7))Ek<=$p#nG7Y{rBJV&sx5^eWz=^oJD7S zO8Si5=s}8z#3fG!?Xy;~wm0bdcJIeIaUV-^<3vP6xInsBznH1`0gS4@X<|ZKvLz6n z58;E3pF(O7452QS1N_2TW=pr{q%m(sRh zJId~oxf9Z|_PULsc1u?}+G0l~^61jQ$@iQiQ`!)dA8J2rY(80S$fT@g8I+~W)qb_( zU|V9>ORJOhvui*DN%6lnD*F%qY}(Ar3B&&~ga2|cfAZb`axl>U6As2e|3xToA#BeI zgJO+`_WPW$mWy(^jC=(~2a6VMJ{Oc47jy^atjnLx9;B?_4Og&<5%k{H(*> z_wmB#rj@+2`tL?%Nuc39POZ;3!t}dd(6K~1QhaI-I>WkKJsmvi&az?oTr0sSu_fAS z|46Oi1q0i!X%V)Rof5gJX-`9NSM`3~wRd5cBd2p5W@^`Fa-QrU}5)56-6*2N0Cq1~}y-E#PlX+26%(Pyb zGzE8(sd|}^*|AV1dFQNNjvsePhC(rf7Ar;BC#+ZH`}yV&|1+FbvlA90A|P6kPF)=T zJVGn5+y&@~nw8bdLh+}$JZaHRs%=>HxNz6O`7VVXOX*LKAO5&THZa(A*H@^L&I*CjXb zAcjn-ixjFG|M+m%`Z*Jstjq^f+~fw09O?W_J<_x3wPJN0ihgY0AyXXI)}C}9dhO8& zcc~%c{S^sT+IKPB@xNz0{_mhU(H2?#BEmT?G%D_9`2mR5j*md&Npc1>U>yS*+9Bfd z+x3LP#8$#S(3h4;t!o=|bZ%Z$s(8kk`}@tVf@aSZ|D>LHOa^V)!9xxdPe+0XCSay6 zX4Lb)b<}|O27f)Sf|w1-+v0h#mD)|2LK8SD5}L1Sn3h}Fupwb}v3T%TyDoS^MWvF) zg|bWe#62@dPGp@8mQPNj*%6_4Rdos?Jhy_{-~T+)%W*P_Dtu9Wbzd`z^|h@G2NwKzFd~)?sP1+MOW1VWD ze7&qkN@)^zwGqqZ>xrK^STqc|OBrH^iw{jyU;0CXo_3j?ysLiT^z*Y45x2oKb+rL6 zkyd!DVgJ+Xa6Uc+FolJ(AI4cfz`vdx9~~VpmGz_|vya2Oc`!|l0b$Axd}WK9jquBXY|2*Sn7-YKn}=biyag)5j+fr{&q(;3SOTB5H}t^;kH zRUUsgBl-`&2oFLFoflZ{*8U>uG_wMvILnq4fiNnovogJCr=*F*>lYEGck&m}Pz$h| zXifWp$o_x2k03(mU(i1Ib)A>emPuTl(DnAgI_}_#?{d_UB_hXeRO8bL`a%Aj7m79>vBg#^y z2jz4XY~Y2WDtQq<>M3Xqd1Zd%MEr&v`oXMR%qu+o9RG$@doJ(e?ktl)gAF>ZCwJf# zh73o&_ouJZccRZKW!~P3Z)w+xCu_Nw^U~kD|HeVd`RVqlv`z4YUwYfLhtd3#C(liz ziVKvq!b3~#D18#heD-M z+v>12Wim~xogt$6@-3#M`hm~m1$XgFyjSmB)zBzt0EN8qoSSv={IOv2)`OW+;h@^j z>Glh()kSLQo~z6xnU+Uq-2Bs~jtCZ;iLM48R@!^F)G-7$3uIS;8TgLsfcLhcAwOqW z>JBF-*S9tK1RWwNQzEDNES++>>P#v!70M?6Q<9;^#Vy%4TnuA*BcDw=un{wgB`?m4 zaWDgQBgmkK*vQ-VcYpVk|HCh;Z0%71VFD#C^B2*JVW2;CTh^>k7if>m^7%!y!oTFI zvHhG-hyV-`AWH(JfgJ(`MAIi2c0ltr8OZ6+nZ~3z+U{LbT;X2gC3ynm3HCP>k6s>~ zRl&txNfb-`U1LcHH7y`5#mQi*YppL=!?YMc`C+E(XWTbnmj*TCUeMCeQqtTsWvnVm z4MT<7^&vKe==|%%&hN0kmp>HUJ_@2u-Slr=(tp;VfzcbJGD+j#c!DC2dyiB)6RUqGAn%Ri6{{jDN5H zZrR>yZmGw?%i(@|do#-NIZ(nhhsNlaGvI@;?A*R=u=*|Pia^);d&>bVrm_)e-<|6S z@SMQhJv|{q@tT}OHQ%a?oSW>7Bu%h8RurPaJN(VOf%odWwHzK#>!=*AuCsuXJB$52 zyWaI=H*MB^2bTB!k|BtORqJ9z1QGFrh$|dek+=v|na3P%egW%*dr-$>d z=26lv$e7hFt1^7U_p6CJ0sXhIsByTj#+<26P4erA;Ay?lcZF2^bbp^v^WP({{Rg{d z8w?QkU8-=Gfl4!X=_278i|(4&8SanHb#a!2-O;P5uYQF46tWU-xsH2Xppe<@;GWWL|SxIT7_RG{kQZhkJ zjw6mV4^6qW+V3ByFJ33on7eE@{Bf=uZ_9 zZX$laxrL7ZUD5ue!5{gTDSD(c__NYHg3;o(D_IenK3G zSyrET0|X&Rq!*-~8#tf78GUM_zVXz!k)!V==w_8P6!L)if<~>M;&SpiFp}r3{wY8i zD5%LlcOeu*-(=&)LZ$ZEfWrTl5YBdFze^o)GO4%-OhX;no*nOg_hIss*ym(t%uNS_ zmLAaYeY)W$3M62kJcDinF~r!ruSe%YMdVvk3p&^&kr&^KmJ{9VyYEB)bVF*nDOa&? z{e~U4W-WICd42Mcb!>M53M{e)}&r!j3+BeX=osZfZlizQ6|~hCvLL0cDpH; zK&Wo4D=$pSYK^zrpB_jGK9J_+rm6Ae@y6aIT~c+W-a6eCo3u#+JwVwS%DB~;>l@&8 zU)qvGzHl=a*Yq`CPoW=z2}|F&S+s$vc)VV#^usBZ_EOZ9u@4RbM;FF!(d=81DLK4g z)?jf+0sERY3BeO|*AW(D1ue#Al-LMTBRO89i8+Ip=@)4eudb>C;l&wO6SJ7G-P{rU zN4v4Jz|9EN!s^NphKM?zt+xfAIR_iXBTN!MO*Br&+&*o(GaEr(-}KEuic;g7{tA>V z{`u^dV{N8X=EDpi*T+;wzpvy-J;j&&((N&2q3;3vVLr!t-7DYE{8MZ1lhQH9Bx8Xt z7h;vQwe_-P!D?lVoCP^q&YU?}9Jw~1=HFV9-hYu4W=ginFg|1F`z}BGPj)~jEpSfq zLReoGFfz*R&*%An!7BXI27~{ncA#3(_BWKNgxZw*go=ru^KJRjf|gP8mZRdk2%Oiz zySoWArKzP_A66OfEHcB13~xVZ4ZpYgWy^hdAXpHp5j@P6Vy!Qq8uDOMw)~Vvd8TaS zsYf_E*4qlI6lj>`T=$S*%*h(|^6)TSQbJNxl_8Q|d6BGIEWckg$(7W9>bySw zZqQ7JbM3{8>lZ68YNf}rhgFXsssrAG@GYitdny7ai<0!THE7?wkR_*oag_hTzKmWp zT$I5vuP~4+t1~r>cOxU^%us|VoS-~E-r3Zj!vEf2nLf0e5*r`;Ot5nYf*A;2@vKshjNz0dQ)xct%%FQO zWvJ+Qo&7)E9Y^y2t(MY1^TPQR00e>^>9mI~3t*`Tec&^m1*&5}r)7_pfPWk`Z+kA! z;Ca5*3^*vRyl$!;e50Zo^jKRIcq_`P?gw;CK4p)37vPS$Egs@Fphs!Hv9VOJOx2J7 zYPsP-gxP$cat9FVTA@I#=>*`7w?Rv5fa}%*?lVT{{Aab@QeWf$#%Bf`_kTth2~d7b zj#hz^h;utm@fT67837?j5_V1iAh34##xJ67t|k(U8=>eO+mY>w>ga#VCHz+__cy=$ zKW~A6Jq9m46NUmaGj*XS9KdiJ!{sj|KPr#3yML|+SKkiu{Y4Zfs(9Mtw({R|fq!#P ze|6mc(o+AUhwl$P{eK<4fA7Ef*WvreHr!uszrXnDUx)9164(Brum6AN;cGydJkY#^ z1{>d#mj}H;PV$mf#S3b3HvqE{&7{{f9g@vI`#!5mW%@*K#S)0c`TTiA>F<2DJm6Bt zfuc8%kow%+13g;=2;z!UGe8D?2B>=XXA@4re`i?ge;T*^-2(UDya<-ZW)miAk4=F& zm(_KOrzF!}Z28bJ8|293(Ub*o8}x8#^B2+TLm;q?{~HHga{p5LBMFXU09^EHn(12W z(^@l+8EQ)}lJ7B9*M9d3RtFl?O_Kk*(hinCUV+Zng#b6YLJLfarMj@B2<=`^+d1jp z8L0`!0~f3OF?1+TX|QRN?{apHs%OuYQ3HmzLJ$o&1K=!6DhzEXG~=arv?w9UO+Z0Q)0CuM!! z^iLeq^4?6GL7WcGm75S8L8iWaJ#_ks+ zZD^>SgWd1e6H}u~oE?5}Y07xS;G=mow5HNcQrm&kegp8^eJay*dj;=b^rqsOM$} z*-Fp+!IQa`un>j*yWCrIv%+giEajJ_JqISR)m8P%X@r%RNOPR;nm zfofzXoiXTOT4RxMSZq?6kFUWy+{uco`g*?D>~ap(0YWLAGywf55Tn&8RyI8xh%PnK zkOO82uGtPKmdGnlPOrJc^lfw5m=J+tw-1MJj$LF#=H8i*AHtwdu3ut)V>QHO5z8H7R~PV1+k9+CVgKUoR0^-p};ruoF0e5K`m->QvC zBbpw=Mc9yp=U3``6m@;hy+y7IcO@8}UKg(>rAoInUSA?Jxwr3E!LM0*g6W|f=W zfoVye>o=aYVg<{-C5@KLj6IRH0H9?2QGt`Xd-$B)S+LBHTNLRem!Apye0{Jn(MVMl zsS?kraM-N1rcSPL?ZevLivz@1+?B$-5KYH!;}Avn^{fW$Sy4`dYe!-$N)MQ3o|YiK zE@zWxs#ZM2BgMe$;&_dZKP6Pk%m^H=P;a1L(CO#+1%^&8_w^zA1~taF=HfLaX`?q0 z>SYY-Cld^+;KU`=98R38bYuBlo@?7&Qisg~GY*n^yt5*b{w(AkrBG3)7_O+Y-M;>2 zpJ=D4_e3D|+HMEmD<9g*-X|0~i*lzou&%4xbJ(xIy_r7;roa=Up4;wv>dUZ^4R7@D z`E>bDN>8vMSyO!{FM6~1JB`yfOP9ZnS2r_vFp1a1x_Ft=v!|I};!LSVr_`~+JLU1t zk-Q^Vs_FnC&Gm`C8mF8CdE?^RVCnm=1DDjFUq3?xB~Sf~0p^1nntoGUnf#VeM{lZb zdw`B`v^qjDTkMBgV=9~m*rjVS!Sri6f{c};*73L{RRN6w(KxWxl}l7+@G%)Ij=Fw8 zicljvV@9B62C|$D-)*l-WfLqW0hnJO4r6az#0QBko_=sUKQpSFQarb)EK51#lDP&H zFdwo4V;=^9{9kNQSQ!hDv_p;oZ9)smi~A*26J9f6|BsjeV@Xq1CM>PQFKUZ}=1tY6 z1;_2TXjZPCqEf(80te(5I2+o-{}c0z z=%yp|C~S5R>@G)ds`$Hm`!b8uR*^=C+}h$nDrpunv*(^3;?CHgu#2RE_0R9ci8<3n*{90WZZw+H(SozR8A~6o0FX1o zrnb}5*LJGQWR#&22ELcn6YU9*0H>Qf23KK1hcZ2%Ui1@S?e4%hP`c1Xd7e)JjjJx9TY<+%Kg=W#f)x6Cb) zoJymK*1V0Yni5Ea!BY9);AsNB^FgQ%?i5om;iq3?Ei?ei&u)5Ez#mLjO*%op;nZ{G zTJG-la|#J?&6+x3n8hA6Co|m71(QNF8=xRHUOZ^0H+Rw^|c}UDd&ZyC^`a7VG8tE zz)vc*UvdAd&zUcDRM6DcSrJF>4otCR-6TYQcl$%(1^j;@wx>{4p?RqbHs-yH%>xUf84L{qOtztk%XM(N#GU-oc zy0a?4j%fe?8S-~<5NS#h8|edjhOKBy7_$M&3DGX!Fm5-{$dhu4TyjwUMMQh5zZ1d& z9J9~2pQJSnpD*_VdBorQ4fqG_xBrmFgzXGd6UKe8&|gH?>(6rns4kqI1JjbTp+F22 zs_RHKJ$tU`ulS=IsGa`Fw;8#C?DUh@w&x?%!wsC{L|%z@lj$_)l?MpFS3w!Qznj%$ zj=|>gZhUPrz5YQdO-X8Aq2Bb(xj$wR?Bnk`EJ7$-mA_}zK4qnS7otBYe`{n;EqH`p zPqli0&%p|2YaF+PoLXrsq*Xf}5M9oR)TEUV__5!w)1>6AZwBv|Ct2<)f9z9ljSnio z$ED#Lqu1RH9Ftr9KJ%=fcrkzF@{GJU&3R9B1+^!^WtUI++Ev<>5Br3-JZd;&A&A`) zjRiw&5CN6yAvTbT!&B6vvH6aPSE3X-Mx}tg2t|1>TTjX`!I{r}*1}R%<=BssriFYY zhCkMb>rvG>fgPBXdoZ1SZVN*dNs7FtAs(7o%g297PCK`<}!Rl+*@3p0vRcYbI zQB;G(oOlJCWj^=VIok-mn&k(Xeui|A@1!j5f{z}ZzJ7$s$U%Them1WIZ6nVj#m0SR zs*oUHE6|GM~i>X1dg2rQk z6AFcpL@bqo2(#I>v^X!=6YQ>)56{w@>E3hthI_`jS%;d*Y=i+8gYN8A*on zHULKK8zw6LR%8oeNpr1$4>td>*Xa*8useyo(JPGSg&`!&%N-95$6q#doUB)rk$UNF-|Bnb_7N*&(&MW-}lQRBez7EX*LaO9mHtuzqP^qq{X_=p)JG1w>M2G7PiBceb88{4mSWiN>|nhW`lA5*(h}-&;dG+Suf!ZZdDvd zS1LVUT{$W~l7OU+1KtNOY2K2-aRnmsq!DV8!DFX1~a zJ%Q&}4>b%|{5-b1;r=9SEFAP+*b(-5?bY0~0;&(RUlhm4#qHk-gia73ovP`3LI{gy zen`zBXM$tRa-pcgqZA=r8e^~zazU*E%Vkfx%1x5w1$nP{Q!Og{tgPZrQ%^KY3Lw1K zaf)Vbb+(c%X;bjoa;aio&4xqzr?_gzzCJ%Zc;U$0D5j3C>AcHWnKvyk=T~ z(Uw!k{@pkXcDl*?wBd~&)BL0v{7t8UUjj;y6H|&(V@ZNU;$#z+=Au={-r_lffAg7T#y! zs56D`Yhx|u5-dRd-b$YI;mlPQcbPZXp0>TdrgQ+4<3WG z;;%`ymv+(Ya0=hlt8960EY`wB#b=Mp8DdFNjxw`vf2+kf%BRIFs?XH~PbTAap`sb$ zFa`dGcUN7Lp2uXT*deuk7C?Y7d<@aQsnKa(^X;eYSinz6U&HecX$nkCgA!cw+6<6m zSX$+W18QX#NmIa(f!jv?NXpG8D{EFG55M7*t2_0Ft$cj!&Bh|eu$&8bzn_}m%3^Qy8bgHU3aMn|hnyY|9JYx94%)`Rc!^PK~Y9rR7 zEJC9+0VcjODKduRvCC~064v(ws+rO6Fiw>;Wp|Zj5#~GgbZ9I*wB}H;*w_&NlObrg zvU(IOO^`u;N=|3i=Q&JEI9r@njaU*kGqz{jD`vmuuJyPwiyrBfqf_JVCR>R}?V^-L5fiVh|`5cAn|z1&0l186WxKgyxa6ATJhImr@eOxs_uhSev-6Zjb# zrSGJ@2u#;gROkPY_1PsIjh$nMmF-?(8+8 zP}^YjCLB zQGEe%!xeoS+ua)b`f#YprQ+4Y>XHusJgtbGAB;xb>TbwVE(y?qg7=t-tXhFsEt(2av&X1ze`U? zIEoocGp?;x#D9T5Y03O@DD@@urMz&%I|uYFC`hL%)okb+eCj}lJVuCnQ`$%JYM%G2 zk(r5HTs7w!arFAbSBnpjuUhjM<6akuOrea+FZ%}QNT?2Y)Kg!7Jwg^@Q^FKs?BcG> z3E>`s1jhMQ!0Wl3n4#jnNXm%})VwiKSxImS-;+J&{CNA7Iy!o1>Q1@5s#{te{yxla zCKj{-KOg{+9Y0C0Qb_F-*!;4dpqa99wu4Me%|Eb_HNUQF8E0?d9RC*n{06)Z!3>72uHAdf7Ewx2$_o_Fr~``vZ{W$SB-8RlVsq{C z5qZTVaSNJ`Ux2@o1)<*(4BS$Cgw1lt3$VbLO@$A=vDEOc5)tO!99Pir z$F8Qs<_pO>jNP{mi;`BQzdmIJ4P9N1hGEOIE+zI%3^2*aJ}n2_kg*vIYD{R5SMXCW znP)@QD(HUze^uHtmB;P~nYs|(O+RXTJYu1jgb_Zg?Rs}LU>B>4oNA_hPD_3DJ8kYy zAi1S`48ccYcdUIXtE~E?&DORtQ^BsV0~_n$lo^C9Jk?1KZICK=Eca~r_@0Cc4Q-bL zSe?14X*$y}O0HEU0gb)$)eYNi(@-;b9PLzBgCD_A>fj{wQ!yYHqG(O+NXa>)k#BpmF;uq0hDcgd7UE*~%}q zMPf1u5dgE5^H@vt6rt*1oFTA8Avfs{t?;#BUL<cH2I=M`jzMTzeja%CX$E$k-nKv-H z5K^>7$2E+dNT}{=*+VqPLcHt8=B}9bb+9Al5>$-=@#sP-eTB=);UhWAh%3xWZ{J$* z1V>vulu;VB9DQ1f#@-6?!Dnp^SJ=G5n^NPXu48ILJiv(g{Ce{ZrttN|on#a6x?Hug zt$;!8vqz|#2%M+}tNBc!WV@5z0@-Zn%7&nCFp6$kRc*E#W!D6Qw0L zmiPcEASLf?#jY@GMRxd5bH1hUXA5{3tOK@v0bMC4$`hPU|R45rJio=rxly?&%beEew>jpaV4 z$K`IBRkN63*({oDD{{RRVqOg3X^p3u=TTM#N<3l}%Hsja6tOFFPL6x3?8YXvX@y{s zj(1AQ$#0z$>J3p?^=j5?-}Kk>E-;1zq`=&Bqk}I0u>$ImbC&*t=xY`SnSqrwm3=&X zOmxvgS@Dut&;Ze|_uC}_02Ci;fz#b`xw3U+F0wuU@r;Cav^|TtH4XIi<8j9nvW-c| z)b3)fH*dv4^b>wJSNKm+iq}T;vrpVou{c37^%YoJN6@!T6gQl*`tSsAn+IXZ^MO8q zK^|BnOgqr#EIb<>K%NzF9P-{AP2p?S*n{2ZWlk5FD+7#O=Mrm8=VRX@l)g4z&u5lV)r<_O#*$srwUP@{*bpR z<^DE?YK2eK5?DJav0#$QGg~RYRmRbF$>M4mzqG&;Tn* zSX(qaL0##qiCnI6<@mu=|*y&u&Deq&!lheSeQhjn^sk8&kTuZ*6kR@)Ny?b^!T7;1pT z@fk5oZNL*>=IhE{wl4-Ev`h?i#>EN}Geu>dTX_pJk>zxq-rGYF3!IezgYhjKCQAp@a@Rsmq9R9S5o7pQfsHAH*uk z+gr;HLL_rRDVIm2Nz8Y*&m&!!*`=0`vshAAz;mjX*Zb`5r%lX(O~S-%U2SH5XOSDa z{-{{}zv4)DIFnryA%jbaNrnM(!BsUlWjOaOvGp(QGFAdM0_rzn=TJp7%FAqT2uD+k zXzYb{ERLU7Y{s*=JR&|t*u;1m$rD{j`sK2!H4!7QmZ=19pW*WtXxn{y!f(m}V8V0% zg9$GM!p(nUnZYZ&ne|U4CSkvb&Xl@;+AYbE>>Qmn0r9QW`H93!MQz)|^SNI{9RTM+ z@Q(;rcW&@fP91f;owq$$TD&b&{P4!gv8-CAZ<4q!ecqK^&IcUNzeJ@*^|Z0;0fxCc zjzB+WDrKANt>ZG|X|Wfq4KlWy6ZEPd9hAWS+R@J zHUc`(1~5#*#~}uc1FcqKCDs;had3}eug3XZYwq#R&LA z7#~-lPOX8aGiN>EgbbpnN*59g{ocVtD})hTCFv+3|d%U3ta?hFldL4*xs-oG&4r=ADud)BX@S2l+=6e&?o$^QTx(Yj0+LVH^`o-h}Xg z*3WETj#Yq)DgqST7;Q)6t$tbV_QeKIdrfB$kleg+{=ip?9iR2B+YoXCm1-`kZ|sE; z-H?^EsiJAwEd`A;qxPFLU;;*Jby2BVOCF|lBxo$JjMy#?-hTju@6D5DA&$7`C_g%_ zy(&;@`ZFriMuDmv<^UYaJzdUwj#KMrBouk3VPILcB+2ogoDXLJEH8q8b2ykQZ?e|$ zBl{Q88%jG2x3*6qZGxjhz2p0o7wcM+TY^-H_j#RP%s9+BJym6nV81Jn@uPCFv+e@$ zaknar{p+&wlCT?>nV)ErI`}k6kP3!|16%P0B>7Cbg97_p!Y`r9TDgAM6%>xvD+1&F zdiSyhbTSysu2%Q&X%QPo+r2Z&g?BFwYM-F_`6ITkmox(Rb*rNi1Ie$JSNZ1eIfQ?g zC;YzP<9lt2i8(WMFO@O3u$8$Ds?D>^5MLa<&RljbTao=sQ&pzRL>0AAvnp|HW$|_= zn$5_35%w6ehf>JgNDShBRKQ%{2NFwu5Y{WfN|In7@WyDIry@`Dnj}}hog~u(#&jS< z+$tE#mUHF8Y;ug>&P^O0>POjX2w9QvtP`RYy**5+7^5+tB7}0ne6ZlX6Oijrb6M(c;mogI$0n+Eb3uC2(r~AQ4!PQ&ftcX4T?OJv-kx0a!bRN z1&|)!*LLSZsI40VS52rSgyEscAI*oWbvJO;@Z3{T-#+GN2|`Pqj@Tp=%|#jQ0>he^%3{EdqwYw4AUM`PFnQ@S`g|bebB17MKW&Uo{J&#=9R;q#Bnn{$+D@S*3 z0dWhs6){UOBEWUhI(8XN>svyWcbR*A%^Ewv<_UN`V3vLS{`qs5FR0t-;Y8;<>legwre-}%g z&O{+Wxt81`v5@2~Q^{N@@pV?%v>n4KT&7gajuvd8E@rUt*bdg;I2wmp*W`G8wLR^d z9!w1qj!K{w_J)>#95#Tkke$m*rYRjK6BWqEbGRTSMHZ)kKaSd&X8e{T8L~ATPOe z5_5(JcWGTs03ZA3JB#FSL!c+~65tr=K;hqvOV3RZ1#}4c`vcyIy;REk=T!PlLk}VG z=DVY@k9}Be5d=RSrC0CXAFOwnW9dRi?ocooFw_I6IzWHfHbWR;EMPQ_b*Ty{(rJp) zsg3Zhs7tTdLk>rxoTbGakGT)xtzfsL&N@ooW^q-;x%F#RH_jyh*A`(Y{U}xb3X=}9 zMY>PD+#|QG_{#jcZcOG{rLpt-udJ6ZU-nVcp%oXle?sBtRi?z}2e-H+a+>i{sBB;Q%sd{19Te$-QqzpD^zBi;0xzRc$4M90AM*$wKgQf*cw#Rm z_flKJ+@R&z#KkBaB!-;$<4^q_ki?W=sya%*zoWFYee1l`6%u91dgE-7Z9G$Yf-}br zyLFRMyxcagcF;Ma#w*IO<$l8~8haBTg3&H*XDU0{ER#;Y@>R1J(yqXrgnP$?HHf@1 z&d zEITep!coApR3=FAaP{t{mh}D)b^{)KN}QqDO0AiGoLyS4*yYlF`%kbImgM@DY&4cu z*i+3~q91e4YbX6yF=?Zw{M*r`{-#Z>eJ)wB?pdCd14%!xSFob684~&625bPvyX05t z;y|OzKf>(B`3jgFrB&4LGTkMg1DefgCg`QZjB#~E3}ZNYe>Ye2s%JA)IsDzP?8PlY z^GPaS$473s?O4bg@m6Q~Y-r0iT!M6JF#=LyCq9yotVu^Y&9`p(Zzk%b)TdVHvsP!#b-S7fHbbEX# zb0Al1#R*eso2Ql7gcT-~E>_TIi`BTVY!sj+^W6~$?Iqnk~Kp0 zkh_c-RKZEAQI7b2%q$PCTHe4d+=h@$vKBm0kp}?dRNB!HeJPhXe(pDT1{Te#eTcK zrNB=#ag3(Pmj%Hz)ImhzfRDWcn4y1|a51&G3gpH9X@rZ4;C`C)NAzpLLr7f-79B&? z>jH@JYeYnhY5I16wFLmNHfvJj#9JrN{*4rdO6;uuW4zQfd47tYvYd&F&Pm$0rVTMO zVqfPk-|J!NBGR0{o`u8%5=aZyNgkbdhn*lDQ!@-v@iyxs27GbaQ$v3L$ks7|nH z0&OnS6#)QTx@x47j70(p|YYSdY zae7hH*PU(jfSCp*{!E`4b6xc@qI?9%dQgfW70MwAlL{~%$kmTE)-d_|I7>c1fJc;V zx&MO~nP){T=(tVH`w_fMV><(qZX9jj(`-VZUKbaiIK`J2d=29v)El-OrnT2|nCAnB zsRgh(f60~venOds04aNPIs}kT?6W|zoxi9)Hhj;vNBmp+;r#I9QByY_0#GqRqfVafG(~ew%^(hgxPM)76JegoWE+e0UxhcUI+gQ; zAvH|b1sY5&(#$o<(*)stU$=vQPriv`bsNp8Fc{?M_vYxxA5k}tJoFh3x?<}x@EpKx z=>Q1&wj8W7;E$ZC$?prWXJ`cz_!ND4nQV z0AK%M{VyU)+tcs=u5|+T#^XydKgEQ!n||C$#kZmb8ysAyi!t1~ouZqRuN@z1ZDeVw zz+uDQiM6qIZBIE_!~(g1-M~;{s-Pt+Vv2*n*egQALEqCsCs;8NXT&lJ2s&c4IY!!! zEJ4)Bg$A4uaeW^7V1$0s{bzOjg0i|`TeGlj8dRfw3-`wB1?7H`2LO~_#MfiY^dQS0 zp&Bx>#q`OZ2tS6QR?y)j*I`jzQX#)s7rS;2{0U4tCF&= zlt?@bHG?r&Pu10J)MXjsBgPi0_NmIZ)3eN~0&J`YJJqKh%mpRVAmODg`4<5!x7Id&o zBi=Djub!N;Otc@cj!Rq1Gv6dSf~3fdJu~o_+2<`;>dyJ?ED1#~(gC zajhgXbB#IbJKn)w=qOKW)A{YZGe`z?lRx{(z2%>ln*xI zTnN9{DSUIkYR}zbFZxVtikGwF`&P$^=}%zml5o%wVpCU*a8G6mtU*E4lWprOS~zR^ z6%irqVo}XJ|G{|3eDk<+C59$JSv?+W8Ci7Wy9_`O6-llR$W+KtlqxYY@OE zrPY$zTpRRAZxNyAFS~p(AU`UaDxZIrT6nvB)==Hz!VN0jK31!{##0Km^`Sr_Lk^(X zla4C`CA?X7{jvDBeeZ4ARo(4ahMg2qhIU5Fb$c!+3p+OMkXmjE)0H$k*NfJNG0LvmMDrCg;$6RYusBsSV)paH2C7`<(1<$KP>mN2iwks z49@U`S>D8)pFIz26_!$GbgWE$maAYaU}J7jREMWoemnAzL-hw9MF)PeU1Dw!nXp|O z!h(v{Dm01YdJldM$z z4CmMlu$_<h?bqqL+-+D%7k?W*?cjzLr!e4TfhIqE`RBF zFSmPzEF1u-YI{ zM*>4G;F`}2>|bM<_3@L;8d$unY*M9GFAFV}MqQXyt0Qt|cZ^OuWGqDvrmL#St*W-E zoIlwLP&JzBHTLA&%i(tBu=lbS^?sdu=lDH|v;751mlc$k)TKmjA(s?rLTu?J?xf|# zxt6GuSiP=(5>8s}ui_L-b5Bop0pxw!TR-p>?SKsBC3KEcG8yMbP*P z*mB3E0bFZ?1S~1!(K>VE^k$dW!Sv3Tv7Zll5FPI$o{ z+9`p=O1|Q#1+`dE7?@qd8fKUaDiSBTemZjs7&mQ? z{ZWHFLaCjYyO&D6k_~UZ9rjsXSrF&;zL@Q*{RQtUro)|J(2U7&yi75_@rh}W{7XuK zKYi|ghfXNUyLmIsYR9i9bV%#OYsuD9z0ePycwt~28Ev3?(k~=XNG`nn2zjH;RIVp6 zNp_NeRgLIXI}>KwwtIK83RMhJ@A6|qQ-zIKVYeRrm`6*+U$+)lUN@9lp+J#(LqKgN zMwbHB?_(BNMCZ6(xN$c(HMHon0^gZJCDZJw)1Pz0K@zQqNdYS&k9B5_n4N_7=^4Ex z?Rnq8^Sr!vmE0C7;bi|)SsWQU_o3PF$N-hXToW+nM$=H6!pd|-jl4cR0sA7gs}FGc zy0Q6eWznY`s0*be*STPvwMd>`-gB$}@`Z1W!f}cHk zW~`W@$*oe8q35{|*?~=#(I;Nv8dkWAy+}0dRE%}Jy3mlnaE~pwY4aki&-*%ixSsN< z3woW|sloY1r!kSyb;OUp{R|99OrqgTlyZKIWiX9k4|gtSQDF^hI^<*x*!;xKnyu@e zw>T_PwhB_RLnLhKdML|!_HuYIiUzVqXJWGXNQW+zy?q`YGy#^Xyiiu}A#`mHChm9( zm&5U8wOy{f$LNt=Nk`BOuAF-))S8dTRL=c|twpyI<}%nmwQcGALy=j}SKiK-u~aOx zVo@yI9%2E^vM>1Q3Xnc&3Ni0uMlagiUEzG}?g8|F5}gZ5oLSTk(3r#uezyua-#5vF z%5Hh^-SiVT%-g9t;gokei!#H~(`@9~lk%LVw82{KF)jFdRq$PZ@VhV?jpwKFFV~FB zchw#=5?WvTu}+!q*+U7}8cyd%bs&~kdjM<=y|bZ`AqV&Y?U1q1_2e&nhfnW%f0qZy z-%7%@fS;Z}%m55Jyw-q0hXTwgo5CMzz?EPD*nO$@Etr?PuXB%xKHk;d%TCCb{%G%oP9HLe+p5@5PO zmPOKj=ZJwC04eicR3nu+L74$Gki>g?o!Cbm4zC^7m~(bAO+shYq6zEtyG6frAcDy4 zH_&D9D)-I({ypebt(j`1XD>$FnBtwAq|o&lVehYMdR@BV*03SVS2ttml%|E{wpiUV zF+cLN%m(Am(OS(I&eVqN8P^ey?1peIPx`DPgPs-v1_fkTQEF<|)23LZ4SFkT6GDvQ z1MnXE7h6c(PFm`{oLhFBlBgsO`|MT+w>r4@GRnHJ&C#;;p7lMptFr3al5SVn^(`cU zA+hciUu2(`G-k6fN)i~hNbbCy%xX5&E*OoYru_9xb2avOTXqq-V_ zO7p>nMlnN}z>?fRVIb_WA0D74rTRX+h1zhV)7DoJ5*`&M(jkR=)+9w?4igug^y3zn zhAUWE+eT#Za%2;ZVCy}9Eg1a?JHbE7M=<>FjpF}UF#oYv|5h>()UA}whD$H_Yg~IZ zxPrX$P@0?1l^uz74-~EEz$1*aD=7}MWzbO*y%6#PXgd8s-)ooR2m+W$_CxRzoy_=A#4Z4POgsFR zrlW{k@1`D3*z=`!JDDvaX$$A35YA1|S=AJH^!EPgmPMIQK*dBB8H#I}%D{XbPLy8* z^hMn& zTgoG(Ne#}S74p!nZZ~p}NbmQCxiQ^zMw-vAP2k|!Klad-C1JK{X|_ip<>iAU>-?v8 z)mgGaGdF+Q3oz2r%l|}~SA)e#0=pC`#mJ`TLZ;5`NvX6f8KV(~9k|TJa=s~0FZ0T- zp)dGWWuQvUQn1?Gjl*^Lo*#%^P42I_>iE%+D@w#AZo~ zgja!MSK=LTE@(!~Q-t!V<<0kYRC2P~Gv0obvYM0^e429I3SpJ|AIb4Mz+!*4is+1^ z#q`m?Qsy}6UYx*v;@b&MUTJ{6G?4zq!u(T(Zy=DUO4{c2RbPt2mW?}>Fhw1auFH32 z7*muml%GMZBijgB!OIf6!OUrlnSrsU-J(3Hc+#}gxnEK-+6|nXVVkRZpQZU+~n?kcSV^M#fk)(U<7u|1YpPmLXIGGSB@a5K3JUheA*ii@qi~mS*K$u z_JE?*o&MFP{TF;({kZfy-LRU?w<4C+WOmF^UkV-SmF>w(=2b`)X`af{t~5A#l(Z*7 z`h3)`=?}&bQR(Z6p~|DuX^Uxa@Di`}s2=f=8~Cz*+J^!0^Qn^N`QB#so#K~8F?MH) zSFGC{3f*Yh)>HjPQiW78x@Q&<_Q<4QaKM61EGSs10|hilPP#W@98 zh8)-TCKReQbqX_XVAd0h?DcT)2)>y{ES2bX0J*eogb@GB;(7BePd+rM|tv5Ep=+9oImEs- zoe*&|Y~%!S9da8?j1NbYG^7vOX||m!-9?fGFPMB7m0U}fa2foD{L-IdQBPTnLc*hx z=EPgFjmnwOwg-AT*}4|7zA<`oWlFV)uMf>KKdo;yN$iiD1<@mewG=KWyT-93T^%c` z$}D0_lA&RkX!1hb!aM(7Z*l{(HjRi`S$lU1KW8CZl6N?K>Zj+)@xXEzZ?LUE3;npH zXVOIm4j(Ly7no}%_nE2-rvBTo*DdMlSZM ztwU*qHb4g24-FXMt0+uYHaqfo>){W}x{aE@^ikniJL%qv8(27Rbh5W|31VKS*oCfN z+WdfJEePf0uzeo)rKNWmgyJih0OM8%DHZs{yQRBa>;p9+#r4;guj_`e+mt0NOjut) zb<|1)?NR&U(UjSF1sCLO?2WXhCYymldo-1~{T&VI3dpQL=($hv1$hePQF%~FYRymO zY_E(Ee%i*=bd***UsiplWmSLWPH5dHiv(9?>dG4**t%Z?0uXEJ%6(Egij8yIsu-zG9M9#k~PtXU!;CeUPdgE-6i{xsHOG1RG^pg?)jK@(TE)h z?6t7+kexPSsLO@Iavcv=a!ER4hL1ve(tFH+#L}JXN zC4kAy;*f$MD02k434HsVKlKjsbS!oim^qL^=kl{t;@d`aWT>6=o-5Vf5UKtF8FB-* z=o`T6{1aXFf7qxW!M+arZ0o3V=9hq%aIT(RGoMa>$!=PtRM?y$?_F%ZrJ6`FQJ>pP zoaLb1y&I0}*f7o_?nXreZEb2A8p_a>`COTYTCwo@JA0qaV9r)?B%KLEGe)``v$S@q zxT|B_#UVCnf)1o;3cU(DzZZhqs=S)5%;)d0x9HR9(!!T@ZYwm?#(9CcQ)m6{-8D8pi34zL$v@o}&>@Br)Bp96_gTvhVThj$-+x^WA!_F&)`!t;YQLpnhSxAi8#m$H>a- z{(Z^%W?jMw3CnSKTMWE(V@5psY#YCRtX?anN|zh}w%<@BSpl_G@*-EG1JQFdVO@vQuv4!KBK%Q1^Zq-!~Cn)?X!DyEqz2OTJI6e z&SV;Keo?Wg=%AOy-`)h6vn#ahC2CpAD}taXJi>G~MdAde?j&kANoULU5)A(|ULvr1 zjFBk7qNw-PkQHUa#Y**?(|t_Hlj;m%4a$?2*1$w;*_q`mdYBbAz_a*@d6TDuQ{a07vH{r$j^bL>?!%E2@W|Wt9jv#>@x;_j-M-ZNI zXouoK_Pp(P5YTJA8z5|aLo7*;H3G`xe`_`KH%t4oaQ$yx`?tnHKf=ejlmf09pQ>|7 zq-}G9lgkdzDFn~*Sac(vZGZ?Rp0Xf`!EI`vnr+{#1>9WoLzn%!aAVj6ms&|IrWs@eBUZF7e-|UiILu z`mYkyWfamX}5_0AWLD?g}D^jKtf-Qf-0leEj<^b33UbV~+H zf|H5~>27rc$$|ko?>O8diX$4hw5s1w1&w2b-R(>Qa?Ted4|8$0Yv{|xUI9Ob5vrC> zhRbzR7$WqZ7qCiWt^ z0$fC{pDy<)w=R@L@2`s7Xmzft?~pRf3!qx+xM4{^38anH^K}ox-GlP>`0_qzUeVRk zE@iuJ*~9qryRF#HWcQ}4a-l0%(pl+KobS6T10YvGFrETgFYU2a{K2}AneAXe!qd7) z%Bq>1SZh=u?Xt)s=Y;d4w}OgqbWdSTdA_Cdf^E7`R!d-z&fMxy^p~-9iWxl!P1xWq z8J?pJxHRk>yFJdcy~8#3M!?`(!>tHO@tUwBAHeA%1YPckN zMx5)&OTUOo1SO9UFBh17>8iF93e>htp*q$7-r2n%zd5mfBZUi_Dpsy?HZ>15CXe2N zM0b)9&^nI7cwQWv(I`XvD0it*31=P|YMCIK4y$+ut+ zpQies7{L`3Gob_m(AM5%=ABZ?SU!!~`H|HAcsu&la||(?E}Dgcy)gsE!9Fy4kBhD) zzC+qPFFYkN5d{+Bilzt(C*6}R<)op@;a5lPQs8UPwgH!bXAg$Lpt8ZTou7dv|HHR9 zajg+u?S+JnJXDlAE-aKx?yA{s!}Bh{6fTc!KagH@F{BtrW_KutZ0}@y6WMF{OW1}< z1Q(VRwFwDok6P~qR`q;*UaoR?9j`?G{Y<4&yWhMv7I(Sf*OcxL4fF5HI{#jM=vbfc zPBsmIKCv@JD)2n1JRxZjkSY?I^Pcd@xmx;%#yk1Iz?(0eLuGONE&+dH_blr^gwa8hz7F#l+IJmX72`f<TTULI+K_#5^hTQ$!0*FE?|-?ZZ43$(Nle z(kt2giHKx!TZ`7a4@Oz_c6IfJTd8q+fq~w`4{a4~NWgh#tEF5LqF!oLsMpuEGfTG3 z(DuKFJCU;G$z;<8uZ(;{dC{$lw!yKqjU%hAXx)jvg5)e~L7M}oO<*{MQiJ8{Pmv`c z5qygWes(3Fc-Td4PnJHb>%$wUW(pN5`Ra1Z0;vmWPFrP$j;#~Rz4q*u>#+>dL1)lq z;R7nx+_6eL7aman9jCy&>+iX|>1@@T5RkcUa;}Unnq3?3WAZx0wnjiBL(5~4taULz zzk8$fzM5Doabng2s$Hjy?u&b_Tw(Ynkh-oyNh53fQt?#FCs{w!Ive)T?PMCgWmzP3 zq{wUAFfriM)t;B2Pd$Hcu_QmM7^QkseZDp)#&b$(3gFrjFy<{)LO64DLx#k_s99zg zvNl>d#6A`I7PoSu(C-{=vs-N{H%~~el$%sGK6Gv(fan{VsQa@epe z*~lt@@yJigIzLx0igmu%>#;uQO(Axe8;=KdiW_C0`I;PNu|6aBHs$q^PwEv@p=T9m!K>z;n zUj2<%$1J{ogT?olLiX<_NZyc$=|3n@izQ1w!{$Hlh{)Hyd^UrNgg~9uL z)qEvSI9b=FZtfkrbwj_?ST^oXf+U;pM*kt>wOEij1@(-`;`ffz;|w`~Q&=Cchecu< zx6Gxcb8-zD6DPpD%h6TgwUsC^2>oR-8F+~`-$NtUhK9MOdz=w-4&Ui_a2+5k`yLhy zNZUR64#o$(mX>MO=BuC^uYJjU@pHfl=WIo6)Fu%e7vFAsgzap8%Gmu_A6);(E83dG zOUV1~-5)r(Z`Nu?sGeuuCwV!2;G74F$$Q_xYU>Z)ED}V}mS}{Dd-UN`Ll=T50BrX8 z?F2-{m=TOYYVfkb%kjoCaYaH)2>`WUMj;j&d>a*&(1_z-`9Jt9<-Nwq9lLQ%VTb0r zBMT~LvFyuUT2}+lIC6ZL{KPR{R8&;M8tVj^(FoWi3)+n?H($#S@lTvzEAZKz)ygDl zm83Xu6Xse6({75Xwn4P^q!Qo@R(a%moEHx&LDM`X^o08NdVuCL0~dYxexUihT2rG| z{)&fQlc66ecRti_3-n?p&xs#Uca*DfmH;)NOS1Zg$~ zLwghJM3u8SDX=JwT#@U7PTm*#E|R<4BMt%sjSJE{tK90F2U=nk!^ZDMuC|6- zAk+CDyz#$OR{s3eKQc?hU@waK2*NRV1R2sJAkV!fd9;*dsj zdGR&Lj(bCp8NoUP@U(b9w_(r%B!+A9`1AhT_HV4QMj=0gz!Z(4QA8pY_qvvLmUnmu z@UM~iXx~o_X;DVdb=<(l(2w32Bd_GlBS?8das+}8IETNIDr&imPCegVL`zBZPO@Rg zjH1Oow#0I&Kg99CG+~;II=ZlS)AIoGLR$RBP`iGdu|A1G)z@aURle#}?pJEhw{P2h z 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 literal 0 HcmV?d00001 diff --git a/static/images/后台编辑器061.jpg b/static/images/后台编辑器061.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cdb7628bc6fdbce1f6c7d1282248af7e2bf262db GIT binary patch literal 346886 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

Mh!xpQCcb5ydKG2Rr-6N?&AvCj@4X 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࿫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 z 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

obz9V*96GvEXV9Nw?=pcR{;Z_qU~Tg4w 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�TXvSalh}SRLT~sW1 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 literal 0 HcmV?d00001 diff --git a/static/images/后台编辑器071.jpg b/static/images/后台编辑器071.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fd0033e34669aedc0f0d23cdb5c275d1ee4f77b7 GIT binary patch literal 23553 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 NxX|b-Zi*iM{{X5C`Zxdp literal 0 HcmV?d00001 diff --git a/static/images/后台编辑器073.jpg b/static/images/后台编辑器073.jpg new file mode 100644 index 0000000000000000000000000000000000000000..53f21517a265110109779ff0eaa4144278030c69 GIT binary patch literal 25529 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 H58wSCFC%z) literal 0 HcmV?d00001 diff --git a/static/images/后台编辑器075.jpg b/static/images/后台编辑器075.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b8a50e5f3f7060a7bb00daf6d47de4b21d8043e3 GIT binary patch literal 24113 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 { + let moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1') + modulesTemp[moduleName] = modulesFiles(modulePath).default; +}); +// #endif + +// #ifdef VUE3 +const modulesFiles = import.meta.globEager('./modules/**/*.js'); +for (const modulePath in modulesFiles) { + const moduleName = modulePath.replace(/^\.\/modules\/(.*)\.\w+$/, '$1') + modulesTemp[moduleName] = modulesFiles[modulePath].default; +} +// #endif +const modules = {}; +for (let moduleName in modulesTemp) { + const moduleItem = modulesTemp[moduleName]; + if (moduleItem && moduleItem.namespaced) { + let moduleNameArr = moduleName.split("/"); + let lastName = moduleNameArr[moduleNameArr.length - 1]; + if (lastName === "index") { + moduleName = moduleName.replace(/\/index$/, ''); + } + modules[moduleName] = moduleItem; + } +} + +for (let moduleName in modules) { + if (notSaveStateKeys.indexOf(moduleName) === -1) { + if (!lifeData[moduleName]) lifeData[moduleName] = {}; + } +} + +uni.setStorageSync('lifeData', lifeData); + +// 保存变量到本地存储中 +const saveLifeData = function(key, value) { + // 判断变量名是否在需要存储的数组中 + if (notSaveStateKeys.indexOf(key) === -1) { + // 获取本地存储的lifeData对象,将变量添加到对象中 + let tmp = uni.getStorageSync('lifeData'); + // 第一次打开APP,不存在lifeData变量,故放一个{}空对象 + tmp = tmp ? tmp : {}; + tmp[key] = value; + // 执行这一步后,所有需要存储的变量,都挂载在本地的lifeData对象中 + uni.setStorageSync('lifeData', tmp); + } +} + +// #ifndef VUE3 +import Vue from 'vue' +import Vuex from 'vuex' + +Vue.use(Vuex) + +const store = new Vuex.Store({ + modules, + // 如果是开发环境,则开启严格模式 + strict: process.env.NODE_ENV === 'development', + // 公共 mutations + mutations: { + updateStore(state, payload) { + // 判断是否多层级调用,state中为对象存在的情况,诸如user.info.score = 1 + if (typeof payload.value === "undefined") payload.value = ""; + let nameArr = payload.name.split('.'); + let saveKey = ''; + let len = nameArr.length; + if (len >= 2) { + let obj = state[nameArr[0]]; + for (let i = 1; i < len - 1; i++) { + let keyName = nameArr[i]; + if (typeof obj[keyName] !== "object") obj[keyName] = {}; + obj = obj[keyName]; + } + obj[nameArr[len - 1]] = JSON.parse(JSON.stringify(payload.value)); + saveKey = nameArr[0]; + } else { + // 单层级变量,在state就是一个普通变量的情况 + state[payload.name] = JSON.parse(JSON.stringify(payload.value)); + saveKey = payload.name; + } + // 保存变量到本地,见顶部函数定义 + saveLifeData(saveKey, state[saveKey]) + } + } +}) +// #endif + +// #ifdef VUE3 +import { createStore } from 'vuex' +const store = createStore({ + modules, + // 如果是开发环境,则开启严格模式 + strict: process.env.NODE_ENV === 'development', + // 公共 mutations + mutations: { + updateStore(state, payload) { + // 判断是否多层级调用,state中为对象存在的情况,诸如user.info.score = 1 + if (typeof payload.value === "undefined") payload.value = ""; + let nameArr = payload.name.split('.'); + let saveKey = ''; + let len = nameArr.length; + if (len >= 2) { + let obj = state[nameArr[0]]; + for (let i = 1; i < len - 1; i++) { + let keyName = nameArr[i]; + if (typeof obj[keyName] !== "object") obj[keyName] = {}; + obj = obj[keyName]; + } + obj[nameArr[len - 1]] = JSON.parse(JSON.stringify(payload.value)); + saveKey = nameArr[0]; + } else { + // 单层级变量,在state就是一个普通变量的情况 + state[payload.name] = JSON.parse(JSON.stringify(payload.value)); + saveKey = payload.name; + } + // 保存变量到本地,见顶部函数定义 + saveLifeData(saveKey, state[saveKey]) + } + } +}) +// #endif + +export default store \ No newline at end of file diff --git a/store/modules/$app.js b/store/modules/$app.js new file mode 100644 index 0000000..fe98b6d --- /dev/null +++ b/store/modules/$app.js @@ -0,0 +1,60 @@ +/** + * vuex 系统状态管理模块 + */ +import config from '@/app.config.js' + +let lifeData = uni.getStorageSync('lifeData') || {}; + +let $app = lifeData.$app || {}; + +export default { + // 通过添加 namespaced: true 的方式使其成为带命名空间的模块 + namespaced: true, + /** + * vuex的基本数据,用来存储变量 + */ + state: { + /** + * 是否已经初始化 + * js调用示例 + * vk.getVuex('$app.inited'); + * 页面上直接使用示例 + * {{ vk.getVuex('$app.inited') }} + * js更新示例 + * vk.setVuex('$app.inited', true); + */ + inited: $app.inited || false, + config:{ + ...config + }, + // 动态主题色 vk.getVuex('$app.color.main') vk.setVuex('$app.color.main','#ff4444') + color: $app.color || config.color, + /** + * vk.getVuex('$app.originalPage'); + * vk.setVuex('$app.originalPage', originalPage); + */ + originalPage: $app.originalPage || null, // 跳登录前的页面 + }, + /** + * 从基本数据(state)派生的数据,相当于state的计算属性 + */ + getters: { + + }, + /** + * 提交更新数据的方法,必须是同步的(如果需要异步使用action)。 + * 每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。 + * 回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数,提交载荷作为第二个参数。 + */ + mutations: { + + }, + /** + * 和mutation的功能大致相同,不同之处在于 ==》 + * 1. Action 提交的是 mutation,而不是直接变更状态。 + * 2. Action 可以包含任意异步操作。 + */ + actions: { + + } +} diff --git a/store/modules/$user.js b/store/modules/$user.js new file mode 100644 index 0000000..10b58fc --- /dev/null +++ b/store/modules/$user.js @@ -0,0 +1,50 @@ +/** + * vuex 用户状态管理模块 + */ +let lifeData = uni.getStorageSync('lifeData') || {}; + +let $user = lifeData.$user || {}; + +export default { + // 通过添加 namespaced: true 的方式使其成为带命名空间的模块 + namespaced: true, + /** + * vuex的基本数据,用来存储变量 + */ + state: { + /** + * 登录用户信息 + * js调用示例 + * (推荐) vk.getVuex('$user.userInfo'); + * 或 vk.vuex.get('$user.userInfo'); + * 页面上直接使用示例 + * {{ vk.getVuex('$user.userInfo') }} + * js更新示例 + * vk.setVuex('$user.userInfo.avatar', avatar); + */ + userInfo: $user.userInfo || {}, + permission:$user.permission || [], + }, + /** + * 从基本数据(state)派生的数据,相当于state的计算属性 + */ + getters: { + + }, + /** + * 提交更新数据的方法,必须是同步的(如果需要异步使用action)。 + * 每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。 + * 回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数,提交载荷作为第二个参数。 + */ + mutations: { + + }, + /** + * 和mutation的功能大致相同,不同之处在于 ==》 + * 1. Action 提交的是 mutation,而不是直接变更状态。 + * 2. Action 可以包含任意异步操作。 + */ + actions: { + + } +} \ No newline at end of file diff --git a/template.h5.html b/template.h5.html new file mode 100644 index 0000000..0899e7a --- /dev/null +++ b/template.h5.html @@ -0,0 +1,32 @@ + + + + + + + + <%= htmlWebpackPlugin.options.title %> + + + + + + + + + + +

+ + + diff --git a/uni.scss b/uni.scss new file mode 100644 index 0000000..f09e0f5 --- /dev/null +++ b/uni.scss @@ -0,0 +1,2 @@ +@import "@/common/css/uni.scss"; +// @import "@/uni_modules/vk-uview-ui/theme.scss"; diff --git a/uniCloud-aliyun/cloudfunctions/fadada_verify_notify/index.js b/uniCloud-aliyun/cloudfunctions/fadada_verify_notify/index.js new file mode 100644 index 0000000..9124ff1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/fadada_verify_notify/index.js @@ -0,0 +1,23 @@ +'use strict'; +const querystring = require('querystring'); +exports.main = async (event, context) => { + //event为客户端上传的参数 + console.log('event : ', event) + const { + body + } = event + + let obj = querystring.parse(body); + // 验证签名 + // Base64(SHA1(app_id +MD5(timestamp)+SHA1(app_secret+authenticationType+certStatus+customerId+serialNo+status+statusDesc))) + + let callFunctionRes = await uniCloud.callFunction({ + name: "router", + data: { + $url: "client/fadada.pub_verifyNotify", + data: obj + } + }); + + return callFunctionRes +}; \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/fadada_verify_notify/package.json b/uniCloud-aliyun/cloudfunctions/fadada_verify_notify/package.json new file mode 100644 index 0000000..0a2c8a5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/fadada_verify_notify/package.json @@ -0,0 +1,7 @@ +{ + "name": "fadada_verify_notify", + "dependencies": {}, + "extensions": { + "uni-cloud-jql": {} + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/config.js b/uniCloud-aliyun/cloudfunctions/router/config.js new file mode 100644 index 0000000..695c324 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/config.js @@ -0,0 +1,12 @@ +const requireFn = function(path) { + return require(path); +} +const initConfig = { + baseDir: __dirname, // 云函数根目录地址 + requireFn, + customUtil :{ + // 你自己的工具包,写这里后即可听过customUtil.mynpm1调用 + // mynpm1:mynpm1 + } +}; +module.exports = initConfig; \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/dao/config.js b/uniCloud-aliyun/cloudfunctions/router/dao/config.js new file mode 100644 index 0000000..81ed98d --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/dao/config.js @@ -0,0 +1,7 @@ +'use strict'; +// 涉及的表名 +const dbName = { + productCategory: "jjx-product-category", //商品-分类表 + product: "jjx-product", //商品-现货表 +}; +module.exports = dbName; \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/dao/index.js b/uniCloud-aliyun/cloudfunctions/router/dao/index.js new file mode 100644 index 0000000..3e675db --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/dao/index.js @@ -0,0 +1,29 @@ +// 加载模块 - 数据库dao层 API 请勿改动此文件----------------------------------- +const modulesPath = __dirname + "/modules"; +const fs = require('fs'); +const fileList = fs.readdirSync(modulesPath); +const moduleObj = {}; +const modulesNames = []; +fileList.map((file, index) => { + if (file.indexOf("Dao.js") > -1) { + modulesNames.push(file.substring(0, file.length - 3)); + } +}); +modulesNames.map((modulesName, index) => { + try { + moduleObj[modulesName] = require(modulesPath + "/" + modulesName); + } catch (err) { + console.error(`【异常】加载【${modulesName}】异常,请检查!↓↓↓请查看下方的错误提示↓↓↓`); + console.error(err); + console.error(`【异常】加载【${modulesName}】异常,请检查!↑↑↑请查看上方的错误提示↑↑↑`); + } +}); +moduleObj.init = function(obj) { + modulesNames.map((modulesName, index) => { + if (typeof moduleObj[modulesName] === "object" && typeof moduleObj[modulesName].init === "function") { + moduleObj[modulesName].init(obj); + } + }); +} +module.exports = moduleObj; +// 加载模块 - 数据库dao层 API 请勿改动此文件----------------------------------- diff --git a/uniCloud-aliyun/cloudfunctions/router/dao/modules/userDao.js b/uniCloud-aliyun/cloudfunctions/router/dao/modules/userDao.js new file mode 100644 index 0000000..5418321 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/dao/modules/userDao.js @@ -0,0 +1,621 @@ +// 涉及的表名 +const dbName = { + user: "uni-id-users", // 用户 +}; + +var dao = {}; +var util = {}; +// 初始化 +dao.init = function(obj) { + util = obj; +} +/** + * 获取用户信息 + * 调用示例 + * await vk.daoCenter.userDao.findById(user_id); + * data 请求参数说明 + * @param {String} user_id 用户ID + */ +dao.findById = async (user_id) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.findById({ + dbName: dbName.user, + id: user_id, + fieldJson: { token: false, password: false }, + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 查 - 根据whereJson获取单条记录 + * @param {Object} whereJson 条件 + * @param {Object} fieldJson 字段显示规则 + * 调用示例 +let userInfo = await vk.daoCenter.userDao.findByWhereJson({ + +}); + */ +dao.findByWhereJson = async (whereJson, fieldJson={ token: false, password: false }) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.findByWhereJson({ + dbName: dbName.user, + whereJson, + fieldJson + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 根据邀请码获取用户信息 + * let inviterUserInfo = await vk.daoCenter.userDao.findByInviteCode(invite_code); + * @param {String} invite_code 邀请码 + */ +dao.findByInviteCode = async (invite_code) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.findByWhereJson({ + dbName: dbName.user, + whereJson: { + my_invite_code: invite_code + }, + fieldJson: { token: false, password: false } + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + + +/** + * 增 - 添加一条记录 + * @param {Object} dataJson 添加的数据 + * 调用示例 +await vk.daoCenter.userDao.add({ + +}); +或 + * 调用示例 +await vk.daoCenter.userDao.add({ + db: transaction, + dataJson: { + + } +}); + */ +dao.add = async (obj) => { + let { vk, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + if (obj.db && obj.dataJson) { + // 支持事务 + res = await vk.baseDao.add({ + ...obj, + cancelAddTime: true, // 因为user表使用了register_date作为创建时间 + dbName: dbName.user, + }); + } else { + // 不支持事务 + res = await vk.baseDao.add({ + dbName: dbName.user, + cancelAddTime: true, // 因为user表使用了register_date作为创建时间 + dataJson: obj + }); + } + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 增 - 添加多条记录 + * @param {Object} dataJson 添加的数据 + * 调用示例 +await vk.daoCenter.userDao.adds(dataArr); + */ +dao.adds = async (dataArr) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.adds({ + dbName: dbName.user, + cancelAddTime: true, // 因为user表使用了register_date作为创建时间 + dataJson: dataArr + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + + +/** + * 删 - 删除多条记录 + * @param {Object} whereJson 条件 + * 调用示例 +await vk.daoCenter.userDao.del({ + +}); + */ +dao.del = async (whereJson) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.del({ + dbName: dbName.user, + whereJson + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 删 - 据ID删除单条数据 + * @param {String} _id + * 调用示例 +await vk.daoCenter.userDao.deleteById(_id); +或 +await vk.daoCenter.userDao.deleteById(_id, transaction); + */ +dao.deleteById = async (_id, db) => { + let { vk, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.deleteById({ + db, + dbName: dbName.user, + id: _id + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + + +/** + * 改 - 批量修改 + * @param {Object} whereJson 条件 + * @param {Object} dataJson 修改的数据 + * 调用示例 +await vk.daoCenter.userDao.update({ + whereJson:{ + + }, + dataJson:{ + + } +}); + */ +dao.update = async (obj = {}) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.update({ + ...obj, + dbName: dbName.user + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + + +/** + * 改 - 根据id修改 + * @param {Object} whereJson 条件 + * @param {Object} dataJson 修改的数据 + * 调用示例 +await vk.daoCenter.userDao.updateById({ + id: uid, + dataJson:{ + + } +}); + */ +dao.updateById = async (obj = {}) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.updateById({ + ...obj, + dbName: dbName.user + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + + +/** + * 改 - 更新并返回更新后的数据(无论条件匹配到多少条记录,只会修改第一条记录,同时返回修改后的数据) + * @param {Object} whereJson 条件 + * @param {Object} dataJson 修改的数据 + * 调用示例 +await vk.daoCenter.userDao.updateAndReturn({ + whereJson:{ + + }, + dataJson:{ + + } +}); + */ +dao.updateAndReturn = async (obj = {}) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.updateAndReturn({ + ...obj, + dbName: dbName.user + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 查 - 获取记录总条数 + * @param {Object} whereJson 条件 + * 调用示例 +await vk.daoCenter.userDao.count(whereJson); + */ +dao.count = async (whereJson) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.count({ + dbName: dbName.user, + whereJson + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + + +/** + * 查 - 求和 + * @param {String} fieldName 需要求和的字段名 + * @param {Object} whereJson 筛选条件 + * 调用示例 +let userSum = await vk.daoCenter.userDao.sum({ + fieldName: "", + whereJson: { + + } +}); + */ +dao.sum = async (obj) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.sum({ + ...obj, + dbName: dbName.user, + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 查 - 求最大值 + * @param {String} fieldName 需要求最大值的字段名 + * @param {Object} whereJson 筛选条件 + * 调用示例 +let userMax = await vk.daoCenter.userDao.max({ + fieldName: "", + whereJson: { + + } +}); + */ +dao.max = async (obj) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.max({ + ...obj, + dbName: dbName.user, + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 查 - 求最小值 + * @param {String} fieldName 需要求最小值的字段名 + * @param {Object} whereJson 筛选条件 + * 调用示例 +let userMin = await vk.daoCenter.userDao.min({ + fieldName: "", + whereJson: { + + } +}); + */ +dao.min = async (obj) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.min({ + ...obj, + dbName: dbName.user, + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 查 - 求最平均值 + * @param {String} fieldName 需要求最平均值的字段名 + * @param {Object} whereJson 筛选条件 + * 调用示例 +let userAvg = await vk.daoCenter.userDao.avg({ + fieldName: "", + whereJson: { + + } +}); + */ +dao.avg = async (obj) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.avg({ + ...obj, + dbName: dbName.user, + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 查 - 获取数据列表 + * 调用示例 +let userList = await vk.daoCenter.userDao.select({ + pageIndex:1, + pageSize:20, + getMain:false, + whereJson:{ + + }, + fieldJson:{}, + sortArr:[{ "name":"_id", "type":"desc" }], +}); + */ +dao.select = async (obj = {}) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.select({ + ...obj, + dbName: dbName.user + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 查 - 获取数据列表 + * 调用示例 +let userList = await vk.daoCenter.userDao.selects({ + pageIndex:1, + pageSize:20, + getMain:false, + whereJson:{ + + }, + fieldJson:{}, + sortArr:[{ "name":"_id", "type":"desc" }], + // 副表列表 + foreignDB:[ + { + dbName:"副表表名", + localKey:"主表外键名", + foreignKey:"副表外键名", + as:"副表as字段", + limit:1 + } + ] +}); + */ +dao.selects = async (obj = {}) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.selects({ + ...obj, + dbName: dbName.user + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 查 - 获取数据列表 + * 调用示例 +res = await vk.daoCenter.userDao.getTableData({ + data +}); + */ +dao.getTableData = async (obj = {}) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.getTableData({ + ...obj, + dbName: dbName.user + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + + +/** + * 获取用户信息(旧版) + * _id + * username + * mobile + * email + * wx_openid.app-plus + * wx_openid.mp-weixin + * wx_unionid + * ali_openid + * my_invite_code + * 调用示例 + await vk.daoCenter.userDao.findByUserInfo({ + mobile:mobile + }); + * data 请求参数说明 + * @param {Object} userInfo 用户信息 + */ +dao.findByUserInfo = async (userInfo) => { + let { vk, db, _ } = util; + let res; + // 数据库操作开始----------------------------------------------------------- + let whereJson = {}; + let list = [ + "_id", + "username", + "mobile", + "email", + "wx_openid.app-plus", + "wx_openid.mp-weixin", + "wx_unionid", + "ali_openid", + "my_invite_code" + ]; + let orArr = []; + for (let i = 0; i < list.length; i++) { + let keyName = list[i]; + let orObj = {}; + if (vk.pubfn.isNotNull(userInfo[keyName])) orObj[keyName] = userInfo[keyName]; + if (vk.pubfn.isNotNull(orObj)) { + orArr.push(orObj); + } + } + if (orArr.length > 0) { + whereJson = _.or(orArr); + res = await vk.baseDao.findByWhereJson({ + dbName: dbName.user, + fieldJson: { token: false, password: false }, + whereJson: whereJson + }); + } + // 数据库操作结束----------------------------------------------------------- + return res; +}; +/** + * 根据ID数组获取用户列表 最多支持500个 + * 调用示例 + * await vk.daoCenter.userDao.listByIds(userIdArr); + * data 请求参数说明 + * @param {Array} userIdArr 用户ID数组 + */ +dao.listByIds = async (userIdArr) => { + let { vk, db, _ } = util; + let res = await vk.baseDao.select({ + dbName: dbName.user, + pageIndex: 1, + pageSize: 500, + getMain: true, + fieldJson: { token: false, password: false }, + whereJson: { + _id: _.in(userIdArr) + }, + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; +/** + * 根据手机号直接注册账号并登录 + * 若手机号已存在,则直接登录 + * @param {Object} data 参数 + * mobile 手机号 必填 + * password 初始密码 + * inviteCode 邀请人的邀请码 + * myInviteCode 设置当前注册用户自己的邀请码 + * needPermission 设置为true时会在checkToken时返回用户权限(permission),建议在管理控制台中使用 + * 调用示例 + await vk.daoCenter.userDao.registerUserByMobile({ + mobile, + }); + */ +dao.registerUserByMobile = async (data) => { + let { vk, db, _, uniID } = util; + let res = {}; + let { + mobile, + password, + inviteCode, + myInviteCode, + needPermission + } = data; + // 数据库操作开始----------------------------------------------------------- + let code = vk.pubfn.random(6); + // 设置验证码 + await uniID.setVerifyCode({ + mobile, + code, + expiresIn: 60, + type: "login" + }); + // 若手机号不存在,则注册并登录。存在,则直接登录。 + res = await uniID.loginBySms({ + mobile, + code, + password, + inviteCode, + myInviteCode, + needPermission + }); + if (res.uid && vk.pubfn.isNull(res.userInfo)) { + res.userInfo = await vk.daoCenter.userDao.findById(res.uid); + } + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 重置用户密码 + * data 请求参数说明 + * @param {String} uid 用户ID + * @param {String} password 需要重置的密码 + * 调用示例 +await vk.daoCenter.userDao.resetPwd({ + uid: uid, + password: "123456" +}); + */ +dao.resetPwd = async (data) => { + let { vk, db, _, uniID } = util; + let res = {}; + let { + uid, + password + } = data; + // 数据库操作开始----------------------------------------------------------- + res = await uniID.resetPwd({ uid, password }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 获取一个未被使用的6位数分享码 + * 调用示例 +await vk.daoCenter.userDao.getValidInviteCode(); + */ +dao.getValidInviteCode = async (data) => { + let { vk, db, _ } = util; + // 数据库操作开始----------------------------------------------------------- + let inviteCode = await vk.pubfn.randomAsync(6, "23456789ABCDEFGHJKLMNPQRSTUVWXYZ", async (val)=>{ + let num = await vk.baseDao.count({ + dbName: dbName.user, + whereJson:{ + my_invite_code: val + } + }, 10); // 最大重试10次 + return num === 0 ? true : false; + }); + // 数据库操作结束----------------------------------------------------------- + return inviteCode; +}; + +module.exports = dao; diff --git a/uniCloud-aliyun/cloudfunctions/router/index.js b/uniCloud-aliyun/cloudfunctions/router/index.js new file mode 100644 index 0000000..fcc5154 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/index.js @@ -0,0 +1,7 @@ +'use strict'; +// 注意:此为云函数路由入口文件,请勿修改此文件代码,你自己的云函数逻辑应写在service目录下 +const vkCloud = require('vk-unicloud'); // 引入 vk-unicloud +const vk = vkCloud.createInstance(require('./config.js')); // 通过 vkCloud.createInstance 创建 vk 实例 +exports.main = async (event, context) => { + return await vk.router({ event, context, vk }); +}; diff --git a/uniCloud-aliyun/cloudfunctions/router/middleware/index.js b/uniCloud-aliyun/cloudfunctions/router/middleware/index.js new file mode 100644 index 0000000..39f7808 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/middleware/index.js @@ -0,0 +1,29 @@ +// 加载模块 - 中间件 请勿改动此文件----------------------------------- +const modulesPath = __dirname+"/modules"; +const fs = require('fs'); +const fileList = fs.readdirSync(modulesPath); +var moduleList = []; +var modulesNames = []; + +fileList.map((file, index) => { + if(file.indexOf(".js") > -1){ + modulesNames.push(file.substring(0,file.length-3)); + } +}); + +modulesNames.map((modulesName, index) => { + try { + moduleList.push(require(modulesPath+"/"+modulesName)); + } catch (err) { + console.error(`【异常】加载中间件【${modulesName}】异常,请检查!↓↓↓请查看下方的错误提示↓↓↓`); + console.error(err); + console.error(`【异常】加载中间件【${modulesName}】异常,请检查!↑↑↑请查看上方的错误提示↑↑↑`); + } +}); + +var middlewareList = []; +moduleList.map((moduleItem, index) => { + middlewareList = middlewareList.concat(moduleItem); +}); +module.exports = middlewareList; +// 加载模块 - 中间件 请勿改动此文件----------------------------------- \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/middleware/modules/addAdminLog.js b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/addAdminLog.js new file mode 100644 index 0000000..bb255a5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/addAdminLog.js @@ -0,0 +1,63 @@ +/** + * 添加操作日志 + */ + +// 需要添加日志的云函数列表 +const urlList = [ + { url: "admin/system/user/sys/add", title: "用户添加" }, + { url: "admin/system/user/sys/update", title: "用户修改" }, + { url: "admin/system/user/sys/delete", title: "用户删除" }, + { url: "admin/system/user/sys/batchUpdateStatus", title: "批量修改用户冻结状态" } +]; + +// 生成regExp规则 +let regExp = urlList.map((item, index) => { + return `^${item.url}$`; +}); + +module.exports = [{ + id: "addAdminLog", + // 需要添加操作日志的云函数列表 + regExp, + description: "添加admin操作日志", + index: 999, // 确保最后执行即可 + mode: "onActionExecuted", // 可选 onActionExecuting onActionExecuted + enable: true, // 通过设置enable=false可以关闭该中间件 + main: async function(event, serviceRes) { + let { url, data = {}, uniIdToken, util, filterResponse, originalParam } = event; + let { uniID, config, vk, db, _ } = util; + let { userInfo = {} } = filterResponse; + let res = serviceRes; + try { + // 此处加 try catch 保证即使添加日志环节出错,不影响业务运行。 + if (res.code === 0) { + // 只有请求成功的请求才添加日志 + let item = vk.pubfn.getListItem(urlList, "url", url); + let title = item && item.title ? item.title : "未分类"; + delete data.uid; + // 日志写入数据库 + // 获取请求id(只有云端云函数才有请求id,本地运行的云函数无请求id) + let request_id; + if (typeof vk.pubfn.getUniCloudRequestId === "function") { + request_id = vk.pubfn.getUniCloudRequestId(); + } + await vk.baseDao.add({ + dbName: "opendb-admin-log", + dataJson: { + user_id: userInfo._id, + user_name: userInfo.nickname, + title, + ip: originalParam.context.CLIENTIP, + url: url, + request_param: data, + response: serviceRes, + request_id + } + }); + } + } catch (err) { + console.error("添加日志异常", err); + } + return res; + } +}] diff --git a/uniCloud-aliyun/cloudfunctions/router/middleware/modules/customFilter1.js b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/customFilter1.js new file mode 100644 index 0000000..1fe60a2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/customFilter1.js @@ -0,0 +1,22 @@ +/** + * 自定义过滤器 - 前置 + */ + +module.exports = [ + { + id: "xxxx1", + regExp: "^xxx1/kh", // 正则匹配规则,这个是以^xxx1/kh/开头的云函数会被拦截 + description: "这里是你过滤器1号的描述", + index: 310,// 此处必须>300 因为检测用户是否登录的过滤器的index是200(sys是300,因此为了能通用,建议填大于300的值)(越小越先执行) + mode:"onActionExecuting", // 可选 onActionExecuting onActionExecuted + main: async function(event) { + // 这里是拦截规则,可以查数据库,最终code:0 代表通过,其他均为未通过,msg是被拦截的原因 + let { data = {}, util } = event; + let { vk } = util; + return { + code: -1, + msg: "被自定义过滤器1号拦截了" + } + } + } +] diff --git a/uniCloud-aliyun/cloudfunctions/router/middleware/modules/customFilter2.js b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/customFilter2.js new file mode 100644 index 0000000..84d976b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/customFilter2.js @@ -0,0 +1,19 @@ +/** + * 自定义过滤器 - 后置 + */ + +module.exports = [ + { + id: "xxxx2", + regExp: "^xxx2/kh", // 正则匹配规则,这个是以^xxx2/kh/开头的云函数会被拦截 + description: "这里是你过滤器2号的描述", + index: 310,// 此处必须>300 因为检测用户是否登录的过滤器的index是200(sys是300,因此为了能通用,建议填大于300的值)(越小越先执行) + mode:"onActionExecuted", // 可选 onActionExecuting onActionExecuted + main: async function(event, serviceRes) { + let { data = {}, util } = event; + let { vk } = util; + serviceRes.msg = "被过滤器修改后的值"; + return serviceRes; + } + } +] diff --git a/uniCloud-aliyun/cloudfunctions/router/middleware/modules/registerInitFilter.js b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/registerInitFilter.js new file mode 100644 index 0000000..52dfc8b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/registerInitFilter.js @@ -0,0 +1,46 @@ +/** + * 注册成功后,统一给用户初始化字段值 + */ + +module.exports = [{ + id: "registerInit", + // 符合下方正则条件的云函数才会进入该中间件 + regExp: [ + "^user/pub/register(.*)", + "^user/pub/login(.*)", + "^admin/system/user/sys/add" + ], + description: "注册成功后,统一给用户初始化字段值", + index: 301, + mode: "onActionExecuted", // 可选 onActionExecuting onActionExecuted + enable: true, // 通过设置enable=false可以关闭该中间件 + main: async function(event, serviceRes) { + let { data = {}, util, filterResponse, originalParam } = event; + let { vk, config, db, _ } = util; + let res = serviceRes; + + // 初始化用户信息(只在用户注册成功时才执行下面的代码) + if (res.code === 0 && res.type === "register" && res.uid) { + let uniIdConfig = vk.pubfn.getUniIdConfig(config); // 获取uniID的配置 + // 你要初始化的字段数据 + let initData = { + // 这里可以加你想要初始化的其他字段,如 status字段初始化为 0 + status: 0, // 用户状态:0 正常 1 禁用 2 审核中 3 审核拒绝 + + }; + // 如果开启了删除dcloud_appid功能,则初始化数据带上 dcloud_appid: _.remove() + if (uniIdConfig.removeDcloudAppid) { + // remove功能是删除该字段(代表关闭隔离不同端用户功能),该用户在其他项目中登录时就不会产生新的账号 详见:https://uniapp.dcloud.io/uniCloud/uni-id.html#isolate-user + initData["dcloud_appid"] = _.remove(); + } + // 修改用户信息,并返回修改后的用户信息 + res.userInfo = await vk.daoCenter.userDao.updateAndReturn({ + whereJson: { + _id: res.uid, + }, + dataJson: initData + }); + } + return res; + } +}] diff --git a/uniCloud-aliyun/cloudfunctions/router/middleware/modules/returnUserInfoFilter.js b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/returnUserInfoFilter.js new file mode 100644 index 0000000..c39e975 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/returnUserInfoFilter.js @@ -0,0 +1,82 @@ +/** + * 返回用户信息 + * 由于通常前端需要对用户信息、登录token进行缓存 + * 故云函数对用户进行修改后,需要返回给前端最新的用户信息,以便前端始终能够缓存最新用户信息 + */ + +module.exports = [{ + id: "returnUserInfo", + // 符合下方正则条件的云函数才会进入该中间件 + regExp: [ + "^user/pub/login(.*)", + "^user/pub/register(.*)", + "^user/kh/bind(.*)", + "^user/kh/unbind(.*)", + "^user/kh/update(.*)", + "^user/kh/set(.*)", + "^user/kh/acceptInvite$", + "^user/kh/getMyUserInfo$", + "^client/user/pub/register(.*)", + "^client/user/pub/login(.*)" + ], + description: "用于指定哪些云函数请求后需要通知前端更新userInfo、token、tokenExpired", + index: 310, + mode: "onActionExecuted", // 可选 onActionExecuting onActionExecuted + enable: true, // 通过设置enable=false可以关闭该中间件 + main: async function(event, serviceRes) { + let { data = {}, uniIdToken, util, filterResponse, originalParam } = event; + let { uniID, config = {}, vk, db, _ } = util; + let { userInfo = {} } = filterResponse; + let res = serviceRes; + if (res.code === 0) { + if (vk.pubfn.isNull(res.userInfo)) { + if (vk.pubfn.isNotNull(res.uid)) { + res.userInfo = await vk.daoCenter.userDao.findById(res.uid); + } else if (vk.pubfn.isNotNull(uniIdToken)) { + let tokenRes = await uniID.checkToken(uniIdToken); + if (tokenRes.code === 0) { + res.userInfo = tokenRes.userInfo; + } + } + } + if (vk.pubfn.isNotNull(res.userInfo)) { + if (res.type === "login") { + // 如果是登录 + // 判断用户当前 token数量 是否超过了最大限制 若 tokenMaxLimit 设置为0,代表不限制 + let tokenMaxLimit = config.uni && config.uni.tokenMaxLimit; + if (tokenMaxLimit > 0) { + let newUserInfo = await vk.baseDao.findById({ + dbName: "uni-id-users", + id: res.userInfo._id, + fieldJson: { token: true } + }); + let token = newUserInfo.token || []; + if (token.length > tokenMaxLimit) { + // 淘汰旧的 token + token = token.splice(tokenMaxLimit * -1); + await vk.baseDao.updateById({ + dbName: "uni-id-users", + id: res.userInfo._id, + dataJson: { + token: _.set(token) + } + }); + } + } + } + res.needUpdateUserInfo = true; + // 此处可以继续去除你不想返回给前端的字段 + let deleteKeys = ["token", "password"]; + res.userInfo = vk.pubfn.deleteObjectKeys(res.userInfo, deleteKeys); + } + if (vk.pubfn.isNotNullAll(res.token, res.tokenExpired)) { + // 当返回vk_uni_token对象后,框架会让token自动被前端缓存,前端不需要手动再保存token至本地缓存了。 + res.vk_uni_token = { + token: res.token, + tokenExpired: res.tokenExpired + }; + } + } + return res; + } +}] diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/.package-lock.json b/uniCloud-aliyun/cloudfunctions/router/node_modules/.package-lock.json new file mode 100644 index 0000000..300c623 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/.package-lock.json @@ -0,0 +1,40 @@ +{ + "name": "router", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "../../../uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center": { + "version": "0.0.3", + "license": "Apache-2.0" + }, + "../../../uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id": { + "version": "3.3.28", + "license": "Apache-2.0", + "dependencies": { + "uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } + }, + "../../../uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud": { + "version": "2.15.3", + "license": "Apache-2.0" + }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, + "node_modules/uni-config-center": { + "resolved": "../../../uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center", + "link": true + }, + "node_modules/uni-id": { + "resolved": "../../../uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id", + "link": true + }, + "node_modules/vk-unicloud": { + "resolved": "../../../uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud", + "link": true + } + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/CONTRIBUTING.md b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/CONTRIBUTING.md new file mode 100644 index 0000000..09bf774 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/CONTRIBUTING.md @@ -0,0 +1,28 @@ +# Contribution + +# Git Flow + +The crypto-js project uses [git flow](https://github.com/nvie/gitflow) to manage branches. +Do your changes on the `develop` or even better on a `feature/*` branch. Don't do any changes on the `master` branch. + +# Pull request + +Target your pull request on `develop` branch. Other pull request won't be accepted. + +# How to build + +1. Clone + +2. Run + + ```sh + npm install + ``` + +3. Run + + ```sh + npm run build + ``` + +4. Check `build` folder \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/LICENSE b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/LICENSE new file mode 100644 index 0000000..b0828e5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/LICENSE @@ -0,0 +1,24 @@ +# License + +[The MIT License (MIT)](http://opensource.org/licenses/MIT) + +Copyright (c) 2009-2013 Jeff Mott +Copyright (c) 2013-2016 Evan Vosberg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/README.md b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/README.md new file mode 100644 index 0000000..6a9bcdf --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/README.md @@ -0,0 +1,275 @@ +# crypto-js + +JavaScript library of crypto standards. + +## Discontinued + +Active development of CryptoJS has been discontinued. This library is no longer maintained. + +Nowadays, NodeJS and modern browsers have a native `Crypto` module. The latest version of CryptoJS already uses the native Crypto module for random number generation, since `Math.random()` is not crypto-safe. Further development of CryptoJS would result in it only being a wrapper of native Crypto. Therefore, development and maintenance has been discontinued, it is time to go for the native `crypto` module. + +## Node.js (Install) + +Requirements: + +- Node.js +- npm (Node.js package manager) + +```bash +npm install crypto-js +``` + +### Usage + +ES6 import for typical API call signing use case: + +```javascript +import sha256 from 'crypto-js/sha256'; +import hmacSHA512 from 'crypto-js/hmac-sha512'; +import Base64 from 'crypto-js/enc-base64'; + +const message, nonce, path, privateKey; // ... +const hashDigest = sha256(nonce + message); +const hmacDigest = Base64.stringify(hmacSHA512(path + hashDigest, privateKey)); +``` + +Modular include: + +```javascript +var AES = require("crypto-js/aes"); +var SHA256 = require("crypto-js/sha256"); +... +console.log(SHA256("Message")); +``` + +Including all libraries, for access to extra methods: + +```javascript +var CryptoJS = require("crypto-js"); +console.log(CryptoJS.HmacSHA1("Message", "Key")); +``` + +## Client (browser) + +Requirements: + +- Node.js +- Bower (package manager for frontend) + +```bash +bower install crypto-js +``` + +### Usage + +Modular include: + +```javascript +require.config({ + packages: [ + { + name: 'crypto-js', + location: 'path-to/bower_components/crypto-js', + main: 'index' + } + ] +}); + +require(["crypto-js/aes", "crypto-js/sha256"], function (AES, SHA256) { + console.log(SHA256("Message")); +}); +``` + +Including all libraries, for access to extra methods: + +```javascript +// Above-mentioned will work or use this simple form +require.config({ + paths: { + 'crypto-js': 'path-to/bower_components/crypto-js/crypto-js' + } +}); + +require(["crypto-js"], function (CryptoJS) { + console.log(CryptoJS.HmacSHA1("Message", "Key")); +}); +``` + +### Usage without RequireJS + +```html + + +``` + +## API + +See: https://cryptojs.gitbook.io/docs/ + +### AES Encryption + +#### Plain text encryption + +```javascript +var CryptoJS = require("crypto-js"); + +// Encrypt +var ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123').toString(); + +// Decrypt +var bytes = CryptoJS.AES.decrypt(ciphertext, 'secret key 123'); +var originalText = bytes.toString(CryptoJS.enc.Utf8); + +console.log(originalText); // 'my message' +``` + +#### Object encryption + +```javascript +var CryptoJS = require("crypto-js"); + +var data = [{id: 1}, {id: 2}] + +// Encrypt +var ciphertext = CryptoJS.AES.encrypt(JSON.stringify(data), 'secret key 123').toString(); + +// Decrypt +var bytes = CryptoJS.AES.decrypt(ciphertext, 'secret key 123'); +var decryptedData = JSON.parse(bytes.toString(CryptoJS.enc.Utf8)); + +console.log(decryptedData); // [{id: 1}, {id: 2}] +``` + +### List of modules + + +- ```crypto-js/core``` +- ```crypto-js/x64-core``` +- ```crypto-js/lib-typedarrays``` + +--- + +- ```crypto-js/md5``` +- ```crypto-js/sha1``` +- ```crypto-js/sha256``` +- ```crypto-js/sha224``` +- ```crypto-js/sha512``` +- ```crypto-js/sha384``` +- ```crypto-js/sha3``` +- ```crypto-js/ripemd160``` + +--- + +- ```crypto-js/hmac-md5``` +- ```crypto-js/hmac-sha1``` +- ```crypto-js/hmac-sha256``` +- ```crypto-js/hmac-sha224``` +- ```crypto-js/hmac-sha512``` +- ```crypto-js/hmac-sha384``` +- ```crypto-js/hmac-sha3``` +- ```crypto-js/hmac-ripemd160``` + +--- + +- ```crypto-js/pbkdf2``` + +--- + +- ```crypto-js/aes``` +- ```crypto-js/tripledes``` +- ```crypto-js/rc4``` +- ```crypto-js/rabbit``` +- ```crypto-js/rabbit-legacy``` +- ```crypto-js/evpkdf``` + +--- + +- ```crypto-js/format-openssl``` +- ```crypto-js/format-hex``` + +--- + +- ```crypto-js/enc-latin1``` +- ```crypto-js/enc-utf8``` +- ```crypto-js/enc-hex``` +- ```crypto-js/enc-utf16``` +- ```crypto-js/enc-base64``` + +--- + +- ```crypto-js/mode-cfb``` +- ```crypto-js/mode-ctr``` +- ```crypto-js/mode-ctr-gladman``` +- ```crypto-js/mode-ofb``` +- ```crypto-js/mode-ecb``` + +--- + +- ```crypto-js/pad-pkcs7``` +- ```crypto-js/pad-ansix923``` +- ```crypto-js/pad-iso10126``` +- ```crypto-js/pad-iso97971``` +- ```crypto-js/pad-zeropadding``` +- ```crypto-js/pad-nopadding``` + + +## Release notes + +### 4.2.0 + +Change default hash algorithm and iteration's for PBKDF2 to prevent weak security by using the default configuration. + +Custom KDF Hasher + +Blowfish support + +### 4.1.1 + +Fix module order in bundled release. + +Include the browser field in the released package.json. + +### 4.1.0 + +Added url safe variant of base64 encoding. [357](https://github.com/brix/crypto-js/pull/357) + +Avoid webpack to add crypto-browser package. [364](https://github.com/brix/crypto-js/pull/364) + +### 4.0.0 + +This is an update including breaking changes for some environments. + +In this version `Math.random()` has been replaced by the random methods of the native crypto module. + +For this reason CryptoJS might not run in some JavaScript environments without native crypto module. Such as IE 10 or before or React Native. + +### 3.3.0 + +Rollback, `3.3.0` is the same as `3.1.9-1`. + +The move of using native secure crypto module will be shifted to a new `4.x.x` version. As it is a breaking change the impact is too big for a minor release. + +### 3.2.1 + +The usage of the native crypto module has been fixed. The import and access of the native crypto module has been improved. + +### 3.2.0 + +In this version `Math.random()` has been replaced by the random methods of the native crypto module. + +For this reason CryptoJS might does not run in some JavaScript environments without native crypto module. Such as IE 10 or before. + +If it's absolute required to run CryptoJS in such an environment, stay with `3.1.x` version. Encrypting and decrypting stays compatible. But keep in mind `3.1.x` versions still use `Math.random()` which is cryptographically not secure, as it's not random enough. + +This version came along with `CRITICAL` `BUG`. + +DO NOT USE THIS VERSION! Please, go for a newer version! + +### 3.1.x + +The `3.1.x` are based on the original CryptoJS, wrapped in CommonJS modules. + + diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/aes.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/aes.js new file mode 100644 index 0000000..166e3ea --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/aes.js @@ -0,0 +1,234 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var BlockCipher = C_lib.BlockCipher; + var C_algo = C.algo; + + // Lookup tables + var SBOX = []; + var INV_SBOX = []; + var SUB_MIX_0 = []; + var SUB_MIX_1 = []; + var SUB_MIX_2 = []; + var SUB_MIX_3 = []; + var INV_SUB_MIX_0 = []; + var INV_SUB_MIX_1 = []; + var INV_SUB_MIX_2 = []; + var INV_SUB_MIX_3 = []; + + // Compute lookup tables + (function () { + // Compute double table + var d = []; + for (var i = 0; i < 256; i++) { + if (i < 128) { + d[i] = i << 1; + } else { + d[i] = (i << 1) ^ 0x11b; + } + } + + // Walk GF(2^8) + var x = 0; + var xi = 0; + for (var i = 0; i < 256; i++) { + // Compute sbox + var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4); + sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63; + SBOX[x] = sx; + INV_SBOX[sx] = x; + + // Compute multiplication + var x2 = d[x]; + var x4 = d[x2]; + var x8 = d[x4]; + + // Compute sub bytes, mix columns tables + var t = (d[sx] * 0x101) ^ (sx * 0x1010100); + SUB_MIX_0[x] = (t << 24) | (t >>> 8); + SUB_MIX_1[x] = (t << 16) | (t >>> 16); + SUB_MIX_2[x] = (t << 8) | (t >>> 24); + SUB_MIX_3[x] = t; + + // Compute inv sub bytes, inv mix columns tables + var t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100); + INV_SUB_MIX_0[sx] = (t << 24) | (t >>> 8); + INV_SUB_MIX_1[sx] = (t << 16) | (t >>> 16); + INV_SUB_MIX_2[sx] = (t << 8) | (t >>> 24); + INV_SUB_MIX_3[sx] = t; + + // Compute next counter + if (!x) { + x = xi = 1; + } else { + x = x2 ^ d[d[d[x8 ^ x2]]]; + xi ^= d[d[xi]]; + } + } + }()); + + // Precomputed Rcon lookup + var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]; + + /** + * AES block cipher algorithm. + */ + var AES = C_algo.AES = BlockCipher.extend({ + _doReset: function () { + var t; + + // Skip reset of nRounds has been set before and key did not change + if (this._nRounds && this._keyPriorReset === this._key) { + return; + } + + // Shortcuts + var key = this._keyPriorReset = this._key; + var keyWords = key.words; + var keySize = key.sigBytes / 4; + + // Compute number of rounds + var nRounds = this._nRounds = keySize + 6; + + // Compute number of key schedule rows + var ksRows = (nRounds + 1) * 4; + + // Compute key schedule + var keySchedule = this._keySchedule = []; + for (var ksRow = 0; ksRow < ksRows; ksRow++) { + if (ksRow < keySize) { + keySchedule[ksRow] = keyWords[ksRow]; + } else { + t = keySchedule[ksRow - 1]; + + if (!(ksRow % keySize)) { + // Rot word + t = (t << 8) | (t >>> 24); + + // Sub word + t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff]; + + // Mix Rcon + t ^= RCON[(ksRow / keySize) | 0] << 24; + } else if (keySize > 6 && ksRow % keySize == 4) { + // Sub word + t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff]; + } + + keySchedule[ksRow] = keySchedule[ksRow - keySize] ^ t; + } + } + + // Compute inv key schedule + var invKeySchedule = this._invKeySchedule = []; + for (var invKsRow = 0; invKsRow < ksRows; invKsRow++) { + var ksRow = ksRows - invKsRow; + + if (invKsRow % 4) { + var t = keySchedule[ksRow]; + } else { + var t = keySchedule[ksRow - 4]; + } + + if (invKsRow < 4 || ksRow <= 4) { + invKeySchedule[invKsRow] = t; + } else { + invKeySchedule[invKsRow] = INV_SUB_MIX_0[SBOX[t >>> 24]] ^ INV_SUB_MIX_1[SBOX[(t >>> 16) & 0xff]] ^ + INV_SUB_MIX_2[SBOX[(t >>> 8) & 0xff]] ^ INV_SUB_MIX_3[SBOX[t & 0xff]]; + } + } + }, + + encryptBlock: function (M, offset) { + this._doCryptBlock(M, offset, this._keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX); + }, + + decryptBlock: function (M, offset) { + // Swap 2nd and 4th rows + var t = M[offset + 1]; + M[offset + 1] = M[offset + 3]; + M[offset + 3] = t; + + this._doCryptBlock(M, offset, this._invKeySchedule, INV_SUB_MIX_0, INV_SUB_MIX_1, INV_SUB_MIX_2, INV_SUB_MIX_3, INV_SBOX); + + // Inv swap 2nd and 4th rows + var t = M[offset + 1]; + M[offset + 1] = M[offset + 3]; + M[offset + 3] = t; + }, + + _doCryptBlock: function (M, offset, keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX) { + // Shortcut + var nRounds = this._nRounds; + + // Get input, add round key + var s0 = M[offset] ^ keySchedule[0]; + var s1 = M[offset + 1] ^ keySchedule[1]; + var s2 = M[offset + 2] ^ keySchedule[2]; + var s3 = M[offset + 3] ^ keySchedule[3]; + + // Key schedule row counter + var ksRow = 4; + + // Rounds + for (var round = 1; round < nRounds; round++) { + // Shift rows, sub bytes, mix columns, add round key + var t0 = SUB_MIX_0[s0 >>> 24] ^ SUB_MIX_1[(s1 >>> 16) & 0xff] ^ SUB_MIX_2[(s2 >>> 8) & 0xff] ^ SUB_MIX_3[s3 & 0xff] ^ keySchedule[ksRow++]; + var t1 = SUB_MIX_0[s1 >>> 24] ^ SUB_MIX_1[(s2 >>> 16) & 0xff] ^ SUB_MIX_2[(s3 >>> 8) & 0xff] ^ SUB_MIX_3[s0 & 0xff] ^ keySchedule[ksRow++]; + var t2 = SUB_MIX_0[s2 >>> 24] ^ SUB_MIX_1[(s3 >>> 16) & 0xff] ^ SUB_MIX_2[(s0 >>> 8) & 0xff] ^ SUB_MIX_3[s1 & 0xff] ^ keySchedule[ksRow++]; + var t3 = SUB_MIX_0[s3 >>> 24] ^ SUB_MIX_1[(s0 >>> 16) & 0xff] ^ SUB_MIX_2[(s1 >>> 8) & 0xff] ^ SUB_MIX_3[s2 & 0xff] ^ keySchedule[ksRow++]; + + // Update state + s0 = t0; + s1 = t1; + s2 = t2; + s3 = t3; + } + + // Shift rows, sub bytes, add round key + var t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++]; + var t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++]; + var t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++]; + var t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++]; + + // Set output + M[offset] = t0; + M[offset + 1] = t1; + M[offset + 2] = t2; + M[offset + 3] = t3; + }, + + keySize: 256/32 + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.AES.encrypt(message, key, cfg); + * var plaintext = CryptoJS.AES.decrypt(ciphertext, key, cfg); + */ + C.AES = BlockCipher._createHelper(AES); + }()); + + + return CryptoJS.AES; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/blowfish.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/blowfish.js new file mode 100644 index 0000000..149812f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/blowfish.js @@ -0,0 +1,471 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var BlockCipher = C_lib.BlockCipher; + var C_algo = C.algo; + + const N = 16; + + //Origin pbox and sbox, derived from PI + const ORIG_P = [ + 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, + 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, + 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, + 0x9216D5D9, 0x8979FB1B + ]; + + const ORIG_S = [ + [ 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, + 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, + 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, + 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, + 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, + 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, + 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, + 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, + 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, + 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, + 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, + 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, + 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, + 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, + 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, + 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, + 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, + 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, + 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, + 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, + 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, + 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, + 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, + 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, + 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, + 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, + 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, + 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, + 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, + 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, + 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, + 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09, + 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, + 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, + 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, + 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, + 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, + 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, + 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, + 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, + 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, + 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, + 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, + 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, + 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, + 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, + 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, + 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, + 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, + 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, + 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, + 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, + 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, + 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, + 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, + 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, + 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, + 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, + 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, + 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, + 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, + 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, + 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, + 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A ], + [ 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, + 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, + 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, + 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, + 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, + 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, + 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, + 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, + 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, + 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, + 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, + 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, + 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, + 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, + 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, + 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331, + 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, + 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, + 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, + 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, + 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, + 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, + 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, + 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, + 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, + 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, + 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, + 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, + 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, + 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, + 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, + 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, + 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, + 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, + 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, + 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, + 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, + 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, + 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, + 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, + 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, + 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, + 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, + 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, + 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, + 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, + 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, + 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, + 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, + 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, + 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, + 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, + 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, + 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, + 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, + 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, + 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, + 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, + 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, + 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, + 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, + 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, + 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, + 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7 ], + [ 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, + 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, + 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, + 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, + 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, + 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, + 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, + 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, + 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, + 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, + 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, + 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, + 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, + 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, + 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, + 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, + 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, + 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, + 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, + 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, + 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, + 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, + 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, + 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, + 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, + 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, + 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, + 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, + 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, + 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, + 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, + 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, + 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, + 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, + 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, + 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, + 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, + 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, + 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, + 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, + 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, + 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, + 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, + 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, + 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, + 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, + 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, + 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C, + 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, + 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, + 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, + 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, + 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, + 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, + 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, + 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, + 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, + 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, + 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, + 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, + 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, + 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, + 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, + 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0 ], + [ 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, + 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, + 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, + 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, + 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, + 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, + 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, + 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, + 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, + 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, + 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, + 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, + 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, + 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, + 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, + 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, + 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, + 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, + 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, + 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, + 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, + 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, + 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, + 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, + 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, + 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, + 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, + 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, + 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, + 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, + 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, + 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47, + 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, + 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, + 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, + 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, + 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, + 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, + 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, + 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, + 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, + 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, + 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, + 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, + 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, + 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, + 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, + 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, + 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, + 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, + 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, + 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, + 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, + 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, + 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, + 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, + 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, + 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, + 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, + 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, + 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, + 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, + 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, + 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 ] + ]; + + var BLOWFISH_CTX = { + pbox: [], + sbox: [] + } + + function F(ctx, x){ + let a = (x >> 24) & 0xFF; + let b = (x >> 16) & 0xFF; + let c = (x >> 8) & 0xFF; + let d = x & 0xFF; + + let y = ctx.sbox[0][a] + ctx.sbox[1][b]; + y = y ^ ctx.sbox[2][c]; + y = y + ctx.sbox[3][d]; + + return y; + } + + function BlowFish_Encrypt(ctx, left, right){ + let Xl = left; + let Xr = right; + let temp; + + for(let i = 0; i < N; ++i){ + Xl = Xl ^ ctx.pbox[i]; + Xr = F(ctx, Xl) ^ Xr; + + temp = Xl; + Xl = Xr; + Xr = temp; + } + + temp = Xl; + Xl = Xr; + Xr = temp; + + Xr = Xr ^ ctx.pbox[N]; + Xl = Xl ^ ctx.pbox[N + 1]; + + return {left: Xl, right: Xr}; + } + + function BlowFish_Decrypt(ctx, left, right){ + let Xl = left; + let Xr = right; + let temp; + + for(let i = N + 1; i > 1; --i){ + Xl = Xl ^ ctx.pbox[i]; + Xr = F(ctx, Xl) ^ Xr; + + temp = Xl; + Xl = Xr; + Xr = temp; + } + + temp = Xl; + Xl = Xr; + Xr = temp; + + Xr = Xr ^ ctx.pbox[1]; + Xl = Xl ^ ctx.pbox[0]; + + return {left: Xl, right: Xr}; + } + + /** + * Initialization ctx's pbox and sbox. + * + * @param {Object} ctx The object has pbox and sbox. + * @param {Array} key An array of 32-bit words. + * @param {int} keysize The length of the key. + * + * @example + * + * BlowFishInit(BLOWFISH_CTX, key, 128/32); + */ + function BlowFishInit(ctx, key, keysize) + { + for(let Row = 0; Row < 4; Row++) + { + ctx.sbox[Row] = []; + for(let Col = 0; Col < 256; Col++) + { + ctx.sbox[Row][Col] = ORIG_S[Row][Col]; + } + } + + let keyIndex = 0; + for(let index = 0; index < N + 2; index++) + { + ctx.pbox[index] = ORIG_P[index] ^ key[keyIndex]; + keyIndex++; + if(keyIndex >= keysize) + { + keyIndex = 0; + } + } + + let Data1 = 0; + let Data2 = 0; + let res = 0; + for(let i = 0; i < N + 2; i += 2) + { + res = BlowFish_Encrypt(ctx, Data1, Data2); + Data1 = res.left; + Data2 = res.right; + ctx.pbox[i] = Data1; + ctx.pbox[i + 1] = Data2; + } + + for(let i = 0; i < 4; i++) + { + for(let j = 0; j < 256; j += 2) + { + res = BlowFish_Encrypt(ctx, Data1, Data2); + Data1 = res.left; + Data2 = res.right; + ctx.sbox[i][j] = Data1; + ctx.sbox[i][j + 1] = Data2; + } + } + + return true; + } + + /** + * Blowfish block cipher algorithm. + */ + var Blowfish = C_algo.Blowfish = BlockCipher.extend({ + _doReset: function () { + // Skip reset of nRounds has been set before and key did not change + if (this._keyPriorReset === this._key) { + return; + } + + // Shortcuts + var key = this._keyPriorReset = this._key; + var keyWords = key.words; + var keySize = key.sigBytes / 4; + + //Initialization pbox and sbox + BlowFishInit(BLOWFISH_CTX, keyWords, keySize); + }, + + encryptBlock: function (M, offset) { + var res = BlowFish_Encrypt(BLOWFISH_CTX, M[offset], M[offset + 1]); + M[offset] = res.left; + M[offset + 1] = res.right; + }, + + decryptBlock: function (M, offset) { + var res = BlowFish_Decrypt(BLOWFISH_CTX, M[offset], M[offset + 1]); + M[offset] = res.left; + M[offset + 1] = res.right; + }, + + blockSize: 64/32, + + keySize: 128/32, + + ivSize: 64/32 + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.Blowfish.encrypt(message, key, cfg); + * var plaintext = CryptoJS.Blowfish.decrypt(ciphertext, key, cfg); + */ + C.Blowfish = BlockCipher._createHelper(Blowfish); + }()); + + + return CryptoJS.Blowfish; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/bower.json b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/bower.json new file mode 100644 index 0000000..4dee617 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/bower.json @@ -0,0 +1,39 @@ +{ + "name": "crypto-js", + "version": "4.2.0", + "description": "JavaScript library of crypto standards.", + "license": "MIT", + "homepage": "http://github.com/brix/crypto-js", + "repository": { + "type": "git", + "url": "http://github.com/brix/crypto-js.git" + }, + "keywords": [ + "security", + "crypto", + "Hash", + "MD5", + "SHA1", + "SHA-1", + "SHA256", + "SHA-256", + "RC4", + "Rabbit", + "AES", + "DES", + "PBKDF2", + "HMAC", + "OFB", + "CFB", + "CTR", + "CBC", + "Base64", + "Base64url" + ], + "main": "index.js", + "dependencies": {}, + "browser": { + "crypto": false + }, + "ignore": [] +} diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/cipher-core.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/cipher-core.js new file mode 100644 index 0000000..903f462 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/cipher-core.js @@ -0,0 +1,895 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./evpkdf")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./evpkdf"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Cipher core components. + */ + CryptoJS.lib.Cipher || (function (undefined) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var WordArray = C_lib.WordArray; + var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm; + var C_enc = C.enc; + var Utf8 = C_enc.Utf8; + var Base64 = C_enc.Base64; + var C_algo = C.algo; + var EvpKDF = C_algo.EvpKDF; + + /** + * Abstract base cipher template. + * + * @property {number} keySize This cipher's key size. Default: 4 (128 bits) + * @property {number} ivSize This cipher's IV size. Default: 4 (128 bits) + * @property {number} _ENC_XFORM_MODE A constant representing encryption mode. + * @property {number} _DEC_XFORM_MODE A constant representing decryption mode. + */ + var Cipher = C_lib.Cipher = BufferedBlockAlgorithm.extend({ + /** + * Configuration options. + * + * @property {WordArray} iv The IV to use for this operation. + */ + cfg: Base.extend(), + + /** + * Creates this cipher in encryption mode. + * + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {Cipher} A cipher instance. + * + * @static + * + * @example + * + * var cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray }); + */ + createEncryptor: function (key, cfg) { + return this.create(this._ENC_XFORM_MODE, key, cfg); + }, + + /** + * Creates this cipher in decryption mode. + * + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {Cipher} A cipher instance. + * + * @static + * + * @example + * + * var cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray }); + */ + createDecryptor: function (key, cfg) { + return this.create(this._DEC_XFORM_MODE, key, cfg); + }, + + /** + * Initializes a newly created cipher. + * + * @param {number} xformMode Either the encryption or decryption transormation mode constant. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @example + * + * var cipher = CryptoJS.algo.AES.create(CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray }); + */ + init: function (xformMode, key, cfg) { + // Apply config defaults + this.cfg = this.cfg.extend(cfg); + + // Store transform mode and key + this._xformMode = xformMode; + this._key = key; + + // Set initial values + this.reset(); + }, + + /** + * Resets this cipher to its initial state. + * + * @example + * + * cipher.reset(); + */ + reset: function () { + // Reset data buffer + BufferedBlockAlgorithm.reset.call(this); + + // Perform concrete-cipher logic + this._doReset(); + }, + + /** + * Adds data to be encrypted or decrypted. + * + * @param {WordArray|string} dataUpdate The data to encrypt or decrypt. + * + * @return {WordArray} The data after processing. + * + * @example + * + * var encrypted = cipher.process('data'); + * var encrypted = cipher.process(wordArray); + */ + process: function (dataUpdate) { + // Append + this._append(dataUpdate); + + // Process available blocks + return this._process(); + }, + + /** + * Finalizes the encryption or decryption process. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} dataUpdate The final data to encrypt or decrypt. + * + * @return {WordArray} The data after final processing. + * + * @example + * + * var encrypted = cipher.finalize(); + * var encrypted = cipher.finalize('data'); + * var encrypted = cipher.finalize(wordArray); + */ + finalize: function (dataUpdate) { + // Final data update + if (dataUpdate) { + this._append(dataUpdate); + } + + // Perform concrete-cipher logic + var finalProcessedData = this._doFinalize(); + + return finalProcessedData; + }, + + keySize: 128/32, + + ivSize: 128/32, + + _ENC_XFORM_MODE: 1, + + _DEC_XFORM_MODE: 2, + + /** + * Creates shortcut functions to a cipher's object interface. + * + * @param {Cipher} cipher The cipher to create a helper for. + * + * @return {Object} An object with encrypt and decrypt shortcut functions. + * + * @static + * + * @example + * + * var AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES); + */ + _createHelper: (function () { + function selectCipherStrategy(key) { + if (typeof key == 'string') { + return PasswordBasedCipher; + } else { + return SerializableCipher; + } + } + + return function (cipher) { + return { + encrypt: function (message, key, cfg) { + return selectCipherStrategy(key).encrypt(cipher, message, key, cfg); + }, + + decrypt: function (ciphertext, key, cfg) { + return selectCipherStrategy(key).decrypt(cipher, ciphertext, key, cfg); + } + }; + }; + }()) + }); + + /** + * Abstract base stream cipher template. + * + * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 1 (32 bits) + */ + var StreamCipher = C_lib.StreamCipher = Cipher.extend({ + _doFinalize: function () { + // Process partial blocks + var finalProcessedBlocks = this._process(!!'flush'); + + return finalProcessedBlocks; + }, + + blockSize: 1 + }); + + /** + * Mode namespace. + */ + var C_mode = C.mode = {}; + + /** + * Abstract base block cipher mode template. + */ + var BlockCipherMode = C_lib.BlockCipherMode = Base.extend({ + /** + * Creates this mode for encryption. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @static + * + * @example + * + * var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words); + */ + createEncryptor: function (cipher, iv) { + return this.Encryptor.create(cipher, iv); + }, + + /** + * Creates this mode for decryption. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @static + * + * @example + * + * var mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words); + */ + createDecryptor: function (cipher, iv) { + return this.Decryptor.create(cipher, iv); + }, + + /** + * Initializes a newly created mode. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @example + * + * var mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words); + */ + init: function (cipher, iv) { + this._cipher = cipher; + this._iv = iv; + } + }); + + /** + * Cipher Block Chaining mode. + */ + var CBC = C_mode.CBC = (function () { + /** + * Abstract base CBC mode. + */ + var CBC = BlockCipherMode.extend(); + + /** + * CBC encryptor. + */ + CBC.Encryptor = CBC.extend({ + /** + * Processes the data block at offset. + * + * @param {Array} words The data words to operate on. + * @param {number} offset The offset where the block starts. + * + * @example + * + * mode.processBlock(data.words, offset); + */ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + // XOR and encrypt + xorBlock.call(this, words, offset, blockSize); + cipher.encryptBlock(words, offset); + + // Remember this block to use with next block + this._prevBlock = words.slice(offset, offset + blockSize); + } + }); + + /** + * CBC decryptor. + */ + CBC.Decryptor = CBC.extend({ + /** + * Processes the data block at offset. + * + * @param {Array} words The data words to operate on. + * @param {number} offset The offset where the block starts. + * + * @example + * + * mode.processBlock(data.words, offset); + */ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + // Remember this block to use with next block + var thisBlock = words.slice(offset, offset + blockSize); + + // Decrypt and XOR + cipher.decryptBlock(words, offset); + xorBlock.call(this, words, offset, blockSize); + + // This block becomes the previous block + this._prevBlock = thisBlock; + } + }); + + function xorBlock(words, offset, blockSize) { + var block; + + // Shortcut + var iv = this._iv; + + // Choose mixing block + if (iv) { + block = iv; + + // Remove IV for subsequent blocks + this._iv = undefined; + } else { + block = this._prevBlock; + } + + // XOR blocks + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= block[i]; + } + } + + return CBC; + }()); + + /** + * Padding namespace. + */ + var C_pad = C.pad = {}; + + /** + * PKCS #5/7 padding strategy. + */ + var Pkcs7 = C_pad.Pkcs7 = { + /** + * Pads data using the algorithm defined in PKCS #5/7. + * + * @param {WordArray} data The data to pad. + * @param {number} blockSize The multiple that the data should be padded to. + * + * @static + * + * @example + * + * CryptoJS.pad.Pkcs7.pad(wordArray, 4); + */ + pad: function (data, blockSize) { + // Shortcut + var blockSizeBytes = blockSize * 4; + + // Count padding bytes + var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes; + + // Create padding word + var paddingWord = (nPaddingBytes << 24) | (nPaddingBytes << 16) | (nPaddingBytes << 8) | nPaddingBytes; + + // Create padding + var paddingWords = []; + for (var i = 0; i < nPaddingBytes; i += 4) { + paddingWords.push(paddingWord); + } + var padding = WordArray.create(paddingWords, nPaddingBytes); + + // Add padding + data.concat(padding); + }, + + /** + * Unpads data that had been padded using the algorithm defined in PKCS #5/7. + * + * @param {WordArray} data The data to unpad. + * + * @static + * + * @example + * + * CryptoJS.pad.Pkcs7.unpad(wordArray); + */ + unpad: function (data) { + // Get number of padding bytes from last byte + var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + + // Remove padding + data.sigBytes -= nPaddingBytes; + } + }; + + /** + * Abstract base block cipher template. + * + * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 4 (128 bits) + */ + var BlockCipher = C_lib.BlockCipher = Cipher.extend({ + /** + * Configuration options. + * + * @property {Mode} mode The block mode to use. Default: CBC + * @property {Padding} padding The padding strategy to use. Default: Pkcs7 + */ + cfg: Cipher.cfg.extend({ + mode: CBC, + padding: Pkcs7 + }), + + reset: function () { + var modeCreator; + + // Reset cipher + Cipher.reset.call(this); + + // Shortcuts + var cfg = this.cfg; + var iv = cfg.iv; + var mode = cfg.mode; + + // Reset block mode + if (this._xformMode == this._ENC_XFORM_MODE) { + modeCreator = mode.createEncryptor; + } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { + modeCreator = mode.createDecryptor; + // Keep at least one block in the buffer for unpadding + this._minBufferSize = 1; + } + + if (this._mode && this._mode.__creator == modeCreator) { + this._mode.init(this, iv && iv.words); + } else { + this._mode = modeCreator.call(mode, this, iv && iv.words); + this._mode.__creator = modeCreator; + } + }, + + _doProcessBlock: function (words, offset) { + this._mode.processBlock(words, offset); + }, + + _doFinalize: function () { + var finalProcessedBlocks; + + // Shortcut + var padding = this.cfg.padding; + + // Finalize + if (this._xformMode == this._ENC_XFORM_MODE) { + // Pad data + padding.pad(this._data, this.blockSize); + + // Process final blocks + finalProcessedBlocks = this._process(!!'flush'); + } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { + // Process final blocks + finalProcessedBlocks = this._process(!!'flush'); + + // Unpad data + padding.unpad(finalProcessedBlocks); + } + + return finalProcessedBlocks; + }, + + blockSize: 128/32 + }); + + /** + * A collection of cipher parameters. + * + * @property {WordArray} ciphertext The raw ciphertext. + * @property {WordArray} key The key to this ciphertext. + * @property {WordArray} iv The IV used in the ciphering operation. + * @property {WordArray} salt The salt used with a key derivation function. + * @property {Cipher} algorithm The cipher algorithm. + * @property {Mode} mode The block mode used in the ciphering operation. + * @property {Padding} padding The padding scheme used in the ciphering operation. + * @property {number} blockSize The block size of the cipher. + * @property {Format} formatter The default formatting strategy to convert this cipher params object to a string. + */ + var CipherParams = C_lib.CipherParams = Base.extend({ + /** + * Initializes a newly created cipher params object. + * + * @param {Object} cipherParams An object with any of the possible cipher parameters. + * + * @example + * + * var cipherParams = CryptoJS.lib.CipherParams.create({ + * ciphertext: ciphertextWordArray, + * key: keyWordArray, + * iv: ivWordArray, + * salt: saltWordArray, + * algorithm: CryptoJS.algo.AES, + * mode: CryptoJS.mode.CBC, + * padding: CryptoJS.pad.PKCS7, + * blockSize: 4, + * formatter: CryptoJS.format.OpenSSL + * }); + */ + init: function (cipherParams) { + this.mixIn(cipherParams); + }, + + /** + * Converts this cipher params object to a string. + * + * @param {Format} formatter (Optional) The formatting strategy to use. + * + * @return {string} The stringified cipher params. + * + * @throws Error If neither the formatter nor the default formatter is set. + * + * @example + * + * var string = cipherParams + ''; + * var string = cipherParams.toString(); + * var string = cipherParams.toString(CryptoJS.format.OpenSSL); + */ + toString: function (formatter) { + return (formatter || this.formatter).stringify(this); + } + }); + + /** + * Format namespace. + */ + var C_format = C.format = {}; + + /** + * OpenSSL formatting strategy. + */ + var OpenSSLFormatter = C_format.OpenSSL = { + /** + * Converts a cipher params object to an OpenSSL-compatible string. + * + * @param {CipherParams} cipherParams The cipher params object. + * + * @return {string} The OpenSSL-compatible string. + * + * @static + * + * @example + * + * var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams); + */ + stringify: function (cipherParams) { + var wordArray; + + // Shortcuts + var ciphertext = cipherParams.ciphertext; + var salt = cipherParams.salt; + + // Format + if (salt) { + wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext); + } else { + wordArray = ciphertext; + } + + return wordArray.toString(Base64); + }, + + /** + * Converts an OpenSSL-compatible string to a cipher params object. + * + * @param {string} openSSLStr The OpenSSL-compatible string. + * + * @return {CipherParams} The cipher params object. + * + * @static + * + * @example + * + * var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString); + */ + parse: function (openSSLStr) { + var salt; + + // Parse base64 + var ciphertext = Base64.parse(openSSLStr); + + // Shortcut + var ciphertextWords = ciphertext.words; + + // Test for salt + if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) { + // Extract salt + salt = WordArray.create(ciphertextWords.slice(2, 4)); + + // Remove salt from ciphertext + ciphertextWords.splice(0, 4); + ciphertext.sigBytes -= 16; + } + + return CipherParams.create({ ciphertext: ciphertext, salt: salt }); + } + }; + + /** + * A cipher wrapper that returns ciphertext as a serializable cipher params object. + */ + var SerializableCipher = C_lib.SerializableCipher = Base.extend({ + /** + * Configuration options. + * + * @property {Formatter} format The formatting strategy to convert cipher param objects to and from a string. Default: OpenSSL + */ + cfg: Base.extend({ + format: OpenSSLFormatter + }), + + /** + * Encrypts a message. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {WordArray|string} message The message to encrypt. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {CipherParams} A cipher params object. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key); + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv }); + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + */ + encrypt: function (cipher, message, key, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Encrypt + var encryptor = cipher.createEncryptor(key, cfg); + var ciphertext = encryptor.finalize(message); + + // Shortcut + var cipherCfg = encryptor.cfg; + + // Create and return serializable cipher params + return CipherParams.create({ + ciphertext: ciphertext, + key: key, + iv: cipherCfg.iv, + algorithm: cipher, + mode: cipherCfg.mode, + padding: cipherCfg.padding, + blockSize: cipher.blockSize, + formatter: cfg.format + }); + }, + + /** + * Decrypts serialized ciphertext. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {CipherParams|string} ciphertext The ciphertext to decrypt. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {WordArray} The plaintext. + * + * @static + * + * @example + * + * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + */ + decrypt: function (cipher, ciphertext, key, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Convert string to CipherParams + ciphertext = this._parse(ciphertext, cfg.format); + + // Decrypt + var plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext); + + return plaintext; + }, + + /** + * Converts serialized ciphertext to CipherParams, + * else assumed CipherParams already and returns ciphertext unchanged. + * + * @param {CipherParams|string} ciphertext The ciphertext. + * @param {Formatter} format The formatting strategy to use to parse serialized ciphertext. + * + * @return {CipherParams} The unserialized ciphertext. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format); + */ + _parse: function (ciphertext, format) { + if (typeof ciphertext == 'string') { + return format.parse(ciphertext, this); + } else { + return ciphertext; + } + } + }); + + /** + * Key derivation function namespace. + */ + var C_kdf = C.kdf = {}; + + /** + * OpenSSL key derivation function. + */ + var OpenSSLKdf = C_kdf.OpenSSL = { + /** + * Derives a key and IV from a password. + * + * @param {string} password The password to derive from. + * @param {number} keySize The size in words of the key to generate. + * @param {number} ivSize The size in words of the IV to generate. + * @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly. + * + * @return {CipherParams} A cipher params object with the key, IV, and salt. + * + * @static + * + * @example + * + * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32); + * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt'); + */ + execute: function (password, keySize, ivSize, salt, hasher) { + // Generate random salt + if (!salt) { + salt = WordArray.random(64/8); + } + + // Derive key and IV + if (!hasher) { + var key = EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt); + } else { + var key = EvpKDF.create({ keySize: keySize + ivSize, hasher: hasher }).compute(password, salt); + } + + + // Separate key and IV + var iv = WordArray.create(key.words.slice(keySize), ivSize * 4); + key.sigBytes = keySize * 4; + + // Return params + return CipherParams.create({ key: key, iv: iv, salt: salt }); + } + }; + + /** + * A serializable cipher wrapper that derives the key from a password, + * and returns ciphertext as a serializable cipher params object. + */ + var PasswordBasedCipher = C_lib.PasswordBasedCipher = SerializableCipher.extend({ + /** + * Configuration options. + * + * @property {KDF} kdf The key derivation function to use to generate a key and IV from a password. Default: OpenSSL + */ + cfg: SerializableCipher.cfg.extend({ + kdf: OpenSSLKdf + }), + + /** + * Encrypts a message using a password. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {WordArray|string} message The message to encrypt. + * @param {string} password The password. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {CipherParams} A cipher params object. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password'); + * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL }); + */ + encrypt: function (cipher, message, password, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Derive key and other params + var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, cfg.salt, cfg.hasher); + + // Add IV to config + cfg.iv = derivedParams.iv; + + // Encrypt + var ciphertext = SerializableCipher.encrypt.call(this, cipher, message, derivedParams.key, cfg); + + // Mix in derived params + ciphertext.mixIn(derivedParams); + + return ciphertext; + }, + + /** + * Decrypts serialized ciphertext using a password. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {CipherParams|string} ciphertext The ciphertext to decrypt. + * @param {string} password The password. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {WordArray} The plaintext. + * + * @static + * + * @example + * + * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password', { format: CryptoJS.format.OpenSSL }); + * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, 'password', { format: CryptoJS.format.OpenSSL }); + */ + decrypt: function (cipher, ciphertext, password, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Convert string to CipherParams + ciphertext = this._parse(ciphertext, cfg.format); + + // Derive key and other params + var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt, cfg.hasher); + + // Add IV to config + cfg.iv = derivedParams.iv; + + // Decrypt + var plaintext = SerializableCipher.decrypt.call(this, cipher, ciphertext, derivedParams.key, cfg); + + return plaintext; + } + }); + }()); + + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/core.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/core.js new file mode 100644 index 0000000..e3a498b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/core.js @@ -0,0 +1,807 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(); + } + else if (typeof define === "function" && define.amd) { + // AMD + define([], factory); + } + else { + // Global (browser) + root.CryptoJS = factory(); + } +}(this, function () { + + /*globals window, global, require*/ + + /** + * CryptoJS core components. + */ + var CryptoJS = CryptoJS || (function (Math, undefined) { + + var crypto; + + // Native crypto from window (Browser) + if (typeof window !== 'undefined' && window.crypto) { + crypto = window.crypto; + } + + // Native crypto in web worker (Browser) + if (typeof self !== 'undefined' && self.crypto) { + crypto = self.crypto; + } + + // Native crypto from worker + if (typeof globalThis !== 'undefined' && globalThis.crypto) { + crypto = globalThis.crypto; + } + + // Native (experimental IE 11) crypto from window (Browser) + if (!crypto && typeof window !== 'undefined' && window.msCrypto) { + crypto = window.msCrypto; + } + + // Native crypto from global (NodeJS) + if (!crypto && typeof global !== 'undefined' && global.crypto) { + crypto = global.crypto; + } + + // Native crypto import via require (NodeJS) + if (!crypto && typeof require === 'function') { + try { + crypto = require('crypto'); + } catch (err) {} + } + + /* + * Cryptographically secure pseudorandom number generator + * + * As Math.random() is cryptographically not safe to use + */ + var cryptoSecureRandomInt = function () { + if (crypto) { + // Use getRandomValues method (Browser) + if (typeof crypto.getRandomValues === 'function') { + try { + return crypto.getRandomValues(new Uint32Array(1))[0]; + } catch (err) {} + } + + // Use randomBytes method (NodeJS) + if (typeof crypto.randomBytes === 'function') { + try { + return crypto.randomBytes(4).readInt32LE(); + } catch (err) {} + } + } + + throw new Error('Native crypto module could not be used to get secure random number.'); + }; + + /* + * Local polyfill of Object.create + + */ + var create = Object.create || (function () { + function F() {} + + return function (obj) { + var subtype; + + F.prototype = obj; + + subtype = new F(); + + F.prototype = null; + + return subtype; + }; + }()); + + /** + * CryptoJS namespace. + */ + var C = {}; + + /** + * Library namespace. + */ + var C_lib = C.lib = {}; + + /** + * Base object for prototypal inheritance. + */ + var Base = C_lib.Base = (function () { + + + return { + /** + * Creates a new object that inherits from this object. + * + * @param {Object} overrides Properties to copy into the new object. + * + * @return {Object} The new object. + * + * @static + * + * @example + * + * var MyType = CryptoJS.lib.Base.extend({ + * field: 'value', + * + * method: function () { + * } + * }); + */ + extend: function (overrides) { + // Spawn + var subtype = create(this); + + // Augment + if (overrides) { + subtype.mixIn(overrides); + } + + // Create default initializer + if (!subtype.hasOwnProperty('init') || this.init === subtype.init) { + subtype.init = function () { + subtype.$super.init.apply(this, arguments); + }; + } + + // Initializer's prototype is the subtype object + subtype.init.prototype = subtype; + + // Reference supertype + subtype.$super = this; + + return subtype; + }, + + /** + * Extends this object and runs the init method. + * Arguments to create() will be passed to init(). + * + * @return {Object} The new object. + * + * @static + * + * @example + * + * var instance = MyType.create(); + */ + create: function () { + var instance = this.extend(); + instance.init.apply(instance, arguments); + + return instance; + }, + + /** + * Initializes a newly created object. + * Override this method to add some logic when your objects are created. + * + * @example + * + * var MyType = CryptoJS.lib.Base.extend({ + * init: function () { + * // ... + * } + * }); + */ + init: function () { + }, + + /** + * Copies properties into this object. + * + * @param {Object} properties The properties to mix in. + * + * @example + * + * MyType.mixIn({ + * field: 'value' + * }); + */ + mixIn: function (properties) { + for (var propertyName in properties) { + if (properties.hasOwnProperty(propertyName)) { + this[propertyName] = properties[propertyName]; + } + } + + // IE won't copy toString using the loop above + if (properties.hasOwnProperty('toString')) { + this.toString = properties.toString; + } + }, + + /** + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = instance.clone(); + */ + clone: function () { + return this.init.prototype.extend(this); + } + }; + }()); + + /** + * An array of 32-bit words. + * + * @property {Array} words The array of 32-bit words. + * @property {number} sigBytes The number of significant bytes in this word array. + */ + var WordArray = C_lib.WordArray = Base.extend({ + /** + * Initializes a newly created word array. + * + * @param {Array} words (Optional) An array of 32-bit words. + * @param {number} sigBytes (Optional) The number of significant bytes in the words. + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.create(); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); + */ + init: function (words, sigBytes) { + words = this.words = words || []; + + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 4; + } + }, + + /** + * Converts this word array to a string. + * + * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex + * + * @return {string} The stringified word array. + * + * @example + * + * var string = wordArray + ''; + * var string = wordArray.toString(); + * var string = wordArray.toString(CryptoJS.enc.Utf8); + */ + toString: function (encoder) { + return (encoder || Hex).stringify(this); + }, + + /** + * Concatenates a word array to this word array. + * + * @param {WordArray} wordArray The word array to append. + * + * @return {WordArray} This word array. + * + * @example + * + * wordArray1.concat(wordArray2); + */ + concat: function (wordArray) { + // Shortcuts + var thisWords = this.words; + var thatWords = wordArray.words; + var thisSigBytes = this.sigBytes; + var thatSigBytes = wordArray.sigBytes; + + // Clamp excess bits + this.clamp(); + + // Concat + if (thisSigBytes % 4) { + // Copy one byte at a time + for (var i = 0; i < thatSigBytes; i++) { + var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); + } + } else { + // Copy one word at a time + for (var j = 0; j < thatSigBytes; j += 4) { + thisWords[(thisSigBytes + j) >>> 2] = thatWords[j >>> 2]; + } + } + this.sigBytes += thatSigBytes; + + // Chainable + return this; + }, + + /** + * Removes insignificant bits. + * + * @example + * + * wordArray.clamp(); + */ + clamp: function () { + // Shortcuts + var words = this.words; + var sigBytes = this.sigBytes; + + // Clamp + words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); + words.length = Math.ceil(sigBytes / 4); + }, + + /** + * Creates a copy of this word array. + * + * @return {WordArray} The clone. + * + * @example + * + * var clone = wordArray.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + clone.words = this.words.slice(0); + + return clone; + }, + + /** + * Creates a word array filled with random bytes. + * + * @param {number} nBytes The number of random bytes to generate. + * + * @return {WordArray} The random word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.random(16); + */ + random: function (nBytes) { + var words = []; + + for (var i = 0; i < nBytes; i += 4) { + words.push(cryptoSecureRandomInt()); + } + + return new WordArray.init(words, nBytes); + } + }); + + /** + * Encoder namespace. + */ + var C_enc = C.enc = {}; + + /** + * Hex encoding strategy. + */ + var Hex = C_enc.Hex = { + /** + * Converts a word array to a hex string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The hex string. + * + * @static + * + * @example + * + * var hexString = CryptoJS.enc.Hex.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var hexChars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + hexChars.push((bite >>> 4).toString(16)); + hexChars.push((bite & 0x0f).toString(16)); + } + + return hexChars.join(''); + }, + + /** + * Converts a hex string to a word array. + * + * @param {string} hexStr The hex string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Hex.parse(hexString); + */ + parse: function (hexStr) { + // Shortcut + var hexStrLength = hexStr.length; + + // Convert + var words = []; + for (var i = 0; i < hexStrLength; i += 2) { + words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); + } + + return new WordArray.init(words, hexStrLength / 2); + } + }; + + /** + * Latin1 encoding strategy. + */ + var Latin1 = C_enc.Latin1 = { + /** + * Converts a word array to a Latin1 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The Latin1 string. + * + * @static + * + * @example + * + * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var latin1Chars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + latin1Chars.push(String.fromCharCode(bite)); + } + + return latin1Chars.join(''); + }, + + /** + * Converts a Latin1 string to a word array. + * + * @param {string} latin1Str The Latin1 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Latin1.parse(latin1String); + */ + parse: function (latin1Str) { + // Shortcut + var latin1StrLength = latin1Str.length; + + // Convert + var words = []; + for (var i = 0; i < latin1StrLength; i++) { + words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); + } + + return new WordArray.init(words, latin1StrLength); + } + }; + + /** + * UTF-8 encoding strategy. + */ + var Utf8 = C_enc.Utf8 = { + /** + * Converts a word array to a UTF-8 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-8 string. + * + * @static + * + * @example + * + * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); + */ + stringify: function (wordArray) { + try { + return decodeURIComponent(escape(Latin1.stringify(wordArray))); + } catch (e) { + throw new Error('Malformed UTF-8 data'); + } + }, + + /** + * Converts a UTF-8 string to a word array. + * + * @param {string} utf8Str The UTF-8 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf8.parse(utf8String); + */ + parse: function (utf8Str) { + return Latin1.parse(unescape(encodeURIComponent(utf8Str))); + } + }; + + /** + * Abstract buffered block algorithm template. + * + * The property blockSize must be implemented in a concrete subtype. + * + * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0 + */ + var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ + /** + * Resets this block algorithm's data buffer to its initial state. + * + * @example + * + * bufferedBlockAlgorithm.reset(); + */ + reset: function () { + // Initial values + this._data = new WordArray.init(); + this._nDataBytes = 0; + }, + + /** + * Adds new data to this block algorithm's buffer. + * + * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8. + * + * @example + * + * bufferedBlockAlgorithm._append('data'); + * bufferedBlockAlgorithm._append(wordArray); + */ + _append: function (data) { + // Convert string to WordArray, else assume WordArray already + if (typeof data == 'string') { + data = Utf8.parse(data); + } + + // Append + this._data.concat(data); + this._nDataBytes += data.sigBytes; + }, + + /** + * Processes available data blocks. + * + * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. + * + * @param {boolean} doFlush Whether all blocks and partial blocks should be processed. + * + * @return {WordArray} The processed data. + * + * @example + * + * var processedData = bufferedBlockAlgorithm._process(); + * var processedData = bufferedBlockAlgorithm._process(!!'flush'); + */ + _process: function (doFlush) { + var processedWords; + + // Shortcuts + var data = this._data; + var dataWords = data.words; + var dataSigBytes = data.sigBytes; + var blockSize = this.blockSize; + var blockSizeBytes = blockSize * 4; + + // Count blocks ready + var nBlocksReady = dataSigBytes / blockSizeBytes; + if (doFlush) { + // Round up to include partial blocks + nBlocksReady = Math.ceil(nBlocksReady); + } else { + // Round down to include only full blocks, + // less the number of blocks that must remain in the buffer + nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); + } + + // Count words ready + var nWordsReady = nBlocksReady * blockSize; + + // Count bytes ready + var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); + + // Process blocks + if (nWordsReady) { + for (var offset = 0; offset < nWordsReady; offset += blockSize) { + // Perform concrete-algorithm logic + this._doProcessBlock(dataWords, offset); + } + + // Remove processed words + processedWords = dataWords.splice(0, nWordsReady); + data.sigBytes -= nBytesReady; + } + + // Return processed words + return new WordArray.init(processedWords, nBytesReady); + }, + + /** + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = bufferedBlockAlgorithm.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + clone._data = this._data.clone(); + + return clone; + }, + + _minBufferSize: 0 + }); + + /** + * Abstract hasher template. + * + * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits) + */ + var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ + /** + * Configuration options. + */ + cfg: Base.extend(), + + /** + * Initializes a newly created hasher. + * + * @param {Object} cfg (Optional) The configuration options to use for this hash computation. + * + * @example + * + * var hasher = CryptoJS.algo.SHA256.create(); + */ + init: function (cfg) { + // Apply config defaults + this.cfg = this.cfg.extend(cfg); + + // Set initial values + this.reset(); + }, + + /** + * Resets this hasher to its initial state. + * + * @example + * + * hasher.reset(); + */ + reset: function () { + // Reset data buffer + BufferedBlockAlgorithm.reset.call(this); + + // Perform concrete-hasher logic + this._doReset(); + }, + + /** + * Updates this hasher with a message. + * + * @param {WordArray|string} messageUpdate The message to append. + * + * @return {Hasher} This hasher. + * + * @example + * + * hasher.update('message'); + * hasher.update(wordArray); + */ + update: function (messageUpdate) { + // Append + this._append(messageUpdate); + + // Update the hash + this._process(); + + // Chainable + return this; + }, + + /** + * Finalizes the hash computation. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} messageUpdate (Optional) A final message update. + * + * @return {WordArray} The hash. + * + * @example + * + * var hash = hasher.finalize(); + * var hash = hasher.finalize('message'); + * var hash = hasher.finalize(wordArray); + */ + finalize: function (messageUpdate) { + // Final message update + if (messageUpdate) { + this._append(messageUpdate); + } + + // Perform concrete-hasher logic + var hash = this._doFinalize(); + + return hash; + }, + + blockSize: 512/32, + + /** + * Creates a shortcut function to a hasher's object interface. + * + * @param {Hasher} hasher The hasher to create a helper for. + * + * @return {Function} The shortcut function. + * + * @static + * + * @example + * + * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); + */ + _createHelper: function (hasher) { + return function (message, cfg) { + return new hasher.init(cfg).finalize(message); + }; + }, + + /** + * Creates a shortcut function to the HMAC's object interface. + * + * @param {Hasher} hasher The hasher to use in this HMAC helper. + * + * @return {Function} The shortcut function. + * + * @static + * + * @example + * + * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); + */ + _createHmacHelper: function (hasher) { + return function (message, key) { + return new C_algo.HMAC.init(hasher, key).finalize(message); + }; + } + }); + + /** + * Algorithm namespace. + */ + var C_algo = C.algo = {}; + + return C; + }(Math)); + + + return CryptoJS; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/crypto-js.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/crypto-js.js new file mode 100644 index 0000000..958ee53 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/crypto-js.js @@ -0,0 +1,6657 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(); + } + else if (typeof define === "function" && define.amd) { + // AMD + define([], factory); + } + else { + // Global (browser) + root.CryptoJS = factory(); + } +}(this, function () { + + /*globals window, global, require*/ + + /** + * CryptoJS core components. + */ + var CryptoJS = CryptoJS || (function (Math, undefined) { + + var crypto; + + // Native crypto from window (Browser) + if (typeof window !== 'undefined' && window.crypto) { + crypto = window.crypto; + } + + // Native crypto in web worker (Browser) + if (typeof self !== 'undefined' && self.crypto) { + crypto = self.crypto; + } + + // Native crypto from worker + if (typeof globalThis !== 'undefined' && globalThis.crypto) { + crypto = globalThis.crypto; + } + + // Native (experimental IE 11) crypto from window (Browser) + if (!crypto && typeof window !== 'undefined' && window.msCrypto) { + crypto = window.msCrypto; + } + + // Native crypto from global (NodeJS) + if (!crypto && typeof global !== 'undefined' && global.crypto) { + crypto = global.crypto; + } + + // Native crypto import via require (NodeJS) + if (!crypto && typeof require === 'function') { + try { + crypto = require('crypto'); + } catch (err) {} + } + + /* + * Cryptographically secure pseudorandom number generator + * + * As Math.random() is cryptographically not safe to use + */ + var cryptoSecureRandomInt = function () { + if (crypto) { + // Use getRandomValues method (Browser) + if (typeof crypto.getRandomValues === 'function') { + try { + return crypto.getRandomValues(new Uint32Array(1))[0]; + } catch (err) {} + } + + // Use randomBytes method (NodeJS) + if (typeof crypto.randomBytes === 'function') { + try { + return crypto.randomBytes(4).readInt32LE(); + } catch (err) {} + } + } + + throw new Error('Native crypto module could not be used to get secure random number.'); + }; + + /* + * Local polyfill of Object.create + + */ + var create = Object.create || (function () { + function F() {} + + return function (obj) { + var subtype; + + F.prototype = obj; + + subtype = new F(); + + F.prototype = null; + + return subtype; + }; + }()); + + /** + * CryptoJS namespace. + */ + var C = {}; + + /** + * Library namespace. + */ + var C_lib = C.lib = {}; + + /** + * Base object for prototypal inheritance. + */ + var Base = C_lib.Base = (function () { + + + return { + /** + * Creates a new object that inherits from this object. + * + * @param {Object} overrides Properties to copy into the new object. + * + * @return {Object} The new object. + * + * @static + * + * @example + * + * var MyType = CryptoJS.lib.Base.extend({ + * field: 'value', + * + * method: function () { + * } + * }); + */ + extend: function (overrides) { + // Spawn + var subtype = create(this); + + // Augment + if (overrides) { + subtype.mixIn(overrides); + } + + // Create default initializer + if (!subtype.hasOwnProperty('init') || this.init === subtype.init) { + subtype.init = function () { + subtype.$super.init.apply(this, arguments); + }; + } + + // Initializer's prototype is the subtype object + subtype.init.prototype = subtype; + + // Reference supertype + subtype.$super = this; + + return subtype; + }, + + /** + * Extends this object and runs the init method. + * Arguments to create() will be passed to init(). + * + * @return {Object} The new object. + * + * @static + * + * @example + * + * var instance = MyType.create(); + */ + create: function () { + var instance = this.extend(); + instance.init.apply(instance, arguments); + + return instance; + }, + + /** + * Initializes a newly created object. + * Override this method to add some logic when your objects are created. + * + * @example + * + * var MyType = CryptoJS.lib.Base.extend({ + * init: function () { + * // ... + * } + * }); + */ + init: function () { + }, + + /** + * Copies properties into this object. + * + * @param {Object} properties The properties to mix in. + * + * @example + * + * MyType.mixIn({ + * field: 'value' + * }); + */ + mixIn: function (properties) { + for (var propertyName in properties) { + if (properties.hasOwnProperty(propertyName)) { + this[propertyName] = properties[propertyName]; + } + } + + // IE won't copy toString using the loop above + if (properties.hasOwnProperty('toString')) { + this.toString = properties.toString; + } + }, + + /** + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = instance.clone(); + */ + clone: function () { + return this.init.prototype.extend(this); + } + }; + }()); + + /** + * An array of 32-bit words. + * + * @property {Array} words The array of 32-bit words. + * @property {number} sigBytes The number of significant bytes in this word array. + */ + var WordArray = C_lib.WordArray = Base.extend({ + /** + * Initializes a newly created word array. + * + * @param {Array} words (Optional) An array of 32-bit words. + * @param {number} sigBytes (Optional) The number of significant bytes in the words. + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.create(); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); + */ + init: function (words, sigBytes) { + words = this.words = words || []; + + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 4; + } + }, + + /** + * Converts this word array to a string. + * + * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex + * + * @return {string} The stringified word array. + * + * @example + * + * var string = wordArray + ''; + * var string = wordArray.toString(); + * var string = wordArray.toString(CryptoJS.enc.Utf8); + */ + toString: function (encoder) { + return (encoder || Hex).stringify(this); + }, + + /** + * Concatenates a word array to this word array. + * + * @param {WordArray} wordArray The word array to append. + * + * @return {WordArray} This word array. + * + * @example + * + * wordArray1.concat(wordArray2); + */ + concat: function (wordArray) { + // Shortcuts + var thisWords = this.words; + var thatWords = wordArray.words; + var thisSigBytes = this.sigBytes; + var thatSigBytes = wordArray.sigBytes; + + // Clamp excess bits + this.clamp(); + + // Concat + if (thisSigBytes % 4) { + // Copy one byte at a time + for (var i = 0; i < thatSigBytes; i++) { + var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); + } + } else { + // Copy one word at a time + for (var j = 0; j < thatSigBytes; j += 4) { + thisWords[(thisSigBytes + j) >>> 2] = thatWords[j >>> 2]; + } + } + this.sigBytes += thatSigBytes; + + // Chainable + return this; + }, + + /** + * Removes insignificant bits. + * + * @example + * + * wordArray.clamp(); + */ + clamp: function () { + // Shortcuts + var words = this.words; + var sigBytes = this.sigBytes; + + // Clamp + words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); + words.length = Math.ceil(sigBytes / 4); + }, + + /** + * Creates a copy of this word array. + * + * @return {WordArray} The clone. + * + * @example + * + * var clone = wordArray.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + clone.words = this.words.slice(0); + + return clone; + }, + + /** + * Creates a word array filled with random bytes. + * + * @param {number} nBytes The number of random bytes to generate. + * + * @return {WordArray} The random word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.random(16); + */ + random: function (nBytes) { + var words = []; + + for (var i = 0; i < nBytes; i += 4) { + words.push(cryptoSecureRandomInt()); + } + + return new WordArray.init(words, nBytes); + } + }); + + /** + * Encoder namespace. + */ + var C_enc = C.enc = {}; + + /** + * Hex encoding strategy. + */ + var Hex = C_enc.Hex = { + /** + * Converts a word array to a hex string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The hex string. + * + * @static + * + * @example + * + * var hexString = CryptoJS.enc.Hex.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var hexChars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + hexChars.push((bite >>> 4).toString(16)); + hexChars.push((bite & 0x0f).toString(16)); + } + + return hexChars.join(''); + }, + + /** + * Converts a hex string to a word array. + * + * @param {string} hexStr The hex string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Hex.parse(hexString); + */ + parse: function (hexStr) { + // Shortcut + var hexStrLength = hexStr.length; + + // Convert + var words = []; + for (var i = 0; i < hexStrLength; i += 2) { + words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); + } + + return new WordArray.init(words, hexStrLength / 2); + } + }; + + /** + * Latin1 encoding strategy. + */ + var Latin1 = C_enc.Latin1 = { + /** + * Converts a word array to a Latin1 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The Latin1 string. + * + * @static + * + * @example + * + * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var latin1Chars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + latin1Chars.push(String.fromCharCode(bite)); + } + + return latin1Chars.join(''); + }, + + /** + * Converts a Latin1 string to a word array. + * + * @param {string} latin1Str The Latin1 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Latin1.parse(latin1String); + */ + parse: function (latin1Str) { + // Shortcut + var latin1StrLength = latin1Str.length; + + // Convert + var words = []; + for (var i = 0; i < latin1StrLength; i++) { + words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); + } + + return new WordArray.init(words, latin1StrLength); + } + }; + + /** + * UTF-8 encoding strategy. + */ + var Utf8 = C_enc.Utf8 = { + /** + * Converts a word array to a UTF-8 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-8 string. + * + * @static + * + * @example + * + * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); + */ + stringify: function (wordArray) { + try { + return decodeURIComponent(escape(Latin1.stringify(wordArray))); + } catch (e) { + throw new Error('Malformed UTF-8 data'); + } + }, + + /** + * Converts a UTF-8 string to a word array. + * + * @param {string} utf8Str The UTF-8 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf8.parse(utf8String); + */ + parse: function (utf8Str) { + return Latin1.parse(unescape(encodeURIComponent(utf8Str))); + } + }; + + /** + * Abstract buffered block algorithm template. + * + * The property blockSize must be implemented in a concrete subtype. + * + * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0 + */ + var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ + /** + * Resets this block algorithm's data buffer to its initial state. + * + * @example + * + * bufferedBlockAlgorithm.reset(); + */ + reset: function () { + // Initial values + this._data = new WordArray.init(); + this._nDataBytes = 0; + }, + + /** + * Adds new data to this block algorithm's buffer. + * + * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8. + * + * @example + * + * bufferedBlockAlgorithm._append('data'); + * bufferedBlockAlgorithm._append(wordArray); + */ + _append: function (data) { + // Convert string to WordArray, else assume WordArray already + if (typeof data == 'string') { + data = Utf8.parse(data); + } + + // Append + this._data.concat(data); + this._nDataBytes += data.sigBytes; + }, + + /** + * Processes available data blocks. + * + * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. + * + * @param {boolean} doFlush Whether all blocks and partial blocks should be processed. + * + * @return {WordArray} The processed data. + * + * @example + * + * var processedData = bufferedBlockAlgorithm._process(); + * var processedData = bufferedBlockAlgorithm._process(!!'flush'); + */ + _process: function (doFlush) { + var processedWords; + + // Shortcuts + var data = this._data; + var dataWords = data.words; + var dataSigBytes = data.sigBytes; + var blockSize = this.blockSize; + var blockSizeBytes = blockSize * 4; + + // Count blocks ready + var nBlocksReady = dataSigBytes / blockSizeBytes; + if (doFlush) { + // Round up to include partial blocks + nBlocksReady = Math.ceil(nBlocksReady); + } else { + // Round down to include only full blocks, + // less the number of blocks that must remain in the buffer + nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); + } + + // Count words ready + var nWordsReady = nBlocksReady * blockSize; + + // Count bytes ready + var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); + + // Process blocks + if (nWordsReady) { + for (var offset = 0; offset < nWordsReady; offset += blockSize) { + // Perform concrete-algorithm logic + this._doProcessBlock(dataWords, offset); + } + + // Remove processed words + processedWords = dataWords.splice(0, nWordsReady); + data.sigBytes -= nBytesReady; + } + + // Return processed words + return new WordArray.init(processedWords, nBytesReady); + }, + + /** + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = bufferedBlockAlgorithm.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + clone._data = this._data.clone(); + + return clone; + }, + + _minBufferSize: 0 + }); + + /** + * Abstract hasher template. + * + * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits) + */ + var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ + /** + * Configuration options. + */ + cfg: Base.extend(), + + /** + * Initializes a newly created hasher. + * + * @param {Object} cfg (Optional) The configuration options to use for this hash computation. + * + * @example + * + * var hasher = CryptoJS.algo.SHA256.create(); + */ + init: function (cfg) { + // Apply config defaults + this.cfg = this.cfg.extend(cfg); + + // Set initial values + this.reset(); + }, + + /** + * Resets this hasher to its initial state. + * + * @example + * + * hasher.reset(); + */ + reset: function () { + // Reset data buffer + BufferedBlockAlgorithm.reset.call(this); + + // Perform concrete-hasher logic + this._doReset(); + }, + + /** + * Updates this hasher with a message. + * + * @param {WordArray|string} messageUpdate The message to append. + * + * @return {Hasher} This hasher. + * + * @example + * + * hasher.update('message'); + * hasher.update(wordArray); + */ + update: function (messageUpdate) { + // Append + this._append(messageUpdate); + + // Update the hash + this._process(); + + // Chainable + return this; + }, + + /** + * Finalizes the hash computation. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} messageUpdate (Optional) A final message update. + * + * @return {WordArray} The hash. + * + * @example + * + * var hash = hasher.finalize(); + * var hash = hasher.finalize('message'); + * var hash = hasher.finalize(wordArray); + */ + finalize: function (messageUpdate) { + // Final message update + if (messageUpdate) { + this._append(messageUpdate); + } + + // Perform concrete-hasher logic + var hash = this._doFinalize(); + + return hash; + }, + + blockSize: 512/32, + + /** + * Creates a shortcut function to a hasher's object interface. + * + * @param {Hasher} hasher The hasher to create a helper for. + * + * @return {Function} The shortcut function. + * + * @static + * + * @example + * + * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); + */ + _createHelper: function (hasher) { + return function (message, cfg) { + return new hasher.init(cfg).finalize(message); + }; + }, + + /** + * Creates a shortcut function to the HMAC's object interface. + * + * @param {Hasher} hasher The hasher to use in this HMAC helper. + * + * @return {Function} The shortcut function. + * + * @static + * + * @example + * + * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); + */ + _createHmacHelper: function (hasher) { + return function (message, key) { + return new C_algo.HMAC.init(hasher, key).finalize(message); + }; + } + }); + + /** + * Algorithm namespace. + */ + var C_algo = C.algo = {}; + + return C; + }(Math)); + + + (function (undefined) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var X32WordArray = C_lib.WordArray; + + /** + * x64 namespace. + */ + var C_x64 = C.x64 = {}; + + /** + * A 64-bit word. + */ + var X64Word = C_x64.Word = Base.extend({ + /** + * Initializes a newly created 64-bit word. + * + * @param {number} high The high 32 bits. + * @param {number} low The low 32 bits. + * + * @example + * + * var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607); + */ + init: function (high, low) { + this.high = high; + this.low = low; + } + + /** + * Bitwise NOTs this word. + * + * @return {X64Word} A new x64-Word object after negating. + * + * @example + * + * var negated = x64Word.not(); + */ + // not: function () { + // var high = ~this.high; + // var low = ~this.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise ANDs this word with the passed word. + * + * @param {X64Word} word The x64-Word to AND with this word. + * + * @return {X64Word} A new x64-Word object after ANDing. + * + * @example + * + * var anded = x64Word.and(anotherX64Word); + */ + // and: function (word) { + // var high = this.high & word.high; + // var low = this.low & word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise ORs this word with the passed word. + * + * @param {X64Word} word The x64-Word to OR with this word. + * + * @return {X64Word} A new x64-Word object after ORing. + * + * @example + * + * var ored = x64Word.or(anotherX64Word); + */ + // or: function (word) { + // var high = this.high | word.high; + // var low = this.low | word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise XORs this word with the passed word. + * + * @param {X64Word} word The x64-Word to XOR with this word. + * + * @return {X64Word} A new x64-Word object after XORing. + * + * @example + * + * var xored = x64Word.xor(anotherX64Word); + */ + // xor: function (word) { + // var high = this.high ^ word.high; + // var low = this.low ^ word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Shifts this word n bits to the left. + * + * @param {number} n The number of bits to shift. + * + * @return {X64Word} A new x64-Word object after shifting. + * + * @example + * + * var shifted = x64Word.shiftL(25); + */ + // shiftL: function (n) { + // if (n < 32) { + // var high = (this.high << n) | (this.low >>> (32 - n)); + // var low = this.low << n; + // } else { + // var high = this.low << (n - 32); + // var low = 0; + // } + + // return X64Word.create(high, low); + // }, + + /** + * Shifts this word n bits to the right. + * + * @param {number} n The number of bits to shift. + * + * @return {X64Word} A new x64-Word object after shifting. + * + * @example + * + * var shifted = x64Word.shiftR(7); + */ + // shiftR: function (n) { + // if (n < 32) { + // var low = (this.low >>> n) | (this.high << (32 - n)); + // var high = this.high >>> n; + // } else { + // var low = this.high >>> (n - 32); + // var high = 0; + // } + + // return X64Word.create(high, low); + // }, + + /** + * Rotates this word n bits to the left. + * + * @param {number} n The number of bits to rotate. + * + * @return {X64Word} A new x64-Word object after rotating. + * + * @example + * + * var rotated = x64Word.rotL(25); + */ + // rotL: function (n) { + // return this.shiftL(n).or(this.shiftR(64 - n)); + // }, + + /** + * Rotates this word n bits to the right. + * + * @param {number} n The number of bits to rotate. + * + * @return {X64Word} A new x64-Word object after rotating. + * + * @example + * + * var rotated = x64Word.rotR(7); + */ + // rotR: function (n) { + // return this.shiftR(n).or(this.shiftL(64 - n)); + // }, + + /** + * Adds this word with the passed word. + * + * @param {X64Word} word The x64-Word to add with this word. + * + * @return {X64Word} A new x64-Word object after adding. + * + * @example + * + * var added = x64Word.add(anotherX64Word); + */ + // add: function (word) { + // var low = (this.low + word.low) | 0; + // var carry = (low >>> 0) < (this.low >>> 0) ? 1 : 0; + // var high = (this.high + word.high + carry) | 0; + + // return X64Word.create(high, low); + // } + }); + + /** + * An array of 64-bit words. + * + * @property {Array} words The array of CryptoJS.x64.Word objects. + * @property {number} sigBytes The number of significant bytes in this word array. + */ + var X64WordArray = C_x64.WordArray = Base.extend({ + /** + * Initializes a newly created word array. + * + * @param {Array} words (Optional) An array of CryptoJS.x64.Word objects. + * @param {number} sigBytes (Optional) The number of significant bytes in the words. + * + * @example + * + * var wordArray = CryptoJS.x64.WordArray.create(); + * + * var wordArray = CryptoJS.x64.WordArray.create([ + * CryptoJS.x64.Word.create(0x00010203, 0x04050607), + * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) + * ]); + * + * var wordArray = CryptoJS.x64.WordArray.create([ + * CryptoJS.x64.Word.create(0x00010203, 0x04050607), + * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) + * ], 10); + */ + init: function (words, sigBytes) { + words = this.words = words || []; + + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 8; + } + }, + + /** + * Converts this 64-bit word array to a 32-bit word array. + * + * @return {CryptoJS.lib.WordArray} This word array's data as a 32-bit word array. + * + * @example + * + * var x32WordArray = x64WordArray.toX32(); + */ + toX32: function () { + // Shortcuts + var x64Words = this.words; + var x64WordsLength = x64Words.length; + + // Convert + var x32Words = []; + for (var i = 0; i < x64WordsLength; i++) { + var x64Word = x64Words[i]; + x32Words.push(x64Word.high); + x32Words.push(x64Word.low); + } + + return X32WordArray.create(x32Words, this.sigBytes); + }, + + /** + * Creates a copy of this word array. + * + * @return {X64WordArray} The clone. + * + * @example + * + * var clone = x64WordArray.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + + // Clone "words" array + var words = clone.words = this.words.slice(0); + + // Clone each X64Word object + var wordsLength = words.length; + for (var i = 0; i < wordsLength; i++) { + words[i] = words[i].clone(); + } + + return clone; + } + }); + }()); + + + (function () { + // Check if typed arrays are supported + if (typeof ArrayBuffer != 'function') { + return; + } + + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + + // Reference original init + var superInit = WordArray.init; + + // Augment WordArray.init to handle typed arrays + var subInit = WordArray.init = function (typedArray) { + // Convert buffers to uint8 + if (typedArray instanceof ArrayBuffer) { + typedArray = new Uint8Array(typedArray); + } + + // Convert other array views to uint8 + if ( + typedArray instanceof Int8Array || + (typeof Uint8ClampedArray !== "undefined" && typedArray instanceof Uint8ClampedArray) || + typedArray instanceof Int16Array || + typedArray instanceof Uint16Array || + typedArray instanceof Int32Array || + typedArray instanceof Uint32Array || + typedArray instanceof Float32Array || + typedArray instanceof Float64Array + ) { + typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength); + } + + // Handle Uint8Array + if (typedArray instanceof Uint8Array) { + // Shortcut + var typedArrayByteLength = typedArray.byteLength; + + // Extract bytes + var words = []; + for (var i = 0; i < typedArrayByteLength; i++) { + words[i >>> 2] |= typedArray[i] << (24 - (i % 4) * 8); + } + + // Initialize this word array + superInit.call(this, words, typedArrayByteLength); + } else { + // Else call normal init + superInit.apply(this, arguments); + } + }; + + subInit.prototype = WordArray; + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + + /** + * UTF-16 BE encoding strategy. + */ + var Utf16BE = C_enc.Utf16 = C_enc.Utf16BE = { + /** + * Converts a word array to a UTF-16 BE string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-16 BE string. + * + * @static + * + * @example + * + * var utf16String = CryptoJS.enc.Utf16.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var utf16Chars = []; + for (var i = 0; i < sigBytes; i += 2) { + var codePoint = (words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff; + utf16Chars.push(String.fromCharCode(codePoint)); + } + + return utf16Chars.join(''); + }, + + /** + * Converts a UTF-16 BE string to a word array. + * + * @param {string} utf16Str The UTF-16 BE string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf16.parse(utf16String); + */ + parse: function (utf16Str) { + // Shortcut + var utf16StrLength = utf16Str.length; + + // Convert + var words = []; + for (var i = 0; i < utf16StrLength; i++) { + words[i >>> 1] |= utf16Str.charCodeAt(i) << (16 - (i % 2) * 16); + } + + return WordArray.create(words, utf16StrLength * 2); + } + }; + + /** + * UTF-16 LE encoding strategy. + */ + C_enc.Utf16LE = { + /** + * Converts a word array to a UTF-16 LE string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-16 LE string. + * + * @static + * + * @example + * + * var utf16Str = CryptoJS.enc.Utf16LE.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var utf16Chars = []; + for (var i = 0; i < sigBytes; i += 2) { + var codePoint = swapEndian((words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff); + utf16Chars.push(String.fromCharCode(codePoint)); + } + + return utf16Chars.join(''); + }, + + /** + * Converts a UTF-16 LE string to a word array. + * + * @param {string} utf16Str The UTF-16 LE string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf16LE.parse(utf16Str); + */ + parse: function (utf16Str) { + // Shortcut + var utf16StrLength = utf16Str.length; + + // Convert + var words = []; + for (var i = 0; i < utf16StrLength; i++) { + words[i >>> 1] |= swapEndian(utf16Str.charCodeAt(i) << (16 - (i % 2) * 16)); + } + + return WordArray.create(words, utf16StrLength * 2); + } + }; + + function swapEndian(word) { + return ((word << 8) & 0xff00ff00) | ((word >>> 8) & 0x00ff00ff); + } + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + + /** + * Base64 encoding strategy. + */ + var Base64 = C_enc.Base64 = { + /** + * Converts a word array to a Base64 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The Base64 string. + * + * @static + * + * @example + * + * var base64String = CryptoJS.enc.Base64.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var map = this._map; + + // Clamp excess bits + wordArray.clamp(); + + // Convert + var base64Chars = []; + for (var i = 0; i < sigBytes; i += 3) { + var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; + var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + + var triplet = (byte1 << 16) | (byte2 << 8) | byte3; + + for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { + base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); + } + } + + // Add padding + var paddingChar = map.charAt(64); + if (paddingChar) { + while (base64Chars.length % 4) { + base64Chars.push(paddingChar); + } + } + + return base64Chars.join(''); + }, + + /** + * Converts a Base64 string to a word array. + * + * @param {string} base64Str The Base64 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Base64.parse(base64String); + */ + parse: function (base64Str) { + // Shortcuts + var base64StrLength = base64Str.length; + var map = this._map; + var reverseMap = this._reverseMap; + + if (!reverseMap) { + reverseMap = this._reverseMap = []; + for (var j = 0; j < map.length; j++) { + reverseMap[map.charCodeAt(j)] = j; + } + } + + // Ignore padding + var paddingChar = map.charAt(64); + if (paddingChar) { + var paddingIndex = base64Str.indexOf(paddingChar); + if (paddingIndex !== -1) { + base64StrLength = paddingIndex; + } + } + + // Convert + return parseLoop(base64Str, base64StrLength, reverseMap); + + }, + + _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' + }; + + function parseLoop(base64Str, base64StrLength, reverseMap) { + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2); + var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2); + var bitsCombined = bits1 | bits2; + words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + return WordArray.create(words, nBytes); + } + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + + /** + * Base64url encoding strategy. + */ + var Base64url = C_enc.Base64url = { + /** + * Converts a word array to a Base64url string. + * + * @param {WordArray} wordArray The word array. + * + * @param {boolean} urlSafe Whether to use url safe + * + * @return {string} The Base64url string. + * + * @static + * + * @example + * + * var base64String = CryptoJS.enc.Base64url.stringify(wordArray); + */ + stringify: function (wordArray, urlSafe) { + if (urlSafe === undefined) { + urlSafe = true + } + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var map = urlSafe ? this._safe_map : this._map; + + // Clamp excess bits + wordArray.clamp(); + + // Convert + var base64Chars = []; + for (var i = 0; i < sigBytes; i += 3) { + var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; + var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + + var triplet = (byte1 << 16) | (byte2 << 8) | byte3; + + for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { + base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); + } + } + + // Add padding + var paddingChar = map.charAt(64); + if (paddingChar) { + while (base64Chars.length % 4) { + base64Chars.push(paddingChar); + } + } + + return base64Chars.join(''); + }, + + /** + * Converts a Base64url string to a word array. + * + * @param {string} base64Str The Base64url string. + * + * @param {boolean} urlSafe Whether to use url safe + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Base64url.parse(base64String); + */ + parse: function (base64Str, urlSafe) { + if (urlSafe === undefined) { + urlSafe = true + } + + // Shortcuts + var base64StrLength = base64Str.length; + var map = urlSafe ? this._safe_map : this._map; + var reverseMap = this._reverseMap; + + if (!reverseMap) { + reverseMap = this._reverseMap = []; + for (var j = 0; j < map.length; j++) { + reverseMap[map.charCodeAt(j)] = j; + } + } + + // Ignore padding + var paddingChar = map.charAt(64); + if (paddingChar) { + var paddingIndex = base64Str.indexOf(paddingChar); + if (paddingIndex !== -1) { + base64StrLength = paddingIndex; + } + } + + // Convert + return parseLoop(base64Str, base64StrLength, reverseMap); + + }, + + _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', + _safe_map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', + }; + + function parseLoop(base64Str, base64StrLength, reverseMap) { + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2); + var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2); + var bitsCombined = bits1 | bits2; + words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + return WordArray.create(words, nBytes); + } + }()); + + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Constants table + var T = []; + + // Compute constants + (function () { + for (var i = 0; i < 64; i++) { + T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0; + } + }()); + + /** + * MD5 hash algorithm. + */ + var MD5 = C_algo.MD5 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0x67452301, 0xefcdab89, + 0x98badcfe, 0x10325476 + ]); + }, + + _doProcessBlock: function (M, offset) { + // Swap endian + for (var i = 0; i < 16; i++) { + // Shortcuts + var offset_i = offset + i; + var M_offset_i = M[offset_i]; + + M[offset_i] = ( + (((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) | + (((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00) + ); + } + + // Shortcuts + var H = this._hash.words; + + var M_offset_0 = M[offset + 0]; + var M_offset_1 = M[offset + 1]; + var M_offset_2 = M[offset + 2]; + var M_offset_3 = M[offset + 3]; + var M_offset_4 = M[offset + 4]; + var M_offset_5 = M[offset + 5]; + var M_offset_6 = M[offset + 6]; + var M_offset_7 = M[offset + 7]; + var M_offset_8 = M[offset + 8]; + var M_offset_9 = M[offset + 9]; + var M_offset_10 = M[offset + 10]; + var M_offset_11 = M[offset + 11]; + var M_offset_12 = M[offset + 12]; + var M_offset_13 = M[offset + 13]; + var M_offset_14 = M[offset + 14]; + var M_offset_15 = M[offset + 15]; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + + // Computation + a = FF(a, b, c, d, M_offset_0, 7, T[0]); + d = FF(d, a, b, c, M_offset_1, 12, T[1]); + c = FF(c, d, a, b, M_offset_2, 17, T[2]); + b = FF(b, c, d, a, M_offset_3, 22, T[3]); + a = FF(a, b, c, d, M_offset_4, 7, T[4]); + d = FF(d, a, b, c, M_offset_5, 12, T[5]); + c = FF(c, d, a, b, M_offset_6, 17, T[6]); + b = FF(b, c, d, a, M_offset_7, 22, T[7]); + a = FF(a, b, c, d, M_offset_8, 7, T[8]); + d = FF(d, a, b, c, M_offset_9, 12, T[9]); + c = FF(c, d, a, b, M_offset_10, 17, T[10]); + b = FF(b, c, d, a, M_offset_11, 22, T[11]); + a = FF(a, b, c, d, M_offset_12, 7, T[12]); + d = FF(d, a, b, c, M_offset_13, 12, T[13]); + c = FF(c, d, a, b, M_offset_14, 17, T[14]); + b = FF(b, c, d, a, M_offset_15, 22, T[15]); + + a = GG(a, b, c, d, M_offset_1, 5, T[16]); + d = GG(d, a, b, c, M_offset_6, 9, T[17]); + c = GG(c, d, a, b, M_offset_11, 14, T[18]); + b = GG(b, c, d, a, M_offset_0, 20, T[19]); + a = GG(a, b, c, d, M_offset_5, 5, T[20]); + d = GG(d, a, b, c, M_offset_10, 9, T[21]); + c = GG(c, d, a, b, M_offset_15, 14, T[22]); + b = GG(b, c, d, a, M_offset_4, 20, T[23]); + a = GG(a, b, c, d, M_offset_9, 5, T[24]); + d = GG(d, a, b, c, M_offset_14, 9, T[25]); + c = GG(c, d, a, b, M_offset_3, 14, T[26]); + b = GG(b, c, d, a, M_offset_8, 20, T[27]); + a = GG(a, b, c, d, M_offset_13, 5, T[28]); + d = GG(d, a, b, c, M_offset_2, 9, T[29]); + c = GG(c, d, a, b, M_offset_7, 14, T[30]); + b = GG(b, c, d, a, M_offset_12, 20, T[31]); + + a = HH(a, b, c, d, M_offset_5, 4, T[32]); + d = HH(d, a, b, c, M_offset_8, 11, T[33]); + c = HH(c, d, a, b, M_offset_11, 16, T[34]); + b = HH(b, c, d, a, M_offset_14, 23, T[35]); + a = HH(a, b, c, d, M_offset_1, 4, T[36]); + d = HH(d, a, b, c, M_offset_4, 11, T[37]); + c = HH(c, d, a, b, M_offset_7, 16, T[38]); + b = HH(b, c, d, a, M_offset_10, 23, T[39]); + a = HH(a, b, c, d, M_offset_13, 4, T[40]); + d = HH(d, a, b, c, M_offset_0, 11, T[41]); + c = HH(c, d, a, b, M_offset_3, 16, T[42]); + b = HH(b, c, d, a, M_offset_6, 23, T[43]); + a = HH(a, b, c, d, M_offset_9, 4, T[44]); + d = HH(d, a, b, c, M_offset_12, 11, T[45]); + c = HH(c, d, a, b, M_offset_15, 16, T[46]); + b = HH(b, c, d, a, M_offset_2, 23, T[47]); + + a = II(a, b, c, d, M_offset_0, 6, T[48]); + d = II(d, a, b, c, M_offset_7, 10, T[49]); + c = II(c, d, a, b, M_offset_14, 15, T[50]); + b = II(b, c, d, a, M_offset_5, 21, T[51]); + a = II(a, b, c, d, M_offset_12, 6, T[52]); + d = II(d, a, b, c, M_offset_3, 10, T[53]); + c = II(c, d, a, b, M_offset_10, 15, T[54]); + b = II(b, c, d, a, M_offset_1, 21, T[55]); + a = II(a, b, c, d, M_offset_8, 6, T[56]); + d = II(d, a, b, c, M_offset_15, 10, T[57]); + c = II(c, d, a, b, M_offset_6, 15, T[58]); + b = II(b, c, d, a, M_offset_13, 21, T[59]); + a = II(a, b, c, d, M_offset_4, 6, T[60]); + d = II(d, a, b, c, M_offset_11, 10, T[61]); + c = II(c, d, a, b, M_offset_2, 15, T[62]); + b = II(b, c, d, a, M_offset_9, 21, T[63]); + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + + var nBitsTotalH = Math.floor(nBitsTotal / 0x100000000); + var nBitsTotalL = nBitsTotal; + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = ( + (((nBitsTotalH << 8) | (nBitsTotalH >>> 24)) & 0x00ff00ff) | + (((nBitsTotalH << 24) | (nBitsTotalH >>> 8)) & 0xff00ff00) + ); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = ( + (((nBitsTotalL << 8) | (nBitsTotalL >>> 24)) & 0x00ff00ff) | + (((nBitsTotalL << 24) | (nBitsTotalL >>> 8)) & 0xff00ff00) + ); + + data.sigBytes = (dataWords.length + 1) * 4; + + // Hash final blocks + this._process(); + + // Shortcuts + var hash = this._hash; + var H = hash.words; + + // Swap endian + for (var i = 0; i < 4; i++) { + // Shortcut + var H_i = H[i]; + + H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) | + (((H_i << 24) | (H_i >>> 8)) & 0xff00ff00); + } + + // Return final computed hash + return hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + function FF(a, b, c, d, x, s, t) { + var n = a + ((b & c) | (~b & d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function GG(a, b, c, d, x, s, t) { + var n = a + ((b & d) | (c & ~d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function HH(a, b, c, d, x, s, t) { + var n = a + (b ^ c ^ d) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function II(a, b, c, d, x, s, t) { + var n = a + (c ^ (b | ~d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.MD5('message'); + * var hash = CryptoJS.MD5(wordArray); + */ + C.MD5 = Hasher._createHelper(MD5); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacMD5(message, key); + */ + C.HmacMD5 = Hasher._createHmacHelper(MD5); + }(Math)); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Reusable object + var W = []; + + /** + * SHA-1 hash algorithm. + */ + var SHA1 = C_algo.SHA1 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0x67452301, 0xefcdab89, + 0x98badcfe, 0x10325476, + 0xc3d2e1f0 + ]); + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var H = this._hash.words; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + + // Computation + for (var i = 0; i < 80; i++) { + if (i < 16) { + W[i] = M[offset + i] | 0; + } else { + var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]; + W[i] = (n << 1) | (n >>> 31); + } + + var t = ((a << 5) | (a >>> 27)) + e + W[i]; + if (i < 20) { + t += ((b & c) | (~b & d)) + 0x5a827999; + } else if (i < 40) { + t += (b ^ c ^ d) + 0x6ed9eba1; + } else if (i < 60) { + t += ((b & c) | (b & d) | (c & d)) - 0x70e44324; + } else /* if (i < 80) */ { + t += (b ^ c ^ d) - 0x359d3e2a; + } + + e = d; + d = c; + c = (b << 30) | (b >>> 2); + b = a; + a = t; + } + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + H[4] = (H[4] + e) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Return final computed hash + return this._hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA1('message'); + * var hash = CryptoJS.SHA1(wordArray); + */ + C.SHA1 = Hasher._createHelper(SHA1); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA1(message, key); + */ + C.HmacSHA1 = Hasher._createHmacHelper(SHA1); + }()); + + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Initialization and round constants tables + var H = []; + var K = []; + + // Compute constants + (function () { + function isPrime(n) { + var sqrtN = Math.sqrt(n); + for (var factor = 2; factor <= sqrtN; factor++) { + if (!(n % factor)) { + return false; + } + } + + return true; + } + + function getFractionalBits(n) { + return ((n - (n | 0)) * 0x100000000) | 0; + } + + var n = 2; + var nPrime = 0; + while (nPrime < 64) { + if (isPrime(n)) { + if (nPrime < 8) { + H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2)); + } + K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3)); + + nPrime++; + } + + n++; + } + }()); + + // Reusable object + var W = []; + + /** + * SHA-256 hash algorithm. + */ + var SHA256 = C_algo.SHA256 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init(H.slice(0)); + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var H = this._hash.words; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + var f = H[5]; + var g = H[6]; + var h = H[7]; + + // Computation + for (var i = 0; i < 64; i++) { + if (i < 16) { + W[i] = M[offset + i] | 0; + } else { + var gamma0x = W[i - 15]; + var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ + ((gamma0x << 14) | (gamma0x >>> 18)) ^ + (gamma0x >>> 3); + + var gamma1x = W[i - 2]; + var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ + ((gamma1x << 13) | (gamma1x >>> 19)) ^ + (gamma1x >>> 10); + + W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; + } + + var ch = (e & f) ^ (~e & g); + var maj = (a & b) ^ (a & c) ^ (b & c); + + var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22)); + var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25)); + + var t1 = h + sigma1 + ch + K[i] + W[i]; + var t2 = sigma0 + maj; + + h = g; + g = f; + f = e; + e = (d + t1) | 0; + d = c; + c = b; + b = a; + a = (t1 + t2) | 0; + } + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + H[4] = (H[4] + e) | 0; + H[5] = (H[5] + f) | 0; + H[6] = (H[6] + g) | 0; + H[7] = (H[7] + h) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Return final computed hash + return this._hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA256('message'); + * var hash = CryptoJS.SHA256(wordArray); + */ + C.SHA256 = Hasher._createHelper(SHA256); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA256(message, key); + */ + C.HmacSHA256 = Hasher._createHmacHelper(SHA256); + }(Math)); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_algo = C.algo; + var SHA256 = C_algo.SHA256; + + /** + * SHA-224 hash algorithm. + */ + var SHA224 = C_algo.SHA224 = SHA256.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 + ]); + }, + + _doFinalize: function () { + var hash = SHA256._doFinalize.call(this); + + hash.sigBytes -= 4; + + return hash; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA224('message'); + * var hash = CryptoJS.SHA224(wordArray); + */ + C.SHA224 = SHA256._createHelper(SHA224); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA224(message, key); + */ + C.HmacSHA224 = SHA256._createHmacHelper(SHA224); + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Hasher = C_lib.Hasher; + var C_x64 = C.x64; + var X64Word = C_x64.Word; + var X64WordArray = C_x64.WordArray; + var C_algo = C.algo; + + function X64Word_create() { + return X64Word.create.apply(X64Word, arguments); + } + + // Constants + var K = [ + X64Word_create(0x428a2f98, 0xd728ae22), X64Word_create(0x71374491, 0x23ef65cd), + X64Word_create(0xb5c0fbcf, 0xec4d3b2f), X64Word_create(0xe9b5dba5, 0x8189dbbc), + X64Word_create(0x3956c25b, 0xf348b538), X64Word_create(0x59f111f1, 0xb605d019), + X64Word_create(0x923f82a4, 0xaf194f9b), X64Word_create(0xab1c5ed5, 0xda6d8118), + X64Word_create(0xd807aa98, 0xa3030242), X64Word_create(0x12835b01, 0x45706fbe), + X64Word_create(0x243185be, 0x4ee4b28c), X64Word_create(0x550c7dc3, 0xd5ffb4e2), + X64Word_create(0x72be5d74, 0xf27b896f), X64Word_create(0x80deb1fe, 0x3b1696b1), + X64Word_create(0x9bdc06a7, 0x25c71235), X64Word_create(0xc19bf174, 0xcf692694), + X64Word_create(0xe49b69c1, 0x9ef14ad2), X64Word_create(0xefbe4786, 0x384f25e3), + X64Word_create(0x0fc19dc6, 0x8b8cd5b5), X64Word_create(0x240ca1cc, 0x77ac9c65), + X64Word_create(0x2de92c6f, 0x592b0275), X64Word_create(0x4a7484aa, 0x6ea6e483), + X64Word_create(0x5cb0a9dc, 0xbd41fbd4), X64Word_create(0x76f988da, 0x831153b5), + X64Word_create(0x983e5152, 0xee66dfab), X64Word_create(0xa831c66d, 0x2db43210), + X64Word_create(0xb00327c8, 0x98fb213f), X64Word_create(0xbf597fc7, 0xbeef0ee4), + X64Word_create(0xc6e00bf3, 0x3da88fc2), X64Word_create(0xd5a79147, 0x930aa725), + X64Word_create(0x06ca6351, 0xe003826f), X64Word_create(0x14292967, 0x0a0e6e70), + X64Word_create(0x27b70a85, 0x46d22ffc), X64Word_create(0x2e1b2138, 0x5c26c926), + X64Word_create(0x4d2c6dfc, 0x5ac42aed), X64Word_create(0x53380d13, 0x9d95b3df), + X64Word_create(0x650a7354, 0x8baf63de), X64Word_create(0x766a0abb, 0x3c77b2a8), + X64Word_create(0x81c2c92e, 0x47edaee6), X64Word_create(0x92722c85, 0x1482353b), + X64Word_create(0xa2bfe8a1, 0x4cf10364), X64Word_create(0xa81a664b, 0xbc423001), + X64Word_create(0xc24b8b70, 0xd0f89791), X64Word_create(0xc76c51a3, 0x0654be30), + X64Word_create(0xd192e819, 0xd6ef5218), X64Word_create(0xd6990624, 0x5565a910), + X64Word_create(0xf40e3585, 0x5771202a), X64Word_create(0x106aa070, 0x32bbd1b8), + X64Word_create(0x19a4c116, 0xb8d2d0c8), X64Word_create(0x1e376c08, 0x5141ab53), + X64Word_create(0x2748774c, 0xdf8eeb99), X64Word_create(0x34b0bcb5, 0xe19b48a8), + X64Word_create(0x391c0cb3, 0xc5c95a63), X64Word_create(0x4ed8aa4a, 0xe3418acb), + X64Word_create(0x5b9cca4f, 0x7763e373), X64Word_create(0x682e6ff3, 0xd6b2b8a3), + X64Word_create(0x748f82ee, 0x5defb2fc), X64Word_create(0x78a5636f, 0x43172f60), + X64Word_create(0x84c87814, 0xa1f0ab72), X64Word_create(0x8cc70208, 0x1a6439ec), + X64Word_create(0x90befffa, 0x23631e28), X64Word_create(0xa4506ceb, 0xde82bde9), + X64Word_create(0xbef9a3f7, 0xb2c67915), X64Word_create(0xc67178f2, 0xe372532b), + X64Word_create(0xca273ece, 0xea26619c), X64Word_create(0xd186b8c7, 0x21c0c207), + X64Word_create(0xeada7dd6, 0xcde0eb1e), X64Word_create(0xf57d4f7f, 0xee6ed178), + X64Word_create(0x06f067aa, 0x72176fba), X64Word_create(0x0a637dc5, 0xa2c898a6), + X64Word_create(0x113f9804, 0xbef90dae), X64Word_create(0x1b710b35, 0x131c471b), + X64Word_create(0x28db77f5, 0x23047d84), X64Word_create(0x32caab7b, 0x40c72493), + X64Word_create(0x3c9ebe0a, 0x15c9bebc), X64Word_create(0x431d67c4, 0x9c100d4c), + X64Word_create(0x4cc5d4be, 0xcb3e42b6), X64Word_create(0x597f299c, 0xfc657e2a), + X64Word_create(0x5fcb6fab, 0x3ad6faec), X64Word_create(0x6c44198c, 0x4a475817) + ]; + + // Reusable objects + var W = []; + (function () { + for (var i = 0; i < 80; i++) { + W[i] = X64Word_create(); + } + }()); + + /** + * SHA-512 hash algorithm. + */ + var SHA512 = C_algo.SHA512 = Hasher.extend({ + _doReset: function () { + this._hash = new X64WordArray.init([ + new X64Word.init(0x6a09e667, 0xf3bcc908), new X64Word.init(0xbb67ae85, 0x84caa73b), + new X64Word.init(0x3c6ef372, 0xfe94f82b), new X64Word.init(0xa54ff53a, 0x5f1d36f1), + new X64Word.init(0x510e527f, 0xade682d1), new X64Word.init(0x9b05688c, 0x2b3e6c1f), + new X64Word.init(0x1f83d9ab, 0xfb41bd6b), new X64Word.init(0x5be0cd19, 0x137e2179) + ]); + }, + + _doProcessBlock: function (M, offset) { + // Shortcuts + var H = this._hash.words; + + var H0 = H[0]; + var H1 = H[1]; + var H2 = H[2]; + var H3 = H[3]; + var H4 = H[4]; + var H5 = H[5]; + var H6 = H[6]; + var H7 = H[7]; + + var H0h = H0.high; + var H0l = H0.low; + var H1h = H1.high; + var H1l = H1.low; + var H2h = H2.high; + var H2l = H2.low; + var H3h = H3.high; + var H3l = H3.low; + var H4h = H4.high; + var H4l = H4.low; + var H5h = H5.high; + var H5l = H5.low; + var H6h = H6.high; + var H6l = H6.low; + var H7h = H7.high; + var H7l = H7.low; + + // Working variables + var ah = H0h; + var al = H0l; + var bh = H1h; + var bl = H1l; + var ch = H2h; + var cl = H2l; + var dh = H3h; + var dl = H3l; + var eh = H4h; + var el = H4l; + var fh = H5h; + var fl = H5l; + var gh = H6h; + var gl = H6l; + var hh = H7h; + var hl = H7l; + + // Rounds + for (var i = 0; i < 80; i++) { + var Wil; + var Wih; + + // Shortcut + var Wi = W[i]; + + // Extend message + if (i < 16) { + Wih = Wi.high = M[offset + i * 2] | 0; + Wil = Wi.low = M[offset + i * 2 + 1] | 0; + } else { + // Gamma0 + var gamma0x = W[i - 15]; + var gamma0xh = gamma0x.high; + var gamma0xl = gamma0x.low; + var gamma0h = ((gamma0xh >>> 1) | (gamma0xl << 31)) ^ ((gamma0xh >>> 8) | (gamma0xl << 24)) ^ (gamma0xh >>> 7); + var gamma0l = ((gamma0xl >>> 1) | (gamma0xh << 31)) ^ ((gamma0xl >>> 8) | (gamma0xh << 24)) ^ ((gamma0xl >>> 7) | (gamma0xh << 25)); + + // Gamma1 + var gamma1x = W[i - 2]; + var gamma1xh = gamma1x.high; + var gamma1xl = gamma1x.low; + var gamma1h = ((gamma1xh >>> 19) | (gamma1xl << 13)) ^ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^ (gamma1xh >>> 6); + var gamma1l = ((gamma1xl >>> 19) | (gamma1xh << 13)) ^ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^ ((gamma1xl >>> 6) | (gamma1xh << 26)); + + // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16] + var Wi7 = W[i - 7]; + var Wi7h = Wi7.high; + var Wi7l = Wi7.low; + + var Wi16 = W[i - 16]; + var Wi16h = Wi16.high; + var Wi16l = Wi16.low; + + Wil = gamma0l + Wi7l; + Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0); + Wil = Wil + gamma1l; + Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0); + Wil = Wil + Wi16l; + Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0); + + Wi.high = Wih; + Wi.low = Wil; + } + + var chh = (eh & fh) ^ (~eh & gh); + var chl = (el & fl) ^ (~el & gl); + var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch); + var majl = (al & bl) ^ (al & cl) ^ (bl & cl); + + var sigma0h = ((ah >>> 28) | (al << 4)) ^ ((ah << 30) | (al >>> 2)) ^ ((ah << 25) | (al >>> 7)); + var sigma0l = ((al >>> 28) | (ah << 4)) ^ ((al << 30) | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7)); + var sigma1h = ((eh >>> 14) | (el << 18)) ^ ((eh >>> 18) | (el << 14)) ^ ((eh << 23) | (el >>> 9)); + var sigma1l = ((el >>> 14) | (eh << 18)) ^ ((el >>> 18) | (eh << 14)) ^ ((el << 23) | (eh >>> 9)); + + // t1 = h + sigma1 + ch + K[i] + W[i] + var Ki = K[i]; + var Kih = Ki.high; + var Kil = Ki.low; + + var t1l = hl + sigma1l; + var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0); + var t1l = t1l + chl; + var t1h = t1h + chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0); + var t1l = t1l + Kil; + var t1h = t1h + Kih + ((t1l >>> 0) < (Kil >>> 0) ? 1 : 0); + var t1l = t1l + Wil; + var t1h = t1h + Wih + ((t1l >>> 0) < (Wil >>> 0) ? 1 : 0); + + // t2 = sigma0 + maj + var t2l = sigma0l + majl; + var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0); + + // Update working variables + hh = gh; + hl = gl; + gh = fh; + gl = fl; + fh = eh; + fl = el; + el = (dl + t1l) | 0; + eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0; + dh = ch; + dl = cl; + ch = bh; + cl = bl; + bh = ah; + bl = al; + al = (t1l + t2l) | 0; + ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0; + } + + // Intermediate hash value + H0l = H0.low = (H0l + al); + H0.high = (H0h + ah + ((H0l >>> 0) < (al >>> 0) ? 1 : 0)); + H1l = H1.low = (H1l + bl); + H1.high = (H1h + bh + ((H1l >>> 0) < (bl >>> 0) ? 1 : 0)); + H2l = H2.low = (H2l + cl); + H2.high = (H2h + ch + ((H2l >>> 0) < (cl >>> 0) ? 1 : 0)); + H3l = H3.low = (H3l + dl); + H3.high = (H3h + dh + ((H3l >>> 0) < (dl >>> 0) ? 1 : 0)); + H4l = H4.low = (H4l + el); + H4.high = (H4h + eh + ((H4l >>> 0) < (el >>> 0) ? 1 : 0)); + H5l = H5.low = (H5l + fl); + H5.high = (H5h + fh + ((H5l >>> 0) < (fl >>> 0) ? 1 : 0)); + H6l = H6.low = (H6l + gl); + H6.high = (H6h + gh + ((H6l >>> 0) < (gl >>> 0) ? 1 : 0)); + H7l = H7.low = (H7l + hl); + H7.high = (H7h + hh + ((H7l >>> 0) < (hl >>> 0) ? 1 : 0)); + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 30] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 31] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Convert hash to 32-bit word array before returning + var hash = this._hash.toX32(); + + // Return final computed hash + return hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + }, + + blockSize: 1024/32 + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA512('message'); + * var hash = CryptoJS.SHA512(wordArray); + */ + C.SHA512 = Hasher._createHelper(SHA512); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA512(message, key); + */ + C.HmacSHA512 = Hasher._createHmacHelper(SHA512); + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_x64 = C.x64; + var X64Word = C_x64.Word; + var X64WordArray = C_x64.WordArray; + var C_algo = C.algo; + var SHA512 = C_algo.SHA512; + + /** + * SHA-384 hash algorithm. + */ + var SHA384 = C_algo.SHA384 = SHA512.extend({ + _doReset: function () { + this._hash = new X64WordArray.init([ + new X64Word.init(0xcbbb9d5d, 0xc1059ed8), new X64Word.init(0x629a292a, 0x367cd507), + new X64Word.init(0x9159015a, 0x3070dd17), new X64Word.init(0x152fecd8, 0xf70e5939), + new X64Word.init(0x67332667, 0xffc00b31), new X64Word.init(0x8eb44a87, 0x68581511), + new X64Word.init(0xdb0c2e0d, 0x64f98fa7), new X64Word.init(0x47b5481d, 0xbefa4fa4) + ]); + }, + + _doFinalize: function () { + var hash = SHA512._doFinalize.call(this); + + hash.sigBytes -= 16; + + return hash; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA384('message'); + * var hash = CryptoJS.SHA384(wordArray); + */ + C.SHA384 = SHA512._createHelper(SHA384); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA384(message, key); + */ + C.HmacSHA384 = SHA512._createHmacHelper(SHA384); + }()); + + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_x64 = C.x64; + var X64Word = C_x64.Word; + var C_algo = C.algo; + + // Constants tables + var RHO_OFFSETS = []; + var PI_INDEXES = []; + var ROUND_CONSTANTS = []; + + // Compute Constants + (function () { + // Compute rho offset constants + var x = 1, y = 0; + for (var t = 0; t < 24; t++) { + RHO_OFFSETS[x + 5 * y] = ((t + 1) * (t + 2) / 2) % 64; + + var newX = y % 5; + var newY = (2 * x + 3 * y) % 5; + x = newX; + y = newY; + } + + // Compute pi index constants + for (var x = 0; x < 5; x++) { + for (var y = 0; y < 5; y++) { + PI_INDEXES[x + 5 * y] = y + ((2 * x + 3 * y) % 5) * 5; + } + } + + // Compute round constants + var LFSR = 0x01; + for (var i = 0; i < 24; i++) { + var roundConstantMsw = 0; + var roundConstantLsw = 0; + + for (var j = 0; j < 7; j++) { + if (LFSR & 0x01) { + var bitPosition = (1 << j) - 1; + if (bitPosition < 32) { + roundConstantLsw ^= 1 << bitPosition; + } else /* if (bitPosition >= 32) */ { + roundConstantMsw ^= 1 << (bitPosition - 32); + } + } + + // Compute next LFSR + if (LFSR & 0x80) { + // Primitive polynomial over GF(2): x^8 + x^6 + x^5 + x^4 + 1 + LFSR = (LFSR << 1) ^ 0x71; + } else { + LFSR <<= 1; + } + } + + ROUND_CONSTANTS[i] = X64Word.create(roundConstantMsw, roundConstantLsw); + } + }()); + + // Reusable objects for temporary values + var T = []; + (function () { + for (var i = 0; i < 25; i++) { + T[i] = X64Word.create(); + } + }()); + + /** + * SHA-3 hash algorithm. + */ + var SHA3 = C_algo.SHA3 = Hasher.extend({ + /** + * Configuration options. + * + * @property {number} outputLength + * The desired number of bits in the output hash. + * Only values permitted are: 224, 256, 384, 512. + * Default: 512 + */ + cfg: Hasher.cfg.extend({ + outputLength: 512 + }), + + _doReset: function () { + var state = this._state = [] + for (var i = 0; i < 25; i++) { + state[i] = new X64Word.init(); + } + + this.blockSize = (1600 - 2 * this.cfg.outputLength) / 32; + }, + + _doProcessBlock: function (M, offset) { + // Shortcuts + var state = this._state; + var nBlockSizeLanes = this.blockSize / 2; + + // Absorb + for (var i = 0; i < nBlockSizeLanes; i++) { + // Shortcuts + var M2i = M[offset + 2 * i]; + var M2i1 = M[offset + 2 * i + 1]; + + // Swap endian + M2i = ( + (((M2i << 8) | (M2i >>> 24)) & 0x00ff00ff) | + (((M2i << 24) | (M2i >>> 8)) & 0xff00ff00) + ); + M2i1 = ( + (((M2i1 << 8) | (M2i1 >>> 24)) & 0x00ff00ff) | + (((M2i1 << 24) | (M2i1 >>> 8)) & 0xff00ff00) + ); + + // Absorb message into state + var lane = state[i]; + lane.high ^= M2i1; + lane.low ^= M2i; + } + + // Rounds + for (var round = 0; round < 24; round++) { + // Theta + for (var x = 0; x < 5; x++) { + // Mix column lanes + var tMsw = 0, tLsw = 0; + for (var y = 0; y < 5; y++) { + var lane = state[x + 5 * y]; + tMsw ^= lane.high; + tLsw ^= lane.low; + } + + // Temporary values + var Tx = T[x]; + Tx.high = tMsw; + Tx.low = tLsw; + } + for (var x = 0; x < 5; x++) { + // Shortcuts + var Tx4 = T[(x + 4) % 5]; + var Tx1 = T[(x + 1) % 5]; + var Tx1Msw = Tx1.high; + var Tx1Lsw = Tx1.low; + + // Mix surrounding columns + var tMsw = Tx4.high ^ ((Tx1Msw << 1) | (Tx1Lsw >>> 31)); + var tLsw = Tx4.low ^ ((Tx1Lsw << 1) | (Tx1Msw >>> 31)); + for (var y = 0; y < 5; y++) { + var lane = state[x + 5 * y]; + lane.high ^= tMsw; + lane.low ^= tLsw; + } + } + + // Rho Pi + for (var laneIndex = 1; laneIndex < 25; laneIndex++) { + var tMsw; + var tLsw; + + // Shortcuts + var lane = state[laneIndex]; + var laneMsw = lane.high; + var laneLsw = lane.low; + var rhoOffset = RHO_OFFSETS[laneIndex]; + + // Rotate lanes + if (rhoOffset < 32) { + tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset)); + tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset)); + } else /* if (rhoOffset >= 32) */ { + tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset)); + tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset)); + } + + // Transpose lanes + var TPiLane = T[PI_INDEXES[laneIndex]]; + TPiLane.high = tMsw; + TPiLane.low = tLsw; + } + + // Rho pi at x = y = 0 + var T0 = T[0]; + var state0 = state[0]; + T0.high = state0.high; + T0.low = state0.low; + + // Chi + for (var x = 0; x < 5; x++) { + for (var y = 0; y < 5; y++) { + // Shortcuts + var laneIndex = x + 5 * y; + var lane = state[laneIndex]; + var TLane = T[laneIndex]; + var Tx1Lane = T[((x + 1) % 5) + 5 * y]; + var Tx2Lane = T[((x + 2) % 5) + 5 * y]; + + // Mix rows + lane.high = TLane.high ^ (~Tx1Lane.high & Tx2Lane.high); + lane.low = TLane.low ^ (~Tx1Lane.low & Tx2Lane.low); + } + } + + // Iota + var lane = state[0]; + var roundConstant = ROUND_CONSTANTS[round]; + lane.high ^= roundConstant.high; + lane.low ^= roundConstant.low; + } + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + var blockSizeBits = this.blockSize * 32; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x1 << (24 - nBitsLeft % 32); + dataWords[((Math.ceil((nBitsLeft + 1) / blockSizeBits) * blockSizeBits) >>> 5) - 1] |= 0x80; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Shortcuts + var state = this._state; + var outputLengthBytes = this.cfg.outputLength / 8; + var outputLengthLanes = outputLengthBytes / 8; + + // Squeeze + var hashWords = []; + for (var i = 0; i < outputLengthLanes; i++) { + // Shortcuts + var lane = state[i]; + var laneMsw = lane.high; + var laneLsw = lane.low; + + // Swap endian + laneMsw = ( + (((laneMsw << 8) | (laneMsw >>> 24)) & 0x00ff00ff) | + (((laneMsw << 24) | (laneMsw >>> 8)) & 0xff00ff00) + ); + laneLsw = ( + (((laneLsw << 8) | (laneLsw >>> 24)) & 0x00ff00ff) | + (((laneLsw << 24) | (laneLsw >>> 8)) & 0xff00ff00) + ); + + // Squeeze state to retrieve hash + hashWords.push(laneLsw); + hashWords.push(laneMsw); + } + + // Return final computed hash + return new WordArray.init(hashWords, outputLengthBytes); + }, + + clone: function () { + var clone = Hasher.clone.call(this); + + var state = clone._state = this._state.slice(0); + for (var i = 0; i < 25; i++) { + state[i] = state[i].clone(); + } + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA3('message'); + * var hash = CryptoJS.SHA3(wordArray); + */ + C.SHA3 = Hasher._createHelper(SHA3); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA3(message, key); + */ + C.HmacSHA3 = Hasher._createHmacHelper(SHA3); + }(Math)); + + + /** @preserve + (c) 2012 by Cédric Mesnil. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Constants table + var _zl = WordArray.create([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13]); + var _zr = WordArray.create([ + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11]); + var _sl = WordArray.create([ + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 ]); + var _sr = WordArray.create([ + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 ]); + + var _hl = WordArray.create([ 0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E]); + var _hr = WordArray.create([ 0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000]); + + /** + * RIPEMD160 hash algorithm. + */ + var RIPEMD160 = C_algo.RIPEMD160 = Hasher.extend({ + _doReset: function () { + this._hash = WordArray.create([0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]); + }, + + _doProcessBlock: function (M, offset) { + + // Swap endian + for (var i = 0; i < 16; i++) { + // Shortcuts + var offset_i = offset + i; + var M_offset_i = M[offset_i]; + + // Swap + M[offset_i] = ( + (((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) | + (((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00) + ); + } + // Shortcut + var H = this._hash.words; + var hl = _hl.words; + var hr = _hr.words; + var zl = _zl.words; + var zr = _zr.words; + var sl = _sl.words; + var sr = _sr.words; + + // Working variables + var al, bl, cl, dl, el; + var ar, br, cr, dr, er; + + ar = al = H[0]; + br = bl = H[1]; + cr = cl = H[2]; + dr = dl = H[3]; + er = el = H[4]; + // Computation + var t; + for (var i = 0; i < 80; i += 1) { + t = (al + M[offset+zl[i]])|0; + if (i<16){ + t += f1(bl,cl,dl) + hl[0]; + } else if (i<32) { + t += f2(bl,cl,dl) + hl[1]; + } else if (i<48) { + t += f3(bl,cl,dl) + hl[2]; + } else if (i<64) { + t += f4(bl,cl,dl) + hl[3]; + } else {// if (i<80) { + t += f5(bl,cl,dl) + hl[4]; + } + t = t|0; + t = rotl(t,sl[i]); + t = (t+el)|0; + al = el; + el = dl; + dl = rotl(cl, 10); + cl = bl; + bl = t; + + t = (ar + M[offset+zr[i]])|0; + if (i<16){ + t += f5(br,cr,dr) + hr[0]; + } else if (i<32) { + t += f4(br,cr,dr) + hr[1]; + } else if (i<48) { + t += f3(br,cr,dr) + hr[2]; + } else if (i<64) { + t += f2(br,cr,dr) + hr[3]; + } else {// if (i<80) { + t += f1(br,cr,dr) + hr[4]; + } + t = t|0; + t = rotl(t,sr[i]) ; + t = (t+er)|0; + ar = er; + er = dr; + dr = rotl(cr, 10); + cr = br; + br = t; + } + // Intermediate hash value + t = (H[1] + cl + dr)|0; + H[1] = (H[2] + dl + er)|0; + H[2] = (H[3] + el + ar)|0; + H[3] = (H[4] + al + br)|0; + H[4] = (H[0] + bl + cr)|0; + H[0] = t; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = ( + (((nBitsTotal << 8) | (nBitsTotal >>> 24)) & 0x00ff00ff) | + (((nBitsTotal << 24) | (nBitsTotal >>> 8)) & 0xff00ff00) + ); + data.sigBytes = (dataWords.length + 1) * 4; + + // Hash final blocks + this._process(); + + // Shortcuts + var hash = this._hash; + var H = hash.words; + + // Swap endian + for (var i = 0; i < 5; i++) { + // Shortcut + var H_i = H[i]; + + // Swap + H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) | + (((H_i << 24) | (H_i >>> 8)) & 0xff00ff00); + } + + // Return final computed hash + return hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + + function f1(x, y, z) { + return ((x) ^ (y) ^ (z)); + + } + + function f2(x, y, z) { + return (((x)&(y)) | ((~x)&(z))); + } + + function f3(x, y, z) { + return (((x) | (~(y))) ^ (z)); + } + + function f4(x, y, z) { + return (((x) & (z)) | ((y)&(~(z)))); + } + + function f5(x, y, z) { + return ((x) ^ ((y) |(~(z)))); + + } + + function rotl(x,n) { + return (x<>>(32-n)); + } + + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.RIPEMD160('message'); + * var hash = CryptoJS.RIPEMD160(wordArray); + */ + C.RIPEMD160 = Hasher._createHelper(RIPEMD160); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacRIPEMD160(message, key); + */ + C.HmacRIPEMD160 = Hasher._createHmacHelper(RIPEMD160); + }(Math)); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var C_enc = C.enc; + var Utf8 = C_enc.Utf8; + var C_algo = C.algo; + + /** + * HMAC algorithm. + */ + var HMAC = C_algo.HMAC = Base.extend({ + /** + * Initializes a newly created HMAC. + * + * @param {Hasher} hasher The hash algorithm to use. + * @param {WordArray|string} key The secret key. + * + * @example + * + * var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key); + */ + init: function (hasher, key) { + // Init hasher + hasher = this._hasher = new hasher.init(); + + // Convert string to WordArray, else assume WordArray already + if (typeof key == 'string') { + key = Utf8.parse(key); + } + + // Shortcuts + var hasherBlockSize = hasher.blockSize; + var hasherBlockSizeBytes = hasherBlockSize * 4; + + // Allow arbitrary length keys + if (key.sigBytes > hasherBlockSizeBytes) { + key = hasher.finalize(key); + } + + // Clamp excess bits + key.clamp(); + + // Clone key for inner and outer pads + var oKey = this._oKey = key.clone(); + var iKey = this._iKey = key.clone(); + + // Shortcuts + var oKeyWords = oKey.words; + var iKeyWords = iKey.words; + + // XOR keys with pad constants + for (var i = 0; i < hasherBlockSize; i++) { + oKeyWords[i] ^= 0x5c5c5c5c; + iKeyWords[i] ^= 0x36363636; + } + oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes; + + // Set initial values + this.reset(); + }, + + /** + * Resets this HMAC to its initial state. + * + * @example + * + * hmacHasher.reset(); + */ + reset: function () { + // Shortcut + var hasher = this._hasher; + + // Reset + hasher.reset(); + hasher.update(this._iKey); + }, + + /** + * Updates this HMAC with a message. + * + * @param {WordArray|string} messageUpdate The message to append. + * + * @return {HMAC} This HMAC instance. + * + * @example + * + * hmacHasher.update('message'); + * hmacHasher.update(wordArray); + */ + update: function (messageUpdate) { + this._hasher.update(messageUpdate); + + // Chainable + return this; + }, + + /** + * Finalizes the HMAC computation. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} messageUpdate (Optional) A final message update. + * + * @return {WordArray} The HMAC. + * + * @example + * + * var hmac = hmacHasher.finalize(); + * var hmac = hmacHasher.finalize('message'); + * var hmac = hmacHasher.finalize(wordArray); + */ + finalize: function (messageUpdate) { + // Shortcut + var hasher = this._hasher; + + // Compute HMAC + var innerHash = hasher.finalize(messageUpdate); + hasher.reset(); + var hmac = hasher.finalize(this._oKey.clone().concat(innerHash)); + + return hmac; + } + }); + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var WordArray = C_lib.WordArray; + var C_algo = C.algo; + var SHA256 = C_algo.SHA256; + var HMAC = C_algo.HMAC; + + /** + * Password-Based Key Derivation Function 2 algorithm. + */ + var PBKDF2 = C_algo.PBKDF2 = Base.extend({ + /** + * Configuration options. + * + * @property {number} keySize The key size in words to generate. Default: 4 (128 bits) + * @property {Hasher} hasher The hasher to use. Default: SHA256 + * @property {number} iterations The number of iterations to perform. Default: 250000 + */ + cfg: Base.extend({ + keySize: 128/32, + hasher: SHA256, + iterations: 250000 + }), + + /** + * Initializes a newly created key derivation function. + * + * @param {Object} cfg (Optional) The configuration options to use for the derivation. + * + * @example + * + * var kdf = CryptoJS.algo.PBKDF2.create(); + * var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8 }); + * var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8, iterations: 1000 }); + */ + init: function (cfg) { + this.cfg = this.cfg.extend(cfg); + }, + + /** + * Computes the Password-Based Key Derivation Function 2. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * + * @return {WordArray} The derived key. + * + * @example + * + * var key = kdf.compute(password, salt); + */ + compute: function (password, salt) { + // Shortcut + var cfg = this.cfg; + + // Init HMAC + var hmac = HMAC.create(cfg.hasher, password); + + // Initial values + var derivedKey = WordArray.create(); + var blockIndex = WordArray.create([0x00000001]); + + // Shortcuts + var derivedKeyWords = derivedKey.words; + var blockIndexWords = blockIndex.words; + var keySize = cfg.keySize; + var iterations = cfg.iterations; + + // Generate key + while (derivedKeyWords.length < keySize) { + var block = hmac.update(salt).finalize(blockIndex); + hmac.reset(); + + // Shortcuts + var blockWords = block.words; + var blockWordsLength = blockWords.length; + + // Iterations + var intermediate = block; + for (var i = 1; i < iterations; i++) { + intermediate = hmac.finalize(intermediate); + hmac.reset(); + + // Shortcut + var intermediateWords = intermediate.words; + + // XOR intermediate with block + for (var j = 0; j < blockWordsLength; j++) { + blockWords[j] ^= intermediateWords[j]; + } + } + + derivedKey.concat(block); + blockIndexWords[0]++; + } + derivedKey.sigBytes = keySize * 4; + + return derivedKey; + } + }); + + /** + * Computes the Password-Based Key Derivation Function 2. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * @param {Object} cfg (Optional) The configuration options to use for this computation. + * + * @return {WordArray} The derived key. + * + * @static + * + * @example + * + * var key = CryptoJS.PBKDF2(password, salt); + * var key = CryptoJS.PBKDF2(password, salt, { keySize: 8 }); + * var key = CryptoJS.PBKDF2(password, salt, { keySize: 8, iterations: 1000 }); + */ + C.PBKDF2 = function (password, salt, cfg) { + return PBKDF2.create(cfg).compute(password, salt); + }; + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var WordArray = C_lib.WordArray; + var C_algo = C.algo; + var MD5 = C_algo.MD5; + + /** + * This key derivation function is meant to conform with EVP_BytesToKey. + * www.openssl.org/docs/crypto/EVP_BytesToKey.html + */ + var EvpKDF = C_algo.EvpKDF = Base.extend({ + /** + * Configuration options. + * + * @property {number} keySize The key size in words to generate. Default: 4 (128 bits) + * @property {Hasher} hasher The hash algorithm to use. Default: MD5 + * @property {number} iterations The number of iterations to perform. Default: 1 + */ + cfg: Base.extend({ + keySize: 128/32, + hasher: MD5, + iterations: 1 + }), + + /** + * Initializes a newly created key derivation function. + * + * @param {Object} cfg (Optional) The configuration options to use for the derivation. + * + * @example + * + * var kdf = CryptoJS.algo.EvpKDF.create(); + * var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8 }); + * var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8, iterations: 1000 }); + */ + init: function (cfg) { + this.cfg = this.cfg.extend(cfg); + }, + + /** + * Derives a key from a password. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * + * @return {WordArray} The derived key. + * + * @example + * + * var key = kdf.compute(password, salt); + */ + compute: function (password, salt) { + var block; + + // Shortcut + var cfg = this.cfg; + + // Init hasher + var hasher = cfg.hasher.create(); + + // Initial values + var derivedKey = WordArray.create(); + + // Shortcuts + var derivedKeyWords = derivedKey.words; + var keySize = cfg.keySize; + var iterations = cfg.iterations; + + // Generate key + while (derivedKeyWords.length < keySize) { + if (block) { + hasher.update(block); + } + block = hasher.update(password).finalize(salt); + hasher.reset(); + + // Iterations + for (var i = 1; i < iterations; i++) { + block = hasher.finalize(block); + hasher.reset(); + } + + derivedKey.concat(block); + } + derivedKey.sigBytes = keySize * 4; + + return derivedKey; + } + }); + + /** + * Derives a key from a password. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * @param {Object} cfg (Optional) The configuration options to use for this computation. + * + * @return {WordArray} The derived key. + * + * @static + * + * @example + * + * var key = CryptoJS.EvpKDF(password, salt); + * var key = CryptoJS.EvpKDF(password, salt, { keySize: 8 }); + * var key = CryptoJS.EvpKDF(password, salt, { keySize: 8, iterations: 1000 }); + */ + C.EvpKDF = function (password, salt, cfg) { + return EvpKDF.create(cfg).compute(password, salt); + }; + }()); + + + /** + * Cipher core components. + */ + CryptoJS.lib.Cipher || (function (undefined) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var WordArray = C_lib.WordArray; + var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm; + var C_enc = C.enc; + var Utf8 = C_enc.Utf8; + var Base64 = C_enc.Base64; + var C_algo = C.algo; + var EvpKDF = C_algo.EvpKDF; + + /** + * Abstract base cipher template. + * + * @property {number} keySize This cipher's key size. Default: 4 (128 bits) + * @property {number} ivSize This cipher's IV size. Default: 4 (128 bits) + * @property {number} _ENC_XFORM_MODE A constant representing encryption mode. + * @property {number} _DEC_XFORM_MODE A constant representing decryption mode. + */ + var Cipher = C_lib.Cipher = BufferedBlockAlgorithm.extend({ + /** + * Configuration options. + * + * @property {WordArray} iv The IV to use for this operation. + */ + cfg: Base.extend(), + + /** + * Creates this cipher in encryption mode. + * + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {Cipher} A cipher instance. + * + * @static + * + * @example + * + * var cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray }); + */ + createEncryptor: function (key, cfg) { + return this.create(this._ENC_XFORM_MODE, key, cfg); + }, + + /** + * Creates this cipher in decryption mode. + * + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {Cipher} A cipher instance. + * + * @static + * + * @example + * + * var cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray }); + */ + createDecryptor: function (key, cfg) { + return this.create(this._DEC_XFORM_MODE, key, cfg); + }, + + /** + * Initializes a newly created cipher. + * + * @param {number} xformMode Either the encryption or decryption transormation mode constant. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @example + * + * var cipher = CryptoJS.algo.AES.create(CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray }); + */ + init: function (xformMode, key, cfg) { + // Apply config defaults + this.cfg = this.cfg.extend(cfg); + + // Store transform mode and key + this._xformMode = xformMode; + this._key = key; + + // Set initial values + this.reset(); + }, + + /** + * Resets this cipher to its initial state. + * + * @example + * + * cipher.reset(); + */ + reset: function () { + // Reset data buffer + BufferedBlockAlgorithm.reset.call(this); + + // Perform concrete-cipher logic + this._doReset(); + }, + + /** + * Adds data to be encrypted or decrypted. + * + * @param {WordArray|string} dataUpdate The data to encrypt or decrypt. + * + * @return {WordArray} The data after processing. + * + * @example + * + * var encrypted = cipher.process('data'); + * var encrypted = cipher.process(wordArray); + */ + process: function (dataUpdate) { + // Append + this._append(dataUpdate); + + // Process available blocks + return this._process(); + }, + + /** + * Finalizes the encryption or decryption process. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} dataUpdate The final data to encrypt or decrypt. + * + * @return {WordArray} The data after final processing. + * + * @example + * + * var encrypted = cipher.finalize(); + * var encrypted = cipher.finalize('data'); + * var encrypted = cipher.finalize(wordArray); + */ + finalize: function (dataUpdate) { + // Final data update + if (dataUpdate) { + this._append(dataUpdate); + } + + // Perform concrete-cipher logic + var finalProcessedData = this._doFinalize(); + + return finalProcessedData; + }, + + keySize: 128/32, + + ivSize: 128/32, + + _ENC_XFORM_MODE: 1, + + _DEC_XFORM_MODE: 2, + + /** + * Creates shortcut functions to a cipher's object interface. + * + * @param {Cipher} cipher The cipher to create a helper for. + * + * @return {Object} An object with encrypt and decrypt shortcut functions. + * + * @static + * + * @example + * + * var AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES); + */ + _createHelper: (function () { + function selectCipherStrategy(key) { + if (typeof key == 'string') { + return PasswordBasedCipher; + } else { + return SerializableCipher; + } + } + + return function (cipher) { + return { + encrypt: function (message, key, cfg) { + return selectCipherStrategy(key).encrypt(cipher, message, key, cfg); + }, + + decrypt: function (ciphertext, key, cfg) { + return selectCipherStrategy(key).decrypt(cipher, ciphertext, key, cfg); + } + }; + }; + }()) + }); + + /** + * Abstract base stream cipher template. + * + * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 1 (32 bits) + */ + var StreamCipher = C_lib.StreamCipher = Cipher.extend({ + _doFinalize: function () { + // Process partial blocks + var finalProcessedBlocks = this._process(!!'flush'); + + return finalProcessedBlocks; + }, + + blockSize: 1 + }); + + /** + * Mode namespace. + */ + var C_mode = C.mode = {}; + + /** + * Abstract base block cipher mode template. + */ + var BlockCipherMode = C_lib.BlockCipherMode = Base.extend({ + /** + * Creates this mode for encryption. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @static + * + * @example + * + * var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words); + */ + createEncryptor: function (cipher, iv) { + return this.Encryptor.create(cipher, iv); + }, + + /** + * Creates this mode for decryption. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @static + * + * @example + * + * var mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words); + */ + createDecryptor: function (cipher, iv) { + return this.Decryptor.create(cipher, iv); + }, + + /** + * Initializes a newly created mode. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @example + * + * var mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words); + */ + init: function (cipher, iv) { + this._cipher = cipher; + this._iv = iv; + } + }); + + /** + * Cipher Block Chaining mode. + */ + var CBC = C_mode.CBC = (function () { + /** + * Abstract base CBC mode. + */ + var CBC = BlockCipherMode.extend(); + + /** + * CBC encryptor. + */ + CBC.Encryptor = CBC.extend({ + /** + * Processes the data block at offset. + * + * @param {Array} words The data words to operate on. + * @param {number} offset The offset where the block starts. + * + * @example + * + * mode.processBlock(data.words, offset); + */ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + // XOR and encrypt + xorBlock.call(this, words, offset, blockSize); + cipher.encryptBlock(words, offset); + + // Remember this block to use with next block + this._prevBlock = words.slice(offset, offset + blockSize); + } + }); + + /** + * CBC decryptor. + */ + CBC.Decryptor = CBC.extend({ + /** + * Processes the data block at offset. + * + * @param {Array} words The data words to operate on. + * @param {number} offset The offset where the block starts. + * + * @example + * + * mode.processBlock(data.words, offset); + */ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + // Remember this block to use with next block + var thisBlock = words.slice(offset, offset + blockSize); + + // Decrypt and XOR + cipher.decryptBlock(words, offset); + xorBlock.call(this, words, offset, blockSize); + + // This block becomes the previous block + this._prevBlock = thisBlock; + } + }); + + function xorBlock(words, offset, blockSize) { + var block; + + // Shortcut + var iv = this._iv; + + // Choose mixing block + if (iv) { + block = iv; + + // Remove IV for subsequent blocks + this._iv = undefined; + } else { + block = this._prevBlock; + } + + // XOR blocks + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= block[i]; + } + } + + return CBC; + }()); + + /** + * Padding namespace. + */ + var C_pad = C.pad = {}; + + /** + * PKCS #5/7 padding strategy. + */ + var Pkcs7 = C_pad.Pkcs7 = { + /** + * Pads data using the algorithm defined in PKCS #5/7. + * + * @param {WordArray} data The data to pad. + * @param {number} blockSize The multiple that the data should be padded to. + * + * @static + * + * @example + * + * CryptoJS.pad.Pkcs7.pad(wordArray, 4); + */ + pad: function (data, blockSize) { + // Shortcut + var blockSizeBytes = blockSize * 4; + + // Count padding bytes + var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes; + + // Create padding word + var paddingWord = (nPaddingBytes << 24) | (nPaddingBytes << 16) | (nPaddingBytes << 8) | nPaddingBytes; + + // Create padding + var paddingWords = []; + for (var i = 0; i < nPaddingBytes; i += 4) { + paddingWords.push(paddingWord); + } + var padding = WordArray.create(paddingWords, nPaddingBytes); + + // Add padding + data.concat(padding); + }, + + /** + * Unpads data that had been padded using the algorithm defined in PKCS #5/7. + * + * @param {WordArray} data The data to unpad. + * + * @static + * + * @example + * + * CryptoJS.pad.Pkcs7.unpad(wordArray); + */ + unpad: function (data) { + // Get number of padding bytes from last byte + var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + + // Remove padding + data.sigBytes -= nPaddingBytes; + } + }; + + /** + * Abstract base block cipher template. + * + * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 4 (128 bits) + */ + var BlockCipher = C_lib.BlockCipher = Cipher.extend({ + /** + * Configuration options. + * + * @property {Mode} mode The block mode to use. Default: CBC + * @property {Padding} padding The padding strategy to use. Default: Pkcs7 + */ + cfg: Cipher.cfg.extend({ + mode: CBC, + padding: Pkcs7 + }), + + reset: function () { + var modeCreator; + + // Reset cipher + Cipher.reset.call(this); + + // Shortcuts + var cfg = this.cfg; + var iv = cfg.iv; + var mode = cfg.mode; + + // Reset block mode + if (this._xformMode == this._ENC_XFORM_MODE) { + modeCreator = mode.createEncryptor; + } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { + modeCreator = mode.createDecryptor; + // Keep at least one block in the buffer for unpadding + this._minBufferSize = 1; + } + + if (this._mode && this._mode.__creator == modeCreator) { + this._mode.init(this, iv && iv.words); + } else { + this._mode = modeCreator.call(mode, this, iv && iv.words); + this._mode.__creator = modeCreator; + } + }, + + _doProcessBlock: function (words, offset) { + this._mode.processBlock(words, offset); + }, + + _doFinalize: function () { + var finalProcessedBlocks; + + // Shortcut + var padding = this.cfg.padding; + + // Finalize + if (this._xformMode == this._ENC_XFORM_MODE) { + // Pad data + padding.pad(this._data, this.blockSize); + + // Process final blocks + finalProcessedBlocks = this._process(!!'flush'); + } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { + // Process final blocks + finalProcessedBlocks = this._process(!!'flush'); + + // Unpad data + padding.unpad(finalProcessedBlocks); + } + + return finalProcessedBlocks; + }, + + blockSize: 128/32 + }); + + /** + * A collection of cipher parameters. + * + * @property {WordArray} ciphertext The raw ciphertext. + * @property {WordArray} key The key to this ciphertext. + * @property {WordArray} iv The IV used in the ciphering operation. + * @property {WordArray} salt The salt used with a key derivation function. + * @property {Cipher} algorithm The cipher algorithm. + * @property {Mode} mode The block mode used in the ciphering operation. + * @property {Padding} padding The padding scheme used in the ciphering operation. + * @property {number} blockSize The block size of the cipher. + * @property {Format} formatter The default formatting strategy to convert this cipher params object to a string. + */ + var CipherParams = C_lib.CipherParams = Base.extend({ + /** + * Initializes a newly created cipher params object. + * + * @param {Object} cipherParams An object with any of the possible cipher parameters. + * + * @example + * + * var cipherParams = CryptoJS.lib.CipherParams.create({ + * ciphertext: ciphertextWordArray, + * key: keyWordArray, + * iv: ivWordArray, + * salt: saltWordArray, + * algorithm: CryptoJS.algo.AES, + * mode: CryptoJS.mode.CBC, + * padding: CryptoJS.pad.PKCS7, + * blockSize: 4, + * formatter: CryptoJS.format.OpenSSL + * }); + */ + init: function (cipherParams) { + this.mixIn(cipherParams); + }, + + /** + * Converts this cipher params object to a string. + * + * @param {Format} formatter (Optional) The formatting strategy to use. + * + * @return {string} The stringified cipher params. + * + * @throws Error If neither the formatter nor the default formatter is set. + * + * @example + * + * var string = cipherParams + ''; + * var string = cipherParams.toString(); + * var string = cipherParams.toString(CryptoJS.format.OpenSSL); + */ + toString: function (formatter) { + return (formatter || this.formatter).stringify(this); + } + }); + + /** + * Format namespace. + */ + var C_format = C.format = {}; + + /** + * OpenSSL formatting strategy. + */ + var OpenSSLFormatter = C_format.OpenSSL = { + /** + * Converts a cipher params object to an OpenSSL-compatible string. + * + * @param {CipherParams} cipherParams The cipher params object. + * + * @return {string} The OpenSSL-compatible string. + * + * @static + * + * @example + * + * var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams); + */ + stringify: function (cipherParams) { + var wordArray; + + // Shortcuts + var ciphertext = cipherParams.ciphertext; + var salt = cipherParams.salt; + + // Format + if (salt) { + wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext); + } else { + wordArray = ciphertext; + } + + return wordArray.toString(Base64); + }, + + /** + * Converts an OpenSSL-compatible string to a cipher params object. + * + * @param {string} openSSLStr The OpenSSL-compatible string. + * + * @return {CipherParams} The cipher params object. + * + * @static + * + * @example + * + * var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString); + */ + parse: function (openSSLStr) { + var salt; + + // Parse base64 + var ciphertext = Base64.parse(openSSLStr); + + // Shortcut + var ciphertextWords = ciphertext.words; + + // Test for salt + if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) { + // Extract salt + salt = WordArray.create(ciphertextWords.slice(2, 4)); + + // Remove salt from ciphertext + ciphertextWords.splice(0, 4); + ciphertext.sigBytes -= 16; + } + + return CipherParams.create({ ciphertext: ciphertext, salt: salt }); + } + }; + + /** + * A cipher wrapper that returns ciphertext as a serializable cipher params object. + */ + var SerializableCipher = C_lib.SerializableCipher = Base.extend({ + /** + * Configuration options. + * + * @property {Formatter} format The formatting strategy to convert cipher param objects to and from a string. Default: OpenSSL + */ + cfg: Base.extend({ + format: OpenSSLFormatter + }), + + /** + * Encrypts a message. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {WordArray|string} message The message to encrypt. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {CipherParams} A cipher params object. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key); + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv }); + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + */ + encrypt: function (cipher, message, key, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Encrypt + var encryptor = cipher.createEncryptor(key, cfg); + var ciphertext = encryptor.finalize(message); + + // Shortcut + var cipherCfg = encryptor.cfg; + + // Create and return serializable cipher params + return CipherParams.create({ + ciphertext: ciphertext, + key: key, + iv: cipherCfg.iv, + algorithm: cipher, + mode: cipherCfg.mode, + padding: cipherCfg.padding, + blockSize: cipher.blockSize, + formatter: cfg.format + }); + }, + + /** + * Decrypts serialized ciphertext. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {CipherParams|string} ciphertext The ciphertext to decrypt. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {WordArray} The plaintext. + * + * @static + * + * @example + * + * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + */ + decrypt: function (cipher, ciphertext, key, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Convert string to CipherParams + ciphertext = this._parse(ciphertext, cfg.format); + + // Decrypt + var plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext); + + return plaintext; + }, + + /** + * Converts serialized ciphertext to CipherParams, + * else assumed CipherParams already and returns ciphertext unchanged. + * + * @param {CipherParams|string} ciphertext The ciphertext. + * @param {Formatter} format The formatting strategy to use to parse serialized ciphertext. + * + * @return {CipherParams} The unserialized ciphertext. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format); + */ + _parse: function (ciphertext, format) { + if (typeof ciphertext == 'string') { + return format.parse(ciphertext, this); + } else { + return ciphertext; + } + } + }); + + /** + * Key derivation function namespace. + */ + var C_kdf = C.kdf = {}; + + /** + * OpenSSL key derivation function. + */ + var OpenSSLKdf = C_kdf.OpenSSL = { + /** + * Derives a key and IV from a password. + * + * @param {string} password The password to derive from. + * @param {number} keySize The size in words of the key to generate. + * @param {number} ivSize The size in words of the IV to generate. + * @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly. + * + * @return {CipherParams} A cipher params object with the key, IV, and salt. + * + * @static + * + * @example + * + * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32); + * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt'); + */ + execute: function (password, keySize, ivSize, salt, hasher) { + // Generate random salt + if (!salt) { + salt = WordArray.random(64/8); + } + + // Derive key and IV + if (!hasher) { + var key = EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt); + } else { + var key = EvpKDF.create({ keySize: keySize + ivSize, hasher: hasher }).compute(password, salt); + } + + + // Separate key and IV + var iv = WordArray.create(key.words.slice(keySize), ivSize * 4); + key.sigBytes = keySize * 4; + + // Return params + return CipherParams.create({ key: key, iv: iv, salt: salt }); + } + }; + + /** + * A serializable cipher wrapper that derives the key from a password, + * and returns ciphertext as a serializable cipher params object. + */ + var PasswordBasedCipher = C_lib.PasswordBasedCipher = SerializableCipher.extend({ + /** + * Configuration options. + * + * @property {KDF} kdf The key derivation function to use to generate a key and IV from a password. Default: OpenSSL + */ + cfg: SerializableCipher.cfg.extend({ + kdf: OpenSSLKdf + }), + + /** + * Encrypts a message using a password. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {WordArray|string} message The message to encrypt. + * @param {string} password The password. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {CipherParams} A cipher params object. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password'); + * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL }); + */ + encrypt: function (cipher, message, password, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Derive key and other params + var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, cfg.salt, cfg.hasher); + + // Add IV to config + cfg.iv = derivedParams.iv; + + // Encrypt + var ciphertext = SerializableCipher.encrypt.call(this, cipher, message, derivedParams.key, cfg); + + // Mix in derived params + ciphertext.mixIn(derivedParams); + + return ciphertext; + }, + + /** + * Decrypts serialized ciphertext using a password. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {CipherParams|string} ciphertext The ciphertext to decrypt. + * @param {string} password The password. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {WordArray} The plaintext. + * + * @static + * + * @example + * + * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password', { format: CryptoJS.format.OpenSSL }); + * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, 'password', { format: CryptoJS.format.OpenSSL }); + */ + decrypt: function (cipher, ciphertext, password, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Convert string to CipherParams + ciphertext = this._parse(ciphertext, cfg.format); + + // Derive key and other params + var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt, cfg.hasher); + + // Add IV to config + cfg.iv = derivedParams.iv; + + // Decrypt + var plaintext = SerializableCipher.decrypt.call(this, cipher, ciphertext, derivedParams.key, cfg); + + return plaintext; + } + }); + }()); + + + /** + * Cipher Feedback block mode. + */ + CryptoJS.mode.CFB = (function () { + var CFB = CryptoJS.lib.BlockCipherMode.extend(); + + CFB.Encryptor = CFB.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher); + + // Remember this block to use with next block + this._prevBlock = words.slice(offset, offset + blockSize); + } + }); + + CFB.Decryptor = CFB.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + // Remember this block to use with next block + var thisBlock = words.slice(offset, offset + blockSize); + + generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher); + + // This block becomes the previous block + this._prevBlock = thisBlock; + } + }); + + function generateKeystreamAndEncrypt(words, offset, blockSize, cipher) { + var keystream; + + // Shortcut + var iv = this._iv; + + // Generate keystream + if (iv) { + keystream = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } else { + keystream = this._prevBlock; + } + cipher.encryptBlock(keystream, 0); + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + + return CFB; + }()); + + + /** + * Counter block mode. + */ + CryptoJS.mode.CTR = (function () { + var CTR = CryptoJS.lib.BlockCipherMode.extend(); + + var Encryptor = CTR.Encryptor = CTR.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher + var blockSize = cipher.blockSize; + var iv = this._iv; + var counter = this._counter; + + // Generate keystream + if (iv) { + counter = this._counter = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } + var keystream = counter.slice(0); + cipher.encryptBlock(keystream, 0); + + // Increment counter + counter[blockSize - 1] = (counter[blockSize - 1] + 1) | 0 + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + }); + + CTR.Decryptor = Encryptor; + + return CTR; + }()); + + + /** @preserve + * Counter block mode compatible with Dr Brian Gladman fileenc.c + * derived from CryptoJS.mode.CTR + * Jan Hruby jhruby.web@gmail.com + */ + CryptoJS.mode.CTRGladman = (function () { + var CTRGladman = CryptoJS.lib.BlockCipherMode.extend(); + + function incWord(word) + { + if (((word >> 24) & 0xff) === 0xff) { //overflow + var b1 = (word >> 16)&0xff; + var b2 = (word >> 8)&0xff; + var b3 = word & 0xff; + + if (b1 === 0xff) // overflow b1 + { + b1 = 0; + if (b2 === 0xff) + { + b2 = 0; + if (b3 === 0xff) + { + b3 = 0; + } + else + { + ++b3; + } + } + else + { + ++b2; + } + } + else + { + ++b1; + } + + word = 0; + word += (b1 << 16); + word += (b2 << 8); + word += b3; + } + else + { + word += (0x01 << 24); + } + return word; + } + + function incCounter(counter) + { + if ((counter[0] = incWord(counter[0])) === 0) + { + // encr_data in fileenc.c from Dr Brian Gladman's counts only with DWORD j < 8 + counter[1] = incWord(counter[1]); + } + return counter; + } + + var Encryptor = CTRGladman.Encryptor = CTRGladman.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher + var blockSize = cipher.blockSize; + var iv = this._iv; + var counter = this._counter; + + // Generate keystream + if (iv) { + counter = this._counter = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } + + incCounter(counter); + + var keystream = counter.slice(0); + cipher.encryptBlock(keystream, 0); + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + }); + + CTRGladman.Decryptor = Encryptor; + + return CTRGladman; + }()); + + + + + /** + * Output Feedback block mode. + */ + CryptoJS.mode.OFB = (function () { + var OFB = CryptoJS.lib.BlockCipherMode.extend(); + + var Encryptor = OFB.Encryptor = OFB.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher + var blockSize = cipher.blockSize; + var iv = this._iv; + var keystream = this._keystream; + + // Generate keystream + if (iv) { + keystream = this._keystream = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } + cipher.encryptBlock(keystream, 0); + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + }); + + OFB.Decryptor = Encryptor; + + return OFB; + }()); + + + /** + * Electronic Codebook block mode. + */ + CryptoJS.mode.ECB = (function () { + var ECB = CryptoJS.lib.BlockCipherMode.extend(); + + ECB.Encryptor = ECB.extend({ + processBlock: function (words, offset) { + this._cipher.encryptBlock(words, offset); + } + }); + + ECB.Decryptor = ECB.extend({ + processBlock: function (words, offset) { + this._cipher.decryptBlock(words, offset); + } + }); + + return ECB; + }()); + + + /** + * ANSI X.923 padding strategy. + */ + CryptoJS.pad.AnsiX923 = { + pad: function (data, blockSize) { + // Shortcuts + var dataSigBytes = data.sigBytes; + var blockSizeBytes = blockSize * 4; + + // Count padding bytes + var nPaddingBytes = blockSizeBytes - dataSigBytes % blockSizeBytes; + + // Compute last byte position + var lastBytePos = dataSigBytes + nPaddingBytes - 1; + + // Pad + data.clamp(); + data.words[lastBytePos >>> 2] |= nPaddingBytes << (24 - (lastBytePos % 4) * 8); + data.sigBytes += nPaddingBytes; + }, + + unpad: function (data) { + // Get number of padding bytes from last byte + var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + + // Remove padding + data.sigBytes -= nPaddingBytes; + } + }; + + + /** + * ISO 10126 padding strategy. + */ + CryptoJS.pad.Iso10126 = { + pad: function (data, blockSize) { + // Shortcut + var blockSizeBytes = blockSize * 4; + + // Count padding bytes + var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes; + + // Pad + data.concat(CryptoJS.lib.WordArray.random(nPaddingBytes - 1)). + concat(CryptoJS.lib.WordArray.create([nPaddingBytes << 24], 1)); + }, + + unpad: function (data) { + // Get number of padding bytes from last byte + var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + + // Remove padding + data.sigBytes -= nPaddingBytes; + } + }; + + + /** + * ISO/IEC 9797-1 Padding Method 2. + */ + CryptoJS.pad.Iso97971 = { + pad: function (data, blockSize) { + // Add 0x80 byte + data.concat(CryptoJS.lib.WordArray.create([0x80000000], 1)); + + // Zero pad the rest + CryptoJS.pad.ZeroPadding.pad(data, blockSize); + }, + + unpad: function (data) { + // Remove zero padding + CryptoJS.pad.ZeroPadding.unpad(data); + + // Remove one more byte -- the 0x80 byte + data.sigBytes--; + } + }; + + + /** + * Zero padding strategy. + */ + CryptoJS.pad.ZeroPadding = { + pad: function (data, blockSize) { + // Shortcut + var blockSizeBytes = blockSize * 4; + + // Pad + data.clamp(); + data.sigBytes += blockSizeBytes - ((data.sigBytes % blockSizeBytes) || blockSizeBytes); + }, + + unpad: function (data) { + // Shortcut + var dataWords = data.words; + + // Unpad + var i = data.sigBytes - 1; + for (var i = data.sigBytes - 1; i >= 0; i--) { + if (((dataWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff)) { + data.sigBytes = i + 1; + break; + } + } + } + }; + + + /** + * A noop padding strategy. + */ + CryptoJS.pad.NoPadding = { + pad: function () { + }, + + unpad: function () { + } + }; + + + (function (undefined) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var CipherParams = C_lib.CipherParams; + var C_enc = C.enc; + var Hex = C_enc.Hex; + var C_format = C.format; + + var HexFormatter = C_format.Hex = { + /** + * Converts the ciphertext of a cipher params object to a hexadecimally encoded string. + * + * @param {CipherParams} cipherParams The cipher params object. + * + * @return {string} The hexadecimally encoded string. + * + * @static + * + * @example + * + * var hexString = CryptoJS.format.Hex.stringify(cipherParams); + */ + stringify: function (cipherParams) { + return cipherParams.ciphertext.toString(Hex); + }, + + /** + * Converts a hexadecimally encoded ciphertext string to a cipher params object. + * + * @param {string} input The hexadecimally encoded string. + * + * @return {CipherParams} The cipher params object. + * + * @static + * + * @example + * + * var cipherParams = CryptoJS.format.Hex.parse(hexString); + */ + parse: function (input) { + var ciphertext = Hex.parse(input); + return CipherParams.create({ ciphertext: ciphertext }); + } + }; + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var BlockCipher = C_lib.BlockCipher; + var C_algo = C.algo; + + // Lookup tables + var SBOX = []; + var INV_SBOX = []; + var SUB_MIX_0 = []; + var SUB_MIX_1 = []; + var SUB_MIX_2 = []; + var SUB_MIX_3 = []; + var INV_SUB_MIX_0 = []; + var INV_SUB_MIX_1 = []; + var INV_SUB_MIX_2 = []; + var INV_SUB_MIX_3 = []; + + // Compute lookup tables + (function () { + // Compute double table + var d = []; + for (var i = 0; i < 256; i++) { + if (i < 128) { + d[i] = i << 1; + } else { + d[i] = (i << 1) ^ 0x11b; + } + } + + // Walk GF(2^8) + var x = 0; + var xi = 0; + for (var i = 0; i < 256; i++) { + // Compute sbox + var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4); + sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63; + SBOX[x] = sx; + INV_SBOX[sx] = x; + + // Compute multiplication + var x2 = d[x]; + var x4 = d[x2]; + var x8 = d[x4]; + + // Compute sub bytes, mix columns tables + var t = (d[sx] * 0x101) ^ (sx * 0x1010100); + SUB_MIX_0[x] = (t << 24) | (t >>> 8); + SUB_MIX_1[x] = (t << 16) | (t >>> 16); + SUB_MIX_2[x] = (t << 8) | (t >>> 24); + SUB_MIX_3[x] = t; + + // Compute inv sub bytes, inv mix columns tables + var t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100); + INV_SUB_MIX_0[sx] = (t << 24) | (t >>> 8); + INV_SUB_MIX_1[sx] = (t << 16) | (t >>> 16); + INV_SUB_MIX_2[sx] = (t << 8) | (t >>> 24); + INV_SUB_MIX_3[sx] = t; + + // Compute next counter + if (!x) { + x = xi = 1; + } else { + x = x2 ^ d[d[d[x8 ^ x2]]]; + xi ^= d[d[xi]]; + } + } + }()); + + // Precomputed Rcon lookup + var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]; + + /** + * AES block cipher algorithm. + */ + var AES = C_algo.AES = BlockCipher.extend({ + _doReset: function () { + var t; + + // Skip reset of nRounds has been set before and key did not change + if (this._nRounds && this._keyPriorReset === this._key) { + return; + } + + // Shortcuts + var key = this._keyPriorReset = this._key; + var keyWords = key.words; + var keySize = key.sigBytes / 4; + + // Compute number of rounds + var nRounds = this._nRounds = keySize + 6; + + // Compute number of key schedule rows + var ksRows = (nRounds + 1) * 4; + + // Compute key schedule + var keySchedule = this._keySchedule = []; + for (var ksRow = 0; ksRow < ksRows; ksRow++) { + if (ksRow < keySize) { + keySchedule[ksRow] = keyWords[ksRow]; + } else { + t = keySchedule[ksRow - 1]; + + if (!(ksRow % keySize)) { + // Rot word + t = (t << 8) | (t >>> 24); + + // Sub word + t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff]; + + // Mix Rcon + t ^= RCON[(ksRow / keySize) | 0] << 24; + } else if (keySize > 6 && ksRow % keySize == 4) { + // Sub word + t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff]; + } + + keySchedule[ksRow] = keySchedule[ksRow - keySize] ^ t; + } + } + + // Compute inv key schedule + var invKeySchedule = this._invKeySchedule = []; + for (var invKsRow = 0; invKsRow < ksRows; invKsRow++) { + var ksRow = ksRows - invKsRow; + + if (invKsRow % 4) { + var t = keySchedule[ksRow]; + } else { + var t = keySchedule[ksRow - 4]; + } + + if (invKsRow < 4 || ksRow <= 4) { + invKeySchedule[invKsRow] = t; + } else { + invKeySchedule[invKsRow] = INV_SUB_MIX_0[SBOX[t >>> 24]] ^ INV_SUB_MIX_1[SBOX[(t >>> 16) & 0xff]] ^ + INV_SUB_MIX_2[SBOX[(t >>> 8) & 0xff]] ^ INV_SUB_MIX_3[SBOX[t & 0xff]]; + } + } + }, + + encryptBlock: function (M, offset) { + this._doCryptBlock(M, offset, this._keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX); + }, + + decryptBlock: function (M, offset) { + // Swap 2nd and 4th rows + var t = M[offset + 1]; + M[offset + 1] = M[offset + 3]; + M[offset + 3] = t; + + this._doCryptBlock(M, offset, this._invKeySchedule, INV_SUB_MIX_0, INV_SUB_MIX_1, INV_SUB_MIX_2, INV_SUB_MIX_3, INV_SBOX); + + // Inv swap 2nd and 4th rows + var t = M[offset + 1]; + M[offset + 1] = M[offset + 3]; + M[offset + 3] = t; + }, + + _doCryptBlock: function (M, offset, keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX) { + // Shortcut + var nRounds = this._nRounds; + + // Get input, add round key + var s0 = M[offset] ^ keySchedule[0]; + var s1 = M[offset + 1] ^ keySchedule[1]; + var s2 = M[offset + 2] ^ keySchedule[2]; + var s3 = M[offset + 3] ^ keySchedule[3]; + + // Key schedule row counter + var ksRow = 4; + + // Rounds + for (var round = 1; round < nRounds; round++) { + // Shift rows, sub bytes, mix columns, add round key + var t0 = SUB_MIX_0[s0 >>> 24] ^ SUB_MIX_1[(s1 >>> 16) & 0xff] ^ SUB_MIX_2[(s2 >>> 8) & 0xff] ^ SUB_MIX_3[s3 & 0xff] ^ keySchedule[ksRow++]; + var t1 = SUB_MIX_0[s1 >>> 24] ^ SUB_MIX_1[(s2 >>> 16) & 0xff] ^ SUB_MIX_2[(s3 >>> 8) & 0xff] ^ SUB_MIX_3[s0 & 0xff] ^ keySchedule[ksRow++]; + var t2 = SUB_MIX_0[s2 >>> 24] ^ SUB_MIX_1[(s3 >>> 16) & 0xff] ^ SUB_MIX_2[(s0 >>> 8) & 0xff] ^ SUB_MIX_3[s1 & 0xff] ^ keySchedule[ksRow++]; + var t3 = SUB_MIX_0[s3 >>> 24] ^ SUB_MIX_1[(s0 >>> 16) & 0xff] ^ SUB_MIX_2[(s1 >>> 8) & 0xff] ^ SUB_MIX_3[s2 & 0xff] ^ keySchedule[ksRow++]; + + // Update state + s0 = t0; + s1 = t1; + s2 = t2; + s3 = t3; + } + + // Shift rows, sub bytes, add round key + var t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++]; + var t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++]; + var t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++]; + var t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++]; + + // Set output + M[offset] = t0; + M[offset + 1] = t1; + M[offset + 2] = t2; + M[offset + 3] = t3; + }, + + keySize: 256/32 + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.AES.encrypt(message, key, cfg); + * var plaintext = CryptoJS.AES.decrypt(ciphertext, key, cfg); + */ + C.AES = BlockCipher._createHelper(AES); + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var BlockCipher = C_lib.BlockCipher; + var C_algo = C.algo; + + // Permuted Choice 1 constants + var PC1 = [ + 57, 49, 41, 33, 25, 17, 9, 1, + 58, 50, 42, 34, 26, 18, 10, 2, + 59, 51, 43, 35, 27, 19, 11, 3, + 60, 52, 44, 36, 63, 55, 47, 39, + 31, 23, 15, 7, 62, 54, 46, 38, + 30, 22, 14, 6, 61, 53, 45, 37, + 29, 21, 13, 5, 28, 20, 12, 4 + ]; + + // Permuted Choice 2 constants + var PC2 = [ + 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32 + ]; + + // Cumulative bit shift constants + var BIT_SHIFTS = [1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28]; + + // SBOXes and round permutation constants + var SBOX_P = [ + { + 0x0: 0x808200, + 0x10000000: 0x8000, + 0x20000000: 0x808002, + 0x30000000: 0x2, + 0x40000000: 0x200, + 0x50000000: 0x808202, + 0x60000000: 0x800202, + 0x70000000: 0x800000, + 0x80000000: 0x202, + 0x90000000: 0x800200, + 0xa0000000: 0x8200, + 0xb0000000: 0x808000, + 0xc0000000: 0x8002, + 0xd0000000: 0x800002, + 0xe0000000: 0x0, + 0xf0000000: 0x8202, + 0x8000000: 0x0, + 0x18000000: 0x808202, + 0x28000000: 0x8202, + 0x38000000: 0x8000, + 0x48000000: 0x808200, + 0x58000000: 0x200, + 0x68000000: 0x808002, + 0x78000000: 0x2, + 0x88000000: 0x800200, + 0x98000000: 0x8200, + 0xa8000000: 0x808000, + 0xb8000000: 0x800202, + 0xc8000000: 0x800002, + 0xd8000000: 0x8002, + 0xe8000000: 0x202, + 0xf8000000: 0x800000, + 0x1: 0x8000, + 0x10000001: 0x2, + 0x20000001: 0x808200, + 0x30000001: 0x800000, + 0x40000001: 0x808002, + 0x50000001: 0x8200, + 0x60000001: 0x200, + 0x70000001: 0x800202, + 0x80000001: 0x808202, + 0x90000001: 0x808000, + 0xa0000001: 0x800002, + 0xb0000001: 0x8202, + 0xc0000001: 0x202, + 0xd0000001: 0x800200, + 0xe0000001: 0x8002, + 0xf0000001: 0x0, + 0x8000001: 0x808202, + 0x18000001: 0x808000, + 0x28000001: 0x800000, + 0x38000001: 0x200, + 0x48000001: 0x8000, + 0x58000001: 0x800002, + 0x68000001: 0x2, + 0x78000001: 0x8202, + 0x88000001: 0x8002, + 0x98000001: 0x800202, + 0xa8000001: 0x202, + 0xb8000001: 0x808200, + 0xc8000001: 0x800200, + 0xd8000001: 0x0, + 0xe8000001: 0x8200, + 0xf8000001: 0x808002 + }, + { + 0x0: 0x40084010, + 0x1000000: 0x4000, + 0x2000000: 0x80000, + 0x3000000: 0x40080010, + 0x4000000: 0x40000010, + 0x5000000: 0x40084000, + 0x6000000: 0x40004000, + 0x7000000: 0x10, + 0x8000000: 0x84000, + 0x9000000: 0x40004010, + 0xa000000: 0x40000000, + 0xb000000: 0x84010, + 0xc000000: 0x80010, + 0xd000000: 0x0, + 0xe000000: 0x4010, + 0xf000000: 0x40080000, + 0x800000: 0x40004000, + 0x1800000: 0x84010, + 0x2800000: 0x10, + 0x3800000: 0x40004010, + 0x4800000: 0x40084010, + 0x5800000: 0x40000000, + 0x6800000: 0x80000, + 0x7800000: 0x40080010, + 0x8800000: 0x80010, + 0x9800000: 0x0, + 0xa800000: 0x4000, + 0xb800000: 0x40080000, + 0xc800000: 0x40000010, + 0xd800000: 0x84000, + 0xe800000: 0x40084000, + 0xf800000: 0x4010, + 0x10000000: 0x0, + 0x11000000: 0x40080010, + 0x12000000: 0x40004010, + 0x13000000: 0x40084000, + 0x14000000: 0x40080000, + 0x15000000: 0x10, + 0x16000000: 0x84010, + 0x17000000: 0x4000, + 0x18000000: 0x4010, + 0x19000000: 0x80000, + 0x1a000000: 0x80010, + 0x1b000000: 0x40000010, + 0x1c000000: 0x84000, + 0x1d000000: 0x40004000, + 0x1e000000: 0x40000000, + 0x1f000000: 0x40084010, + 0x10800000: 0x84010, + 0x11800000: 0x80000, + 0x12800000: 0x40080000, + 0x13800000: 0x4000, + 0x14800000: 0x40004000, + 0x15800000: 0x40084010, + 0x16800000: 0x10, + 0x17800000: 0x40000000, + 0x18800000: 0x40084000, + 0x19800000: 0x40000010, + 0x1a800000: 0x40004010, + 0x1b800000: 0x80010, + 0x1c800000: 0x0, + 0x1d800000: 0x4010, + 0x1e800000: 0x40080010, + 0x1f800000: 0x84000 + }, + { + 0x0: 0x104, + 0x100000: 0x0, + 0x200000: 0x4000100, + 0x300000: 0x10104, + 0x400000: 0x10004, + 0x500000: 0x4000004, + 0x600000: 0x4010104, + 0x700000: 0x4010000, + 0x800000: 0x4000000, + 0x900000: 0x4010100, + 0xa00000: 0x10100, + 0xb00000: 0x4010004, + 0xc00000: 0x4000104, + 0xd00000: 0x10000, + 0xe00000: 0x4, + 0xf00000: 0x100, + 0x80000: 0x4010100, + 0x180000: 0x4010004, + 0x280000: 0x0, + 0x380000: 0x4000100, + 0x480000: 0x4000004, + 0x580000: 0x10000, + 0x680000: 0x10004, + 0x780000: 0x104, + 0x880000: 0x4, + 0x980000: 0x100, + 0xa80000: 0x4010000, + 0xb80000: 0x10104, + 0xc80000: 0x10100, + 0xd80000: 0x4000104, + 0xe80000: 0x4010104, + 0xf80000: 0x4000000, + 0x1000000: 0x4010100, + 0x1100000: 0x10004, + 0x1200000: 0x10000, + 0x1300000: 0x4000100, + 0x1400000: 0x100, + 0x1500000: 0x4010104, + 0x1600000: 0x4000004, + 0x1700000: 0x0, + 0x1800000: 0x4000104, + 0x1900000: 0x4000000, + 0x1a00000: 0x4, + 0x1b00000: 0x10100, + 0x1c00000: 0x4010000, + 0x1d00000: 0x104, + 0x1e00000: 0x10104, + 0x1f00000: 0x4010004, + 0x1080000: 0x4000000, + 0x1180000: 0x104, + 0x1280000: 0x4010100, + 0x1380000: 0x0, + 0x1480000: 0x10004, + 0x1580000: 0x4000100, + 0x1680000: 0x100, + 0x1780000: 0x4010004, + 0x1880000: 0x10000, + 0x1980000: 0x4010104, + 0x1a80000: 0x10104, + 0x1b80000: 0x4000004, + 0x1c80000: 0x4000104, + 0x1d80000: 0x4010000, + 0x1e80000: 0x4, + 0x1f80000: 0x10100 + }, + { + 0x0: 0x80401000, + 0x10000: 0x80001040, + 0x20000: 0x401040, + 0x30000: 0x80400000, + 0x40000: 0x0, + 0x50000: 0x401000, + 0x60000: 0x80000040, + 0x70000: 0x400040, + 0x80000: 0x80000000, + 0x90000: 0x400000, + 0xa0000: 0x40, + 0xb0000: 0x80001000, + 0xc0000: 0x80400040, + 0xd0000: 0x1040, + 0xe0000: 0x1000, + 0xf0000: 0x80401040, + 0x8000: 0x80001040, + 0x18000: 0x40, + 0x28000: 0x80400040, + 0x38000: 0x80001000, + 0x48000: 0x401000, + 0x58000: 0x80401040, + 0x68000: 0x0, + 0x78000: 0x80400000, + 0x88000: 0x1000, + 0x98000: 0x80401000, + 0xa8000: 0x400000, + 0xb8000: 0x1040, + 0xc8000: 0x80000000, + 0xd8000: 0x400040, + 0xe8000: 0x401040, + 0xf8000: 0x80000040, + 0x100000: 0x400040, + 0x110000: 0x401000, + 0x120000: 0x80000040, + 0x130000: 0x0, + 0x140000: 0x1040, + 0x150000: 0x80400040, + 0x160000: 0x80401000, + 0x170000: 0x80001040, + 0x180000: 0x80401040, + 0x190000: 0x80000000, + 0x1a0000: 0x80400000, + 0x1b0000: 0x401040, + 0x1c0000: 0x80001000, + 0x1d0000: 0x400000, + 0x1e0000: 0x40, + 0x1f0000: 0x1000, + 0x108000: 0x80400000, + 0x118000: 0x80401040, + 0x128000: 0x0, + 0x138000: 0x401000, + 0x148000: 0x400040, + 0x158000: 0x80000000, + 0x168000: 0x80001040, + 0x178000: 0x40, + 0x188000: 0x80000040, + 0x198000: 0x1000, + 0x1a8000: 0x80001000, + 0x1b8000: 0x80400040, + 0x1c8000: 0x1040, + 0x1d8000: 0x80401000, + 0x1e8000: 0x400000, + 0x1f8000: 0x401040 + }, + { + 0x0: 0x80, + 0x1000: 0x1040000, + 0x2000: 0x40000, + 0x3000: 0x20000000, + 0x4000: 0x20040080, + 0x5000: 0x1000080, + 0x6000: 0x21000080, + 0x7000: 0x40080, + 0x8000: 0x1000000, + 0x9000: 0x20040000, + 0xa000: 0x20000080, + 0xb000: 0x21040080, + 0xc000: 0x21040000, + 0xd000: 0x0, + 0xe000: 0x1040080, + 0xf000: 0x21000000, + 0x800: 0x1040080, + 0x1800: 0x21000080, + 0x2800: 0x80, + 0x3800: 0x1040000, + 0x4800: 0x40000, + 0x5800: 0x20040080, + 0x6800: 0x21040000, + 0x7800: 0x20000000, + 0x8800: 0x20040000, + 0x9800: 0x0, + 0xa800: 0x21040080, + 0xb800: 0x1000080, + 0xc800: 0x20000080, + 0xd800: 0x21000000, + 0xe800: 0x1000000, + 0xf800: 0x40080, + 0x10000: 0x40000, + 0x11000: 0x80, + 0x12000: 0x20000000, + 0x13000: 0x21000080, + 0x14000: 0x1000080, + 0x15000: 0x21040000, + 0x16000: 0x20040080, + 0x17000: 0x1000000, + 0x18000: 0x21040080, + 0x19000: 0x21000000, + 0x1a000: 0x1040000, + 0x1b000: 0x20040000, + 0x1c000: 0x40080, + 0x1d000: 0x20000080, + 0x1e000: 0x0, + 0x1f000: 0x1040080, + 0x10800: 0x21000080, + 0x11800: 0x1000000, + 0x12800: 0x1040000, + 0x13800: 0x20040080, + 0x14800: 0x20000000, + 0x15800: 0x1040080, + 0x16800: 0x80, + 0x17800: 0x21040000, + 0x18800: 0x40080, + 0x19800: 0x21040080, + 0x1a800: 0x0, + 0x1b800: 0x21000000, + 0x1c800: 0x1000080, + 0x1d800: 0x40000, + 0x1e800: 0x20040000, + 0x1f800: 0x20000080 + }, + { + 0x0: 0x10000008, + 0x100: 0x2000, + 0x200: 0x10200000, + 0x300: 0x10202008, + 0x400: 0x10002000, + 0x500: 0x200000, + 0x600: 0x200008, + 0x700: 0x10000000, + 0x800: 0x0, + 0x900: 0x10002008, + 0xa00: 0x202000, + 0xb00: 0x8, + 0xc00: 0x10200008, + 0xd00: 0x202008, + 0xe00: 0x2008, + 0xf00: 0x10202000, + 0x80: 0x10200000, + 0x180: 0x10202008, + 0x280: 0x8, + 0x380: 0x200000, + 0x480: 0x202008, + 0x580: 0x10000008, + 0x680: 0x10002000, + 0x780: 0x2008, + 0x880: 0x200008, + 0x980: 0x2000, + 0xa80: 0x10002008, + 0xb80: 0x10200008, + 0xc80: 0x0, + 0xd80: 0x10202000, + 0xe80: 0x202000, + 0xf80: 0x10000000, + 0x1000: 0x10002000, + 0x1100: 0x10200008, + 0x1200: 0x10202008, + 0x1300: 0x2008, + 0x1400: 0x200000, + 0x1500: 0x10000000, + 0x1600: 0x10000008, + 0x1700: 0x202000, + 0x1800: 0x202008, + 0x1900: 0x0, + 0x1a00: 0x8, + 0x1b00: 0x10200000, + 0x1c00: 0x2000, + 0x1d00: 0x10002008, + 0x1e00: 0x10202000, + 0x1f00: 0x200008, + 0x1080: 0x8, + 0x1180: 0x202000, + 0x1280: 0x200000, + 0x1380: 0x10000008, + 0x1480: 0x10002000, + 0x1580: 0x2008, + 0x1680: 0x10202008, + 0x1780: 0x10200000, + 0x1880: 0x10202000, + 0x1980: 0x10200008, + 0x1a80: 0x2000, + 0x1b80: 0x202008, + 0x1c80: 0x200008, + 0x1d80: 0x0, + 0x1e80: 0x10000000, + 0x1f80: 0x10002008 + }, + { + 0x0: 0x100000, + 0x10: 0x2000401, + 0x20: 0x400, + 0x30: 0x100401, + 0x40: 0x2100401, + 0x50: 0x0, + 0x60: 0x1, + 0x70: 0x2100001, + 0x80: 0x2000400, + 0x90: 0x100001, + 0xa0: 0x2000001, + 0xb0: 0x2100400, + 0xc0: 0x2100000, + 0xd0: 0x401, + 0xe0: 0x100400, + 0xf0: 0x2000000, + 0x8: 0x2100001, + 0x18: 0x0, + 0x28: 0x2000401, + 0x38: 0x2100400, + 0x48: 0x100000, + 0x58: 0x2000001, + 0x68: 0x2000000, + 0x78: 0x401, + 0x88: 0x100401, + 0x98: 0x2000400, + 0xa8: 0x2100000, + 0xb8: 0x100001, + 0xc8: 0x400, + 0xd8: 0x2100401, + 0xe8: 0x1, + 0xf8: 0x100400, + 0x100: 0x2000000, + 0x110: 0x100000, + 0x120: 0x2000401, + 0x130: 0x2100001, + 0x140: 0x100001, + 0x150: 0x2000400, + 0x160: 0x2100400, + 0x170: 0x100401, + 0x180: 0x401, + 0x190: 0x2100401, + 0x1a0: 0x100400, + 0x1b0: 0x1, + 0x1c0: 0x0, + 0x1d0: 0x2100000, + 0x1e0: 0x2000001, + 0x1f0: 0x400, + 0x108: 0x100400, + 0x118: 0x2000401, + 0x128: 0x2100001, + 0x138: 0x1, + 0x148: 0x2000000, + 0x158: 0x100000, + 0x168: 0x401, + 0x178: 0x2100400, + 0x188: 0x2000001, + 0x198: 0x2100000, + 0x1a8: 0x0, + 0x1b8: 0x2100401, + 0x1c8: 0x100401, + 0x1d8: 0x400, + 0x1e8: 0x2000400, + 0x1f8: 0x100001 + }, + { + 0x0: 0x8000820, + 0x1: 0x20000, + 0x2: 0x8000000, + 0x3: 0x20, + 0x4: 0x20020, + 0x5: 0x8020820, + 0x6: 0x8020800, + 0x7: 0x800, + 0x8: 0x8020000, + 0x9: 0x8000800, + 0xa: 0x20800, + 0xb: 0x8020020, + 0xc: 0x820, + 0xd: 0x0, + 0xe: 0x8000020, + 0xf: 0x20820, + 0x80000000: 0x800, + 0x80000001: 0x8020820, + 0x80000002: 0x8000820, + 0x80000003: 0x8000000, + 0x80000004: 0x8020000, + 0x80000005: 0x20800, + 0x80000006: 0x20820, + 0x80000007: 0x20, + 0x80000008: 0x8000020, + 0x80000009: 0x820, + 0x8000000a: 0x20020, + 0x8000000b: 0x8020800, + 0x8000000c: 0x0, + 0x8000000d: 0x8020020, + 0x8000000e: 0x8000800, + 0x8000000f: 0x20000, + 0x10: 0x20820, + 0x11: 0x8020800, + 0x12: 0x20, + 0x13: 0x800, + 0x14: 0x8000800, + 0x15: 0x8000020, + 0x16: 0x8020020, + 0x17: 0x20000, + 0x18: 0x0, + 0x19: 0x20020, + 0x1a: 0x8020000, + 0x1b: 0x8000820, + 0x1c: 0x8020820, + 0x1d: 0x20800, + 0x1e: 0x820, + 0x1f: 0x8000000, + 0x80000010: 0x20000, + 0x80000011: 0x800, + 0x80000012: 0x8020020, + 0x80000013: 0x20820, + 0x80000014: 0x20, + 0x80000015: 0x8020000, + 0x80000016: 0x8000000, + 0x80000017: 0x8000820, + 0x80000018: 0x8020820, + 0x80000019: 0x8000020, + 0x8000001a: 0x8000800, + 0x8000001b: 0x0, + 0x8000001c: 0x20800, + 0x8000001d: 0x820, + 0x8000001e: 0x20020, + 0x8000001f: 0x8020800 + } + ]; + + // Masks that select the SBOX input + var SBOX_MASK = [ + 0xf8000001, 0x1f800000, 0x01f80000, 0x001f8000, + 0x0001f800, 0x00001f80, 0x000001f8, 0x8000001f + ]; + + /** + * DES block cipher algorithm. + */ + var DES = C_algo.DES = BlockCipher.extend({ + _doReset: function () { + // Shortcuts + var key = this._key; + var keyWords = key.words; + + // Select 56 bits according to PC1 + var keyBits = []; + for (var i = 0; i < 56; i++) { + var keyBitPos = PC1[i] - 1; + keyBits[i] = (keyWords[keyBitPos >>> 5] >>> (31 - keyBitPos % 32)) & 1; + } + + // Assemble 16 subkeys + var subKeys = this._subKeys = []; + for (var nSubKey = 0; nSubKey < 16; nSubKey++) { + // Create subkey + var subKey = subKeys[nSubKey] = []; + + // Shortcut + var bitShift = BIT_SHIFTS[nSubKey]; + + // Select 48 bits according to PC2 + for (var i = 0; i < 24; i++) { + // Select from the left 28 key bits + subKey[(i / 6) | 0] |= keyBits[((PC2[i] - 1) + bitShift) % 28] << (31 - i % 6); + + // Select from the right 28 key bits + subKey[4 + ((i / 6) | 0)] |= keyBits[28 + (((PC2[i + 24] - 1) + bitShift) % 28)] << (31 - i % 6); + } + + // Since each subkey is applied to an expanded 32-bit input, + // the subkey can be broken into 8 values scaled to 32-bits, + // which allows the key to be used without expansion + subKey[0] = (subKey[0] << 1) | (subKey[0] >>> 31); + for (var i = 1; i < 7; i++) { + subKey[i] = subKey[i] >>> ((i - 1) * 4 + 3); + } + subKey[7] = (subKey[7] << 5) | (subKey[7] >>> 27); + } + + // Compute inverse subkeys + var invSubKeys = this._invSubKeys = []; + for (var i = 0; i < 16; i++) { + invSubKeys[i] = subKeys[15 - i]; + } + }, + + encryptBlock: function (M, offset) { + this._doCryptBlock(M, offset, this._subKeys); + }, + + decryptBlock: function (M, offset) { + this._doCryptBlock(M, offset, this._invSubKeys); + }, + + _doCryptBlock: function (M, offset, subKeys) { + // Get input + this._lBlock = M[offset]; + this._rBlock = M[offset + 1]; + + // Initial permutation + exchangeLR.call(this, 4, 0x0f0f0f0f); + exchangeLR.call(this, 16, 0x0000ffff); + exchangeRL.call(this, 2, 0x33333333); + exchangeRL.call(this, 8, 0x00ff00ff); + exchangeLR.call(this, 1, 0x55555555); + + // Rounds + for (var round = 0; round < 16; round++) { + // Shortcuts + var subKey = subKeys[round]; + var lBlock = this._lBlock; + var rBlock = this._rBlock; + + // Feistel function + var f = 0; + for (var i = 0; i < 8; i++) { + f |= SBOX_P[i][((rBlock ^ subKey[i]) & SBOX_MASK[i]) >>> 0]; + } + this._lBlock = rBlock; + this._rBlock = lBlock ^ f; + } + + // Undo swap from last round + var t = this._lBlock; + this._lBlock = this._rBlock; + this._rBlock = t; + + // Final permutation + exchangeLR.call(this, 1, 0x55555555); + exchangeRL.call(this, 8, 0x00ff00ff); + exchangeRL.call(this, 2, 0x33333333); + exchangeLR.call(this, 16, 0x0000ffff); + exchangeLR.call(this, 4, 0x0f0f0f0f); + + // Set output + M[offset] = this._lBlock; + M[offset + 1] = this._rBlock; + }, + + keySize: 64/32, + + ivSize: 64/32, + + blockSize: 64/32 + }); + + // Swap bits across the left and right words + function exchangeLR(offset, mask) { + var t = ((this._lBlock >>> offset) ^ this._rBlock) & mask; + this._rBlock ^= t; + this._lBlock ^= t << offset; + } + + function exchangeRL(offset, mask) { + var t = ((this._rBlock >>> offset) ^ this._lBlock) & mask; + this._lBlock ^= t; + this._rBlock ^= t << offset; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.DES.encrypt(message, key, cfg); + * var plaintext = CryptoJS.DES.decrypt(ciphertext, key, cfg); + */ + C.DES = BlockCipher._createHelper(DES); + + /** + * Triple-DES block cipher algorithm. + */ + var TripleDES = C_algo.TripleDES = BlockCipher.extend({ + _doReset: function () { + // Shortcuts + var key = this._key; + var keyWords = key.words; + // Make sure the key length is valid (64, 128 or >= 192 bit) + if (keyWords.length !== 2 && keyWords.length !== 4 && keyWords.length < 6) { + throw new Error('Invalid key length - 3DES requires the key length to be 64, 128, 192 or >192.'); + } + + // Extend the key according to the keying options defined in 3DES standard + var key1 = keyWords.slice(0, 2); + var key2 = keyWords.length < 4 ? keyWords.slice(0, 2) : keyWords.slice(2, 4); + var key3 = keyWords.length < 6 ? keyWords.slice(0, 2) : keyWords.slice(4, 6); + + // Create DES instances + this._des1 = DES.createEncryptor(WordArray.create(key1)); + this._des2 = DES.createEncryptor(WordArray.create(key2)); + this._des3 = DES.createEncryptor(WordArray.create(key3)); + }, + + encryptBlock: function (M, offset) { + this._des1.encryptBlock(M, offset); + this._des2.decryptBlock(M, offset); + this._des3.encryptBlock(M, offset); + }, + + decryptBlock: function (M, offset) { + this._des3.decryptBlock(M, offset); + this._des2.encryptBlock(M, offset); + this._des1.decryptBlock(M, offset); + }, + + keySize: 192/32, + + ivSize: 64/32, + + blockSize: 64/32 + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.TripleDES.encrypt(message, key, cfg); + * var plaintext = CryptoJS.TripleDES.decrypt(ciphertext, key, cfg); + */ + C.TripleDES = BlockCipher._createHelper(TripleDES); + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var StreamCipher = C_lib.StreamCipher; + var C_algo = C.algo; + + /** + * RC4 stream cipher algorithm. + */ + var RC4 = C_algo.RC4 = StreamCipher.extend({ + _doReset: function () { + // Shortcuts + var key = this._key; + var keyWords = key.words; + var keySigBytes = key.sigBytes; + + // Init sbox + var S = this._S = []; + for (var i = 0; i < 256; i++) { + S[i] = i; + } + + // Key setup + for (var i = 0, j = 0; i < 256; i++) { + var keyByteIndex = i % keySigBytes; + var keyByte = (keyWords[keyByteIndex >>> 2] >>> (24 - (keyByteIndex % 4) * 8)) & 0xff; + + j = (j + S[i] + keyByte) % 256; + + // Swap + var t = S[i]; + S[i] = S[j]; + S[j] = t; + } + + // Counters + this._i = this._j = 0; + }, + + _doProcessBlock: function (M, offset) { + M[offset] ^= generateKeystreamWord.call(this); + }, + + keySize: 256/32, + + ivSize: 0 + }); + + function generateKeystreamWord() { + // Shortcuts + var S = this._S; + var i = this._i; + var j = this._j; + + // Generate keystream word + var keystreamWord = 0; + for (var n = 0; n < 4; n++) { + i = (i + 1) % 256; + j = (j + S[i]) % 256; + + // Swap + var t = S[i]; + S[i] = S[j]; + S[j] = t; + + keystreamWord |= S[(S[i] + S[j]) % 256] << (24 - n * 8); + } + + // Update counters + this._i = i; + this._j = j; + + return keystreamWord; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.RC4.encrypt(message, key, cfg); + * var plaintext = CryptoJS.RC4.decrypt(ciphertext, key, cfg); + */ + C.RC4 = StreamCipher._createHelper(RC4); + + /** + * Modified RC4 stream cipher algorithm. + */ + var RC4Drop = C_algo.RC4Drop = RC4.extend({ + /** + * Configuration options. + * + * @property {number} drop The number of keystream words to drop. Default 192 + */ + cfg: RC4.cfg.extend({ + drop: 192 + }), + + _doReset: function () { + RC4._doReset.call(this); + + // Drop + for (var i = this.cfg.drop; i > 0; i--) { + generateKeystreamWord.call(this); + } + } + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.RC4Drop.encrypt(message, key, cfg); + * var plaintext = CryptoJS.RC4Drop.decrypt(ciphertext, key, cfg); + */ + C.RC4Drop = StreamCipher._createHelper(RC4Drop); + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var StreamCipher = C_lib.StreamCipher; + var C_algo = C.algo; + + // Reusable objects + var S = []; + var C_ = []; + var G = []; + + /** + * Rabbit stream cipher algorithm + */ + var Rabbit = C_algo.Rabbit = StreamCipher.extend({ + _doReset: function () { + // Shortcuts + var K = this._key.words; + var iv = this.cfg.iv; + + // Swap endian + for (var i = 0; i < 4; i++) { + K[i] = (((K[i] << 8) | (K[i] >>> 24)) & 0x00ff00ff) | + (((K[i] << 24) | (K[i] >>> 8)) & 0xff00ff00); + } + + // Generate initial state values + var X = this._X = [ + K[0], (K[3] << 16) | (K[2] >>> 16), + K[1], (K[0] << 16) | (K[3] >>> 16), + K[2], (K[1] << 16) | (K[0] >>> 16), + K[3], (K[2] << 16) | (K[1] >>> 16) + ]; + + // Generate initial counter values + var C = this._C = [ + (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff), + (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff), + (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff), + (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff) + ]; + + // Carry bit + this._b = 0; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + + // Modify the counters + for (var i = 0; i < 8; i++) { + C[i] ^= X[(i + 4) & 7]; + } + + // IV setup + if (iv) { + // Shortcuts + var IV = iv.words; + var IV_0 = IV[0]; + var IV_1 = IV[1]; + + // Generate four subvectors + var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00); + var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00); + var i1 = (i0 >>> 16) | (i2 & 0xffff0000); + var i3 = (i2 << 16) | (i0 & 0x0000ffff); + + // Modify counter values + C[0] ^= i0; + C[1] ^= i1; + C[2] ^= i2; + C[3] ^= i3; + C[4] ^= i0; + C[5] ^= i1; + C[6] ^= i2; + C[7] ^= i3; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + } + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var X = this._X; + + // Iterate the system + nextState.call(this); + + // Generate four keystream words + S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16); + S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16); + S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16); + S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16); + + for (var i = 0; i < 4; i++) { + // Swap endian + S[i] = (((S[i] << 8) | (S[i] >>> 24)) & 0x00ff00ff) | + (((S[i] << 24) | (S[i] >>> 8)) & 0xff00ff00); + + // Encrypt + M[offset + i] ^= S[i]; + } + }, + + blockSize: 128/32, + + ivSize: 64/32 + }); + + function nextState() { + // Shortcuts + var X = this._X; + var C = this._C; + + // Save old counter values + for (var i = 0; i < 8; i++) { + C_[i] = C[i]; + } + + // Calculate new counter values + C[0] = (C[0] + 0x4d34d34d + this._b) | 0; + C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0; + C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0; + C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0; + C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0; + C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0; + C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0; + C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0; + this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0; + + // Calculate the g-values + for (var i = 0; i < 8; i++) { + var gx = X[i] + C[i]; + + // Construct high and low argument for squaring + var ga = gx & 0xffff; + var gb = gx >>> 16; + + // Calculate high and low result of squaring + var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb; + var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0); + + // High XOR low + G[i] = gh ^ gl; + } + + // Calculate new state values + X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0; + X[1] = (G[1] + ((G[0] << 8) | (G[0] >>> 24)) + G[7]) | 0; + X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0; + X[3] = (G[3] + ((G[2] << 8) | (G[2] >>> 24)) + G[1]) | 0; + X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0; + X[5] = (G[5] + ((G[4] << 8) | (G[4] >>> 24)) + G[3]) | 0; + X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0; + X[7] = (G[7] + ((G[6] << 8) | (G[6] >>> 24)) + G[5]) | 0; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.Rabbit.encrypt(message, key, cfg); + * var plaintext = CryptoJS.Rabbit.decrypt(ciphertext, key, cfg); + */ + C.Rabbit = StreamCipher._createHelper(Rabbit); + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var StreamCipher = C_lib.StreamCipher; + var C_algo = C.algo; + + // Reusable objects + var S = []; + var C_ = []; + var G = []; + + /** + * Rabbit stream cipher algorithm. + * + * This is a legacy version that neglected to convert the key to little-endian. + * This error doesn't affect the cipher's security, + * but it does affect its compatibility with other implementations. + */ + var RabbitLegacy = C_algo.RabbitLegacy = StreamCipher.extend({ + _doReset: function () { + // Shortcuts + var K = this._key.words; + var iv = this.cfg.iv; + + // Generate initial state values + var X = this._X = [ + K[0], (K[3] << 16) | (K[2] >>> 16), + K[1], (K[0] << 16) | (K[3] >>> 16), + K[2], (K[1] << 16) | (K[0] >>> 16), + K[3], (K[2] << 16) | (K[1] >>> 16) + ]; + + // Generate initial counter values + var C = this._C = [ + (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff), + (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff), + (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff), + (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff) + ]; + + // Carry bit + this._b = 0; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + + // Modify the counters + for (var i = 0; i < 8; i++) { + C[i] ^= X[(i + 4) & 7]; + } + + // IV setup + if (iv) { + // Shortcuts + var IV = iv.words; + var IV_0 = IV[0]; + var IV_1 = IV[1]; + + // Generate four subvectors + var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00); + var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00); + var i1 = (i0 >>> 16) | (i2 & 0xffff0000); + var i3 = (i2 << 16) | (i0 & 0x0000ffff); + + // Modify counter values + C[0] ^= i0; + C[1] ^= i1; + C[2] ^= i2; + C[3] ^= i3; + C[4] ^= i0; + C[5] ^= i1; + C[6] ^= i2; + C[7] ^= i3; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + } + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var X = this._X; + + // Iterate the system + nextState.call(this); + + // Generate four keystream words + S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16); + S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16); + S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16); + S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16); + + for (var i = 0; i < 4; i++) { + // Swap endian + S[i] = (((S[i] << 8) | (S[i] >>> 24)) & 0x00ff00ff) | + (((S[i] << 24) | (S[i] >>> 8)) & 0xff00ff00); + + // Encrypt + M[offset + i] ^= S[i]; + } + }, + + blockSize: 128/32, + + ivSize: 64/32 + }); + + function nextState() { + // Shortcuts + var X = this._X; + var C = this._C; + + // Save old counter values + for (var i = 0; i < 8; i++) { + C_[i] = C[i]; + } + + // Calculate new counter values + C[0] = (C[0] + 0x4d34d34d + this._b) | 0; + C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0; + C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0; + C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0; + C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0; + C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0; + C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0; + C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0; + this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0; + + // Calculate the g-values + for (var i = 0; i < 8; i++) { + var gx = X[i] + C[i]; + + // Construct high and low argument for squaring + var ga = gx & 0xffff; + var gb = gx >>> 16; + + // Calculate high and low result of squaring + var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb; + var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0); + + // High XOR low + G[i] = gh ^ gl; + } + + // Calculate new state values + X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0; + X[1] = (G[1] + ((G[0] << 8) | (G[0] >>> 24)) + G[7]) | 0; + X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0; + X[3] = (G[3] + ((G[2] << 8) | (G[2] >>> 24)) + G[1]) | 0; + X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0; + X[5] = (G[5] + ((G[4] << 8) | (G[4] >>> 24)) + G[3]) | 0; + X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0; + X[7] = (G[7] + ((G[6] << 8) | (G[6] >>> 24)) + G[5]) | 0; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.RabbitLegacy.encrypt(message, key, cfg); + * var plaintext = CryptoJS.RabbitLegacy.decrypt(ciphertext, key, cfg); + */ + C.RabbitLegacy = StreamCipher._createHelper(RabbitLegacy); + }()); + + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var BlockCipher = C_lib.BlockCipher; + var C_algo = C.algo; + + const N = 16; + + //Origin pbox and sbox, derived from PI + const ORIG_P = [ + 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, + 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, + 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, + 0x9216D5D9, 0x8979FB1B + ]; + + const ORIG_S = [ + [ 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, + 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, + 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, + 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, + 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, + 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, + 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, + 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, + 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, + 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, + 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, + 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, + 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, + 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, + 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, + 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, + 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, + 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, + 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, + 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, + 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, + 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, + 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, + 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, + 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, + 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, + 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, + 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, + 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, + 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, + 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, + 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09, + 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, + 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, + 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, + 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, + 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, + 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, + 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, + 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, + 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, + 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, + 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, + 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, + 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, + 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, + 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, + 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, + 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, + 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, + 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, + 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, + 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, + 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, + 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, + 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, + 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, + 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, + 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, + 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, + 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, + 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, + 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, + 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A ], + [ 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, + 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, + 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, + 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, + 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, + 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, + 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, + 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, + 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, + 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, + 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, + 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, + 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, + 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, + 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, + 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331, + 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, + 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, + 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, + 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, + 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, + 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, + 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, + 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, + 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, + 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, + 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, + 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, + 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, + 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, + 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, + 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, + 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, + 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, + 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, + 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, + 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, + 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, + 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, + 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, + 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, + 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, + 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, + 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, + 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, + 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, + 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, + 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, + 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, + 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, + 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, + 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, + 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, + 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, + 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, + 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, + 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, + 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, + 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, + 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, + 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, + 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, + 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, + 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7 ], + [ 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, + 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, + 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, + 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, + 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, + 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, + 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, + 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, + 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, + 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, + 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, + 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, + 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, + 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, + 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, + 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, + 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, + 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, + 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, + 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, + 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, + 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, + 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, + 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, + 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, + 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, + 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, + 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, + 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, + 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, + 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, + 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, + 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, + 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, + 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, + 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, + 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, + 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, + 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, + 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, + 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, + 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, + 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, + 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, + 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, + 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, + 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, + 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C, + 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, + 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, + 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, + 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, + 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, + 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, + 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, + 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, + 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, + 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, + 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, + 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, + 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, + 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, + 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, + 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0 ], + [ 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, + 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, + 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, + 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, + 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, + 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, + 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, + 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, + 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, + 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, + 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, + 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, + 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, + 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, + 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, + 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, + 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, + 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, + 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, + 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, + 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, + 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, + 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, + 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, + 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, + 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, + 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, + 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, + 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, + 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, + 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, + 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47, + 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, + 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, + 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, + 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, + 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, + 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, + 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, + 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, + 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, + 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, + 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, + 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, + 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, + 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, + 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, + 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, + 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, + 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, + 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, + 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, + 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, + 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, + 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, + 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, + 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, + 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, + 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, + 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, + 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, + 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, + 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, + 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 ] + ]; + + var BLOWFISH_CTX = { + pbox: [], + sbox: [] + } + + function F(ctx, x){ + let a = (x >> 24) & 0xFF; + let b = (x >> 16) & 0xFF; + let c = (x >> 8) & 0xFF; + let d = x & 0xFF; + + let y = ctx.sbox[0][a] + ctx.sbox[1][b]; + y = y ^ ctx.sbox[2][c]; + y = y + ctx.sbox[3][d]; + + return y; + } + + function BlowFish_Encrypt(ctx, left, right){ + let Xl = left; + let Xr = right; + let temp; + + for(let i = 0; i < N; ++i){ + Xl = Xl ^ ctx.pbox[i]; + Xr = F(ctx, Xl) ^ Xr; + + temp = Xl; + Xl = Xr; + Xr = temp; + } + + temp = Xl; + Xl = Xr; + Xr = temp; + + Xr = Xr ^ ctx.pbox[N]; + Xl = Xl ^ ctx.pbox[N + 1]; + + return {left: Xl, right: Xr}; + } + + function BlowFish_Decrypt(ctx, left, right){ + let Xl = left; + let Xr = right; + let temp; + + for(let i = N + 1; i > 1; --i){ + Xl = Xl ^ ctx.pbox[i]; + Xr = F(ctx, Xl) ^ Xr; + + temp = Xl; + Xl = Xr; + Xr = temp; + } + + temp = Xl; + Xl = Xr; + Xr = temp; + + Xr = Xr ^ ctx.pbox[1]; + Xl = Xl ^ ctx.pbox[0]; + + return {left: Xl, right: Xr}; + } + + /** + * Initialization ctx's pbox and sbox. + * + * @param {Object} ctx The object has pbox and sbox. + * @param {Array} key An array of 32-bit words. + * @param {int} keysize The length of the key. + * + * @example + * + * BlowFishInit(BLOWFISH_CTX, key, 128/32); + */ + function BlowFishInit(ctx, key, keysize) + { + for(let Row = 0; Row < 4; Row++) + { + ctx.sbox[Row] = []; + for(let Col = 0; Col < 256; Col++) + { + ctx.sbox[Row][Col] = ORIG_S[Row][Col]; + } + } + + let keyIndex = 0; + for(let index = 0; index < N + 2; index++) + { + ctx.pbox[index] = ORIG_P[index] ^ key[keyIndex]; + keyIndex++; + if(keyIndex >= keysize) + { + keyIndex = 0; + } + } + + let Data1 = 0; + let Data2 = 0; + let res = 0; + for(let i = 0; i < N + 2; i += 2) + { + res = BlowFish_Encrypt(ctx, Data1, Data2); + Data1 = res.left; + Data2 = res.right; + ctx.pbox[i] = Data1; + ctx.pbox[i + 1] = Data2; + } + + for(let i = 0; i < 4; i++) + { + for(let j = 0; j < 256; j += 2) + { + res = BlowFish_Encrypt(ctx, Data1, Data2); + Data1 = res.left; + Data2 = res.right; + ctx.sbox[i][j] = Data1; + ctx.sbox[i][j + 1] = Data2; + } + } + + return true; + } + + /** + * Blowfish block cipher algorithm. + */ + var Blowfish = C_algo.Blowfish = BlockCipher.extend({ + _doReset: function () { + // Skip reset of nRounds has been set before and key did not change + if (this._keyPriorReset === this._key) { + return; + } + + // Shortcuts + var key = this._keyPriorReset = this._key; + var keyWords = key.words; + var keySize = key.sigBytes / 4; + + //Initialization pbox and sbox + BlowFishInit(BLOWFISH_CTX, keyWords, keySize); + }, + + encryptBlock: function (M, offset) { + var res = BlowFish_Encrypt(BLOWFISH_CTX, M[offset], M[offset + 1]); + M[offset] = res.left; + M[offset + 1] = res.right; + }, + + decryptBlock: function (M, offset) { + var res = BlowFish_Decrypt(BLOWFISH_CTX, M[offset], M[offset + 1]); + M[offset] = res.left; + M[offset + 1] = res.right; + }, + + blockSize: 64/32, + + keySize: 128/32, + + ivSize: 64/32 + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.Blowfish.encrypt(message, key, cfg); + * var plaintext = CryptoJS.Blowfish.decrypt(ciphertext, key, cfg); + */ + C.Blowfish = BlockCipher._createHelper(Blowfish); + }()); + + + return CryptoJS; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/docs/QuickStartGuide.wiki b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/docs/QuickStartGuide.wiki new file mode 100644 index 0000000..2bee35d --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/docs/QuickStartGuide.wiki @@ -0,0 +1,470 @@ + + +---- + += Quick-start Guide = + +== Hashers == + +=== The Hasher Algorithms === + +==== MD5 ==== + +MD5 is a widely used hash function. It's been used in a variety of security applications and is also commonly used to check the integrity of files. Though, MD5 is not collision resistant, and it isn't suitable for applications like SSL certificates or digital signatures that rely on this property. + +{{{ + + +}}} + +==== SHA-1 ==== + +The SHA hash functions were designed by the National Security Agency (NSA). SHA-1 is the most established of the existing SHA hash functions, and it's used in a variety of security applications and protocols. Though, SHA-1's collision resistance has been weakening as new attacks are discovered or improved. + +{{{ + + +}}} + +==== SHA-2 ==== + +SHA-256 is one of the four variants in the SHA-2 set. It isn't as widely used as SHA-1, though it appears to provide much better security. + +{{{ + + +}}} + +SHA-512 is largely identical to SHA-256 but operates on 64-bit words rather than 32. + +{{{ + + +}}} + +CryptoJS also supports SHA-224 and SHA-384, which are largely identical but truncated versions of SHA-256 and SHA-512 respectively. + +==== SHA-3 ==== + +SHA-3 is the winner of a five-year competition to select a new cryptographic hash algorithm where 64 competing designs were evaluated. + +{{{ + + +}}} + +SHA-3 can be configured to output hash lengths of one of 224, 256, 384, or 512 bits. The default is 512 bits. + +{{{ + + +}}} + +==== RIPEMD-160 ==== + +{{{ + + +}}} + +=== The Hasher Input === + +The hash algorithms accept either strings or instances of CryptoJS.lib.WordArray. A WordArray object represents an array of 32-bit words. When you pass a string, it's automatically converted to a WordArray encoded as UTF-8. + +=== The Hasher Output === + +The hash you get back isn't a string yet. It's a WordArray object. When you use a WordArray object in a string context, it's automatically converted to a hex string. + +{{{ + + +}}} + +You can convert a WordArray object to other formats by explicitly calling the toString method and passing an encoder. + +{{{ + + + +}}} + +=== Progressive Hashing === + +{{{ + + +}}} + +== HMAC == + +Keyed-hash message authentication codes (HMAC) is a mechanism for message authentication using cryptographic hash functions. + +HMAC can be used in combination with any iterated cryptographic hash function. + +{{{ + + + + + +}}} + +=== Progressive HMAC Hashing === + +{{{ + + +}}} + +== PBKDF2 == + +PBKDF2 is a password-based key derivation function. In many applications of cryptography, user security is ultimately dependent on a password, and because a password usually can't be used directly as a cryptographic key, some processing is required. + +A salt provides a large set of keys for any given password, and an iteration count increases the cost of producing keys from a password, thereby also increasing the difficulty of attack. + +{{{ + + +}}} + +== Ciphers == + +=== The Cipher Algorithms === + +==== AES ==== + +The Advanced Encryption Standard (AES) is a U.S. Federal Information Processing Standard (FIPS). It was selected after a 5-year process where 15 competing designs were evaluated. + +{{{ + + +}}} + +CryptoJS supports AES-128, AES-192, and AES-256. It will pick the variant by the size of the key you pass in. If you use a passphrase, then it will generate a 256-bit key. + +==== DES, Triple DES ==== + +DES is a previously dominant algorithm for encryption, and was published as an official Federal Information Processing Standard (FIPS). DES is now considered to be insecure due to the small key size. + +{{{ + + +}}} + +Triple DES applies DES three times to each block to increase the key size. The algorithm is believed to be secure in this form. + +{{{ + + +}}} + +==== Rabbit ==== + +Rabbit is a high-performance stream cipher and a finalist in the eSTREAM Portfolio. It is one of the four designs selected after a 3 1/2-year process where 22 designs were evaluated. + +{{{ + + +}}} + +==== RC4, RC4Drop ==== + +RC4 is a widely-used stream cipher. It's used in popular protocols such as SSL and WEP. Although remarkable for its simplicity and speed, the algorithm's history doesn't inspire confidence in its security. + +{{{ + + +}}} + +It was discovered that the first few bytes of keystream are strongly non-random and leak information about the key. We can defend against this attack by discarding the initial portion of the keystream. This modified algorithm is traditionally called RC4-drop. + +By default, 192 words (768 bytes) are dropped, but you can configure the algorithm to drop any number of words. + +{{{ + + +}}} + +=== Custom Key and IV === + +{{{ + + +}}} + +=== Block Modes and Padding === + +{{{ + + + + +}}} + +CryptoJS supports the following modes: + + * CBC (the default) + * CFB + * CTR + * OFB + * ECB + +And CryptoJS supports the following padding schemes: + + * Pkcs7 (the default) + * Iso97971 + * AnsiX923 + * Iso10126 + * ZeroPadding + * NoPadding + +=== The Cipher Input === + +For the plaintext message, the cipher algorithms accept either strings or instances of CryptoJS.lib.WordArray. + +For the key, when you pass a string, it's treated as a passphrase and used to derive an actual key and IV. Or you can pass a WordArray that represents the actual key. If you pass the actual key, you must also pass the actual IV. + +For the ciphertext, the cipher algorithms accept either strings or instances of CryptoJS.lib.CipherParams. A CipherParams object represents a collection of parameters such as the IV, a salt, and the raw ciphertext itself. When you pass a string, it's automatically converted to a CipherParams object according to a configurable format strategy. + +=== The Cipher Output === + +The plaintext you get back after decryption is a WordArray object. See Hashers' Output for more detail. + +The ciphertext you get back after encryption isn't a string yet. It's a CipherParams object. A CipherParams object gives you access to all the parameters used during encryption. When you use a CipherParams object in a string context, it's automatically converted to a string according to a format strategy. The default is an OpenSSL-compatible format. + +{{{ + + +}}} + +You can define your own formats in order to be compatible with other crypto implementations. A format is an object with two methods—stringify and parse—that converts between CipherParams objects and ciphertext strings. + +Here's how you might write a JSON formatter: + +{{{ + + +}}} + +=== Progressive Ciphering === + +{{{ + + +}}} + +=== Interoperability === + +==== With OpenSSL ==== + +Encrypt with OpenSSL: + +{{{ +openssl enc -aes-256-cbc -in infile -out outfile -pass pass:"Secret Passphrase" -e -base64 +}}} + +Decrypt with CryptoJS: + +{{{ + + +}}} + +== Encoders == + +CryptoJS can convert from encoding formats such as Base64, Latin1 or Hex to WordArray objects and vica versa. + +{{{ + + + + +}}} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-base64.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-base64.js new file mode 100644 index 0000000..0ffcd53 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-base64.js @@ -0,0 +1,136 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + + /** + * Base64 encoding strategy. + */ + var Base64 = C_enc.Base64 = { + /** + * Converts a word array to a Base64 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The Base64 string. + * + * @static + * + * @example + * + * var base64String = CryptoJS.enc.Base64.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var map = this._map; + + // Clamp excess bits + wordArray.clamp(); + + // Convert + var base64Chars = []; + for (var i = 0; i < sigBytes; i += 3) { + var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; + var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + + var triplet = (byte1 << 16) | (byte2 << 8) | byte3; + + for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { + base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); + } + } + + // Add padding + var paddingChar = map.charAt(64); + if (paddingChar) { + while (base64Chars.length % 4) { + base64Chars.push(paddingChar); + } + } + + return base64Chars.join(''); + }, + + /** + * Converts a Base64 string to a word array. + * + * @param {string} base64Str The Base64 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Base64.parse(base64String); + */ + parse: function (base64Str) { + // Shortcuts + var base64StrLength = base64Str.length; + var map = this._map; + var reverseMap = this._reverseMap; + + if (!reverseMap) { + reverseMap = this._reverseMap = []; + for (var j = 0; j < map.length; j++) { + reverseMap[map.charCodeAt(j)] = j; + } + } + + // Ignore padding + var paddingChar = map.charAt(64); + if (paddingChar) { + var paddingIndex = base64Str.indexOf(paddingChar); + if (paddingIndex !== -1) { + base64StrLength = paddingIndex; + } + } + + // Convert + return parseLoop(base64Str, base64StrLength, reverseMap); + + }, + + _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' + }; + + function parseLoop(base64Str, base64StrLength, reverseMap) { + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2); + var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2); + var bitsCombined = bits1 | bits2; + words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + return WordArray.create(words, nBytes); + } + }()); + + + return CryptoJS.enc.Base64; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-base64url.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-base64url.js new file mode 100644 index 0000000..af682e3 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-base64url.js @@ -0,0 +1,148 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + + /** + * Base64url encoding strategy. + */ + var Base64url = C_enc.Base64url = { + /** + * Converts a word array to a Base64url string. + * + * @param {WordArray} wordArray The word array. + * + * @param {boolean} urlSafe Whether to use url safe + * + * @return {string} The Base64url string. + * + * @static + * + * @example + * + * var base64String = CryptoJS.enc.Base64url.stringify(wordArray); + */ + stringify: function (wordArray, urlSafe) { + if (urlSafe === undefined) { + urlSafe = true + } + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var map = urlSafe ? this._safe_map : this._map; + + // Clamp excess bits + wordArray.clamp(); + + // Convert + var base64Chars = []; + for (var i = 0; i < sigBytes; i += 3) { + var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; + var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + + var triplet = (byte1 << 16) | (byte2 << 8) | byte3; + + for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { + base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); + } + } + + // Add padding + var paddingChar = map.charAt(64); + if (paddingChar) { + while (base64Chars.length % 4) { + base64Chars.push(paddingChar); + } + } + + return base64Chars.join(''); + }, + + /** + * Converts a Base64url string to a word array. + * + * @param {string} base64Str The Base64url string. + * + * @param {boolean} urlSafe Whether to use url safe + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Base64url.parse(base64String); + */ + parse: function (base64Str, urlSafe) { + if (urlSafe === undefined) { + urlSafe = true + } + + // Shortcuts + var base64StrLength = base64Str.length; + var map = urlSafe ? this._safe_map : this._map; + var reverseMap = this._reverseMap; + + if (!reverseMap) { + reverseMap = this._reverseMap = []; + for (var j = 0; j < map.length; j++) { + reverseMap[map.charCodeAt(j)] = j; + } + } + + // Ignore padding + var paddingChar = map.charAt(64); + if (paddingChar) { + var paddingIndex = base64Str.indexOf(paddingChar); + if (paddingIndex !== -1) { + base64StrLength = paddingIndex; + } + } + + // Convert + return parseLoop(base64Str, base64StrLength, reverseMap); + + }, + + _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', + _safe_map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', + }; + + function parseLoop(base64Str, base64StrLength, reverseMap) { + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2); + var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2); + var bitsCombined = bits1 | bits2; + words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + return WordArray.create(words, nBytes); + } + }()); + + + return CryptoJS.enc.Base64url; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-hex.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-hex.js new file mode 100644 index 0000000..88161ff --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-hex.js @@ -0,0 +1,18 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.enc.Hex; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-latin1.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-latin1.js new file mode 100644 index 0000000..ade56dc --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-latin1.js @@ -0,0 +1,18 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.enc.Latin1; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-utf16.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-utf16.js new file mode 100644 index 0000000..7de6245 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-utf16.js @@ -0,0 +1,149 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + + /** + * UTF-16 BE encoding strategy. + */ + var Utf16BE = C_enc.Utf16 = C_enc.Utf16BE = { + /** + * Converts a word array to a UTF-16 BE string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-16 BE string. + * + * @static + * + * @example + * + * var utf16String = CryptoJS.enc.Utf16.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var utf16Chars = []; + for (var i = 0; i < sigBytes; i += 2) { + var codePoint = (words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff; + utf16Chars.push(String.fromCharCode(codePoint)); + } + + return utf16Chars.join(''); + }, + + /** + * Converts a UTF-16 BE string to a word array. + * + * @param {string} utf16Str The UTF-16 BE string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf16.parse(utf16String); + */ + parse: function (utf16Str) { + // Shortcut + var utf16StrLength = utf16Str.length; + + // Convert + var words = []; + for (var i = 0; i < utf16StrLength; i++) { + words[i >>> 1] |= utf16Str.charCodeAt(i) << (16 - (i % 2) * 16); + } + + return WordArray.create(words, utf16StrLength * 2); + } + }; + + /** + * UTF-16 LE encoding strategy. + */ + C_enc.Utf16LE = { + /** + * Converts a word array to a UTF-16 LE string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-16 LE string. + * + * @static + * + * @example + * + * var utf16Str = CryptoJS.enc.Utf16LE.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var utf16Chars = []; + for (var i = 0; i < sigBytes; i += 2) { + var codePoint = swapEndian((words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff); + utf16Chars.push(String.fromCharCode(codePoint)); + } + + return utf16Chars.join(''); + }, + + /** + * Converts a UTF-16 LE string to a word array. + * + * @param {string} utf16Str The UTF-16 LE string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf16LE.parse(utf16Str); + */ + parse: function (utf16Str) { + // Shortcut + var utf16StrLength = utf16Str.length; + + // Convert + var words = []; + for (var i = 0; i < utf16StrLength; i++) { + words[i >>> 1] |= swapEndian(utf16Str.charCodeAt(i) << (16 - (i % 2) * 16)); + } + + return WordArray.create(words, utf16StrLength * 2); + } + }; + + function swapEndian(word) { + return ((word << 8) & 0xff00ff00) | ((word >>> 8) & 0x00ff00ff); + } + }()); + + + return CryptoJS.enc.Utf16; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-utf8.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-utf8.js new file mode 100644 index 0000000..e7a251d --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/enc-utf8.js @@ -0,0 +1,18 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.enc.Utf8; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/evpkdf.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/evpkdf.js new file mode 100644 index 0000000..578974a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/evpkdf.js @@ -0,0 +1,134 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./sha1"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./sha1", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var WordArray = C_lib.WordArray; + var C_algo = C.algo; + var MD5 = C_algo.MD5; + + /** + * This key derivation function is meant to conform with EVP_BytesToKey. + * www.openssl.org/docs/crypto/EVP_BytesToKey.html + */ + var EvpKDF = C_algo.EvpKDF = Base.extend({ + /** + * Configuration options. + * + * @property {number} keySize The key size in words to generate. Default: 4 (128 bits) + * @property {Hasher} hasher The hash algorithm to use. Default: MD5 + * @property {number} iterations The number of iterations to perform. Default: 1 + */ + cfg: Base.extend({ + keySize: 128/32, + hasher: MD5, + iterations: 1 + }), + + /** + * Initializes a newly created key derivation function. + * + * @param {Object} cfg (Optional) The configuration options to use for the derivation. + * + * @example + * + * var kdf = CryptoJS.algo.EvpKDF.create(); + * var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8 }); + * var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8, iterations: 1000 }); + */ + init: function (cfg) { + this.cfg = this.cfg.extend(cfg); + }, + + /** + * Derives a key from a password. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * + * @return {WordArray} The derived key. + * + * @example + * + * var key = kdf.compute(password, salt); + */ + compute: function (password, salt) { + var block; + + // Shortcut + var cfg = this.cfg; + + // Init hasher + var hasher = cfg.hasher.create(); + + // Initial values + var derivedKey = WordArray.create(); + + // Shortcuts + var derivedKeyWords = derivedKey.words; + var keySize = cfg.keySize; + var iterations = cfg.iterations; + + // Generate key + while (derivedKeyWords.length < keySize) { + if (block) { + hasher.update(block); + } + block = hasher.update(password).finalize(salt); + hasher.reset(); + + // Iterations + for (var i = 1; i < iterations; i++) { + block = hasher.finalize(block); + hasher.reset(); + } + + derivedKey.concat(block); + } + derivedKey.sigBytes = keySize * 4; + + return derivedKey; + } + }); + + /** + * Derives a key from a password. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * @param {Object} cfg (Optional) The configuration options to use for this computation. + * + * @return {WordArray} The derived key. + * + * @static + * + * @example + * + * var key = CryptoJS.EvpKDF(password, salt); + * var key = CryptoJS.EvpKDF(password, salt, { keySize: 8 }); + * var key = CryptoJS.EvpKDF(password, salt, { keySize: 8, iterations: 1000 }); + */ + C.EvpKDF = function (password, salt, cfg) { + return EvpKDF.create(cfg).compute(password, salt); + }; + }()); + + + return CryptoJS.EvpKDF; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/format-hex.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/format-hex.js new file mode 100644 index 0000000..2e9a861 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/format-hex.js @@ -0,0 +1,66 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function (undefined) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var CipherParams = C_lib.CipherParams; + var C_enc = C.enc; + var Hex = C_enc.Hex; + var C_format = C.format; + + var HexFormatter = C_format.Hex = { + /** + * Converts the ciphertext of a cipher params object to a hexadecimally encoded string. + * + * @param {CipherParams} cipherParams The cipher params object. + * + * @return {string} The hexadecimally encoded string. + * + * @static + * + * @example + * + * var hexString = CryptoJS.format.Hex.stringify(cipherParams); + */ + stringify: function (cipherParams) { + return cipherParams.ciphertext.toString(Hex); + }, + + /** + * Converts a hexadecimally encoded ciphertext string to a cipher params object. + * + * @param {string} input The hexadecimally encoded string. + * + * @return {CipherParams} The cipher params object. + * + * @static + * + * @example + * + * var cipherParams = CryptoJS.format.Hex.parse(hexString); + */ + parse: function (input) { + var ciphertext = Hex.parse(input); + return CipherParams.create({ ciphertext: ciphertext }); + } + }; + }()); + + + return CryptoJS.format.Hex; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/format-openssl.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/format-openssl.js new file mode 100644 index 0000000..3373edc --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/format-openssl.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.format.OpenSSL; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-md5.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-md5.js new file mode 100644 index 0000000..ad7a90a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-md5.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./md5"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./md5", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.HmacMD5; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-ripemd160.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-ripemd160.js new file mode 100644 index 0000000..73d55a7 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-ripemd160.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./ripemd160"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./ripemd160", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.HmacRIPEMD160; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha1.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha1.js new file mode 100644 index 0000000..0b570cb --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha1.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./sha1"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./sha1", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.HmacSHA1; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha224.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha224.js new file mode 100644 index 0000000..3778863 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha224.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./sha256"), require("./sha224"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./sha256", "./sha224", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.HmacSHA224; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha256.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha256.js new file mode 100644 index 0000000..33b0c9f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha256.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./sha256"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./sha256", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.HmacSHA256; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha3.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha3.js new file mode 100644 index 0000000..1248804 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha3.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core"), require("./sha3"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core", "./sha3", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.HmacSHA3; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha384.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha384.js new file mode 100644 index 0000000..0036e2b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha384.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core"), require("./sha512"), require("./sha384"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core", "./sha512", "./sha384", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.HmacSHA384; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha512.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha512.js new file mode 100644 index 0000000..c1005b6 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac-sha512.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core"), require("./sha512"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core", "./sha512", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.HmacSHA512; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac.js new file mode 100644 index 0000000..8c09851 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/hmac.js @@ -0,0 +1,143 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var C_enc = C.enc; + var Utf8 = C_enc.Utf8; + var C_algo = C.algo; + + /** + * HMAC algorithm. + */ + var HMAC = C_algo.HMAC = Base.extend({ + /** + * Initializes a newly created HMAC. + * + * @param {Hasher} hasher The hash algorithm to use. + * @param {WordArray|string} key The secret key. + * + * @example + * + * var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key); + */ + init: function (hasher, key) { + // Init hasher + hasher = this._hasher = new hasher.init(); + + // Convert string to WordArray, else assume WordArray already + if (typeof key == 'string') { + key = Utf8.parse(key); + } + + // Shortcuts + var hasherBlockSize = hasher.blockSize; + var hasherBlockSizeBytes = hasherBlockSize * 4; + + // Allow arbitrary length keys + if (key.sigBytes > hasherBlockSizeBytes) { + key = hasher.finalize(key); + } + + // Clamp excess bits + key.clamp(); + + // Clone key for inner and outer pads + var oKey = this._oKey = key.clone(); + var iKey = this._iKey = key.clone(); + + // Shortcuts + var oKeyWords = oKey.words; + var iKeyWords = iKey.words; + + // XOR keys with pad constants + for (var i = 0; i < hasherBlockSize; i++) { + oKeyWords[i] ^= 0x5c5c5c5c; + iKeyWords[i] ^= 0x36363636; + } + oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes; + + // Set initial values + this.reset(); + }, + + /** + * Resets this HMAC to its initial state. + * + * @example + * + * hmacHasher.reset(); + */ + reset: function () { + // Shortcut + var hasher = this._hasher; + + // Reset + hasher.reset(); + hasher.update(this._iKey); + }, + + /** + * Updates this HMAC with a message. + * + * @param {WordArray|string} messageUpdate The message to append. + * + * @return {HMAC} This HMAC instance. + * + * @example + * + * hmacHasher.update('message'); + * hmacHasher.update(wordArray); + */ + update: function (messageUpdate) { + this._hasher.update(messageUpdate); + + // Chainable + return this; + }, + + /** + * Finalizes the HMAC computation. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} messageUpdate (Optional) A final message update. + * + * @return {WordArray} The HMAC. + * + * @example + * + * var hmac = hmacHasher.finalize(); + * var hmac = hmacHasher.finalize('message'); + * var hmac = hmacHasher.finalize(wordArray); + */ + finalize: function (messageUpdate) { + // Shortcut + var hasher = this._hasher; + + // Compute HMAC + var innerHash = hasher.finalize(messageUpdate); + hasher.reset(); + var hmac = hasher.finalize(this._oKey.clone().concat(innerHash)); + + return hmac; + } + }); + }()); + + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/index.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/index.js new file mode 100644 index 0000000..b696646 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/index.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core"), require("./lib-typedarrays"), require("./enc-utf16"), require("./enc-base64"), require("./enc-base64url"), require("./md5"), require("./sha1"), require("./sha256"), require("./sha224"), require("./sha512"), require("./sha384"), require("./sha3"), require("./ripemd160"), require("./hmac"), require("./pbkdf2"), require("./evpkdf"), require("./cipher-core"), require("./mode-cfb"), require("./mode-ctr"), require("./mode-ctr-gladman"), require("./mode-ofb"), require("./mode-ecb"), require("./pad-ansix923"), require("./pad-iso10126"), require("./pad-iso97971"), require("./pad-zeropadding"), require("./pad-nopadding"), require("./format-hex"), require("./aes"), require("./tripledes"), require("./rc4"), require("./rabbit"), require("./rabbit-legacy"), require("./blowfish")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core", "./lib-typedarrays", "./enc-utf16", "./enc-base64", "./enc-base64url", "./md5", "./sha1", "./sha256", "./sha224", "./sha512", "./sha384", "./sha3", "./ripemd160", "./hmac", "./pbkdf2", "./evpkdf", "./cipher-core", "./mode-cfb", "./mode-ctr", "./mode-ctr-gladman", "./mode-ofb", "./mode-ecb", "./pad-ansix923", "./pad-iso10126", "./pad-iso97971", "./pad-zeropadding", "./pad-nopadding", "./format-hex", "./aes", "./tripledes", "./rc4", "./rabbit", "./rabbit-legacy", "./blowfish"], factory); + } + else { + // Global (browser) + root.CryptoJS = factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/lib-typedarrays.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/lib-typedarrays.js new file mode 100644 index 0000000..264b210 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/lib-typedarrays.js @@ -0,0 +1,76 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Check if typed arrays are supported + if (typeof ArrayBuffer != 'function') { + return; + } + + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + + // Reference original init + var superInit = WordArray.init; + + // Augment WordArray.init to handle typed arrays + var subInit = WordArray.init = function (typedArray) { + // Convert buffers to uint8 + if (typedArray instanceof ArrayBuffer) { + typedArray = new Uint8Array(typedArray); + } + + // Convert other array views to uint8 + if ( + typedArray instanceof Int8Array || + (typeof Uint8ClampedArray !== "undefined" && typedArray instanceof Uint8ClampedArray) || + typedArray instanceof Int16Array || + typedArray instanceof Uint16Array || + typedArray instanceof Int32Array || + typedArray instanceof Uint32Array || + typedArray instanceof Float32Array || + typedArray instanceof Float64Array + ) { + typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength); + } + + // Handle Uint8Array + if (typedArray instanceof Uint8Array) { + // Shortcut + var typedArrayByteLength = typedArray.byteLength; + + // Extract bytes + var words = []; + for (var i = 0; i < typedArrayByteLength; i++) { + words[i >>> 2] |= typedArray[i] << (24 - (i % 4) * 8); + } + + // Initialize this word array + superInit.call(this, words, typedArrayByteLength); + } else { + // Else call normal init + superInit.apply(this, arguments); + } + }; + + subInit.prototype = WordArray; + }()); + + + return CryptoJS.lib.WordArray; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/md5.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/md5.js new file mode 100644 index 0000000..72fce03 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/md5.js @@ -0,0 +1,268 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Constants table + var T = []; + + // Compute constants + (function () { + for (var i = 0; i < 64; i++) { + T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0; + } + }()); + + /** + * MD5 hash algorithm. + */ + var MD5 = C_algo.MD5 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0x67452301, 0xefcdab89, + 0x98badcfe, 0x10325476 + ]); + }, + + _doProcessBlock: function (M, offset) { + // Swap endian + for (var i = 0; i < 16; i++) { + // Shortcuts + var offset_i = offset + i; + var M_offset_i = M[offset_i]; + + M[offset_i] = ( + (((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) | + (((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00) + ); + } + + // Shortcuts + var H = this._hash.words; + + var M_offset_0 = M[offset + 0]; + var M_offset_1 = M[offset + 1]; + var M_offset_2 = M[offset + 2]; + var M_offset_3 = M[offset + 3]; + var M_offset_4 = M[offset + 4]; + var M_offset_5 = M[offset + 5]; + var M_offset_6 = M[offset + 6]; + var M_offset_7 = M[offset + 7]; + var M_offset_8 = M[offset + 8]; + var M_offset_9 = M[offset + 9]; + var M_offset_10 = M[offset + 10]; + var M_offset_11 = M[offset + 11]; + var M_offset_12 = M[offset + 12]; + var M_offset_13 = M[offset + 13]; + var M_offset_14 = M[offset + 14]; + var M_offset_15 = M[offset + 15]; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + + // Computation + a = FF(a, b, c, d, M_offset_0, 7, T[0]); + d = FF(d, a, b, c, M_offset_1, 12, T[1]); + c = FF(c, d, a, b, M_offset_2, 17, T[2]); + b = FF(b, c, d, a, M_offset_3, 22, T[3]); + a = FF(a, b, c, d, M_offset_4, 7, T[4]); + d = FF(d, a, b, c, M_offset_5, 12, T[5]); + c = FF(c, d, a, b, M_offset_6, 17, T[6]); + b = FF(b, c, d, a, M_offset_7, 22, T[7]); + a = FF(a, b, c, d, M_offset_8, 7, T[8]); + d = FF(d, a, b, c, M_offset_9, 12, T[9]); + c = FF(c, d, a, b, M_offset_10, 17, T[10]); + b = FF(b, c, d, a, M_offset_11, 22, T[11]); + a = FF(a, b, c, d, M_offset_12, 7, T[12]); + d = FF(d, a, b, c, M_offset_13, 12, T[13]); + c = FF(c, d, a, b, M_offset_14, 17, T[14]); + b = FF(b, c, d, a, M_offset_15, 22, T[15]); + + a = GG(a, b, c, d, M_offset_1, 5, T[16]); + d = GG(d, a, b, c, M_offset_6, 9, T[17]); + c = GG(c, d, a, b, M_offset_11, 14, T[18]); + b = GG(b, c, d, a, M_offset_0, 20, T[19]); + a = GG(a, b, c, d, M_offset_5, 5, T[20]); + d = GG(d, a, b, c, M_offset_10, 9, T[21]); + c = GG(c, d, a, b, M_offset_15, 14, T[22]); + b = GG(b, c, d, a, M_offset_4, 20, T[23]); + a = GG(a, b, c, d, M_offset_9, 5, T[24]); + d = GG(d, a, b, c, M_offset_14, 9, T[25]); + c = GG(c, d, a, b, M_offset_3, 14, T[26]); + b = GG(b, c, d, a, M_offset_8, 20, T[27]); + a = GG(a, b, c, d, M_offset_13, 5, T[28]); + d = GG(d, a, b, c, M_offset_2, 9, T[29]); + c = GG(c, d, a, b, M_offset_7, 14, T[30]); + b = GG(b, c, d, a, M_offset_12, 20, T[31]); + + a = HH(a, b, c, d, M_offset_5, 4, T[32]); + d = HH(d, a, b, c, M_offset_8, 11, T[33]); + c = HH(c, d, a, b, M_offset_11, 16, T[34]); + b = HH(b, c, d, a, M_offset_14, 23, T[35]); + a = HH(a, b, c, d, M_offset_1, 4, T[36]); + d = HH(d, a, b, c, M_offset_4, 11, T[37]); + c = HH(c, d, a, b, M_offset_7, 16, T[38]); + b = HH(b, c, d, a, M_offset_10, 23, T[39]); + a = HH(a, b, c, d, M_offset_13, 4, T[40]); + d = HH(d, a, b, c, M_offset_0, 11, T[41]); + c = HH(c, d, a, b, M_offset_3, 16, T[42]); + b = HH(b, c, d, a, M_offset_6, 23, T[43]); + a = HH(a, b, c, d, M_offset_9, 4, T[44]); + d = HH(d, a, b, c, M_offset_12, 11, T[45]); + c = HH(c, d, a, b, M_offset_15, 16, T[46]); + b = HH(b, c, d, a, M_offset_2, 23, T[47]); + + a = II(a, b, c, d, M_offset_0, 6, T[48]); + d = II(d, a, b, c, M_offset_7, 10, T[49]); + c = II(c, d, a, b, M_offset_14, 15, T[50]); + b = II(b, c, d, a, M_offset_5, 21, T[51]); + a = II(a, b, c, d, M_offset_12, 6, T[52]); + d = II(d, a, b, c, M_offset_3, 10, T[53]); + c = II(c, d, a, b, M_offset_10, 15, T[54]); + b = II(b, c, d, a, M_offset_1, 21, T[55]); + a = II(a, b, c, d, M_offset_8, 6, T[56]); + d = II(d, a, b, c, M_offset_15, 10, T[57]); + c = II(c, d, a, b, M_offset_6, 15, T[58]); + b = II(b, c, d, a, M_offset_13, 21, T[59]); + a = II(a, b, c, d, M_offset_4, 6, T[60]); + d = II(d, a, b, c, M_offset_11, 10, T[61]); + c = II(c, d, a, b, M_offset_2, 15, T[62]); + b = II(b, c, d, a, M_offset_9, 21, T[63]); + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + + var nBitsTotalH = Math.floor(nBitsTotal / 0x100000000); + var nBitsTotalL = nBitsTotal; + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = ( + (((nBitsTotalH << 8) | (nBitsTotalH >>> 24)) & 0x00ff00ff) | + (((nBitsTotalH << 24) | (nBitsTotalH >>> 8)) & 0xff00ff00) + ); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = ( + (((nBitsTotalL << 8) | (nBitsTotalL >>> 24)) & 0x00ff00ff) | + (((nBitsTotalL << 24) | (nBitsTotalL >>> 8)) & 0xff00ff00) + ); + + data.sigBytes = (dataWords.length + 1) * 4; + + // Hash final blocks + this._process(); + + // Shortcuts + var hash = this._hash; + var H = hash.words; + + // Swap endian + for (var i = 0; i < 4; i++) { + // Shortcut + var H_i = H[i]; + + H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) | + (((H_i << 24) | (H_i >>> 8)) & 0xff00ff00); + } + + // Return final computed hash + return hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + function FF(a, b, c, d, x, s, t) { + var n = a + ((b & c) | (~b & d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function GG(a, b, c, d, x, s, t) { + var n = a + ((b & d) | (c & ~d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function HH(a, b, c, d, x, s, t) { + var n = a + (b ^ c ^ d) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function II(a, b, c, d, x, s, t) { + var n = a + (c ^ (b | ~d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.MD5('message'); + * var hash = CryptoJS.MD5(wordArray); + */ + C.MD5 = Hasher._createHelper(MD5); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacMD5(message, key); + */ + C.HmacMD5 = Hasher._createHmacHelper(MD5); + }(Math)); + + + return CryptoJS.MD5; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-cfb.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-cfb.js new file mode 100644 index 0000000..444c9cb --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-cfb.js @@ -0,0 +1,80 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Cipher Feedback block mode. + */ + CryptoJS.mode.CFB = (function () { + var CFB = CryptoJS.lib.BlockCipherMode.extend(); + + CFB.Encryptor = CFB.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher); + + // Remember this block to use with next block + this._prevBlock = words.slice(offset, offset + blockSize); + } + }); + + CFB.Decryptor = CFB.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + // Remember this block to use with next block + var thisBlock = words.slice(offset, offset + blockSize); + + generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher); + + // This block becomes the previous block + this._prevBlock = thisBlock; + } + }); + + function generateKeystreamAndEncrypt(words, offset, blockSize, cipher) { + var keystream; + + // Shortcut + var iv = this._iv; + + // Generate keystream + if (iv) { + keystream = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } else { + keystream = this._prevBlock; + } + cipher.encryptBlock(keystream, 0); + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + + return CFB; + }()); + + + return CryptoJS.mode.CFB; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-ctr-gladman.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-ctr-gladman.js new file mode 100644 index 0000000..bbc5687 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-ctr-gladman.js @@ -0,0 +1,116 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** @preserve + * Counter block mode compatible with Dr Brian Gladman fileenc.c + * derived from CryptoJS.mode.CTR + * Jan Hruby jhruby.web@gmail.com + */ + CryptoJS.mode.CTRGladman = (function () { + var CTRGladman = CryptoJS.lib.BlockCipherMode.extend(); + + function incWord(word) + { + if (((word >> 24) & 0xff) === 0xff) { //overflow + var b1 = (word >> 16)&0xff; + var b2 = (word >> 8)&0xff; + var b3 = word & 0xff; + + if (b1 === 0xff) // overflow b1 + { + b1 = 0; + if (b2 === 0xff) + { + b2 = 0; + if (b3 === 0xff) + { + b3 = 0; + } + else + { + ++b3; + } + } + else + { + ++b2; + } + } + else + { + ++b1; + } + + word = 0; + word += (b1 << 16); + word += (b2 << 8); + word += b3; + } + else + { + word += (0x01 << 24); + } + return word; + } + + function incCounter(counter) + { + if ((counter[0] = incWord(counter[0])) === 0) + { + // encr_data in fileenc.c from Dr Brian Gladman's counts only with DWORD j < 8 + counter[1] = incWord(counter[1]); + } + return counter; + } + + var Encryptor = CTRGladman.Encryptor = CTRGladman.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher + var blockSize = cipher.blockSize; + var iv = this._iv; + var counter = this._counter; + + // Generate keystream + if (iv) { + counter = this._counter = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } + + incCounter(counter); + + var keystream = counter.slice(0); + cipher.encryptBlock(keystream, 0); + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + }); + + CTRGladman.Decryptor = Encryptor; + + return CTRGladman; + }()); + + + + + return CryptoJS.mode.CTRGladman; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-ctr.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-ctr.js new file mode 100644 index 0000000..c3d470a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-ctr.js @@ -0,0 +1,58 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Counter block mode. + */ + CryptoJS.mode.CTR = (function () { + var CTR = CryptoJS.lib.BlockCipherMode.extend(); + + var Encryptor = CTR.Encryptor = CTR.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher + var blockSize = cipher.blockSize; + var iv = this._iv; + var counter = this._counter; + + // Generate keystream + if (iv) { + counter = this._counter = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } + var keystream = counter.slice(0); + cipher.encryptBlock(keystream, 0); + + // Increment counter + counter[blockSize - 1] = (counter[blockSize - 1] + 1) | 0 + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + }); + + CTR.Decryptor = Encryptor; + + return CTR; + }()); + + + return CryptoJS.mode.CTR; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-ecb.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-ecb.js new file mode 100644 index 0000000..ff06921 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-ecb.js @@ -0,0 +1,40 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Electronic Codebook block mode. + */ + CryptoJS.mode.ECB = (function () { + var ECB = CryptoJS.lib.BlockCipherMode.extend(); + + ECB.Encryptor = ECB.extend({ + processBlock: function (words, offset) { + this._cipher.encryptBlock(words, offset); + } + }); + + ECB.Decryptor = ECB.extend({ + processBlock: function (words, offset) { + this._cipher.decryptBlock(words, offset); + } + }); + + return ECB; + }()); + + + return CryptoJS.mode.ECB; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-ofb.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-ofb.js new file mode 100644 index 0000000..c01314c --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/mode-ofb.js @@ -0,0 +1,54 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Output Feedback block mode. + */ + CryptoJS.mode.OFB = (function () { + var OFB = CryptoJS.lib.BlockCipherMode.extend(); + + var Encryptor = OFB.Encryptor = OFB.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher + var blockSize = cipher.blockSize; + var iv = this._iv; + var keystream = this._keystream; + + // Generate keystream + if (iv) { + keystream = this._keystream = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } + cipher.encryptBlock(keystream, 0); + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + }); + + OFB.Decryptor = Encryptor; + + return OFB; + }()); + + + return CryptoJS.mode.OFB; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/package.json b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/package.json new file mode 100644 index 0000000..fe24e65 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/package.json @@ -0,0 +1,70 @@ +{ + "_from": "crypto-js@4.2.0", + "_id": "crypto-js@4.2.0", + "_inBundle": false, + "_integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", + "_location": "/crypto-js", + "_phantomChildren": {}, + "_requested": { + "type": "version", + "registry": true, + "raw": "crypto-js@4.2.0", + "name": "crypto-js", + "escapedName": "crypto-js", + "rawSpec": "4.2.0", + "saveSpec": null, + "fetchSpec": "4.2.0" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "_shasum": "4d931639ecdfd12ff80e8186dba6af2c2e856631", + "_spec": "crypto-js@4.2.0", + "_where": "C:\\Users\\59409\\Documents\\HBuilderProjects\\jinjiuxin-pc\\uniCloud-aliyun\\cloudfunctions\\router", + "author": { + "name": "Evan Vosberg", + "url": "http://github.com/evanvosberg" + }, + "browser": { + "crypto": false + }, + "bugs": { + "url": "https://github.com/brix/crypto-js/issues" + }, + "bundleDependencies": false, + "dependencies": {}, + "deprecated": false, + "description": "JavaScript library of crypto standards.", + "homepage": "http://github.com/brix/crypto-js", + "keywords": [ + "security", + "crypto", + "Hash", + "MD5", + "SHA1", + "SHA-1", + "SHA256", + "SHA-256", + "RC4", + "Rabbit", + "AES", + "DES", + "PBKDF2", + "HMAC", + "OFB", + "CFB", + "CTR", + "CBC", + "Base64", + "Base64url" + ], + "license": "MIT", + "main": "index.js", + "name": "crypto-js", + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/brix/crypto-js.git" + }, + "version": "4.2.0" +} diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-ansix923.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-ansix923.js new file mode 100644 index 0000000..f01f21e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-ansix923.js @@ -0,0 +1,49 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * ANSI X.923 padding strategy. + */ + CryptoJS.pad.AnsiX923 = { + pad: function (data, blockSize) { + // Shortcuts + var dataSigBytes = data.sigBytes; + var blockSizeBytes = blockSize * 4; + + // Count padding bytes + var nPaddingBytes = blockSizeBytes - dataSigBytes % blockSizeBytes; + + // Compute last byte position + var lastBytePos = dataSigBytes + nPaddingBytes - 1; + + // Pad + data.clamp(); + data.words[lastBytePos >>> 2] |= nPaddingBytes << (24 - (lastBytePos % 4) * 8); + data.sigBytes += nPaddingBytes; + }, + + unpad: function (data) { + // Get number of padding bytes from last byte + var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + + // Remove padding + data.sigBytes -= nPaddingBytes; + } + }; + + + return CryptoJS.pad.Ansix923; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-iso10126.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-iso10126.js new file mode 100644 index 0000000..6e2aefd --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-iso10126.js @@ -0,0 +1,44 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * ISO 10126 padding strategy. + */ + CryptoJS.pad.Iso10126 = { + pad: function (data, blockSize) { + // Shortcut + var blockSizeBytes = blockSize * 4; + + // Count padding bytes + var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes; + + // Pad + data.concat(CryptoJS.lib.WordArray.random(nPaddingBytes - 1)). + concat(CryptoJS.lib.WordArray.create([nPaddingBytes << 24], 1)); + }, + + unpad: function (data) { + // Get number of padding bytes from last byte + var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + + // Remove padding + data.sigBytes -= nPaddingBytes; + } + }; + + + return CryptoJS.pad.Iso10126; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-iso97971.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-iso97971.js new file mode 100644 index 0000000..41049b4 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-iso97971.js @@ -0,0 +1,40 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * ISO/IEC 9797-1 Padding Method 2. + */ + CryptoJS.pad.Iso97971 = { + pad: function (data, blockSize) { + // Add 0x80 byte + data.concat(CryptoJS.lib.WordArray.create([0x80000000], 1)); + + // Zero pad the rest + CryptoJS.pad.ZeroPadding.pad(data, blockSize); + }, + + unpad: function (data) { + // Remove zero padding + CryptoJS.pad.ZeroPadding.unpad(data); + + // Remove one more byte -- the 0x80 byte + data.sigBytes--; + } + }; + + + return CryptoJS.pad.Iso97971; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-nopadding.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-nopadding.js new file mode 100644 index 0000000..c7787c9 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-nopadding.js @@ -0,0 +1,30 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * A noop padding strategy. + */ + CryptoJS.pad.NoPadding = { + pad: function () { + }, + + unpad: function () { + } + }; + + + return CryptoJS.pad.NoPadding; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-pkcs7.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-pkcs7.js new file mode 100644 index 0000000..3555168 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-pkcs7.js @@ -0,0 +1,18 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS.pad.Pkcs7; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-zeropadding.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-zeropadding.js new file mode 100644 index 0000000..a1a459e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pad-zeropadding.js @@ -0,0 +1,47 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Zero padding strategy. + */ + CryptoJS.pad.ZeroPadding = { + pad: function (data, blockSize) { + // Shortcut + var blockSizeBytes = blockSize * 4; + + // Pad + data.clamp(); + data.sigBytes += blockSizeBytes - ((data.sigBytes % blockSizeBytes) || blockSizeBytes); + }, + + unpad: function (data) { + // Shortcut + var dataWords = data.words; + + // Unpad + var i = data.sigBytes - 1; + for (var i = data.sigBytes - 1; i >= 0; i--) { + if (((dataWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff)) { + data.sigBytes = i + 1; + break; + } + } + } + }; + + + return CryptoJS.pad.ZeroPadding; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pbkdf2.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pbkdf2.js new file mode 100644 index 0000000..6850934 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/pbkdf2.js @@ -0,0 +1,145 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./sha256"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./sha256", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var WordArray = C_lib.WordArray; + var C_algo = C.algo; + var SHA256 = C_algo.SHA256; + var HMAC = C_algo.HMAC; + + /** + * Password-Based Key Derivation Function 2 algorithm. + */ + var PBKDF2 = C_algo.PBKDF2 = Base.extend({ + /** + * Configuration options. + * + * @property {number} keySize The key size in words to generate. Default: 4 (128 bits) + * @property {Hasher} hasher The hasher to use. Default: SHA256 + * @property {number} iterations The number of iterations to perform. Default: 250000 + */ + cfg: Base.extend({ + keySize: 128/32, + hasher: SHA256, + iterations: 250000 + }), + + /** + * Initializes a newly created key derivation function. + * + * @param {Object} cfg (Optional) The configuration options to use for the derivation. + * + * @example + * + * var kdf = CryptoJS.algo.PBKDF2.create(); + * var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8 }); + * var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8, iterations: 1000 }); + */ + init: function (cfg) { + this.cfg = this.cfg.extend(cfg); + }, + + /** + * Computes the Password-Based Key Derivation Function 2. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * + * @return {WordArray} The derived key. + * + * @example + * + * var key = kdf.compute(password, salt); + */ + compute: function (password, salt) { + // Shortcut + var cfg = this.cfg; + + // Init HMAC + var hmac = HMAC.create(cfg.hasher, password); + + // Initial values + var derivedKey = WordArray.create(); + var blockIndex = WordArray.create([0x00000001]); + + // Shortcuts + var derivedKeyWords = derivedKey.words; + var blockIndexWords = blockIndex.words; + var keySize = cfg.keySize; + var iterations = cfg.iterations; + + // Generate key + while (derivedKeyWords.length < keySize) { + var block = hmac.update(salt).finalize(blockIndex); + hmac.reset(); + + // Shortcuts + var blockWords = block.words; + var blockWordsLength = blockWords.length; + + // Iterations + var intermediate = block; + for (var i = 1; i < iterations; i++) { + intermediate = hmac.finalize(intermediate); + hmac.reset(); + + // Shortcut + var intermediateWords = intermediate.words; + + // XOR intermediate with block + for (var j = 0; j < blockWordsLength; j++) { + blockWords[j] ^= intermediateWords[j]; + } + } + + derivedKey.concat(block); + blockIndexWords[0]++; + } + derivedKey.sigBytes = keySize * 4; + + return derivedKey; + } + }); + + /** + * Computes the Password-Based Key Derivation Function 2. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * @param {Object} cfg (Optional) The configuration options to use for this computation. + * + * @return {WordArray} The derived key. + * + * @static + * + * @example + * + * var key = CryptoJS.PBKDF2(password, salt); + * var key = CryptoJS.PBKDF2(password, salt, { keySize: 8 }); + * var key = CryptoJS.PBKDF2(password, salt, { keySize: 8, iterations: 1000 }); + */ + C.PBKDF2 = function (password, salt, cfg) { + return PBKDF2.create(cfg).compute(password, salt); + }; + }()); + + + return CryptoJS.PBKDF2; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/rabbit-legacy.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/rabbit-legacy.js new file mode 100644 index 0000000..e118b6b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/rabbit-legacy.js @@ -0,0 +1,190 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var StreamCipher = C_lib.StreamCipher; + var C_algo = C.algo; + + // Reusable objects + var S = []; + var C_ = []; + var G = []; + + /** + * Rabbit stream cipher algorithm. + * + * This is a legacy version that neglected to convert the key to little-endian. + * This error doesn't affect the cipher's security, + * but it does affect its compatibility with other implementations. + */ + var RabbitLegacy = C_algo.RabbitLegacy = StreamCipher.extend({ + _doReset: function () { + // Shortcuts + var K = this._key.words; + var iv = this.cfg.iv; + + // Generate initial state values + var X = this._X = [ + K[0], (K[3] << 16) | (K[2] >>> 16), + K[1], (K[0] << 16) | (K[3] >>> 16), + K[2], (K[1] << 16) | (K[0] >>> 16), + K[3], (K[2] << 16) | (K[1] >>> 16) + ]; + + // Generate initial counter values + var C = this._C = [ + (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff), + (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff), + (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff), + (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff) + ]; + + // Carry bit + this._b = 0; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + + // Modify the counters + for (var i = 0; i < 8; i++) { + C[i] ^= X[(i + 4) & 7]; + } + + // IV setup + if (iv) { + // Shortcuts + var IV = iv.words; + var IV_0 = IV[0]; + var IV_1 = IV[1]; + + // Generate four subvectors + var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00); + var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00); + var i1 = (i0 >>> 16) | (i2 & 0xffff0000); + var i3 = (i2 << 16) | (i0 & 0x0000ffff); + + // Modify counter values + C[0] ^= i0; + C[1] ^= i1; + C[2] ^= i2; + C[3] ^= i3; + C[4] ^= i0; + C[5] ^= i1; + C[6] ^= i2; + C[7] ^= i3; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + } + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var X = this._X; + + // Iterate the system + nextState.call(this); + + // Generate four keystream words + S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16); + S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16); + S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16); + S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16); + + for (var i = 0; i < 4; i++) { + // Swap endian + S[i] = (((S[i] << 8) | (S[i] >>> 24)) & 0x00ff00ff) | + (((S[i] << 24) | (S[i] >>> 8)) & 0xff00ff00); + + // Encrypt + M[offset + i] ^= S[i]; + } + }, + + blockSize: 128/32, + + ivSize: 64/32 + }); + + function nextState() { + // Shortcuts + var X = this._X; + var C = this._C; + + // Save old counter values + for (var i = 0; i < 8; i++) { + C_[i] = C[i]; + } + + // Calculate new counter values + C[0] = (C[0] + 0x4d34d34d + this._b) | 0; + C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0; + C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0; + C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0; + C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0; + C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0; + C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0; + C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0; + this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0; + + // Calculate the g-values + for (var i = 0; i < 8; i++) { + var gx = X[i] + C[i]; + + // Construct high and low argument for squaring + var ga = gx & 0xffff; + var gb = gx >>> 16; + + // Calculate high and low result of squaring + var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb; + var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0); + + // High XOR low + G[i] = gh ^ gl; + } + + // Calculate new state values + X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0; + X[1] = (G[1] + ((G[0] << 8) | (G[0] >>> 24)) + G[7]) | 0; + X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0; + X[3] = (G[3] + ((G[2] << 8) | (G[2] >>> 24)) + G[1]) | 0; + X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0; + X[5] = (G[5] + ((G[4] << 8) | (G[4] >>> 24)) + G[3]) | 0; + X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0; + X[7] = (G[7] + ((G[6] << 8) | (G[6] >>> 24)) + G[5]) | 0; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.RabbitLegacy.encrypt(message, key, cfg); + * var plaintext = CryptoJS.RabbitLegacy.decrypt(ciphertext, key, cfg); + */ + C.RabbitLegacy = StreamCipher._createHelper(RabbitLegacy); + }()); + + + return CryptoJS.RabbitLegacy; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/rabbit.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/rabbit.js new file mode 100644 index 0000000..1b06833 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/rabbit.js @@ -0,0 +1,192 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var StreamCipher = C_lib.StreamCipher; + var C_algo = C.algo; + + // Reusable objects + var S = []; + var C_ = []; + var G = []; + + /** + * Rabbit stream cipher algorithm + */ + var Rabbit = C_algo.Rabbit = StreamCipher.extend({ + _doReset: function () { + // Shortcuts + var K = this._key.words; + var iv = this.cfg.iv; + + // Swap endian + for (var i = 0; i < 4; i++) { + K[i] = (((K[i] << 8) | (K[i] >>> 24)) & 0x00ff00ff) | + (((K[i] << 24) | (K[i] >>> 8)) & 0xff00ff00); + } + + // Generate initial state values + var X = this._X = [ + K[0], (K[3] << 16) | (K[2] >>> 16), + K[1], (K[0] << 16) | (K[3] >>> 16), + K[2], (K[1] << 16) | (K[0] >>> 16), + K[3], (K[2] << 16) | (K[1] >>> 16) + ]; + + // Generate initial counter values + var C = this._C = [ + (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff), + (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff), + (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff), + (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff) + ]; + + // Carry bit + this._b = 0; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + + // Modify the counters + for (var i = 0; i < 8; i++) { + C[i] ^= X[(i + 4) & 7]; + } + + // IV setup + if (iv) { + // Shortcuts + var IV = iv.words; + var IV_0 = IV[0]; + var IV_1 = IV[1]; + + // Generate four subvectors + var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00); + var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00); + var i1 = (i0 >>> 16) | (i2 & 0xffff0000); + var i3 = (i2 << 16) | (i0 & 0x0000ffff); + + // Modify counter values + C[0] ^= i0; + C[1] ^= i1; + C[2] ^= i2; + C[3] ^= i3; + C[4] ^= i0; + C[5] ^= i1; + C[6] ^= i2; + C[7] ^= i3; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + } + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var X = this._X; + + // Iterate the system + nextState.call(this); + + // Generate four keystream words + S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16); + S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16); + S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16); + S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16); + + for (var i = 0; i < 4; i++) { + // Swap endian + S[i] = (((S[i] << 8) | (S[i] >>> 24)) & 0x00ff00ff) | + (((S[i] << 24) | (S[i] >>> 8)) & 0xff00ff00); + + // Encrypt + M[offset + i] ^= S[i]; + } + }, + + blockSize: 128/32, + + ivSize: 64/32 + }); + + function nextState() { + // Shortcuts + var X = this._X; + var C = this._C; + + // Save old counter values + for (var i = 0; i < 8; i++) { + C_[i] = C[i]; + } + + // Calculate new counter values + C[0] = (C[0] + 0x4d34d34d + this._b) | 0; + C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0; + C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0; + C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0; + C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0; + C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0; + C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0; + C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0; + this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0; + + // Calculate the g-values + for (var i = 0; i < 8; i++) { + var gx = X[i] + C[i]; + + // Construct high and low argument for squaring + var ga = gx & 0xffff; + var gb = gx >>> 16; + + // Calculate high and low result of squaring + var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb; + var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0); + + // High XOR low + G[i] = gh ^ gl; + } + + // Calculate new state values + X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0; + X[1] = (G[1] + ((G[0] << 8) | (G[0] >>> 24)) + G[7]) | 0; + X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0; + X[3] = (G[3] + ((G[2] << 8) | (G[2] >>> 24)) + G[1]) | 0; + X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0; + X[5] = (G[5] + ((G[4] << 8) | (G[4] >>> 24)) + G[3]) | 0; + X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0; + X[7] = (G[7] + ((G[6] << 8) | (G[6] >>> 24)) + G[5]) | 0; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.Rabbit.encrypt(message, key, cfg); + * var plaintext = CryptoJS.Rabbit.decrypt(ciphertext, key, cfg); + */ + C.Rabbit = StreamCipher._createHelper(Rabbit); + }()); + + + return CryptoJS.Rabbit; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/rc4.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/rc4.js new file mode 100644 index 0000000..0e4bdff --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/rc4.js @@ -0,0 +1,139 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var StreamCipher = C_lib.StreamCipher; + var C_algo = C.algo; + + /** + * RC4 stream cipher algorithm. + */ + var RC4 = C_algo.RC4 = StreamCipher.extend({ + _doReset: function () { + // Shortcuts + var key = this._key; + var keyWords = key.words; + var keySigBytes = key.sigBytes; + + // Init sbox + var S = this._S = []; + for (var i = 0; i < 256; i++) { + S[i] = i; + } + + // Key setup + for (var i = 0, j = 0; i < 256; i++) { + var keyByteIndex = i % keySigBytes; + var keyByte = (keyWords[keyByteIndex >>> 2] >>> (24 - (keyByteIndex % 4) * 8)) & 0xff; + + j = (j + S[i] + keyByte) % 256; + + // Swap + var t = S[i]; + S[i] = S[j]; + S[j] = t; + } + + // Counters + this._i = this._j = 0; + }, + + _doProcessBlock: function (M, offset) { + M[offset] ^= generateKeystreamWord.call(this); + }, + + keySize: 256/32, + + ivSize: 0 + }); + + function generateKeystreamWord() { + // Shortcuts + var S = this._S; + var i = this._i; + var j = this._j; + + // Generate keystream word + var keystreamWord = 0; + for (var n = 0; n < 4; n++) { + i = (i + 1) % 256; + j = (j + S[i]) % 256; + + // Swap + var t = S[i]; + S[i] = S[j]; + S[j] = t; + + keystreamWord |= S[(S[i] + S[j]) % 256] << (24 - n * 8); + } + + // Update counters + this._i = i; + this._j = j; + + return keystreamWord; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.RC4.encrypt(message, key, cfg); + * var plaintext = CryptoJS.RC4.decrypt(ciphertext, key, cfg); + */ + C.RC4 = StreamCipher._createHelper(RC4); + + /** + * Modified RC4 stream cipher algorithm. + */ + var RC4Drop = C_algo.RC4Drop = RC4.extend({ + /** + * Configuration options. + * + * @property {number} drop The number of keystream words to drop. Default 192 + */ + cfg: RC4.cfg.extend({ + drop: 192 + }), + + _doReset: function () { + RC4._doReset.call(this); + + // Drop + for (var i = this.cfg.drop; i > 0; i--) { + generateKeystreamWord.call(this); + } + } + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.RC4Drop.encrypt(message, key, cfg); + * var plaintext = CryptoJS.RC4Drop.decrypt(ciphertext, key, cfg); + */ + C.RC4Drop = StreamCipher._createHelper(RC4Drop); + }()); + + + return CryptoJS.RC4; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/ripemd160.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/ripemd160.js new file mode 100644 index 0000000..24feb47 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/ripemd160.js @@ -0,0 +1,267 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** @preserve + (c) 2012 by Cédric Mesnil. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Constants table + var _zl = WordArray.create([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13]); + var _zr = WordArray.create([ + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11]); + var _sl = WordArray.create([ + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 ]); + var _sr = WordArray.create([ + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 ]); + + var _hl = WordArray.create([ 0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E]); + var _hr = WordArray.create([ 0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000]); + + /** + * RIPEMD160 hash algorithm. + */ + var RIPEMD160 = C_algo.RIPEMD160 = Hasher.extend({ + _doReset: function () { + this._hash = WordArray.create([0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]); + }, + + _doProcessBlock: function (M, offset) { + + // Swap endian + for (var i = 0; i < 16; i++) { + // Shortcuts + var offset_i = offset + i; + var M_offset_i = M[offset_i]; + + // Swap + M[offset_i] = ( + (((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) | + (((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00) + ); + } + // Shortcut + var H = this._hash.words; + var hl = _hl.words; + var hr = _hr.words; + var zl = _zl.words; + var zr = _zr.words; + var sl = _sl.words; + var sr = _sr.words; + + // Working variables + var al, bl, cl, dl, el; + var ar, br, cr, dr, er; + + ar = al = H[0]; + br = bl = H[1]; + cr = cl = H[2]; + dr = dl = H[3]; + er = el = H[4]; + // Computation + var t; + for (var i = 0; i < 80; i += 1) { + t = (al + M[offset+zl[i]])|0; + if (i<16){ + t += f1(bl,cl,dl) + hl[0]; + } else if (i<32) { + t += f2(bl,cl,dl) + hl[1]; + } else if (i<48) { + t += f3(bl,cl,dl) + hl[2]; + } else if (i<64) { + t += f4(bl,cl,dl) + hl[3]; + } else {// if (i<80) { + t += f5(bl,cl,dl) + hl[4]; + } + t = t|0; + t = rotl(t,sl[i]); + t = (t+el)|0; + al = el; + el = dl; + dl = rotl(cl, 10); + cl = bl; + bl = t; + + t = (ar + M[offset+zr[i]])|0; + if (i<16){ + t += f5(br,cr,dr) + hr[0]; + } else if (i<32) { + t += f4(br,cr,dr) + hr[1]; + } else if (i<48) { + t += f3(br,cr,dr) + hr[2]; + } else if (i<64) { + t += f2(br,cr,dr) + hr[3]; + } else {// if (i<80) { + t += f1(br,cr,dr) + hr[4]; + } + t = t|0; + t = rotl(t,sr[i]) ; + t = (t+er)|0; + ar = er; + er = dr; + dr = rotl(cr, 10); + cr = br; + br = t; + } + // Intermediate hash value + t = (H[1] + cl + dr)|0; + H[1] = (H[2] + dl + er)|0; + H[2] = (H[3] + el + ar)|0; + H[3] = (H[4] + al + br)|0; + H[4] = (H[0] + bl + cr)|0; + H[0] = t; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = ( + (((nBitsTotal << 8) | (nBitsTotal >>> 24)) & 0x00ff00ff) | + (((nBitsTotal << 24) | (nBitsTotal >>> 8)) & 0xff00ff00) + ); + data.sigBytes = (dataWords.length + 1) * 4; + + // Hash final blocks + this._process(); + + // Shortcuts + var hash = this._hash; + var H = hash.words; + + // Swap endian + for (var i = 0; i < 5; i++) { + // Shortcut + var H_i = H[i]; + + // Swap + H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) | + (((H_i << 24) | (H_i >>> 8)) & 0xff00ff00); + } + + // Return final computed hash + return hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + + function f1(x, y, z) { + return ((x) ^ (y) ^ (z)); + + } + + function f2(x, y, z) { + return (((x)&(y)) | ((~x)&(z))); + } + + function f3(x, y, z) { + return (((x) | (~(y))) ^ (z)); + } + + function f4(x, y, z) { + return (((x) & (z)) | ((y)&(~(z)))); + } + + function f5(x, y, z) { + return ((x) ^ ((y) |(~(z)))); + + } + + function rotl(x,n) { + return (x<>>(32-n)); + } + + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.RIPEMD160('message'); + * var hash = CryptoJS.RIPEMD160(wordArray); + */ + C.RIPEMD160 = Hasher._createHelper(RIPEMD160); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacRIPEMD160(message, key); + */ + C.HmacRIPEMD160 = Hasher._createHmacHelper(RIPEMD160); + }(Math)); + + + return CryptoJS.RIPEMD160; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha1.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha1.js new file mode 100644 index 0000000..6691149 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha1.js @@ -0,0 +1,150 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Reusable object + var W = []; + + /** + * SHA-1 hash algorithm. + */ + var SHA1 = C_algo.SHA1 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0x67452301, 0xefcdab89, + 0x98badcfe, 0x10325476, + 0xc3d2e1f0 + ]); + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var H = this._hash.words; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + + // Computation + for (var i = 0; i < 80; i++) { + if (i < 16) { + W[i] = M[offset + i] | 0; + } else { + var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]; + W[i] = (n << 1) | (n >>> 31); + } + + var t = ((a << 5) | (a >>> 27)) + e + W[i]; + if (i < 20) { + t += ((b & c) | (~b & d)) + 0x5a827999; + } else if (i < 40) { + t += (b ^ c ^ d) + 0x6ed9eba1; + } else if (i < 60) { + t += ((b & c) | (b & d) | (c & d)) - 0x70e44324; + } else /* if (i < 80) */ { + t += (b ^ c ^ d) - 0x359d3e2a; + } + + e = d; + d = c; + c = (b << 30) | (b >>> 2); + b = a; + a = t; + } + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + H[4] = (H[4] + e) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Return final computed hash + return this._hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA1('message'); + * var hash = CryptoJS.SHA1(wordArray); + */ + C.SHA1 = Hasher._createHelper(SHA1); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA1(message, key); + */ + C.HmacSHA1 = Hasher._createHmacHelper(SHA1); + }()); + + + return CryptoJS.SHA1; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha224.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha224.js new file mode 100644 index 0000000..d8ce988 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha224.js @@ -0,0 +1,80 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./sha256")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./sha256"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_algo = C.algo; + var SHA256 = C_algo.SHA256; + + /** + * SHA-224 hash algorithm. + */ + var SHA224 = C_algo.SHA224 = SHA256.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 + ]); + }, + + _doFinalize: function () { + var hash = SHA256._doFinalize.call(this); + + hash.sigBytes -= 4; + + return hash; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA224('message'); + * var hash = CryptoJS.SHA224(wordArray); + */ + C.SHA224 = SHA256._createHelper(SHA224); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA224(message, key); + */ + C.HmacSHA224 = SHA256._createHmacHelper(SHA224); + }()); + + + return CryptoJS.SHA224; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha256.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha256.js new file mode 100644 index 0000000..de2d7fc --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha256.js @@ -0,0 +1,199 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Initialization and round constants tables + var H = []; + var K = []; + + // Compute constants + (function () { + function isPrime(n) { + var sqrtN = Math.sqrt(n); + for (var factor = 2; factor <= sqrtN; factor++) { + if (!(n % factor)) { + return false; + } + } + + return true; + } + + function getFractionalBits(n) { + return ((n - (n | 0)) * 0x100000000) | 0; + } + + var n = 2; + var nPrime = 0; + while (nPrime < 64) { + if (isPrime(n)) { + if (nPrime < 8) { + H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2)); + } + K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3)); + + nPrime++; + } + + n++; + } + }()); + + // Reusable object + var W = []; + + /** + * SHA-256 hash algorithm. + */ + var SHA256 = C_algo.SHA256 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init(H.slice(0)); + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var H = this._hash.words; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + var f = H[5]; + var g = H[6]; + var h = H[7]; + + // Computation + for (var i = 0; i < 64; i++) { + if (i < 16) { + W[i] = M[offset + i] | 0; + } else { + var gamma0x = W[i - 15]; + var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ + ((gamma0x << 14) | (gamma0x >>> 18)) ^ + (gamma0x >>> 3); + + var gamma1x = W[i - 2]; + var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ + ((gamma1x << 13) | (gamma1x >>> 19)) ^ + (gamma1x >>> 10); + + W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; + } + + var ch = (e & f) ^ (~e & g); + var maj = (a & b) ^ (a & c) ^ (b & c); + + var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22)); + var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25)); + + var t1 = h + sigma1 + ch + K[i] + W[i]; + var t2 = sigma0 + maj; + + h = g; + g = f; + f = e; + e = (d + t1) | 0; + d = c; + c = b; + b = a; + a = (t1 + t2) | 0; + } + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + H[4] = (H[4] + e) | 0; + H[5] = (H[5] + f) | 0; + H[6] = (H[6] + g) | 0; + H[7] = (H[7] + h) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Return final computed hash + return this._hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA256('message'); + * var hash = CryptoJS.SHA256(wordArray); + */ + C.SHA256 = Hasher._createHelper(SHA256); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA256(message, key); + */ + C.HmacSHA256 = Hasher._createHmacHelper(SHA256); + }(Math)); + + + return CryptoJS.SHA256; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha3.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha3.js new file mode 100644 index 0000000..34ad86c --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha3.js @@ -0,0 +1,326 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_x64 = C.x64; + var X64Word = C_x64.Word; + var C_algo = C.algo; + + // Constants tables + var RHO_OFFSETS = []; + var PI_INDEXES = []; + var ROUND_CONSTANTS = []; + + // Compute Constants + (function () { + // Compute rho offset constants + var x = 1, y = 0; + for (var t = 0; t < 24; t++) { + RHO_OFFSETS[x + 5 * y] = ((t + 1) * (t + 2) / 2) % 64; + + var newX = y % 5; + var newY = (2 * x + 3 * y) % 5; + x = newX; + y = newY; + } + + // Compute pi index constants + for (var x = 0; x < 5; x++) { + for (var y = 0; y < 5; y++) { + PI_INDEXES[x + 5 * y] = y + ((2 * x + 3 * y) % 5) * 5; + } + } + + // Compute round constants + var LFSR = 0x01; + for (var i = 0; i < 24; i++) { + var roundConstantMsw = 0; + var roundConstantLsw = 0; + + for (var j = 0; j < 7; j++) { + if (LFSR & 0x01) { + var bitPosition = (1 << j) - 1; + if (bitPosition < 32) { + roundConstantLsw ^= 1 << bitPosition; + } else /* if (bitPosition >= 32) */ { + roundConstantMsw ^= 1 << (bitPosition - 32); + } + } + + // Compute next LFSR + if (LFSR & 0x80) { + // Primitive polynomial over GF(2): x^8 + x^6 + x^5 + x^4 + 1 + LFSR = (LFSR << 1) ^ 0x71; + } else { + LFSR <<= 1; + } + } + + ROUND_CONSTANTS[i] = X64Word.create(roundConstantMsw, roundConstantLsw); + } + }()); + + // Reusable objects for temporary values + var T = []; + (function () { + for (var i = 0; i < 25; i++) { + T[i] = X64Word.create(); + } + }()); + + /** + * SHA-3 hash algorithm. + */ + var SHA3 = C_algo.SHA3 = Hasher.extend({ + /** + * Configuration options. + * + * @property {number} outputLength + * The desired number of bits in the output hash. + * Only values permitted are: 224, 256, 384, 512. + * Default: 512 + */ + cfg: Hasher.cfg.extend({ + outputLength: 512 + }), + + _doReset: function () { + var state = this._state = [] + for (var i = 0; i < 25; i++) { + state[i] = new X64Word.init(); + } + + this.blockSize = (1600 - 2 * this.cfg.outputLength) / 32; + }, + + _doProcessBlock: function (M, offset) { + // Shortcuts + var state = this._state; + var nBlockSizeLanes = this.blockSize / 2; + + // Absorb + for (var i = 0; i < nBlockSizeLanes; i++) { + // Shortcuts + var M2i = M[offset + 2 * i]; + var M2i1 = M[offset + 2 * i + 1]; + + // Swap endian + M2i = ( + (((M2i << 8) | (M2i >>> 24)) & 0x00ff00ff) | + (((M2i << 24) | (M2i >>> 8)) & 0xff00ff00) + ); + M2i1 = ( + (((M2i1 << 8) | (M2i1 >>> 24)) & 0x00ff00ff) | + (((M2i1 << 24) | (M2i1 >>> 8)) & 0xff00ff00) + ); + + // Absorb message into state + var lane = state[i]; + lane.high ^= M2i1; + lane.low ^= M2i; + } + + // Rounds + for (var round = 0; round < 24; round++) { + // Theta + for (var x = 0; x < 5; x++) { + // Mix column lanes + var tMsw = 0, tLsw = 0; + for (var y = 0; y < 5; y++) { + var lane = state[x + 5 * y]; + tMsw ^= lane.high; + tLsw ^= lane.low; + } + + // Temporary values + var Tx = T[x]; + Tx.high = tMsw; + Tx.low = tLsw; + } + for (var x = 0; x < 5; x++) { + // Shortcuts + var Tx4 = T[(x + 4) % 5]; + var Tx1 = T[(x + 1) % 5]; + var Tx1Msw = Tx1.high; + var Tx1Lsw = Tx1.low; + + // Mix surrounding columns + var tMsw = Tx4.high ^ ((Tx1Msw << 1) | (Tx1Lsw >>> 31)); + var tLsw = Tx4.low ^ ((Tx1Lsw << 1) | (Tx1Msw >>> 31)); + for (var y = 0; y < 5; y++) { + var lane = state[x + 5 * y]; + lane.high ^= tMsw; + lane.low ^= tLsw; + } + } + + // Rho Pi + for (var laneIndex = 1; laneIndex < 25; laneIndex++) { + var tMsw; + var tLsw; + + // Shortcuts + var lane = state[laneIndex]; + var laneMsw = lane.high; + var laneLsw = lane.low; + var rhoOffset = RHO_OFFSETS[laneIndex]; + + // Rotate lanes + if (rhoOffset < 32) { + tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset)); + tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset)); + } else /* if (rhoOffset >= 32) */ { + tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset)); + tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset)); + } + + // Transpose lanes + var TPiLane = T[PI_INDEXES[laneIndex]]; + TPiLane.high = tMsw; + TPiLane.low = tLsw; + } + + // Rho pi at x = y = 0 + var T0 = T[0]; + var state0 = state[0]; + T0.high = state0.high; + T0.low = state0.low; + + // Chi + for (var x = 0; x < 5; x++) { + for (var y = 0; y < 5; y++) { + // Shortcuts + var laneIndex = x + 5 * y; + var lane = state[laneIndex]; + var TLane = T[laneIndex]; + var Tx1Lane = T[((x + 1) % 5) + 5 * y]; + var Tx2Lane = T[((x + 2) % 5) + 5 * y]; + + // Mix rows + lane.high = TLane.high ^ (~Tx1Lane.high & Tx2Lane.high); + lane.low = TLane.low ^ (~Tx1Lane.low & Tx2Lane.low); + } + } + + // Iota + var lane = state[0]; + var roundConstant = ROUND_CONSTANTS[round]; + lane.high ^= roundConstant.high; + lane.low ^= roundConstant.low; + } + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + var blockSizeBits = this.blockSize * 32; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x1 << (24 - nBitsLeft % 32); + dataWords[((Math.ceil((nBitsLeft + 1) / blockSizeBits) * blockSizeBits) >>> 5) - 1] |= 0x80; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Shortcuts + var state = this._state; + var outputLengthBytes = this.cfg.outputLength / 8; + var outputLengthLanes = outputLengthBytes / 8; + + // Squeeze + var hashWords = []; + for (var i = 0; i < outputLengthLanes; i++) { + // Shortcuts + var lane = state[i]; + var laneMsw = lane.high; + var laneLsw = lane.low; + + // Swap endian + laneMsw = ( + (((laneMsw << 8) | (laneMsw >>> 24)) & 0x00ff00ff) | + (((laneMsw << 24) | (laneMsw >>> 8)) & 0xff00ff00) + ); + laneLsw = ( + (((laneLsw << 8) | (laneLsw >>> 24)) & 0x00ff00ff) | + (((laneLsw << 24) | (laneLsw >>> 8)) & 0xff00ff00) + ); + + // Squeeze state to retrieve hash + hashWords.push(laneLsw); + hashWords.push(laneMsw); + } + + // Return final computed hash + return new WordArray.init(hashWords, outputLengthBytes); + }, + + clone: function () { + var clone = Hasher.clone.call(this); + + var state = clone._state = this._state.slice(0); + for (var i = 0; i < 25; i++) { + state[i] = state[i].clone(); + } + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA3('message'); + * var hash = CryptoJS.SHA3(wordArray); + */ + C.SHA3 = Hasher._createHelper(SHA3); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA3(message, key); + */ + C.HmacSHA3 = Hasher._createHmacHelper(SHA3); + }(Math)); + + + return CryptoJS.SHA3; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha384.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha384.js new file mode 100644 index 0000000..a0b95bf --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha384.js @@ -0,0 +1,83 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core"), require("./sha512")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core", "./sha512"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_x64 = C.x64; + var X64Word = C_x64.Word; + var X64WordArray = C_x64.WordArray; + var C_algo = C.algo; + var SHA512 = C_algo.SHA512; + + /** + * SHA-384 hash algorithm. + */ + var SHA384 = C_algo.SHA384 = SHA512.extend({ + _doReset: function () { + this._hash = new X64WordArray.init([ + new X64Word.init(0xcbbb9d5d, 0xc1059ed8), new X64Word.init(0x629a292a, 0x367cd507), + new X64Word.init(0x9159015a, 0x3070dd17), new X64Word.init(0x152fecd8, 0xf70e5939), + new X64Word.init(0x67332667, 0xffc00b31), new X64Word.init(0x8eb44a87, 0x68581511), + new X64Word.init(0xdb0c2e0d, 0x64f98fa7), new X64Word.init(0x47b5481d, 0xbefa4fa4) + ]); + }, + + _doFinalize: function () { + var hash = SHA512._doFinalize.call(this); + + hash.sigBytes -= 16; + + return hash; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA384('message'); + * var hash = CryptoJS.SHA384(wordArray); + */ + C.SHA384 = SHA512._createHelper(SHA384); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA384(message, key); + */ + C.HmacSHA384 = SHA512._createHmacHelper(SHA384); + }()); + + + return CryptoJS.SHA384; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha512.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha512.js new file mode 100644 index 0000000..d274ab0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/sha512.js @@ -0,0 +1,326 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Hasher = C_lib.Hasher; + var C_x64 = C.x64; + var X64Word = C_x64.Word; + var X64WordArray = C_x64.WordArray; + var C_algo = C.algo; + + function X64Word_create() { + return X64Word.create.apply(X64Word, arguments); + } + + // Constants + var K = [ + X64Word_create(0x428a2f98, 0xd728ae22), X64Word_create(0x71374491, 0x23ef65cd), + X64Word_create(0xb5c0fbcf, 0xec4d3b2f), X64Word_create(0xe9b5dba5, 0x8189dbbc), + X64Word_create(0x3956c25b, 0xf348b538), X64Word_create(0x59f111f1, 0xb605d019), + X64Word_create(0x923f82a4, 0xaf194f9b), X64Word_create(0xab1c5ed5, 0xda6d8118), + X64Word_create(0xd807aa98, 0xa3030242), X64Word_create(0x12835b01, 0x45706fbe), + X64Word_create(0x243185be, 0x4ee4b28c), X64Word_create(0x550c7dc3, 0xd5ffb4e2), + X64Word_create(0x72be5d74, 0xf27b896f), X64Word_create(0x80deb1fe, 0x3b1696b1), + X64Word_create(0x9bdc06a7, 0x25c71235), X64Word_create(0xc19bf174, 0xcf692694), + X64Word_create(0xe49b69c1, 0x9ef14ad2), X64Word_create(0xefbe4786, 0x384f25e3), + X64Word_create(0x0fc19dc6, 0x8b8cd5b5), X64Word_create(0x240ca1cc, 0x77ac9c65), + X64Word_create(0x2de92c6f, 0x592b0275), X64Word_create(0x4a7484aa, 0x6ea6e483), + X64Word_create(0x5cb0a9dc, 0xbd41fbd4), X64Word_create(0x76f988da, 0x831153b5), + X64Word_create(0x983e5152, 0xee66dfab), X64Word_create(0xa831c66d, 0x2db43210), + X64Word_create(0xb00327c8, 0x98fb213f), X64Word_create(0xbf597fc7, 0xbeef0ee4), + X64Word_create(0xc6e00bf3, 0x3da88fc2), X64Word_create(0xd5a79147, 0x930aa725), + X64Word_create(0x06ca6351, 0xe003826f), X64Word_create(0x14292967, 0x0a0e6e70), + X64Word_create(0x27b70a85, 0x46d22ffc), X64Word_create(0x2e1b2138, 0x5c26c926), + X64Word_create(0x4d2c6dfc, 0x5ac42aed), X64Word_create(0x53380d13, 0x9d95b3df), + X64Word_create(0x650a7354, 0x8baf63de), X64Word_create(0x766a0abb, 0x3c77b2a8), + X64Word_create(0x81c2c92e, 0x47edaee6), X64Word_create(0x92722c85, 0x1482353b), + X64Word_create(0xa2bfe8a1, 0x4cf10364), X64Word_create(0xa81a664b, 0xbc423001), + X64Word_create(0xc24b8b70, 0xd0f89791), X64Word_create(0xc76c51a3, 0x0654be30), + X64Word_create(0xd192e819, 0xd6ef5218), X64Word_create(0xd6990624, 0x5565a910), + X64Word_create(0xf40e3585, 0x5771202a), X64Word_create(0x106aa070, 0x32bbd1b8), + X64Word_create(0x19a4c116, 0xb8d2d0c8), X64Word_create(0x1e376c08, 0x5141ab53), + X64Word_create(0x2748774c, 0xdf8eeb99), X64Word_create(0x34b0bcb5, 0xe19b48a8), + X64Word_create(0x391c0cb3, 0xc5c95a63), X64Word_create(0x4ed8aa4a, 0xe3418acb), + X64Word_create(0x5b9cca4f, 0x7763e373), X64Word_create(0x682e6ff3, 0xd6b2b8a3), + X64Word_create(0x748f82ee, 0x5defb2fc), X64Word_create(0x78a5636f, 0x43172f60), + X64Word_create(0x84c87814, 0xa1f0ab72), X64Word_create(0x8cc70208, 0x1a6439ec), + X64Word_create(0x90befffa, 0x23631e28), X64Word_create(0xa4506ceb, 0xde82bde9), + X64Word_create(0xbef9a3f7, 0xb2c67915), X64Word_create(0xc67178f2, 0xe372532b), + X64Word_create(0xca273ece, 0xea26619c), X64Word_create(0xd186b8c7, 0x21c0c207), + X64Word_create(0xeada7dd6, 0xcde0eb1e), X64Word_create(0xf57d4f7f, 0xee6ed178), + X64Word_create(0x06f067aa, 0x72176fba), X64Word_create(0x0a637dc5, 0xa2c898a6), + X64Word_create(0x113f9804, 0xbef90dae), X64Word_create(0x1b710b35, 0x131c471b), + X64Word_create(0x28db77f5, 0x23047d84), X64Word_create(0x32caab7b, 0x40c72493), + X64Word_create(0x3c9ebe0a, 0x15c9bebc), X64Word_create(0x431d67c4, 0x9c100d4c), + X64Word_create(0x4cc5d4be, 0xcb3e42b6), X64Word_create(0x597f299c, 0xfc657e2a), + X64Word_create(0x5fcb6fab, 0x3ad6faec), X64Word_create(0x6c44198c, 0x4a475817) + ]; + + // Reusable objects + var W = []; + (function () { + for (var i = 0; i < 80; i++) { + W[i] = X64Word_create(); + } + }()); + + /** + * SHA-512 hash algorithm. + */ + var SHA512 = C_algo.SHA512 = Hasher.extend({ + _doReset: function () { + this._hash = new X64WordArray.init([ + new X64Word.init(0x6a09e667, 0xf3bcc908), new X64Word.init(0xbb67ae85, 0x84caa73b), + new X64Word.init(0x3c6ef372, 0xfe94f82b), new X64Word.init(0xa54ff53a, 0x5f1d36f1), + new X64Word.init(0x510e527f, 0xade682d1), new X64Word.init(0x9b05688c, 0x2b3e6c1f), + new X64Word.init(0x1f83d9ab, 0xfb41bd6b), new X64Word.init(0x5be0cd19, 0x137e2179) + ]); + }, + + _doProcessBlock: function (M, offset) { + // Shortcuts + var H = this._hash.words; + + var H0 = H[0]; + var H1 = H[1]; + var H2 = H[2]; + var H3 = H[3]; + var H4 = H[4]; + var H5 = H[5]; + var H6 = H[6]; + var H7 = H[7]; + + var H0h = H0.high; + var H0l = H0.low; + var H1h = H1.high; + var H1l = H1.low; + var H2h = H2.high; + var H2l = H2.low; + var H3h = H3.high; + var H3l = H3.low; + var H4h = H4.high; + var H4l = H4.low; + var H5h = H5.high; + var H5l = H5.low; + var H6h = H6.high; + var H6l = H6.low; + var H7h = H7.high; + var H7l = H7.low; + + // Working variables + var ah = H0h; + var al = H0l; + var bh = H1h; + var bl = H1l; + var ch = H2h; + var cl = H2l; + var dh = H3h; + var dl = H3l; + var eh = H4h; + var el = H4l; + var fh = H5h; + var fl = H5l; + var gh = H6h; + var gl = H6l; + var hh = H7h; + var hl = H7l; + + // Rounds + for (var i = 0; i < 80; i++) { + var Wil; + var Wih; + + // Shortcut + var Wi = W[i]; + + // Extend message + if (i < 16) { + Wih = Wi.high = M[offset + i * 2] | 0; + Wil = Wi.low = M[offset + i * 2 + 1] | 0; + } else { + // Gamma0 + var gamma0x = W[i - 15]; + var gamma0xh = gamma0x.high; + var gamma0xl = gamma0x.low; + var gamma0h = ((gamma0xh >>> 1) | (gamma0xl << 31)) ^ ((gamma0xh >>> 8) | (gamma0xl << 24)) ^ (gamma0xh >>> 7); + var gamma0l = ((gamma0xl >>> 1) | (gamma0xh << 31)) ^ ((gamma0xl >>> 8) | (gamma0xh << 24)) ^ ((gamma0xl >>> 7) | (gamma0xh << 25)); + + // Gamma1 + var gamma1x = W[i - 2]; + var gamma1xh = gamma1x.high; + var gamma1xl = gamma1x.low; + var gamma1h = ((gamma1xh >>> 19) | (gamma1xl << 13)) ^ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^ (gamma1xh >>> 6); + var gamma1l = ((gamma1xl >>> 19) | (gamma1xh << 13)) ^ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^ ((gamma1xl >>> 6) | (gamma1xh << 26)); + + // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16] + var Wi7 = W[i - 7]; + var Wi7h = Wi7.high; + var Wi7l = Wi7.low; + + var Wi16 = W[i - 16]; + var Wi16h = Wi16.high; + var Wi16l = Wi16.low; + + Wil = gamma0l + Wi7l; + Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0); + Wil = Wil + gamma1l; + Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0); + Wil = Wil + Wi16l; + Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0); + + Wi.high = Wih; + Wi.low = Wil; + } + + var chh = (eh & fh) ^ (~eh & gh); + var chl = (el & fl) ^ (~el & gl); + var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch); + var majl = (al & bl) ^ (al & cl) ^ (bl & cl); + + var sigma0h = ((ah >>> 28) | (al << 4)) ^ ((ah << 30) | (al >>> 2)) ^ ((ah << 25) | (al >>> 7)); + var sigma0l = ((al >>> 28) | (ah << 4)) ^ ((al << 30) | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7)); + var sigma1h = ((eh >>> 14) | (el << 18)) ^ ((eh >>> 18) | (el << 14)) ^ ((eh << 23) | (el >>> 9)); + var sigma1l = ((el >>> 14) | (eh << 18)) ^ ((el >>> 18) | (eh << 14)) ^ ((el << 23) | (eh >>> 9)); + + // t1 = h + sigma1 + ch + K[i] + W[i] + var Ki = K[i]; + var Kih = Ki.high; + var Kil = Ki.low; + + var t1l = hl + sigma1l; + var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0); + var t1l = t1l + chl; + var t1h = t1h + chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0); + var t1l = t1l + Kil; + var t1h = t1h + Kih + ((t1l >>> 0) < (Kil >>> 0) ? 1 : 0); + var t1l = t1l + Wil; + var t1h = t1h + Wih + ((t1l >>> 0) < (Wil >>> 0) ? 1 : 0); + + // t2 = sigma0 + maj + var t2l = sigma0l + majl; + var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0); + + // Update working variables + hh = gh; + hl = gl; + gh = fh; + gl = fl; + fh = eh; + fl = el; + el = (dl + t1l) | 0; + eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0; + dh = ch; + dl = cl; + ch = bh; + cl = bl; + bh = ah; + bl = al; + al = (t1l + t2l) | 0; + ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0; + } + + // Intermediate hash value + H0l = H0.low = (H0l + al); + H0.high = (H0h + ah + ((H0l >>> 0) < (al >>> 0) ? 1 : 0)); + H1l = H1.low = (H1l + bl); + H1.high = (H1h + bh + ((H1l >>> 0) < (bl >>> 0) ? 1 : 0)); + H2l = H2.low = (H2l + cl); + H2.high = (H2h + ch + ((H2l >>> 0) < (cl >>> 0) ? 1 : 0)); + H3l = H3.low = (H3l + dl); + H3.high = (H3h + dh + ((H3l >>> 0) < (dl >>> 0) ? 1 : 0)); + H4l = H4.low = (H4l + el); + H4.high = (H4h + eh + ((H4l >>> 0) < (el >>> 0) ? 1 : 0)); + H5l = H5.low = (H5l + fl); + H5.high = (H5h + fh + ((H5l >>> 0) < (fl >>> 0) ? 1 : 0)); + H6l = H6.low = (H6l + gl); + H6.high = (H6h + gh + ((H6l >>> 0) < (gl >>> 0) ? 1 : 0)); + H7l = H7.low = (H7l + hl); + H7.high = (H7h + hh + ((H7l >>> 0) < (hl >>> 0) ? 1 : 0)); + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 30] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 31] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Convert hash to 32-bit word array before returning + var hash = this._hash.toX32(); + + // Return final computed hash + return hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + }, + + blockSize: 1024/32 + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA512('message'); + * var hash = CryptoJS.SHA512(wordArray); + */ + C.SHA512 = Hasher._createHelper(SHA512); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA512(message, key); + */ + C.HmacSHA512 = Hasher._createHmacHelper(SHA512); + }()); + + + return CryptoJS.SHA512; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/tripledes.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/tripledes.js new file mode 100644 index 0000000..1a92477 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/tripledes.js @@ -0,0 +1,779 @@ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var BlockCipher = C_lib.BlockCipher; + var C_algo = C.algo; + + // Permuted Choice 1 constants + var PC1 = [ + 57, 49, 41, 33, 25, 17, 9, 1, + 58, 50, 42, 34, 26, 18, 10, 2, + 59, 51, 43, 35, 27, 19, 11, 3, + 60, 52, 44, 36, 63, 55, 47, 39, + 31, 23, 15, 7, 62, 54, 46, 38, + 30, 22, 14, 6, 61, 53, 45, 37, + 29, 21, 13, 5, 28, 20, 12, 4 + ]; + + // Permuted Choice 2 constants + var PC2 = [ + 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32 + ]; + + // Cumulative bit shift constants + var BIT_SHIFTS = [1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28]; + + // SBOXes and round permutation constants + var SBOX_P = [ + { + 0x0: 0x808200, + 0x10000000: 0x8000, + 0x20000000: 0x808002, + 0x30000000: 0x2, + 0x40000000: 0x200, + 0x50000000: 0x808202, + 0x60000000: 0x800202, + 0x70000000: 0x800000, + 0x80000000: 0x202, + 0x90000000: 0x800200, + 0xa0000000: 0x8200, + 0xb0000000: 0x808000, + 0xc0000000: 0x8002, + 0xd0000000: 0x800002, + 0xe0000000: 0x0, + 0xf0000000: 0x8202, + 0x8000000: 0x0, + 0x18000000: 0x808202, + 0x28000000: 0x8202, + 0x38000000: 0x8000, + 0x48000000: 0x808200, + 0x58000000: 0x200, + 0x68000000: 0x808002, + 0x78000000: 0x2, + 0x88000000: 0x800200, + 0x98000000: 0x8200, + 0xa8000000: 0x808000, + 0xb8000000: 0x800202, + 0xc8000000: 0x800002, + 0xd8000000: 0x8002, + 0xe8000000: 0x202, + 0xf8000000: 0x800000, + 0x1: 0x8000, + 0x10000001: 0x2, + 0x20000001: 0x808200, + 0x30000001: 0x800000, + 0x40000001: 0x808002, + 0x50000001: 0x8200, + 0x60000001: 0x200, + 0x70000001: 0x800202, + 0x80000001: 0x808202, + 0x90000001: 0x808000, + 0xa0000001: 0x800002, + 0xb0000001: 0x8202, + 0xc0000001: 0x202, + 0xd0000001: 0x800200, + 0xe0000001: 0x8002, + 0xf0000001: 0x0, + 0x8000001: 0x808202, + 0x18000001: 0x808000, + 0x28000001: 0x800000, + 0x38000001: 0x200, + 0x48000001: 0x8000, + 0x58000001: 0x800002, + 0x68000001: 0x2, + 0x78000001: 0x8202, + 0x88000001: 0x8002, + 0x98000001: 0x800202, + 0xa8000001: 0x202, + 0xb8000001: 0x808200, + 0xc8000001: 0x800200, + 0xd8000001: 0x0, + 0xe8000001: 0x8200, + 0xf8000001: 0x808002 + }, + { + 0x0: 0x40084010, + 0x1000000: 0x4000, + 0x2000000: 0x80000, + 0x3000000: 0x40080010, + 0x4000000: 0x40000010, + 0x5000000: 0x40084000, + 0x6000000: 0x40004000, + 0x7000000: 0x10, + 0x8000000: 0x84000, + 0x9000000: 0x40004010, + 0xa000000: 0x40000000, + 0xb000000: 0x84010, + 0xc000000: 0x80010, + 0xd000000: 0x0, + 0xe000000: 0x4010, + 0xf000000: 0x40080000, + 0x800000: 0x40004000, + 0x1800000: 0x84010, + 0x2800000: 0x10, + 0x3800000: 0x40004010, + 0x4800000: 0x40084010, + 0x5800000: 0x40000000, + 0x6800000: 0x80000, + 0x7800000: 0x40080010, + 0x8800000: 0x80010, + 0x9800000: 0x0, + 0xa800000: 0x4000, + 0xb800000: 0x40080000, + 0xc800000: 0x40000010, + 0xd800000: 0x84000, + 0xe800000: 0x40084000, + 0xf800000: 0x4010, + 0x10000000: 0x0, + 0x11000000: 0x40080010, + 0x12000000: 0x40004010, + 0x13000000: 0x40084000, + 0x14000000: 0x40080000, + 0x15000000: 0x10, + 0x16000000: 0x84010, + 0x17000000: 0x4000, + 0x18000000: 0x4010, + 0x19000000: 0x80000, + 0x1a000000: 0x80010, + 0x1b000000: 0x40000010, + 0x1c000000: 0x84000, + 0x1d000000: 0x40004000, + 0x1e000000: 0x40000000, + 0x1f000000: 0x40084010, + 0x10800000: 0x84010, + 0x11800000: 0x80000, + 0x12800000: 0x40080000, + 0x13800000: 0x4000, + 0x14800000: 0x40004000, + 0x15800000: 0x40084010, + 0x16800000: 0x10, + 0x17800000: 0x40000000, + 0x18800000: 0x40084000, + 0x19800000: 0x40000010, + 0x1a800000: 0x40004010, + 0x1b800000: 0x80010, + 0x1c800000: 0x0, + 0x1d800000: 0x4010, + 0x1e800000: 0x40080010, + 0x1f800000: 0x84000 + }, + { + 0x0: 0x104, + 0x100000: 0x0, + 0x200000: 0x4000100, + 0x300000: 0x10104, + 0x400000: 0x10004, + 0x500000: 0x4000004, + 0x600000: 0x4010104, + 0x700000: 0x4010000, + 0x800000: 0x4000000, + 0x900000: 0x4010100, + 0xa00000: 0x10100, + 0xb00000: 0x4010004, + 0xc00000: 0x4000104, + 0xd00000: 0x10000, + 0xe00000: 0x4, + 0xf00000: 0x100, + 0x80000: 0x4010100, + 0x180000: 0x4010004, + 0x280000: 0x0, + 0x380000: 0x4000100, + 0x480000: 0x4000004, + 0x580000: 0x10000, + 0x680000: 0x10004, + 0x780000: 0x104, + 0x880000: 0x4, + 0x980000: 0x100, + 0xa80000: 0x4010000, + 0xb80000: 0x10104, + 0xc80000: 0x10100, + 0xd80000: 0x4000104, + 0xe80000: 0x4010104, + 0xf80000: 0x4000000, + 0x1000000: 0x4010100, + 0x1100000: 0x10004, + 0x1200000: 0x10000, + 0x1300000: 0x4000100, + 0x1400000: 0x100, + 0x1500000: 0x4010104, + 0x1600000: 0x4000004, + 0x1700000: 0x0, + 0x1800000: 0x4000104, + 0x1900000: 0x4000000, + 0x1a00000: 0x4, + 0x1b00000: 0x10100, + 0x1c00000: 0x4010000, + 0x1d00000: 0x104, + 0x1e00000: 0x10104, + 0x1f00000: 0x4010004, + 0x1080000: 0x4000000, + 0x1180000: 0x104, + 0x1280000: 0x4010100, + 0x1380000: 0x0, + 0x1480000: 0x10004, + 0x1580000: 0x4000100, + 0x1680000: 0x100, + 0x1780000: 0x4010004, + 0x1880000: 0x10000, + 0x1980000: 0x4010104, + 0x1a80000: 0x10104, + 0x1b80000: 0x4000004, + 0x1c80000: 0x4000104, + 0x1d80000: 0x4010000, + 0x1e80000: 0x4, + 0x1f80000: 0x10100 + }, + { + 0x0: 0x80401000, + 0x10000: 0x80001040, + 0x20000: 0x401040, + 0x30000: 0x80400000, + 0x40000: 0x0, + 0x50000: 0x401000, + 0x60000: 0x80000040, + 0x70000: 0x400040, + 0x80000: 0x80000000, + 0x90000: 0x400000, + 0xa0000: 0x40, + 0xb0000: 0x80001000, + 0xc0000: 0x80400040, + 0xd0000: 0x1040, + 0xe0000: 0x1000, + 0xf0000: 0x80401040, + 0x8000: 0x80001040, + 0x18000: 0x40, + 0x28000: 0x80400040, + 0x38000: 0x80001000, + 0x48000: 0x401000, + 0x58000: 0x80401040, + 0x68000: 0x0, + 0x78000: 0x80400000, + 0x88000: 0x1000, + 0x98000: 0x80401000, + 0xa8000: 0x400000, + 0xb8000: 0x1040, + 0xc8000: 0x80000000, + 0xd8000: 0x400040, + 0xe8000: 0x401040, + 0xf8000: 0x80000040, + 0x100000: 0x400040, + 0x110000: 0x401000, + 0x120000: 0x80000040, + 0x130000: 0x0, + 0x140000: 0x1040, + 0x150000: 0x80400040, + 0x160000: 0x80401000, + 0x170000: 0x80001040, + 0x180000: 0x80401040, + 0x190000: 0x80000000, + 0x1a0000: 0x80400000, + 0x1b0000: 0x401040, + 0x1c0000: 0x80001000, + 0x1d0000: 0x400000, + 0x1e0000: 0x40, + 0x1f0000: 0x1000, + 0x108000: 0x80400000, + 0x118000: 0x80401040, + 0x128000: 0x0, + 0x138000: 0x401000, + 0x148000: 0x400040, + 0x158000: 0x80000000, + 0x168000: 0x80001040, + 0x178000: 0x40, + 0x188000: 0x80000040, + 0x198000: 0x1000, + 0x1a8000: 0x80001000, + 0x1b8000: 0x80400040, + 0x1c8000: 0x1040, + 0x1d8000: 0x80401000, + 0x1e8000: 0x400000, + 0x1f8000: 0x401040 + }, + { + 0x0: 0x80, + 0x1000: 0x1040000, + 0x2000: 0x40000, + 0x3000: 0x20000000, + 0x4000: 0x20040080, + 0x5000: 0x1000080, + 0x6000: 0x21000080, + 0x7000: 0x40080, + 0x8000: 0x1000000, + 0x9000: 0x20040000, + 0xa000: 0x20000080, + 0xb000: 0x21040080, + 0xc000: 0x21040000, + 0xd000: 0x0, + 0xe000: 0x1040080, + 0xf000: 0x21000000, + 0x800: 0x1040080, + 0x1800: 0x21000080, + 0x2800: 0x80, + 0x3800: 0x1040000, + 0x4800: 0x40000, + 0x5800: 0x20040080, + 0x6800: 0x21040000, + 0x7800: 0x20000000, + 0x8800: 0x20040000, + 0x9800: 0x0, + 0xa800: 0x21040080, + 0xb800: 0x1000080, + 0xc800: 0x20000080, + 0xd800: 0x21000000, + 0xe800: 0x1000000, + 0xf800: 0x40080, + 0x10000: 0x40000, + 0x11000: 0x80, + 0x12000: 0x20000000, + 0x13000: 0x21000080, + 0x14000: 0x1000080, + 0x15000: 0x21040000, + 0x16000: 0x20040080, + 0x17000: 0x1000000, + 0x18000: 0x21040080, + 0x19000: 0x21000000, + 0x1a000: 0x1040000, + 0x1b000: 0x20040000, + 0x1c000: 0x40080, + 0x1d000: 0x20000080, + 0x1e000: 0x0, + 0x1f000: 0x1040080, + 0x10800: 0x21000080, + 0x11800: 0x1000000, + 0x12800: 0x1040000, + 0x13800: 0x20040080, + 0x14800: 0x20000000, + 0x15800: 0x1040080, + 0x16800: 0x80, + 0x17800: 0x21040000, + 0x18800: 0x40080, + 0x19800: 0x21040080, + 0x1a800: 0x0, + 0x1b800: 0x21000000, + 0x1c800: 0x1000080, + 0x1d800: 0x40000, + 0x1e800: 0x20040000, + 0x1f800: 0x20000080 + }, + { + 0x0: 0x10000008, + 0x100: 0x2000, + 0x200: 0x10200000, + 0x300: 0x10202008, + 0x400: 0x10002000, + 0x500: 0x200000, + 0x600: 0x200008, + 0x700: 0x10000000, + 0x800: 0x0, + 0x900: 0x10002008, + 0xa00: 0x202000, + 0xb00: 0x8, + 0xc00: 0x10200008, + 0xd00: 0x202008, + 0xe00: 0x2008, + 0xf00: 0x10202000, + 0x80: 0x10200000, + 0x180: 0x10202008, + 0x280: 0x8, + 0x380: 0x200000, + 0x480: 0x202008, + 0x580: 0x10000008, + 0x680: 0x10002000, + 0x780: 0x2008, + 0x880: 0x200008, + 0x980: 0x2000, + 0xa80: 0x10002008, + 0xb80: 0x10200008, + 0xc80: 0x0, + 0xd80: 0x10202000, + 0xe80: 0x202000, + 0xf80: 0x10000000, + 0x1000: 0x10002000, + 0x1100: 0x10200008, + 0x1200: 0x10202008, + 0x1300: 0x2008, + 0x1400: 0x200000, + 0x1500: 0x10000000, + 0x1600: 0x10000008, + 0x1700: 0x202000, + 0x1800: 0x202008, + 0x1900: 0x0, + 0x1a00: 0x8, + 0x1b00: 0x10200000, + 0x1c00: 0x2000, + 0x1d00: 0x10002008, + 0x1e00: 0x10202000, + 0x1f00: 0x200008, + 0x1080: 0x8, + 0x1180: 0x202000, + 0x1280: 0x200000, + 0x1380: 0x10000008, + 0x1480: 0x10002000, + 0x1580: 0x2008, + 0x1680: 0x10202008, + 0x1780: 0x10200000, + 0x1880: 0x10202000, + 0x1980: 0x10200008, + 0x1a80: 0x2000, + 0x1b80: 0x202008, + 0x1c80: 0x200008, + 0x1d80: 0x0, + 0x1e80: 0x10000000, + 0x1f80: 0x10002008 + }, + { + 0x0: 0x100000, + 0x10: 0x2000401, + 0x20: 0x400, + 0x30: 0x100401, + 0x40: 0x2100401, + 0x50: 0x0, + 0x60: 0x1, + 0x70: 0x2100001, + 0x80: 0x2000400, + 0x90: 0x100001, + 0xa0: 0x2000001, + 0xb0: 0x2100400, + 0xc0: 0x2100000, + 0xd0: 0x401, + 0xe0: 0x100400, + 0xf0: 0x2000000, + 0x8: 0x2100001, + 0x18: 0x0, + 0x28: 0x2000401, + 0x38: 0x2100400, + 0x48: 0x100000, + 0x58: 0x2000001, + 0x68: 0x2000000, + 0x78: 0x401, + 0x88: 0x100401, + 0x98: 0x2000400, + 0xa8: 0x2100000, + 0xb8: 0x100001, + 0xc8: 0x400, + 0xd8: 0x2100401, + 0xe8: 0x1, + 0xf8: 0x100400, + 0x100: 0x2000000, + 0x110: 0x100000, + 0x120: 0x2000401, + 0x130: 0x2100001, + 0x140: 0x100001, + 0x150: 0x2000400, + 0x160: 0x2100400, + 0x170: 0x100401, + 0x180: 0x401, + 0x190: 0x2100401, + 0x1a0: 0x100400, + 0x1b0: 0x1, + 0x1c0: 0x0, + 0x1d0: 0x2100000, + 0x1e0: 0x2000001, + 0x1f0: 0x400, + 0x108: 0x100400, + 0x118: 0x2000401, + 0x128: 0x2100001, + 0x138: 0x1, + 0x148: 0x2000000, + 0x158: 0x100000, + 0x168: 0x401, + 0x178: 0x2100400, + 0x188: 0x2000001, + 0x198: 0x2100000, + 0x1a8: 0x0, + 0x1b8: 0x2100401, + 0x1c8: 0x100401, + 0x1d8: 0x400, + 0x1e8: 0x2000400, + 0x1f8: 0x100001 + }, + { + 0x0: 0x8000820, + 0x1: 0x20000, + 0x2: 0x8000000, + 0x3: 0x20, + 0x4: 0x20020, + 0x5: 0x8020820, + 0x6: 0x8020800, + 0x7: 0x800, + 0x8: 0x8020000, + 0x9: 0x8000800, + 0xa: 0x20800, + 0xb: 0x8020020, + 0xc: 0x820, + 0xd: 0x0, + 0xe: 0x8000020, + 0xf: 0x20820, + 0x80000000: 0x800, + 0x80000001: 0x8020820, + 0x80000002: 0x8000820, + 0x80000003: 0x8000000, + 0x80000004: 0x8020000, + 0x80000005: 0x20800, + 0x80000006: 0x20820, + 0x80000007: 0x20, + 0x80000008: 0x8000020, + 0x80000009: 0x820, + 0x8000000a: 0x20020, + 0x8000000b: 0x8020800, + 0x8000000c: 0x0, + 0x8000000d: 0x8020020, + 0x8000000e: 0x8000800, + 0x8000000f: 0x20000, + 0x10: 0x20820, + 0x11: 0x8020800, + 0x12: 0x20, + 0x13: 0x800, + 0x14: 0x8000800, + 0x15: 0x8000020, + 0x16: 0x8020020, + 0x17: 0x20000, + 0x18: 0x0, + 0x19: 0x20020, + 0x1a: 0x8020000, + 0x1b: 0x8000820, + 0x1c: 0x8020820, + 0x1d: 0x20800, + 0x1e: 0x820, + 0x1f: 0x8000000, + 0x80000010: 0x20000, + 0x80000011: 0x800, + 0x80000012: 0x8020020, + 0x80000013: 0x20820, + 0x80000014: 0x20, + 0x80000015: 0x8020000, + 0x80000016: 0x8000000, + 0x80000017: 0x8000820, + 0x80000018: 0x8020820, + 0x80000019: 0x8000020, + 0x8000001a: 0x8000800, + 0x8000001b: 0x0, + 0x8000001c: 0x20800, + 0x8000001d: 0x820, + 0x8000001e: 0x20020, + 0x8000001f: 0x8020800 + } + ]; + + // Masks that select the SBOX input + var SBOX_MASK = [ + 0xf8000001, 0x1f800000, 0x01f80000, 0x001f8000, + 0x0001f800, 0x00001f80, 0x000001f8, 0x8000001f + ]; + + /** + * DES block cipher algorithm. + */ + var DES = C_algo.DES = BlockCipher.extend({ + _doReset: function () { + // Shortcuts + var key = this._key; + var keyWords = key.words; + + // Select 56 bits according to PC1 + var keyBits = []; + for (var i = 0; i < 56; i++) { + var keyBitPos = PC1[i] - 1; + keyBits[i] = (keyWords[keyBitPos >>> 5] >>> (31 - keyBitPos % 32)) & 1; + } + + // Assemble 16 subkeys + var subKeys = this._subKeys = []; + for (var nSubKey = 0; nSubKey < 16; nSubKey++) { + // Create subkey + var subKey = subKeys[nSubKey] = []; + + // Shortcut + var bitShift = BIT_SHIFTS[nSubKey]; + + // Select 48 bits according to PC2 + for (var i = 0; i < 24; i++) { + // Select from the left 28 key bits + subKey[(i / 6) | 0] |= keyBits[((PC2[i] - 1) + bitShift) % 28] << (31 - i % 6); + + // Select from the right 28 key bits + subKey[4 + ((i / 6) | 0)] |= keyBits[28 + (((PC2[i + 24] - 1) + bitShift) % 28)] << (31 - i % 6); + } + + // Since each subkey is applied to an expanded 32-bit input, + // the subkey can be broken into 8 values scaled to 32-bits, + // which allows the key to be used without expansion + subKey[0] = (subKey[0] << 1) | (subKey[0] >>> 31); + for (var i = 1; i < 7; i++) { + subKey[i] = subKey[i] >>> ((i - 1) * 4 + 3); + } + subKey[7] = (subKey[7] << 5) | (subKey[7] >>> 27); + } + + // Compute inverse subkeys + var invSubKeys = this._invSubKeys = []; + for (var i = 0; i < 16; i++) { + invSubKeys[i] = subKeys[15 - i]; + } + }, + + encryptBlock: function (M, offset) { + this._doCryptBlock(M, offset, this._subKeys); + }, + + decryptBlock: function (M, offset) { + this._doCryptBlock(M, offset, this._invSubKeys); + }, + + _doCryptBlock: function (M, offset, subKeys) { + // Get input + this._lBlock = M[offset]; + this._rBlock = M[offset + 1]; + + // Initial permutation + exchangeLR.call(this, 4, 0x0f0f0f0f); + exchangeLR.call(this, 16, 0x0000ffff); + exchangeRL.call(this, 2, 0x33333333); + exchangeRL.call(this, 8, 0x00ff00ff); + exchangeLR.call(this, 1, 0x55555555); + + // Rounds + for (var round = 0; round < 16; round++) { + // Shortcuts + var subKey = subKeys[round]; + var lBlock = this._lBlock; + var rBlock = this._rBlock; + + // Feistel function + var f = 0; + for (var i = 0; i < 8; i++) { + f |= SBOX_P[i][((rBlock ^ subKey[i]) & SBOX_MASK[i]) >>> 0]; + } + this._lBlock = rBlock; + this._rBlock = lBlock ^ f; + } + + // Undo swap from last round + var t = this._lBlock; + this._lBlock = this._rBlock; + this._rBlock = t; + + // Final permutation + exchangeLR.call(this, 1, 0x55555555); + exchangeRL.call(this, 8, 0x00ff00ff); + exchangeRL.call(this, 2, 0x33333333); + exchangeLR.call(this, 16, 0x0000ffff); + exchangeLR.call(this, 4, 0x0f0f0f0f); + + // Set output + M[offset] = this._lBlock; + M[offset + 1] = this._rBlock; + }, + + keySize: 64/32, + + ivSize: 64/32, + + blockSize: 64/32 + }); + + // Swap bits across the left and right words + function exchangeLR(offset, mask) { + var t = ((this._lBlock >>> offset) ^ this._rBlock) & mask; + this._rBlock ^= t; + this._lBlock ^= t << offset; + } + + function exchangeRL(offset, mask) { + var t = ((this._rBlock >>> offset) ^ this._lBlock) & mask; + this._lBlock ^= t; + this._rBlock ^= t << offset; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.DES.encrypt(message, key, cfg); + * var plaintext = CryptoJS.DES.decrypt(ciphertext, key, cfg); + */ + C.DES = BlockCipher._createHelper(DES); + + /** + * Triple-DES block cipher algorithm. + */ + var TripleDES = C_algo.TripleDES = BlockCipher.extend({ + _doReset: function () { + // Shortcuts + var key = this._key; + var keyWords = key.words; + // Make sure the key length is valid (64, 128 or >= 192 bit) + if (keyWords.length !== 2 && keyWords.length !== 4 && keyWords.length < 6) { + throw new Error('Invalid key length - 3DES requires the key length to be 64, 128, 192 or >192.'); + } + + // Extend the key according to the keying options defined in 3DES standard + var key1 = keyWords.slice(0, 2); + var key2 = keyWords.length < 4 ? keyWords.slice(0, 2) : keyWords.slice(2, 4); + var key3 = keyWords.length < 6 ? keyWords.slice(0, 2) : keyWords.slice(4, 6); + + // Create DES instances + this._des1 = DES.createEncryptor(WordArray.create(key1)); + this._des2 = DES.createEncryptor(WordArray.create(key2)); + this._des3 = DES.createEncryptor(WordArray.create(key3)); + }, + + encryptBlock: function (M, offset) { + this._des1.encryptBlock(M, offset); + this._des2.decryptBlock(M, offset); + this._des3.encryptBlock(M, offset); + }, + + decryptBlock: function (M, offset) { + this._des3.decryptBlock(M, offset); + this._des2.encryptBlock(M, offset); + this._des1.decryptBlock(M, offset); + }, + + keySize: 192/32, + + ivSize: 64/32, + + blockSize: 64/32 + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.TripleDES.encrypt(message, key, cfg); + * var plaintext = CryptoJS.TripleDES.decrypt(ciphertext, key, cfg); + */ + C.TripleDES = BlockCipher._createHelper(TripleDES); + }()); + + + return CryptoJS.TripleDES; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/x64-core.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/x64-core.js new file mode 100644 index 0000000..57dcc14 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/crypto-js/x64-core.js @@ -0,0 +1,304 @@ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function (undefined) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var X32WordArray = C_lib.WordArray; + + /** + * x64 namespace. + */ + var C_x64 = C.x64 = {}; + + /** + * A 64-bit word. + */ + var X64Word = C_x64.Word = Base.extend({ + /** + * Initializes a newly created 64-bit word. + * + * @param {number} high The high 32 bits. + * @param {number} low The low 32 bits. + * + * @example + * + * var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607); + */ + init: function (high, low) { + this.high = high; + this.low = low; + } + + /** + * Bitwise NOTs this word. + * + * @return {X64Word} A new x64-Word object after negating. + * + * @example + * + * var negated = x64Word.not(); + */ + // not: function () { + // var high = ~this.high; + // var low = ~this.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise ANDs this word with the passed word. + * + * @param {X64Word} word The x64-Word to AND with this word. + * + * @return {X64Word} A new x64-Word object after ANDing. + * + * @example + * + * var anded = x64Word.and(anotherX64Word); + */ + // and: function (word) { + // var high = this.high & word.high; + // var low = this.low & word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise ORs this word with the passed word. + * + * @param {X64Word} word The x64-Word to OR with this word. + * + * @return {X64Word} A new x64-Word object after ORing. + * + * @example + * + * var ored = x64Word.or(anotherX64Word); + */ + // or: function (word) { + // var high = this.high | word.high; + // var low = this.low | word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise XORs this word with the passed word. + * + * @param {X64Word} word The x64-Word to XOR with this word. + * + * @return {X64Word} A new x64-Word object after XORing. + * + * @example + * + * var xored = x64Word.xor(anotherX64Word); + */ + // xor: function (word) { + // var high = this.high ^ word.high; + // var low = this.low ^ word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Shifts this word n bits to the left. + * + * @param {number} n The number of bits to shift. + * + * @return {X64Word} A new x64-Word object after shifting. + * + * @example + * + * var shifted = x64Word.shiftL(25); + */ + // shiftL: function (n) { + // if (n < 32) { + // var high = (this.high << n) | (this.low >>> (32 - n)); + // var low = this.low << n; + // } else { + // var high = this.low << (n - 32); + // var low = 0; + // } + + // return X64Word.create(high, low); + // }, + + /** + * Shifts this word n bits to the right. + * + * @param {number} n The number of bits to shift. + * + * @return {X64Word} A new x64-Word object after shifting. + * + * @example + * + * var shifted = x64Word.shiftR(7); + */ + // shiftR: function (n) { + // if (n < 32) { + // var low = (this.low >>> n) | (this.high << (32 - n)); + // var high = this.high >>> n; + // } else { + // var low = this.high >>> (n - 32); + // var high = 0; + // } + + // return X64Word.create(high, low); + // }, + + /** + * Rotates this word n bits to the left. + * + * @param {number} n The number of bits to rotate. + * + * @return {X64Word} A new x64-Word object after rotating. + * + * @example + * + * var rotated = x64Word.rotL(25); + */ + // rotL: function (n) { + // return this.shiftL(n).or(this.shiftR(64 - n)); + // }, + + /** + * Rotates this word n bits to the right. + * + * @param {number} n The number of bits to rotate. + * + * @return {X64Word} A new x64-Word object after rotating. + * + * @example + * + * var rotated = x64Word.rotR(7); + */ + // rotR: function (n) { + // return this.shiftR(n).or(this.shiftL(64 - n)); + // }, + + /** + * Adds this word with the passed word. + * + * @param {X64Word} word The x64-Word to add with this word. + * + * @return {X64Word} A new x64-Word object after adding. + * + * @example + * + * var added = x64Word.add(anotherX64Word); + */ + // add: function (word) { + // var low = (this.low + word.low) | 0; + // var carry = (low >>> 0) < (this.low >>> 0) ? 1 : 0; + // var high = (this.high + word.high + carry) | 0; + + // return X64Word.create(high, low); + // } + }); + + /** + * An array of 64-bit words. + * + * @property {Array} words The array of CryptoJS.x64.Word objects. + * @property {number} sigBytes The number of significant bytes in this word array. + */ + var X64WordArray = C_x64.WordArray = Base.extend({ + /** + * Initializes a newly created word array. + * + * @param {Array} words (Optional) An array of CryptoJS.x64.Word objects. + * @param {number} sigBytes (Optional) The number of significant bytes in the words. + * + * @example + * + * var wordArray = CryptoJS.x64.WordArray.create(); + * + * var wordArray = CryptoJS.x64.WordArray.create([ + * CryptoJS.x64.Word.create(0x00010203, 0x04050607), + * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) + * ]); + * + * var wordArray = CryptoJS.x64.WordArray.create([ + * CryptoJS.x64.Word.create(0x00010203, 0x04050607), + * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) + * ], 10); + */ + init: function (words, sigBytes) { + words = this.words = words || []; + + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 8; + } + }, + + /** + * Converts this 64-bit word array to a 32-bit word array. + * + * @return {CryptoJS.lib.WordArray} This word array's data as a 32-bit word array. + * + * @example + * + * var x32WordArray = x64WordArray.toX32(); + */ + toX32: function () { + // Shortcuts + var x64Words = this.words; + var x64WordsLength = x64Words.length; + + // Convert + var x32Words = []; + for (var i = 0; i < x64WordsLength; i++) { + var x64Word = x64Words[i]; + x32Words.push(x64Word.high); + x32Words.push(x64Word.low); + } + + return X32WordArray.create(x32Words, this.sigBytes); + }, + + /** + * Creates a copy of this word array. + * + * @return {X64WordArray} The clone. + * + * @example + * + * var clone = x64WordArray.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + + // Clone "words" array + var words = clone.words = this.words.slice(0); + + // Clone each X64Word object + var wordsLength = words.length; + for (var i = 0; i < wordsLength; i++) { + words[i] = words[i].clone(); + } + + return clone; + } + }); + }()); + + + return CryptoJS; + +})); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/uni-config-center/index.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/uni-config-center/index.js new file mode 100644 index 0000000..00ba62f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/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;tt?t.toUpperCase():"")}function w(e){return e.replace(g,e=>"_"+e.toLowerCase())}function v(e,t){let r,n;switch(t){case"snake2camel":n=y,r=h;break;case"camel2snake":n=w,r=g}for(const i in e)if(d(e,i)&&r.test(i)){const r=n(i);e[r]=e[i],delete e[i],p(e[r])?e[r]=v(e[r],t):Array.isArray(e[r])&&(e[r]=e[r].map(e=>v(e,t)))}return e}function _(e){return v(e,"snake2camel")}function b(e){return v(e,"camel2snake")}function T(e){return function(e,t="-"){e=e||new Date;const r=[];return r.push(e.getFullYear()),r.push(("00"+(e.getMonth()+1)).substr(-2)),r.push(("00"+e.getDate()).substr(-2)),r.join(t)}(e=e||new Date)+" "+function(e,t=":"){e=e||new Date;const r=[];return r.push(("00"+e.getHours()).substr(-2)),r.push(("00"+e.getMinutes()).substr(-2)),r.push(("00"+e.getSeconds()).substr(-2)),r.join(t)}(e)}function E(){"development"===process.env.NODE_ENV&&console.log(...arguments)}function C(e=6){let t="";for(let r=0;r-1?"&":"?"}access_token=${t.accessToken}`}return`${e}${r}`}class G{constructor(e){this.options=Object.assign({baseUrl:"https://api.weixin.qq.com",timeout:5e3},e)}async _requestWxOpenapi({name:e,url:t,data:r,options:n}){const i={method:"GET",dataType:"json",dataAsQueryString:!0,timeout:this.options.timeout};return await H({name:"auth."+e,url:`${this.options.baseUrl}${K(t,r)}`,data:r,options:n,defaultOptions:i})}async code2Session(e){return await this._requestWxOpenapi({name:"code2Session",url:"/sns/jscode2session",data:{grant_type:"authorization_code",appid:this.options.appId,secret:this.options.secret,js_code:e}})}async getOauthAccessToken(e){const t=await this._requestWxOpenapi({name:"getOauthAccessToken",url:"/sns/oauth2/access_token",data:{grant_type:"authorization_code",appid:this.options.appId,secret:this.options.secret,code:e}});return t.expiresIn&&(t.expired=Date.now()+1e3*t.expiresIn),t}async getUserInfo({accessToken:e,openid:t}={}){const{nickname:r,headimgurl:n}=await this._requestWxOpenapi({name:"getUserInfo",url:"/sns/userinfo",data:{accessToken:e,openid:t,appid:this.options.appId,secret:this.options.secret,scope:"snsapi_userinfo"}});return{nickname:r,avatar:n}}}async function Q({name:e,url:t,data:r,options:n,defaultOptions:i}){let o;n=Object.assign({},i,n,{data:b(Object.assign({},r))});try{o=await uniCloud.httpclient.request(t,n)}catch(t){return function(e,t){throw new a({code:t.code||-2,message:t.message||e+" fail"})}(e,t)}let s=o.data;const c=o.headers["content-type"];if(!Buffer.isBuffer(s)||0!==c.indexOf("text/plain")&&0!==c.indexOf("application/json"))Buffer.isBuffer(s)&&(s={buffer:s,contentType:c});else try{s=JSON.parse(s.toString())}catch(e){s=s.toString()}return _(function(e,t){if(t.ret||t.error){const r=t.ret||t.error||t.errcode||-2,n=t.msg||t.error_description||t.errmsg||e+" fail";throw new a({code:r,message:n})}return delete t.ret,delete t.msg,delete t.error,delete t.error_description,delete t.errcode,delete t.errmsg,{...t,errMsg:e+" ok",errCode:0}}(e,s||{errCode:-2,errMsg:"Request failed"}))}class X{constructor(e){this.options=Object.assign({baseUrl:"https://graph.qq.com",timeout:5e3},e)}async _requestQQOpenapi({name:e,url:t,data:r,options:n}){const i={method:"GET",dataType:"json",dataAsQueryString:!0,timeout:this.options.timeout};var o,s;return await Q({name:"auth."+e,url:(o=this.options.baseUrl,s=t,/^https?:/.test(s)?s:o+s),data:r,options:n,defaultOptions:i})}async getOpenidByToken({accessToken:e}={}){const t=await this._requestQQOpenapi({name:"getOpenidByToken",url:"/oauth2.0/me",data:{accessToken:e,unionid:1,fmt:"json"}});if(t.clientId!==this.options.appId)throw new a({code:"APPID_NOT_MATCH",message:"appid not match"});return{openid:t.openid,unionid:t.unionid}}async code2Session({code:e}={}){return await this._requestQQOpenapi({name:"getOpenidByToken",url:"https://api.q.qq.com/sns/jscode2session",data:{grant_type:"authorization_code",appid:this.options.appId,secret:this.options.secret,js_code:e}})}}const Y={RSA:"RSA-SHA1",RSA2:"RSA-SHA256"};var z={code2Session:{returnValue:{openid:"userId"}}};class W extends class{constructor(e={}){if(!e.appId)throw new Error("appId required");if(!e.privateKey)throw new Error("privateKey required");const t={gateway:"https://openapi.alipay.com/gateway.do",timeout:5e3,charset:"utf-8",version:"1.0",signType:"RSA2",timeOffset:-(new Date).getTimezoneOffset()/60,keyType:"PKCS8"};e.sandbox&&(e.gateway="https://openapi.alipaydev.com/gateway.do"),this.options=Object.assign({},t,e);const r="PKCS8"===this.options.keyType?"PRIVATE KEY":"RSA PRIVATE KEY";this.options.privateKey=this._formatKey(this.options.privateKey,r),this.options.alipayPublicKey&&(this.options.alipayPublicKey=this._formatKey(this.options.alipayPublicKey,"PUBLIC KEY"))}_formatKey(e,t){return`-----BEGIN ${t}-----\n${e}\n-----END ${t}-----`}_formatUrl(e,t){let r=e;const n=["app_id","method","format","charset","sign_type","sign","timestamp","version","notify_url","return_url","auth_token","app_auth_token"];for(const e in t)if(n.indexOf(e)>-1){const n=encodeURIComponent(t[e]);r=`${r}${r.includes("?")?"&":"?"}${e}=${n}`,delete t[e]}return{execParams:t,url:r}}_getSign(e,r){const n=r.bizContent||null;delete r.bizContent;const i=Object.assign({method:e,appId:this.options.appId,charset:this.options.charset,version:this.options.version,signType:this.options.signType,timestamp:T((o=this.options.timeOffset,new Date(Date.now()+6e4*((new Date).getTimezoneOffset()+60*(o||0)))))},r);var o;n&&(i.bizContent=JSON.stringify(b(n)));const s=b(i),a=Object.keys(s).sort().map(e=>{let t=s[e];return"[object String]"!==Array.prototype.toString.call(t)&&(t=JSON.stringify(t)),`${e}=${t}`}).join("&"),c=t.createSign(Y[this.options.signType]).update(a,"utf8").sign(this.options.privateKey,"base64");return Object.assign(s,{sign:c})}async _exec(e,t={},r={}){const n=this._getSign(e,t),{url:i,execParams:o}=this._formatUrl(this.options.gateway,n),{status:s,data:a}=await uniCloud.httpclient.request(i,{method:"POST",data:o,dataType:"text",timeout:this.options.timeout});if(200!==s)throw new Error("request fail");const c=JSON.parse(a),u=e.replace(/\./g,"_")+"_response",d=c[u],p=c.error_response;if(d){if(!r.validateSign||this._checkResponseSign(a,u)){if(!d.code||"10000"===d.code){return{errCode:0,errMsg:d.msg||"",..._(d)}}const e=d.sub_code?`${d.sub_code} ${d.sub_msg}`:""+(d.msg||"unkonwn error");throw new Error(e)}throw new Error("check sign error")}if(p)throw new Error(p.sub_msg||p.msg||"request fail");throw new Error("request fail")}_checkResponseSign(e,r){if(!this.options.alipayPublicKey||""===this.options.alipayPublicKey)return console.warn("options.alipayPublicKey is empty"),!0;if(!e)return!1;const n=this._getSignStr(e,r),i=JSON.parse(e).sign,o=t.createVerify(Y[this.options.signType]);return o.update(n,"utf8"),o.verify(this.options.alipayPublicKey,i,"base64")}_getSignStr(e,t){let r=e.trim();const n=e.indexOf(t+'"'),i=e.lastIndexOf('"sign"');return r=r.substr(n+t.length+1),r=r.substr(0,i),r=r.replace(/^[^{]*{/g,"{"),r=r.replace(/\}([^}]*)$/g,"}"),r}}{constructor(e){super(e),this._protocols=z}async code2Session(e){return await this._exec("alipay.system.oauth.token",{grantType:"authorization_code",code:e})}}function J(e){var t=e[0];return t<"0"||t>"7"?"00"+e:e}function Z(e){var t=e.toString(16);return t.length%2?"0"+t:t}function ee(e){if(e<=127)return Z(e);var t=Z(e);return Z(128+t.length/2)+t}function te(e,t){return e(t={exports:{}},t.exports),t.exports}var re=te((function(e,t){var n=r.Buffer;function i(e,t){for(var r in e)t[r]=e[r]}function o(e,t,r){return n(e,t,r)}n.from&&n.alloc&&n.allocUnsafe&&n.allocUnsafeSlow?e.exports=r:(i(r,t),t.Buffer=o),o.prototype=Object.create(n.prototype),i(n,o),o.from=function(e,t,r){if("number"==typeof e)throw new TypeError("Argument must not be a number");return n(e,t,r)},o.alloc=function(e,t,r){if("number"!=typeof e)throw new TypeError("Argument must be a number");var i=n(e);return void 0!==t?"string"==typeof r?i.fill(t,r):i.fill(t):i.fill(0),i},o.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return n(e)},o.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return r.SlowBuffer(e)}})),ne=(re.Buffer,re.Buffer);function ie(e){if(this.buffer=null,this.writable=!0,this.readable=!0,!e)return this.buffer=ne.alloc(0),this;if("function"==typeof e.pipe)return this.buffer=ne.alloc(0),e.pipe(this),this;if(e.length||"object"==typeof e)return this.buffer=e,this.writable=!1,process.nextTick(function(){this.emit("end",e),this.readable=!1,this.emit("close")}.bind(this)),this;throw new TypeError("Unexpected data type ("+typeof e+")")}i.inherits(ie,n),ie.prototype.write=function(e){this.buffer=ne.concat([this.buffer,ne.from(e)]),this.emit("data",e)},ie.prototype.end=function(e){e&&this.write(e),this.emit("end",e),this.emit("close"),this.writable=!1,this.readable=!1};var oe=ie,se=r.Buffer,ae=r.SlowBuffer,ce=ue;function ue(e,t){if(!se.isBuffer(e)||!se.isBuffer(t))return!1;if(e.length!==t.length)return!1;for(var r=0,n=0;n=128&&--n,n}var we={derToJose:function(e,t){e=ge(e);var r=me(t),n=r+1,i=e.length,o=0;if(48!==e[o++])throw new Error('Could not find expected "seq"');var s=e[o++];if(129===s&&(s=e[o++]),i-o0)return function(e){if((e=String(e)).length>100)return;var t=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(!t)return;var r=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*r;case"weeks":case"week":case"w":return 6048e5*r;case"days":case"day":case"d":return r*mt;case"hours":case"hour":case"hrs":case"hr":case"h":return r*ft;case"minutes":case"minute":case"mins":case"min":case"m":return r*lt;case"seconds":case"second":case"secs":case"sec":case"s":return r*pt;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}(e);if("number"===r&&isFinite(e))return t.long?function(e){var t=Math.abs(e);if(t>=mt)return gt(e,t,mt,"day");if(t>=ft)return gt(e,t,ft,"hour");if(t>=lt)return gt(e,t,lt,"minute");if(t>=pt)return gt(e,t,pt,"second");return e+" ms"}(e):function(e){var t=Math.abs(e);if(t>=mt)return Math.round(e/mt)+"d";if(t>=ft)return Math.round(e/ft)+"h";if(t>=lt)return Math.round(e/lt)+"m";if(t>=pt)return Math.round(e/pt)+"s";return e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))};function gt(e,t,r,n){var i=t>=1.5*r;return Math.round(e/r)+" "+n+(i?"s":"")}var yt=function(e,t){var r=t||Math.floor(Date.now()/1e3);if("string"==typeof e){var n=ht(e);if(void 0===n)return;return Math.floor(r+n/1e3)}return"number"==typeof e?r+e:void 0},wt=te((function(e,t){var r;t=e.exports=G,r="object"==typeof process&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?function(){var e=Array.prototype.slice.call(arguments,0);e.unshift("SEMVER"),console.log.apply(console,e)}:function(){},t.SEMVER_SPEC_VERSION="2.0.0";var n=Number.MAX_SAFE_INTEGER||9007199254740991,i=t.re=[],o=t.src=[],s=0,a=s++;o[a]="0|[1-9]\\d*";var c=s++;o[c]="[0-9]+";var u=s++;o[u]="\\d*[a-zA-Z-][a-zA-Z0-9-]*";var d=s++;o[d]="("+o[a]+")\\.("+o[a]+")\\.("+o[a]+")";var p=s++;o[p]="("+o[c]+")\\.("+o[c]+")\\.("+o[c]+")";var l=s++;o[l]="(?:"+o[a]+"|"+o[u]+")";var f=s++;o[f]="(?:"+o[c]+"|"+o[u]+")";var m=s++;o[m]="(?:-("+o[l]+"(?:\\."+o[l]+")*))";var h=s++;o[h]="(?:-?("+o[f]+"(?:\\."+o[f]+")*))";var g=s++;o[g]="[0-9A-Za-z-]+";var y=s++;o[y]="(?:\\+("+o[g]+"(?:\\."+o[g]+")*))";var w=s++,v="v?"+o[d]+o[m]+"?"+o[y]+"?";o[w]="^"+v+"$";var _="[v=\\s]*"+o[p]+o[h]+"?"+o[y]+"?",b=s++;o[b]="^"+_+"$";var T=s++;o[T]="((?:<|>)?=?)";var E=s++;o[E]=o[c]+"|x|X|\\*";var C=s++;o[C]=o[a]+"|x|X|\\*";var A=s++;o[A]="[v=\\s]*("+o[C]+")(?:\\.("+o[C]+")(?:\\.("+o[C]+")(?:"+o[m]+")?"+o[y]+"?)?)?";var I=s++;o[I]="[v=\\s]*("+o[E]+")(?:\\.("+o[E]+")(?:\\.("+o[E]+")(?:"+o[h]+")?"+o[y]+"?)?)?";var S=s++;o[S]="^"+o[T]+"\\s*"+o[A]+"$";var x=s++;o[x]="^"+o[T]+"\\s*"+o[I]+"$";var k=s++;o[k]="(?:^|[^\\d])(\\d{1,16})(?:\\.(\\d{1,16}))?(?:\\.(\\d{1,16}))?(?:$|[^\\d])";var O=s++;o[O]="(?:~>?)";var P=s++;o[P]="(\\s*)"+o[O]+"\\s+",i[P]=new RegExp(o[P],"g");var R=s++;o[R]="^"+o[O]+o[A]+"$";var j=s++;o[j]="^"+o[O]+o[I]+"$";var D=s++;o[D]="(?:\\^)";var q=s++;o[q]="(\\s*)"+o[D]+"\\s+",i[q]=new RegExp(o[q],"g");var N=s++;o[N]="^"+o[D]+o[A]+"$";var U=s++;o[U]="^"+o[D]+o[I]+"$";var L=s++;o[L]="^"+o[T]+"\\s*("+_+")$|^$";var V=s++;o[V]="^"+o[T]+"\\s*("+v+")$|^$";var M=s++;o[M]="(\\s*)"+o[T]+"\\s*("+_+"|"+o[A]+")",i[M]=new RegExp(o[M],"g");var B=s++;o[B]="^\\s*("+o[A]+")\\s+-\\s+("+o[A]+")\\s*$";var F=s++;o[F]="^\\s*("+o[I]+")\\s+-\\s+("+o[I]+")\\s*$";var $=s++;o[$]="(<|>)?=?\\s*\\*";for(var H=0;H<35;H++)r(H,o[H]),i[H]||(i[H]=new RegExp(o[H]));function K(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof G)return e;if("string"!=typeof e)return null;if(e.length>256)return null;if(!(t.loose?i[b]:i[w]).test(e))return null;try{return new G(e,t)}catch(e){return null}}function G(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof G){if(e.loose===t.loose)return e;e=e.version}else if("string"!=typeof e)throw new TypeError("Invalid Version: "+e);if(e.length>256)throw new TypeError("version is longer than 256 characters");if(!(this instanceof G))return new G(e,t);r("SemVer",e,t),this.options=t,this.loose=!!t.loose;var o=e.trim().match(t.loose?i[b]:i[w]);if(!o)throw new TypeError("Invalid Version: "+e);if(this.raw=e,this.major=+o[1],this.minor=+o[2],this.patch=+o[3],this.major>n||this.major<0)throw new TypeError("Invalid major version");if(this.minor>n||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>n||this.patch<0)throw new TypeError("Invalid patch version");o[4]?this.prerelease=o[4].split(".").map((function(e){if(/^[0-9]+$/.test(e)){var t=+e;if(t>=0&&t=0;)"number"==typeof this.prerelease[r]&&(this.prerelease[r]++,r=-2);-1===r&&this.prerelease.push(0)}t&&(this.prerelease[0]===t?isNaN(this.prerelease[1])&&(this.prerelease=[t,0]):this.prerelease=[t,0]);break;default:throw new Error("invalid increment argument: "+e)}return this.format(),this.raw=this.version,this},t.inc=function(e,t,r,n){"string"==typeof r&&(n=r,r=void 0);try{return new G(e,r).inc(t,n).version}catch(e){return null}},t.diff=function(e,t){if(J(e,t))return null;var r=K(e),n=K(t),i="";if(r.prerelease.length||n.prerelease.length){i="pre";var o="prerelease"}for(var s in r)if(("major"===s||"minor"===s||"patch"===s)&&r[s]!==n[s])return i+s;return o},t.compareIdentifiers=X;var Q=/^[0-9]+$/;function X(e,t){var r=Q.test(e),n=Q.test(t);return r&&n&&(e=+e,t=+t),e===t?0:r&&!n?-1:n&&!r?1:e0}function W(e,t,r){return Y(e,t,r)<0}function J(e,t,r){return 0===Y(e,t,r)}function Z(e,t,r){return 0!==Y(e,t,r)}function ee(e,t,r){return Y(e,t,r)>=0}function te(e,t,r){return Y(e,t,r)<=0}function re(e,t,r,n){switch(t){case"===":return"object"==typeof e&&(e=e.version),"object"==typeof r&&(r=r.version),e===r;case"!==":return"object"==typeof e&&(e=e.version),"object"==typeof r&&(r=r.version),e!==r;case"":case"=":case"==":return J(e,r,n);case"!=":return Z(e,r,n);case">":return z(e,r,n);case">=":return ee(e,r,n);case"<":return W(e,r,n);case"<=":return te(e,r,n);default:throw new TypeError("Invalid operator: "+t)}}function ne(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof ne){if(e.loose===!!t.loose)return e;e=e.value}if(!(this instanceof ne))return new ne(e,t);r("comparator",e,t),this.options=t,this.loose=!!t.loose,this.parse(e),this.semver===ie?this.value="":this.value=this.operator+this.semver.version,r("comp",this)}t.rcompareIdentifiers=function(e,t){return X(t,e)},t.major=function(e,t){return new G(e,t).major},t.minor=function(e,t){return new G(e,t).minor},t.patch=function(e,t){return new G(e,t).patch},t.compare=Y,t.compareLoose=function(e,t){return Y(e,t,!0)},t.rcompare=function(e,t,r){return Y(t,e,r)},t.sort=function(e,r){return e.sort((function(e,n){return t.compare(e,n,r)}))},t.rsort=function(e,r){return e.sort((function(e,n){return t.rcompare(e,n,r)}))},t.gt=z,t.lt=W,t.eq=J,t.neq=Z,t.gte=ee,t.lte=te,t.cmp=re,t.Comparator=ne;var ie={};function oe(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof oe)return e.loose===!!t.loose&&e.includePrerelease===!!t.includePrerelease?e:new oe(e.raw,t);if(e instanceof ne)return new oe(e.value,t);if(!(this instanceof oe))return new oe(e,t);if(this.options=t,this.loose=!!t.loose,this.includePrerelease=!!t.includePrerelease,this.raw=e,this.set=e.split(/\s*\|\|\s*/).map((function(e){return this.parseRange(e.trim())}),this).filter((function(e){return e.length})),!this.set.length)throw new TypeError("Invalid SemVer Range: "+e);this.format()}function se(e){return!e||"x"===e.toLowerCase()||"*"===e}function ae(e,t,r,n,i,o,s,a,c,u,d,p,l){return((t=se(r)?"":se(n)?">="+r+".0.0":se(i)?">="+r+"."+n+".0":">="+t)+" "+(a=se(c)?"":se(u)?"<"+(+c+1)+".0.0":se(d)?"<"+c+"."+(+u+1)+".0":p?"<="+c+"."+u+"."+d+"-"+p:"<="+a)).trim()}function ce(e,t,n){for(var i=0;i0){var o=e[i].semver;if(o.major===t.major&&o.minor===t.minor&&o.patch===t.patch)return!0}return!1}return!0}function ue(e,t,r){try{t=new oe(t,r)}catch(e){return!1}return t.test(e)}function de(e,t,r,n){var i,o,s,a,c;switch(e=new G(e,n),t=new oe(t,n),r){case">":i=z,o=te,s=W,a=">",c=">=";break;case"<":i=W,o=ee,s=z,a="<",c="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(ue(e,t,n))return!1;for(var u=0;u=0.0.0")),p=p||e,l=l||e,i(e.semver,p.semver,n)?p=e:s(e.semver,l.semver,n)&&(l=e)})),p.operator===a||p.operator===c)return!1;if((!l.operator||l.operator===a)&&o(e,l.semver))return!1;if(l.operator===c&&s(e,l.semver))return!1}return!0}ne.prototype.parse=function(e){var t=this.options.loose?i[L]:i[V],r=e.match(t);if(!r)throw new TypeError("Invalid comparator: "+e);this.operator=r[1],"="===this.operator&&(this.operator=""),r[2]?this.semver=new G(r[2],this.options.loose):this.semver=ie},ne.prototype.toString=function(){return this.value},ne.prototype.test=function(e){return r("Comparator.test",e,this.options.loose),this.semver===ie||("string"==typeof e&&(e=new G(e,this.options)),re(e,this.operator,this.semver,this.options))},ne.prototype.intersects=function(e,t){if(!(e instanceof ne))throw new TypeError("a Comparator is required");var r;if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),""===this.operator)return r=new oe(e.value,t),ue(this.value,r,t);if(""===e.operator)return r=new oe(this.value,t),ue(e.semver,r,t);var n=!(">="!==this.operator&&">"!==this.operator||">="!==e.operator&&">"!==e.operator),i=!("<="!==this.operator&&"<"!==this.operator||"<="!==e.operator&&"<"!==e.operator),o=this.semver.version===e.semver.version,s=!(">="!==this.operator&&"<="!==this.operator||">="!==e.operator&&"<="!==e.operator),a=re(this.semver,"<",e.semver,t)&&(">="===this.operator||">"===this.operator)&&("<="===e.operator||"<"===e.operator),c=re(this.semver,">",e.semver,t)&&("<="===this.operator||"<"===this.operator)&&(">="===e.operator||">"===e.operator);return n||i||o&&s||a||c},t.Range=oe,oe.prototype.format=function(){return this.range=this.set.map((function(e){return e.join(" ").trim()})).join("||").trim(),this.range},oe.prototype.toString=function(){return this.range},oe.prototype.parseRange=function(e){var t=this.options.loose;e=e.trim();var n=t?i[F]:i[B];e=e.replace(n,ae),r("hyphen replace",e),e=e.replace(i[M],"$1$2$3"),r("comparator trim",e,i[M]),e=(e=(e=e.replace(i[P],"$1~")).replace(i[q],"$1^")).split(/\s+/).join(" ");var o=t?i[L]:i[V],s=e.split(" ").map((function(e){return function(e,t){return r("comp",e,t),e=function(e,t){return e.trim().split(/\s+/).map((function(e){return function(e,t){r("caret",e,t);var n=t.loose?i[U]:i[N];return e.replace(n,(function(t,n,i,o,s){var a;return r("caret",e,t,n,i,o,s),se(n)?a="":se(i)?a=">="+n+".0.0 <"+(+n+1)+".0.0":se(o)?a="0"===n?">="+n+"."+i+".0 <"+n+"."+(+i+1)+".0":">="+n+"."+i+".0 <"+(+n+1)+".0.0":s?(r("replaceCaret pr",s),a="0"===n?"0"===i?">="+n+"."+i+"."+o+"-"+s+" <"+n+"."+i+"."+(+o+1):">="+n+"."+i+"."+o+"-"+s+" <"+n+"."+(+i+1)+".0":">="+n+"."+i+"."+o+"-"+s+" <"+(+n+1)+".0.0"):(r("no pr"),a="0"===n?"0"===i?">="+n+"."+i+"."+o+" <"+n+"."+i+"."+(+o+1):">="+n+"."+i+"."+o+" <"+n+"."+(+i+1)+".0":">="+n+"."+i+"."+o+" <"+(+n+1)+".0.0"),r("caret return",a),a}))}(e,t)})).join(" ")}(e,t),r("caret",e),e=function(e,t){return e.trim().split(/\s+/).map((function(e){return function(e,t){var n=t.loose?i[j]:i[R];return e.replace(n,(function(t,n,i,o,s){var a;return r("tilde",e,t,n,i,o,s),se(n)?a="":se(i)?a=">="+n+".0.0 <"+(+n+1)+".0.0":se(o)?a=">="+n+"."+i+".0 <"+n+"."+(+i+1)+".0":s?(r("replaceTilde pr",s),a=">="+n+"."+i+"."+o+"-"+s+" <"+n+"."+(+i+1)+".0"):a=">="+n+"."+i+"."+o+" <"+n+"."+(+i+1)+".0",r("tilde return",a),a}))}(e,t)})).join(" ")}(e,t),r("tildes",e),e=function(e,t){return r("replaceXRanges",e,t),e.split(/\s+/).map((function(e){return function(e,t){e=e.trim();var n=t.loose?i[x]:i[S];return e.replace(n,(function(t,n,i,o,s,a){r("xRange",e,t,n,i,o,s,a);var c=se(i),u=c||se(o),d=u||se(s);return"="===n&&d&&(n=""),c?t=">"===n||"<"===n?"<0.0.0":"*":n&&d?(u&&(o=0),s=0,">"===n?(n=">=",u?(i=+i+1,o=0,s=0):(o=+o+1,s=0)):"<="===n&&(n="<",u?i=+i+1:o=+o+1),t=n+i+"."+o+"."+s):u?t=">="+i+".0.0 <"+(+i+1)+".0.0":d&&(t=">="+i+"."+o+".0 <"+i+"."+(+o+1)+".0"),r("xRange return",t),t}))}(e,t)})).join(" ")}(e,t),r("xrange",e),e=function(e,t){return r("replaceStars",e,t),e.trim().replace(i[$],"")}(e,t),r("stars",e),e}(e,this.options)}),this).join(" ").split(/\s+/);return this.options.loose&&(s=s.filter((function(e){return!!e.match(o)}))),s=s.map((function(e){return new ne(e,this.options)}),this)},oe.prototype.intersects=function(e,t){if(!(e instanceof oe))throw new TypeError("a Range is required");return this.set.some((function(r){return r.every((function(r){return e.set.some((function(e){return e.every((function(e){return r.intersects(e,t)}))}))}))}))},t.toComparators=function(e,t){return new oe(e,t).set.map((function(e){return e.map((function(e){return e.value})).join(" ").trim().split(" ")}))},oe.prototype.test=function(e){if(!e)return!1;"string"==typeof e&&(e=new G(e,this.options));for(var t=0;t":0===t.prerelease.length?t.patch++:t.prerelease.push(0),t.raw=t.format();case"":case">=":r&&!z(r,t)||(r=t);break;case"<":case"<=":break;default:throw new Error("Unexpected operation: "+e.operator)}}))}if(r&&e.test(r))return r;return null},t.validRange=function(e,t){try{return new oe(e,t).range||"*"}catch(e){return null}},t.ltr=function(e,t,r){return de(e,t,"<",r)},t.gtr=function(e,t,r){return de(e,t,">",r)},t.outside=de,t.prerelease=function(e,t){var r=K(e,t);return r&&r.prerelease.length?r.prerelease:null},t.intersects=function(e,t,r){return e=new oe(e,r),t=new oe(t,r),e.intersects(t)},t.coerce=function(e){if(e instanceof G)return e;if("string"!=typeof e)return null;var t=e.match(i[k]);if(null==t)return null;return K(t[1]+"."+(t[2]||"0")+"."+(t[3]||"0"))}})),vt=(wt.SEMVER_SPEC_VERSION,wt.re,wt.src,wt.parse,wt.valid,wt.clean,wt.SemVer,wt.inc,wt.diff,wt.compareIdentifiers,wt.rcompareIdentifiers,wt.major,wt.minor,wt.patch,wt.compare,wt.compareLoose,wt.rcompare,wt.sort,wt.rsort,wt.gt,wt.lt,wt.eq,wt.neq,wt.gte,wt.lte,wt.cmp,wt.Comparator,wt.Range,wt.toComparators,wt.satisfies,wt.maxSatisfying,wt.minSatisfying,wt.minVersion,wt.validRange,wt.ltr,wt.gtr,wt.outside,wt.prerelease,wt.intersects,wt.coerce,wt.satisfies(process.version,"^6.12.0 || >=8.0.0")),_t=["RS256","RS384","RS512","ES256","ES384","ES512"],bt=["RS256","RS384","RS512"],Tt=["HS256","HS384","HS512"];vt&&(_t.splice(3,0,"PS256","PS384","PS512"),bt.splice(3,0,"PS256","PS384","PS512"));var Et=/^\s+|\s+$/g,Ct=/^[-+]0x[0-9a-f]+$/i,At=/^0b[01]+$/i,It=/^0o[0-7]+$/i,St=/^(?:0|[1-9]\d*)$/,xt=parseInt;function kt(e){return e!=e}function Ot(e,t){return function(e,t){for(var r=-1,n=e?e.length:0,i=Array(n);++r-1&&e%1==0&&e-1&&e%1==0&&e<=9007199254740991}(e.length)&&!function(e){var t=Ht(e)?qt.call(e):"";return"[object Function]"==t||"[object GeneratorFunction]"==t}(e)}function Ht(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function Kt(e){return!!e&&"object"==typeof e}var Gt=function(e,t,r,n){var i;e=$t(e)?e:(i=e)?Ot(i,function(e){return $t(e)?Vt(e):Mt(e)}(i)):[],r=r&&!n?function(e){var t=function(e){if(!e)return 0===e?e:0;if((e=function(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||Kt(e)&&"[object Symbol]"==qt.call(e)}(e))return NaN;if(Ht(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=Ht(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(Et,"");var r=At.test(e);return r||It.test(e)?xt(e.slice(2),r?2:8):Ct.test(e)?NaN:+e}(e))===1/0||e===-1/0){return 17976931348623157e292*(e<0?-1:1)}return e==e?e:0}(e),r=t%1;return t==t?r?t-r:t:0}(r):0;var o=e.length;return r<0&&(r=Lt(o+r,0)),function(e){return"string"==typeof e||!Ft(e)&&Kt(e)&&"[object String]"==qt.call(e)}(e)?r<=o&&e.indexOf(t,r)>-1:!!o&&function(e,t,r){if(t!=t)return function(e,t,r,n){for(var i=e.length,o=r+(n?1:-1);n?o--:++o-1},Qt=Object.prototype.toString;var Xt=function(e){return!0===e||!1===e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Boolean]"==Qt.call(e)},Yt=/^\s+|\s+$/g,zt=/^[-+]0x[0-9a-f]+$/i,Wt=/^0b[01]+$/i,Jt=/^0o[0-7]+$/i,Zt=parseInt,er=Object.prototype.toString;function tr(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}var rr=function(e){return"number"==typeof e&&e==function(e){var t=function(e){if(!e)return 0===e?e:0;if((e=function(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==er.call(e)}(e))return NaN;if(tr(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=tr(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(Yt,"");var r=Wt.test(e);return r||Jt.test(e)?Zt(e.slice(2),r?2:8):zt.test(e)?NaN:+e}(e))===1/0||e===-1/0){return 17976931348623157e292*(e<0?-1:1)}return e==e?e:0}(e),r=t%1;return t==t?r?t-r:t:0}(e)},nr=Object.prototype.toString;var ir=function(e){return"number"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Number]"==nr.call(e)};var or=Function.prototype,sr=Object.prototype,ar=or.toString,cr=sr.hasOwnProperty,ur=ar.call(Object),dr=sr.toString,pr=function(e,t){return function(r){return e(t(r))}}(Object.getPrototypeOf,Object);var lr=function(e){if(!function(e){return!!e&&"object"==typeof e}(e)||"[object Object]"!=dr.call(e)||function(e){var t=!1;if(null!=e&&"function"!=typeof e.toString)try{t=!!(e+"")}catch(e){}return t}(e))return!1;var t=pr(e);if(null===t)return!0;var r=cr.call(t,"constructor")&&t.constructor;return"function"==typeof r&&r instanceof r&&ar.call(r)==ur},fr=Object.prototype.toString,mr=Array.isArray;var hr=function(e){return"string"==typeof e||!mr(e)&&function(e){return!!e&&"object"==typeof e}(e)&&"[object String]"==fr.call(e)},gr=/^\s+|\s+$/g,yr=/^[-+]0x[0-9a-f]+$/i,wr=/^0b[01]+$/i,vr=/^0o[0-7]+$/i,_r=parseInt,br=Object.prototype.toString;function Tr(e,t){var r;if("function"!=typeof t)throw new TypeError("Expected a function");return e=function(e){var t=function(e){if(!e)return 0===e?e:0;if((e=function(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==br.call(e)}(e))return NaN;if(Er(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=Er(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(gr,"");var r=wr.test(e);return r||vr.test(e)?_r(e.slice(2),r?2:8):yr.test(e)?NaN:+e}(e))===1/0||e===-1/0){return 17976931348623157e292*(e<0?-1:1)}return e==e?e:0}(e),r=t%1;return t==t?r?t-r:t:0}(e),function(){return--e>0&&(r=t.apply(this,arguments)),e<=1&&(t=void 0),r}}function Er(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}var Cr=function(e){return Tr(2,e)},Ar=["RS256","RS384","RS512","ES256","ES384","ES512","HS256","HS384","HS512","none"];vt&&Ar.splice(3,0,"PS256","PS384","PS512");var Ir={expiresIn:{isValid:function(e){return rr(e)||hr(e)&&e},message:'"expiresIn" should be a number of seconds or string representing a timespan'},notBefore:{isValid:function(e){return rr(e)||hr(e)&&e},message:'"notBefore" should be a number of seconds or string representing a timespan'},audience:{isValid:function(e){return hr(e)||Array.isArray(e)},message:'"audience" must be a string or array'},algorithm:{isValid:Gt.bind(null,Ar),message:'"algorithm" must be a valid string enum value'},header:{isValid:lr,message:'"header" must be an object'},encoding:{isValid:hr,message:'"encoding" must be a string'},issuer:{isValid:hr,message:'"issuer" must be a string'},subject:{isValid:hr,message:'"subject" must be a string'},jwtid:{isValid:hr,message:'"jwtid" must be a string'},noTimestamp:{isValid:Xt,message:'"noTimestamp" must be a boolean'},keyid:{isValid:hr,message:'"keyid" must be a string'},mutatePayload:{isValid:Xt,message:'"mutatePayload" must be a boolean'}},Sr={iat:{isValid:ir,message:'"iat" should be a number of seconds'},exp:{isValid:ir,message:'"exp" should be a number of seconds'},nbf:{isValid:ir,message:'"nbf" should be a number of seconds'}};function xr(e,t,r,n){if(!lr(r))throw new Error('Expected "'+n+'" to be a plain object.');Object.keys(r).forEach((function(i){var o=e[i];if(o){if(!o.isValid(r[i]))throw new Error(o.message)}else if(!t)throw new Error('"'+i+'" is not allowed in "'+n+'"')}))}var kr={audience:"aud",issuer:"iss",subject:"sub",jwtid:"jti"},Or=["expiresIn","notBefore","noTimestamp","audience","issuer","subject","jwtid"],Pr=function(e,t,r,n){var i;if("function"!=typeof r||n||(n=r,r={}),r||(r={}),r=Object.assign({},r),i=n||function(e,t){if(e)throw e;return t},r.clockTimestamp&&"number"!=typeof r.clockTimestamp)return i(new st("clockTimestamp must be a number"));if(void 0!==r.nonce&&("string"!=typeof r.nonce||""===r.nonce.trim()))return i(new st("nonce must be a non-empty string"));var o=r.clockTimestamp||Math.floor(Date.now()/1e3);if(!e)return i(new st("jwt must be provided"));if("string"!=typeof e)return i(new st("jwt must be a string"));var s,a=e.split(".");if(3!==a.length)return i(new st("jwt malformed"));try{s=it(e,{complete:!0})}catch(e){return i(e)}if(!s)return i(new st("invalid token"));var c,u=s.header;if("function"==typeof t){if(!n)return i(new st("verify must be called asynchronous if secret or public key is provided as a callback"));c=t}else c=function(e,r){return r(null,t)};return c(u,(function(t,n){if(t)return i(new st("error in secret or public key callback: "+t.message));var c,d=""!==a[2].trim();if(!d&&n)return i(new st("jwt signature is required"));if(d&&!n)return i(new st("secret or public key must be provided"));if(d||r.algorithms||(r.algorithms=["none"]),r.algorithms||(r.algorithms=~n.toString().indexOf("BEGIN CERTIFICATE")||~n.toString().indexOf("BEGIN PUBLIC KEY")?_t:~n.toString().indexOf("BEGIN RSA PUBLIC KEY")?bt:Tt),!~r.algorithms.indexOf(s.header.alg))return i(new st("invalid algorithm"));try{c=nt.verify(e,s.header.alg,n)}catch(e){return i(e)}if(!c)return i(new st("invalid signature"));var p=s.payload;if(void 0!==p.nbf&&!r.ignoreNotBefore){if("number"!=typeof p.nbf)return i(new st("invalid nbf value"));if(p.nbf>o+(r.clockTolerance||0))return i(new ct("jwt not active",new Date(1e3*p.nbf)))}if(void 0!==p.exp&&!r.ignoreExpiration){if("number"!=typeof p.exp)return i(new st("invalid exp value"));if(o>=p.exp+(r.clockTolerance||0))return i(new dt("jwt expired",new Date(1e3*p.exp)))}if(r.audience){var l=Array.isArray(r.audience)?r.audience:[r.audience];if(!(Array.isArray(p.aud)?p.aud:[p.aud]).some((function(e){return l.some((function(t){return t instanceof RegExp?t.test(e):t===e}))})))return i(new st("jwt audience invalid. expected: "+l.join(" or ")))}if(r.issuer&&("string"==typeof r.issuer&&p.iss!==r.issuer||Array.isArray(r.issuer)&&-1===r.issuer.indexOf(p.iss)))return i(new st("jwt issuer invalid. expected: "+r.issuer));if(r.subject&&p.sub!==r.subject)return i(new st("jwt subject invalid. expected: "+r.subject));if(r.jwtid&&p.jti!==r.jwtid)return i(new st("jwt jwtid invalid. expected: "+r.jwtid));if(r.nonce&&p.nonce!==r.nonce)return i(new st("jwt nonce invalid. expected: "+r.nonce));if(r.maxAge){if("number"!=typeof p.iat)return i(new st("iat required when maxAge is specified"));var f=yt(r.maxAge,p.iat);if(void 0===f)return i(new st('"maxAge" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'));if(o>=f+(r.clockTolerance||0))return i(new dt("maxAge exceeded",new Date(1e3*f)))}if(!0===r.complete){var m=s.signature;return i(null,{header:u,payload:p,signature:m})}return i(null,p)}))},Rr=function(e,t,r,n){"function"==typeof r?(n=r,r={}):r=r||{};var i="object"==typeof e&&!Buffer.isBuffer(e),o=Object.assign({alg:r.algorithm||"HS256",typ:i?"JWT":void 0,kid:r.keyid},r.header);function s(e){if(n)return n(e);throw e}if(!t&&"none"!==r.algorithm)return s(new Error("secretOrPrivateKey must have a value"));if(void 0===e)return s(new Error("payload is required"));if(i){try{!function(e){xr(Sr,!0,e,"payload")}(e)}catch(e){return s(e)}r.mutatePayload||(e=Object.assign({},e))}else{var a=Or.filter((function(e){return void 0!==r[e]}));if(a.length>0)return s(new Error("invalid "+a.join(",")+" option for "+typeof e+" payload"))}if(void 0!==e.exp&&void 0!==r.expiresIn)return s(new Error('Bad "options.expiresIn" option the payload already has an "exp" property.'));if(void 0!==e.nbf&&void 0!==r.notBefore)return s(new Error('Bad "options.notBefore" option the payload already has an "nbf" property.'));try{!function(e){xr(Ir,!1,e,"options")}(r)}catch(e){return s(e)}var c=e.iat||Math.floor(Date.now()/1e3);if(r.noTimestamp?delete e.iat:i&&(e.iat=c),void 0!==r.notBefore){try{e.nbf=yt(r.notBefore,c)}catch(e){return s(e)}if(void 0===e.nbf)return s(new Error('"notBefore" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'))}if(void 0!==r.expiresIn&&"object"==typeof e){try{e.exp=yt(r.expiresIn,c)}catch(e){return s(e)}if(void 0===e.exp)return s(new Error('"expiresIn" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'))}Object.keys(kr).forEach((function(t){var n=kr[t];if(void 0!==r[t]){if(void 0!==e[n])return s(new Error('Bad "options.'+t+'" option. The payload already has an "'+n+'" property.'));e[n]=r[t]}}));var u=r.encoding||"utf8";if("function"!=typeof n)return nt.sign({header:o,payload:e,secret:t,encoding:u});n=n&&Cr(n),nt.createSign({header:o,privateKey:t,payload:e,encoding:u}).once("error",n).once("done",(function(e){n(null,e)}))};let jr=[];class Dr{constructor(e){this.options=Object.assign({baseUrl:"https://appleid.apple.com",timeout:1e4},e)}async _fetch(e,t){const{baseUrl:r}=this.options;return uniCloud.httpclient.request(r+e,t)}async verifyIdentityToken(e){const t=e.split(".")[0],{kid:r}=JSON.parse(Buffer.from(t,"base64").toString());if(!jr.length)try{jr=await this.getAuthKeys()}catch(e){return{code:10705,msg:e.message}}const n=this.getUsedKey(jr,r);if(!Object.keys(n).length&&!this.fetched)try{jr=await this.getAuthKeys()}catch(e){return{code:10705,msg:e.message}}let i=null;try{i=Pr(e,function(e,t){var r=Buffer.from(e,"base64"),n=Buffer.from(t,"base64"),i=r.toString("hex"),o=n.toString("hex");i=J(i),o=J(o);var s=i.length/2,a=o.length/2,c=ee(s),u=ee(a),d="30"+ee(s+a+c.length/2+u.length/2+2)+"02"+c+i+"02"+u+o;return"-----BEGIN RSA PUBLIC KEY-----\n"+Buffer.from(d,"hex").toString("base64").match(/.{1,64}/g).join("\n")+"\n-----END RSA PUBLIC KEY-----\n"}(n.n,n.e),{algorithms:n.alg})}catch(e){return{code:10705,msg:e.message}}return{code:0,msg:i}}async getAuthKeys(){const{status:e,data:t}=await this._fetch("/auth/keys",{method:"GET",dataType:"json",timeout:this.options.timeout});if(200!==e)throw new Error("request https://appleid.apple.com/auth/keys fail");return t.keys}getUsedKey(e,t){let r={};for(let n=0;nvoid 0===e))return{code:N,messageValues:{param:this.t("dcloud-appid")}};const r=await P.doc(e).get(),n=r&&r.data&&r.data[0];if(!n)return{code:10002};const i=Object.keys(q).reduce((e,t)=>{const r=t,i=function(e,t){return t.split(".").reduce((e,t)=>e&&e[t],e)}(n,t);return i&&e.push({[r]:i}),e},[]);let o;const s={dcloud_appid:Mr.in(t),_id:Mr.neq(n._id)},a={dcloud_appid:Mr.exists(!1),_id:Mr.neq(n._id)};switch(i.length){case 0:return{code:10004};case 1:o=Mr.or([Mr.and([i[0],s]),Mr.and([i[0],a])]);break;default:o=Mr.or([Mr.and([Mr.or(i),s]),Mr.and([Mr.or(i),a])])}const c=await P.where(o).limit(1).get();return c&&c.data&&c.data[0]?{code:10005}:{code:0}}const Fr=uniCloud.database().command;const $r=uniCloud.database();const Hr=uniCloud.database();const Kr=uniCloud.database();async function Gr(e){const t=["apiKey","apiSecret"];for(let r=0,n=t.length;r0){u=a.and(a.or(c),a.or({dcloud_appid:a.in(s)},{dcloud_appid:a.exists(!1)}));if((await P.where(u).limit(1).get()).data.length>0)return{code:10201,messageValues:{type:this.t("username")}}}const d={role:o,nickname:t,dcloud_appid:s,register_date:Date.now()};if(e&&(d.username=e),r){const{passwordHash:e,version:t}=this.encryptPwd(r);d.password=e,t&&(d.password_secret_version=t)}return n&&(d.mobile=n,d.mobile_confirmed=1),i&&(d.email=i,d.email_confirmed=1),{code:0,uid:(await P.add(d)).id}},getUserInfo:async function({uid:e,field:t}){if(!e)return{code:N,messageValues:{param:this.t("user-id")}};let r;if(t&&t.length){const n={};for(let e=0;evoid 0===e.dcloud_appid||e.dcloud_appid.includes(this.context.APPID));if(0===i.length)return{code:10002};if(i.length>1)return{code:10005};const o=i[0]._id;return this.resetPwd({uid:o,password:r})},setAvatar:async function(e){return await P.doc(e.uid).update({avatar:e.avatar}),{code:0,msg:""}},updatePwd:async function(e){const t=await P.doc(e.uid).get();if(t&&t.data&&t.data.length>0){if(0===this._checkPwd(t.data[0],e.oldPassword).code){const{passwordHash:r,version:n}=this.encryptPwd(e.newPassword),i={password:r,token:[]};n&&(i.password_secret_version=n);return E("upRes",await P.doc(t.data[0]._id).update(i)),{code:0,msg:""}}return{code:40202}}return{code:40201}},updateUser:async function(e){const t=e.uid;if(!t)return{code:N,messageValues:{param:this.t("user-id")}};delete e.uid;const{username:r,email:n}=e,{usernameToLowerCase:i,emailToLowerCase:o}=this._getConfig();let s=r&&r.trim(),a=n&&n.trim();return s&&(i&&(s=s.toLowerCase()),e.username=s),a&&(o&&(a=a.toLowerCase()),e.email=a),E("update -> upRes",await P.doc(t).update(e)),{code:0,msg:""}},banAccount:async function({uid:e}={}){return $.call(this,{uid:e,status:B})},unbanAccount:async function({uid:e}={}){return $.call(this,{uid:e,status:M})},closeAccount:async function({uid:e}={}){return $.call(this,{uid:e,status:F})},openAccount:async function({uid:e}={}){return $.call(this,{uid:e,status:M})},_getAlipayApi:function(){const e=this.context.PLATFORM,t=this._getConfig();if(!t.oauth||!t.oauth.alipay)throw new Error(this.t("config-param-require",{param:e+".alipay"}));return["appid","privateKey"].forEach(r=>{if(!t.oauth.alipay[r])throw new Error(this.t("config-param-require",{param:`${e}.alipay.${r}`}))}),Ur({...t.oauth.alipay})},_getValidInviteCode:async function({inviteCode:e}){let t,r=10;e?(r=1,t=e):t=Vr();let n=!1;try{for(;r>0&&!n;){r--;if(0===(await P.where({my_invite_code:t}).get()).data.length){n=!0;break}t=Vr()}t=Vr()}catch(e){}return n?{code:0,inviteCode:t}:e?{code:80401}:{code:80402}},_addUser:async function(e,{needPermission:t,autoSetDcloudAppid:r=!0}={}){const n=this._getConfig(),i={...e,dcloud_appid:r?[this.context.APPID]:[],register_date:Date.now()},o=(await P.add(i)).id;let s;if(n.removePermissionAndRoleFromToken)s=await this.createToken({uid:o,needPermission:t});else{const t=e.role||[];let r;r=0===t.length||t.includes("admin")?[]:await this._getPermissionListByRoleList(t),s=await this.createToken({uid:o,role:t,permission:r})}const{token:a,tokenExpired:c}=s;return await P.doc(o).update({token:[a]}),{token:a,tokenExpired:c,uid:o,type:"register",userInfo:Object.assign({},i,{token:[a]})}},_loginExec:async function(e,t={}){if(e.status===B)return{code:10001};if(e.status===F)return{code:10006};const r=this._getConfig();let n=e.token||[];"string"==typeof n&&(n=[n]);const i=this._getExpiredToken(n);let o;if(n=n.filter(e=>-1===i.indexOf(e)),r.removePermissionAndRoleFromToken){const r=t.needPermission;o=await this.createToken({uid:e._id,needPermission:r})}else{const t=e.role||[];let r;r=0===t.length||t.includes("admin")?[]:await this._getPermissionListByRoleList(t),o=await this.createToken({uid:e._id,role:t,permission:r})}const{token:s,tokenExpired:a}=o;n.push(s),e.token=n;const c={last_login_date:Date.now(),last_login_ip:this.context.CLIENTIP,token:n,...t.extraData};await P.doc(e._id).update(c);const u=Object.assign({},e,c);return{code:0,msg:"",token:s,uid:u._id,username:u.username,type:"login",userInfo:u,tokenExpired:a}},_registerExec:async function(e,{needPermission:t,autoSetDcloudAppid:r=!0}={}){const{my_invite_code:n}=e;if(this._getConfig().autoSetInviteCode||n){const t=await this._getValidInviteCode({inviteCode:n});if(t.code)return t;e.my_invite_code=t.inviteCode}const{PLATFORM:i,appId:o,appid:s,APPID:a,uniPlatform:c,appName:u,appVersion:d,appVersionCode:p,channel:l,clientIP:f,CLIENTIP:m,OS:h,osName:g}=this.context;return e.register_env={appid:o||s||a||"",uni_platform:c||i||"",os_name:g||h||"",app_name:u||"",app_version:d||"",app_version_code:p||"",channel:l?l+"":"",client_ip:f||m||""},{code:0,msg:"",...await this._addUser(e,{needPermission:t,autoSetDcloudAppid:r})}},_getWeixinApi:function(){const e=this.context.PLATFORM,t=this._getConfig();if(!t.oauth||!t.oauth.weixin)throw new Error(this.t("config-param-require",{param:e+".weixin"}));return["appid","appsecret"].forEach(r=>{if(!t.oauth.weixin[r])throw new Error(this.t("config-param-require",{param:`${e}.weixin.${r}`}))}),qr({...t.oauth.weixin})},_getQQApi:function(){const e=this.context.PLATFORM,t=this._getConfig();if(!t.oauth||!t.oauth.qq)throw new Error(this.t("config-param-require",{param:e+".qq"}));return["appid","appsecret"].forEach(r=>{if(!t.oauth.qq[r])throw new Error(this.t("config-param-require",{param:`${e}.qq.${r}`}))}),Nr({...t.oauth.qq})},_getMatchedUser:function(e,t){if(0===e.length)return{code:10002};let r;const n={},i={};for(let r=e.length-1;r>=0;r--){const o=e[r];for(let s=0;s0?{code:10003,messageValues:{target:"用户"}}:{code:0,msg:"",userMatched:r,fieldMatched:s,isFallbackValueMatched:!!s&&i[s]}},_getCurrentAppUser:function(e){const t=this.context.APPID;return e.filter(e=>void 0===e.dcloud_appid||null===e.dcloud_appid||e.dcloud_appid.indexOf(t)>-1||e.dcloud_appid.indexOf(null)>-1)},_checkLoginUserList:function(e){if(e&&1!==e.length)return e[0].status===F?{code:10006}:{code:10005}},setAuthorizedAppLogin:async function({uid:e,dcloudAppidList:t}={}){if("array"!==m(t))return{code:U,messageValues:{param:"dcloudAppidList",reason:this.t("type-array-required",{param:this.t("dcloud-appid-list")})}};if(t&&0!==t.length){const r=await Br.bind(this)({uid:e,dcloudAppidList:t});if(r.code)return r}return await P.doc(e).update({dcloud_appid:Mr.set(t)}),{code:0}},authorizeAppLogin:async function({uid:e,dcloudAppid:t}={}){const r=await Br.bind(this)({uid:e,dcloudAppidList:[t]});return r.code?r:(await P.doc(e).update({dcloud_appid:Mr.push(t)}),{code:0})},forbidAppLogin:async function({uid:e,dcloudAppid:t}={}){return e?(await P.doc(e).update({dcloud_appid:Mr.pull(t)}),{code:0}):{code:N,messageValues:{param:this.t("user-id")}}},acceptInvite:async function({uid:e,inviteCode:t}){const r=await P.where({_id:Fr.neq(e),inviter_uid:Fr.not(Fr.all([e])),my_invite_code:t}).get();if(1!==r.data.length)return{code:80501,msg:"邀请码无效"};const n=[r.data[0]._id].concat(r.data[0].inviter_uid||[]),i=await P.doc(e).field({my_invite_code:!0,inviter_uid:!0}).get();if(0===i.data.length)return{code:80502};if(i.data[0].inviter_uid&&i.data[0].inviter_uid.length>0)return{code:80503,msg:"邀请码不可修改"};const o=Date.now();return await P.doc(e).update({inviter_uid:n,invite_time:o}),await P.where({inviter_uid:e}).update({inviter_uid:Fr.push(n)}),{code:0,msg:""}},getInvitedUser:async function({uid:e,level:t=1,limit:r=20,offset:n=0,needTotal:i=!1}){const o={code:0,msg:"",invitedUser:(await P.where({["inviter_uid."+(t-1)]:e}).field({_id:!0,username:!0,mobile:!0,invite_time:!0}).orderBy("invite_time","desc").skip(n).limit(r).get()).data};if(i){const r=await P.where({["inviter_uid."+(t-1)]:e}).count();o.total=r.total}return o},setUserInviteCode:async function({uid:e,myInviteCode:t}){const r=await this._getValidInviteCode({inviteCode:t});return r.code?r:(await P.doc(e).update({my_invite_code:r.inviteCode}),{code:0,msg:"",myInviteCode:r.inviteCode})},loginByAlipay:async function(e){"string"==typeof e&&(e={code:e});const{needPermission:t,code:r,myInviteCode:n,role:i,type:o}=e,{openid:s}=await this._getAlipayApi().code2Session(r);if(!s)return{code:10501,messageValues:{account:this.t("alipay-account")}};let a=await P.where({ali_openid:s}).get();if(a=this._getCurrentAppUser(a.data),a&&a.length>0){if("register"===o)return{code:10502,messageValues:{type:this.t("alipay-account")}};if(1!==a.length)return{code:10005};const e=a[0],r=await this._loginExec(e,{needPermission:t});if(0!==r.code)return r;const{userInfo:n}=r;return{...r,openid:s,mobileConfirmed:1===n.mobile_confirmed,emailConfirmed:1===n.email_confirmed}}{if("login"===o)return{code:10503,messageValues:{type:this.t("alipay-account")}};const e={ali_openid:s};e.my_invite_code=n,e.role=i;const r=await this._registerExec(e,{needPermission:t});return 0!==r.code?r:{...r,openid:s,mobileConfirmed:!1,emailConfirmed:!1}}},loginByEmail:async function(e){let{email:t,code:r,password:n,myInviteCode:i,type:o,needPermission:s,role:a}=e||{};if(t=t&&t.trim(),!t)return{code:N,messageValues:{param:"邮箱"}};const{emailToLowerCase:c}=this._getConfig();let u=t;c&&(u=t.toLowerCase());const d=await this.verifyCode({email:u,code:r,type:o||"login"});if(0!==d.code)return d;let p={email:t,email_confirmed:1};const l={field:"email",value:t},f=$r.command;u!==t&&(p=f.or(p,{email:u,email_confirmed:1}),l.fallbackValue=u);let m=await P.where(p).get();if(m=this._getCurrentAppUser(m.data),m&&m.length>0){if("register"===o)return{code:10301,messageValues:{type:"邮箱"}};const e=this._getMatchedUser(m,[l]);if(e.code)return e;const{userMatched:t}=e,r=await this._loginExec(t,{needPermission:s});return 0!==r.code?r:{...r,email:u}}{if("login"===o)return{code:10302,messageValues:{type:"邮箱"}};const e={email:u,email_confirmed:1},t=n&&n.trim();if(t){const{passwordHash:r,version:n}=this.encryptPwd(t);e.password=r,n&&(e.password_secret_version=n)}e.my_invite_code=i,e.role=a;const r=await this._registerExec(e,{needPermission:s});return 0!==r.code?r:{...r,email:u}}},loginBySms:async function({mobile:e,code:t,password:r,inviteCode:n,myInviteCode:i,type:o,needPermission:s,role:a}){if(!(e=e&&e.trim()))return{code:N,messageValues:{param:this.t("mobile")}};const c=this._getConfig();if(c.forceInviteCode&&!o)throw new Error(this.t("login-with-invite-type-required"));const u=await this.verifyCode({mobile:e,code:t,type:o||"login"});if(0!==u.code)return u;const d={mobile:e,mobile_confirmed:1};let p=await P.where(d).get();if(p=this._getCurrentAppUser(p.data),p&&p.length>0){if("register"===o)return{code:10201,messageValues:{type:this.t("mobile")}};if(1!==p.length)return{code:10005};const t=p[0],r=await this._loginExec(t,{needPermission:s});return 0!==r.code?r:{...r,mobile:e}}{const t=Date.now();if("login"===o)return{code:10202,messageValues:{type:this.t("mobile")}};const u={mobile:e,mobile_confirmed:1,register_ip:this.context.CLIENTIP,register_date:t},d=r&&r.trim();if(d){const{passwordHash:e,version:t}=this.encryptPwd(d);u.password=e,t&&(u.password_secret_version=t)}if(n){const e=await P.where({my_invite_code:n}).get();if(1!==e.data.length)return{code:10203};u.inviter_uid=[e.data[0]._id].concat(e.data[0].inviter_uid||[]),u.invite_time=t}else if(c.forceInviteCode)return{code:10203};u.my_invite_code=i,u.role=a;const p=await this._registerExec(u,{needPermission:s});return 0!==p.code?p:{...p,mobile:e}}},loginByWeixin:async function(e){"string"==typeof e&&(e={code:e});const{needPermission:t,platform:r,code:n,myInviteCode:i,role:o,type:s}=e,a=r||this.context.PLATFORM,c="mp-weixin"===a,{openid:u,unionid:d,sessionKey:p,accessToken:l,refreshToken:f,expired:m}=await this._getWeixinApi()[c?"code2Session":"getOauthAccessToken"](n);if(!u)return{code:10401,messageValues:{account:"微信openid"}};let h;h=c?{sessionKey:p}:{accessToken:l,refreshToken:f,accessTokenExpired:m};const g=Hr.command,y=[{wx_openid:{[a]:u}}];d&&y.push({wx_unionid:d});let w=await P.where(g.or(...y)).get();if(w=this._getCurrentAppUser(w.data),w&&w.length>0){if("register"===s)return{code:10402,messageValues:{type:this.t("wechat-account")}};if(1!==w.length)return{code:10005};const e=w[0],r={wx_openid:{[a]:u}};d&&(r.wx_unionid=d);const n=await this._loginExec(e,{needPermission:t,extraData:r});if(0!==n.code)return n;const{userInfo:i}=n;return{...n,openid:u,unionid:d,...h,mobileConfirmed:1===i.mobile_confirmed,emailConfirmed:1===i.email_confirmed}}{if("login"===s)return{code:10403,messageValues:{type:this.t("wechat-account")}};const e={wx_openid:{[a]:u},wx_unionid:d};e.my_invite_code=i,e.role=o;const r=await this._registerExec(e,{needPermission:t});return 0!==r.code?r:{...r,openid:u,unionid:d,...h,mobileConfirmed:!1,emailConfirmed:!1}}},loginByQQ:async function({code:e,accessToken:t,myInviteCode:r,needPermission:n,role:i,type:o}={}){const s=this.context.PLATFORM,a="mp-qq"===s,{openid:c,unionid:u,sessionKey:d}=await this._getQQApi()[a?"code2Session":"getOpenidByToken"]({code:e,accessToken:t});if(!c)return{code:10801,messageValues:{account:"qq openid"}};const p={accessToken:t,sessionKey:d},l=Kr.command,f=[{qq_openid:{[s]:c}}];u&&f.push({qq_unionid:u});let m=await P.where(l.or(...f)).get();if(m=this._getCurrentAppUser(m.data),m&&m.length>0){if("register"===o)return{code:10802,messageValues:{type:this.t("qq-account")}};if(1!==m.length)return{code:10005};const e=m[0],t={qq_openid:{[s]:c}};u&&(t.qq_unionid=u);const r=await this._loginExec(e,{needPermission:n,extraData:t});if(0!==r.code)return r;const{userInfo:i}=r;return{...r,openid:c,unionid:u,...p,mobileConfirmed:1===i.mobile_confirmed,emailConfirmed:1===i.email_confirmed}}{if("login"===o)return{code:10803,messageValues:{type:this.t("qq-account")}};const e={qq_openid:{[s]:c},qq_unionid:u};e.my_invite_code=r,e.role=i;const t=await this._registerExec(e);return 0!==t.code?t:{...t,openid:c,unionid:u,...p,mobileConfirmed:!1,emailConfirmed:!1}}},loginByUniverify:async function({openid:e,access_token:t,password:r,inviteCode:n,myInviteCode:i,type:o,needPermission:s,role:a}){const c=this._getConfig(),u=c&&c.service&&c.service.univerify;if(!u)throw new Error(this.t("uni-verify-config-required"));if(c.forceInviteCode&&!o)throw new Error(this.t("login-with-invite-type-required"));const d=await Gr.bind(this)({...u,openid:e,access_token:t});if(0!==d.code)return d;const p=String(d.phoneNumber);let l=await P.where({mobile:p,mobile_confirmed:1}).get();if(l=this._getCurrentAppUser(l.data),l&&l.length>0){if("register"===o)return{code:10601,messageValues:{type:this.t("mobile")}};if(1!==l.length)return{code:10005};const e=l[0],t=await this._loginExec(e,{needPermission:s});return 0!==t.code?t:{...t,mobile:p}}if("login"===o)return{code:10602,messageValues:{type:this.t("mobile")}};const f=Date.now(),m={mobile:p,my_invite_code:i,mobile_confirmed:1,role:a},h=r&&r.trim();if(h){const{passwordHash:e,version:t}=this.encryptPwd(h);m.password=e,t&&(m.password_secret_version=t)}if(n){let e=await P.where({my_invite_code:n}).get();if(1!==e.data.length)return{code:10203};e=e.data[0],m.inviter_uid=[e._id].concat(e.inviter_uid||[]),m.invite_time=f}else if(c.forceInviteCode)return{code:10203};m.my_invite_code=i;const g=await this._registerExec(m,{needPermission:s});return 0!==g.code?g:{...g,mobile:p}},loginByApple:async function({nickName:e,fullName:t,identityToken:r,myInviteCode:n,type:i,needPermission:o,role:s}){const a=this._getConfig(),c=a&&a.oauth&&a.oauth.apple,u=c&&c.bundleId;if(!u)throw new Error(this.t("config-param-require",{param:"(app || app-plus).apple.bundleId"}));if(!r)return{code:N,messageValues:{param:"identityToken"}};t=e||(t&&Object.keys(t).length>0?t.familyName+t.givenName:"");const{code:d,msg:p}=await Lr().verifyIdentityToken(r);if(0!==d)return{code:d,msg:p,messageValues:{account:this.t("apple-account")}};const{iss:l,sub:f,aud:m,email:h}=p;if("https://appleid.apple.com"!==l)return{code:10706,messageValues:{account:this.t("apple-account")}};if(!f)return{code:10701,messageValues:{account:this.t("apple-account")}};if(u!==m)return{code:10702,messageValues:{account:this.t("apple-account")}};const g=t||"User-"+(h?h.split("@")[0]:Math.random().toString(32).slice(2));let y=await P.where({apple_openid:f}).get();if(y=this._getCurrentAppUser(y.data),y&&y.length>0){if("register"===i)return{code:10703,messageValues:{type:this.t("apple-account")}};if(1!==y.length)return{code:10005};const e=y[0],t=await this._loginExec(e,{needPermission:o});return 0!==t.code?t:{...t,openid:f}}if("login"===i)return{code:10704,messageValues:{type:this.t("apple-account")}};const w={nickname:g,apple_openid:f,my_invite_code:n,role:s},v=await this._registerExec(w,{needPermission:o});return 0!==v.code?v:{...v,openid:f}},login:async function({username:e,password:t,queryField:r=[],needPermission:n}){const i=Qr.command,o=[];r&&r.length||(r=["username"]),r.length>1&&console.warn(this.t("query-field-warning"));const{usernameToLowerCase:s,emailToLowerCase:a,passwordErrorLimit:c,passwordErrorRetryTime:u}=this._getConfig(),d={email:{email_confirmed:1},mobile:{mobile_confirmed:1}},p={},l=e&&e.trim();if(!l)return{code:N,messageValues:{param:this.t("username")}};s&&(p.username=l.toLowerCase()),a&&(p.email=l.toLowerCase());const f=[];r.forEach(t=>{o.push({[t]:e,...d[t]});const r={field:t,value:e};"username"===t&&p.username!==e?(o.push({[t]:p.username,...d[t]}),r.fallbackValue=p.username):"email"===t&&p.email!==e&&(o.push({[t]:p.email,...d[t]}),r.fallbackValue=p.email),f.push(r)});let m=await P.where(i.or(...o)).get();m=this._getCurrentAppUser(m.data);const h=this.context.CLIENTIP,g=this._getMatchedUser(m,f);if(g.code)return g;const{userMatched:y}=g;let w=y.login_ip_limit||[];w=w.filter(e=>e.last_error_time>Date.now()-1e3*u);let v=w.find(e=>e.ip===h);if(v&&v.error_times>=c)return{code:10103};const _=t&&t.trim();if(!_)return{code:N,messageValues:{param:"密码"}};const b=this._checkPwd(y,_);if(0===b.code){const e=w.indexOf(v);e>-1&&w.splice(e,1);const t={login_ip_limit:w},{passwordHash:r,passwordVersion:i}=b;r&&i&&(t.password=r,t.password_secret_version=i);const o=await this._loginExec(y,{needPermission:n,extraData:t});return o.code,o}return v?(v.error_times++,v.last_error_time=Date.now()):(v={ip:h,error_times:1,last_error_time:Date.now()},w.push(v)),await P.doc(y._id).update({login_ip_limit:w}),{code:10102,msg:"密码错误"}},register:async function(e){const t=[],r=[{name:"username",desc:this.t("username")},{name:"email",desc:this.t("email"),extraCond:{email_confirmed:1}},{name:"mobile",desc:this.t("mobile"),extraCond:{mobile_confirmed:1}}],{usernameToLowerCase:n,emailToLowerCase:i}=this._getConfig();r.forEach(r=>{const o=r.name;let s=e[o]&&e[o].trim();s?(("username"===r.name&&n||"email"===r.name&&i)&&(s=s.toLowerCase()),e[o]=s,t.push({[o]:s,...r.extraCond})):delete e[o]});const{username:o,email:s,mobile:a,myInviteCode:c,needPermission:u,autoSetDcloudAppid:d=!0}=e;if("needPermission"in e&&delete e.needPermission,"autoSetDcloudAppid"in e&&delete e.autoSetDcloudAppid,0===t.length)return{code:20101,messageValues:{param:this.t("user-unique-param")}};const p=Xr.command;let l=await P.where(p.or(...t)).get();if(l=this._getCurrentAppUser(l.data),l&&l.length>0){const t=l[0];if(t.status===F)return{code:10006};for(let n=0;nt[e]===i.extraCond[e])),t[i.name]===e[i.name]&&o)return{code:20102,messageValues:{type:i.desc}}}}const f=e.password&&e.password.trim();if(!f)return{code:N,messageValues:{param:this.t("password")}};const{passwordHash:m,version:h}=this.encryptPwd(f);e.password=m,h&&(e.password_secret_version=h),e.my_invite_code=c,delete e.myInviteCode;const g=await this._registerExec(e,{needPermission:u,autoSetDcloudAppid:d});return 0!==g.code?g:{...g,username:o,email:s,mobile:a}},logout:async function(e){const t=await this.checkToken(e);if(t.code)return t;const r=Yr.command;return await P.doc(t.uid).update({token:r.pull(e)}),{code:0,msg:""}},getRoleByUid:async function({uid:e}){if(!e)return{code:N,messageValues:{param:this.t("user-id")}};const t=await P.doc(e).get();return 0===t.data.length?{code:L}:{code:0,msg:"",role:t.data[0].role||[]}},getPermissionByRole:async function({roleID:e}){if(!e)return{code:N,messageValues:{param:"roleID"}};if("admin"===e){return{code:0,msg:"",permission:(await D.limit(1e3).get()).data.map(e=>e.permission_id)}}const t=await j.where({role_id:e}).get();return 0===t.data.length?{code:V}:{code:0,msg:"",permission:t.data[0].permission||[]}},getPermissionByUid:async function({uid:e}={}){const t=await P.aggregate().match({_id:e}).project({role:!0}).unwind("$role").lookup({from:"uni-id-roles",localField:"role",foreignField:"role_id",as:"roleDetail"}).unwind("$roleDetail").replaceRoot({newRoot:"$roleDetail"}).end(),r=[],n=[];return t.data.forEach(e=>{n.push(e.role_id),r.push(...e.permission)}),{code:0,msg:"",role:n,permission:A(r)}},bindRole:async function({uid:e,roleList:t,reset:r=!1}){const n={};return"string"==typeof t&&(t=[t]),n.role=r?t:zr.push(t),await P.doc(e).update(n),{code:0,msg:""}},bindPermission:async function({roleID:e,permissionList:t,reset:r=!1}){const n={};return"string"==typeof t&&(t=[t]),n.permission=r?t:zr.push(t),await j.where({role_id:e}).update(n),{code:0,msg:""}},unbindRole:async function({uid:e,roleList:t}){return"string"==typeof t&&(t=[t]),await P.doc(e).update({role:zr.pull(zr.in(t))}),{code:0,msg:""}},unbindPermission:async function({roleID:e,permissionList:t}){return"string"==typeof t&&(t=[t]),await j.where({role_id:e}).update({permission:zr.pull(zr.in(t))}),{code:0,msg:""}},addRole:async function({roleID:e,roleName:t,comment:r,permission:n=[]}){return e?"admin"===e?{code:U,messageValues:{param:"roleID",reason:this.t("add-role-admin-is-not-allowed")}}:(await j.add({role_id:e,role_name:t,comment:r,permission:n,create_date:Date.now()}),{code:0,msg:""}):{code:N,messageValues:{param:this.t("role-id")}}},addPermission:async function({permissionID:e,permissionName:t,comment:r}){return e?(await D.add({permission_id:e,permission_name:t,comment:r,create_date:Date.now()}),{code:0,msg:""}):{code:N,messageValues:{param:this.t("permission-id")}}},getRoleList:async function({limit:e=20,offset:t=0,needTotal:r=!0}){const n={code:0,msg:"",roleList:(await j.skip(t).limit(e).get()).data};if(r){const{total:e}=await j.where({_id:zr.exists(!0)}).count();n.total=e}return n},getRoleInfo:async function(e){const t=await j.where({role_id:e}).get();return 0===t.data.length?{code:V}:{code:0,...t.data[0]}},updateRole:async function({roleID:e,roleName:t,comment:r,permission:n}){return e?(await j.where({role_id:e}).update({role_name:t,comment:r,permission:n}),{code:0,msg:""}):{code:N,messageValues:{param:this.t("role-id")}}},deleteRole:async function({roleID:e}){const t=m(e);if("string"===t)e=[e];else if("array"!==t)throw new Error("typeof roleID must be array or string");return await j.where({role_id:zr.in(e)}).remove(),await P.where({role:zr.elemMatch(zr.in(e))}).update({role:zr.pullAll(e)}),{code:0,msg:""}},getPermissionList:async function({limit:e=20,offset:t=0,needTotal:r=!0}){const n={code:0,msg:"",permissionList:(await D.skip(t).limit(e).get()).data};if(r){const{total:e}=await D.where({_id:zr.exists(!0)}).count();n.total=e}return n},getPermissionInfo:async function(e){const t=await D.where({permission_id:e}).get();return 0===t.data.length?{code:N,messageValues:{param:this.t("permission-id")}}:{code:0,...t.data[0]}},updatePermission:async function({permissionID:e,permissionName:t,comment:r}){return e?(await D.where({permission_id:e}).update({permission_name:t,comment:r}),{code:0,msg:""}):{code:N,messageValues:{param:this.t("permission-id")}}},deletePermission:async function({permissionID:e}){const t=m(e);if("string"===t)e=[e];else if("array"!==t)throw new Error("typeof permissionID must be array or string");return await D.where({permission_id:zr.in(e)}).remove(),await j.where({permission:zr.elemMatch(zr.in(e))}).update({permission:zr.pullAll(e)}),{code:0,msg:""}},bindAlipay:async function({uid:e,code:t,platform:r}){const n=r||this.context.PLATFORM,{openid:i}=await this._getAlipayApi({platform:n}).code2Session(t);if(!i)return{code:60401,messageValues:{account:this.t("alipay-account")}};let o=await P.where({ali_openid:i}).get();return o=this._getCurrentAppUser(o.data),o&&o.length>0?{code:60402,messageValues:{type:this.t("alipay-account")}}:(await P.doc(e).update({ali_openid:i}),{code:0,openid:i,msg:""})},bindEmail:async function(e){let{uid:t,email:r,code:n}=e||{};if(r=r&&r.trim(),!r)return{code:N,messageValues:{param:this.t("email")}};if(!n)return{code:N,messageValues:{param:this.t("verify-code")}};const{emailToLowerCase:i}=this._getConfig();i&&(r=r.toLowerCase());let o=await P.where({email:r,email_confirmed:1}).get();if(o=this._getCurrentAppUser(o.data),o&&o.length>0)return{code:60201,messageValues:{type:this.t("email")}};const s=await this.verifyCode({email:r,code:n,type:"bind"});return 0!==s.code?s:(await P.doc(t).update({email:r,email_confirmed:1}),{code:0,msg:"",email:r})},bindMobile:async function(e){let{uid:t,mobile:r,code:n,openid:i,access_token:o,type:s="sms"}=e||{};if("univerify"===s){const e=this._getConfig(),t=e&&e.service&&e.service.univerify;if(!t)throw new Error("请在config.json中配置service.univerify下一键登录相关参数");const n=await Gr.bind(this)({...t,openid:i,access_token:o});if(0!==n.code)return n;r=""+n.phoneNumber}let a=await P.where({mobile:r,mobile_confirmed:1}).get();if(a=this._getCurrentAppUser(a.data),a&&a.length>0)return{code:60101,messageValues:{type:"手机号"}};if("sms"===s&&"code"in e){if(!r)return{code:N,messageValues:{param:this.t("mobile")}};if(!n)return{code:N,messageValues:{param:this.t("verify-code")}};const e=await this.verifyCode({mobile:r,code:n,type:"bind"});if(0!==e.code)return e}return await P.doc(t).update({mobile:r,mobile_confirmed:1}),{code:0,msg:"",mobile:r}},bindWeixin:async function({uid:e,code:t,platform:r}){const n=r||this.context.PLATFORM,i="mp-weixin"===n,{openid:o,unionid:s,sessionKey:a,accessToken:c,refreshToken:u,expired:d}=await this._getWeixinApi({platform:n})[i?"code2Session":"getOauthAccessToken"](t);if(!o)return{code:60301,messageValues:{account:"微信openid"}};const p=Wr.command,l=[{wx_openid:{[n]:o}}];s&&l.push({wx_unionid:s});let f=await P.where(p.or(...l)).get();if(f=this._getCurrentAppUser(f.data),f&&f.length>0)return{code:60302,messageValues:{type:this.t("wechat-account")}};const m={wx_openid:{[n]:o}};let h;return s&&(m.wx_unionid=s),await P.doc(e).update(m),h=i?{sessionKey:a}:{accessToken:c,refreshToken:u,accessTokenExpired:d},{code:0,msg:"",openid:o,unionid:s,...h}},bindQQ:async function({uid:e,code:t,accessToken:r,platform:n}={}){const i=n||this.context.PLATFORM,o="mp-qq"===i,{openid:s,unionid:a,sessionKey:c}=await this._getQQApi()[o?"code2Session":"getOpenidByToken"]({code:t,accessToken:r});if(!s)return{code:60501,messageValues:{account:"qq openid"}};const u=Jr.command,d=[{qq_openid:{[i]:s}}];a&&d.push({qq_unionid:a});let p=await P.where(u.or(...d)).get();if(p=this._getCurrentAppUser(p.data),p&&p.length>0)return{code:60502,messageValues:{type:this.t("qq-account")}};const l={qq_openid:{[i]:s}};return a&&(l.qq_unionid=a),await P.doc(e).update(l),{code:0,msg:"",openid:s,unionid:a,...{accessToken:r,sessionKey:c}}},unbindAlipay:async function(e){const t=Zr.command,r=await P.doc(e).update({ali_openid:t.remove()});return E("upRes:",r),1===r.updated?{code:0,msg:""}:{code:70401}},unbindEmail:async function(e){let{uid:t,email:r,code:n}=e||{};if(r=r&&r.trim(),!t||!r)return{code:N,messageValues:{param:t?this.t("email"):this.t("user-id")}};const{emailToLowerCase:i}=this._getConfig();if("code"in e){const e=await this.verifyCode({email:r,code:n,type:"unbind"});if(0!==e.code)return e}const o=en.command;let s={_id:t,email:r};if(i){const e=r.toLowerCase();e!==r&&(s=o.or(s,{_id:t,email:e}))}return 1===(await P.where(s).update({email:o.remove(),email_confirmed:o.remove()})).updated?{code:0,msg:""}:{code:70201}},unbindMobile:async function(e){const{uid:t,mobile:r,code:n}=e||{};if("code"in e){const e=await this.verifyCode({mobile:r,code:n,type:"unbind"});if(0!==e.code)return e}const i=tn.command;return 1===(await P.where({_id:t,mobile:r}).update({mobile:i.remove(),mobile_confirmed:i.remove()})).updated?{code:0,msg:""}:{code:70101}},unbindWeixin:async function(e){const t=rn.command,r=await P.doc(e).update({wx_openid:t.remove(),wx_unionid:t.remove()});return E("upRes:",r),1===r.updated?{code:0,msg:""}:{code:70301}},unbindQQ:async function(e){const t=nn.command,r=await P.doc(e).update({qq_openid:t.remove(),qq_unionid:t.remove()});return E("upRes:",r),1===r.updated?{code:0,msg:""}:{code:70501}},getSupportedLoginType:function({appid:e,platform:t}={}){if(!e||!t)throw new Error("Parameter appid and platform is required");const r=this._getConfig({appid:e,platform:t}),n=["username-password","mobile-password","email-password"];for(const e in on)on[e](r)&&n.push(e);return{supportedLoginType:n}},code2SessionAlipay:async function(e){let t=e;"string"==typeof e&&(t={code:e});try{const e=t.platform||this.context.PLATFORM,r=await this._getAlipayApi({platform:e}).code2Session(t.code);return r.openid?{code:0,msg:"",...r}:{code:80701,messageValues:{account:this.t("alipay-account")}}}catch(e){return console.error(e),{code:80702,messageValues:{account:this.t("alipay-account")}}}},code2SessionWeixin:async function(e){let t=e;"string"==typeof e&&(t={code:e});try{const e=t.platform||this.context.PLATFORM,r=await this._getWeixinApi({platform:e})["mp-weixin"===e?"code2Session":"getOauthAccessToken"](t.code);return r.openid?{code:0,msg:"",...r}:{code:80601,messageValues:{account:"微信openid"}}}catch(e){return console.error(e),{code:80602,messageValues:{account:"微信openid"}}}},verifyAppleIdentityToken:async function({identityToken:e,platform:t}){const r=t||this.context.PLATFORM,{code:n,msg:i}=await Lr({clientType:r}).verifyIdentityToken(e);return 0!==n?{code:n,msg:i}:{code:n,msg:"验证通过",...i}},wxBizDataCrypt:async function({code:e,sessionKey:r,encryptedData:n,iv:i}){if(!n)return{code:N,messageValues:{param:"encryptedData"}};if(!i)return{code:N,messageValues:{param:"iv"}};if(!e&&!r)return{code:N,messageValues:{param:"sessionKey"}};const o=this._getWeixinApi();if(!r){const t=await o.code2Session(e);if(!t.sessionKey)return{code:80801};r=t.sessionKey}r=Buffer.from(r,"base64"),n=Buffer.from(n,"base64"),i=Buffer.from(i,"base64");try{var s=t.createDecipheriv("aes-128-cbc",r,i);s.setAutoPadding(!0);var a=s.update(n,"binary","utf8");a+=s.final("utf8"),a=JSON.parse(a)}catch(e){return console.error(e),{code:80802}}return a.watermark.appid!==o.options.appId?{code:80803}:{code:0,msg:"",...a}},getWeixinUserInfo:async function({accessToken:e,openid:t}={}){const r=this.context.PLATFORM;if("app"!==r&&"app-plus"!==r)throw new Error(this.t("limit-client-platform"));try{return{code:0,msg:"",...await this._getWeixinApi().getUserInfo({accessToken:e,openid:t})}}catch(e){return console.error(e),{code:80901}}},encryptPwd:function(e,{value:r,version:n}={}){if(!(e=e&&e.trim()))throw new Error(this.t("param-required",{param:this.t("password")}));if(!r){const e=this._getConfig(),{passwordSecret:t}=e;if("array"===m(t)){const e=t.sort((e,t)=>e.version-t.version);r=e[e.length-1].value,n=e[e.length-1].version}else r=t}if(!r)throw new Error(this.t("param-error",{param:"passwordSecret",reason:"invalid passwordSecret"}));const i=t.createHmac("sha1",r.toString("ascii"));return i.update(e),{passwordHash:i.digest("hex"),version:n}},checkToken:async function(e,{needPermission:t,needUserInfo:r=!0}={}){const n=this._getConfig(),i=this._verifyToken(e);if(i.code)return i;const{uid:o,needPermission:s,role:a,permission:c,exp:u,iat:d,...p}=i,l=a&&c;t=void 0===t?s:t;const f=n.removePermissionAndRoleFromToken||!l||r,m=!n.removePermissionAndRoleFromToken&&!l||n.removePermissionAndRoleFromToken&&l||n.tokenExpiresThreshold&&u-Date.now()/1e3this._createTokenInternal({signContent:e,config:o})):this._createTokenInternal({signContent:a,config:o})},_updateToken:async function({uid:e,tokenList:t,removeToken:r=[],addToken:n=[]}={}){if(!t){const r=await P.doc(e).get(),n=r.data&&r.data[0];t=n&&n.token||[]}"string"==typeof t&&(t=[t]);const i=this._getExpiredToken(t);(t=t.filter(e=>-1===i.indexOf(e))).push(...n);for(let e=0;ee.version-t.version);let c;if(c=n?a.find(e=>e.version===n):a[0],!c)return{code:3};const u=a[a.length-1],{passwordHash:d}=this.encryptPwd(t,c);if(d===r){const e={code:0};if(c!==u){const{passwordHash:r,version:n}=this.encryptPwd(t,u);e.passwordHash=r,e.passwordVersion=n}return e}return{code:4,message:""}},_verifyToken:function(e){const t=this._getConfig();let r;try{r=Pr(e,t.tokenSecret)}catch(e){return"TokenExpiredError"===e.name?{code:30203,err:e}:{code:30204,err:e}}return t.bindTokenToDevice&&r.clientId&&r.clientId!==this._getClientUaHash()?{code:30201}:{code:0,message:"",...r}},_getExpiredToken:function(e){const t=this._getConfig(),r=[];return e.forEach(e=>{try{Pr(e,t.tokenSecret)}catch(t){r.push(e)}}),r},_getPermissionListByRoleList:async function(e){if(!Array.isArray(e))return[];if(0===e.length)return[];if(e.includes("admin")){return(await D.limit(500).get()).data.map(e=>e.permission_id)}const t=await j.where({role_id:sn.in(e)}).get(),r=[];return t.data.forEach(e=>{Array.prototype.push.apply(r,e.permission)}),A(r)},_getClientUaHash:function(){const e=t.createHash("md5"),r=/MicroMessenger/i.test(this.context.CLIENTUA)?this.context.CLIENTUA.replace(/(MicroMessenger\S+).*/i,"$1"):this.context.CLIENTUA;return e.update(r),e.digest("hex")},_createTokenInternal:function({signContent:e,config:t}){if(t.tokenExpiresIn&&t.tokenExpiresThreshold&&t.tokenExpiresIn<=t.tokenExpiresThreshold)throw new Error(this.t("token-expires-config-warning"));return"object"===m(e)&&e.uid?(t.bindTokenToDevice&&(e.clientId=this._getClientUaHash()),{token:Rr(e,t.tokenSecret,{expiresIn:t.tokenExpiresIn}),tokenExpired:Date.now()+1e3*t.tokenExpiresIn}):{code:30101,messageValues:{param:this.t("user-id")}}},setVerifyCode:async function({mobile:e,email:t,code:r,expiresIn:n,type:i}){if(t=t&&t.trim(),e=e&&e.trim(),t){const{emailToLowerCase:e}=this._getConfig();e&&(t=t.toLowerCase())}if(!e&&!t)return{code:50101,messageValues:{param:"手机号或邮箱"}};if(e&&t)return{code:50102,messageValues:{param:"参数",reason:"手机号和邮箱不可同时存在"}};r||(r=C()),n||(n=180);const o=Date.now(),s={mobile:e,email:t,type:i,code:r,state:0,ip:this.context.CLIENTIP,created_at:o,expired_at:o+1e3*n};return await R.add(s),{code:0,mobile:e,email:t}},verifyCode:async function({mobile:e,email:t,code:r,type:n}){if(t=t&&t.trim(),e=e&&e.trim(),t){const{emailToLowerCase:e}=this._getConfig();e&&(t=t.toLowerCase())}if(!e&&!t)return{code:50201,messageValues:{param:"手机号或邮箱"}};if(e&&t)return{code:50203,messageValues:{param:"参数",reason:"手机号和邮箱不可同时存在"}};if(!r)return{code:50202,messageValues:{type:this.t(e?"sms":"email")}};const i=an.command,o=Date.now(),s={mobile:e,email:t,type:n,code:r,state:0,expired_at:i.gt(o)},a=await R.where(s).orderBy("created_at","desc").limit(1).get();if(a&&a.data&&a.data.length>0){const e=a.data[0];return await R.doc(e._id).update({state:1}),{code:0,msg:"验证通过"}}return{code:50202,messageValues:{type:this.t(e?"sms":"email")}}},sendSmsCode:async function({mobile:e,code:t,type:r,templateId:n}){if(!e)return{code:N,messageValues:{param:this.t("mobile")}};if(t||(t=C()),!r)return{code:N,messageValues:{param:this.t("verify-code-type")}};const i=this._getConfig();let o=i&&i.service&&i.service.sms;if(!o)throw new Error(this.t("config-param-required",{param:"service.sms"}));o=Object.assign({codeExpiresIn:300},o);const s=["smsKey","smsSecret"];for(let e=0,t=s.length;e=0?o:{code:0,msg:""}}catch(e){return console.error(e),{code:50301}}}});let un;try{un=require("uni-config-center")}catch(e){throw new Error("Plugin[uni-config-center] was not found")}class dn{constructor({context:e,clientInfo:t,config:r}={}){const n=un({pluginId:"uni-id"});this.pluginConfig=n,this.config=r||this._getConfigContent(),this._configCache={},Object.defineProperty(this,"context",{get(){let r;r=t?{OS:t.os,CLIENTIP:t.clientIP,CLIENTUA:t.userAgent,PLATFORM:t.platform,APPID:t.appId,LOCALE:t.locale,DEVICEID:t.deviceId}:Object.assign({},e||global.__ctx__||{});const n=["CLIENTIP","PLATFORM","APPID","LOCALE"];for(let e=0;ee.dcloudAppid===t)||e.find(e=>e.isDefaultConfig):e}_parseConfigContent(e){return Array.isArray(e)?e:e[0]?Object.values(e):e}_getConfigContent(){if(this.pluginConfig&&this.pluginConfig.hasFile("config.json")){let e;try{e=this.pluginConfig.config()}catch(e){throw new Error("Invalid uni-id config file\n"+e.message)}return this._parseConfigContent(e)}{let e;try{e=require("./config.json")}catch(e){if("MODULE_NOT_FOUND"===e.code||"ENOENT"===e.code)throw new Error("uni-id config file[uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json] not found");throw e}return this._parseConfigContent(e)}}init(){throw new Error("uniID.init has been deprecated, use uniID.createInstance instead")}setInterceptor(e,t){this.interceptorMap.set(e,t)}_getConfig({appid:e,platform:t}={}){const r=`${e=e||this.context.APPID}_${t=t||this.context.PLATFORM}`;if(this._configCache[r])return this._configCache[r];if(!(this.config&&0!==Object.keys(this.config).length))throw new Error(this.t("config-file-not-found"));const n=this._getAppConfig(this.config,e);"app"!==t&&"app-plus"!==t||(t=n.preferedAppPlatform||t),"web"!==t&&"h5"!==t||(t=n.preferedWebPlatform||t);const i=Object.assign(n,n[t])||{},o=Object.assign({bindTokenToDevice:!1,tokenExpiresIn:7200,tokenExpiresThreshold:1200,passwordErrorLimit:6,passwordErrorRetryTime:3600,usernameToLowerCase:!0,emailToLowerCase:!0},i);return["passwordSecret","tokenSecret","tokenExpiresIn","passwordErrorLimit","passwordErrorRetryTime"].forEach(e=>{if(!o||!o[e])throw new Error(this.t("config-param-required",{param:e}))}),this._configCache[r]=o,o}}for(const e in cn)dn.prototype[e]=cn[e];function pn(e){const t=new dn(e);return new Proxy(t,{get(e,t){if(t in e&&0!==t.indexOf("_")){if("function"==typeof e[t])return(r=e[t],function(){const e=r.apply(this,arguments);return f(e)?e.then(e=>(x.bind(this)(e),e)):(x.bind(this)(e),e)}).bind(e);if("context"!==t&&"config"!==t)return e[t]}var r}})}dn.prototype.createInstance=pn;var ln=pn();module.exports=ln; diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/node_modules/uni-config-center/index.js b/uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/node_modules/uni-config-center/index.js new file mode 100644 index 0000000..00ba62f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/uni-id/node_modules/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;t{let{serviceParam:t,middlewareService:n=[]}=e,i={code:403,msg:"access denied",filterStack:[]},{url:a}=t;for(let e in n){let r=n[e],{mode:o="onActionExecuting",enable:s=!0}=r;if(s&&"onActionExecuting"===o&&util_1.regExpTest(r.regExp,a)){t.filterResponse=i;let e=await r.main(t);if(e.filterId=r.id,i.filterStack.push(e),0!==e.code){i=e;break}i=Object.assign(i,e)}}return i},onActionExecuted=async(e={})=>{let{serviceParam:t,middlewareService:n=[],serviceRes:i}=e,{url:a}=t;for(let e in n){let r=n[e],{mode:o,enable:s=!0}=r;if(s&&"onActionExecuted"===o&&util_1.regExpTest(r.regExp,a)){let e=await r.main(t,i);if(e){if(0!==e.code){i=e;break}i=Object.assign(i,e)}}}return i},onActionIntercepted=async(e={})=>{let{serviceParam:t,middlewareService:n=[],filterResponse:i}=e,{url:a}=t;for(let e in n){let r=n[e],{mode:o,enable:s=!0}=r;if(s&&"onActionIntercepted"===o&&util_1.regExpTest(r.regExp,a)){let e=await r.main(t,i);if(e){if(0!==e.code){i=e;break}i=Object.assign(i,e)}}}return i},onActionError=async(e={})=>{let{serviceParam:t,middlewareService:n=[],serviceRes:i}=e,{url:a}=t;for(let e in n){let r=n[e],{mode:o,enable:s=!0}=r;if(s&&"onActionError"===o&&util_1.regExpTest(r.regExp,a)){let e=await r.main(t,i);if(e){if(0!==e.code){i=e;break}i=Object.assign(i,e)}}}return i},checkIsLogin={main:async e=>{let{url:t,data:n={},util:i}=e,{uniID:a}=i,{need_user_info:r}=n,o={code:-1,msg:""};void 0===r&&(r=-1==t.indexOf("."));let s=0==t.indexOf("admin/");s&&(r=!0),(t.indexOf("sys.")>-1||t.indexOf("sys_")>-1||t.indexOf("/sys")>-1)&&(r=!0);let u=t.indexOf("/sys/")>-1,l=await a.checkToken(e.uniIdToken,{needPermission:u,needUserInfo:r});if(l.code&&l.code>0)return l;if(l.userInfo){let e=l.userInfo;e.permission=l.permission,delete e.token,delete e.password,o.userInfo=e}if(o.uid=l.uid,l.token&&(o.token=l.token,o.tokenExpired=l.tokenExpired),s){if(!o.userInfo)return{code:403,msg:"need_user_info必须为true"};{let e=o.userInfo.role||[];if(!o.userInfo.allow_login_background&&!e.includes("admin"))return{code:403,msg:"您无权限登录后台"}}}return o.code=0,o.msg="ok",o}},checkSysAuth={main:async e=>{let{url:t,util:n}=e,{uniID:i,config:a,pubFun:r,vk:o,db:s,_:u}=n,l={code:-1,msg:""};const c=checkIsLogin;if(l=await c.main(e),0!==l.code)return l;if(!l.userInfo)return{code:403,msg:"请去除need_user_info:false"};if(l.userInfo.role||(l.userInfo.role=[]),l.userInfo.role.includes("admin"))return l;if(!l.userInfo.allow_login_background&&0==t.indexOf("admin/"))return{code:403,msg:"您无权限登录后台"};let d=[];if(l.userInfo.role.includes("admin-lv3")){let e=await listPermission({whereJson:{level:u.in([1,2,3])},justNeedID:!0},n);o.pubfn.isNotNull(e)&&(d=d.concat(e))}if(l.userInfo.role.includes("admin-lv2")){let e=await listPermission({whereJson:{level:u.in([1,2])},justNeedID:!0},n);o.pubfn.isNotNull(e)&&(d=d.concat(e))}if(l.userInfo.role.includes("admin-lv1")){let e=await listPermission({whereJson:{level:u.in([1])},justNeedID:!0},n);o.pubfn.isNotNull(e)&&(d=d.concat(e))}if(l.userInfo.role.includes("query-all")){let e=await listPermission({whereJson:{curd_category:4,level:u.neq(4)},justNeedID:!0},n);o.pubfn.isNotNull(e)&&(d=d.concat(e))}let p=await listRole({role:l.userInfo.role},n);for(let e in p){let{permission:t}=p[e];o.pubfn.isNotNull(t)&&(d=d.concat(t))}if(0==d.length)return{code:403,msg:"权限不足"};d=[...new Set(d)];let f=await listPermission({whereJson:{permission_id:u.in(d),match_mode:u.in([1,2])}},n),g=!1;for(let e=0;e0}async function listRole(e,t){let{vk:n,db:i,_:a}=t,{role:r}=e;return n.pubfn.isNull(r)?[]:(await n.baseDao.select({dbName:"uni-id-roles",whereJson:{role_id:a.in(r),enable:!0},fieldJson:{permission:!0}})).rows}var filterService=[{id:"pub",regExp:function(e=""){return"pub"===getType(e)},description:"pub函数为所有人都可以访问的函数",index:100,mode:"onActionExecuting",main:async function(e){let{url:t,data:n={},util:i}=e,{uniID:a}=i,r={};if(e.data.need_user_info)r=await checkIsLogin.main(e);else if(e.uniIdToken){let t=await a.checkToken(e.uniIdToken,{needPermission:!1,needUserInfo:!1});0===t.code&&(r.uid=t.uid)}return r.code=0,r.msg="ok",r}},{id:"kh",regExp:function(e=""){return"kh"===getType(e)},description:"kh函数为必须登录后才能访问的函数(客户端用户)",index:200,mode:"onActionExecuting",main:checkIsLogin.main},{id:"sys",regExp:function(e=""){return"sys"===getType(e)},description:"sys函数为后端管理人员才能访问的函数(商家后台工作人员)",index:300,mode:"onActionExecuting",main:checkSysAuth.main},{id:"access_denied",regExp:function(e=""){return"access denied"===getType(e)},description:"sys函数为后端管理人员才能访问的函数(商家后台工作人员)",index:100,mode:"onActionExecuting",main:function(){return{code:403,msg:"禁止访问私有函数!"}}}];function getType(e=""){let t="";return e.indexOf("/sys/")>-1?t="sys":e.indexOf("/kh/")>-1?t="kh":e.indexOf("/pub/")>-1&&(t="pub"),e.indexOf("/sys.")>-1||e.indexOf("/sys_")>-1||0===e.indexOf("sys.")||0===e.indexOf("sys_")?t="sys":e.indexOf("/kh.")>-1||e.indexOf("/kh_")>-1||0===e.indexOf("kh.")||0===e.indexOf("kh_")?t="kh":(e.indexOf("/pub.")>-1||e.indexOf("/pub_")>-1||0===e.indexOf("pub.")||0===e.indexOf("pub_"))&&(t="pub"),e.indexOf(".sys_")>-1?t="sys":e.indexOf(".kh_")>-1?t="kh":e.indexOf(".pub_")>-1&&(t="pub"),""==t&&e.indexOf(".")>-1&&(t="kh"),e.indexOf("._")>-1&&(t="access denied"),t}function getMiddleware(e){let t=[];if(e){let n=[...filterService,...e];n.sort((function(e,t){return e.index-t.index})),t=n.filter((e,t,i)=>{var a=[];return n.forEach((e,t)=>{a.push(e.id)}),a.indexOf(e.id)===t})}else t=filterService;return t}var getMiddleware_1=getMiddleware,filter={onActionExecuting:onActionExecuting,onActionExecuted:onActionExecuted,onActionIntercepted:onActionIntercepted,onActionError:onActionError,getMiddleware:getMiddleware_1},routerUtil={filterService:filter,getQueryStringParameters:function(e){let{event:t,vk:n}=e,i={};if(t.httpMethod){let{path:e=""}=t;if("/"===e[0]&&(e=e.substring(1)),e){let a,{urlrewrite:r={}}=n.getUnicloud(),{rule:o}=r,s=n.pubfn.getData(r,"config.accessOnlyInRule"),u=!1;if(o)for(let t in o){let i=o[t],r=n.pubfn.regExpExecToTemplate(e,t,i);if(r){u=!0;let t=r.split("?");e=t[0],a=n.pubfn.urlStringToJson(t[1]);break}}if(!u&&s)return{mpserverlessComposedResponse:!0,statusCode:403,code:403,headers:{"content-type":"application/json"},body:JSON.stringify({code:403,msg:"access denied"})};if(i={data:{}},n.pubfn.isNotNull(a)&&(i.data=Object.assign(i.data,a)),t.queryStringParameters){let e=t.queryStringParameters;"string"==typeof e&&(e=JSON.parse(e)),i.data=Object.assign(i.data,e)}if(t.body){let e=t.body,a=t.headers&&t.headers["content-type"]?t.headers["content-type"]:"";if(a.indexOf("multipart/form-data;")>-1)e=n.formDataUtil.formParser(t),i.data=Object.assign(i.data,e);else{t.isBase64Encoded&&(e=Buffer.from(e,"base64").toString("utf-8"));try{"string"==typeof e&&(e=JSON.parse(e)),i.data=Object.assign(i.data,e)}catch(e){}try{"string"==typeof e&&a.indexOf("x-www-form-urlencoded")>-1&&(e=n.pubfn.urlStringToJson(e),"object"==typeof e&&(e=n.pubfn.string2Number(e),i.data=Object.assign(i.data,e)))}catch(e){}}}i.$url||(i.data.$url?i.$url=i.data.$url:i.$url=e),i.data.uni_id_token&&(i.uni_id_token=i.data.uni_id_token,delete i.data.uni_id_token)}else{if(t.queryStringParameters){let e=t.queryStringParameters;"string"==typeof e.data&&(e.data=JSON.parse(e.data)),i=Object.assign(i,e)}if(t.body){let e=t.body;t.isBase64Encoded&&(e=Buffer.from(e,"base64").toString("utf-8"));try{"string"==typeof e&&(e=JSON.parse(e)),i=Object.assign(i,e)}catch(e){}}}try{let e=t.headers["uni-id-token"]||t.headers.uni_id_token;!i.uni_id_token&&e&&(i.uni_id_token=e)}catch(e){}}else i=JSON.parse(JSON.stringify(t));return i.data||(i.data={}),i.uniIdToken||(i.uniIdToken=i.uni_id_token),i.url=i.$url||"",i},returnError:returnError,filterInterception:async function({serviceParam:e,middlewareService:t,filterResponse:n}){try{n=await filter.onActionIntercepted({serviceParam:e,middlewareService:t,filterResponse:n})}catch(n){return await returnError({code:500,msg:`云函数 ${e.url} 的中间件 onActionIntercepted 运行异常!`,err:n,serviceParam:e,middlewareService:t})}return n},requireService:async function(e={}){let t,{vk:n,serviceParam:i}=e,{url:a,data:r,uniIdToken:o,util:s,filterResponse:u={},originalParam:l={}}=i;if(a.indexOf(".")>-1){let e,i=a.lastIndexOf("."),c=n.require("service/"+a.substring(0,i));if(t=n.pubfn.objectAssign({},c),!t.isCloudObject)throw new Error("msg:禁止访问私有对象内的函数!");let d=a.substring(i+1);if(0==d.indexOf("_"))throw new Error("msg:禁止访问私有函数!");if("function"!=typeof t[d]){try{l.event&&l.event.httpMethod&&l.event.path&&(a=l.event.path.substring(1))}catch(e){}throw{code:404,name:"cloudObject",message:`not found【${a}】`}}Object.assign(t,{vk:n,methodName:d,isCloudObject:!0,getClientInfo:function(){let{context:e={}}=l,t={...e,os:e.OS,appId:e.APPID,locale:e.LOCALE,clientIP:e.CLIENTIP,userAgent:e.CLIENTUA,platform:e.PLATFORM,deviceId:e.DEVICEID,source:e.SOURCE,uniIdToken:o,uid:u.uid,userInfo:u.userInfo,filterResponse:u,originalParam:l};return n.pubfn.objectKeySort(t)},getUserInfo:async function(){if(u.userInfo&&u.userInfo._id)return u.userInfo;if(!e&&u.uid){let t=await s.uniID.checkToken(o,{needUserInfo:!0});if(0!==t.code)throw new Error("msg:token失效:"+t.errMsg);t.userInfo&&t.userInfo._id&&(delete t.userInfo.token,delete t.userInfo.password,e=t.userInfo)}return e},getUtil:function(){return s},getMethodName:function(){return d},getParams:function(){return r},getCloudInfo:function(){let{SPACEINFO:e={},FUNCTION_NAME:t,FUNCTION_TYPE:n}=l.context||{},{provider:i,spaceId:a}=e;return{provider:i,spaceId:a,functionName:t,functionType:"cloudobject"}},getUniIdToken:function(){return o},getUniCloudRequestId:function(){return l.context.requestId},getHttpInfo:function(){return l.event}})}else t=n.require("service/"+a);return t},serviceRun:async function(e={}){let t,{serviceParam:n={},serviceMain:i}=e,{filterResponse:a}=n;if(a.uid&&(n.uid=a.uid),a.userInfo&&(n.userInfo=a.userInfo),i.isCloudObject){let{methodName:e="main"}=i;if("function"==typeof i._before){let e=await i._before();if("string"==typeof e)return{code:-1,msg:e};if("object"==typeof e&&0!==e.code)return{code:e.code,msg:e.msg};if("boolean"==typeof e&&!1===e)return{code:-1,msg:""}}if(t=await i[e](n.data),"function"==typeof i._after){let e=await i._after({res:t||{}});"object"==typeof e&&(t=e)}}else t=await i.main(n);return"object"==typeof t&&(void 0===t.vk_uni_token&&"object"==typeof a&&a.token&&void 0!==a.tokenExpired&&(t.vk_uni_token={token:a.token,tokenExpired:a.tokenExpired}),t=routerUtil.returnRes(t)),t},errorCatch:async function(e={}){let{err:t,type:n,serviceParam:i,middlewareService:a,serviceMain:r={}}=e,{url:o,originalParam:s={}}=i;t||(t={});let{code:u}=t,l=t.message||t.msg||t.errMsg||"";if("run"===n&&"function"==typeof r._after){let e=await r._after({err:t});if(e)return e}let c={code:500,msg:l,err:t,serviceParam:i,middlewareService:a};try{s.event&&s.event.httpMethod&&s.event.path&&(o=s.event.path.substring(1))}catch(t){}return"MODULE_NOT_FOUND"==u&&l.indexOf("service/")>-1||"ENOENT"==u&&l.indexOf("service")>-1||404==u&&["cloudFunction","cloudObject"].indexOf(t.name)>-1?(t.stack=`Error: not found【${o}】`,Object.assign(c,{code:404,msg:`not found【${o}】`})):"MODULE_NOT_FOUND"==u&&l.indexOf("Cannot find module")>-1?Object.assign(c,{code:500,msg:l}):"InternalServerError"==u&&l.indexOf("_id_ dup key")>-1?Object.assign(c,{code:500,msg:"vk.baseDao.add : _id不能重复添加"}):0===l.indexOf("Cannot read property 'mp-weixin' of undefined")?Object.assign(c,{code:501,msg:"请先绑定微信"}):l.indexOf("Response timeout for 10000ms")>-1?Object.assign(c,{code:502,msg:"timeout 请求超时,请重试!"}):l.indexOf("msg:token失效")>-1?Object.assign(c,{code:30202,errMsg:l,msg:l}):l.indexOf("msg:禁止访问私有对象内的函数")>-1||l.indexOf("msg:禁止访问私有函数")>-1?Object.assign(c,{code:403,msg:l.substring(4)}):0===l.indexOf("msg:")?Object.assign(c,{code:501,msg:l.substring(4)}):"ReferenceError"===t.name?Object.assign(c,{code:501,msg:`云函数 ${o} 变量引用错误:${l}`}):"TypeError"===t.name?Object.assign(c,{code:501,msg:`云函数 ${o} 运行异常,类型错误:${l}`}):"InternalServerError"==u?Object.assign(c,{code:"InternalServerError",msg:"内部错误"}):"Error"===t.name?Object.assign(c,{code:t.code,msg:l}):t.stack?Object.assign(c,{code:500,msg:"require"==n?`云函数 ${o} 编译异常!`:`云函数 ${o} 运行异常!`}):"string"==typeof t?Object.assign(c,{code:-1,msg:t}):Object.assign(c,t),await returnError(c)},returnRes:function(e={}){return"object"==typeof e&&(void 0!==e.code||void 0!==e.errCode&&(e.code=e.errCode,e.msg=e.errMsg)),e}},routerUtil_1=routerUtil;async function returnError(e={}){let{code:t,msg:n,err:i,serviceParam:a,middlewareService:r}=e;console.error(n);let o={code:t,msg:n};i&&(i.stack?(console.error(i.stack),o.err={message:i.message,stack:i.stack,code:i.code}):o.err=i);try{o.requestId=a.originalParam.context.requestId}catch(i){}let s=await filter.onActionError({serviceParam:a,middlewareService:r,serviceRes:o});return routerUtil.returnRes(s)}try{process.env.TZ="Asia/Shanghai"}catch(e){}async function main(e){let{event:t,context:n,vk:i}=e;!i&&this&&(i=this);let{config:a,uniID:r,uniPay:o,db:s,middlewareService:u,pubFun:l,customUtil:c,crypto:d}=i.getUnicloud();if(i.pubfn.getData(a,"vk.system.serviceShutdown"))return routerUtil_1.returnRes({code:405,msg:i.pubfn.getData(a,"vk.system.serviceShutdownDescription")});if(["h5","web"].indexOf(n.PLATFORM)>-1){let e=i.pubfn.getUniIdConfig(a,"preferedWebPlatform","h5");n.PLATFORM=e}else if(["app-plus","app"].indexOf(n.PLATFORM)>-1){let e=i.pubfn.getUniIdConfig(a,"preferedAppPlatform","app-plus");n.PLATFORM=e}let p={event:t,context:n},f=routerUtil_1.getQueryStringParameters(e),{url:g,data:m,uniIdToken:b}=f;if([403].indexOf(f.code)>-1)return routerUtil_1.returnRes(f);if(g&&"function"==typeof g.trim&&(g=g.trim()),m){m.vk_appId&&(n.APPID=m.vk_appId),m.vk_appid&&(n.APPID=m.vk_appid),m.vk_platform&&(n.PLATFORM=m.vk_platform),m.vk_locale&&(n.LOCALE=m.vk_locale);let e={};if("object"==typeof t.headers&&(t.headers["vk-appId"]&&(e.appId=t.headers["vk-appId"]),t.headers["vk-appid"]&&(e.appid=t.headers["vk-appid"]),t.headers["vk-platform"]&&(e.platform=t.headers["vk-platform"]),t.headers["vk-locale"]&&(e.locale=t.headers["vk-locale"]),t.headers["vk-device-id"]&&(e.deviceId=t.headers["vk-device-id"]),t.headers["vk-client-ip"]&&(e.clientIP=t.headers["vk-client-ip"]),t.headers["vk-os"]&&(e.os=t.headers["vk-os"])),"object"==typeof m.vk_context&&(e=i.pubfn.objectAssign(e,m.vk_context),delete m.vk_context),"object"==typeof e&&i.pubfn.isNotNull(e)&&(e.appId&&(n.APPID=e.appId),e.appid&&(n.APPID=e.appid),e.platform&&(n.PLATFORM=e.platform),e.locale&&(n.LOCALE=e.locale),e.clientIP&&!n.CLIENTIP&&(n.CLIENTIP=e.clientIP),e.os&&(n.OS=e.os),e.deviceId&&(n.DEVICEID=e.deviceId),"function"===n.SOURCE&&(e.clientIP&&(n.CLIENTIP=e.clientIP),e.userAgent&&(n.CLIENTUA=e.userAgent))),i.pubfn.isNullOne(n.APPID,n.PLATFORM)){let e=i.pubfn.getData(a,"vk.context");i.pubfn.isNotNull(e)&&(n.APPID||(n.APPID=e.APPID),n.PLATFORM||(n.PLATFORM=e.PLATFORM),n.LOCALE||(n.LOCALE=e.LOCALE),n.CLIENTIP||(n.CLIENTIP=e.CLIENTIP))}}const h=r.createInstance({context:n});s.command.$=s.command.aggregate;let y={vk:i,config:a,pubFun:l,uniID:h,uniPay:o,db:s,_:s.command,$:s.command.aggregate,customUtil:c,crypto:d,env:{APPID:n.APPID,CLIENTIP:n.CLIENTIP,DEVICEID:n.DEVICEID,LOCALE:n.LOCALE,OS:n.OS,PLATFORM:n.PLATFORM,CLIENTUA:n.CLIENTUA}};try{uniCloud.vk=i,uniCloud.env=y.env,uniCloud.context=n}catch(e){}let w={url:g,data:m,uniIdToken:b,util:y,originalParam:p};const _=routerUtil_1.filterService.getMiddleware(u);try{let e=await routerUtil_1.filterService.onActionExecuting({serviceParam:w,middlewareService:_});if(0!==e.code)return routerUtil_1.returnRes(await routerUtil_1.filterInterception({serviceParam:w,middlewareService:_,filterResponse:e}));delete m.uid,e.uid&&(m.uid=e.uid),w.filterResponse=e}catch(e){return await routerUtil_1.returnError({code:500,msg:`云函数 ${g} 的中间件 onActionExecuting 运行异常!`,err:e,serviceParam:w,middlewareService:_})}let k,v;try{k=await routerUtil_1.requireService({vk:i,serviceParam:w})}catch(e){return await routerUtil_1.errorCatch({err:e,type:"require",serviceParam:w,middlewareService:_})}try{v=await routerUtil_1.serviceRun({serviceParam:w,serviceMain:k})}catch(e){return await routerUtil_1.errorCatch({err:e,type:"run",serviceParam:w,middlewareService:_,serviceMain:k})}try{v=await routerUtil_1.filterService.onActionExecuted({serviceParam:w,middlewareService:_,serviceRes:v})}catch(e){return await routerUtil_1.returnError({code:500,msg:`云函数 ${g} 的中间件 onActionExecuted 运行异常!`,err:e,serviceParam:w,middlewareService:_})}return routerUtil_1.returnRes(v)}var router=main,md5=function(e){return crypto$1.createHash("md5").update(e).digest("hex")},util$1={},baseDao={init:function(e){util$1=e},add:async function(e){let{db:t,_:n,vk:i,config:a}=util$1,{dbName:r,dataJson:o,db:s,cancelAddTime:u,cancelAddTimeStr:l}=e;if(i.pubfn.isNull(r))throw new Error("vk.baseDao.add 中 dbName 不能为空");if(i.pubfn.isNull(o))throw new Error("vk.baseDao.add 中 dataJson 不能为空");let c=s||t;if(!o._add_time){let e=i.pubfn.getData(a,"vk.db.unicloud.cancelAddTime");void 0===u&&e&&(u=e);let t=i.pubfn.getData(a,"vk.db.unicloud.cancelAddTimeStr");if(void 0===l&&t&&(l=t),!u){let e=new Date;o._add_time=e.getTime(),l||(o._add_time_str=i.pubfn.timeFormat(e,"yyyy-MM-dd hh:mm:ss"))}}let d=await c.collection(r).add(o);return d.id?d.id:null},adds:async function(e){let{db:t,_:n,vk:i,config:a}=util$1,{dbName:r,dataJson:o,db:s,cancelAddTime:u,cancelAddTimeStr:l}=e;if(i.pubfn.isNull(r))throw new Error("vk.baseDao.adds 中 dbName 不能为空");if(i.pubfn.isNull(o))throw new Error("vk.baseDao.adds 中 dataJson 不能为空");if("[object Array]"!==Object.prototype.toString.call(o))throw new Error("vk.baseDao.adds 中 dataJson 必须是数组对象");let c=s||t,d=i.pubfn.getData(a,"vk.db.unicloud.cancelAddTime");void 0===u&&d&&(u=d);let p=i.pubfn.getData(a,"vk.db.unicloud.cancelAddTimeStr");if(void 0===l&&p&&(l=p),!u){let e=new Date,t=e.getTime(),n=i.pubfn.timeFormat(e,"yyyy-MM-dd hh:mm:ss");for(let e in o)o[e]._add_time||(o[e]._add_time=t,l||(o[e]._add_time_str=n))}let f=await c.collection(r).add(o);return f.ids?f.ids:f.id?f.id:null},del:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r,db:o}=e,s=o||n,u=0;if(t.pubfn.isNotNull(r)){let e=await s.collection(a).where(r).remove();e?u=e.deleted:(console.error(e.errMsg),u=-1)}else console.error("whereJson条件不能为空");return u},delete:async function(e){return await baseDao.del(e)},remove:async function(e){return await baseDao.del(e)},deleteById:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,id:r,db:o}=e,s=o||n,u=0;if(t.pubfn.isNull(r))throw new Error("deleteById的id不能为空,且必须是字符串");let l=await s.collection(a).doc(r).remove();return l?u=l.deleted:(console.error(l.errMsg),u=0),u},update:async function(e){let t,{vk:n,db:i,_:a}=util$1,{dbName:r,whereJson:o,dataJson:s,db:u}=e,l=u||i,c=0;if(n.pubfn.isNull(o))throw new Error("update的whereJson不能为空,且必须是对象形式");if(n.pubfn.isNull(s))throw new Error("update的dataJson不能为空,且必须是对象形式");return s._id&&delete s._id,t=void 0===o?await l.collection(r).update(s):await l.collection(r).where(o).update(s),t?c=t.updated:console.error(t.errMsg),c},updateById:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,id:r,dataJson:o,getUpdateData:s,db:u}=e,l=u||n,c=0;if(t.pubfn.isNull(r))throw new Error("updateById的id不能为空,且必须是字符串");if(t.pubfn.isNull(o))throw new Error("updateById的dataJson不能为空,且必须是对象形式");o._id===r&&delete o._id;let d=await l.collection(a).doc(r).update(o);return s?d?await baseDao.findById({db:l,dbName:a,id:r}):null:(d?c=d.updated:(console.error(d.errMsg),c=0),c)},updateAndReturn:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,id:r,whereJson:o,dataJson:s,db:u}=e,l=u||n;if(t.pubfn.isNullAll(r,o))throw new Error("updateAndReturn的id和whereJson两者不能都为空");if(t.pubfn.isNull(s))throw new Error("updateAndReturn的dataJson不能为空,且必须是对象形式");if(s._id&&delete s._id,t.pubfn.isNotNull(r)){return(await l.collection(a).doc(r).updateAndReturn(s)).doc}if(t.pubfn.isNotNull(o)){return(await l.collection(a).where(o).updateAndReturn(s)).doc}throw new Error("updateAndReturn的id和whereJson两者不能都为空")},setById:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,id:r,dataJson:o,db:s}=e,u=s||n;if(t.pubfn.isNull(o))throw new Error("setById的dataJson不能为空,且必须是对象形式");if(t.pubfn.isNullAll(r,o._id))throw new Error("id或dataJson._id不能均为空");if(t.pubfn.isNotNullAll(r,o._id)&&r!==o._id)throw new Error("id和dataJson._id必须一致");t.pubfn.isNotNull(o._id)&&(r=o._id,delete o._id);let l=await u.collection(a).doc(r).set(o);return l.updated>0?l.type="update":(l.type="add",l.id=l.upsertedId),l},select:async function(e={}){let{vk:t,db:n,_:i}=util$1;"string"==typeof e.pageIndex&&(e.pageIndex=parseInt(e.pageIndex)),"string"==typeof e.pageSize&&(e.pageSize=parseInt(e.pageSize));let{dbName:a,whereJson:r,pageSize:o=10,getOne:s=!1,getMain:u=!1}=e;if(o<=0&&(o=999999999),o>500)return await baseDao.selectAll(e);let l=await baseDao.getSelectData(e),{result:c,hasMore:d,total:p,getCount:f,pageIndex:g,fieldJson:m}=l;return c=c.skip((g-1)*o).limit(o),t.pubfn.isNotNull(m)&&(c=c.field(m)),c.get().then(e=>{let t={};return f?(t.total=p,t.hasMore=d):(t.total=e.data?e.data.length:0,t.hasMore=t.total>=o),t.rows=e.data,t.code=0,t.msg="查询成功",t.pagination={pageIndex:g,pageSize:o},s&&(t.rows=t.rows[0]),u?t.rows:t})},findById:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,id:r,fieldJson:o,db:s}=e,u=(s||n).collection(a).doc(r);o&&(u=u.field(o));let l=await u.get();return"[object Array]"===Object.prototype.toString.call(l.data)?l.data[0]:l.data},findByWhereJson:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r,fieldJson:o,sortArr:s,db:u}=e,l=u||n;if(t.pubfn.isNotNull(r)){let e=l.collection(a).where(r);if(s)for(let t in s){let n=s[t],i=n.name,a=n.type;null!=a&&""!=a||(a="asc"),e=e.orderBy(i,a)}o&&(e=e.field(o));let t=await e.limit(1).get();if(t.data&&t.data.length>0)return t.data[0]}else console.error("whereJson条件不能为空");return null},count:async function(e){let t,{vk:n,db:i,_:a}=util$1,{dbName:r,whereJson:o,foreignDB:s,foreignKey:u,groupJson:l,lastWhereJson:c,db:d}=e,p=d||i;if(n.pubfn.isNotNull(s)||n.pubfn.isNotNull(l)){let e=p.collection(r).aggregate();return n.pubfn.isNotNull(o)&&e.match(o),n.pubfn.isNotNull(l)&&e.group(l),n.pubfn.isNotNull(s)&&(e=baseDao.addForeignDB({foreignDB:s,foreignKey:u,result:e})),n.pubfn.isNotNull(c)&&(e=e.match(c)),e=await e.count("total").end(),e.data[0]?e.data[0].total:0}return t=n.pubfn.isNotNull(o)?await p.collection(r).where(o).count():await p.collection(r).count(),t.total},getSelectData:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r,pageIndex:o=1,pageSize:s=10,getCount:u=!1,db:l}=e;s<0&&(o=1,s=999999999,u=!0);let c=l||n,d=e.sortArr,p=e.fieldJson,f=0,g=!1;if(u){let e;e=t.pubfn.isNotNull(r)?await c.collection(a).where(r).count():await c.collection(a).count(),f=e.total,o1e3&&(u=1e3));let l=await baseDao.getSelectData(e),{result:c,hasMore:d,total:p,getCount:f,pageIndex:g,pageSize:m,fieldJson:b}=l;m>0&&!p&&!f&&(p=m),i.pubfn.isNotNull(b)&&(c=c.field(b));let h={};if(f&&0===p)h={data:[]};else{let t=p;mr&&(n=r-t);let o=c.skip(t).limit(n).get();i.push(o)}try{h=(await Promise.all(i)).reduce((e,t)=>({data:e.data.concat(t.data),errMsg:e.errMsg}))}catch(t){throw console.error("vk.baseDao.select-异常",e,t),new Error("msg:vk.baseDao.select-异常")}}let y={};return y.total=f?p:h.data?h.data.length:0,y.hasMore=d,y.rows=h.data,y.code=0,y.msg="查询成功",y.pagination={pageIndex:g,pageSize:m},o&&(y.rows=y.rows[0]),s?y.rows:y},sum:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,fieldName:r,whereJson:o,db:s}=e,u=s||n;const l=u.command.aggregate;let c=u.collection(a).aggregate();t.pubfn.isNotNull(o)&&c.match(o),c.group({_id:null,num:l.sum("$"+r)});let d=await c.end();return d.data&&d.data[0]?d.data[0].num:0},avg:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,fieldName:r,whereJson:o,db:s}=e,u=s||n;const l=u.command.aggregate;let c=u.collection(a).aggregate();t.pubfn.isNotNull(o)&&c.match(o),c.group({_id:null,num:l.avg("$"+r)});let d=await c.end();return d.data&&d.data[0]?d.data[0].num:null},max:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,fieldName:r,whereJson:o,db:s}=e,u=s||n;const l=u.command.aggregate;let c=u.collection(a).aggregate();t.pubfn.isNotNull(o)&&c.match(o),c.group({_id:null,num:l.max("$"+r)});let d=await c.end();return d.data&&d.data[0]?d.data[0].num:null},min:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,fieldName:r,whereJson:o,db:s}=e,u=s||n;const l=u.command.aggregate;let c=u.collection(a).aggregate();t.pubfn.isNotNull(o)&&c.match(o),c.group({_id:null,num:l.min("$"+r)});let d=await c.end();return d.data&&d.data[0]?d.data[0].num:null},sample:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r,size:o,fieldJson:s,db:u}=e,l=u||n;l.command.aggregate;let c=l.collection(a).aggregate();return t.pubfn.isNotNull(r)&&c.match(r),c.sample({size:o}).limit(o),t.pubfn.isNotNull(s)&&c.project(s),(await c.end()).data},selects:async function(e={}){let{vk:t,db:n,_:i}=util$1;if(t.pubfn.isNotNull(e.treeProps))return await baseDao.tree(e);"string"==typeof e.pageIndex&&(e.pageIndex=parseInt(e.pageIndex)),"string"==typeof e.pageSize&&(e.pageSize=parseInt(e.pageSize));let{db:a,dbName:r,foreignKey:o="_id",pageIndex:s=1,pageSize:u=10,getCount:l=!1,getOne:c=!1,getMain:d=!1,whereJson:p={},unwindJson:f,groupJson:g,sortArr:m=[],foreignDB:b=[],lastWhereJson:h,lastSortArr:y=[],fieldJson:w={},addFields:_}=e,k=a||n;-1==u&&(s=1,u=999999999,l=!1),c&&(u=1,l=!1);let v,x=0,N=!1;if(t.pubfn.isNotNull(p))for(let e in p)p[e]&&"object"==typeof p[e]&&"geoNear"===p[e].operator&&(v=t.pubfn.copyObject(p[e]),v.keyName=e,v.limit=s*u,delete p[e]);if(l){if(t.pubfn.isNullAll(g,f,h)){let e;e=t.pubfn.isNotNull(p)?await k.collection(r).where(p).count():await k.collection(r).count(),x=e.total}else{let e=k.collection(r).aggregate();t.pubfn.isNotNull(p)&&(t.pubfn.isNotNull(v)?e=baseDao.getGeoNearJson({runDB:k,result:e,geoNearJson:v,whereJson:p}):e.match(p)),t.pubfn.isNotNull(f)&&(e=baseDao.getTnwind({result:e,unwindJson:f})),t.pubfn.isNotNull(g)&&e.group(g),t.pubfn.isNotNull(h)&&(t.pubfn.isNotNull(b)&&(e=baseDao.addForeignDB({foreignDB:b,foreignKey:o,result:e})),e.match(h)),e=await e.count("total").end(),x=e.data[0]?e.data[0].total:0}s=u),$.rows=O,$.code=0,$.msg="查询成功",$.pagination={pageIndex:s,pageSize:u},c&&($.rows=$.rows[0]),d?$.rows:$},listToObjectByLimit1:function(e){let{vk:t,db:n,_:i}=util$1,{list:a,foreignDB:r}=e;if(t.pubfn.isNotNull(r))for(let e in a)for(let n in r){let{as:i,limit:o,foreignDB:s,dbName:u}=r[n];i||(i=u),t.pubfn.isNotNull(s)&&(a[e][i]=baseDao.listToObjectByLimit1({list:a[e][i],foreignDB:s})),1===o&&(t.pubfn.isArray(a[e][i])?a[e][i]&&a[e][i].length>0?a[e][i]=a[e][i][0]:a[e][i]={}:void 0===a[e][i]&&(a[e][i]={}))}return a},addForeignDB:function(e){let{vk:t,db:n,_:i}=util$1,{foreignDB:a,foreignKey:r,result:o}=e;const s=i.aggregate;for(let e in a){let n,{dbName:u,foreignKey:l,localKey:c,localKeyType:d="",foreignKeyType:p="",as:f,limit:g,getOne:m,whereJson:b,fieldJson:h,sortArr:y,foreignDB:w,addFields:_}=a[e];f||(f=u),n=t.pubfn.isNotNull(c)?c:"object"==typeof r?r[e]:r;let k,v="string"==typeof n?"$"+n:n,x="string"==typeof l?"$"+l:l,N="$$foreignKey"+baseDao.getForeignKeyName(n),$="foreignKey"+baseDao.getForeignKeyName(n);k="array"===d.toLowerCase()?[s.cond({if:s.isArray(N),then:s.in([x,N]),else:s.eq([x,N])})]:"array"===p.toLowerCase()?[s.cond({if:s.isArray(x),then:s.in([N,x]),else:s.eq([x,N])})]:[s.eq([x,N])];let D=s.pipeline().match(i.expr(s.and(k)));if(t.pubfn.isNotNull(b)&&(D=D.match(b)),t.pubfn.isNotNull(y)){let e={};for(let t in y){let n=y[t],i=n.name,a=n.type;a=null==a||""==a||"asc"==a?1:-1,e[i]=a}D=D.sort(e)}g&&(D=D.limit(g)),t.pubfn.isNotNull(w)&&(D=baseDao.addForeignDB({foreignDB:w,result:D})),t.pubfn.isNotNull(h)&&(h=baseDao.foreignDBToProject({fieldJson:h,foreignDB:w}),D=D.project(h)),t.pubfn.isNotNull(_)&&(D=D.addFields(_)),D=D.done();let T={};T[$]=v;let O={from:u,let:T,pipeline:D,as:f};o=o.lookup(O),(1===g&&!1!==m||!0===m)&&(o=o.unwind({path:"$"+f,preserveNullAndEmptyArrays:!0}))}return o},getForeignKeyName:function(e){return"string"==typeof e?e.replace(new RegExp("\\.","g"),"__"):"__vk__foreignKey1"},addWhereJson:function(e,t={},n="whereJson"){let{vk:i,db:a,_:r}=util$1,{formData:o,columns:s}=e;for(let e in s){let a,u=s[e],{key:l,mode:c,defaultValue:d,type:p="",lastWhereJson:f,auxiliary:g=!0,trim:m=!0,isNumber:b=!1}=u;if("lastWhereJson"===n&&!f)continue;if("lastWhereJson"!==n&&f)continue;let h=l;if(i.pubfn.isNotNull(u.fieldName)&&(h=u.fieldName),a=i.pubfn.isNotNull(u.value)?u.value:o[l],i.pubfn.isNull(a)&&i.pubfn.isNotNull(d)&&(a=d),i.pubfn.isNull(c)&&(c=["address","province","city","area"].indexOf(p)>-1?"address":"[object Array]"===Object.prototype.toString.call(a)&&a.length>=2?"[]":"="),i.pubfn.isNotNull(a))if("string"==typeof a&&m&&"function"==typeof a.trim&&(a=a.trim()),b&&!isNaN(a)&&(a=Number(a)),"custom"===c);else if("%%"===c)try{t[h]=new RegExp(a)}catch(e){}else if("%*"===c)try{t[h]=new RegExp("^"+a)}catch(e){}else if("*%"===c)try{t[h]=new RegExp(a+"$")}catch(e){}else if(">"===c)t[h]=t[h]?t[h].gt(a):r.gt(a);else if(">="===c)t[h]=t[h]?t[h].gte(a):r.gte(a);else if("<"===c)t[h]=t[h]?t[h].lt(a):r.lt(a);else if("<="===c)t[h]=t[h]?t[h].lte(a):r.lte(a);else if("in"===c)t[h]=r.in(a);else if("nin"===c)t[h]=r.nin(a);else if("!="===c)t[h]=r.neq(a);else if("[]"===c)t[h]=r.gte(a[0]).lte(a[1]);else if("[)"===c)t[h]=r.gte(a[0]).lt(a[1]);else if("(]"===c)t[h]=r.gt(a[0]).lte(a[1]);else if("()"===c)t[h]=r.gt(a[0]).lt(a[1]);else if("address"===c){let e={};a.province&&a.province.code&&(e["province.code"]=a.province.code),a.city&&a.city.code&&(e["city.code"]=a.city.code),a.area&&a.area.code&&(e["area.code"]=a.area.code),t[h]=e}else t[h]=g?"___empty-array___"===a?[]:"___empty-object___"===a?{}:"___non-existent___"===a?r.exists(!1):"___existent___"===a?r.exists(!0):a:a}return t},addLastWhereJson:function(e,t={}){return baseDao.addWhereJson(e,t,"lastWhereJson")},getTableData:async function(e){let{vk:t,db:n,_:i,config:a}=util$1,{db:r,dbName:o,data:s={},getCount:u=!0,getMain:l,whereJson:c,unwindJson:d,fieldJson:p,sortArr:f,treeProps:g,groupJson:m,foreignKey:b,foreignDB:h,lastWhereJson:y,lastSortArr:w,addFields:_}=e,{pageIndex:k,pageSize:v,pagination:x,sortRule:N,lastSortRule:$,formData:D,columns:T}=s;x&&(k=x.pageIndex,v=x.pageSize);let O,A={},I={},S=[],E={};if(t.pubfn.isNotNull(f))S=f;else{let e=t.pubfn.getData(a,"vk.db.unicloud.getTableData.sortArr");t.pubfn.isNotNull(e)?S=e:S.push({name:"_id",type:"desc"})}if(t.pubfn.isNotNull(N)&&(S=N),t.pubfn.isNotNull($)&&(w=$),I=baseDao.addWhereJson(s),E=baseDao.addLastWhereJson(s),t.pubfn.isNotNull(c)&&(c.operator&&c.operands&&["or","and"].indexOf(c.operator)>-1?I=i.and([I,c]):t.pubfn.objectAssign(I,c)),t.pubfn.isNotNull(p)&&t.pubfn.objectAssign(A,p),t.pubfn.isNotNull(y)&&t.pubfn.objectAssign(E,y),t.pubfn.isNotNull(I))for(let e in I)"object"==typeof I[e]&&I[e]&&"geoNear"===I[e].operator&&(O=!0);return t.pubfn.isNullAll(h,m,g,d,O)?await t.baseDao.select({db:r,dbName:o,getMain:l,getCount:u,pageIndex:k,pageSize:v,fieldJson:A,whereJson:I,sortArr:S}):await t.baseDao.selects({db:r,dbName:o,foreignKey:b,getMain:l,getCount:u,pageIndex:k,pageSize:v,whereJson:I,unwindJson:d,fieldJson:A,sortArr:S,treeProps:g,groupJson:m,foreignDB:h,lastWhereJson:E,lastSortArr:w,addFields:_})},startTransaction:async function(e){let{vk:t,db:n,_:i}=util$1;return await n.startTransaction()},rollbackTransaction:async function(e){let{db:t,msg:n="【异常】操作失败",tips:i="事务已回滚。",err:a={},code:r=-1}=e;console.error("transaction error",a);let o={code:r,msg:n,tips:i};await t.rollback();let s={message:a.message,stack:a.stack};try{s.body=JSON.parse(a.message),"object"==typeof s.body&&void 0!==s.body.code&&(s.body.msg,1)&&(o.msg=s.body.msg)}catch(e){}return console.error("transaction errJson",s),o.err=s,o},group:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r,groupJson:o,sortArr:s,pageIndex:u=1,pageSize:l=10,getCount:c=!1,lookupJson:d,db:p}=e,f=p||n;l<=0&&(l=999999999);i.aggregate;let g,m=f.collection(a).aggregate();if(t.pubfn.isNotNull(r)&&(m=m.match(r)),t.pubfn.isNotNull(o)&&(m=m.group(o)),t.pubfn.isNotNull(s)){let e={};for(let t in s){let n=s[t],i=n.name,a=n.type;a=null==a||""==a||"asc"==a?1:-1,e[i]=a}m=m.sort(e)}m=m.skip((u-1)*l).limit(l),t.pubfn.isNotNull(d)&&(g=d.returnObject,delete d.returnObject,m=m.lookup(d)),m=await m.end();let b,h=m.data;if(g)for(let e in h)h[e][d.as]=h[e][d.as][0];let y=!1;if(c){let e=f.collection(a).aggregate();t.pubfn.isNotNull(r)&&(e=e.match(r)),t.pubfn.isNotNull(o)&&(e=e.group(o));let n=await e.count("total").end();b=n.data[0]?n.data[0].total:0,u=l;return{hasMore:y,total:b,rows:h,code:0,key:1,pageIndex:u,pageSize:l}},tree:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r={},pageIndex:o=1,pageSize:s=10,getCount:u=!1,sortArr:l=[],fieldJson:c={},lastWhereJson:d,treeProps:p={}}=e;e.foreignDB||(e.foreignDB=[]);let{id:f="_id",parent_id:g="parent_id",children:m="children",level:b=10,limit:h=500}=p;if(b<1||b>20)throw new Error("msg:treeProps.level的范围必须在[1,20]");delete e.treeProps,e.whereJson||(e.whereJson={[g]:null}),e.foreignDB.unshift({dbName:a,localKey:f,foreignKey:g,as:m,limit:h,whereJson:p.whereJson,fieldJson:p.fieldJson||e.fieldJson,sortArr:p.sortArr,foreignDB:t.pubfn.copyObject(e.foreignDB)});let y=t.pubfn.copyObject(e.foreignDB);for(let n=1;n{"[object object]"===Object.prototype.toString.call(e.content)&&(e.content=JSON.stringify(e.content)),void 0===e.dataType&&(e.dataType="json"),"default"!=e.dataType&&""!==e.dataType||delete e.dataType,e.useContent&&(e.content=JSON.stringify(e.data)),e.method||(e.method="POST"),e.method=e.method.toUpperCase(),void 0===e.headers&&void 0!==e.header&&(e.headers=e.header);let t=await uniCloud.httpclient.request(e.url,e);return!e.needOriginalRes&&t&&t.data?t.data:t};var vk_request=request;const callFunction=async(e={})=>{let{name:t,url:n,data:i={},uniIdToken:a,clientInfo:r={},event:o={},uniCloud:s}=e;if(o&&o.originalParam&&o.originalParam.context){let e=o.originalParam.context;a=o.uniIdToken,r={...e,appId:e.APPID,platform:e.PLATFORM,locale:e.LOCALE,clientIP:e.CLIENTIP,os:e.OS,userAgent:e.CLIENTUA,deviceId:e.DEVICEID,uniIdToken:a}}let u,l=s||uniCloud;u=l.$context&&l.$context.FUNCTION_NAME?l.$context.FUNCTION_NAME:l.$options&&l.$options.context&&l.$options.context.FUNCTION_NAME?l.$options.context.FUNCTION_NAME:"router",a||r.uniIdToken&&(a=r.uniIdToken);let c={...i,vk_context:{appId:r.appId,platform:r.platform,locale:r.locale,clientIP:r.clientIP,os:r.os,userAgent:r.userAgent,deviceId:r.deviceId}};t||(t=u);let d=await l.callFunction({name:t,data:{$url:n,uniIdToken:a,data:c}});return d&&d.result};var vk_callFunction=callFunction,util$2={formValidateItem:function(e,t,n){let i={code:0,msg:"ok"},a=getData(e,t);void 0===a&&(a=e[t]);for(let e in n){let r=n[e];if(void 0===a&&r.required){i={type:"undefined",code:-1,msg:"字段:"+t+" 名称错误,请检查!",key:t,value:a};break}if(r.required&&(null==a||null==a||""===a||0==a.length)){i={type:"required",code:-1,msg:r.message,key:t,value:a};break}if(r.type&&void 0!==a){if(Object.prototype.toString.call(a).toLowerCase().toLowerCase()!==`[object ${r.type}]`.toLowerCase()){i={type:"type",code:-1,msg:r.message,key:t,value:a};break}}if(r.len&&a.length!=r.len){i={type:"len",code:-1,msg:r.message,key:t,value:a};break}if(r.min&&isNotNull(a))if("number"==r.type){if(ar.max){i={type:"max",code:-1,msg:r.message,key:t,value:a};break}}else if(a.length>r.max){i={type:"max",code:-1,msg:r.message,key:t,value:a};break}if("function"==typeof r.validator){let e,n,o=0,s=r.validator(r,a,(function(e){return n||(n=e),e}));if(n||(n=s),void 0!==n&&!0!==n&&(o=-1,"object"==typeof n?e||(e=n.message||n.msg,n.code&&(o=n.code)):"string"==typeof n&&(e||(e=n))),o){i={type:"validator",code:o,msg:e||r.message,key:t,value:a};break}}}return i}},formValidate=function(e={}){let t={code:0,msg:"ok"},{data:n,rules:i}=e;if(i)for(let e in i){let a=i[e];if(t=util$2.formValidateItem(n,e,a),0!=t.code)break}return t};function isNotNull(e){return-1===[void 0,null,""].indexOf(e)}function getData(e,t,n){let i=JSON.parse(JSON.stringify(e));t=t.replace(/\s+/g,"")+".";let a="";for(let e=0;e0&&(n=util$3.treeToArrayFn(l[o],t,n,l[a])),s&&delete l[o]}return n},util$3.arrayToTree=function(e,t){let n=deepClone(e),{id:i="_id",parent_id:a="parent_id",children:r="children",deleteParentId:o=!1,need_field:s}=t,u=[],l={};for(let e=0;e=10&&(e=Number(e)),"number"==typeof e)10==e.toString().length&&(e*=1e3),n=new Date(e);else if("object"==typeof e)n=new Date(e.getTime());else if("string"==typeof e){let i=t=util$4.getTargetTimezone(t),a=t>=0?"+":"";t>=0&&t<10?i="0"+t:t<0&&t>-10&&(i="-0"+-1*t);let r,o=e.split(" "),s=o[0]||"",u=o[1]||"";r=s.indexOf("-")>-1?s.split("-"):s.split("/");let l=u.split(":"),c={year:Number(r[0]),month:Number(r[1])||1,day:Number(r[2])||1,hour:Number(l[0])||0,minute:Number(l[1])||0,second:Number(l[2])||0};for(let e in c)c[e]>=0&&c[e]<10&&(c[e]="0"+c[e]);let d=`${c.year}-${c.month}-${c.day}T${c.hour}:${c.minute}:${c.second}${a}${i}:00`;n=new Date(d)}return n},getTimeByTimeZone:function(e,t){let n=util$4.getDateObject(e);t=util$4.getTargetTimezone(t);let i=60*n.getTimezoneOffset()*1e3+60*t*60*1e3,a=n.getTime()+i;return n=new Date(a),n},timeFormat:function(e,t="yyyy-MM-dd hh:mm:ss",n){try{if(!e)return"";n=util$4.getTargetTimezone(n);let i=util$4.getTimeByTimeZone(e,n),a={"M+":i.getMonth()+1,"d+":i.getDate(),"h+":i.getHours(),"m+":i.getMinutes(),"s+":i.getSeconds(),"q+":Math.floor((i.getMonth()+3)/3),S:i.getMilliseconds(),Z:`${n>=0?"+":"-"}${Math.abs(n).toString().padStart(2,"0")}:00`};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(i.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in a)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?a[e]:("00"+a[e]).substr((""+a[e]).length)));return t}catch(e){return time}},getDateInfo:function(e=new Date,t){let n=util$4.getTimeByTimeZone(e,t),i=n.getFullYear()+"",a=n.getMonth()+1<10?"0"+(n.getMonth()+1):n.getMonth()+1,r=n.getDate()<10?"0"+n.getDate():n.getDate(),o=n.getHours()<10?"0"+n.getHours():n.getHours(),s=n.getMinutes()<10?"0"+n.getMinutes():n.getMinutes(),u=n.getSeconds()<10?"0"+n.getSeconds():n.getSeconds(),l=n.getMilliseconds(),c=n.getDay(),d=Math.floor((n.getMonth()+3)/3);return{year:Number(i),month:Number(a),day:Number(r),hour:Number(o),minute:Number(s),second:Number(u),millisecond:Number(l),week:Number(c),quarter:Number(d)}},getCommonTime:function(e=new Date,t){let n={},i=util$4.getDateObject(e);t=util$4.getTargetTimezone(t);const a=60*i.getTimezoneOffset()*1e3+60*t*60*1e3,{year:r,month:o,day:s,hour:u,minute:l,second:c,millisecond:d,week:p,quarter:f}=util$4.getDateInfo(i,t);n.now={year:r,month:o,day:s,hour:u,minute:l,second:c,millisecond:d,week:p,quarter:f,date_str:util$4.timeFormat(i,"yyyy-MM-dd hh:mm:ss",t),date_day_str:util$4.timeFormat(i,"yyyy-MM-dd",t),date_month_str:util$4.timeFormat(i,"yyyy-MM",t)};let g=new Date(r,o,0).getDate(),m=new Date(r,12,0).getDate();n.todayStart=new Date(`${r}/${o}/${s}`).getTime()-a,n.today12End=new Date(`${r}/${o}/${s}`).getTime()+43199999-a,n.todayEnd=new Date(`${r}/${o}/${s}`).getTime()+86399999-a,n.monthStart=new Date(`${r}/${o}/1`).getTime()-a,n.monthEnd=new Date(`${r}/${o}/${g}`).getTime()+86399999-a,n.yearStart=new Date(r+"/1/1").getTime()-a,n.yearEnd=new Date(`${r}/12/${m}`).getTime()+86399999-a,n.hourStart=new Date(`${r}/${o}/${s} ${u}:00:00`).getTime()-a,n.hourEnd=new Date(`${r}/${o}/${s} ${u}:59:59`).getTime()-a;let b=r,h=o-1;0===h&&(h=12,b=r-1);let y=new Date(b,h,0).getDate();n.lastMonthStart=new Date(`${b}/${h}/1`).getTime()-a,n.lastMonthEnd=new Date(`${b}/${h}/${y}`).getTime()+86399999-a,n.yesterdayStart=n.todayStart-864e5,n.yesterday12End=n.today12End-864e5,n.yesterdayEnd=n.todayEnd-864e5;let w=util$4.getWeekOffsetStartAndEnd(0,i,t);n.weekStart=w.startTime,n.weekEnd=w.endTime,n.months=[],n.months[0]={startTime:n.monthStart,endTime:n.monthEnd,startTimeStr:util$4.timeFormat(n.monthStart,"yyyy-MM-dd hh:mm:ss",t),endTimeStr:util$4.timeFormat(n.monthEnd,"yyyy-MM-dd hh:mm:ss",t),monthStart:n.monthStart,monthEnd:n.monthEnd};for(let e=1;e<=12;e++){let i=new Date(r,e,0).getDate(),o=new Date(`${r}/${e}/1`).getTime()-a,s=new Date(`${r}/${e}/${i}`).getTime()+86399999-a;n.months[e]={startTime:o,endTime:s,startTimeStr:util$4.timeFormat(o,"yyyy-MM-dd hh:mm:ss",t),endTimeStr:util$4.timeFormat(s,"yyyy-MM-dd hh:mm:ss",t),monthStart:o,monthEnd:s}}n.days=[],n.days[0]={startTime:n.todayStart,endTime:n.todayEnd,startTimeStr:util$4.timeFormat(n.todayStart,"yyyy-MM-dd hh:mm:ss",t),endTimeStr:util$4.timeFormat(n.todayEnd,"yyyy-MM-dd hh:mm:ss",t)};for(let e=1;e<=g;e++){let i=n.monthStart+864e5*(e-1),{startTime:a,endTime:r}=util$4.getDayOffsetStartAndEnd(0,i,t);n.days[e]={startTime:a,endTime:r,startTimeStr:util$4.timeFormat(a,"yyyy-MM-dd hh:mm:ss",t),endTimeStr:util$4.timeFormat(r,"yyyy-MM-dd hh:mm:ss",t)}}for(let e in n)"number"==typeof n[e]&&13===n[e].toString().length&&(n[e+"Str"]=util$4.timeFormat(n[e],"yyyy-MM-dd hh:mm:ss",t));return n},getMonthStartAndEnd:function(e,t){t=util$4.getTargetTimezone(t);let n={startTime:null,endTime:null},{year:i,month:a}=e;if(i>0&&a>0){const e=60*(new Date).getTimezoneOffset()*1e3+60*t*60*1e3;let r=new Date(i,a,0).getDate();n.startTime=new Date(`${i}/${a}/1`).getTime()-e,n.endTime=new Date(`${i}/${a}/${r}`).getTime()+86399999-e}return n},getHourOffsetStartAndEnd:function(e=0,t=new Date,n){let i=util$4.getDateObject(t);n=util$4.getTargetTimezone(n);let a={};const r=60*i.getTimezoneOffset()*1e3+60*n*60*1e3;i=new Date(i.getTime()+36e5*e);let o=util$4.getDateInfo(i);return a.startTime=new Date(`${o.year}/${o.month}/${o.day} ${o.hour}:00:00`).getTime()-r,a.endTime=new Date(`${o.year}/${o.month}/${o.day} ${o.hour}:00:00`).getTime()+3599999-r,a},getDayOffsetStartAndEnd:function(e=0,t=new Date,n){let i=util$4.getDateObject(t);n=util$4.getTargetTimezone(n);let a={};const r=60*i.getTimezoneOffset()*1e3+60*n*60*1e3;i=new Date(i.getTime()+864e5*e);let o=util$4.getDateInfo(i);return a.startTime=new Date(`${o.year}/${o.month}/${o.day}`).getTime()-r,a.endTime=new Date(`${o.year}/${o.month}/${o.day}`).getTime()+86399999-r,a},getWeekOffsetStartAndEnd:function(e=0,t=new Date,n){let i={},a=util$4.getDateObject(t);n=util$4.getTargetTimezone(n);const r=60*a.getTimezoneOffset()*1e3+60*n*60*1e3;let o=0===a.getDay()?7:a.getDay();a.setDate(a.getDate()-o+1+7*e);let s=util$4.getDateInfo(a);a.setDate(a.getDate()+7);let u=util$4.getDateInfo(a);return i.startTime=new Date(`${s.year}/${s.month}/${s.day}`).getTime()-r,i.endTime=new Date(`${u.year}/${u.month}/${u.day}`).getTime()-1-r,i},getMonthOffsetStartAndEnd:function(e=0,t=new Date,n){let i={},a=util$4.getDateObject(t),r=util$4.getDateInfo(a),o=r.month+e,s=r.year;o>12?(s+=Math.floor(o/12),o=Math.abs(o)%12):o<=0&&(s=s-1-Math.floor(Math.abs(o)/12),o=12-Math.abs(o)%12);let u=new Date(s,o,0).getDate();return i.startTime=util$4.getDateObject(`${s}/${o}/01`,n).getTime(),i.endTime=util$4.getDateObject(`${s}/${o}/${u}`,n).getTime()+86399999,i},getQuarterOffsetStartAndEnd:function(e=0,t=new Date,n){let i={},a=util$4.getDateObject(t);a.setMonth(a.getMonth()+3*e),n=util$4.getTargetTimezone(n);const r=60*a.getTimezoneOffset()*1e3+60*n*60*1e3;let o=util$4.getDateInfo(a).month;[1,2,3].indexOf(o)>-1?o=1:[4,5,6].indexOf(o)>-1?o=4:[7,8,9].indexOf(o)>-1?o=7:[10,11,12].indexOf(o)>-1&&(o=10),a.setMonth(o-1);let s=util$4.getDateInfo(a);a.setMonth(a.getMonth()+3);let u=util$4.getDateInfo(a);return i.startTime=new Date(`${s.year}/${s.month}/1`).getTime()-r,i.endTime=new Date(`${u.year}/${u.month}/1`).getTime()-1-r,i},getYearOffsetStartAndEnd:function(e=0,t=new Date,n){let i={},a=util$4.getDateObject(t);n=util$4.getTargetTimezone(n);const r=60*a.getTimezoneOffset()*1e3+60*n*60*1e3;let o=util$4.getDateInfo(a).year+e;return i.startTime=new Date(o+"/1/1").getTime()-r,i.endTime=new Date(o+"/12/31").getTime()+86399999-r,i},getOffsetTime:function(e=new Date,t,n){let i=util$4.getDateObject(e),a=util$4.getDateInfo(i);n=util$4.getTargetTimezone(n);const r=60*i.getTimezoneOffset()*1e3+60*n*60*1e3;let o=t.year||t.y||0,s=t.month||t.m||0,u=t.day||t.d||0,l=t.hour||t.hours||t.hh||0,c=t.minute||t.minutes||t.mm||0,d=t.second||t.seconds||t.ss||0,{mode:p="after"}=t;"before"==p&&(o*=-1,s*=-1,u*=-1,l*=-1,c*=-1,d*=-1);let f={year:a.year+o,month:a.month+s,day:a.day+u,hour:a.hour+l,minute:a.minute+c,second:a.second+d};return i=new Date(f.year,f.month-1,f.day,f.hour,f.minute,f.second),i.getTime()-r},isLeapYear:function(e){if(void 0===e){let{now:t}=util$4.getCommonTime();e=t.year}else if("object"==typeof e){let{now:t}=util$4.getCommonTime(e);e=t.year}return e%4==0&&e%100!=0||e%400==0},isQingming:function(e=new Date){let{now:t}=util$4.getCommonTime(e),{year:n,month:i,day:a}=t,r=!1;return util$4.isLeapYear(n)||util$4.isLeapYear(n-1)?4===i&&4===a&&(r=!0):4===i&&5===a&&(r=!0),r},getFullTime:function(e,t=0,n){if(!e)return"";n=util$4.getTargetTimezone(n);let i=util$4.getDateObject(e);const a=60*i.getTimezoneOffset()*1e3+60*n*60*1e3,r=i.getTime()+a;i=new Date(r);let o=i.getFullYear()+"",s=i.getMonth()+1<10?"0"+(i.getMonth()+1):i.getMonth()+1,u=i.getDate()<10?"0"+i.getDate():i.getDate(),l=i.getHours()<10?"0"+i.getHours():i.getHours(),c=i.getMinutes()<10?"0"+i.getMinutes():i.getMinutes(),d=i.getSeconds()<10?"0"+i.getSeconds():i.getSeconds();return 2===t?{YYYY:Number(o),MM:Number(s),DD:Number(u),hh:Number(l),mm:Number(c),ss:Number(d),year:Number(o),month:Number(s),day:Number(u),hour:Number(l),minute:Number(c),second:Number(d)}:1===t?o+""+s+u+l+c+d:o+"-"+s+"-"+u+" "+l+":"+c+":"+d}},timeUtil=util$4,pubfn={};pubfn.formValidate=formValidate,pubfn.treeUtil=treeUtil,pubfn.timeUtil=timeUtil,pubfn.sleep=e=>new Promise(t=>setTimeout(t,e)),pubfn.timeFormat=pubfn.timeUtil.timeFormat,pubfn.getDateInfo=pubfn.timeUtil.getDateInfo,pubfn.getFullTime=pubfn.timeUtil.getFullTime,pubfn.getCommonTime=pubfn.timeUtil.getCommonTime,pubfn.getOffsetTime=pubfn.timeUtil.getOffsetTime,pubfn.getHourOffsetStartAndEnd=pubfn.timeUtil.getHourOffsetStartAndEnd,pubfn.getDayOffsetStartAndEnd=pubfn.timeUtil.getDayOffsetStartAndEnd,pubfn.getWeekOffsetStartAndEnd=pubfn.timeUtil.getWeekOffsetStartAndEnd,pubfn.getWeekStartAndEnd=pubfn.timeUtil.getWeekOffsetStartAndEnd,pubfn.getMonthOffsetStartAndEnd=pubfn.timeUtil.getMonthOffsetStartAndEnd,pubfn.getQuarterOffsetStartAndEnd=pubfn.timeUtil.getQuarterOffsetStartAndEnd,pubfn.getYearOffsetStartAndEnd=pubfn.timeUtil.getYearOffsetStartAndEnd,pubfn.getMonthStartAndEnd=pubfn.timeUtil.getMonthStartAndEnd,pubfn.validator=function(e){return function(t,n,i){let a=pubfn.test(n,e);return"function"!=typeof i||!a&&n?i(!1):void i()}},pubfn.test=function(e,t="",n=!1){let i;if(t=t.toLowerCase(),n&&(""===e||null==e))return!0;switch(t){case"mobile":return new RegExp(/^1[3|4|5|6|7|8|9][0-9]{9}$/).test(e);case"tel":return new RegExp(/^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/).test(e);case"card":return new RegExp(/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/).test(e);case"mobilecode":return new RegExp(/^[0-9]{6}$/).test(e);case"username":return new RegExp(/^[a-zA-Z]([-_a-zA-Z0-9]{2,31})$/).test(e);case"pwd":case"password":return new RegExp(/^([a-zA-Z0-9_@]){6,18}$/).test(e);case"paypwd":return new RegExp(/^[0-9]{6}$/).test(e);case"postal":return new RegExp(/[1-9]\d{5}(?!\d)/).test(e);case"qq":return new RegExp(/^[1-9][0-9]{4,9}$/).test(e);case"email":return new RegExp(/^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/).test(e);case"money":return new RegExp(/^\d*(?:\.\d{0,2})?$/).test(e);case"url":return new RegExp(/^(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/).test(e);case"ip":return new RegExp(/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/).test(e);case"date":return new RegExp(/^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/).test(e);case"time":return new RegExp(/^(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d$/).test(e);case"datetime":return new RegExp(/^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\s+(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d$/).test(e);case"english+number":return new RegExp(/^[a-zA-Z0-9]+$/).test(e);case"english+number+_":return new RegExp(/^[a-zA-Z0-9_]+$/).test(e);case"english+number+_-":return new RegExp(/^[a-zA-Z0-9_-]+$/).test(e);case"version":return new RegExp(/^([1-9]\d|[1-9])(.([1-9]\d|\d)){2}$/).test(e);case"number":return new RegExp(/^[0-9]+$/).test(e);case"english":return new RegExp(/^[a-zA-Z]+$/).test(e);case"chinese":return new RegExp(/^[\u4e00-\u9fa5]+$/gi).test(e);case"lower":return new RegExp(/^[a-z]+$/).test(e);case"upper":return new RegExp(/^[A-Z]+$/).test(e);case"html":return new RegExp(/<("[^"]*"|'[^']*'|[^'">])*>/).test(e);case"image":return i=e.split("?")[0],new RegExp(/\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)$/).test(i);case"video":return i=e.split("?")[0],new RegExp(/\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv|m3u8|3gp)$/).test(i);case"audio":return i=e.split("?")[0],new RegExp(/\.(mp3)$/).test(i);default:return!0}},pubfn.checkStr=pubfn.test,pubfn.priceFilter=function(e,t=""){return pubfn.isNull(e)?t:isNaN(e)?e:("string"==typeof e&&(e=parseFloat(e)),(e/100).toFixed(2))},pubfn.priceLeftFilter=function(e){let t="";return e&&(t=pubfn.priceFilter(e).split(".")[0]),t},pubfn.priceRightFilter=function(e){let t="";return e&&(t=pubfn.priceFilter(e).split(".")[1]),t},pubfn.percentageFilter=function(e,t=!0,n=""){return pubfn.isNull(e)?n:(isNaN(e)||("string"==typeof e&&(e=parseFloat(e)),e=parseFloat((100*e).toFixed(2)),t&&(e+="%")),e)},pubfn.discountFilter=function(e,t=!0,n=""){return pubfn.isNull(e)?n:isNaN(e)?e:("string"==typeof e&&(e=parseFloat(e)),(e=parseFloat((10*e).toFixed(2)))>10?"折扣不可以大于原价":10==e?"原价":0==e?"免费":e<0?"折扣不可以小于0":(t&&(e+=" 折"),e))},pubfn.objectDeleteInvalid=function(e){return Object.keys(e).forEach(t=>{void 0===e[t]&&delete e[t]}),e},pubfn.objectAssign=function(e,t,n=!0){return n&&pubfn.objectDeleteInvalid(t),Object.assign(e,t)},pubfn.copyObject=function(e){return void 0!==e?JSON.parse(JSON.stringify(e)):e},pubfn.deepClone=function(e){if([null,void 0,NaN,!1].includes(e))return e;if("object"!=typeof e&&"function"!=typeof e)return e;let t="[object Array]"===Object.prototype.toString.call(e)?[]:{};for(let n in e)e.hasOwnProperty(n)&&(t[n]="object"==typeof e[n]?pubfn.deepClone(e[n]):e[n]);return t},pubfn.formAssign=function(e,t){let n=pubfn.copyObject(e);return pubfn.objectAssign(n,t)},pubfn.arr_concat=function(e,t,n){n||(n="id"),e||(e=[]),t||(t=[]);let i=e.concat(t),a=[];if(-1!=n){let e=[];for(let t in i)-1==e.indexOf(i[t][n])&&(e.push(i[t][n]),a.push(i[t]))}else a=i;return a},pubfn.getData=function(e,t,n){let i=JSON.parse(JSON.stringify(e));t=t.replace(/\s+/g,"")+".";let a="";for(let e=0;ee[t])},pubfn.random=function(e,t,n){let i;if(pubfn.isNull(n))i=pubfn.randomFn(e,t);else{let a=0,r=1e5;do{a++,i=pubfn.randomFn(e,t)}while(n.indexOf(i)>-1&&ae){n+="0123456789"[i[e].charCodeAt()%10]}else n="0"+n;return n},pubfn.hidden=function(e="",t=0,n=0){let i=e.length-t-n,a="";for(let e=0;e-1&&(n=!0);return n},pubfn.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)},pubfn.isObject=function(e){return"[object Object]"===Object.prototype.toString.call(e)},pubfn.calcFreights=function(e,t){return pubfn.calcFreightDetail(e,t).total_amount},pubfn.calcFreightDetail=function(e,t){let{first_weight:n,first_weight_price:i,continuous_weight:a,continuous_weight_price:r,max_weight:o}=e;o||(o=1e9);let s=t,u=0,l=o,c=!1,d=0;for(;t>0;)c?(d++,t-=a,l-=a):(c=!0,u++,l=o,t-=n,l-=n),l<=0&&(c=!1);let p=i*u+r*d;return{weight:s,first_weight:n,first_weight_price:i,first_weight_count:u,continuous_weight:a,continuous_weight_price:r,continuous_weight_count:d,first_weight_amount:u*i,continuous_weight_amount:r*d,total_amount:p,formula:`${i} * ${u} + ${r} * ${d} = ${p}`}},pubfn.getNewObject=function(e,t){let n=pubfn.copyObject(e),i={};if(t&&t.length>0)for(let e in t){let a=t[e];pubfn.isNotNull(n[a])&&(i[a]=n[a])}else i=n;return i},pubfn.deleteObjectKeys=function(e,t=[]){var n={};if(e)for(let i in e)-1==t.indexOf(i)&&(n[i]=e[i]);return n},pubfn.arrayToTree=pubfn.treeUtil.arrayToTree,pubfn.treeToArray=pubfn.treeUtil.treeToArray,pubfn.wildcardTestOne=function(e,t){if(!t)return!1;let n=t.replace(new RegExp("\\*"),"(.*)"),i=0!==t.indexOf("*")?"^":"",a="*"!==t[t.length-1]?"$":"";return new RegExp(i+n+a).test(e)},pubfn.wildcardTest=function(e,t){let n=0;if("string"==typeof t)pubfn.wildcardTestOne(e,t)&&n++;else if("object"==typeof t)for(let i=0;i0?l=r+"天":o>0?l=o+"小时":s>0?l=s+"分钟":u>0&&(l=u+"秒"),l+=t},pubfn.dateDiff2=function(e,t="1秒"){if(!e)return"";"string"!=typeof e||isNaN(e)||(e=Number(e)),"number"==typeof e&&(10==e.toString().length&&(e*=1e3),e=new Date(e),e=pubfn.timeFormat(e)),"string"==typeof e&&(e=e=e.replace("T"," "),e=new Date(e.replace(/-/g,"/")));var n=new Date,i=864e5,a=36e5,r=e.getTime()-n.getTime(),o=Math.floor(r/i),s=Math.floor(r%i/a),u=Math.floor(r%i%a/6e4),l=Math.round(r%i%a%6e4/1e3),c=t;return o>0?c=o+"天":s>0?c=s+"小时":u>0?c=u+"分钟":l>0&&(c=l+"秒"),c},pubfn.numStr=function(e){"string"==typeof e&&(e=parseFloat(e));var t=e;if(e<1e3)t=e;else if(e<1e4){t=Math.floor(e/100)/10+"千"}else if(e<1e6){t=Math.floor(e/1e3)/10+"万"}else if(e<1e7){t=Math.floor(e/1e6)+"百万"}else if(e<1e8){t=Math.floor(e/1e7)+"千万"}else if(e>=1e8){t=Math.floor(e/1e7)/10+"亿"}return t},pubfn.calcSize=function(e=0,t,n,i=2,a="auto"){let r=0,o="";if((e=parseFloat(e))parseObjectKeys(e,t)))}return e}pubfn.snake2camel=function(e){return e.replace(isSnakeCase,(e,t)=>t?t.toUpperCase():"")},pubfn.camel2snake=function(e){return e.replace(isCamelCase,e=>"_"+e.toLowerCase())},pubfn.snake2camelJson=function(e){return parseObjectKeys(e,"snake2camel")},pubfn.camel2snakeJson=function(e){return parseObjectKeys(e,"camel2snake")},pubfn.string2Number=function(e,t={}){switch(Object.prototype.toString.call(e).slice(8,-1).toLowerCase()){case"string":if(e&&!isNaN(e)){let{mobile:n=!0,idCard:i=!0,startFrom0:a=!0,maxLength:r=14}=t;return e.length>r||(n&&pubfn.test(e,"mobile")||i&&pubfn.test(e,"card")||a&&e.length>1&&0===e.indexOf("0")&&1!==e.indexOf("."))?e:Number(e)}return e;case"object":const n=Object.keys(e);for(let t=0;t-1&&(t=e.substring(n+1)),t},pubfn.checkFileSuffix=function(e,t){let n=!1,i=pubfn.getFileSuffix(e);for(let e=0;e-1){n=!0;break}return n},pubfn.splitArray=function(e,t){let n=[];for(let i=0;i-1){var o=a.indexOf('"',r),s=a.substring(r,o);if(o>r){var u=a.indexOf("---",o),l=a.substring(o+1,u).trim();n[s]=l}}}return n},pubfn.getPlatform=function(e){return"web"===e?e="h5":"app"===e&&(e="app-plus"),e},pubfn.getClientUAByContext=function(e={}){return e.ua||e.CLIENTUA},pubfn.getPlatformForUniId=function(e={}){let t=e.PLATFORM;if(t=pubfn.getPlatform(t),"h5"===t){pubfn.getClientUAByContext(e).toLowerCase().indexOf("micromessenger")>-1&&(t="h5-weixin")}return t},pubfn.getUniCloudContext=function(){let e;try{e=uniCloud.context}catch(e){}return e},pubfn.getUniCloudFunctionName=function(){let e;try{let t=pubfn.getUniCloudContext();e=t.FUNCTION_NAME||t.function_name}catch(e){}return e},pubfn.getUniCloudProvider=function(){let e;try{e=uniCloud.context.SPACEINFO.provider}catch(e){}return e},pubfn.getUniCloudRequestId=function(){let e;try{e=pubfn.getUniCloudContext().requestId}catch(e){}return e},pubfn.getUniIdConfig=function(e={},t,n){const i=e.uni;let a;if(pubfn.isArray(i)){let e=uniCloud.env&&uniCloud.env.APPID?uniCloud.env.APPID:uniCloud.$context.APPID;a=pubfn.getListItem(i,"dcloudAppid",e),pubfn.isNull(a)&&(a=pubfn.getListItem(i,"isDefaultConfig",!0))}else a=i;if(pubfn.isNotNull(t)){let e=pubfn.getData(a,t);return pubfn.isNull(e)?n:e}return a},pubfn.batchRun=async function(e){let{main:t,data:n=[],concurrency:i=50}=e;if(pubfn.isArray(t))return pubfn.batchRun2(e);let a=n.length,r=[];if(0==a)return{stack:r,total:a};if(1===i){for(let e=0;e=a)break;let u=t(n[s],s);e.push(u)}try{await Promise.all(e).then(e=>{r=r.concat(e)})}catch(e){console.error(e)}}return{stack:r,total:a}}},pubfn.batchRun2=async function(e){let{main:t,concurrency:n=100}=e,i=t.length,a=[];if(0==i)return{stack:a,total:i};if(1===n){for(let e=0;e=i)break;let s=(0,t[o])();e.push(s)}try{await Promise.all(e).then(e=>{a=a.concat(e)})}catch(e){console.error(e)}}return{stack:a,total:i}}},pubfn.randomAsync=async function(e,t,n,i=500){let a;if("function"==typeof n){let r=0;do{r++,a=pubfn.randomFn(e,t)}while(!await n(a)&&r0?(new Date).getTime()+1e3*n:0};dataCache[e]=i},util$5.del=function(e){delete dataCache[e]},util$5.clear=function(e){if(e)for(let t in dataCache)0==t.indexOf(e)&&delete dataCache[t];else dataCache={}},util$5.isExpired=function(e){let t=!0,n=dataCache[e];return n&&(0==n.expired||n.expired>(new Date).getTime())&&(t=!1),t},util$5.getAll=function(e){let t={};if(e)for(let n in dataCache)0==n.indexOf(e)&&(t[e]=dataCache[e]);else t=dataCache;for(let e in t)util$5.isExpired(e)&&(delete t[e],delete dataCache[e]);return t};var temporaryCache=util$5,globalDataCache={},util$6={},globalDataDao={};globalDataCache.init=function(e){globalDataDao=(util$6=e).vk.system.globalDataDao},globalDataCache.get=async function(e,t=0,n,i=!0){return"function"==typeof n?globalDataCache.autoGet(e,t,n,i):globalDataCache._get(e)},globalDataCache.autoGet=async function(e,t=0,n,i=!0){let a,{vk:r}=util$6;try{a=await globalDataCache._get(e),r.pubfn.isNull(a)&&"function"==typeof n&&(a=await n(),void 0!==a&&i&&await r.globalDataCache.set(e,a,t))}catch(e){return}return a},globalDataCache._get=async function(e){let t;try{let n=await globalDataDao.find(e);if(n){let{value:i,expired_at:a}=n;globalDataCache.isExpired(n)?await globalDataCache.del(e):t=i}}catch(e){return}return t},globalDataCache.set=async function(e,t,n=0,i){let a;e&&void 0!==e.key&&void 0!==e.value?(a=e.key,t=e.value,n=e.second,i=e.comment):a=e;let r={code:0,msg:"ok"};try{if(!a)return{code:-1,msg:"key值不能为空"};let e=n>0?(new Date).getTime()+1e3*n:0;r=await globalDataDao.set({key:a,value:t,expired_at:e,comment:i})}catch(e){return console.error(e),{code:-1,msg:"异常"}}return r},globalDataCache.del=async function(e){await globalDataDao.del(e)},globalDataCache.clear=async function(e){if(e)return await globalDataDao.deleteByWhere({key:new RegExp("^"+e)})},globalDataCache.list=async function(e){return await globalDataDao.list(e)},globalDataCache.count=async function(e){return await globalDataDao.count(e)},globalDataCache.isExpired=function(e){let t=!0;return e&&(!e.expired_at||0==e.expired_at||e.expired_at>(new Date).getTime())&&(t=!1),t},globalDataCache.inc=async function(e,t=1,n=0){let i;e&&void 0!==e.key&&void 0!==e.value?(i=e.key,t=e.value,n=e.second):i=e;let a={code:0,msg:"ok"};try{if(!i)return{code:-1,msg:"key值不能为空"};let e=n>0?(new Date).getTime()+1e3*n:0;a=await globalDataDao.inc({key:i,value:t,expired_at:e})}catch(e){return{code:-1,msg:"异常",err:e}}return a},globalDataCache.uniqueAdd=async function(e,t=1,n=5){let{vk:i}=util$6,a={code:0,msg:"ok"};try{if(!e)return{code:-1,msg:"key值不能为空"};let r=n>0?(new Date).getTime()+1e3*n:0;await i.globalDataCache.deleteExpired(e);a.id=await globalDataDao.add({key:e,value:t,expired_at:r})}catch(e){return console.error(e),{code:-1,msg:"异常"}}return a},globalDataCache.deleteExpired=async function(e){await globalDataDao.deleteExpired(e)};var globalDataCache_1=globalDataCache,util$7={aes:{}};const aesKey="5fb2cd73c7b53918728417c50762e6d45fb2cd73c7b53918728417c50762e6d4",AESMODE={AES192:"aes192",AES256ECB:"aes-256-ecb"};util$7.aes.MODE=AESMODE,util$7.aes.encrypt=function(e){let{data:t,key:n,mode:i=AESMODE.AES192}=e,a=uniCloud.vk,{crypto:r,config:o}=a.getUnicloud();if(n||(n=a.pubfn.getData(o.vk,"crypto.aes",aesKey)),"object"==typeof t&&(t=JSON.stringify(t)),i===AESMODE.AES256ECB)return encryptUseAes256Ecb(t,n);if(i===AESMODE.AES192)return encryptUseAes192(t,n);throw new Error(`msg:不支持 ${i} 加密算法`)},util$7.aes.decrypt=function(e){let{data:t,key:n,mode:i=AESMODE.AES192}=e,a=uniCloud.vk,{crypto:r,config:o}=a.getUnicloud();if(a.pubfn.isNull(t))throw new Error("msg:待解密原文不能为空");if(n||(n=a.pubfn.getData(o.vk,"crypto.aes",aesKey)),i===AESMODE.AES256ECB)return decryptUseAes256Ecb(t,n);if(i===AESMODE.AES192)return decryptUseAes192(t,n);throw new Error(`msg:不支持 ${i} 加密算法`)};var crypto=util$7;function encryptUseAes192(e,t){let n=uniCloud.vk,{crypto:i}=n.getUnicloud();const a=i.createCipher(AESMODE.AES192,t);let r=a.update(e,"utf8","hex");return r+=a.final("hex"),r}function decryptUseAes192(e,t){let n,i=uniCloud.vk,{crypto:a}=i.getUnicloud();try{const i=a.createDecipher(AESMODE.AES192,t);n=i.update(e,"hex","utf8"),n+=i.final("utf8");try{n=JSON.parse(n)}catch(e){}}catch(e){throw"msg:解密失败"}return n}function encryptUseAes256Ecb(e,t){let n=uniCloud.vk,{crypto:i}=n.getUnicloud(),a=Buffer.from(e),r=t;r.length>32&&(r=r.substring(0,32)),r=Buffer.from(r);const o=i.createCipheriv(AESMODE.AES256ECB,r,"");o.setAutoPadding(!1);const s=16-a.length%16,u=Buffer.alloc(s,s);a=Buffer.concat([a,u]);let l=o.update(a,null,"base64");return l+=o.final("base64"),l}function decryptUseAes256Ecb(e,t){let n=uniCloud.vk,{crypto:i}=n.getUnicloud(),a=t;a.length>32&&(a=a.substring(0,32)),a=Buffer.from(a);try{const t=i.createDecipheriv(AESMODE.AES256ECB,a,"");t.setAutoPadding(!1);let n=t.update(e,"base64");n+=t.final();const r=n.charCodeAt(n.length-1);n=n.slice(0,n.length-r);try{n=JSON.parse(n)}catch(e){}return n}catch(e){throw"解密失败"}}var alipay={},ALIPAY_ALGORITHM_MAPPING={RSA:"RSA-SHA1",RSA2:"RSA-SHA256"};alipay.sign=function(e,t,n){let i=JSON.parse(JSON.stringify(t)),a=Object.assign({method:e,app_id:n.appid,charset:n.charset||"utf-8",version:n.version||"1.0",sign_type:n.signType||"RSA2"},i);n.appCertSn&&n.alipayRootCertSn&&(a=Object.assign({app_cert_sn:n.appCertSn,alipay_root_cert_sn:n.alipayRootCertSn},a));const r=i.bizContent||i.biz_content;r&&(a.biz_content=JSON.stringify(r));const o=alipay.sortObj(a);let s=alipay.objectToUrl(o);const u="PKCS8"===(n.keyType||"PKCS8")?"PRIVATE KEY":"RSA PRIVATE KEY";let l=alipay.formatKey(n.privateKey,u);const c=crypto$1.createSign(ALIPAY_ALGORITHM_MAPPING[a.sign_type]).update(s,"utf8").sign(l,"base64");return Object.assign(o,{sign:c})},alipay.formatUrl=function(e,t="https://openapi.alipay.com/gateway.do"){let n=t;const i=["app_id","method","format","charset","sign_type","sign","timestamp","version","notify_url","return_url","auth_token","app_auth_token","ws_service_url"];for(const t in e)if(i.indexOf(t)>-1){const i=encodeURIComponent(e[t]);n=`${n}${n.includes("?")?"&":"?"}${t}=${i}`,delete e[t]}return{execParams:e,url:n}},alipay.sortObj=function(e){new Array;let t=Object.keys(e).sort(),n={};for(let i in t)n[t[i]]=e[t[i]];return n},alipay.objectToUrl=function(e){let t="";for(let n in e)e[n]&&(t+=`&${n}=${e[n]}`);return t&&(t=t.substring(1)),t},alipay.formatKey=function(e,t){return`-----BEGIN ${t}-----\n${e}\n-----END ${t}-----`},alipay.getRequestRes=function(e,t){return e[t.replace(new RegExp("\\.","g"),"_")+"_response"]||e.error_response};var util$8=alipay,alipay$1={},util$9={};const serviceUrl="https://openapi.alipay.com/gateway.do",configKey="mp-alipay.oauth.alipay";function returnRes(e){return e.code=e.sub_code||e.code||0,e.msg=e.sub_msg||e.msg||"",e}alipay$1.init=function(e){util$9=e},alipay$1.getConfig=function(){let{vk:e,config:t}=util$9;return e.pubfn.getUniIdConfig(t)},alipay$1.request=async function(e={}){let{vk:t}=util$9,{method:n,data:i={},successText:a}=e,r=alipay$1.auth.getAppidInfo(e),o=Date.now(),s={timestamp:t.pubfn.timeFormat(o,"yyyy-MM-dd hh:mm:ss"),...i};const u=util$8.sign(n,s,r),{url:l,execParams:c}=util$8.formatUrl(u,serviceUrl);let d=await t.request({url:l,method:"POST",data:c}),p=await util$8.getRequestRes(d,n);return p.code&&"10000"!==p.code||(p.code=0,p.msg=a),p=returnRes(p),p},alipay$1.auth={},alipay$1.auth.getAppidInfo=function(e={}){let{appid:t,privateKey:n}=e,{vk:i,config:a}=util$9;const r=alipay$1.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.alipay.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};if(t=r.appid,n=r.privateKey,i.pubfn.isNullOne(t,n))throw console.log("config",e),new Error(`你使用了多小程序登录模式,但未找到${t}对应的 privateKey 请先在 uni-config-center/vk-unicloud/index.js 中配置支付宝小程序(vk.oauth.alipay.list)的appid和privateKey`)}}else{let e=i.pubfn.getData(r,configKey)||{};if(t=e.appid,n=e.privateKey,i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error(`请先在 uni-config-center/uni-id/config.json 中配置支付宝小程序(${configKey})的appid和privateKey`)}return{appid:t,privateKey:n}},alipay$1.auth.code2Session=async function(e={}){let{vk:t,uniID:n}=util$9,{platform:i,needKey:a=!1}=e;i||(i="mp-alipay");let r=await alipay$1.auth.code2SessionMp(e);try{let e=t.crypto.aes.encrypt({data:r});r.encryptedKey=e}catch(e){}return a||(delete r.sessionKey,delete r.accessToken,delete r.refreshToken),delete r.privateKey,r.platform=i,r.openid=r.userId,r},alipay$1.auth.code2SessionMp=async function(e={}){let{appid:t}=alipay$1.auth.getAppidInfo(e),n=e.code||e.js_code,{vk:i}=util$9,a=await alipay$1.request({method:"alipay.system.oauth.token",data:{code:n,grant_type:"authorization_code"}});return{...i.pubfn.snake2camelJson(a),appid:t,code:0,msg:"ok"}},alipay$1.security={},alipay$1.security.msgSecCheck=async function(e={}){return{code:-1,msg:"支付宝未提供此API"}},alipay$1.security.imgSecCheck=async function(e={}){return{code:-1,msg:"支付宝未提供此API"}},alipay$1.acode={},alipay$1.acode.getMiniCode=async function(e={}){let{page:t,scene:n="miniCode=1",line_color:i}=e,a={url_param:t,query_param:n,describe:"推广",color:i};return await alipay$1.request({method:"alipay.open.app.qrcode.create",data:{biz_content:a},successText:"生成成功"})},alipay$1.subscribeMessage={},alipay$1.subscribeMessage.send=async function(e={}){let{touser:t,form_id:n,template_id:i,page:a,data:r}=e,{appid:o}=alipay$1.auth.getAppidInfo(e),s={to_user_id:t,form_id:n,user_template_id:i,page:a,data:r};return await alipay$1.request({method:"alipay.open.app.mini.templatemessage.send",data:{biz_content:s},successText:"发送成功"})};var alipay_1=alipay$1,baidu={},util$a={};baidu.init=function(e){util$a=e},baidu.open={},baidu.open.auth={},baidu.open.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$a;if(!t){let e=i.pubfn.getData(a,"vk.service.openapi.baidu")||{};t=e.appid,n=e.appsecret}if(i.pubfn.isNullOne(t,n))throw new Error("请在uniCloud/cloudfunctions/common/uni-config-center/vk-unicloud/index.js中配置并检查百度开放平台的appid和appsecret是否正确,参数路径:vk.service.openapi.baidu");return{appid:t,appsecret:n}},baidu.open.auth.getAccessTokenFn=async function(e={}){let{appid:t,appsecret:n}=baidu.open.auth.getAppidInfo(e),{vk:i,config:a}=util$a,r=await i.request({url:`https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=${t}&client_secret=${n}`,method:"GET"});return r.error_code?(console.error("getAccessToken失败:",r),{code:r.error_code,msg:r.error_msg,err:r}):{...r,code:0,msg:"ok"}},baidu.open.auth.getAccessToken=async function(e={}){let t,{appid:n,appsecret:i}=baidu.open.auth.getAppidInfo(e),{cache:a=!0}=e,{vk:r}=util$a,o="openapi-baidu-"+n;if(a&&(t=await r.globalDataCache.get(o)),r.pubfn.isNull(t)){let n=await baidu.open.auth.getAccessTokenFn(e);0===n.code&&(t=n.access_token,await r.globalDataCache.set(o,t,n.expires_in-3600),await r.globalDataCache.deleteExpired())}return t},baidu.open.ocr={},baidu.open.ocr.business_license=async function(e={}){let{image:t,url:n}=e;return await baidu.open.request({...e,action:"ocr/v1/business_license",actionVersion:"2.0",data:{image:t,url:n}})},baidu.open.ocr.idcard=async function(e={}){let{image:t,url:n,id_card_side:i,detect_risk:a,detect_photo:r}=e;return await baidu.open.request({...e,action:"ocr/v1/idcard",actionVersion:"2.0",data:{image:t,url:n,id_card_side:i,detect_risk:a,detect_photo:r}})},baidu.open.request=async function(e={}){let{vk:t}=util$a,n=await baidu.open.auth.getAccessToken(e);if(!n)return{code:-1,msg:"获取access_token失败,请检查vk-unicloud配置下vk.service.openapi.baidu配置的appid和appsecret是否正确"};let{action:i,actionVersion:a="2.0",header:r={"content-type":"application/x-www-form-urlencoded"},data:o}=e,s=await t.request({url:`https://aip.baidubce.com/rest/${a}/${i}?access_token=${n}`,method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},data:o});return s.error_code?{code:s.error_code,msg:s.error_msg,err:s}:{...s,code:0,msg:"ok"}};var baidu_1=baidu,douyin={},util$b={};const serviceUrl$1="https://developer.toutiao.com",configKey$1="mp-toutiao.oauth.toutiao";function returnRes$1(e){return e.code=e.err_no||0,e.msg=e.err_tips||"",e}douyin.init=function(e){util$b=e},douyin.getConfig=function(){let{vk:e,config:t}=util$b;return e.pubfn.getUniIdConfig(t)},douyin.request=async function(e={}){let{vk:t}=util$b,{url:n,data:i={}}=e,{appid:a,appsecret:r}=douyin.auth.getAppidInfo(e);if(!0===i.access_token){let t=await douyin.auth.getAccessToken(e);if(!t)return{code:-1,msg:`获取access_token失败,请检查uni-id配置${configKey$1}配置下的appid和appsecret是否正确`};i.access_token=t}-1===n.indexOf("http")&&(n=`${serviceUrl$1}/${n}`);let o=await t.request({contentType:"json",dataType:"json",...e,url:n});return o=returnRes$1(o),o},douyin.auth={},douyin.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$b;const r=douyin.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.toutiao.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};if(t=r.appid,n=r.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",e),new Error(`你使用了多小程序登录模式,但未找到${t}对应的 appsecret 请先在 uni-config-center/vk-unicloud/index.js 中配置抖音小程序(vk.oauth.toutiao.list)的appid和appsecret`)}}else{let e=i.pubfn.getData(r,configKey$1)||{};if(t=e.appid,n=e.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error(`请先在 uni-config-center/uni-id/config.json 中配置抖音小程序(${configKey$1})的appid和appsecret`)}return{appid:t,appsecret:n}},douyin.auth.getAccessTokenFn=async function(e={}){let{appid:t,appsecret:n}=douyin.auth.getAppidInfo(e),{vk:i,config:a}=util$b,r=await i.request({url:serviceUrl$1+"/api/apps/v2/token",method:"POST",data:{appid:t,secret:n,grant_type:"client_credential"},contentType:"json",dataType:"json"});return r.err_no?(console.error("getAccessToken失败:",r),{code:r.err_no,msg:r.err_tips,err:r}):{code:0,msg:"ok",access_token:r.data.access_token,expires_in:r.data.expires_in}},douyin.auth.getAccessToken=async function(e={}){let t,{appid:n,appsecret:i}=douyin.auth.getAppidInfo(e),{cache:a=!0}=e,{vk:r}=util$b,o="mp-toutiao-access_token-"+n;if(a&&(t=await r.globalDataCache.get(o)),r.pubfn.isNull(t)){let n=await douyin.auth.getAccessTokenFn(e);0===n.code&&(t=n.access_token,await r.globalDataCache.set(o,t,240),await r.globalDataCache.deleteExpired())}return t},douyin.auth.code2Session=async function(e={}){let{vk:t,uniID:n}=util$b,{platform:i,needKey:a=!1}=e;i||(i="mp-toutiao");let r=await douyin.auth.code2SessionMp(e);try{let e=t.crypto.aes.encrypt({data:r});r.encryptedKey=e}catch(e){}return a||(delete r.sessionKey,delete r.accessToken,delete r.refreshToken),delete r.appsecret,r.platform=i,r},douyin.auth.code2SessionMp=async function(e={}){let{appid:t,appsecret:n}=douyin.auth.getAppidInfo(e),i=e.code||e.js_code,a=e.anonymousCode,{vk:r}=util$b,o=await douyin.request({url:"api/apps/v2/jscode2session",method:"POST",data:{appid:t,secret:n,code:i,anonymous_code:a}});return o.code?(40018!==o.code&&40019!==o.code||(o.msg="无效code,请重新获取"),o):{...r.pubfn.snake2camelJson(o.data),appid:t,appsecret:n,code:0,msg:"ok"}},douyin.security={},douyin.security.msgSecCheck=async function(e={}){let{content:t,tasks:n}=e,{appid:i,appsecret:a}=douyin.auth.getAppidInfo(e),r=await douyin.auth.getAccessToken(e);if(!r)return{code:-1,msg:`获取access_token失败,请检查uni-id配置${configKey$1}配置下的appid和appsecret是否正确`};n||(n=[{content:t}]);let o=await douyin.request({url:"api/v2/tags/text/antidirt",method:"POST",header:{"X-Token":r},data:{tasks:n}});try{let e,t;o.data.map((n,i)=>{n.predicts.map((n,a)=>{n.hit&&(e||(e=!0,t=i))})}),e?(o.taskIndex=t,o.code=87014):o.code=0}catch(e){}return 40001===o.code&&(o.msg="access_token错误"),87014===o.code&&(o.msg="内容含有违法违规内容,请检查!"),0===o.code&&(o.msg="ok"),o},douyin.security.imgSecCheck=async function(e={}){let{image:t,access_token:n=!0}=e,i=e.base64||e.image_data,{appid:a,appsecret:r}=douyin.auth.getAppidInfo(e);if(i){let e=i.indexOf("base64,");e>-1&&(i=i.substring(e+"base64,".length))}let o=await douyin.request({url:"api/apps/censor/image",method:"POST",data:{app_id:a,access_token:n,image:t,image_data:i}});try{let e;o.predicts.map((t,n)=>{t.hit&&(e=!0)}),o.code=e?87014:0}catch(e){}return 87014===o.code&&(o.msg="内容含有违法违规内容,请检查!"),0===o.code&&(o.msg="ok"),o},douyin.acode={},douyin.acode.getMiniCode=async function(e={}){let{path:t,appname:n="douyin",width:i,line_color:a,background:r,set_icon:o,access_token:s=!0}=e,{appid:u,appsecret:l}=douyin.auth.getAppidInfo(e),c=await douyin.request({url:"api/apps/qrcode",method:"POST",data:{access_token:s,appname:n,path:t,width:i,line_color:a,background:r,set_icon:o},dataType:"default",useContent:!0,header:{"content-type":"application/json;charset=utf8"}});if(c.length<500){let e=c.toString();try{return e=JSON.parse(e),{code:e.errcode,msg:e.errmsg}}catch(e){}return{code:-1,err:err}}return c},douyin.subscribeMessage={},douyin.subscribeMessage.send=async function(e={}){let{touser:t,template_id:n,page:i,data:a,access_token:r=!0}=e,{appid:o,appsecret:s}=douyin.auth.getAppidInfo(e);return await douyin.request({url:"api/apps/subscribe_notification/developer/v1/notify",method:"POST",data:{access_token:r,app_id:o,tpl_id:n,open_id:t,data:a,page:i}})};var douyin_1=douyin,qq={},util$c={};const serviceUrl$2="https://api.q.qq.com",configKey$2="mp-qq.oauth.qq";function returnRes$2(e){return e.code=e.errcode||e.errCode||0,e.msg=e.errmsg||e.errMsg||"",e}qq.init=function(e){util$c=e},qq.getConfig=function(){let{vk:e,config:t}=util$c;return e.pubfn.getUniIdConfig(t)},qq.request=async function(e={}){let{vk:t}=util$c,{url:n,method:i,data:a={}}=e;if(-1===n.indexOf("http")&&(n=`${serviceUrl$2}/${n}`),!0===a.access_token){delete a.access_token;let t=await qq.auth.getAccessToken(e);if(!t)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-qq配置的appid和appsecret是否正确"};n+=-1===n.indexOf("?")?"?":"&",n+="access_token="+t}let r=await t.request({...e,url:n});return r=returnRes$2(r),r},qq.auth={},qq.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$c;const r=qq.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.qq.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};if(t=r.appid,n=r.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",e),new Error(`你使用了多小程序登录模式,但未找到${t}对应的 appsecret 请先在 uni-config-center/vk-unicloud/index.js 中配置QQ小程序(vk.oauth.qq.list)的appid和appsecret`)}}else{let e=i.pubfn.getData(r,configKey$2)||{};if(t=e.appid,n=e.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error("请先在 uni-config-center/uni-id/config.json 中配置QQ小程序(mp-qq.oauth.qq)的appid和appsecret")}return{appid:t,appsecret:n}},qq.auth.getAccessTokenFn=async function(e={}){let{appid:t,appsecret:n}=qq.auth.getAppidInfo(e),{vk:i,config:a}=util$c,r=await i.request({url:`https://api.q.qq.com/api/getToken?grant_type=client_credential&appid=${t}&secret=${n}`,method:"GET"});return r.errcode?(console.error("getAccessToken失败:",r),{code:r.errcode,msg:r.errmsg,err:r}):{code:0,msg:"ok",access_token:r.access_token,expires_in:r.expires_in}},qq.auth.getAccessToken=async function(e={}){let t,{appid:n,appsecret:i}=qq.auth.getAppidInfo(e),{cache:a=!0}=e,{vk:r}=util$c,o="mp-qq-access_token-"+n;if(a&&(t=await r.globalDataCache.get(o)),r.pubfn.isNull(t)){let n=await qq.auth.getAccessTokenFn(e);0===n.code&&(t=n.access_token,await r.globalDataCache.set(o,t,240),await r.globalDataCache.deleteExpired())}return t},qq.auth.code2Session=async function(e={}){let{vk:t,uniID:n}=util$c,{platform:i,needKey:a=!1}=e;i||(i="mp-qq");let r=await qq.auth.code2SessionMpWeixin(e);try{let e=t.crypto.aes.encrypt({data:r});r.encryptedKey=e}catch(e){}return a||(delete r.sessionKey,delete r.accessToken,delete r.refreshToken),delete r.appsecret,r.platform=i,r},qq.auth.code2SessionMpWeixin=async function(e={}){let{appid:t,appsecret:n}=qq.auth.getAppidInfo(e),i=e.code||e.js_code,{vk:a}=util$c,r=await qq.request({url:`sns/jscode2session?appid=${t}&secret=${n}&js_code=${i}&grant_type=authorization_code`,method:"GET"});return r.code?(-101600007===r.code&&(r.msg="appid错误"),-101222100===r.code&&(r.msg="appsecret错误"),-2100===r.code&&(r.msg="无效code,请重新获取"),r):(r=a.pubfn.snake2camelJson(r),{appid:t,appsecret:n,...r,code:0,msg:"ok"})},qq.security={},qq.security.msgSecCheck=async function(e={}){let{content:t,access_token:n=!0}=e,{appid:i,appsecret:a}=qq.auth.getAppidInfo(e),r=await qq.request({url:"api/json/security/MsgSecCheck",method:"POST",data:{access_token:n,appid:i,content:t}});return 40001===r.code&&(r.msg="access_token错误"),87014===r.code&&(r.msg="内容含有违法违规内容,请检查!"),r},qq.security.imgSecCheck=async function(e={}){let{vk:t}=util$c,{dataBuffer:n,formData:i,base64:a}=e,{appid:r,appsecret:o}=qq.auth.getAppidInfo(e),s=await qq.auth.getAccessToken(e);if(!s)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-qq配置的appid和appsecret是否正确"};if(a&&!n){let e="base64,",t=a.indexOf(e);t>-1&&(a=a.substring(t+e.length)),n=new Buffer(a,"base64")}n&&!i&&(i=new t.formDataUtil.FormData,i.append("appid",r),i.append("media",n,{filename:Date.now()+".png",contentType:"image/png"}));let u=await qq.request({url:"api/json/security/ImgSecCheck?access_token="+s,content:i.getBuffer(),headers:i.getHeaders()});switch(u.code){case 40001:u.msg="access_token错误";break;case 87014:u.msg="图片内容含有违法违规内容,请检查!";break;case 40006:u.msg="图片大小不能超过1M"}return u},qq.acode={},qq.acode.getMiniCode=async function(e={}){let{path:t,access_token:n=!0}=e,{appid:i,appsecret:a}=qq.auth.getAppidInfo(e),r=await qq.request({url:"api/json/qqa/CreateMiniCode",method:"POST",data:{access_token:n,appid:i,path:t},dataType:"default",useContent:!0,header:{"content-type":"application/json;charset=utf8"}});if(r.length<500){let e=r.toString();try{e=JSON.parse(e)}catch(e){}return r=returnRes$2(e),40001===r.code&&(r.msg="access_token错误"),41030===r.code&&(r.msg="小程序页面不存在!"),r}return r},qq.subscribeMessage={},qq.subscribeMessage.send=async function(e={}){let{vk:t}=util$c,{touser:n,template_id:i,page:a,data:r,emphasis_keyword:o,oac_appid:s,use_robot:u}=e,l=await qq.auth.getAccessToken(e);if(!l)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-qq配置的appid和appsecret是否正确"};let c=await t.request({url:`${serviceUrl$2}/api/json/subscribe/SendSubscriptionMessage?access_token=${l}`,method:"POST",data:{touser:n,template_id:i,page:a,data:r,emphasis_keyword:o,oac_appid:s,use_robot:u},useContent:!0,header:{"content-type":"application/json;charset=utf8"}});switch(c=returnRes$2(c),c.code){case 40003:c.msg="touser字段openid为空或者不正确";break;case 40037:c.msg="订阅模板id为空不正确";break;case 43101:c.msg="用户未订阅该消息";break;case 40036:c.msg="您的小程序不支持发送长期订阅消息";break;case 47003:c.msg="模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错";break;case 41030:c.msg="page路径不正确,需要保证在现网版本小程序中存在"}return c};var qq_1=qq,weixin={},util$d={};function returnRes$3(e){return e.code=e.errcode||0,e.msg=e.errmsg||"",e}weixin.init=function(e){util$d=e},weixin.getConfig=function(){let{vk:e,config:t}=util$d;return e.pubfn.getUniIdConfig(t)},weixin.request=async function(e={}){let{vk:t}=util$d,{url:n,method:i,data:a,access_token:r}=e;if(r||(r=await weixin.auth.getAccessToken(e)),!r)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};-1===n.indexOf("http")&&(n="https://api.weixin.qq.com/"+n),i||(i=t.pubfn.isNull(a)?"GET":"POST"),i&&"POST"===i.toUpperCase()&&void 0===e.useContent&&(e.useContent=!0),n+=-1===n.indexOf("?")?"?":"&",n+="access_token="+r;let o=await t.request({...e,url:n});return o=returnRes$3(o),o},weixin.decrypt={},weixin.decrypt.getPhoneNumber=async function(e={}){let{vk:t}=util$d,{code:n}=e;if(!n&&e.encryptedData)return await weixin.decrypt.getPhoneNumberByEncryptedData(e);let i={code:0,msg:"ok"},a=t.pubfn.isNullOneByObject({code:n});if(a)return{code:-1,msg:a+"不能为空"};let r=await t.openapi.weixin.request({method:"POST",url:"wxa/business/getuserphonenumber",data:{code:n}});return 0!==r.code?r:(i.data=r.phone_info,i.phone=i.data.phoneNumber,i.mobile=i.data.phoneNumber,i)},weixin.decrypt.getPhoneNumberByEncryptedData=async function(e={}){let t,{vk:n}=util$d,{encryptedData:i,iv:a,sessionKey:r,encryptedKey:o,code:s}=e,u={code:0,msg:"ok"},l=n.pubfn.isNullOneByObject({encryptedData:i,iv:a});if(l)return{code:-1,msg:l+"不能为空"};if(o){let e=n.crypto.aes.decrypt({data:o});t=e.appid,r=e.sessionKey}else{t=weixin.auth.getAppidInfo(e).appid}return u.data=weixin.decrypt.decryptData({appid:t,encryptedData:i,iv:a,sessionKey:r}),u.phone=u.data.phoneNumber,u.mobile=u.data.phoneNumber,u},weixin.decrypt.decryptData=function(e={}){let t,{appid:n,encryptedData:i,iv:a,sessionKey:r}=e,{vk:o,crypto:s}=util$d,u=new Buffer(r,"base64"),l=new Buffer(i,"base64"),c=new Buffer(a,"base64");try{let e=s.createDecipheriv("aes-128-cbc",u,c);e.setAutoPadding(!0),t=e.update(l,"binary","utf8"),t+=e.final("utf8"),t=JSON.parse(t)}catch(e){throw new Error(e)}return t.watermark.appid!==n?{code:-1,msg:"appid不一致"}:t},weixin.auth={},weixin.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$d;const r=weixin.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.weixin.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};if(t=r.appid,n=r.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",e),new Error(`你使用了多小程序登录模式,但未找到${t}对应的 appsecret 请先在 uni-config-center/vk-unicloud/index.js 中配置微信小程序(vk.oauth.weixin.list)的appid和appsecret`)}}else{let e=i.pubfn.getData(r,"mp-weixin.oauth.weixin")||{};if(t=e.appid,n=e.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error("请先在 uni-config-center/uni-id/config.json 中配置微信小程序(mp-weixin)的appid和appsecret")}return{appid:t,appsecret:n}},weixin.auth.getAccessTokenFn=async function(e={}){let{appid:t,appsecret:n}=weixin.auth.getAppidInfo(e),{vk:i,config:a}=util$d,r=await i.request({url:`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${t}&secret=${n}`,method:"GET"});return r.errcode?(console.error("getAccessToken失败:",r),{code:r.errcode,msg:r.errmsg,err:r}):{code:0,msg:"ok",access_token:r.access_token,expires_in:r.expires_in}},weixin.auth.getAccessToken=async function(e={}){let t,{appid:n,appsecret:i}=weixin.auth.getAppidInfo(e),{cache:a=!0}=e,{vk:r}=util$d,o="mp-weixin-"+n;if(a&&(t=await r.globalDataCache.get(o)),r.pubfn.isNull(t)){let n=await weixin.auth.getAccessTokenFn(e);0===n.code&&(t=n.access_token,await r.globalDataCache.set(o,t,240),await r.globalDataCache.deleteExpired())}return t},weixin.auth.code2Session=async function(e={}){let t,{vk:n,uniID:i}=util$d,{platform:a,context:r,needKey:o=!1}=e;a||(a=n.pubfn.getPlatformForUniId(r)||"mp-weixin"),t="mp-weixin"===a?await weixin.auth.code2SessionMpWeixin(e):"h5-weixin"===a?await weixin.h5.auth.code2Session(e):await i.code2SessionWeixin(e);try{let e=n.crypto.aes.encrypt({data:t});t.encryptedKey=e}catch(e){}return o||(delete t.sessionKey,delete t.accessToken,delete t.refreshToken),delete t.appsecret,t.platform=a,t},weixin.auth.code2SessionMpWeixin=async function(e={}){let{appid:t,appsecret:n}=weixin.auth.getAppidInfo(e),i=e.code||e.js_code,{vk:a}=util$d,r=await a.request({url:`https://api.weixin.qq.com/sns/jscode2session?appid=${t}&secret=${n}&js_code=${i}&grant_type=authorization_code`,method:"GET"});if(r.errcode){let e=r.errmsg;return 40163===r.errcode&&(e="该code已被使用,请重新获取"),40029===r.errcode&&(e="无效code,请重新获取"),{...r,code:r.errcode,msg:e}}return r=a.pubfn.snake2camelJson(r),{appid:t,appsecret:n,...r,code:0,msg:"ok"}},weixin.wxacode={},weixin.wxacode.getUnlimited=async function(e={}){let{vk:t}=util$d,{access_token:n,page:i,scene:a,check_path:r,env_version:o,width:s,auto_color:u,line_color:l,is_hyaline:c}=e;if(n||(n=await weixin.auth.getAccessToken(e)),!n)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let d=await t.request({url:"https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+n,method:"POST",data:{page:i,scene:a,check_path:r,env_version:o,width:s,auto_color:u,line_color:l,is_hyaline:c},dataType:"default",useContent:!0,headers:{encoding:null}});if(d.length<500){let e=d.toString();try{e=JSON.parse(e)}catch(e){}return d=returnRes$3(e),40001===d.code&&(d.msg="access_token错误"),41030===d.code&&(d.msg="小程序页面不存在!"),d}return Buffer.isBuffer(d)?d:returnRes$3(d)},weixin.urlscheme={},weixin.urlscheme.generate=async function(e={}){let{vk:t}=util$d,{access_token:n,jump_wxa:i,is_expire:a,expire_time:r,expire_type:o,expire_interval:s}=e;if(n||(n=await weixin.auth.getAccessToken(e)),!n)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let u=await t.request({url:"https://api.weixin.qq.com/wxa/generatescheme?access_token="+n,method:"POST",data:{jump_wxa:i,is_expire:a,expire_time:r,expire_type:o,expire_interval:s},useContent:!0});return u=returnRes$3(u),40001===u.code&&(u.msg="access_token错误"),40165===u.code&&(u.msg="小程序页面不存在!"),u},weixin.urllink={},weixin.urllink.generate=async function(e={}){let{vk:t}=util$d,{access_token:n,path:i,query:a,is_expire:r,expire_type:o,expire_time:s,expire_interval:u,cloud_base:l,env_version:c}=e;if(n||(n=await weixin.auth.getAccessToken(e)),!n)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let d=await t.request({url:"https://api.weixin.qq.com/wxa/generate_urllink?access_token="+n,method:"POST",data:{path:i,query:a,is_expire:r,expire_type:o,expire_time:s,expire_interval:u,cloud_base:l,env_version:c},useContent:!0});return d=returnRes$3(d),40001===d.code&&(d.msg="access_token错误"),40165===d.code&&(d.msg="小程序页面不存在!"),d},weixin.security={},weixin.security.msgSecCheck=async function(e={}){let{vk:t}=util$d,{content:n,version:i,scene:a,openid:r,title:o,nickname:s,signature:u}=e,l=await weixin.auth.getAccessToken(e);if(!l)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let c=await t.request({url:"https://api.weixin.qq.com/wxa/msg_sec_check?access_token="+l,method:"POST",data:{content:n,version:i,scene:a,openid:r,title:o,nickname:s,signature:u},useContent:!0});return c=returnRes$3(c),40001===c.code&&(c.msg="access_token错误"),87014===c.code&&(c.msg="内容含有违法违规内容,请检查!"),2===i&&c.result&&100!==c.result.label&&(c.code=c.result.label,c.msg="内容含有违法违规内容,请检查!"),c},weixin.security.imgSecCheck=async function(e={}){let{vk:t}=util$d,{dataBuffer:n,formData:i,base64:a}=e,r=await weixin.auth.getAccessToken(e);if(!r)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};if(a&&!n){let e="base64,",t=a.indexOf(e);t>-1&&(a=a.substring(t+e.length)),n=new Buffer(a,"base64")}n&&!i&&(i=new t.formDataUtil.FormData,i.append("media",n,{filename:Date.now()+".png",contentType:"image/png"}));let o=await t.request({url:"https://api.weixin.qq.com/wxa/img_sec_check?access_token="+r,content:i.getBuffer(),headers:i.getHeaders()});switch(o=returnRes$3(o),o.code){case 40001:o.msg="access_token错误";break;case 87014:o.msg="图片内容含有违法违规内容,请检查!";break;case 40006:o.msg="图片大小不能超过1M"}return o},weixin.riskControl={},weixin.riskControl.getUserRiskRank=async function(e={}){let{vk:t}=util$d,{appid:n,openid:i,scene:a,mobile_no:r,client_ip:o,email_address:s,extended_info:u,is_test:l}=e,c=await weixin.auth.getAccessToken(e);if(!c)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let d=await t.request({url:"https://api.weixin.qq.com/wxa/getuserriskrank?access_token="+c,method:"POST",data:{appid:n,openid:i,scene:a,mobile_no:r,client_ip:o,email_address:s,extended_info:u,is_test:l},useContent:!0});return d=returnRes$3(d),40001===d.code&&(d.msg="access_token错误"),d},weixin.subscribeMessage={},weixin.subscribeMessage.send=async function(e={}){let{vk:t}=util$d,{touser:n,template_id:i,page:a,data:r,miniprogram_state:o="formal",lang:s="zh_CN"}=e,u=await weixin.auth.getAccessToken(e);if(!u)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let l=await t.request({url:"https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token="+u,method:"POST",data:{touser:n,template_id:i,page:a,data:r,miniprogram_state:o,lang:s},useContent:!0});switch(l=returnRes$3(l),l.code){case 40003:l.msg="touser字段openid为空或者不正确";break;case 40037:l.msg="订阅模板id为空不正确";break;case 43101:l.msg="用户未订阅该消息";break;case 47003:l.msg="模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错";break;case 41030:l.msg="page路径不正确,需要保证在现网版本小程序中存在"}return l},weixin.uniformMessage={},weixin.uniformMessage.send=async function(e={}){let{vk:t}=util$d,{appid:n,touser:i,template_appid:a,template_id:r,url:o,miniprogram:s,data:u}=e,l=await weixin.auth.getAccessToken(e);if(!l)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};if(!a){a=weixin.h5.auth.getAppidInfo({appid:a}).appid}let c=await t.request({url:"https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token="+l,method:"POST",data:{touser:i,mp_template_msg:{appid:a,template_id:r,url:o,miniprogram:s,data:u}},useContent:!0});switch(c=returnRes$3(c),c.code){case 40003:c.msg="touser字段openid为空或者不正确";break;case 40037:c.msg="订阅模板id为空不正确";break;case 43101:c.msg="用户未订阅该消息";break;case 47003:c.msg="模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错";break;case 41030:c.msg="page路径不正确,需要保证在现网版本小程序中存在"}return c},weixin.livebroadcast={},weixin.livebroadcast.getLiveInfo=async function(e={}){let{vk:t}=util$d,{pageIndex:n=1,pageSize:i=100}=e,a=await weixin.auth.getAccessToken(e);if(!a)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};if(n<=0)return{code:-1,msg:"pageIndex必须是大于0的整数"};let r=(n-1)*i,o=i,s=await t.request({url:"https://api.weixin.qq.com/wxa/business/getliveinfo?access_token="+a,method:"POST",data:{start:r,limit:o},useContent:!0});switch(s=returnRes$3(s),s.code){case 941e4:s.msg="直播间列表为空"}return s},weixin.app={},weixin.app.auth={},weixin.app.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$d;const r=weixin.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.weixin.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};t=r.appid,n=r.appsecret}}else{let e=i.pubfn.getData(r,"app-plus.oauth.weixin")||{};t=e.appid,n=e.appsecret}if(i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error("请先在 uni-config-center/uni-id/config.json 中配置微信app登录(app-plus)的appid和appsecret");return{appid:t,appsecret:n}},weixin.app.auth.getAccessToken=async function(e={}){let{appid:t,appsecret:n}=weixin.app.auth.getAppidInfo(e),{vk:i,config:a}=util$d,{code:r}=e,o=await i.request({url:`https://api.weixin.qq.com/sns/oauth2/access_token?appid=${t}&secret=${n}&code=${r}&grant_type=authorization_code`,method:"GET"});return o.errcode?(console.error("getAccessToken失败:",o),{code:o.errcode,msg:o.errmsg,err:o}):{...o,code:0,msg:"ok"}},weixin.app.auth.getUserInfo=async function(e={}){let{vk:t,config:n}=util$d,{access_token:i,openid:a,lang:r="zh-CN"}=e;if(!i)return{code:-1,msg:"access_token不能为空"};let o=await t.request({url:`https://api.weixin.qq.com/sns/userinfo?access_token=${i}&openid=${a}$lang=${r}`,method:"GET"});return o.errcode?(console.error("getUserInfo失败:",o),{code:o.errcode,msg:o.errmsg,err:o}):{...o,code:0,msg:"ok",avatar:o.headimgurl,gender:o.sex}},weixin.h5={},weixin.h5.request=async function(e={}){let{vk:t}=util$d,{url:n,method:i,data:a,access_token:r}=e;if(r||(r=await weixin.h5.auth.getAccessToken(e)),!r)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的h5-weixin配置的appid和appsecret是否正确"};-1===n.indexOf("http")&&(n="https://api.weixin.qq.com/"+n),i||(i=t.pubfn.isNull(a)?"GET":"POST"),i&&"POST"===i.toUpperCase()&&void 0===e.useContent&&(e.useContent=!0),n+=-1===n.indexOf("?")?"?":"&",n+="access_token="+r;let o=await t.request({...e,url:n});return o=returnRes$3(o),o},weixin.h5.auth={},weixin.h5.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$d;const r=weixin.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.weixin.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};t=r.appid,n=r.appsecret}}else{let e=i.pubfn.getData(r,"h5-weixin.oauth.weixin")||{};t=e.appid,n=e.appsecret}if(i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error("请先配置微信公众号appid和appsecret");return{appid:t,appsecret:n}},weixin.h5.auth.code2Session=async function(e={}){let{appid:t,appsecret:n}=weixin.h5.auth.getAppidInfo(e),{code:i}=e,{vk:a}=util$d,r=await a.request({url:`https://api.weixin.qq.com/sns/oauth2/access_token?appid=${t}&secret=${n}&code=${i}&grant_type=authorization_code`,method:"GET"});if(r.errcode){let e=r.errmsg;return 40163===r.errcode&&(e="该code已被使用,请重新获取"),40029===r.errcode&&(e="无效code,请重新获取"),{...r,code:r.errcode,msg:e}}return r=a.pubfn.snake2camelJson(r),{appid:t,appsecret:n,...r,code:0,msg:"ok"}},weixin.h5.auth.getAccessToken=async function(e={}){let t,{appid:n,appsecret:i}=weixin.h5.auth.getAppidInfo(e),{cache:a=!0}=e,{vk:r}=util$d,o="h5-weixin-"+n;if(a&&(t=await r.globalDataCache.get(o)),r.pubfn.isNull(t)){let n=await weixin.h5.auth.getAccessTokenFn(e);if(0===n.code)t=n.access_token,await r.globalDataCache.set(o,t,240),await r.globalDataCache.deleteExpired();else if(console.log("获取微信公众号access_token失败:",n),40164===n.code)throw{code:n.code,msg:"请将固定IP全部加入微信公众号IP白名单,详见搜索文档:固定ip",err:n}}return t},weixin.h5.auth.getAccessTokenFn=async function(e={}){let t,{appid:n,appsecret:i}=weixin.h5.auth.getAppidInfo(e),{vk:a,config:r}=util$d;if("aliyun"===a.pubfn.getUniCloudProvider()){let e=await uniCloud.httpProxyForEip.get("https://api.weixin.qq.com/cgi-bin/token",{grant_type:"client_credential",appid:n,secret:i});if("string"==typeof e)try{e=JSON.parse(e)}catch(e){t={errcode:-1,errmsg:"异常"+e.message}}t="object"==typeof e?e.body:{errcode:-1,errmsg:"异常:getRes未获取到值"}}else t=await a.request({url:`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${n}&secret=${i}`,method:"GET"});return t.errcode?(console.error("getAccessToken失败:",t),{code:t.errcode,msg:t.errmsg,err:t}):{code:0,msg:"ok",access_token:t.access_token,expires_in:t.expires_in}},weixin.h5.subscribeMessage={},weixin.h5.subscribeMessage.send=async function(e={}){let{vk:t}=util$d,{touser:n,template_id:i,page:a,data:r,miniprogram:o}=e,s=await weixin.h5.auth.getAccessToken(e);if(!s)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的h5-weixin配置的appid和appsecret是否正确"};let u=await t.request({url:"https://api.weixin.qq.com/cgi-bin/message/subscribe/bizsend?access_token="+s,method:"POST",data:{touser:n,template_id:i,page:a,data:r,miniprogram:o},useContent:!0});switch(u=returnRes$3(u),u.code){case 40003:u.msg="touser字段openid为空或者不正确";break;case 40037:u.msg="订阅模板id为空不正确";break;case 43101:u.msg="用户未订阅该消息";break;case 47003:u.msg="模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错";break;case 41030:u.msg="page路径不正确,需要保证在现网版本小程序中存在"}return u},weixin.h5.templateMessage={},weixin.h5.templateMessage.send=async function(e={}){let{vk:t}=util$d,{touser:n,template_id:i,url:a,miniprogram:r,data:o}=e,s=await weixin.h5.auth.getAccessToken(e);if(!s)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的h5-weixin配置的appid和appsecret是否正确"};let u=await t.request({url:"https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+s,method:"POST",data:{touser:n,template_id:i,url:a,miniprogram:r,data:o},useContent:!0});switch(u=returnRes$3(u),u.code){case 40003:u.msg="touser字段openid为空或者不正确";break;case 40037:u.msg="订阅模板id为空不正确";break;case 43101:u.msg="用户未订阅该消息";break;case 47003:u.msg="模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错";break;case 41030:u.msg="page路径不正确,需要保证在现网版本小程序中存在"}return u},weixin.loginByWeixin=async function(e={},t,n){let i,a,r;e.context?(i=e.data||{},a=e.context,r=e.custom,e.appid&&(i.appid=e.appid),e.appsecret&&(i.appsecret=e.appsecret)):(i=e,a=t,r=n);let o,s,{vk:u,uniID:l,_:c}=util$d,{code:d,platform:p,type:f,appid:g}=i;if(p||(p=u.pubfn.getPlatformForUniId(a),i.platform=p),g&&["mp-weixin","h5-weixin","app-plus"].indexOf(p)>-1){let e;"mp-weixin"===p?e=weixin.auth.getAppidInfo(i):"h5-weixin"===p?e=weixin.h5.auth.getAppidInfo(i):"app-plus"===p&&(e=weixin.app.auth.getAppidInfo(i));let{appid:t,appsecret:n}=e,r=u.pubfn.copyObject(weixin.getConfig());u.pubfn.setData(r,p+".oauth.weixin",{appid:t,appsecret:n}),i.platform=p,s=l.createInstance({context:a,config:r})}s||(s=l);try{delete i.role,o=await s.loginByWeixin(i);try{if(o.uid&&!o.msg&&(o.msg="register"===o.type?"注册成功":"登录成功"),o.uid&&"register"===o.type){let e={},t={last_login_date:Date.now(),last_login_ip:a.CLIENTIP};if(["h5-weixin","app-plus"].indexOf(p)>-1){let t=await u.openapi.weixin.app.auth.getUserInfo({access_token:o.accessToken,openid:o.openid});e={nickname:t.nickname,avatar:t.headimgurl}}["mp-weixin"].indexOf(p)>-1&&(e={nickname:i.nickname,avatar:i.avatar}),u.pubfn.isNotNull(r)&&(e=u.pubfn.objectAssign(e,r)),u.pubfn.isNotNull(t)&&(e=u.pubfn.objectAssign(e,t)),u.pubfn.isNotNull(e)&&(o.userInfo=await u.baseDao.updateAndReturn({dbName:"uni-id-users",whereJson:{_id:o.uid||"___",nickname:c.exists(!1)},dataJson:e}))}}catch(e){console.error("保存用户头像昵称异常:",e)}if(0===o.code)try{let t=u.crypto.aes.encrypt({data:{code:0,sessionKey:o.sessionKey,openid:o.openid,unionid:o.unionid,uid:o.uid,accessToken:o.accessToken,accessTokenExpired:o.accessTokenExpired,refreshToken:o.refreshToken}});o.encryptedKey=t,e.needKey||(delete o.sessionKey,delete o.accessToken,delete o.refreshToken)}catch(e){}}catch(e){console.error("loginByWeixin异常:",e);let t=e.message||"";throw e.message.indexOf("code been used")>-1&&(t="该code已被使用,请重新获取"),e.message.indexOf("invalid code")>-1&&(t="无效code,请重新获取"),new Error("msg:"+t)}return o};var weixin_1=weixin,openapi={};openapi.alipay=alipay_1,openapi.baidu=baidu_1,openapi.douyin=douyin_1,openapi.qq=qq_1,openapi.weixin=weixin_1,openapi.init=function(e){openapi.alipay.init(e),openapi.baidu.init(e),openapi.douyin.init(e),openapi.qq.init(e),openapi.weixin.init(e)};var openapi_1=openapi,builder=class{constructor(){this._shouldUseCache=!1,this._cachedBuffer=null,this._lineBreak="\r\n",this._boundary="------FormDataBaseBoundary"+Math.random().toString(36).substring(2),this.dataList=[]}_addData(e){if(this._shouldUseCache=!1,0===this.dataList.length)return void this.dataList.push(e);const t=this.dataList[this.dataList.length-1];switch(`${Buffer.isBuffer(t)?"buffer":"other"}_${Buffer.isBuffer(e)?"buffer":"other"}`){case"buffer_buffer":this.dataList.push(this._lineBreak),this.dataList.push(e);break;case"buffer_other":this.dataList.push(this._lineBreak+e);break;case"other_buffer":this.dataList[this.dataList.length-1]=t+"\r\n",this.dataList.push(e);break;case"other_other":this.dataList[this.dataList.length-1]=t+"\r\n"+e}}append(e,t,n){this._addData("--"+this._boundary);let i=`Content-Disposition: form-data; name="${encodeURIComponent(e)}"`;if(Buffer.isBuffer(t)){if(!n.filename||!n.contentType)throw new Error("filename and contentType required");i+=`; filename="${encodeURIComponent(n.filename)}"`,this._addData(i),this._addData("Content-Type: "+n.contentType),this._addData(""),this._addData(t)}else this._addData(i),this._addData(""),this._addData(t)}getHeaders(e){const t={"Content-Type":"multipart/form-data; boundary="+this._boundary};return Object.assign(t,e)}getBuffer(){if(this._shouldUseCache)return this._cachedBuffer;this._shouldUseCache=!0;let e=Buffer.alloc(0);return this.dataList.forEach(t=>{e=Buffer.isBuffer(t)?Buffer.concat([e,t]):Buffer.concat([e,Buffer.from(""+t)])}),e=Buffer.concat([e,Buffer.from(`${this._lineBreak}--${this._boundary}--`)]),this._cachedBuffer=e,e}};const BOUNDARY_REG=/^multipart\/.+?(?:;\s*boundary=(?:(?:"(.+)")|(?:([^\s]+))))$/i,LEADING_REG=/Content-Disposition:\sform-data;\sname="(.+?)"(?:;\sfilename="(.+?)")?/i,TYPE_REG=/Content-Type:\s(.+?)$/i,lineBreak="\r\n";function split(e,t){let n=0,i=0,a=[];for(;-1!==(i=e.indexOf(t,n));)a.push(e.slice(n,i)),n=i+t.length,i=e.indexOf(t,n);return a}function readParam(e){let t=e.indexOf("\r\n")+"\r\n".length,n=t,i=e.lastIndexOf("\r\n"),a=[];for(;-1!==(n=e.indexOf("\r\n",t));)if(a.push(e.slice(t,n)),t=n+"\r\n".length,0===a[a.length-1].length){a.push(e.slice(t,i));break}return a}var parser=e=>{const t=(e.headers["content-type"]||e.headers["Content-Type"]).match(BOUNDARY_REG),n=t[1]||t[2],i=split(Buffer.from(e.body,"base64"),Buffer.from("--"+n)).map(e=>readParam(e).filter(e=>e.length>0)).filter(e=>2===e.length||3===e.length||4===e.length).map(e=>{const t={},n=e[0].toString().match(LEADING_REG);switch(t.name=decodeURIComponent(n[1]),e.length){case 2:t.value=e[1].toString();break;case 3:t.filename=decodeURIComponent(n[2]),t.contentType=e[1].toString().match(TYPE_REG)[1],t.fileContent=e[2];break;case 4:t.filename=decodeURIComponent(n[2]),t.contentType=e[1].toString().match(TYPE_REG)[1],t.fileContent=e[3]}return t}),a={};return i.forEach(e=>{const t=e.name;delete e.name,a[t]=e.fileContent?e:e.value}),a},formDataUtils={FormData:builder,formParser:parser};const dbName_role="uni-id-roles",dbName_menu="opendb-admin-menus",dbName_permission="uni-id-permissions";var dao={},util$e={};dao.init=function(e){util$e=e},dao.findRoleById=async(e="___")=>{let t,{vk:n,db:i,_:a}=util$e;return t=await n.baseDao.findByWhereJson({dbName:dbName_role,whereJson:{role_id:e}}),t},dao.roleBindPermission=async(e={})=>{let{vk:t,db:n,_:i}=util$e,a={code:0,msg:""},{role_id:r="___",permissionList:o=[],reset:s=!1}=e;if(!s){let e=await dao.findRoleById(r),{permission:t=[]}=e;o=t.concat(o),o=[...new Set(o)]}return a.num=await t.baseDao.update({dbName:dbName_role,whereJson:{role_id:r},dataJson:{permission:i.set(o)}}),a},dao.roleBindMenu=async(e={})=>{let{vk:t,db:n,_:i}=util$e,a={code:0,msg:""},{role_id:r="___",menuList:o=[],reset:s=!1,addPermission:u=!1}=e,l=[],c=await dao.findRoleById(r),{menu:d=[],permission:p=[]}=c;if(s?l=compareArray(o,d):(o=d.concat(o),o=[...new Set(o)]),a.num=await t.baseDao.update({dbName:dbName_role,whereJson:{role_id:r},dataJson:{menu:i.set(o)}}),u){let e=await dao.findMenuByIdsToPermission(o),n=[];if(s&&t.pubfn.isNotNull(l)){n=compareArray(e,await dao.findMenuByIdsToPermission(l))}p=p.concat(e),p=compareArray(n,p),p=[...new Set(p)],dao.roleBindPermission({role_id:r,permissionList:p,reset:!0})}return a},dao.findPermissionById=async(e="___")=>{let t,{vk:n,db:i,_:a}=util$e;return t=await n.baseDao.findByWhereJson({dbName:dbName_permission,whereJson:{permission_id:e}}),t},dao.findMenuByIdsToPermission=async e=>{let{vk:t,db:n,_:i}=util$e,a=await dao.findMenuByIds(e);if(t.pubfn.isNull(a))return[];let r=[];for(let e in a){let n=a[e].permission;t.pubfn.isNotNull(n)&&(r=r.concat(n))}return r=[...new Set(r)],r},dao.listPermissionToTree=async(e={})=>{let t,{vk:n,db:i,_:a}=util$e,{getCount:r=!1,pageSize:o=500,pageIndex:s=1,whereJson:u={parent_id:a.in([null,""])},sortArr:l=[{name:"sort",type:"asc"}],treeProps:c={}}=e,{level:d=3,limit:p=500,whereJson:f}=c;u&&!u.permission_id&&(u.permission_id=a.exists(!0)),t=await n.baseDao.selects({dbName:dbName_permission,pageIndex:s,pageSize:o,getCount:r,whereJson:u,sortArr:l,treeProps:{id:"permission_id",parent_id:"parent_id",children:"children",level:d,limit:p,whereJson:f,sortArr:l}});let g={id:"permission_id",parent_id:"parent_id",children:"children"},m=t.rows;m=n.pubfn.treeToArray(m,g),t.list=n.pubfn.copyObject(m);for(let e in m){let t=m[e],i="",a="";if(n.pubfn.isNotNull(t.level)){i=` - ${["未分类","子弹级","炸弹级","榴弹级","核弹级"][t.level]}(LV:${t.level})`}if(n.pubfn.isNotNull(t.curd_category)){a=" - "+["未分类","增","删","改","查","特殊"][t.curd_category]}m[e].label=`${t.permission_name}(${t.permission_id})${a}${i}`}return m=n.pubfn.arrayToTree(m,g),t.rows=m,t},dao.findMenuById=async(e="___")=>{let t,{vk:n,db:i,_:a}=util$e;return t=await n.baseDao.findByWhereJson({dbName:dbName_menu,whereJson:{menu_id:e}}),t},dao.findMenuByIds=async e=>{let t,{vk:n,db:i,_:a}=util$e;return n.pubfn.isNull(e)?[]:(t=(await n.baseDao.select({dbName:dbName_menu,pageIndex:1,pageSize:500,whereJson:{menu_id:a.in(e)}})).rows,t)},dao.listMenuByRole=async(e={})=>{let{vk:t,db:n,_:i}=util$e,a={code:0,msg:"",menus:[],menuList:[]},{role:r,treeProps:o={}}=e,s=[],u={enable:!0},l={enable:!0};if(!(r.indexOf("admin")>-1)){if(t.pubfn.isNull(r))return a;let e=await t.baseDao.select({dbName:dbName_role,pageSize:500,whereJson:{role_id:i.in(r),enable:!0},fieldJson:{menu:!0}});for(let n in e.rows){let{menu:i}=e.rows[n];t.pubfn.isNotNull(i)&&(s=s.concat(i))}if(0==s.length)return a;s=[...new Set(s)],u.menu_id=i.in(s),l.menu_id=i.in(s)}u.parent_id=i.in([null,""]);let c=[{name:"sort",type:"asc"}],{level:d=3,limit:p=500}=o,f=await t.baseDao.selects({dbName:dbName_menu,pageIndex:1,pageSize:500,whereJson:u,sortArr:c,treeProps:{id:"menu_id",parent_id:"parent_id",children:"children",level:d,limit:p,whereJson:l,sortArr:c}});return a.menus=f.rows,a.menuList=t.pubfn.treeToArray(f.rows,{id:"menu_id",parent_id:"parent_id",children:"children"}),a},dao.menuBindPermission=async(e={})=>{let{vk:t,db:n,_:i}=util$e,a={code:0,msg:""},{menu_id:r="___",permissionList:o=[],reset:s=!1}=e;if(!s){let e=await dao.findMenuById(r),{permission:t=[]}=e;o=t.concat(o),o=[...new Set(o)]}return a.num=await t.baseDao.update({dbName:dbName_menu,whereJson:{menu_id:r},dataJson:{permission:i.set(o)}}),a},dao.listMenuToTree=async(e={})=>{let t,{vk:n,db:i,_:a}=util$e,{getCount:r=!1,pageSize:o=500,pageIndex:s=1,whereJson:u={parent_id:a.in([null,""]),menu_id:a.exists(!0)},sortArr:l=[{name:"sort",type:"asc"}],treeProps:c={}}=e,{level:d=3,limit:p=500,whereJson:f}=c;u&&!u.menu_id&&(u.menu_id=a.exists(!0)),t=await n.baseDao.selects({dbName:dbName_menu,pageIndex:s,pageSize:o,getCount:r,whereJson:u,sortArr:l,treeProps:{id:"menu_id",parent_id:"parent_id",children:"children",level:d,limit:p,whereJson:f,sortArr:l}});let g={id:"menu_id",parent_id:"parent_id",children:"children"},m=t.rows;m=n.pubfn.treeToArray(m,g),t.list=n.pubfn.copyObject(m);for(let e in m){let t=m[e];m[e].label=`${t.name}(${t.menu_id})`}return m=n.pubfn.arrayToTree(m,g),t.rows=m,t};var sysDao=dao;function compareArray(e,t){let n=new Set(e);return t.filter(e=>!n.has(e))}const dbName="vk-global-data";var dao$1={},util$f={};dao$1.init=function(e){util$f=e},dao$1.find=async e=>{let{vk:t,db:n,_:i}=util$f,a={};return a=await t.baseDao.findById({dbName:dbName,id:e}),a},dao$1.del=async e=>{let{vk:t,db:n,_:i}=util$f,a={};return a=await t.baseDao.deleteById({dbName:dbName,id:e}),a},dao$1.deleteByWhere=async e=>{let{vk:t,db:n,_:i}=util$f,a={};return a=await t.baseDao.del({dbName:dbName,whereJson:e}),a},dao$1.deleteExpired=async e=>{let{vk:t,db:n,_:i}=util$f,a={},r={};"string"==typeof e?r._id=e:"object"==typeof e&&(r=e);let o=(new Date).getTime();return a=await t.baseDao.del({dbName:dbName,whereJson:{...r,expired_at:i.gt(0).lte(o)}}),a},dao$1.update=async e=>{let{vk:t,db:n,_:i}=util$f,a={},{key:r,value:o,comment:s,expired_at:u}=e;return a=await t.baseDao.updateById({dbName:dbName,id:r,dataJson:{value:i.set(o),comment:s,expired_at:u}}),a},dao$1.add=async e=>{let{vk:t,db:n,_:i}=util$f,a={},{key:r,value:o,comment:s,expired_at:u}=e;return a=await t.baseDao.add({dbName:dbName,dataJson:{_id:r,key:r,value:o,comment:s,expired_at:u}}),a},dao$1.count=async e=>{let{vk:t,db:n,_:i}=util$f,a={};return a=await t.baseDao.count({dbName:dbName,whereJson:e}),a},dao$1.set=async e=>{let{vk:t,db:n,_:i}=util$f,a={code:0,msg:"ok"},r=new Date;e._add_time=r.getTime(),e._add_time_str=t.pubfn.timeFormat(r,"yyyy-MM-dd hh:mm:ss");let o=await n.collection(dbName).doc(e.key).set(e);return o.upsertedId?(a.id=o.upsertedId,a.mode="add"):(a.mode="update",a.updated=o.updated),a.num=1,a},dao$1.inc=async e=>{let{vk:t,db:n,_:i}=util$f,{key:a,value:r,expired_at:o}=e,s={},u=await t.baseDao.updateById({dbName:dbName,id:a,dataJson:{value:i.inc(r),expired_at:o}});if(0==u){0===await dao$1.count({_id:a})&&(s.id=await dao$1.add(e),s.num=1,s.mode="add")}else s.num=u,s.mode="update";return s},dao$1.list=async e=>{let{vk:t,db:n,_:i}=util$f,a={},{pageIndex:r,pageSize:o,whereJson:s,sortArr:u}=e;return a=await t.baseDao.select({dbName:dbName,pageIndex:r,pageSize:o,whereJson:s,sortArr:u}),a};var globalDataDao$1=dao$1,util$g={},smsUtil={init:function(e){util$g=e}},aliyun={specialUrlEncode:function(e){return(e=encodeURIComponent(e)).replace(/\+/g,"%20").replace(/\*/g,"%2A").replace(/%7E/g,"~")},sign:function(e,t){let{crypto:n}=util$g;return n.createHmac("sha1",e).update(t).digest("base64")}};smsUtil.sendSms=async function(e){let{vk:t,config:n}=util$g,{provider:i,appid:a,smsKey:r,smsSecret:o,signName:s,phone:u,templateId:l,data:c}=e,d={};if("aliyun"===i){let i=t.pubfn.getData(n,"vk.service.sms.aliyun");t.pubfn.isNotNull(i)&&(r||(e.smsKey=i.accessKeyId),o||(e.smsSecret=i.accessKeySecret),s||(e.signName=i.signName)),d=await smsUtil.sendSmsByAliyun(e)}else{if("unicloud"!==i)return{code:-1,msg:`暂不支持${i}供应商`};{let i=t.pubfn.getUniIdConfig(n,"service.sms");t.pubfn.isNotNull(i)&&(r||(e.smsKey=i.smsKey),o||(e.smsSecret=i.smsSecret),s||(e.signName=i.signName)),d=await smsUtil.sendSmsByUnicloud(e)}}return d.requestParam={provider:i,phone:u},d},smsUtil.sendSmsByAliyun=async function(e){let{vk:t,config:n}=util$g,{provider:i,appid:a,smsKey:r,smsSecret:o,signName:s,phone:u,templateId:l,data:c}=e,d={code:0,msg:""};try{if(t.pubfn.isNullOne(r,o))return{code:-1,msg:"阿里云短信配置错误,请检查vk-unicloud配置下的vk.service.sms.aliyun配置的accessKeyId和accessKeySecret是否正确"};let e="https://dysmsapi.aliyuncs.com",n=t.pubfn.timeFormat(new Date,"yyyy-MM-ddThh:mm:ssZ",0),i=(new Date).getTime().toString().substring(7)+t.pubfn.random(30);"object"==typeof c&&(c=JSON.stringify(c));let a={SignatureMethod:"HMAC-SHA1",SignatureNonce:i,AccessKeyId:r,SignatureVersion:"1.0",Timestamp:n,Format:"json",Action:"SendSms",Version:"2017-05-25",PhoneNumbers:u,SignName:s,TemplateParam:c,TemplateCode:l};delete a.Signature;let p=[];for(let e in a)p.push(e);p.sort();let f=!1,g="";for(let e in p){let t=p[e];g+="&"+aliyun.specialUrlEncode(t)+"="+aliyun.specialUrlEncode(a[t])}g=g.substring(1);let m="GET&"+aliyun.specialUrlEncode("/")+"&"+aliyun.specialUrlEncode(g),b=aliyun.sign(o+"&",m),h=aliyun.specialUrlEncode(b),y="Signature="+h+"&"+g;f&&(console.log("\r\n随机数\r\n"),console.log(a.SignatureNonce),console.log("\r\n=========\r\n"),console.log(a.Timestamp),console.log("\r\n====sortedQueryString====\r\n"),console.log(g),console.log("\r\n=====stringToSign====\r\n"),console.log(m),console.log("\r\n=====sign====\r\n"),console.log(b),console.log("\r\n=====signature====\r\n"),console.log(h),console.log("\r\n=========\r\n"),console.log(e+"/?"+y));t.pubfn.urlStringToJson(y);let w=await t.request({url:`${e}?${y}`,method:"GET"});return d="OK"===w.Code?{code:0,msg:"ok",requestRes:w}:{code:-1,msg:w.Message,requestRes:w},d}catch(e){return{code:-1,msg:"短信发送失败",err:{message:e.message,stack:e.stack}}}},smsUtil.sendSmsByUnicloud=async function(e){let{vk:t,config:n}=util$g,{provider:i,appid:a,smsKey:r,smsSecret:o,signName:s,phone:u,templateId:l,data:c}=e,d={code:0,msg:""};try{if(t.pubfn.isNullOne(r,o))return{code:-1,msg:"unicloud短信配置错误,请检查uni-id配置下的service.sms配置的smsKey和smsSecret是否正确"};let e=await uniCloud.sendSms({smsKey:r,smsSecret:o,phone:u,templateId:l,data:c});d=0==e.code||0==e.errCode?{code:0,msg:"ok",requestRes:e}:{code:-1,msg:e.errMessage||e.errMsg,requestRes:e}}catch(e){return{code:-1,msg:"短信发送失败",err:{message:e.message,stack:e.stack}}}return d},smsUtil.sendSmsVerifyCode=async function(e){let t,{vk:n,config:i,uniID:a}=util$g,{provider:r,phone:o,code:s,type:u,expiresIn:l=180}=e,c={code:0,msg:""};if("unicloud"===r){t=n.pubfn.getUniIdConfig(i,"service.sms.templateId");let e=n.pubfn.getUniIdConfig(i,"service.sms.codeExpiresIn");e&&(l=e);let a=n.pubfn.getUniIdConfig(i,"service.sms.name"),u=Math.ceil(l/60).toString();c=await n.system.smsUtil.sendSms({provider:r,phone:o,templateId:t,data:{code:s,name:a,action:"身份验证",expMinute:u}})}else t=n.pubfn.getData(i,`vk.service.sms.${r}.templateCode.verifyCode`),c=await n.system.smsUtil.sendSms({provider:r,phone:o,templateId:t,data:{code:s}});return 0===c.code&&await a.setVerifyCode({mobile:o,code:s,expiresIn:l,type:u}),c};var smsUtil_1=smsUtil,system={};system.sysDao=sysDao,system.globalDataDao=globalDataDao$1,system.smsUtil=smsUtil_1,system.init=function(e){let t=["sysDao","globalDataDao","smsUtil"];for(let n in t){let i=t[n];"function"==typeof system[i].init&&system[i].init(e)}};var system_1=system,vkunicloud={};class VK{constructor(e){this.router=router,this.md5=md5,this.baseDao=vkBaseDao,this.request=vk_request,this.callFunction=vk_callFunction,this.pubfn=_function,this.temporaryCache=temporaryCache,this.globalDataCache=globalDataCache_1,this.crypto=crypto,this.openapi=openapi_1,this.formDataUtil=formDataUtils,this.system=system_1,this.baseDir=null,e&&this.init(e)}require(e){return vkunicloud.requireFn(this.baseDir+"/"+e)}requireFn(e){try{return vkunicloud.requireFn(e)}catch(e){let{message:t=""}=e;return void(-1==t.indexOf("Cannot find module")&&-1==t.indexOf("no such file or directory")&&console.error(e))}}use(e,t){for(let n in e)e[n]&&"function"==typeof e[n].init&&e[n].init(t),this[n]=e[n]}getGlobalObject(){return"object"==typeof globalThis?globalThis:"object"==typeof self?self:"object"==typeof window?window:"object"==typeof commonjsGlobal?commonjsGlobal:void 0}init(e={}){let t=this;if(e.requireFn&&(vkunicloud.requireFn=e.requireFn),e.baseDir&&(t.baseDir=e.baseDir),e.configCenter||(e.configCenter=t.requireFn("uni-config-center")),e.uniID||(e.uniID=t.requireFn("uni-id")),e.uniPay||(e.uniPay=t.requireFn("uni-pay")),e.middlewareService||(e.middlewareService=t.requireFn("./middleware/index")),e.daoCenter||(e.daoCenter=t.requireFn("./dao/index")),e.crypto||(e.crypto=t.requireFn("crypto")),e.urlrewrite||(e.urlrewrite=t.requireFn("./util/urlrewrite")),e.config||(e.config=e.configCenter({pluginId:"vk-unicloud"}).requireFile("index.js")),!e.config)throw new Error("配置文件:uniCloud/cloudfunctions/common/uni-config-center/vk-unicloud/index.js \n编译错误,请检查!");if(!e.db)try{e.db=uniCloud.database()}catch(e){}if(t.vkPay=t.requireFn("vk-uni-pay"),e.pubFun||(e.pubFun=t.requireFn("./util/pubFunction")),e.pubFun&&(t.myfn=e.pubFun),e.redis||(e.redis=t.requireFn("vk-redis")),e.redis)t.redisUtil=e.redis,t.redis=e.redis.redis,t.newRedis=e.redis.newRedis;else try{t.redis=uniCloud.redis}catch(e){}e.uniMap||(e.uniMap=t.requireFn("uni-map-common")),e.uniMap&&(t.uniMap=e.uniMap),e.db&&(vkunicloud.db=e.db,vkunicloud._=e.db.command),vkunicloud.pubfn=t.pubfn,e.configCenter&&(vkunicloud.configCenter=e.configCenter),e.config&&(vkunicloud.config=e.config),e.uniID&&(vkunicloud.uniID=e.uniID),e.uniPay&&(vkunicloud.uniPay=e.uniPay),e.middlewareService&&(vkunicloud.middlewareService=e.middlewareService),e.pubFun&&(vkunicloud.pubFun=e.pubFun),e.customUtil&&(vkunicloud.customUtil=e.customUtil),e.crypto&&(vkunicloud.crypto=e.crypto),e.urlrewrite&&(vkunicloud.urlrewrite=e.urlrewrite);const n={vk:t,...vkunicloud};t.use({daoCenter:e.daoCenter,baseDao:t.baseDao,openapi:t.openapi,globalDataCache:t.globalDataCache,system:t.system,pubFun:e.pubFun},n);try{let n=t.getGlobalObject();"object"==typeof n&&e.middlewareService&&(n.vk=t)}catch(e){}}getUnicloud(){return vkunicloud}createInstance(e){return new VK(e)}}var src=new VK;module.exports=src; diff --git a/uniCloud-aliyun/cloudfunctions/router/node_modules/vk-unicloud/package.json b/uniCloud-aliyun/cloudfunctions/router/node_modules/vk-unicloud/package.json new file mode 100644 index 0000000..cb547fc --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/node_modules/vk-unicloud/package.json @@ -0,0 +1,16 @@ +{ + "name": "vk-unicloud", + "version": "2.15.3", + "description": "【云函数端SDK】VK云函数路由模式uniCloud开发框架,在router目录下执行 npm i vk-unicloud 进行安装和升级", + "main": "index.js", + "homepage": "https://gitee.com/vk-uni/vk-uni-cloud-router.git", + "repository": { + "type": "git", + "url": "git+https://gitee.com/vk-uni/vk-uni-cloud-router.git" + }, + "files": [ + "dist" + ], + "author": "VK", + "license": "Apache-2.0" +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/package-lock.json b/uniCloud-aliyun/cloudfunctions/router/package-lock.json new file mode 100644 index 0000000..ac76494 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/package-lock.json @@ -0,0 +1,30 @@ +{ + "name": "router", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, + "uni-config-center": { + "version": "file:../../../uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + }, + "uni-id": { + "version": "file:../../../uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id", + "requires": { + "uni-config-center": "file:../../../uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + }, + "dependencies": { + "uni-config-center": { + "version": "file:../../../uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } + } + }, + "vk-unicloud": { + "version": "file:../../../uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud" + } + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/package.json b/uniCloud-aliyun/cloudfunctions/router/package.json new file mode 100644 index 0000000..ac14b02 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/package.json @@ -0,0 +1,29 @@ +{ + "name": "router", + "version": "1.0.0", + "description": "【开箱即用】vk-uniCloud-router - 云函数路由模式 - uniCloud开发框架 - 已集成uni-id", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "crypto-js": "^4.2.0", + "uni-config-center": "file:../../../uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center", + "uni-id": "file:../../../uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id", + "vk-unicloud": "file:../../../uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud" + }, + "private": true, + "cloudfunction-config": { + "concurrency": 1, + "memorySize": 512, + "path": "/http/router", + "timeout": 60, + "triggers": [], + "runtime": "Nodejs12", + "keepRunningAfterReturn": false + }, + "extensions": {} +} diff --git a/uniCloud-aliyun/cloudfunctions/router/router.param.json b/uniCloud-aliyun/cloudfunctions/router/router.param.json new file mode 100644 index 0000000..580d5c7 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/router.param.json @@ -0,0 +1,14 @@ + +// 运行方法:右键云函数根目录(如router目录),并点击【运行-本地云函数】即可。 +// 若函数需要登录才能访问,则填写uni_id_token的值,值为对应用户的token(可直接从数据库中复制1个过来) +// $url 是 云函数运行路径,如 user/pub/checkToken +// data 是 请求参数,为标准json格式(属性名需要加双引号) + +{ + "uni_id_token":"", + "$url":"template/db_api/pub/tree", + "data":{ + "username":"admin", + "password":"123456" + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/attributes/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/attributes/sys/add.js new file mode 100644 index 0000000..ad7f7e8 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/attributes/sys/add.js @@ -0,0 +1,35 @@ +'use strict'; +module.exports = { + /** + * 新增询价模板 + * @url admin/enquiry/template/sys/add 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + label, + enable, + sort, + values + } = data; + // 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段 + let dbName = "jjx-enquiry-attributes"; + res.id = await vk.baseDao.add({ + dbName, + dataJson:{ + label, + enable, + sort, + values + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/attributes/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/attributes/sys/delete.js new file mode 100644 index 0000000..f138631 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/attributes/sys/delete.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 数据删除 + * @url admin/kong/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + if(vk.pubfn.isNull(_id)){ + return { code : -1, msg : 'id不能为空' }; + } + let dbName = "jjx-enquiry-attributes"; + await vk.baseDao.deleteById({ + dbName, + id:_id + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/attributes/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/attributes/sys/getList.js new file mode 100644 index 0000000..1378b84 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/attributes/sys/getList.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 查询多条记录 分页 + * @url admin/kong/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "jjx-enquiry-attributes"; + res = await vk.baseDao.getTableData({ + dbName, + data + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/attributes/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/attributes/sys/update.js new file mode 100644 index 0000000..120079b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/attributes/sys/update.js @@ -0,0 +1,37 @@ +'use strict'; +module.exports = { + /** + * 新增询价模板 + * @url admin/enquiry/template/sys/add 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + label, + enable, + sort, + values + } = data; + // 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段 + let dbName = "jjx-enquiry-attributes"; + res.id = await vk.baseDao.updateById({ + dbName, + id: _id, + dataJson:{ + label, + enable, + sort, + values + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/template/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/template/sys/add.js new file mode 100644 index 0000000..ef1eaf6 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/template/sys/add.js @@ -0,0 +1,35 @@ +'use strict'; +module.exports = { + /** + * 新增询价模板 + * @url admin/enquiry/template/sys/add 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + name, + enable, + sort, + attributes + } = data; + // 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段 + let dbName = "jjx-enquiry-template"; + res.id = await vk.baseDao.add({ + dbName, + dataJson:{ + name, + enable, + sort, + attributes + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/template/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/template/sys/delete.js new file mode 100644 index 0000000..6945628 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/template/sys/delete.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 数据删除 + * @url admin/kong/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + if(vk.pubfn.isNull(_id)){ + return { code : -1, msg : 'id不能为空' }; + } + let dbName = "jjx-enquiry-template"; + await vk.baseDao.deleteById({ + dbName, + id:_id + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/template/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/template/sys/getList.js new file mode 100644 index 0000000..3249887 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/template/sys/getList.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 查询多条记录 分页 + * @url admin/kong/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "jjx-enquiry-template"; + res = await vk.baseDao.getTableData({ + dbName, + data + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/template/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/template/sys/update.js new file mode 100644 index 0000000..b90535f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/enquiry/template/sys/update.js @@ -0,0 +1,37 @@ +'use strict'; +module.exports = { + /** + * 新增询价模板 + * @url admin/enquiry/template/sys/add 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + name, + enable, + sort, + attributes + } = data; + // 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段 + let dbName = "jjx-enquiry-template"; + res.id = await vk.baseDao.updateById({ + dbName, + id: _id, + dataJson:{ + name, + enable, + sort, + attributes + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/add.js new file mode 100644 index 0000000..1e20c1e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/add.js @@ -0,0 +1,34 @@ +module.exports = { + /** + * 添加单条数据 + * @url admin/kong/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + params1, + params2, + params3 + } = data; + // 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段 + let dbName = "vk-test"; + res.id = await vk.baseDao.add({ + dbName, + dataJson:{ + params1, + params2, + params3 + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/delete.js new file mode 100644 index 0000000..8fb19ac --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/delete.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 数据删除 + * @url admin/kong/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + if(vk.pubfn.isNull(_id)){ + return { code : -1, msg : 'id不能为空' }; + } + let dbName = "vk-test"; + await vk.baseDao.deleteById({ + dbName, + id:_id + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/getList.js new file mode 100644 index 0000000..373756a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/getList.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 查询多条记录 分页 + * @url admin/kong/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "vk-test"; + res = await vk.baseDao.getTableData({ + dbName, + data + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/update.js new file mode 100644 index 0000000..859773c --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/update.js @@ -0,0 +1,40 @@ +module.exports = { + /** + * 修改数据 + * @url admin/kong/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + params1, + params2, + params3 + } = data; + // 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段 + if(vk.pubfn.isNullOne(_id)){ + return { code : -1, msg : '参数错误' }; + } + let dbName = "vk-test"; + await vk.baseDao.updateById({ + dbName, + id:_id, + dataJson:{ + params1, + params2, + params3 + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/select/kh/user.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/select/kh/user.js new file mode 100644 index 0000000..ef80325 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/select/kh/user.js @@ -0,0 +1,96 @@ +module.exports = { + /** + * 查询用户列表(用于后端用户选择器的搜索数据) + * @url admin/select/kh/user 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} searchvalue 搜索内容 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let { searchvalue } = data; + if (!searchvalue) { + return { code: 0, list: [] }; + } + let dbName = "uni-id-users"; + let fieldJson = { + _id: true, + username: true, + nickname: true, + mobile: true, + }; + let sortArr = []; + // 排序规则开始----------------------------------------------------------- + sortArr.push({ + "name": "register_date", + "type": "desc" + }); + // 排序规则结束----------------------------------------------------------- + // 查询条件开始----------------------------------------------------------- + let whereJson = {}; + let andArr = []; + if (searchvalue) { + // 查询包含searchvalue的数据 + try { + let regExp = new RegExp(searchvalue); + let orObj = _.or([ + { + "username": regExp + }, + { + "nickname": regExp + }, + { + "mobile": regExp + }, + { + "_id": searchvalue + } + ]); + andArr.push(orObj); + } catch (err) { + return { code: -1, msg: '请输入合法的查询内容' }; + } + } + if (andArr.length > 0) { + whereJson = _.and(andArr); + } + // 查询条件结束----------------------------------------------------------- + let selectRes = await vk.baseDao.select({ + dbName: dbName, + pageIndex: 1, + pageSize: 10, + fieldJson: fieldJson, + whereJson: whereJson, + sortArr: sortArr + }, util); + let list = []; + for (let i in selectRes.rows) { + let item = selectRes.rows[i]; + let value = item._id; + let label = item.nickname || "未设置昵称"; + if (item.mobile) { + item.mobile = vk.pubfn.hidden(item.mobile, 3, 4); + label += `(${item.mobile})`; + } else if (item.username) { + item.username = vk.pubfn.hidden(item.username, 2, 3); + label += `(${item.username})`; + } + list.push({ + value: value, + label: label + }); + } + res.list = list; + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/setting_config.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/setting_config.js new file mode 100644 index 0000000..fb5ed8c --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/setting_config.js @@ -0,0 +1,83 @@ +'use strict'; +var vk; // 全局vk实例 +// 涉及的表名 +const dbName = { + configSite: "jjx-config-site", // 测试表 +}; + +var db = uniCloud.database(); // 全局数据库引用 +var _ = db.command; // 数据库操作符 +var $ = _.aggregate; // 聚合查询操作符 +/** + * 权限注意:访问以下链接查看 + * 文档地址:https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#内置权限 + */ +var cloudObject = { + isCloudObject: true, // 标记为云对象模式 + /** + * 请求前处理,主要用于调用方法之前进行预处理,一般用于拦截器、统一的身份验证、参数校验、定义全局对象等。 + * 文档地址:https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#before-预处理 + */ + _before: async function() { + vk = this.vk; // 将vk定义为全局对象 + // let { customUtil, uniID, config, pubFun } = this.getUtil(); // 获取工具包 + }, + /** + * 请求后处理,主要用于处理本次调用方法的返回结果或者抛出的错误 + * 文档地址:https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#after-后处理 + */ + _after: async function(options) { + let { err, res } = options; + if (err) { + return; // 如果方法抛出错误,直接return;不处理 + } + return res; + }, + /** + * 获取列表 + * @url admin/config.getList 前端调用的url参数地址 + */ + getList: async function(data) { + let res = { code: 0, msg: '' }; + let { uid } = this.getClientInfo(); // 获取客户端信息 + // 业务逻辑开始----------------------------------------------------------- + + + // 业务逻辑结束----------------------------------------------------------- + return res; + }, + /** + * 模板函数 + * @url admin/config.test 前端调用的url参数地址 + */ + test: async function(data) { + let res = { code: 0, msg: '' }; + let { uid } = this.getClientInfo(); // 获取客户端信息 + // 业务逻辑开始----------------------------------------------------------- + + + // 业务逻辑结束----------------------------------------------------------- + return res; + }, + /** + * @param {Object} data更新网站配置 + */ + sys_updateSiteInfo: async function(data) { + let res = { code: 0, msg: '' }; + let { uid } = this.getClientInfo(); // 获取客户端信息 + // 业务逻辑开始----------------------------------------------------------- + const {_id,siteLogo, siteTitle, siteDesc, siteCopyright, siteIcpNumber, companyName, companyAddress, companyPhone, companyEmail, companyServicePhone, companyGzhImage, companyMobileSiteImage} = data + res.data = await vk.baseDao.setById({ + dbName: dbName.configSite, + dataJson:{ + _id: 'jinjiuxingangcheng', + siteLogo, siteTitle, siteDesc, siteCopyright, siteIcpNumber, companyName, companyAddress, companyPhone, companyEmail, companyServicePhone, companyGzhImage, companyMobileSiteImage + }, + }); + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +}; + +module.exports = cloudObject; diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/site_config/sys/detail.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/site_config/sys/detail.js new file mode 100644 index 0000000..d3c0336 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/site_config/sys/detail.js @@ -0,0 +1,25 @@ +'use strict'; +module.exports = { + /** + * XXXnameXXX + * @url admin/site_config/sys/detail 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + res.data = await vk.baseDao.findById({ + dbName: "jjx-site-config", + id: 'jinjiuxingangcheng' + }) + + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/site_config/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/site_config/sys/update.js new file mode 100644 index 0000000..873942d --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/site_config/sys/update.js @@ -0,0 +1,29 @@ +'use strict'; +module.exports = { + /** + * XXXnameXXX + * @url admin/site_config/sys/update 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + + + const {_id,siteLogo, siteTitle, siteDesc, siteCopyright, siteIcpNumber, companyName, companyAddress, companyPhone, companyEmail, companyServicePhone, companyGzhImage, companyMobileSiteImage} = data + res.data = await vk.baseDao.setById({ + dbName: "jjx-site-config", + dataJson:{ + _id: 'jinjiuxingangcheng', + siteLogo, siteTitle, siteDesc, siteCopyright, siteIcpNumber, companyName, companyAddress, companyPhone, companyEmail, companyServicePhone, companyGzhImage, companyMobileSiteImage + }, + }); + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/add.js new file mode 100644 index 0000000..abf63c0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/add.js @@ -0,0 +1,66 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 添加单条数据 + * @url admin/kong/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + + let formRulesRes = await formRules.add(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 业务逻辑开始----------------------------------------------------------- + let { + name, + icon, + sort, + remark, + parent_id, + level + } = data; + + let dbName = "jjx-spot-category"; + + + if(parent_id) { + const parent = await vk.baseDao.findById({ + dbName, + id: parent_id + }) + + if(parent.level >= 3) { + return { + code: -1, + msg: '最多支持三级分类' + } + } + + level = parent.level + 1 + + } else { + level = 1 + } + res.id = await vk.baseDao.add({ + dbName, + dataJson:{ + name, + icon, + sort, + remark, + parent_id, + level + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/delete.js new file mode 100644 index 0000000..f88a0f8 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/delete.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 数据删除 + * @url admin/kong/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + if(vk.pubfn.isNull(_id)){ + return { code : -1, msg : 'id不能为空' }; + } + let dbName = "jjx-spot-category"; + await vk.baseDao.deleteById({ + dbName, + id:_id + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/getList.js new file mode 100644 index 0000000..b5daa7b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/getList.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 查询多条记录 分页 + * @url admin/kong/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "jjx-spot-category"; + res = await vk.baseDao.getTableData({ + dbName, + data + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/getTree.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/getTree.js new file mode 100644 index 0000000..81d4266 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/getTree.js @@ -0,0 +1,45 @@ +module.exports = { + /** + * 查询多条记录 分页 + * @url admin/kong/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "jjx-spot-category"; + res = await vk.baseDao.selects({ + dbName, + pageIndex: 1, + pageSize: 500, + whereJson:{ + parent_id: _.in([null, ""]), + _id: _.exists(true) + }, + sortArr: [{ name: "sort", type: "asc" }], + // 树状结构参数 + treeProps: { + id: "_id", // 唯一标识字段,默认为 _id + parent_id: "parent_id", // 父级标识字段,默认为 parent_id + children: "children", // 自定义返回的下级字段名,默认为 children + level: 3, // 查询返回的树的最大层级。超过设定层级的节点不会返回。默认10级,最大15,最小1 + limit: 500, // 每一级最大返回的数据。 + whereJson: { + } + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/update.js new file mode 100644 index 0000000..0c216ca --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/sys/update.js @@ -0,0 +1,67 @@ +module.exports = { + /** + * 修改数据 + * @url admin/kong/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + name, + icon, + sort, + remark, + parent_id, + level + } = data; + // 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段 + if(vk.pubfn.isNullOne(_id)){ + return { code : -1, msg : '参数错误' }; + } + let dbName = "jjx-spot-category"; + + + if(parent_id) { + const parent = await vk.baseDao.findById({ + dbName, + id: parent_id + }) + + if(parent.level >= 3) { + return { + code: -1, + msg: '最多支持三级分类' + } + } + + level = parent.level + 1 + + } else { + level = 1 + } + + await vk.baseDao.updateById({ + dbName, + id:_id, + dataJson:{ + name, + icon, + sort, + remark, + parent_id, + level + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/util/formRules.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/util/formRules.js new file mode 100644 index 0000000..beb72ee --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/category/util/formRules.js @@ -0,0 +1,59 @@ +'use strict'; +/** + * 表单验证 + */ +class Util { + constructor() { + + } + /** + * 添加 + */ + async add(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + // 验证规则开始 ----------------------------------------------------------- + let rules = { + name: [ + // 必填 + { required: true, message: "名称不能为空", trigger: ['blur','change'] }, + ] + + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } + /** + * 修改 + */ + async update(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + _id: [ + { required: true, message: 'id不能为空', trigger: 'blur' }, + ], + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } +} +module.exports = new Util diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/add.js new file mode 100644 index 0000000..4ccdd52 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/add.js @@ -0,0 +1,38 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 添加单条数据 + * @url admin/kong/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + + let formRulesRes = await formRules.add(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 业务逻辑开始----------------------------------------------------------- + let { + name,categoryIds,address,stock,files,sort + } = data; + + let dbName = "jjx-spot-goods"; + + + res.id = await vk.baseDao.add({ + dbName, + dataJson:{ + name,categoryIds,address,stock,files,user_id: uid,sort + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/delete.js new file mode 100644 index 0000000..40835f6 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/delete.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 数据删除 + * @url admin/kong/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + if(vk.pubfn.isNull(_id)){ + return { code : -1, msg : 'id不能为空' }; + } + let dbName = "jjx-spot-goods"; + await vk.baseDao.deleteById({ + dbName, + id:_id + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/getList.js new file mode 100644 index 0000000..c8dc57d --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/getList.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 查询多条记录 分页 + * @url admin/kong/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "jjx-spot-goods"; + res = await vk.baseDao.getTableData({ + dbName, + data + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/getTree.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/getTree.js new file mode 100644 index 0000000..c3f0bf8 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/getTree.js @@ -0,0 +1,45 @@ +module.exports = { + /** + * 查询多条记录 分页 + * @url admin/kong/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "jjx-spot-goods"; + res = await vk.baseDao.selects({ + dbName, + pageIndex: 1, + pageSize: 500, + whereJson:{ + parent_id: _.in([null, ""]), + _id: _.exists(true) + }, + sortArr: [{ name: "sort", type: "asc" }], + // 树状结构参数 + treeProps: { + id: "_id", // 唯一标识字段,默认为 _id + parent_id: "parent_id", // 父级标识字段,默认为 parent_id + children: "children", // 自定义返回的下级字段名,默认为 children + level: 3, // 查询返回的树的最大层级。超过设定层级的节点不会返回。默认10级,最大15,最小1 + limit: 500, // 每一级最大返回的数据。 + whereJson: { + } + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/update.js new file mode 100644 index 0000000..57c758e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/sys/update.js @@ -0,0 +1,35 @@ +module.exports = { + /** + * 修改数据 + * @url admin/kong/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id,name,categoryIds,address,stock,files,sort + } = data; + // 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段 + if(vk.pubfn.isNullOne(_id)){ + return { code : -1, msg : '参数错误' }; + } + let dbName = "jjx-spot-goods"; + await vk.baseDao.updateById({ + dbName, + id:_id, + dataJson:{ + name,categoryIds,address,stock,files,sort + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/util/formRules.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/util/formRules.js new file mode 100644 index 0000000..beb72ee --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/spot/goods/util/formRules.js @@ -0,0 +1,59 @@ +'use strict'; +/** + * 表单验证 + */ +class Util { + constructor() { + + } + /** + * 添加 + */ + async add(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + // 验证规则开始 ----------------------------------------------------------- + let rules = { + name: [ + // 必填 + { required: true, message: "名称不能为空", trigger: ['blur','change'] }, + ] + + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } + /** + * 修改 + */ + async update(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + _id: [ + { required: true, message: 'id不能为空', trigger: 'blur' }, + ], + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } +} +module.exports = new Util diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/addUpdate.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/addUpdate.js new file mode 100644 index 0000000..30109cf --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/addUpdate.js @@ -0,0 +1,162 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 添加或修改 + * @url admin/system/app-upgrade-center/sys/addUpdate, 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} appid 应用的AppID + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { vk, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + if (data.platformRadio && vk.pubfn.isNull(data.platform)) { + data.platform = [data.platformRadio]; + } + let { + _id, + appid, + name, + title, + contents, + platform, + platformRadio, + type, + version, + min_uni_version, + url, + stable_publish, + is_silently, + is_mandatory, + create_env = "upgrade-center", + store_list + } = data; + // 参数合法校验开始----------------------------------------------------------- + let mode = _id ? "update" : "add"; + let formRulesRes = await formRules[mode](event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + if (type === "wgt") { + if (vk.pubfn.isNull(min_uni_version)) return { code: -1, msg: "最低app版本号不能为空" }; + } + // 参数合法校验结束----------------------------------------------------------- + appid = appid.trim(); + let create_date = Date.now(); + let uni_platform = platform.indexOf("Android") > -1 ? "android" : "ios"; + let dbName = "opendb-app-versions"; + // 添加和修改公共的dataJson + let dataJson = { + title, + contents, + url, + min_uni_version, + stable_publish, + is_silently, + is_mandatory, + store_list + }; + + if (mode === "add") { + // 获取最新的已发布的版本信息 + let info = await vk.baseDao.select({ + dbName, + getCount: false, + getMain: true, + getOne: true, + pageIndex: 1, + pageSize: 1, + whereJson: { + appid, + type, + platform, + stable_publish: true + }, + sortArr: [{ name: "create_date", type: "desc" }], + }); + // 版本必须比之前的版本高 + if (info && info.version && compareVersion(version, info.version) !== 1) { + return { code: -1, msg: `版本必须大于${info.version}` }; + } + // 添加 + vk.pubfn.objectAssign(dataJson, { + appid, + name, + platform, + version, + type, + create_date, + uni_platform, + create_env, + }); + _id = await vk.baseDao.add({ + dbName, + dataJson + }); + if (_id) { + res.success = true; + res.msg = "添加成功"; + } + } else { + // 修改并返回修改后的数据 + res.info = await vk.baseDao.updateAndReturn({ + dbName, + whereJson: { + _id + }, + dataJson + }); + if (res.info) { + res.success = true; + res.msg = "修改成功"; + } + } + + if (res.success && dataJson.stable_publish) { + // 将其他版本设置为已下线 + await vk.baseDao.update({ + dbName, + whereJson: { + appid, + type, + platform, + stable_publish: true, + _id: _.neq(_id) + }, + dataJson: { + stable_publish: false + } + }); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} +/** + * 比较2个版本号的大小 + * 1 version1 > version2 + * 0 version1 = version2 + * -1 version1 < version2 + */ +function compareVersion(version1, version2) { + let arr1 = version1.split("."); + let arr2 = version2.split("."); + if (Number(arr1[0]) === Number(arr2[0]) && Number(arr1[1]) === Number(arr2[1]) && Number(arr1[2]) === Number(arr2[2])) { + return 0; + } + if (Number(arr1[0]) > Number(arr2[0])) { + return 1; + } + if (Number(arr1[0]) === Number(arr2[0]) && Number(arr1[1]) > Number(arr2[1])) { + return 1; + } + if (Number(arr1[0]) === Number(arr2[0]) && Number(arr1[1]) === Number(arr2[1]) && Number(arr1[2]) > Number(arr2[2])) { + return 1; + } + return -1; +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/delete.js new file mode 100644 index 0000000..fe695e0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/delete.js @@ -0,0 +1,34 @@ +module.exports = { + /** + * 删除 + * @url admin/system/app-upgrade-center/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { vk, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + if (vk.pubfn.isNull(_id)) return { code: -1, msg: 'id不能为空' }; + let dbName = "opendb-app-versions"; + let info = await vk.baseDao.findById({ + dbName, + id: _id, + }); + if (vk.pubfn.isNull(info)) return { code: -1, msg: "版本不存在" }; + if (info.stable_publish) return { code: -1, msg: "不可删除已上线的版本" }; + res.num = await vk.baseDao.deleteById({ + dbName, + id: _id + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/getList.js new file mode 100644 index 0000000..b821513 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/getList.js @@ -0,0 +1,31 @@ +module.exports = { + /** + * 分页查询 + * @url admin/system/app-upgrade-center/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { vk, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let dbName = "opendb-app-versions"; + res = await vk.baseDao.getTableData({ + dbName, + data, + sortArr: [{ name: "create_date", type: "desc" }] + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/util/formRules.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/util/formRules.js new file mode 100644 index 0000000..f797424 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/util/formRules.js @@ -0,0 +1,83 @@ +'use strict'; +/** + * 表单验证 + */ +class Util { + constructor() { + + } + /** + * 添加 + */ + async add(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + // 验证规则开始 ----------------------------------------------------------- + let rules = { + appid: [ + // 必填 + { required: true, message: "appid不能为空", trigger: ['blur','change'] } + ], + contents: [ + // 必填 + { required: true, message: "更新内容不能为空", trigger: ['blur','change'] } + ], + platform: [ + // 必填 + { required: true, message: "平台不能为空", trigger: ['blur','change'] } + ], + version: [ + // 必填 + { required: true, message: "版本号不能为空", trigger: ['blur','change'] }, + { validator: vk.pubfn.validator("version"), message: '版本号格式必须为:xx.xx.xx(3个数字组成,数字范围1-99,0-99,0-99) 如1.0.1 不可以是1.0.01', trigger: 'blur' } + ], + url: [ + // 必填 + { required: true, message: "链接不能为空", trigger: ['blur','change'] } + ], + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } + /** + * 修改 + */ + async update(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + _id: [ + { required: true, message: 'id不能为空', trigger: 'blur' }, + ], + contents: [ + // 必填 + { required: true, message: "更新内容不能为空", trigger: ['blur','change'] } + ], + url: [ + // 必填 + { required: true, message: "链接不能为空", trigger: ['blur','change'] } + ], + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } +} +module.exports = new Util diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/add.js new file mode 100644 index 0000000..0b151c9 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/add.js @@ -0,0 +1,100 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 添加应用 + * @url admin/system/app/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * @param {String} appid 应用的AppID + * @param {String} type 应用类型 + * @param {String} name 应用名称 + * @param {String} description 应用描述 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + appid, + type, + name, + description, + // 1.13.4 新增以下字段(主要用于生成统一发布页和APP升级中心) + enable_upgrade_center, + introduction, + icon_url, + screenshot, + app_android, + app_ios, + mp_weixin, + mp_alipay, + mp_baidu, + mp_toutiao, + mp_qq, + mp_kuaishou, + mp_lark, + mp_jd, + mp_dingtalk, + quickapp, + h5, + store_list, + } = data; + + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.add(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + appid = appid.trim(); + let dbName = "opendb-app-list"; + let num = await vk.baseDao.count({ + dbName, + whereJson: { + appid + } + }); + if (num > 0) { + return { code: -1, msg: 'appid已存在,请勿重复添加' }; + } + + let create_date = Date.now(); + res.id = await vk.baseDao.add({ + dbName, + dataJson: { + appid, + type, + name, + description, + create_date, + // 1.13.4 新增以下字段(主要用于生成统一发布页和APP升级中心) + enable_upgrade_center, + creator_uid: uid, // 创建者 + introduction, + icon_url, + screenshot, + app_android, + app_ios, + mp_weixin, + mp_alipay, + mp_baidu, + mp_toutiao, + mp_qq, + mp_kuaishou, + mp_lark, + mp_jd, + mp_dingtalk, + quickapp, + h5, + store_list, + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/createPublishHtml.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/createPublishHtml.js new file mode 100644 index 0000000..6e6ffda --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/createPublishHtml.js @@ -0,0 +1,22 @@ +'use strict'; +const createPublishHtml = require('../util/createPublishHtml/index.js') +module.exports = { + /** + * 生成发布页HTML + * @url admin/system/app/sys/createPublishHtml 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { vk, db, _ } = util; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { id } = data; + res = await createPublishHtml({ + id + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/delete.js new file mode 100644 index 0000000..769c131 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/delete.js @@ -0,0 +1,31 @@ +module.exports = { + /** + * 删除应用 + * @url admin/system/app/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + // 这里id不传默认设置成"___" 是为了防止因未传_id导致误删所有数据. + let { _id } = data; + if(vk.pubfn.isNull(_id)){ + return { code : -1, msg : 'id不能为空' }; + } + let dbName = "opendb-app-list"; + res.num = await vk.baseDao.deleteById({ + dbName, + id:_id + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/getInfo.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/getInfo.js new file mode 100644 index 0000000..3e9523b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/getInfo.js @@ -0,0 +1,26 @@ +'use strict'; +module.exports = { + /** + * 根据id获取信息 + * @url admin/system/app/sys/getInfo 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { appid } = data; + let dbName = "opendb-app-list"; + res.info = await vk.baseDao.findByWhereJson({ + dbName, + whereJson:{ + appid + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/getList.js new file mode 100644 index 0000000..9038302 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/getList.js @@ -0,0 +1,31 @@ +module.exports = { + /** + * 分页查询应用 + * @url admin/system/app/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let dbName = "opendb-app-list"; + res = await vk.baseDao.getTableData({ + dbName, + data, + sortArr: [{ name: "_id", type: "asc" }] + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/update.js new file mode 100644 index 0000000..1be7087 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/update.js @@ -0,0 +1,98 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 修改应用 + * @url admin/system/app/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * @param {String} name 应用名称 + * @param {String} type 应用类型 + * @param {String} description 应用描述 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + appid, + type, + name, + description, + // 1.13.4 新增以下字段(主要用于生成统一发布页和APP升级中心) + enable_upgrade_center, + introduction, + icon_url, + screenshot, + app_android, + app_ios, + mp_weixin, + mp_alipay, + mp_baidu, + mp_toutiao, + mp_qq, + mp_kuaishou, + mp_lark, + mp_jd, + mp_dingtalk, + quickapp, + h5, + store_list, + } = data; + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.update(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + appid = appid.trim(); + let dbName = "opendb-app-list"; + let num = await vk.baseDao.count({ + dbName, + whereJson: { + _id: _.neq(_id), + appid + } + }); + if (num > 0) { + return { code: -1, msg: '修改失败,appid已存在!' }; + } + res.num = await vk.baseDao.updateById({ + dbName, + id:_id, + dataJson:{ + appid, + type, + name, + description, + // 1.13.4 新增以下字段(主要用于生成统一发布页和APP升级中心) + enable_upgrade_center, + introduction, + icon_url, + screenshot, + app_android, + app_ios, + mp_weixin, + mp_alipay, + mp_baidu, + mp_toutiao, + mp_qq, + mp_kuaishou, + mp_lark, + mp_jd, + mp_dingtalk, + quickapp, + h5, + store_list, + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/index.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/index.js new file mode 100644 index 0000000..1bc24dc --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/index.js @@ -0,0 +1,214 @@ +const fs = require('fs') +const path = require('path') +const TE = require('./lib/art-template.js'); + +// 标准语法的界定符规则 +TE.defaults.openTag = '{@' +TE.defaults.closeTag = '@}' + +const success = { + code: 0, + success: true, +} +const fail = { + code: -1, + success: false +} + +async function translateTCB(_fileList = []) { + if (!_fileList.length) return _fileList + // 腾讯云和阿里云下载链接不同,需要处理一下,阿里云会原样返回 + const { + fileList + } = await uniCloud.getTempFileURL({ + fileList: _fileList + }); + return fileList.map((item, index) => item.tempFileURL ? item.tempFileURL : _fileList[index]) +} + +function hasValue(value) { + if (typeof value !== 'object') return !!value + if (value instanceof Array) return !!value.length + return !!(value && Object.keys(value).length && value.enable) +} + +module.exports = async function(data = {}) { + let { + id, + template + } = data; + if (!id) { + return { + ...fail, + code: -1, + errMsg: 'id required' + }; + } + + // 方式一:使用网络资源 + let templatePage; + if (template) { + try { + let htmlBuffer = await vk.request({ + url: template, + method: "GET", + dataType: "default" + }); + templatePage = htmlBuffer.toString("utf8"); + } catch (err) { + return { + ...fail, + code: -2, + errMsg: 'page template no found', + err + }; + } + } else { + // 方式二:使用本地资源 + templatePage = fs.readFileSync(path.resolve(__dirname, './template.html'), 'utf8'); + if (!templatePage) { + return { + ...fail, + code: -2, + errMsg: 'page template no found' + }; + } + } + + let appInfo = await vk.baseDao.findById({ + dbName: "opendb-app-list", + id: id + }); + + if (appInfo) { + + const defaultOptions = { + hasApp: false, + hasMP: false, + hasH5: false, + hasQuickApp: false + } + + defaultOptions.mpNames = { + 'mp_weixin': '微信', + 'mp_alipay': '支付宝', + 'mp_baidu': '百度', + 'mp_toutiao': '字节', + 'mp_qq': 'QQ', + 'mp_dingtalk': '钉钉', + 'mp_kuaishou': '快手', + 'mp_lark': '飞书', + 'mp_jd': '京东' + } + + const imageList = []; + ['app_android'].forEach(key => { + if (!hasValue(appInfo[key])) return + imageList.push({ + key, + urlKey: 'url', + url: appInfo[key].url + }) + }) + Object.keys(defaultOptions.mpNames).concat('quickapp').forEach(key => { + if (!hasValue(appInfo[key])) return + imageList.push({ + key, + urlKey: 'qrcode_url', + url: appInfo[key].qrcode_url + }) + }); + ['icon_url'].forEach(key => { + if (!hasValue(appInfo[key])) return + imageList.push({ + key, + url: appInfo[key] + }) + }) + const filelist = await translateTCB(imageList.map(item => item.url)) + imageList.forEach((item, index) => { + if (item.urlKey) { + appInfo[item.key][item.urlKey] = filelist[index] + } else { + appInfo[item.key] = filelist[index] + } + }) + if (hasValue(appInfo.screenshot)) { + appInfo.screenshot = await translateTCB(appInfo.screenshot) + } + + { + const appInfoKeys = Object.keys(appInfo) + if (appInfoKeys.some(key => { + return key.indexOf('app_') !== -1 && hasValue(appInfo[key]) + })) { + defaultOptions.hasApp = true + } + if (appInfoKeys.some(key => { + return key.indexOf('mp') !== -1 && hasValue(appInfo[key]) + })) { + defaultOptions.hasMP = true + } + if (appInfo.h5 && appInfo.h5.url) { + defaultOptions.hasH5 = true + } + if (appInfo.quickapp && appInfo.quickapp.qrcode_url) { + defaultOptions.hasQuickApp = true + } + + // app + if (defaultOptions.hasApp && appInfo.app_android && appInfo.app_android.url) { + defaultOptions.android_url = appInfo.app_android.url + } else { + defaultOptions.android_url = '' + } + if (defaultOptions.hasApp && appInfo.app_ios && appInfo.app_ios.url) { + defaultOptions.ios_url = appInfo.app_ios.url + } else { + defaultOptions.ios_url = '' + } + + // mp + defaultOptions.mpKeys = Object.keys(appInfo).filter(key => { + return key.indexOf('mp') !== -1 && hasValue(appInfo[key]) + }) + } + + // 解决二维码不显示的问题 + if (appInfo.icon_url && appInfo.icon_url.indexOf("http") == 0) { + let imageBuffer = await vk.request({ + url: appInfo.icon_url, + method: "GET", + dataType: "default" + }); + appInfo.icon_url = "data:image/png;base64," + imageBuffer.toString('base64'); + } + + const html = TE.render(templatePage)(Object.assign({}, appInfo, defaultOptions)); + + if (!(defaultOptions.hasApp || defaultOptions.hasH5 || defaultOptions.hasMP || defaultOptions + .hasQuickApp)) { + return { + ...fail, + code: -100, + errMsg: '缺少应用信息,App、小程序、H5、快应用请至少填写一项' + } + } + + return { + ...success, + mpserverlessComposedResponse: true, // 使用阿里云返回集成响应是需要此字段为true + statusCode: 200, + headers: { + 'content-type': 'text/html' + }, + body: html + }; + } + + return { + ...fail, + code: -3, + errMsg: 'no record' + }; +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/lib/art-template.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/lib/art-template.js new file mode 100644 index 0000000..b292990 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/lib/art-template.js @@ -0,0 +1,2 @@ +/*!art-template - Template Engine | http://aui.github.com/artTemplate/*/ +!function(){function a(a){return a.replace(t,"").replace(u,",").replace(v,"").replace(w,"").replace(x,"").split(y)}function b(a){return"'"+a.replace(/('|\\)/g,"\\$1").replace(/\r/g,"\\r").replace(/\n/g,"\\n")+"'"}function c(c,d){function e(a){return m+=a.split(/\n/).length-1,k&&(a=a.replace(/\s+/g," ").replace(//g,"")),a&&(a=s[1]+b(a)+s[2]+"\n"),a}function f(b){var c=m;if(j?b=j(b,d):g&&(b=b.replace(/\n/g,function(){return m++,"$line="+m+";"})),0===b.indexOf("=")){var e=l&&!/^=[=#]/.test(b);if(b=b.replace(/^=[=#]?|[\s;]*$/g,""),e){var f=b.replace(/\s*\([^\)]+\)/,"");n[f]||/^(include|print)$/.test(f)||(b="$escape("+b+")")}else b="$string("+b+")";b=s[1]+b+s[2]}return g&&(b="$line="+c+";"+b),r(a(b),function(a){if(a&&!p[a]){var b;b="print"===a?u:"include"===a?v:n[a]?"$utils."+a:o[a]?"$helpers."+a:"$data."+a,w+=a+"="+b+",",p[a]=!0}}),b+"\n"}var g=d.debug,h=d.openTag,i=d.closeTag,j=d.parser,k=d.compress,l=d.escape,m=1,p={$data:1,$filename:1,$utils:1,$helpers:1,$out:1,$line:1},q="".trim,s=q?["$out='';","$out+=",";","$out"]:["$out=[];","$out.push(",");","$out.join('')"],t=q?"$out+=text;return $out;":"$out.push(text);",u="function(){var text=''.concat.apply('',arguments);"+t+"}",v="function(filename,data){data=data||$data;var text=$utils.$include(filename,data,$filename);"+t+"}",w="'use strict';var $utils=this,$helpers=$utils.$helpers,"+(g?"$line=0,":""),x=s[0],y="return new String("+s[3]+");";r(c.split(h),function(a){a=a.split(i);var b=a[0],c=a[1];1===a.length?x+=e(b):(x+=f(b),c&&(x+=e(c)))});var z=w+x+y;g&&(z="try{"+z+"}catch(e){throw {filename:$filename,name:'Render Error',message:e.message,line:$line,source:"+b(c)+".split(/\\n/)[$line-1].replace(/^\\s+/,'')};}");try{var A=new Function("$data","$filename",z);return A.prototype=n,A}catch(B){throw B.temp="function anonymous($data,$filename) {"+z+"}",B}}var d=function(a,b){return"string"==typeof b?q(b,{filename:a}):g(a,b)};d.version="3.0.0",d.config=function(a,b){e[a]=b};var e=d.defaults={openTag:"<%",closeTag:"%>",escape:!0,cache:!0,compress:!1,parser:null},f=d.cache={};d.render=function(a,b){return q(a,b)};var g=d.renderFile=function(a,b){var c=d.get(a)||p({filename:a,name:"Render Error",message:"Template not found"});return b?c(b):c};d.get=function(a){var b;if(f[a])b=f[a];else if("object"==typeof document){var c=document.getElementById(a);if(c){var d=(c.value||c.innerHTML).replace(/^\s*|\s*$/g,"");b=q(d,{filename:a})}}return b};var h=function(a,b){return"string"!=typeof a&&(b=typeof a,"number"===b?a+="":a="function"===b?h(a.call(a)):""),a},i={"<":"<",">":">",'"':""","'":"'","&":"&"},j=function(a){return i[a]},k=function(a){return h(a).replace(/&(?![\w#]+;)|[<>"']/g,j)},l=Array.isArray||function(a){return"[object Array]"==={}.toString.call(a)},m=function(a,b){var c,d;if(l(a))for(c=0,d=a.length;d>c;c++)b.call(a,a[c],c,a);else for(c in a)b.call(a,a[c],c)},n=d.utils={$helpers:{},$include:g,$string:h,$escape:k,$each:m};d.helper=function(a,b){o[a]=b};var o=d.helpers=n.$helpers;d.onerror=function(a){var b="Template Error\n\n";for(var c in a)b+="<"+c+">\n"+a[c]+"\n\n";"object"==typeof console&&console.error(b)};var p=function(a){return d.onerror(a),function(){return"{Template Error}"}},q=d.compile=function(a,b){function d(c){try{return new i(c,h)+""}catch(d){return b.debug?p(d)():(b.debug=!0,q(a,b)(c))}}b=b||{};for(var g in e)void 0===b[g]&&(b[g]=e[g]);var h=b.filename;try{var i=c(a,b)}catch(j){return j.filename=h||"anonymous",j.name="Syntax Error",p(j)}return d.prototype=i.prototype,d.toString=function(){return i.toString()},h&&b.cache&&(f[h]=d),d},r=n.$each,s="break,case,catch,continue,debugger,default,delete,do,else,false,finally,for,function,if,in,instanceof,new,null,return,switch,this,throw,true,try,typeof,var,void,while,with,abstract,boolean,byte,char,class,const,double,enum,export,extends,final,float,goto,implements,import,int,interface,long,native,package,private,protected,public,short,static,super,synchronized,throws,transient,volatile,arguments,let,yield,undefined",t=/\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|\s*\.\s*[$\w\.]+/g,u=/[^\w$]+/g,v=new RegExp(["\\b"+s.replace(/,/g,"\\b|\\b")+"\\b"].join("|"),"g"),w=/^\d[^,]*|,\d[^,]*/g,x=/^,+|,+$/g,y=/^$|,+/;e.openTag="{{",e.closeTag="}}";var z=function(a,b){var c=b.split(":"),d=c.shift(),e=c.join(":")||"";return e&&(e=", "+e),"$helpers."+d+"("+a+e+")"};e.parser=function(a){a=a.replace(/^\s/,"");var b=a.split(" "),c=b.shift(),e=b.join(" ");switch(c){case"if":a="if("+e+"){";break;case"else":b="if"===b.shift()?" if("+b.join(" ")+")":"",a="}else"+b+"{";break;case"/if":a="}";break;case"each":var f=b[0]||"$data",g=b[1]||"as",h=b[2]||"$value",i=b[3]||"$index",j=h+","+i;"as"!==g&&(f="[]"),a="$each("+f+",function("+j+"){";break;case"/each":a="});";break;case"echo":a="print("+e+");";break;case"print":case"include":a=c+"("+b.join(",")+");";break;default:if(/^\s*\|\s*[\w\$]/.test(e)){var k=!0;0===a.indexOf("#")&&(a=a.substr(1),k=!1);for(var l=0,m=a.split("|"),n=m.length,o=m[l++];n>l;l++)o=z(o,m[l]);a=(k?"=":"=#")+o}else a=d.helpers[c]?"=#"+c+"("+b.join(",")+");":"="+a}return a},"function"==typeof define?define(function(){return d}):"undefined"!=typeof exports?module.exports=d:this.template=d}(); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/template.html b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/template.html new file mode 100644 index 0000000..c54f23d --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/template.html @@ -0,0 +1,241 @@ + + + + + + + + + {@name@} + + + + +
+ +
+ +
+ +

{@name@}

+

{@introduction@}

+
+ + {@if hasApp || hasMP || hasH5 || hasQuickApp@} +
+
+ {@if hasApp@} + App + {@/if@} + {@if hasMP@} + 小程序 + {@/if@} + {@if hasH5@} + H5 + {@/if@} + {@if hasQuickApp@} + 快应用 + {@/if@} +
+
+ {@if hasApp@} +
+ +

扫码获取

+ 下载安装 + + +

Android平台尚未发布,敬请期待~

+
+ {@/if@} + {@if hasMP@} +
+
+
+ {@each mpKeys@} +
+
+
+ {@mpNames[$value]@} +
+
+ {@/each@} +
+
+ {@each mpKeys@} +
+ + +

长按图片识别小程序

+
+ {@/each@} +
+
+
+ {@/if@} + {@if hasH5@} +
+
+ + {@h5.url@} +
+
+ {@/if@} + {@if hasQuickApp@} +
+ +

快应用

+

扫描二维码或复制名称后可在手机应用市场中搜索快应用

+
+ {@/if@} +
+
+ {@/if@} + + +
+
+ +
+
+
+ +
+ + +
+

{@name@}

+

{@introduction@}

+
+ + {@if hasApp || hasMP || hasH5 || hasQuickApp@} +
+
+ {@if hasApp@} + App + {@/if@} + {@if hasMP@} + 小程序 + {@/if@} + {@if hasH5@} + H5 + {@/if@} + {@if hasQuickApp@} + 快应用 + {@/if@} +
+
+ {@if hasApp@} + + {@/if@} + {@if hasMP@} +
+ {@each mpKeys@} +
+ +
扫二维码识别小程序
+
{@mpNames[$value]@}小程序
+
+ {@/each@} +
+ {@/if@} + {@if hasH5@} +
+
+
+ {@h5.url@} +
+
+ {@/if@} + {@if hasQuickApp@} +
+ +

快应用

+

扫描二维码或复制名称后可在手机应用市场中搜索快应用

+
+ {@/if@} +
+
+ {@/if@} +
+ + {@if description && description.length@} +
+

应用描述

+
{@description@}
+
+ {@/if@} + + {@if screenshot && screenshot.length@} +
+

应用截图

+
+
+
    + {@each screenshot@} +
  • + +
  • + {@/each@} +
+
+ {@/if@} +
+

复制成功

+
+
+ + + + + \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/formRules.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/formRules.js new file mode 100644 index 0000000..3a4c4bd --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/formRules.js @@ -0,0 +1,72 @@ +'use strict'; +/** + * 表单验证 + */ +class Util { + constructor() { + + } + /** + * 添加 + */ + async add(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + // 验证规则开始 ----------------------------------------------------------- + let rules = { + appid: [ + { required: true, message: '应用的AppID为必填字段', trigger: 'blur' }, + ], + name: [ + { required: true, message: '应用名称为必填字段', trigger: 'blur' } + ], + type: [ + { required: true, message: '应用类型为必填字段', trigger: 'blur' } + ] + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } + /** + * 修改 + */ + async update(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + _id: [ + { required: true, message: 'id不能为空', trigger: 'blur' }, + ], + appid: [ + { required: true, message: '应用的AppID为必填字段', trigger: 'blur' }, + ], + name: [ + { required: true, message: '应用名称为必填字段', trigger: 'blur' } + ], + type: [ + { required: true, message: '应用类型为必填字段', trigger: 'blur' } + ] + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } +} +module.exports = new Util diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/add.js new file mode 100644 index 0000000..f2a3d4a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/add.js @@ -0,0 +1,87 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 新增 + * @url admin/system/menu/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} menu_id 菜单Id,唯一标识 + * @param {String} name 菜单名称 + * @param {String} comment 备注 + * @param {String} url 页面路径 + * @param {String} icon 菜单图标 + * @param {Number} sort 排序(越大越在前面) + * @param {String} parent_id 父级id + * @param {Boolean} enable 是否启用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + menu_id, + name, + comment, + url, + icon, + sort = 0, + parent_id, + enable = true, + hidden_menu + } = data; + + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.add(event); + if(formRulesRes.code !== 0){ + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + let dbName = "opendb-admin-menus"; + // 检测menu_id是否存在 + let num = await vk.baseDao.count({ + dbName, + whereJson:{ + menu_id + } + }); + if(num > 0){ + return { code : -1, msg : `标识【${menu_id}】不能重复!` }; + } + let dataJson = { + menu_id, + name, + comment, + url, + icon, + sort, + parent_id, + enable, + hidden_menu + }; + // 检测parent_id是否不存在 + if(vk.pubfn.isNotNull(parent_id)){ + let num = await vk.baseDao.count({ + dbName, + whereJson:{ + menu_id : parent_id + } + }); + if(num <= 0){ + return { code : -1, msg : `父标识【${parent_id}】不存在!` }; + } + }else{ + delete dataJson.parent_id; + } + // 执行数据库API请求 + res.id = await vk.baseDao.add({ + dbName, + dataJson + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/adds.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/adds.js new file mode 100644 index 0000000..467d3b5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/adds.js @@ -0,0 +1,74 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 批量新增 + * @url admin/system/menu/sys/adds 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} mode 模式 1 :覆盖 2:忽略 + * @param {Array} menus 菜单json + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + mode, + menus, + } = data; + + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.adds(event); + if(formRulesRes.code !== 0){ + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + let dataArr = []; + for(let i=0;i { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + menu_id, + permissionList, + reset + } = data; + res = await vk.system.sysDao.menuBindPermission({ + menu_id, + permissionList, + reset + }); + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/delete.js new file mode 100644 index 0000000..d73e45a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/delete.js @@ -0,0 +1,40 @@ +module.exports = { + /** + * 删除 + * @url admin/system/menu/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} menu_id 菜单Id,唯一标识 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { menu_id } = data; + if(vk.pubfn.isNullOne(menu_id)){ + return { code : -1, msg : 'menu_id不能为空' }; + } + // 检查是否有子项 + let num = await vk.baseDao.count({ + dbName:"opendb-admin-menus", + whereJson:{ + parent_id : menu_id + } + }); + if(num > 0){ + return { code : -1, msg : '该项含有子项,请先删除子项!' }; + } + res.num = await vk.baseDao.del({ + dbName:"opendb-admin-menus", + whereJson:{ + menu_id + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/getAll.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/getAll.js new file mode 100644 index 0000000..b0937e3 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/getAll.js @@ -0,0 +1,31 @@ +'use strict'; +module.exports = { + /** + * 获取菜单列表(一次性获取全部) + * @url admin/system/menu/sys/getAll 前端调用的url参数地址 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + // 返回树状结构代码详情见:https://vkdoc.fsq.pub/client/uniCloud/db/getTree.html + res = await vk.system.sysDao.listMenuToTree({ + pageIndex: 1, + pageSize: 500, + whereJson: { + parent_id: _.in([null, ""]), + menu_id: _.exists(true) + }, + treeProps: { + level: 3 + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/getCascader.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/getCascader.js new file mode 100644 index 0000000..27b0dff --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/getCascader.js @@ -0,0 +1,57 @@ +'use strict'; +module.exports = { + /** + * 获取菜单级联数据(懒加载形式) + * @url admin/system/menu/sys/getCascader 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Object} node 当前点击的节点 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { node = {} } = data; + let whereJson = { + enable: true + }; + if (node.root) { + whereJson["parent_id"] = null; + } else { + whereJson["parent_id"] = node.value; + } + res = await vk.baseDao.selects({ + dbName: "opendb-admin-menus", + pageIndex: 1, + pageSize: 500, + whereJson, + sortArr: [{ name: "sort", type: "asc" }], + // 副表列表 + foreignDB: [ + { + dbName: "opendb-admin-menus", + localKey:"menu_id", + foreignKey: "parent_id", + as: "hasChildren", + limit: 1, // 避免浪费查询,这里设置limit:1 + } + ] + }); + // 数据预处理 + let rows = res.rows; + for (let i in rows) { + let item = rows[i]; + rows[i].label = `${item.name}(${item.menu_id})`; + if(vk.pubfn.isNull(item.hasChildren)){ + rows[i].leaf = true; + } + } + res.rows = rows; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/update.js new file mode 100644 index 0000000..f69e2f2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/update.js @@ -0,0 +1,87 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 修改 + * @url admin/system/menu/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} menu_id 菜单Id,唯一标识 + * @param {String} name 菜单名称 + * @param {String} comment 备注 + * @param {String} url 页面路径 + * @param {String} icon 菜单图标 + * @param {Number} sort 排序(越大越在前面) + * @param {String} parent_id 父级id + * @param {Boolean} enable 是否启用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + menu_id, + name, + comment, + url, + icon, + sort = 0, + parent_id, + enable = true, + hidden_menu + } = data; + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.update(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + let dbName = "opendb-admin-menus"; + let dataJson = { + name, + comment, + url, + icon, + sort, + parent_id, + enable, + hidden_menu + }; + // 检测parent_id是否不存在 + if (vk.pubfn.isNotNull(parent_id)) { + let num = await vk.baseDao.count({ + dbName, + whereJson: { + menu_id: parent_id + } + }); + if (num <= 0) { + return { code: -1, msg: `父标识【${parent_id}】不存在!` }; + } + let info = await vk.baseDao.findByWhereJson({ + dbName, + whereJson: { + menu_id + } + }); + if (vk.pubfn.isNotNull(info) && info.menu_id === parent_id) { + return { code: -1, msg: `不可以设置自己为父菜单` }; + } + } else { + dataJson["parent_id"] = _.remove(); + } + // 执行数据库API请求 + res.num = await vk.baseDao.update({ + dbName, + whereJson: { + menu_id + }, + dataJson + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/updateBase.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/updateBase.js new file mode 100644 index 0000000..4b0b1c5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/updateBase.js @@ -0,0 +1,43 @@ +module.exports = { + /** + * 修改基础信息 + * @url admin/system/menu/sys/updateBase 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id _id + * @param {Number} sort 排序 + * @param {Boolean} enable 是否启用 + * @param {Boolean} hidden_menu 是否隐藏(左侧菜单中不显示) + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + sort, + enable, + hidden_menu + } = data; + if (vk.pubfn.isNull(_id)) return { code: -1, msg: "_id不能为空" }; + + let dbName = "opendb-admin-menus"; + + // 执行数据库API请求 + res.num = await vk.baseDao.updateById({ + dbName, + id: _id, + dataJson: { + sort, + enable, + hidden_menu + }, + }); + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/util/formRules.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/util/formRules.js new file mode 100644 index 0000000..c3e41f0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/util/formRules.js @@ -0,0 +1,80 @@ +'use strict'; +/** + * 表单验证 + */ +class Util { + constructor() { + + } + /** + * 添加 + */ + async add(event){ + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code : 0, msg : '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + menu_id: [ + { required: true, message: '菜单标识不能为空', trigger: 'blur' }, + ], + name: [ + { required: true, message: '菜单名称不能为空', trigger: 'blur' }, + ], + sort:[ + { type: 'number', message: '排序值必须为数字'} + ] + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data : data, + rules : rules + }); + // 返回验证结果 + return res; + } + /** + * 修改 + */ + async update(event){ + return this.add(event); + } + + /** + * 批量添加 + */ + async adds(event){ + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code : 0, msg : '' }; + // 验证规则开始 ----------------------------------------------------------- + let rules = { + menu_id: [ + { required: true, message: '菜单标识不能为空', trigger: 'blur' }, + ], + name: [ + { required: true, message: '菜单名称不能为空', trigger: 'blur' }, + ], + sort:[ + { type: 'number', message: '排序值必须为数字'} + ] + }; + // 验证规则结束 ----------------------------------------------------------- + let { menus } = data; + for(let i=0;i { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + permission_id, + permission_name, + comment, + url, + icon, + sort = 0, + parent_id, + enable = true, + match_mode = 0, + curd_category, + level + } = data; + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.add(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + let dbName = "uni-id-permissions"; + // 检测permission_id是否存在 + let num = await vk.baseDao.count({ + dbName, + whereJson: { + permission_id + } + }); + if (num > 0) { + return { code: -1, msg: `标识【${permission_id}】不能重复!` }; + } + let dataJson = { + permission_id, + permission_name, + comment, + url, + icon, + sort, + parent_id, + enable, + match_mode, + curd_category, + level + }; + // 检测parent_id是否不存在 + if (vk.pubfn.isNotNull(parent_id)) { + let num = await vk.baseDao.count({ + dbName, + whereJson: { + permission_id: parent_id + } + }); + if (num <= 0) { + return { code: -1, msg: `父标识【${parent_id}】不存在!` }; + } + } else{ + delete dataJson.parent_id; + } + if(url === "" || JSON.stringify(url) === '[""]'){ + delete dataJson.url; + } + // 执行数据库API请求 + res.id = await vk.baseDao.add({ + dbName, + dataJson + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/delete.js new file mode 100644 index 0000000..621b60f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/delete.js @@ -0,0 +1,39 @@ +module.exports = { + /** + * 删除权限 + * @url admin/system/permission/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} permission_id 权限Id,唯一标识 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { permission_id } = data; + if (vk.pubfn.isNullOne(permission_id)) { + return { code: -1, msg: 'permission_id不能为空' }; + } + let dbName = "uni-id-permissions"; + // 检查是否有子项 + let num = await vk.baseDao.count({ + dbName, + whereJson: { + parent_id: permission_id + } + }); + if (num > 0) { + return { code: -1, msg: '该项含有子项,请先删除子项!' }; + } + res = uniID.deletePermission({ + permissionID: permission_id + }); + res.msg = res.message; + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/getAll.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/getAll.js new file mode 100644 index 0000000..f35b14b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/getAll.js @@ -0,0 +1,30 @@ +'use strict'; +module.exports = { + /** + * 获取权限列表 + * @url admin/system/permission/sys/getAll 前端调用的url参数地址 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + res = await vk.system.sysDao.listPermissionToTree({ + pageIndex: 1, + pageSize: 500, + whereJson: { + parent_id: _.in([null, ""]), + permission_id: _.exists(true) + }, + treeProps: { + level: 3 + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/update.js new file mode 100644 index 0000000..4a8c64e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/update.js @@ -0,0 +1,97 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 修改权限 + * @url admin/system/permission/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} permission_id 权限Id,唯一标识 + * @param {String} permission_name 权限名称,展示用 + * @param {String} comment 备注 + * @param {String} url 云函数路径 + * @param {String} icon 图标 + * @param {Number} sort 排序(越大越在前面) + * @param {String} parent_id 父级id + * @param {Boolean} enable 是否启用 + * @param {Number} match_mode 0:完整路径 1:通配符 2:正则表达式 + * @param {Number} curd_category 0:未分类 1:增 2:删 3:改 4:查 5:特殊 + * @param {Number} level 0:未分类 1:子弹级 2:炸弹级 3:榴弹级 4:核弹级 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + permission_id, + permission_name, + comment, + url, + icon, + sort = 0, + parent_id, + enable = true, + match_mode = 0, + curd_category, + level + } = data; + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.update(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + let dbName = "uni-id-permissions"; + let dataJson = { + permission_name, + comment, + url, + icon, + sort, + parent_id, + enable, + match_mode, + curd_category, + level + }; + // 检测parent_id是否不存在 + if (vk.pubfn.isNotNull(parent_id)) { + let num = await vk.baseDao.count({ + dbName, + whereJson: { + permission_id: parent_id + } + }); + if (num <= 0) { + return { code: -1, msg: `父标识【${parent_id}】不存在!` }; + } + let info = await vk.baseDao.findByWhereJson({ + dbName, + whereJson: { + permission_id + } + }); + if (vk.pubfn.isNotNull(info) && info.permission_id === parent_id) { + return { code: -1, msg: `不可以设置自己为父级` }; + } + } else { + dataJson["parent_id"] = _.remove(); + } + if (url === "" || JSON.stringify(url) === '[""]') { + dataJson["url"] = _.remove(); + } + // 执行数据库API请求 + res.num = await vk.baseDao.update({ + dbName, + whereJson: { + permission_id + }, + dataJson + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateBase.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateBase.js new file mode 100644 index 0000000..07833ee --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateBase.js @@ -0,0 +1,40 @@ +module.exports = { + /** + * 修改基础信息 + * @url admin/system/permission/sys/updateBase 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * @param {Number} sort 排序 + * @param {Boolean} enable 是否启用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + sort, + enable, + } = data; + if (vk.pubfn.isNull(_id)) return { code: -1, msg: "_id不能为空" }; + + let dbName = "uni-id-permissions"; + + // 执行数据库API请求 + res.num = await vk.baseDao.updateById({ + dbName, + id: _id, + dataJson: { + sort, + enable, + }, + }); + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateCategory.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateCategory.js new file mode 100644 index 0000000..ccb7879 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateCategory.js @@ -0,0 +1,34 @@ +module.exports = { + /** + * 修改权限分类 + * @url admin/system/permission/sys/updateCategory 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id 权限Id + * @param {Number} curd_category 0:未分类 1:增 2:删 3:改 4:查 5:特殊 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + curd_category=0, + } = data; + let dbName = "uni-id-permissions"; + // 执行数据库API请求 + res.num = await vk.baseDao.updateById({ + dbName, + id:_id, + dataJson:{ + curd_category + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateLevel.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateLevel.js new file mode 100644 index 0000000..e63a4e8 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateLevel.js @@ -0,0 +1,34 @@ +module.exports = { + /** + * 修改权限等级 + * @url admin/system/permission/sys/updateLevel 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id 权限Id + * @param {Number} level 0:未分类 1:子弹级 2:炸弹级 3:榴弹级 4:核弹级 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + level=0, + } = data; + let dbName = "uni-id-permissions"; + // 执行数据库API请求 + res.num = await vk.baseDao.updateById({ + dbName, + id:_id, + dataJson:{ + level + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/util/formRules.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/util/formRules.js new file mode 100644 index 0000000..fcdba83 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/util/formRules.js @@ -0,0 +1,46 @@ +'use strict'; +/** + * 表单验证 + */ +class Util { + constructor() { + + } + /** + * 添加 + */ + async add(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + permission_id: [ + { required: true, message: '权限标识不能为空', trigger: 'blur' }, + ], + permission_name: [ + { required: true, message: '权限名称不能为空', trigger: 'blur' }, + ], + sort: [ + { type: 'number', message: '排序值必须为数字' } + ] + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } + /** + * 修改 + */ + async update(event) { + return this.add(event); + } +} +module.exports = new Util diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/add.js new file mode 100644 index 0000000..6a576d7 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/add.js @@ -0,0 +1,58 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 新增角色 + * @url admin/system/role/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} role_id 角色Id(role_id) + * @param {String} role_name 角色名称,展示用 + * @param {String} comment 备注 + * @param {Boolean} enable 是否启用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + role_id, + role_name, + comment, + enable = true, + } = data; + + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.add(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + let dbName = "uni-id-roles"; + // 检查role_id是否存在 + let num = await vk.baseDao.count({ + dbName, + whereJson: { + role_id + } + }); + if (num > 0) { + return { code: -1, msg: `标识【${role_id}】不能重复!` }; + } + // 执行数据库API请求 + res.id = await vk.baseDao.add({ + dbName, + dataJson: { + role_id, + role_name, + comment, + enable + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/bindMenu.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/bindMenu.js new file mode 100644 index 0000000..c85d05a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/bindMenu.js @@ -0,0 +1,49 @@ +module.exports = { + /** + * 为角色绑定菜单 + * @url admin/system/role/sys/bindMenu 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Array} role_id 角色Id(role_id) + * @param {Array} menuList 菜单Id(menu_id)列表 + * @param {Boolean} reset 是否直接覆盖菜单,true:直接将menuList设置为角色菜单,false:在角色已有菜单后追加菜单 + * @param {Boolean} addPermission 是否自动添加菜单内置的权限 默认false + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { role_id, menuList, reset, addPermission } = data; + res = await vk.system.sysDao.roleBindMenu({ + role_id, + menuList, + reset, + addPermission + }); + if (res.code !== 0) return res; + let dbName = "uni-id-roles"; + let roleInfo = await vk.baseDao.findByWhereJson({ + dbName, + whereJson: { + role_id, + } + }); + let count = roleInfo.menu ? roleInfo.menu.length : 0; + // 修改stats_count_info统计信息 + res.info = await vk.baseDao.updateAndReturn({ + dbName, + whereJson: { + role_id + }, + dataJson: { + ["stats_count_info.type.0.count"]: count + }, + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/bindPermission.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/bindPermission.js new file mode 100644 index 0000000..a8812b1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/bindPermission.js @@ -0,0 +1,40 @@ +module.exports = { + /** + * 为角色绑定权限 + * @url admin/system/role/sys/bindPermission 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Array} role_id 角色Id(role_id) + * @param {Array} permissionList 权限Id(permission_id)列表 + * @param {Boolean} reset 是否直接覆盖角色权限,true:直接将permissionList设置为角色权限,false:在角色已有权限后追加权限 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { role_id, permissionList, reset, stats_count_info = {} } = data; + res = await uniID.bindPermission({ + roleID: role_id, + permissionList, + reset + }); + if (res.code !== 0) return res; + res.msg = res.message; + // 修改stats_count_info统计信息 + res.info = await vk.baseDao.updateAndReturn({ + dbName: "uni-id-roles", + whereJson: { + role_id + }, + dataJson: { + stats_count_info: _.set(stats_count_info) + }, + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/delete.js new file mode 100644 index 0000000..e888e71 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/delete.js @@ -0,0 +1,28 @@ +module.exports = { + /** + * 删除角色 + * @url admin/system/role/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} role_id 角色Id(role_id) + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { role_id } = data; + if (vk.pubfn.isNullOne(role_id)) { + return { code: -1, msg: 'role_id不能为空' }; + } + res = uniID.deleteRole({ + roleID: role_id + }); + res.msg = res.message; + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/getList.js new file mode 100644 index 0000000..b8ef282 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/getList.js @@ -0,0 +1,63 @@ +module.exports = { + /** + * 查询角色列表 + * @url admin/system/role/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "uni-id-roles"; + res = await vk.baseDao.getTableData({ + dbName, + data, + // 副表列表 + foreignDB: [ + { + dbName: "uni-id-permissions", + localKey: "permission", + localKeyType: "array", + foreignKey: "permission_id", + as: "permissionList", + limit: 500, + fieldJson: { + permission_id: true, + permission_name: true, + comment: true, + enable: true, + url: true + } + }, + { + dbName: "opendb-admin-menus", + localKey: "menu", + localKeyType: "array", + foreignKey: "menu_id", + as: "menuList", + limit: 500, + fieldJson: { + menu_id: true, + name: true, + comment: true, + enable: true, + url: true + } + } + ] + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/update.js new file mode 100644 index 0000000..a13b2f1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/update.js @@ -0,0 +1,50 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 修改角色 + * @url admin/system/role/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} role_id 角色Id(role_id) + * @param {String} role_name 角色名称,展示用 + * @param {String} comment 备注 + * @param {Boolean} enable 是否启用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + role_id, + role_name, + comment, + enable = true, + } = data; + + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.add(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + + // 执行数据库API请求 + res.num = await vk.baseDao.update({ + dbName: "uni-id-roles", + whereJson: { + role_id + }, + dataJson: { + role_name, + comment, + enable + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/updateBase.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/updateBase.js new file mode 100644 index 0000000..72313b9 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/updateBase.js @@ -0,0 +1,37 @@ +module.exports = { + /** + * 修改基础信息 + * @url admin/system/role/sys/updateBase 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * @param {Boolean} enable 是否启用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + enable, + } = data; + if (vk.pubfn.isNull(_id)) return { code: -1, msg: "_id不能为空" }; + + let dbName = "uni-id-roles"; + + // 执行数据库API请求 + res.num = await vk.baseDao.updateById({ + dbName, + id: _id, + dataJson: { + enable, + }, + }); + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/util/formRules.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/util/formRules.js new file mode 100644 index 0000000..cea27d5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/util/formRules.js @@ -0,0 +1,43 @@ +'use strict'; +/** + * 表单验证 + */ +class Util { + constructor() { + + } + /** + * 添加 + */ + async add(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + role_id: [ + { required: true, message: '角色标识不能为空', trigger: 'blur' }, + ], + role_name: [ + { required: true, message: '角色名称不能为空', trigger: 'change' } + ] + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } + /** + * 修改 + */ + async update(event) { + return this.add(event); + } +} +module.exports = new Util diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/add.js new file mode 100644 index 0000000..358a597 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/add.js @@ -0,0 +1,93 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 添加用户 + * @url admin/system/user/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} username 用户名 + * @param {String} nickname 昵称 + * @param {String} gender 性别 + * @param {Boolean} mobile 手机号 + * @param {String} comment 备注 + * @param {Array} dcloud_appid 允许登录的应用列表 + * @param {Number} login_appid_type 0:全部应用 1:部分应用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + username, + password, + nickname, + gender, + mobile, + email, + comment, + allow_login_background, + dcloud_appid = [], + login_appid_type + } = data; + if (!password) password = "234567"; + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.add(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + + let dbName = "uni-id-users"; + // 检测username + let num = await vk.baseDao.count({ dbName, whereJson: { username } }); + if (num > 0) return { code: -1, msg: `用户名【${username}】已注册!` }; + // 检测mobile + if (mobile) { + let num = await vk.baseDao.count({ dbName, whereJson: { mobile } }); + if (num > 0) return { code: -1, msg: `手机号【${mobile}】已注册!` }; + } + // 检测email + if (email) { + let num = await vk.baseDao.count({ dbName, whereJson: { email } }); + if (num > 0) return { code: -1, msg: `邮箱【${email}】已注册!` }; + } + if (typeof uniID.addUser !== "function") return { code: -1, msg: `请升级uni-id版本至3.3.14或以上。` }; + let addUserRes = await uniID.addUser({ + username, + password, + mobile, + email, + authorizedApp: dcloud_appid + }); + if (addUserRes.code !== 0 || !addUserRes.uid) { + return addUserRes; + } + // 用户其他信息 + let dataJson = { + nickname, + gender, + comment, + allow_login_background, + status: 0, + }; + // 如果设置允许登录所有应用,则直接删除dcloud_appid字段 + if (login_appid_type === 0) { + dataJson["dcloud_appid"] = _.remove(); + } + // 设置用户其他信息 + await vk.baseDao.update({ + dbName, + whereJson: { + _id: addUserRes.uid + }, + dataJson + }); + res.type = "register"; + res.uid = addUserRes.uid; + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/batchUpdateAppLogin.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/batchUpdateAppLogin.js new file mode 100644 index 0000000..ba4d693 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/batchUpdateAppLogin.js @@ -0,0 +1,78 @@ +'use strict'; +module.exports = { + /** + * 批量修改用户可登录的客户端 + * @url admin/system/user/sys/batchUpdateAppLogin 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { uniID, customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let { + user_ids, + allow_login_background = false, + dcloud_appid, + login_appid_type, + mode + } = data; + if(vk.pubfn.isNullOne(user_ids, login_appid_type, mode)){ + return { code: -1, msg: "参数错误" }; + } + if(mode !== 1 && typeof dcloud_appid !== "string"){ + return { code: -1, msg: "新增和移除模式下,dcloud_appid只能是字符串" }; + } + let dataJson = {}; + dataJson["allow_login_background"] = allow_login_background; + if(login_appid_type === 0){ + // 可登录全部应用 + dataJson["dcloud_appid"] = _.remove(); + } else{ + res.successNum = 0; + res.failNum = 0; + for(let i=0; i { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { user_id, parent_id } = data; + // 参数非空检测 + if (vk.pubfn.isNullOne(user_id)) { + return { code: -1, msg: '参数错误' }; + } + let parentUser = await vk.baseDao.findById({ + dbName: "uni-id-users", + id: parent_id, + }); + if (vk.pubfn.isNull(parentUser)) { + return { code: -1, msg: '父标识对应的用户不存在!' }; + } + let { my_invite_code } = parentUser; + if (vk.pubfn.isNull(my_invite_code)) { + return { code: -1, msg: '父标识对应的用户无邀请码,无法邀请!' }; + } + // 执行数据库API请求 + res = await uniID.acceptInvite({ + uid: user_id, + inviteCode: my_invite_code + }); + res.msg = res.message; + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/batchUpdateStatus.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/batchUpdateStatus.js new file mode 100644 index 0000000..8894ec6 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/batchUpdateStatus.js @@ -0,0 +1,40 @@ +module.exports = { + /** + * 批量修改用户状态 + * @url admin/system/user/sys/batchUpdateStatus 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Array} user_ids 用户id数组 + * @param {Integer} status 修改成的用户状态:0 正常 1 禁用 2 审核中 3 审核拒绝 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { user_ids, status } = data; + // 参数非空检测 + if (vk.pubfn.isNullOne(user_ids, status)) { + return { code: -1, msg: '参数错误' }; + } + if (user_ids.indexOf(uid) > -1 && status === 1) { + return { code: -1, msg: '不可禁用自己' }; + } + // 执行数据库API请求 + res.num = await vk.baseDao.update({ + dbName: "uni-id-users", + whereJson: { + _id: _.in(user_ids) + }, + dataJson: { + status: status + } + }); + + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/bindRole.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/bindRole.js new file mode 100644 index 0000000..f06a1b2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/bindRole.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 为用户绑定角色 + * @url admin/system/user/sys/bindRole 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} user_id 用户id + * @param {Array} roleList 角色Id(role_id)列表 + * @param {Boolean} reset 是否直接覆盖用户角色,true:直接将roleList设置为用户角色,false:在用户已有角色后追加角色 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { user_id, roleList, reset } = data; + res = uniID.bindRole({ + uid: user_id, + roleList, + reset + }); + res.msg = res.message; + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/delete.js new file mode 100644 index 0000000..9afafc0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/delete.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 删除用户 + * @url admin/system/user/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id 用户ID + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + if (vk.pubfn.isNullOne(_id)) { + return { code: -1, msg: '_id不能为空' }; + } + if (uid === _id) { + return { code: -1, msg: '请勿删除当前登录账户!' }; + } + // 执行数据库API请求 + res.num = await vk.baseDao.deleteById({ + dbName: "uni-id-users", + id:_id + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/getList.js new file mode 100644 index 0000000..13c707e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/getList.js @@ -0,0 +1,54 @@ +module.exports = { + /** + * 查询用户列表(可登录后台的) + * @url admin/system/user/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { dcloud_appid, appids } = data.formData || {}; + let whereJson = {}; + if (dcloud_appid) { + if (dcloud_appid === "___empty-array___") { + whereJson["dcloud_appid"] = []; + } else if (dcloud_appid === "___error___") { + whereJson["dcloud_appid"] = _.and(_.exists(true), _.nin(appids)); + } else if (dcloud_appid === "___non-existent___") { + whereJson["dcloud_appid"] = _.exists(false); + } else { + whereJson["dcloud_appid"] = _.or(_.eq(dcloud_appid), _.exists(false)); + } + } + let dbName = "uni-id-users"; + res = await vk.baseDao.getTableData({ + dbName, + data, + whereJson, + sortArr: [{ "name": "register_date", "type": "desc" }], + // 副表列表 + foreignDB: [{ + dbName: "opendb-app-list", + localKey: "dcloud_appid", + foreignKey: "appid", + localKeyType: "array", + as: "appList", + limit: 500 + }], + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/resetPassword.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/resetPassword.js new file mode 100644 index 0000000..6fd2bc0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/resetPassword.js @@ -0,0 +1,27 @@ +module.exports = { + /** + * 强制重置用户密码 + * @url admin/system/user/sys/resetPassword 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} user_id 用户ID + * @param {String} password 重置后的密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { uniID, customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { user_id, password } = data; + // 重置密码 + res = await uniID.resetPwd({ + uid: user_id, + password + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/update.js new file mode 100644 index 0000000..c578801 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/update.js @@ -0,0 +1,102 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 修改用户信息 + * @url admin/system/user/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id 用户ID + * @param {String} nickname 昵称 + * @param {String} gender 性别 + * @param {Boolean} mobile 手机号 + * @param {String} comment 备注 + * @param {Array} dcloud_appid 允许登录的应用列表 + * @param {Number} login_appid_type 0:全部应用 1:部分应用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + nickname, + gender, + mobile, + email, + comment, + allow_login_background, + dcloud_appid = [], + login_appid_type + } = data; + let mobile_confirmed; + let email_confirmed; + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.update(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + + let dbName = "uni-id-users"; + + // 检测mobile + if (mobile) { + let num = await vk.baseDao.count({ + dbName, + whereJson: { + mobile: mobile, + _id: _.neq(_id) + } + }); + if (num > 0) return { code: -1, msg: `手机号【${mobile}】已注册!` }; + mobile_confirmed = 1; // 设置该手机号为已验证(否则无法通过手机号进行登录) + } + // 检测email + if (email) { + let num = await vk.baseDao.count({ + dbName, + whereJson: { + email: email, + _id: _.neq(_id) + } + }); + if (num > 0) return { code: -1, msg: `邮箱【${email}】已注册!` }; + email_confirmed = 1; // 设置该邮箱为已验证(否则无法通过邮箱进行登录) + } + let dataJson = { + nickname, + gender, + mobile, + mobile_confirmed, + email, + email_confirmed, + comment, + allow_login_background + }; + // 设置允许登录的应用列表 + if (login_appid_type && typeof uniID.setAuthorizedAppLogin === "function") { + let setAuthorizedAppLoginRes = await uniID.setAuthorizedAppLogin({ + uid: _id, + dcloudAppidList: dcloud_appid + }); + if (setAuthorizedAppLoginRes.code !== 0) { + return setAuthorizedAppLoginRes; + } + } else if (login_appid_type === 0) { + dataJson["dcloud_appid"] = _.remove(); + } + // 执行数据库API请求 + res.num = await vk.baseDao.updateById({ + dbName, + id: _id, + dataJson + }); + + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/util/formRules.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/util/formRules.js new file mode 100644 index 0000000..2bd4b00 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/util/formRules.js @@ -0,0 +1,81 @@ +'use strict'; +/** + * 表单验证 + */ +class Util { + constructor() { + + } + /** + * 添加 + */ + async add(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + // 验证规则开始 ----------------------------------------------------------- + let rules = { + username: [ + { required: true, validator: vk.pubfn.validator("username"), + message: '用户名以字母开头,长度在6~18之间,只能包含字母、数字和下划线', trigger: 'blur' } + ], + nickname: [ + { required: true, message: '昵称为必填字段', trigger: 'blur' }, + { min: 2, max: 20, message: '昵称长度在 2 到 20 个字符', trigger: 'blur' } + ], + password: [ + { validator:vk.pubfn.validator("password"), message: '密码长度在6~18之间,只能包含字母、数字和下划线', trigger: 'blur' } + ], + mobile: [ + { validator: vk.pubfn.validator("mobile"), message: '手机号格式错误', trigger: 'blur' } + ], + email: [ + { validator: vk.pubfn.validator("email"), message: '邮箱格式错误', trigger: 'blur' } + ], + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } + /** + * 修改 + */ + async update(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + _id: [ + { required: true, message: '用户ID不能为空', trigger: 'blur' }, + ], + nickname: [ + { required: true, message: '昵称为必填字段', trigger: 'blur' }, + { min: 2, max: 20, message: '昵称长度在 2 到 20 个字符', trigger: 'blur' } + ], + mobile: [ + { validator: vk.pubfn.validator("mobile"), message: '手机号格式错误', trigger: 'blur' } + ], + email: [ + { validator: vk.pubfn.validator("email"), message: '邮箱格式错误', trigger: 'blur' } + ] + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } +} +module.exports = new Util diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/admin-log/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/admin-log/sys/getList.js new file mode 100644 index 0000000..e95103a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/admin-log/sys/getList.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 分页查询 + * @url admin/system_uni/admin-log/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "opendb-admin-log"; + res = await vk.baseDao.getTableData({ + dbName, + data, + whereJson:{ + + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/add.js new file mode 100644 index 0000000..5ccc443 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/add.js @@ -0,0 +1,61 @@ +module.exports = { + /** + * 添加 + * @url admin/system_uni/components-dynamic/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} data_id 组件数据id + * @param {String} title 数据标题 + * @param {Object} data 组件数据 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + data_id, + data: dynamicData, + title, + description, + type, + sort = 0, + show = true, + name + } = data; + + // 参数非空检测 + if (vk.pubfn.isNull(data_id)) return { code: -1, msg: 'data_id不能为空' }; + + let dbName = "vk-components-dynamic"; + // 检测key是否已存在 + let num = await vk.baseDao.count({ + dbName: dbName, + whereJson: { + data_id, + } + }); + if (num > 0) { + return { code: -1, msg: `组件数据id不能重复!` }; + } + // 执行数据库API请求 + res.id = await vk.baseDao.add({ + dbName, + dataJson: { + data: dynamicData, + data_id, + title, + description, + type, + sort, + show, + name + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/delete.js new file mode 100644 index 0000000..1ffbbc0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/delete.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 删除 + * @url admin/system_uni/components-dynamic/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + // 参数非空检测 + if(vk.pubfn.isNullOne(_id)){ + return { code : -1, msg : '_id不能为空' }; + } + // 执行数据库API请求 + let num = await vk.baseDao.del({ + dbName:"vk-components-dynamic", + whereJson:{ + _id + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/getList.js new file mode 100644 index 0000000..638b64f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/getList.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 分页查询 + * @url admin/system_uni/components-dynamic/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "vk-components-dynamic"; + res = await vk.baseDao.getTableData({ + dbName, + data, + whereJson:{ + + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/update.js new file mode 100644 index 0000000..32012d2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/update.js @@ -0,0 +1,69 @@ +module.exports = { + /** + * 修改 + * @url admin/system_uni/components-dynamic/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} data_id 组件数据id + * @param {String} title 数据标题 + * @param {Object} data 组件数据 + * @param {Object} description 数据描述 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + data_id, + data: dynamicData, + title, + description, + type, + sort, + show, + name + } = data; + + // 参数非空检测 + if (vk.pubfn.isNull(_id)) return { code: -1, msg: 'id不能为空' }; + + let dbName = "vk-components-dynamic"; + + if (vk.pubfn.isNotNull(data_id)) { + // 检测data_id是否已存在 + let num = await vk.baseDao.count({ + dbName, + whereJson: { + data_id, + _id: _.neq(_id) + } + }); + if (num > 0) { + return { code: -1, msg: `组件数据id不能重复!` }; + } + } + // 执行数据库API请求 + res.num = await vk.baseDao.updateById({ + dbName, + id: _id, + dataJson: { + data: dynamicData, + data_id, + title, + description, + type, + sort, + show, + name + } + }); + + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/add.js new file mode 100644 index 0000000..bb04e11 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/add.js @@ -0,0 +1,59 @@ +const formRules = require('../util/formRules.js'); +module.exports = { + /** + * 添加 + * @url admin/system_uni/global-data/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} key 键名 + * @param {any} value 键值 + * @param {time} expired_at 过期时间 + * @param {String} comment 备注 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + key, + value, + expired_at, + comment + } = data; + if (!expired_at) expired_at = 0; + // 参数合法校验 + let formRulesRes = await formRules.add(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + + let dbName = "vk-global-data"; + // 检测key是否已存在 + let num = await vk.baseDao.count({ + dbName, + whereJson: { + key + } + }); + if (num > 0) { + return { code: -1, msg: `键值【${key}】不能重复!` }; + } + // 执行数据库API请求 + res.id = await vk.baseDao.add({ + dbName, + dataJson: { + _id: key, // 此处将_id也设置为key,方便使用doc查询提高性能 + key, + value, + expired_at, + comment + } + }); + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/delete.js new file mode 100644 index 0000000..93a0943 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/delete.js @@ -0,0 +1,33 @@ +module.exports = { + /** + * 删除 + * @url admin/system_uni/global-data/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + // 参数非空检测 + if(vk.pubfn.isNullOne(_id)){ + return { code : -1, msg : '_id不能为空' }; + } + let dbName = "vk-global-data"; + // 执行数据库API请求 + let num = await vk.baseDao.del({ + dbName:dbName, + whereJson:{ + _id + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/getList.js new file mode 100644 index 0000000..80ca5c1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/getList.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 分页查询 + * @url admin/system_uni/global-data/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "vk-global-data"; + res = await vk.baseDao.getTableData({ + dbName, + data, + whereJson:{ + + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/update.js new file mode 100644 index 0000000..6d81565 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/update.js @@ -0,0 +1,52 @@ +const formRules = require('../util/formRules.js'); +module.exports = { + /** + * 修改 + * @url admin/system_uni/global-data/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} key 键名 + * @param {any} value 键值 + * @param {time} expired_at 过期时间 + * @param {any} comment 备注 + * @param {String} _id id + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + key, + value, + expired_at, + comment + } = data; + if (typeof expired_at !== "undefined" && !expired_at) expired_at = 0; + // 参数合法校验 + let formRulesRes = await formRules.update(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + let dbName = "vk-global-data"; + // 执行数据库API请求 + res.num = await vk.baseDao.update({ + dbName: dbName, + whereJson: { + _id: key + }, + dataJson: { + value, + expired_at, + comment + } + }); + + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/util/formRules.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/util/formRules.js new file mode 100644 index 0000000..d20583c --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/util/formRules.js @@ -0,0 +1,64 @@ +'use strict'; +/** + * 表单验证 + */ +class Util { + constructor() { + + } + /** + * 添加 + */ + async add(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + key: [ + { required: true, message: '键名不能为空', trigger: 'blur' }, + ], + value: [ + { required: true, message: '键值不能为空', trigger: 'change' } + ] + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } + /** + * 修改 + */ + async update(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + key: [ + { required: true, message: '键名不能为空', trigger: 'blur' }, + ], + value: [ + { required: true, message: '键值不能为空', trigger: 'change' } + ] + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } +} +module.exports = new Util \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/pay-orders/sys/afreshNotice.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/pay-orders/sys/afreshNotice.js new file mode 100644 index 0000000..0a4eae8 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/pay-orders/sys/afreshNotice.js @@ -0,0 +1,117 @@ +'use strict'; +module.exports = { + /** + * 重新执行回调通知 + * @url admin/system_uni/pay-orders/sys/afreshNotice 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, // 订单id + } = data; + + let dbName = "vk-pay-orders"; + + // 获取异步回调配置 + let spaceId = originalParam.context.SPACEINFO.spaceId; // 服务空间ID + let currentNotifyUrl = getNotifyUrl(config, spaceId); + if (!currentNotifyUrl || currentNotifyUrl.indexOf("http") !== 0) { + return { code: -1, msg: "请先配置正确的异步回调URL,参考配置文档:https://vkdoc.fsq.pub/vk-uni-pay/config.html" } + } + + // 获取订单信息 + let orderInfo = await vk.baseDao.findById({ + dbName, + id: _id + }); + if (vk.pubfn.isNull(orderInfo)) return { code: -1, msg: "订单不存在" }; + if (orderInfo.status !== 1) return { code: -1, msg: "订单状态错误" }; + if (orderInfo.user_order_success) return { code: -1, msg: "无需重新通知" }; + + // 先将订单的状态改为未支付(重新回调需要) + let updateNum = await vk.baseDao.update({ + dbName, + whereJson: { + _id, + status: 1 + }, + dataJson: { + status: 0, + user_order_success: _.remove() + } + }); + + if (!updateNum) { + return { code: -1, msg: "订单状态错误" }; + } + + let { original_data, out_trade_no } = orderInfo; + try { + // 执行回调 + let requestRes = await vk.request({ + url: `${currentNotifyUrl}${original_data.path}`, + method: "POST", + dataType: "text", + header: original_data.headers, + content: original_data.body + }); + } catch (err) {} + // 再次获取订单信息,判断是否回调成功 + let payOrderInfo = await vk.baseDao.findById({ + dbName, + id: _id + }); + if (payOrderInfo.status === 1) { + // 等待回调全部执行完成,最大等待20秒 + let await_max_time = 20; + if (typeof payOrderInfo.user_order_success == "undefined") { + let whileTime = 0; // 当前循环已执行的时间(毫秒) + let whileInterval = 1000; // 每次循环间隔时间(毫秒) + let maxTime = await_max_time * 1000; // 循环执行时间超过此值则退出循环(毫秒) + while (typeof payOrderInfo.user_order_success == "undefined" && whileTime <= maxTime) { + await vk.pubfn.sleep(whileInterval); + whileTime += whileInterval; + // 查询最新的订单信息 + payOrderInfo = await vk.baseDao.findById({ + dbName, + id: _id + }); + } + } + } + // 还原部分信息(如支付时间不可被重新回调修改) + await vk.baseDao.updateById({ + dbName, + id: _id, + dataJson: { + status: orderInfo.status, + pay_date: orderInfo.pay_date, + original_data: orderInfo.original_data, + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} +// 获取异步回调配置 +function getNotifyUrl(config, spaceId) { + const payConifg = config["uni-pay"]; + const { notifyUrl } = payConifg; + let currentNotifyUrl = notifyUrl[spaceId]; // 异步回调地址 + // 兼容正式版阿里云与公测版阿里云spaceId开始----------------------------------------------------------- + if (!currentNotifyUrl) { + if (spaceId.indexOf("mp-") === 0) { + currentNotifyUrl = notifyUrl[spaceId.substring(3)]; + } else { + currentNotifyUrl = notifyUrl[`mp-${spaceId}`]; + } + } + // 兼容正式版阿里云与公测版阿里云spaceId结束----------------------------------------------------------- + return currentNotifyUrl; +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/pay-orders/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/pay-orders/sys/getList.js new file mode 100644 index 0000000..d8881f5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/pay-orders/sys/getList.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * vk-pay支付插件支付订单查询 + * @url admin/system_uni/pay-orders/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "vk-pay-orders"; + res = await vk.baseDao.getTableData({ + dbName, + data + }); + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/kh/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/kh/getList.js new file mode 100644 index 0000000..6f061e1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/kh/getList.js @@ -0,0 +1,33 @@ +module.exports = { + /** + * 分页查询 + * @url admin/system_uni/uni-id-files/categories/kh/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "vk-files-categories"; + res = await vk.baseDao.getTableData({ + dbName, + data, + whereJson:{ + + }, + sortArr:[{ name:"_id", type:"asc" }] + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/add.js new file mode 100644 index 0000000..88bd11b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/add.js @@ -0,0 +1,51 @@ +module.exports = { + /** + * 添加 + * @url admin/system_uni/uni-id-files/categories/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} name 分类名称 + * @param {String} description 数据描述 + * @param {Number} sort 排序值 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + name, + description, + sort, + } = data; + // 参数非空检测 + if(vk.pubfn.isNull(name)){ + return { code : -1, msg : '名称不能为空' }; + } + let dbName = "vk-files-categories"; + // 检测key是否已存在 + let num = await vk.baseDao.count({ + dbName, + whereJson:{ + name, + } + }); + if(num > 0){ + return { code : -1, msg : `名称【${name}】不能重复!` }; + } + // 执行数据库API请求 + res.id = await vk.baseDao.add({ + dbName, + dataJson:{ + name, + description, + sort + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/delete.js new file mode 100644 index 0000000..92305cf --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/delete.js @@ -0,0 +1,30 @@ +module.exports = { + /** + * 删除 + * @url admin/system_uni/uni-id-files/categories/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + // 参数非空检测 + if(vk.pubfn.isNullOne(_id)){ + return { code : -1, msg : '_id不能为空' }; + } + let dbName = "vk-files-categories"; + await vk.baseDao.deleteById({ + dbName, + id:_id + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/update.js new file mode 100644 index 0000000..4c4694a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/update.js @@ -0,0 +1,57 @@ +module.exports = { + /** + * 修改 + * @url admin/system_uni/uni-id-files/categories/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * @param {String} name 分类名称 + * @param {String} description 数据描述 + * @param {Number} sort 排序值 + * @param {String} parent_id 父id + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + name, + description, + sort + } = data; + // 参数非空检测 + if(vk.pubfn.isNull(name)){ + return { code : -1, msg : '名称不能为空' }; + } + let dbName = "vk-files-categories"; + + // 检测data_id是否已存在 + let num = await vk.baseDao.count({ + dbName, + whereJson:{ + name, + _id : _.neq(_id) + } + }); + if(num > 0){ + return { code : -1, msg : `名称【${name}】不能重复!` }; + } + // 执行数据库API请求 + res.num = await vk.baseDao.updateById({ + dbName, + id:_id, + dataJson:{ + name, + description, + sort + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/delete.js new file mode 100644 index 0000000..d504d39 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/delete.js @@ -0,0 +1,60 @@ +module.exports = { + /** + * 删除 + * @url admin/system_uni/uni-id-files/files/kh/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String,Array} _id id 或id数组 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + // 参数非空检测 + if (vk.pubfn.isNullOne(_id)) { + return { code: -1, msg: '_id不能为空' }; + } + let whereJson = {}; + let { role = [] } = userInfo; + if (role.indexOf("admin") === -1) { + // 如果不是admin角色用户,则只能删除自己上传的 + whereJson["user_id"] = uid; + } + if (typeof _id === "string") { + // 单条删除 + whereJson["_id"] = _id; + } else if (typeof _id === "object") { + // 批量删除 + whereJson["_id"] = _.in(_id); + } + let selectRes = await vk.baseDao.select({ + dbName: "vk-files", + pageIndex: 1, + pageSize: 500, + getMain: true, + whereJson, + fieldJson: { + file_id: true + } + }); + if (selectRes.length > 0) { + try { + let fileList = vk.pubfn.arrayObjectGetArray(selectRes, "file_id"); + await uniCloud.deleteFile({ fileList }); + } catch (err) {} + // 执行数据库API请求 + res.num = await vk.baseDao.del({ + dbName: "vk-files", + whereJson + }); + } + res.msg = "ok"; + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/getList.js new file mode 100644 index 0000000..f92b4da --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/getList.js @@ -0,0 +1,40 @@ +module.exports = { + /** + * 分页查询 + * @url admin/system_uni/uni-id-files/files/kh/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "vk-files"; + let whereJson = {}; + let { role = [] } = userInfo; + let { formData = {} } = data; + let { category_id } = formData; + if (category_id == "null") { + whereJson["category_id"] = null; + } + if (role.indexOf("admin") === -1) { + // 如果不是admin角色用户,则只能查看自己上传的 + whereJson["user_id"] = uid; + } + res = await vk.baseDao.getTableData({ + dbName, + data, + whereJson + }); + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/update.js new file mode 100644 index 0000000..1bbf96d --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/update.js @@ -0,0 +1,64 @@ +module.exports = { + /** + * 修改 + * @url admin/system_uni/uni-id-files/files/kh/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} display_name 显示在后台的文件名称 + * @param {String} category_id 分类id + * @param {Number} status 0:未审核 1:已审核通过 2:审核不通过 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + display_name, + category_id, + cover_image, + status = 0 + } = data; + // 参数非空检测 + if (vk.pubfn.isNullOne(_id)) { + return { code: -1, msg: '_id不能为空' }; + } + let dbName = "vk-files"; + let whereJson = {}; + let dataJson = { + display_name, + category_id, + cover_image, + status + }; + let { role = [] } = userInfo; + if (role.indexOf("admin") === -1) { + // 如果不是admin角色用户,则只能修改自己上传的 + whereJson["user_id"] = uid; + } + if (typeof _id === "string") { + // 单条操作 + whereJson["_id"] = _id; + } else if (typeof _id === "object") { + // 批量操作 + whereJson["_id"] = _.in(_id); + } + if (category_id == "null" || category_id === "") { + dataJson["category_id"] = _.remove(); + } + + // 执行数据库API请求 + res.num = await vk.baseDao.update({ + dbName: dbName, + whereJson, + dataJson + }); + + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-log/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-log/sys/getList.js new file mode 100644 index 0000000..12b2194 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-log/sys/getList.js @@ -0,0 +1,66 @@ +module.exports = { + /** + * 分页查询 + * @url admin/system_uni/uni-id-log/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { dcloud_appid, appids } = data.formData || {}; + let whereJson = {}; + if (dcloud_appid) { + if (dcloud_appid === "___empty-array___") { + whereJson["dcloud_appid"] = []; + } else if (dcloud_appid === "___error___") { + whereJson["dcloud_appid"] = _.and(_.exists(true), _.nin(appids)); + } else if (dcloud_appid === "___non-existent___") { + whereJson["dcloud_appid"] = _.exists(false); + } else { + whereJson["dcloud_appid"] = _.or(_.eq(dcloud_appid), _.exists(false)); + } + } + let dbName = "uni-id-log"; + res = await vk.baseDao.getTableData({ + dbName, + data, + whereJson, + // 副表列表 + foreignDB: [{ + dbName: "opendb-app-list", + localKey: "dcloud_appid", + foreignKey: "appid", + localKeyType: "array", + as: "appList", + limit: 500 + }, + { + dbName: "uni-id-users", + localKey: "user_id", + foreignKey: "_id", + as: "userInfo", + limit: 1, + fieldJson: { + _id: true, + avatar: true, + nickname: true, + gender: true + } + } + ], + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/后台PC管理端.md b/uniCloud-aliyun/cloudfunctions/router/service/admin/后台PC管理端.md new file mode 100644 index 0000000..8b29abf --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/后台PC管理端.md @@ -0,0 +1,17 @@ +## PC后台admin管理端 +#### `router/service/admin` 目录为后台管理端逻辑 +#### 以下的目录并非强制性,只是建议,便于统一开发规范。 + +``` +. +├── admin──────────────────────# 后台管理端逻辑 +│ └── system────────────────# 系统(用户、角色、权限、菜单、应用) +│ └── system_uni────────────# 系统插件 +│ └── user──────────────────# 用户管理 +│ └── order─────────────────# 订单管理 +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +└───────────────────────────────── +``` diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/enquiry/attributes/pub/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/client/enquiry/attributes/pub/getList.js new file mode 100644 index 0000000..f7eb564 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/enquiry/attributes/pub/getList.js @@ -0,0 +1,43 @@ +'use strict'; +const dbName = 'jjx-enquiry-attributes' +module.exports = { + /** + * 查询现货列表 + * @url client/spot/goods/kh/getList 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + const {pageIndex,pageSize,label } = data + + let whereJson = { + enable: true, + label + }; + + + + res = await vk.baseDao.selects({ + dbName, + getCount:false, + pageIndex, + pageSize, + // 主表where条件 + whereJson: whereJson, + // 主表字段显示规则 + fieldJson:{}, + // 主表排序规则 + sortArr:[{ name:"sort", type:"asc" }], + + }); + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/enquiry/attributes/pub/getOne.js b/uniCloud-aliyun/cloudfunctions/router/service/client/enquiry/attributes/pub/getOne.js new file mode 100644 index 0000000..b9d99ff --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/enquiry/attributes/pub/getOne.js @@ -0,0 +1,44 @@ +'use strict'; +const dbName = 'jjx-enquiry-attributes' +module.exports = { + /** + * 查询现货列表 + * @url client/spot/goods/kh/getList 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "",list: [] }; + // 业务逻辑开始----------------------------------------------------------- + const {pageIndex,pageSize,label } = data + + let whereJson = { + enable: true, + label + }; + + + + const info = await vk.baseDao.findByWhereJson({ + dbName, + getCount:false, + whereJson: whereJson, + }); + + if(info != null) { + res.list = info.values.map(item => { + return { + label: item, + value: item + } + }) + } + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/enquiry/sheet/kh/add.js b/uniCloud-aliyun/cloudfunctions/router/service/client/enquiry/sheet/kh/add.js new file mode 100644 index 0000000..4bc2811 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/enquiry/sheet/kh/add.js @@ -0,0 +1,63 @@ +'use strict'; +module.exports = { + /** + * XXXnameXXX + * @url client/enquiry/sheet/kh/add 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { + productList, + remark, + invoice, + writeInvoiceTime, + nvoiceType, + transportDocuments, + otherTransportDocuments, + transportLimit, + tradeMethod, + payMethod, + advancePayRate, + otherPayMethod, + reputationPayDay, + answerTime, + earnestMoney, + status + + } = data; + // 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段 + let dbName = "jjx-enquiry-sheet"; + res.id = await vk.baseDao.add({ + dbName, + dataJson:{ + productList, + remark, + invoice, + writeInvoiceTime, + nvoiceType, + transportDocuments, + otherTransportDocuments, + transportLimit, + tradeMethod, + payMethod, + advancePayRate, + otherPayMethod, + reputationPayDay, + answerTime, + earnestMoney, + status + } + }); + + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/enquiry/template/pub/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/client/enquiry/template/pub/getList.js new file mode 100644 index 0000000..5953269 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/enquiry/template/pub/getList.js @@ -0,0 +1,42 @@ +'use strict'; +const dbName = 'jjx-enquiry-template' +module.exports = { + /** + * 查询现货列表 + * @url client/spot/goods/kh/getList 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + const {pageIndex,pageSize } = data + + let whereJson = { + enable: true + }; + + + + res = await vk.baseDao.selects({ + dbName, + getCount:false, + pageIndex, + pageSize, + // 主表where条件 + whereJson: whereJson, + // 主表字段显示规则 + fieldJson:{}, + // 主表排序规则 + sortArr:[{ name:"sort", type:"desc" }], + + }); + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/fadada.js b/uniCloud-aliyun/cloudfunctions/router/service/client/fadada.js new file mode 100644 index 0000000..58f574f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/fadada.js @@ -0,0 +1,196 @@ +'use strict'; +const { verify } = require("crypto"); +var CryptoJS = require("crypto-js"); +var vk; // 全局vk实例 +// 涉及的表名 +const dbName = { + //test: "vk-test", // 测试表 +}; + +var db = uniCloud.database(); // 全局数据库引用 +var _ = db.command; // 数据库操作符 +var $ = _.aggregate; // 聚合查询操作符 +/** + * 权限注意:访问以下链接查看 + * 文档地址:https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#内置权限 + */ +var cloudObject = { + isCloudObject: true, // 标记为云对象模式 + /** + * 请求前处理,主要用于调用方法之前进行预处理,一般用于拦截器、统一的身份验证、参数校验、定义全局对象等。 + * 文档地址:https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#before-预处理 + */ + _before: async function() { + vk = this.vk; // 将vk定义为全局对象 + // let { customUtil, uniID, config, pubFun } = this.getUtil(); // 获取工具包 + }, + /** + * 请求后处理,主要用于处理本次调用方法的返回结果或者抛出的错误 + * 文档地址:https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#after-后处理 + */ + _after: async function(options) { + let { err, res } = options; + if (err) { + return; // 如果方法抛出错误,直接return;不处理 + } + return res; + }, + /** + * 获取列表 + * @url client/fadada.getList 前端调用的url参数地址 + */ + getList: async function(data) { + let res = { code: 0, msg: '' }; + let { uid } = this.getClientInfo(); // 获取客户端信息 + // 业务逻辑开始----------------------------------------------------------- + + + // 业务逻辑结束----------------------------------------------------------- + return res; + }, + /** + * 模板函数 + * @url client/fadada.test 前端调用的url参数地址 + */ + test: async function(data) { + + }, + /** + * 实名认证异步通知回调 + * @param {Object} data + */ + async pub_verifyNotify(data) { + let { customUtil, uniID, config, pubFun } = this.getUtil(); // 获取工具包 + const {customerId} = data; + // 查询认证结果 + let user = await vk.baseDao.findByWhereJson({ + dbName:"uni-id-users", + whereJson:{ + fadadaCustomerId: customerId, + } + }); + let res + + if(user.accountType == 1) { + res = await pubFun.fadada('find_personCertInfo.api', { + verified_serialno: user.fadadaVerify.transactionNo + }) + }else { + res = await pubFun.fadada('find_companyCertInfo.api', { + verified_serialno: user.fadadaVerify.transactionNo + }) + } + + + + // 认证成功 + if(res.code == 1) { + await vk.baseDao.setById({ + dbName:"fadada-verify-record", + dataJson:{ + _id: user._id, + ...res.data + } + }) + + await vk.baseDao.updateById({ + dbName:"uni-id-users", + id: user._id, + dataJson:{ + person: res.data.person, + company: res.data.company, + manager: res.data.manager, + BankCard: res.data.BankCard, + fadadaConfirm: true + } + }); + + } + + + return res + }, + /** + * 获取用户认证结果 + */ + async getVerifyResult() { + let { customUtil, uniID, config, pubFun } = this.getUtil(); // 获取工具包 + let res = { code: 0, msg: '' }; + let { uid } = this.getClientInfo(); // 获取客户端信息 + let {accountType,fadadaCustomerId} = await this.getUserInfo(); + + res.data = await vk.baseDao.findById({ + dbName:"fadada-verify-record", + id: uid + }); + + + return res + }, + /** + * 获取实名认证地址 + */ + async getVerifyUrl() { + let { customUtil, uniID, config, pubFun } = this.getUtil(); // 获取工具包 + let res = { code: 0, msg: '' }; + let { uid } = this.getClientInfo(); // 获取客户端信息 + let {accountType,fadadaCustomerId, fadadaVerify} = await this.getUserInfo(); + // 业务逻辑开始----------------------------------------------------------- + + if(fadadaVerify) { + res.data = fadadaVerify + return res; + } + + + let verify_url_res ; + + if(accountType === 1) { + verify_url_res = await pubFun.fadada('get_person_verify_url.api', { + customer_id: fadadaCustomerId, + verified_way: 2, + page_modify: 1, + notify_url: 'https://fc-mp-0737e52b-fffa-4223-bcdf-d4ad3d9968a5.next.bspapp.com/fadada_verify_notify' + + }) + }else { + verify_url_res = await pubFun.fadada('get_company_verify_url.api', { + customer_id: fadadaCustomerId, + page_modify: 1, + notify_url: 'https://fc-mp-0737e52b-fffa-4223-bcdf-d4ad3d9968a5.next.bspapp.com/fadada_verify_notify' + }) + console.log(': ',); + } + + console.log('verify_url_res: ',verify_url_res); + let {transactionNo, url} = verify_url_res.data + var parsedWordArray = CryptoJS.enc.Base64.parse(url); + url = parsedWordArray.toString(CryptoJS.enc.Utf8); + + await vk.baseDao.update({ + dbName: "uni-id-users", + whereJson: { + _id: uid + }, + dataJson: { + fadadaVerify: { + transactionNo, + url + } + } + }); + + + + res.data = { + transactionNo, + url + } + + // 业务逻辑结束----------------------------------------------------------- + return res; + + } +}; + +module.exports = cloudObject; diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/order/kh/test.js b/uniCloud-aliyun/cloudfunctions/router/service/client/order/kh/test.js new file mode 100644 index 0000000..8e21145 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/order/kh/test.js @@ -0,0 +1,23 @@ +'use strict'; +module.exports = { + /** + * 此函数名称 + * @url client/order/kh/test 前端调用的url参数地址 + * data 请求参数 + * @params {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + + + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/order/pub/test.js b/uniCloud-aliyun/cloudfunctions/router/service/client/order/pub/test.js new file mode 100644 index 0000000..5472395 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/order/pub/test.js @@ -0,0 +1,23 @@ +'use strict'; +module.exports = { + /** + * 此函数名称 + * @url client/order/pub/test 前端调用的url参数地址 + * data 请求参数 + * @params {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + + + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/pub.test.js b/uniCloud-aliyun/cloudfunctions/router/service/client/pub.test.js new file mode 100644 index 0000000..1f1de17 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/pub.test.js @@ -0,0 +1,105 @@ +/** + * 此为云对象模式,可以在这一个对象中写多个函数,具体文档请查看 + * https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html + */ +'use strict'; +var vk; // 全局vk实例 +// 涉及的表名 +const dbName = { + //test: "vk-test", // 测试表 +}; + +var db = uniCloud.database(); // 全局数据库引用 +var _ = db.command; // 数据库操作符 +var $ = _.aggregate; // 聚合查询操作符 +/** + * 权限注意:访问以下链接查看 + * 文档地址:https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#内置权限 + */ +var cloudObject = { + isCloudObject: true, // 标记为云对象模式 + /** + * 请求前处理,主要用于调用方法之前进行预处理,一般用于拦截器、统一的身份验证、参数校验、定义全局对象等。 + * 文档地址:https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#before-预处理 + */ + _before: async function() { + vk = this.vk; // 将vk定义为全局对象 + // let { customUtil, uniID, config, pubFun } = this.getUtil(); // 获取工具包 + }, + /** + * 请求后处理,主要用于处理本次调用方法的返回结果或者抛出的错误 + * 文档地址:https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#after-后处理 + */ + _after: async function(options) { + let { err, res } = options; + if (err) { + return; // 如果方法抛出错误,直接return;不处理 + } + return res; + }, + /** + * 模板函数 + * @url client/pub.test.getInfo 前端调用的url参数地址 + */ + getInfo: async function(data) { + let { uid } = this.getClientInfo(); // 获取客户端信息 + let userInfo = await this.getUserInfo(); // 获取当前登录的用户信息 + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + console.log("getInfo请求参数", data); + res.userInfo = userInfo; // 返回前端当前登录的用户信息 + + // 业务逻辑结束----------------------------------------------------------- + return res; + }, + /** + * 模板函数 + * @url client/pub.test.getList 前端调用的url参数地址 + */ + getList: async function(data) { + let { uid, filterResponse, originalParam } = this.getClientInfo(); // 获取客户端信息 + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + console.log("getList请求参数", data); + + + // 业务逻辑结束----------------------------------------------------------- + return res; + }, + /** + * 云对象调用自身函数 + * @url client/pub.test.test1 前端调用的url参数地址 + */ + test1: async function(data) { + let { uid, filterResponse, originalParam } = this.getClientInfo(); // 获取客户端信息 + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + console.log("test1请求参数", data); + let res1 = await this.getInfo(data); + console.log("res1", res1); + // 业务逻辑结束----------------------------------------------------------- + return res; + }, + /** + * 云对象调用任意云对象或云函数 + * @url client/pub.test.test2 前端调用的url参数地址 + */ + test2: async function(data) { + let { uid, filterResponse, originalParam } = this.getClientInfo(); // 获取客户端信息 + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + console.log("test2请求参数", data); + let callRes = await vk.callFunction({ + url: 'client/pub.test.getInfo', + clientInfo: this.getClientInfo(), + data: { + a:1 + }, + }); + console.log("callRes", callRes); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +}; + +module.exports = cloudObject; diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/spot/category/pub/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/client/spot/category/pub/getList.js new file mode 100644 index 0000000..391d481 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/spot/category/pub/getList.js @@ -0,0 +1,27 @@ +'use strict'; +module.exports = { + /** + * 查询商品分类列表 + * @url client/product/category/pub/getAll 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid, whereJson } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "jjx-spot-category"; + res.data = await vk.baseDao.selects({ + dbName, + getMain: true, + whereJson + }); + + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/spot/category/pub/getTree.js b/uniCloud-aliyun/cloudfunctions/router/service/client/spot/category/pub/getTree.js new file mode 100644 index 0000000..c138b06 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/spot/category/pub/getTree.js @@ -0,0 +1,42 @@ +'use strict'; +module.exports = { + /** + * 查询商品分类列表 + * @url client/product/category/pub/getAll 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "jjx-spot-category"; + res = await vk.baseDao.selects({ + dbName, + pageIndex: 1, + pageSize: 500, + whereJson:{ + parent_id: _.in([null, ""]), + _id: _.exists(true) + }, + sortArr: [{ name: "sort", type: "asc" }], + // 树状结构参数 + treeProps: { + id: "_id", // 唯一标识字段,默认为 _id + parent_id: "parent_id", // 父级标识字段,默认为 parent_id + children: "children", // 自定义返回的下级字段名,默认为 children + level: 3, // 查询返回的树的最大层级。超过设定层级的节点不会返回。默认10级,最大15,最小1 + limit: 500, // 每一级最大返回的数据。 + whereJson: { + } + } + }); + + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/kh/addCooperate.js b/uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/kh/addCooperate.js new file mode 100644 index 0000000..be49fdc --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/kh/addCooperate.js @@ -0,0 +1,69 @@ +'use strict'; +module.exports = { + /** + * 申请合作 + * @url client/spot/goods/kh/addCooperate 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid,company,manager,person,accountType, goodsUserId, goodsId,remark } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let info = await vk.baseDao.findByWhereJson({ + dbName:"jjx-goods-cooperate", + whereJson:{ + userId: uid, + goodsId: goodsId + } + }); + + if(info != null) { + return { + code: -1, + msg: '您已经申请过了' + } + } + + let subjectName = '' + let subjectMobile = '' + let managerName = '' + let managerMobile = '' + + if(accountType == 1) { + subjectName = person.personName + subjectMobile = person.mobile + }else { + subjectName = company.companyName + subjectMobile = company.legalMobile + if(manager.mobile && manager.personName){ + managerName = manager.personName + managerMobile = manager.mobile + } + } + + res.data = await vk.baseDao.add({ + dbName:"jjx-goods-cooperate",// 表名 + dataJson:{ // 需要新增的数据 json格式 + userId: uid, + goodsUserId: goodsUserId, + goodsId: goodsId, + company, + manager, + person, + accountType, + status: 0, + subjectName, + subjectMobile, + managerName, + managerMobile, + remark + } + }); + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/kh/addUpdate.js b/uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/kh/addUpdate.js new file mode 100644 index 0000000..270f294 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/kh/addUpdate.js @@ -0,0 +1,46 @@ +'use strict'; +module.exports = { + /** + * 新增或更新现货 + * @url client/product/goods/kh/addUpdate 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + const dbName = 'jjx-spot-goods' + let {_id,name,categoryIds,address,stock,files} = data + // 业务逻辑开始----------------------------------------------------------- + let info = await vk.baseDao.findByWhereJson({ + dbName, + whereJson:{ + userId: uid, + } + }); + + if(info == null) { + await vk.baseDao.add({ + dbName, + dataJson:{ + name,categoryIds,address,stock,files,userId: uid,sort: 0 + } + }); + }else { + await vk.baseDao.updateById({ + dbName, + id: info._id, + dataJson:{ + name,categoryIds,address,stock,files + } + }); + } + + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/kh/getSelfOne.js b/uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/kh/getSelfOne.js new file mode 100644 index 0000000..cddafee --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/kh/getSelfOne.js @@ -0,0 +1,28 @@ +'use strict'; +const dbName = 'jjx-spot-goods' +module.exports = { + /** + * XXXnameXXX + * @url client/spot/goods/kh/getSelfOne 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + res.data = await vk.baseDao.findByWhereJson({ + dbName, + whereJson:{ + user_id: uid, + } + }); + + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/pub/getDetail.js b/uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/pub/getDetail.js new file mode 100644 index 0000000..920f2e7 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/pub/getDetail.js @@ -0,0 +1,75 @@ +'use strict'; +const dbName = 'jjx-spot-goods' +module.exports = { + /** + * XXXnameXXX + * @url client/spot/goods/kh/getDetail 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { + data = {}, userInfo, util, filterResponse, originalParam + } = event; + let { + customUtil, + uniID, + config, + pubFun, + vk, + db, + _ + } = util; + let { + uid + } = data; + let res = { + code: 0, + msg: "" + }; + // 业务逻辑开始----------------------------------------------------------- + const { + _id + } = data + res.data = await vk.baseDao.selects({ + dbName, + getOne: true, + getMain: true, + // 主表where条件 + whereJson: { + _id: _id + }, + foreignDB: [{ + dbName: "uni-id-users", + localKey: "user_id", + foreignKey: "_id", + as: "user", + limit: 1, // limit=1则以对象形式返回 + fieldJson: { + _id: true, + company: { + companyName: true + }, + person: { + personName: true + }, + businessCard: true, + accountType: true, + }, + }, + { + dbName: "jjx-goods-cooperate", + localKey: "_id", + foreignKey: "goodsId", + as: "cooperateList", + limit: 500, // limit=1则以对象形式返回 + } + ] + }); + + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/pub/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/pub/getList.js new file mode 100644 index 0000000..34fe991 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/spot/goods/pub/getList.js @@ -0,0 +1,72 @@ +'use strict'; +const dbName = 'jjx-spot-goods' +module.exports = { + /** + * 查询现货列表 + * @url client/spot/goods/kh/getList 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + const {keyword, categoryIds,provinceCodes,pageIndex,pageSize } = data + + let whereJson = {}; + + if(vk.pubfn.isNotNull(keyword)) { + whereJson.name = new RegExp(keyword) + } + if(vk.pubfn.isNotNull(categoryIds)) { + whereJson.categoryIds = _.in(categoryIds) + } + + if(vk.pubfn.isNotNull(categoryIds)) { + whereJson.categoryIds = _.in(categoryIds) + } + + if(vk.pubfn.isNotNull(provinceCodes)) { + whereJson['address.province.code'] = _.in(provinceCodes) + } + + res = await vk.baseDao.selects({ + dbName, + getCount:false, + pageIndex, + pageSize, + // 主表where条件 + whereJson: whereJson, + // 主表字段显示规则 + fieldJson:{}, + // 主表排序规则 + sortArr:[{ name:"sort", type:"desc" }], + foreignDB: [ + { + dbName:"uni-id-users", + localKey:"user_id", + foreignKey:"_id", + as:"user", + limit:1, // limit=1则以对象形式返回 + fieldJson:{ + _id: true, + company: { + companyName: true + }, + person: { + personName: true + }, + businessCard: true, + accountType: true, + }, + } + ] + }); + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/user/kh/setBusinessCard.js b/uniCloud-aliyun/cloudfunctions/router/service/client/user/kh/setBusinessCard.js new file mode 100644 index 0000000..2959308 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/user/kh/setBusinessCard.js @@ -0,0 +1,23 @@ +'use strict'; +module.exports = { + /** + * 设置名片数据 + * @url client/user/kh/setBusinessCard 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + + + + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/user/kh/test.js b/uniCloud-aliyun/cloudfunctions/router/service/client/user/kh/test.js new file mode 100644 index 0000000..353041e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/user/kh/test.js @@ -0,0 +1,23 @@ +'use strict'; +module.exports = { + /** + * 此函数名称 + * @url client/user/kh/test 前端调用的url参数地址 + * data 请求参数 + * @params {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + + + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/user/pub/test.js b/uniCloud-aliyun/cloudfunctions/router/service/client/user/pub/test.js new file mode 100644 index 0000000..e17fbc0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/user/pub/test.js @@ -0,0 +1,23 @@ +'use strict'; +module.exports = { + /** + * 此函数名称 + * @url client/user/pub/test 前端调用的url参数地址 + * data 请求参数 + * @params {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + + + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/小程序、h5、APP客户端.md b/uniCloud-aliyun/cloudfunctions/router/service/client/小程序、h5、APP客户端.md new file mode 100644 index 0000000..10436c3 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/小程序、h5、APP客户端.md @@ -0,0 +1,11 @@ +## 客户端(H5、小程序、APP客户端) +#### `router/service/client` 目录为客户端端逻辑 +#### 以下的目录并非强制性,只是建议,便于统一开发规范。 + +``` +. +├── client──────────────────────# 客户端逻辑 +│ └── user───────────────────# 用户服务 +│ └── order──────────────────# 订单服务 +└───────────────────────────────── +``` diff --git a/uniCloud-aliyun/cloudfunctions/router/service/muban.js b/uniCloud-aliyun/cloudfunctions/router/service/muban.js new file mode 100644 index 0000000..70d64a2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/muban.js @@ -0,0 +1,35 @@ +'use strict'; +module.exports = { + /** + * 此函数名称 + * @url user/pub/test1 前端调用的url参数地址 + * @description 此函数描述 + * @param {Object} data 请求参数 + * @param {String} uniIdToken 用户token + * @param {String} userInfo 当前登录用户信息(可信任,仅kh目录下的函数有此值) + * pub目录下请求参数需要带上 need_user_info = true + * @param {Object} util 公共工具包 + * @param {Object} filterResponse 过滤器返回的数据 + * @param {Object} originalParam 原始请求参数(包含了原始event和context) + * data 请求参数 说明 + * @param {String} uid 当前登录用户id(可信任,仅kh目录下的函数有此值) + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + // 注意: userInfo 和 uid 是可信任的,但默认只有kh目录下的函数才有此值 + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + + + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/muban_easy.js b/uniCloud-aliyun/cloudfunctions/router/service/muban_easy.js new file mode 100644 index 0000000..8601279 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/muban_easy.js @@ -0,0 +1,23 @@ +'use strict'; +module.exports = { + /** + * 此函数名称 + * @url user/pub/test1 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + + + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/muban_object.js b/uniCloud-aliyun/cloudfunctions/router/service/muban_object.js new file mode 100644 index 0000000..c9bdfd3 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/muban_object.js @@ -0,0 +1,67 @@ +'use strict'; +var vk; // 全局vk实例 +// 涉及的表名 +const dbName = { + //test: "vk-test", // 测试表 +}; + +var db = uniCloud.database(); // 全局数据库引用 +var _ = db.command; // 数据库操作符 +var $ = _.aggregate; // 聚合查询操作符 +/** + * 权限注意:访问以下链接查看 + * 文档地址:https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#内置权限 + */ +var cloudObject = { + isCloudObject: true, // 标记为云对象模式 + /** + * 请求前处理,主要用于调用方法之前进行预处理,一般用于拦截器、统一的身份验证、参数校验、定义全局对象等。 + * 文档地址:https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#before-预处理 + */ + _before: async function() { + vk = this.vk; // 将vk定义为全局对象 + // let { customUtil, uniID, config, pubFun } = this.getUtil(); // 获取工具包 + }, + /** + * 请求后处理,主要用于处理本次调用方法的返回结果或者抛出的错误 + * 文档地址:https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#after-后处理 + */ + _after: async function(options) { + let { err, res } = options; + if (err) { + return; // 如果方法抛出错误,直接return;不处理 + } + return res; + }, + /** + * 模板函数 + * @url client/muban.getInfo 前端调用的url参数地址 + */ + getInfo: async function(data) { + let { uid } = this.getClientInfo(); // 获取客户端信息 + let userInfo = await this.getUserInfo(); // 获取当前登录的用户信息 + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + console.log("请求参数", data); + res.userInfo = userInfo; // 返回前端当前登录的用户信息 + + // 业务逻辑结束----------------------------------------------------------- + return res; + }, + /** + * 模板函数 + * @url client/muban.getList 前端调用的url参数地址 + */ + getList: async function(data) { + let { uid, filterResponse, originalParam } = this.getClientInfo(); // 获取客户端信息 + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + console.log("请求参数", data); + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +}; + +module.exports = cloudObject; diff --git a/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/getAccessToken.js b/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/getAccessToken.js new file mode 100644 index 0000000..5d0ad22 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/getAccessToken.js @@ -0,0 +1,21 @@ +'use strict'; +module.exports = { + /** + * 获取accessToken + * @url plugs/baidu/client/pub/getAccessToken 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} image 图像数据,base64编码后进行urlencode,要求base64编码和urlencode后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/jpeg/png/bmp格式 + * @param {String} url 图片完整URL,URL长度不超过1024字节,URL对应的图片base64编码后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/jpeg/png/bmp格式,当image字段存在时url字段失效请注意关闭URL防盗链 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + res.access_token = await vk.openapi.baidu.open.auth.getAccessToken(); + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/ocr/business_license.js b/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/ocr/business_license.js new file mode 100644 index 0000000..7076624 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/ocr/business_license.js @@ -0,0 +1,29 @@ +'use strict'; +module.exports = { + /** + * 营业执照识别 + * @url plugs/baidu/client/pub/ocr/business_license 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} image 图像数据,base64编码后进行urlencode,要求base64编码和urlencode后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/jpeg/png/bmp格式 + * @param {String} url 图片完整URL,URL长度不超过1024字节,URL对应的图片base64编码后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/jpeg/png/bmp格式,当image字段存在时url字段失效请注意关闭URL防盗链 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + let { image, url } = data; + res = await vk.openapi.baidu.open.request({ + action:"ocr/v1/business_license", + actionVersion: "2.0", + data:{ + image, + url + } + }); + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/ocr/idcard.js b/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/ocr/idcard.js new file mode 100644 index 0000000..092bc79 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/ocr/idcard.js @@ -0,0 +1,29 @@ +'use strict'; +module.exports = { + /** + * 身份证识别 + * @url plugs/baidu/client/pub/ocr/idcard 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} image 图像数据,base64编码后进行urlencode,要求base64编码和urlencode后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/jpeg/png/bmp格式 + * @param {String} url 图片完整URL,URL长度不超过1024字节,URL对应的图片base64编码后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/jpeg/png/bmp格式,当image字段存在时url字段失效请注意关闭URL防盗链 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + let { image, url } = data; + res = await vk.openapi.baidu.open.request({ + action:"ocr/v1/idcard", + actionVersion: "2.0", + data:{ + image, + url + } + }); + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/getComponentsDynamicData.js b/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/getComponentsDynamicData.js new file mode 100644 index 0000000..5aa19d7 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/getComponentsDynamicData.js @@ -0,0 +1,37 @@ +module.exports = { + /** + * 此函数名称 + * @url plugs/components_dynamic/client/pub/getComponentsDynamicData 前端调用的url参数地址 + * data 请求参数 说明 + * @params {String} uid 当前登录用户id,若用户已登录且token有效,则data中会带uid参数 + * (此参数是后端过滤器通过token获取并添加到data中的,是可信任的)(只有kh函数才带此参数) + * @params {Array} ids 需要获取的组件数据 id数组 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { uid, ids } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 根据ids获取组件动态数据列表 + let res_select = await vk.baseDao.select({ + dbName:"vk-components-dynamic", + getCount:false, + pageSize:500, + whereJson:{ + data_id : _.in(ids) + }, + }); + // 将数组形式 转换成 组件需要的格式 + res.componentsDynamic = {}; + for(let i in res_select.rows){ + let item = res_select.rows[i]; + res.componentsDynamic[item.data_id] = item.data; + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/init.js b/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/init.js new file mode 100644 index 0000000..43822d3 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/init.js @@ -0,0 +1,138 @@ +module.exports = { + /** + * 初始化数据 + * @url plugs/components_dynamic/client/pub/init 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + // 承载所有读操作的 promise 的数组 + let dbName = "vk-components-dynamic"; + let data_ids = [ + "vk-test-notice-bar-01", + "vk-test-notice-bar-02", + "vk-test-notice-bar-03", + "vk-test-notice-bar-04", + "vk-test-index-swiper-01", + "vk-test-grid-button-01" + ]; + let whereJson = { + data_id:_.in(data_ids) + }; + res = await vk.baseDao.select({ + dbName:dbName, + getCount:true, + pageIndex:1, + pageSize:100, + whereJson:whereJson + }); + if(res.rows.length == data_ids.length){ + return res; + } + await vk.baseDao.del({ + dbName:dbName, + whereJson:whereJson + }); + let dataArr = [ + { + "data_id": "vk-test-notice-bar-01", + "data": { + "list": [ + "公告111公告111公告111公告111公告111公告111公告111" + ] + } + }, + { + "data_id": "vk-test-notice-bar-02", + "data": { + "list": [ + "公告222公告222公告222公告222公告222公告222公告222" + ] + } + }, + { + "data_id": "vk-test-notice-bar-03", + "data": { + "list": [ + "公告333333公告333333公告333333公告333333公告333333" + ] + } + }, + { + "data_id": "vk-test-notice-bar-04", + "data": { + "list": [ + "公告44444公告44444公告44444公告44444公告44444公告44444" + ] + } + }, + { + "data_id": "vk-test-index-swiper-01", + "data": { + "list": [ + { + "title": "标题11111111", + "image": "https://img0.baidu.com/it/u=1595128334,82706458&fm=26&fmt=auto&gp=0.jpg" + }, + { + "title": "标题2222222", + "image": "https://img2.baidu.com/it/u=3290011888,2972843018&fm=26&fmt=auto&gp=0.jpg" + }, + { + "title": "标题3333333", + "image": "https://img2.baidu.com/it/u=528808604,872300859&fm=26&fmt=auto&gp=0.jpg" + } + ], + "height": 300 + } + }, + { + "data_id": "vk-test-grid-button-01", + "data": { + "col":4, + "icon-size":46, + "text-margin-top":10, + "text-color":"#000000", + "icon-color":"#000000", + "border":false, + "list":[ + { + "icon":"red-packet", + "text":"按钮1", + "page":"../vk-u-notice-bar/vk-u-notice-bar" + }, + { + "icon":"red-packet", + "text":"按钮2", + "icon-color":"red", + "page":"../vk-u-swiper/vk-u-swiper" + }, + { + "icon":"red-packet", + "text":"按钮3", + "text-color":"red" + }, + { + "icon":"red-packet", + "text":"按钮4" + } + ] + } + } + ]; + await vk.baseDao.adds({ + dbName:dbName, + dataJson:dataArr + }); + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/update.js b/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/update.js new file mode 100644 index 0000000..80a415b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/update.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 修改数据 + * @url plugs/components_dynamic/client/pub/update 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid, data_id, data_value } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res.num = await vk.baseDao.update({ + dbName:"vk-components-dynamic", + whereJson:{ + data_id : data_id, + }, + dataJson:{ + data : data_value + } + },event.util); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/plugs/插件.md b/uniCloud-aliyun/cloudfunctions/router/service/plugs/插件.md new file mode 100644 index 0000000..35af134 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/plugs/插件.md @@ -0,0 +1,15 @@ +## 插件 +#### `router/service/plugs` +#### 此目录一般为插件作者开发的一些通用功能,如动态数据组件的API将在此目录,未来会新增微信小程序订阅消息发送等等。 + +``` +. +├── plugs──────────────────────# 插件逻辑 +│ └── plugs-A───────────────────# 插件A +│ ────└── admin───────────────────# 插件A admin端 +│ ────└── client──────────────────# 插件A client端 +│ └── plugs-B───────────────────# 插件B +│ ────└── admin───────────────────# 插件B admin端 +│ ────└── client──────────────────# 插件B client端 +└───────────────────────────────── +``` diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/Promise.all.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/Promise.all.js new file mode 100644 index 0000000..52b1628 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/Promise.all.js @@ -0,0 +1,54 @@ +module.exports = { + /** + * 此函数名称 + * @url template/db_api/user/pub/Promise.all 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "vk-test"; + let runTime1 = new Date().getTime(); + let addNum = 200; + console.log(new Date(runTime1),"开始运行,添加"+addNum+"条数据"); + // 承载所有读操作的 promise 的数组 + let tasks = []; + for(let i = 1; i <= addNum; i++){ + let promise = vk.baseDao.add({ + dbName:dbName, + dataJson:{ + "money": 10.02+i, + "_add_time": 1597456395010+i, + "user_id": "001" + } + }); + tasks.push(promise); + } + // 等待所有 + let ids = []; + try { + res = await Promise.all(tasks).then((values) => { + return { + //ids:values, + total:values.length + }; + }); + } catch (e) { + //console.log("异常:",e,res); + console.log("异常:运行超时"); + res.msg = "运行超时"; + } + let runTime2 = new Date().getTime(); + let runTime = (runTime2 - runTime1) / 1000 + "秒"; + console.log(new Date(runTime2),"运行结束,耗时:"+runTime); + res.runTime = runTime; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/add.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/add.js new file mode 100644 index 0000000..659c4d8 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/add.js @@ -0,0 +1,40 @@ +module.exports = { + /** + * 添加单条数据 + * @url template/db_api/pub/add 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let startTime = Date.now(); + + // 为了方便测试,这里固定在杭州市西湖区附近 + let longitude = 120.12792 + Math.floor(Math.random() * 500) / 10000; + let latitude = 30.228932 + Math.floor(Math.random() * 500) / 10000; + // 随机定位结束----------------------------------------------------------- + res.id = await vk.baseDao.add({ + dbName:"vk-test", + dataJson:{ + "money": Math.floor(Math.random() * 9 + 1), + "user_id": "00"+Math.floor(Math.random() * 2 + 1), + "location":new db.Geo.Point(longitude, latitude), + "position":{ + "longitude":longitude, + "latitude":latitude, + }, + } + }); + + let endTime = Date.now(); + res.runTime = (endTime - startTime); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/adds.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/adds.js new file mode 100644 index 0000000..c331c1c --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/adds.js @@ -0,0 +1,50 @@ +module.exports = { + /** + * 批量添加数据 + * @url template/db_api/pub/adds 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "vk-test"; + let startTime = Date.now(); + let addNum = 10; + console.log("开始运行,添加"+addNum+"条数据"); + // 承载所有读操作的 promise 的数组 + let dataArr = []; + + for(let i = 1; i <= addNum; i++){ + // 随机定位开始----------------------------------------------------------- + // 为了方便测试,这里固定在杭州市西湖区附近 + let longitude = 120.12792 + Math.floor(Math.random() * 500) / 10000; + let latitude = 30.228932 + Math.floor(Math.random() * 500) / 10000; + // 随机定位结束----------------------------------------------------------- + dataArr.push({ + "money": Math.floor(Math.random() * 9 + 1), + "user_id": "00"+Math.floor(Math.random() * 2 + 1), + "location":new db.Geo.Point(longitude, latitude), + "position":{ + "longitude":longitude, + "latitude":latitude, + }, + }); + } + await vk.baseDao.adds({ + dbName:dbName, + dataJson:dataArr + }); + + let endTime = Date.now(); + res.runTime = endTime - startTime; + console.log("运行结束,耗时:"+res.runTime/1000 + "秒"); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/avg.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/avg.js new file mode 100644 index 0000000..83b5637 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/avg.js @@ -0,0 +1,27 @@ +module.exports = { + /** + * avg求平均值 + * @url template/db_api/pub/avg 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res.avg = await vk.baseDao.avg({ + dbName:"vk-test", + fieldName:"money", + whereJson:{ + + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/count.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/count.js new file mode 100644 index 0000000..2ddcb75 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/count.js @@ -0,0 +1,33 @@ +module.exports = { + /** + * count求总记录条数 + * @url template/db_api/pub/count 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let startTime = Date.now(); + + res.num = await vk.baseDao.count({ + dbName:"vk-test", + whereJson:{ + + } + }); + + let endTime = Date.now(); + res.runTime = (endTime - startTime); + // 对应的sql: + // count * from vk-test + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/del.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/del.js new file mode 100644 index 0000000..71ba0db --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/del.js @@ -0,0 +1,33 @@ +module.exports = { + /** + * 数据删除 + * @url template/db_api/pub/del 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + /** + * 这里为了防止误删,故vk.baseDao.del API + * 会判断如果whereJson为空,则不执行删除操作 + * 所以这里加了个_id: _.exists(true)条件来达到删除全部的功能(实际开发时慎用删除全部功能) + */ + res.num = await vk.baseDao.del({ + dbName:"vk-test", + whereJson:{ + _id: _.exists(true) + } + }); + // 对应的sql: + // delete from vk-test where user_id != '___' + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/deleteById.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/deleteById.js new file mode 100644 index 0000000..2261b44 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/deleteById.js @@ -0,0 +1,25 @@ +module.exports = { + /** + * 数据删除 + * @url template/db_api/pub/del 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + res.num = await vk.baseDao.deleteById({ + dbName:"vk-test", + id:_id + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/findById.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/findById.js new file mode 100644 index 0000000..30c8f43 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/findById.js @@ -0,0 +1,33 @@ +module.exports = { + /** + * 根据id获取记录 + * @url template/db_api/pub/findById 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let startTime = Date.now(); + res.item = await vk.baseDao.findById({ + dbName:"vk-test", + id:data._id, + fieldJson:{ + + } + }); + let endTime = Date.now(); + res.runTime = (endTime - startTime); + // 上面的 fieldJson 可以设置 显示什么字段或设置不显示什么字段 如 money:false 代表不显示money字段 + // 对应的sql: + // select * from vk-test where _id = "5f3a125b3d11c6000106d338" + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/findByWhereJson.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/findByWhereJson.js new file mode 100644 index 0000000..6f01891 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/findByWhereJson.js @@ -0,0 +1,38 @@ +module.exports = { + /** + * 根据where条件获取单条记录(首条) + * @url template/db_api/pub/findByWhereJson 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let startTime = Date.now(); + + res.item = await vk.baseDao.findByWhereJson({ + dbName:"vk-test", + fieldJson:{ + + }, + whereJson:{ + _id:data._id, + } + }); + + let endTime = Date.now(); + res.runTime = (endTime - startTime); + + // 上面的 fieldJson 可以设置 显示什么字段或设置不显示什么字段 如 money:false 代表不显示money字段 + // 对应的sql: + // select * from vk-test where _id = "5f3a125b3d11c6000106d338" + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/geo.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/geo.js new file mode 100644 index 0000000..1350f3f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/geo.js @@ -0,0 +1,33 @@ +module.exports = { + /** + * 根据地理位置获取列表数据信息 + * @url template/db_api/pub/geo 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res = await vk.baseDao.selects({ + dbName:"vk-test", + pageIndex:1, + pageSize:100, + whereJson:{ + location: _.geoNear({ + geometry: new db.Geo.Point(120.12792, 30.228932), // 点的地理位置,为了方便测试,这里固定在杭州市西湖区 + maxDistance: 4000, // 选填,最大距离,米为单位 + minDistance: 0 ,// 选填,最小距离,米为单位 + distanceMultiplier:1, // 返回时在距离上乘以该数字 1代表米 100 代表厘米 0.001 代表千米 + distanceField:"distance", // 输出的每个记录中 distance 即是与给定点的距离 + }) + }, + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/getList.js new file mode 100644 index 0000000..d9af7a6 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/getList.js @@ -0,0 +1,73 @@ +module.exports = { + /** + * 查询多条记录 分页 + * @url template/db_api/pub/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @params {String} tableName 表名 + * @params {String} addTime 搜索开始时间 + * @params {String} endTime 搜索截止时间 + * @params {String} searchvalue 搜索指定内容 + * @params {Number} pageIndex 当前页码 + * @params {Number} pageSize 每页显示数量 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let { pageIndex, pageSize, searchvalue, timeArr = [], addTimeLong, endTimeLong, sortRule } = data; + let dbName = "vk-test"; + let fieldJson = {}; + let whereJson = {}; + let sortArr = []; + // 排序规则开始----------------------------------------------------------- + sortArr.push({ + "name":"_add_time", + "type":"desc" + }); + if(sortRule) sortArr = sortRule; + // 排序规则结束----------------------------------------------------------- + // 查询条件开始----------------------------------------------------------- + if(searchvalue){ + // 查询searchvalue开头的数据 + try{ + // 如果查询需要用到正则,建议将正则用try catch 包起来。 + //whereJson["title"] = new RegExp('^'+searchvalue); + whereJson["money"] = Number(searchvalue); + }catch(err){ + return { code : -1, msg : '请输入合法的查询内容' }; + } + } + if(timeArr.length >=2 ){ + addTimeLong = timeArr[0]; + endTimeLong = timeArr[1]; + } + if(addTimeLong && endTimeLong){ + whereJson["_add_time"] = _.gte(addTimeLong).lte(endTimeLong); + }else if(addTimeLong && !endTimeLong){ + whereJson["_add_time"] = _.gte(addTimeLong); + }else if(!addTimeLong && endTimeLong){ + whereJson["_add_time"] = _.lte(endTimeLong); + } + // 这里可以写必须满足的查询条件,如whereJson["user_id"] = uid;代表只查自己的记录 + // whereJson["user_id"] = uid; + // 查询条件结束----------------------------------------------------------- + res = await vk.baseDao.select({ + dbName:dbName, + getCount:true, + pageIndex:pageIndex, + pageSize:pageSize, + fieldJson:fieldJson, + whereJson:whereJson, + sortArr:sortArr + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/groupCount.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/groupCount.js new file mode 100644 index 0000000..258ea04 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/groupCount.js @@ -0,0 +1,38 @@ +module.exports = { + /** + * 分组求count + * @url template/db_api/pub/groupCount 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id = "___" } = data; + res = await vk.baseDao.selects({ + dbName: "vk-test", + pageIndex: 1, + pageSize: 10, + // 主表where条件 + whereJson: { + + }, + groupJson: { + _id: "$money", // _id是分组id, $ 后面接字段名,如按money字段进行分组 + count: _.$.addToSet("$user_id"), // $ 后面接字段名,如把user_id原样输出(去重) + }, + sortArr: [{ name: "money",type: "desc" }], // 对分组后的结果进行排序 + addFields:{ + count: _.$.size("$count") + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/max.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/max.js new file mode 100644 index 0000000..095865b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/max.js @@ -0,0 +1,27 @@ +module.exports = { + /** + * max求最大值 + * @url template/db_api/pub/max 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res.max = await vk.baseDao.max({ + dbName:"vk-test", + fieldName:"money", + whereJson:{ + + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/min.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/min.js new file mode 100644 index 0000000..14152d3 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/min.js @@ -0,0 +1,27 @@ +module.exports = { + /** + * min求最小值 + * @url template/db_api/pub/min 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res.min = await vk.baseDao.min({ + dbName:"vk-test", + fieldName:"money", + whereJson:{ + + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/sample.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/sample.js new file mode 100644 index 0000000..ba8fa80 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/sample.js @@ -0,0 +1,27 @@ +module.exports = { + /** + * sample随机获取N条数据 + * @url template/db_api/pub/sample 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res.list = await vk.baseDao.sample({ + dbName:"vk-test", + size:1, + whereJson:{ + + }, + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/select.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/select.js new file mode 100644 index 0000000..89c052b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/select.js @@ -0,0 +1,30 @@ +module.exports = { + /** + * 查询多条记录 + * @url template/db_api/pub/select 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res = await vk.baseDao.select({ + dbName: "vk-test", + getCount: true, + pageIndex: 1, + pageSize: 10, + whereJson: { + + } + }); + // 对应的sql: + // select * from vk-test limit 0,100; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/select2.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/select2.js new file mode 100644 index 0000000..e0b47f0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/select2.js @@ -0,0 +1,50 @@ +module.exports = { + /** + * 连表查询(仅限两表查询)(VK版本) + * @url template/db_api/pub/select2 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + // 想要两表以上的连接,请使用vk.baseDao.selects + res = await vk.baseDao.selects({ + dbName:"uni-id-users", + foreignKey:"_id", + getCount:false, + pageIndex:1, + pageSize:10, + // 主表where条件 + whereJson:{ + + }, + // 主表字段显示规则 + fieldJson:{token:false, password:false}, + // 主表排序规则 + sortArr:[{"name":"_id", "type":"desc"}], + // 副表列表 + foreignDB:[ + { + dbName:"vk-test", + foreignKey:"user_id", + as:"testList", + limit:1, + // 副表where条件 + whereJson:{ }, + // 副表字段显示规则 + fieldJson:{ }, + // 副表排序规则 + sortArr:[{"name":"money", "type":"desc"}], + } + ] + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects.js new file mode 100644 index 0000000..028bb22 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects.js @@ -0,0 +1,51 @@ +module.exports = { + /** + * 多表查询(支持多张表连接查询)(VK版本) + * @url template/db_api/pub/selects 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + // 演示3表连接 + res = await vk.baseDao.selects({ + dbName:"uni-id-users", + getCount:false, + pageIndex:1, + pageSize:10, + // 主表where条件 + whereJson:{ + + }, + // 主表字段显示规则 + fieldJson:{ token:false, password:false }, + // 主表排序规则 + sortArr:[{ "name":"_id", "type":"desc" }], + // 副表列表 + foreignDB:[ + { + dbName:"vk-test", + localKey:"_id", + foreignKey:"user_id", + as:"testList", + limit:1 + }, + { + dbName:"gy-shop", + localKey:"_id", + foreignKey:"user_id", + as:"shopList", + limit:1 + }, + ] + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_geo.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_geo.js new file mode 100644 index 0000000..6a9bf76 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_geo.js @@ -0,0 +1,47 @@ +module.exports = { + /** + * 连表查询地理位置就近搜索示例 + * @url template/db_api/pub/selects_geo 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + // 演示3表连接 + res = await vk.baseDao.selects({ + dbName:"vk-test", + getCount:true, + pageIndex:1, + pageSize:10, + // 主表where条件 + whereJson:{ + location: _.geoNear({ + geometry: new db.Geo.Point(120.12792, 30.228932), // 点的地理位置,为了方便测试,这里固定在杭州市西湖区 + maxDistance: 4000, // 选填,最大距离,米为单位 + minDistance: 0 , // 选填,最小距离,米为单位 + distanceMultiplier:1, // 返回时在距离上乘以该数字 1代表米 100 代表厘米 0.001 代表千米 + distanceField:"distance", // 输出的每个记录中 distance 即是与给定点的距离 + }), + money:_.gt(0) + }, + // 副表列表 + foreignDB:[ + { + dbName:"uni-id-users", + localKey:"user_id", + foreignKey:"_id", + as:"userInfo", + limit:1 + } + ] + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_getOne.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_getOne.js new file mode 100644 index 0000000..033b6a3 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_getOne.js @@ -0,0 +1,48 @@ +module.exports = { + /** + * 连表查询,并返回第一条数据 + * @url template/db_api/pub/selects_getOne 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + // 演示3表连接 + res.info = await vk.baseDao.selects({ + dbName:"uni-id-users", + getOne:true, + getMain:true, + // 主表where条件 + whereJson:{ + _id:"001" + }, + // 主表字段显示规则 + fieldJson:{ token:false, password:false }, + // 副表列表 + foreignDB:[ + { + dbName:"vk-test", + localKey:"_id", + foreignKey:"user_id", + as:"testList", + limit:1 + }, + { + dbName:"gy-shop", + localKey:"_id", + foreignKey:"user_id", + as:"shopList", + limit:1 + }, + ] + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_inviter_uid.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_inviter_uid.js new file mode 100644 index 0000000..c89d725 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_inviter_uid.js @@ -0,0 +1,45 @@ +module.exports = { + /** + * 多表查询 + * @url template/db_api/pub/selects_inviter_uid 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk, db, _, $ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + /** + * 此为演示 使用数组下标对应的值进行连表,如用户表根据inviter_uid的第一个值进行连表查出第一个上级的用户信息 + */ + res = await vk.baseDao.selects({ + dbName: "uni-id-users", + getCount: false, + pageIndex: 1, + pageSize: 5, + fieldJson: { + token: false, + password: false + }, + // 副表列表 + foreignDB: [{ + dbName: "uni-id-users", + localKey: $.arrayElemAt(['$inviter_uid', 0]), + foreignKey: "_id", + as: "inviterUserInfo", + limit: 1, + fieldJson: { + token: false, + password: false + }, + }] + }); + console.log(11, res.rows); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_mode_2.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_mode_2.js new file mode 100644 index 0000000..6809d77 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_mode_2.js @@ -0,0 +1,43 @@ +module.exports = { + /** + * 多表查询(支持多张表连接查询)(VK2.0版本) + * @url template/db_api/pub/selects_mode_2 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + /** + * 此为简化版 + * 此版本支持无限张表和主表进行连接 + */ + res = await vk.baseDao.selects({ + dbName:"opendb-mall-comments", + // 副表列表 + foreignDB:[ + { + dbName:"opendb-mall-goods", + localKey:"goods_id", + foreignKey:"_id", + as:"goodsInfo", + limit:1 + }, + { + dbName:"uni-id-users", + localKey:"user_id", + foreignKey:"_id", + as:"userInfo", + limit:1 + } + ] + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_mode_3.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_mode_3.js new file mode 100644 index 0000000..b5e4459 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_mode_3.js @@ -0,0 +1,44 @@ +module.exports = { + /** + * 多表查询(支持多张表连接查询)(VK3.0版本) + * @url template/db_api/pub/selects_mode_3 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + /** + * 此为演示竖向无限层连接 + */ + res = await vk.baseDao.selects({ + dbName:"opendb-mall-comments", + // 副表列表 + foreignDB:[ + { + dbName:"uni-id-users", + localKey:"user_id", + foreignKey:"_id", + as:"userInfo", + limit:1, + foreignDB:[ + { + dbName:"opendb-mall-orders", + localKey:"_id", + foreignKey:"user_id", + as:"orderList", + limit:3, + }, + ] + } + ] + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/sum.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/sum.js new file mode 100644 index 0000000..5024dcf --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/sum.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * sum求和 + * @url template/db_api/pub/sum 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res.sum = await vk.baseDao.sum({ + dbName:"vk-test", + fieldName:"money", + whereJson:{ + + } + }); + // 对应的sql: + // select sum(money) from vk-test + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/tree.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/tree.js new file mode 100644 index 0000000..7877dfa --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/tree.js @@ -0,0 +1,36 @@ +'use strict'; +module.exports = { + /** + * XXXnameXXX + * @url template/db_api/pub/tree 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + res = await vk.baseDao.getTableData({ + dbName: "opendb-admin-menus", + whereJson:{ + enable: true, + parent_id: null + }, + // 树状结构参数 + treeProps: { + id: "menu_id", // 唯一标识字段,默认为 _id + parent_id: "parent_id", // 父级标识字段,默认为 parent_id + children: "children", // 自定义返回的下级字段名,默认为 children + level: 3, // 查询返回的树的最大层级。超过设定层级的节点不会返回。默认10级,最大15,最小1 + limit: 500, // 每一级最大返回的数据。 + whereJson: { + enable: true + } + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/update.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/update.js new file mode 100644 index 0000000..123032b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/update.js @@ -0,0 +1,30 @@ +module.exports = { + /** + * 修改数据 + * @url template/db_api/pub/update 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id = "___" } = data; + res.num = await vk.baseDao.update({ + dbName:"vk-test", + whereJson:{ + _id:_id, + }, + dataJson:{ + money:1 + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/updateAndReturn.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/updateAndReturn.js new file mode 100644 index 0000000..83d31be --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/updateAndReturn.js @@ -0,0 +1,63 @@ +module.exports = { + /** + * 修改数据,并返回修改后的数据 + * @url template/db_api/pub/updateAndReturn 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id = "___" } = data; + + // 非事务版本开始----------------------------------------------------------- + res.info = await vk.baseDao.updateAndReturn({ + dbName: "vk-test", + whereJson: { + _id: _id + }, + dataJson: { + money: _.inc(1) + }, + }); + // 非事务版本结束----------------------------------------------------------- + + + // 事务版本开始----------------------------------------------------------- + /* + const transaction = await vk.baseDao.startTransaction(); + try { + res.info = await vk.baseDao.updateAndReturn({ + db:transaction, + dbName:"vk-test", + whereJson:{ + _id:_id + }, + dataJson:{ + money:_.inc(1) + }, + }); + // 提交事物 + await transaction.commit(); + console.log(`transaction succeeded`); + return res; + }catch (err) { + // 事务回滚 + return await vk.baseDao.rollbackTransaction({ + db:transaction, + err + }); + } + */ + // 事务版本结束----------------------------------------------------------- + + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/updateById.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/updateById.js new file mode 100644 index 0000000..12b83ff --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/updateById.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 修改数据,并返回修改后的数据 + * @url template/db_api/pub/updateById 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id = "___" } = data; + res.info = await vk.baseDao.updateById({ + dbName:"vk-test", + id:_id, + dataJson:{ + money:1 + }, + getUpdateData:true + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/add.js new file mode 100644 index 0000000..d00f14f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/add.js @@ -0,0 +1,33 @@ +module.exports = { + /** + * 添加单条数据 + * @url template/db_api/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + user_id, + money, + remark, + } = data; + let dbName = "vk-test"; + res.id = await vk.baseDao.add({ + dbName, + dataJson:{ + user_id, + money, + remark, + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/delete.js new file mode 100644 index 0000000..12ea03b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/delete.js @@ -0,0 +1,30 @@ +module.exports = { + /** + * 数据删除 + * @url template/db_api/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + // 这里id不传默认设置成"___" 是为了防止因未传_id导致误删所有数据. + let { _id } = data; + if(vk.pubfn.isNull(_id)){ + return { code : -1, msg : 'id不能为空' }; + } + let dbName = "vk-test"; + await vk.baseDao.deleteById({ + dbName, + id:_id + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/getList.js new file mode 100644 index 0000000..aadac87 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/getList.js @@ -0,0 +1,30 @@ +module.exports = { + /** + * 查询多条记录 分页 + * @url template/db_api/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @params {Number} pageIndex 当前页码 + * @params {Number} pageSize 每页显示数量 + * @params {Array} sortRule 排序规则 + * @params {object} formData 查询条件数据源 + * @params {Array} columns 查询条件规则 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let dbName = "vk-test"; + res = await vk.baseDao.getTableData({ + dbName, + data + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/update.js new file mode 100644 index 0000000..67c922e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/update.js @@ -0,0 +1,39 @@ +module.exports = { + /** + * 修改数据 + * @url template/db_api/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + user_id, + money, + remark, + } = data; + if(vk.pubfn.isNullOne(_id)){ + return { code : -1, msg : '参数错误' }; + } + let dbName = "vk-test"; + await vk.baseDao.updateById({ + dbName, + id:_id, + dataJson:{ + user_id, + money, + remark, + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/alipay/pub/code2Session.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/alipay/pub/code2Session.js new file mode 100644 index 0000000..da6c233 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/alipay/pub/code2Session.js @@ -0,0 +1,30 @@ +'use strict'; +module.exports = { + /** + * code2Session + * @url template/openapi/alipay/pub/code2Session 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { + code, + } = data; + let code2SessionRes = await vk.openapi.alipay.auth.code2Session({ + code, + needKey: true + }); + if (code2SessionRes.code !== 0) { + return code2SessionRes; + } + console.log('code2SessionRes: ', code2SessionRes); + res.openid = code2SessionRes.openid; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/alipay/pub/getMiniCode.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/alipay/pub/getMiniCode.js new file mode 100644 index 0000000..ab85fd7 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/alipay/pub/getMiniCode.js @@ -0,0 +1,24 @@ +'use strict'; +module.exports = { + /** + * 获取支付宝小程序码 + * @url template/openapi/alipay/pub/getMiniCode 前端调用的url参数地址 + * data 请求参数 + * @param {String} path 小程序页面路径 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { + page, + scene + } = data; + res = await vk.openapi.alipay.acode.getMiniCode(data); + res.base64 = res.qr_code_url_circle_white; // 兼容其他小程序的返回字段 + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/douyin/pub/code2Session.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/douyin/pub/code2Session.js new file mode 100644 index 0000000..45453f1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/douyin/pub/code2Session.js @@ -0,0 +1,34 @@ +'use strict'; +module.exports = { + /** + * code2Session + * @url template/openapi/douyin/pub/code2Session 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { + code, + anonymousCode + } = data; + let code2SessionRes = await vk.openapi.douyin.auth.code2Session({ + code, + anonymousCode, + needKey: true + }); + if (code2SessionRes.code !== 0) { + return code2SessionRes; + } + console.log('code2SessionRes: ', code2SessionRes); + res.openid = code2SessionRes.openid; + res.anonymousOpenid = code2SessionRes.anonymousOpenid; + res.unionid = code2SessionRes.unionid; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/douyin/pub/getMiniCode.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/douyin/pub/getMiniCode.js new file mode 100644 index 0000000..1c453a0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/douyin/pub/getMiniCode.js @@ -0,0 +1,46 @@ +'use strict'; +module.exports = { + /** + * 获取抖音小程序码 + * @url template/openapi/douyin/pub/getMiniCode 前端调用的url参数地址 + * data 请求参数 + * @param {String} path 小程序页面路径 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { + path + } = data; + + res = await vk.openapi.douyin.acode.getMiniCode({ + path + }); + if (typeof res === "object" && res.code) { + return res; + } + try { + // 二进制转base64 + let base64 = Buffer.from(res, 'binary').toString('base64'); + return { + code: 0, + base64: `data:image/png;base64,${base64}` + }; + } catch (err) { + // 转base64失败 + return { + code: -1, + msg: "生成小程序码失败", + err: { + message: err.message, + stack: err.stack + } + }; + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/douyin/pub/imgSecCheck.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/douyin/pub/imgSecCheck.js new file mode 100644 index 0000000..cf41883 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/douyin/pub/imgSecCheck.js @@ -0,0 +1,38 @@ +'use strict'; +module.exports = { + /** + * 图片违规检测示例 + * @url template/openapi/douyin/pub/imgSecCheck 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { base64 } = data; + /** + * 实际开发中,图片可能是多张图,比如多达9张图 + * 如果在一个请求中循环检测,可能会超时。 + * 方案1:前端选择完图片就自动一张一张检测和上传(即9张图会有9个请求) + * 方案2:使用Promise.all + */ + let imgSecCheckRes = await vk.openapi.douyin.security.imgSecCheck({ + base64 + }); + if (imgSecCheckRes.code !== 0) { + // 未通过检测 + return imgSecCheckRes; + } + // 若通过检测,则继续执行自己的业务 + // ... + // ... + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/douyin/pub/msgSecCheck.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/douyin/pub/msgSecCheck.js new file mode 100644 index 0000000..3b1aa99 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/douyin/pub/msgSecCheck.js @@ -0,0 +1,36 @@ +'use strict'; +module.exports = { + /** + * 文本违规检测示例 + * @url template/openapi/douyin/pub/msgSecCheck 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + content, + } = data; + // 实际业务中,content可能是评论的内容等 + let msgSecCheckRes = await vk.openapi.douyin.security.msgSecCheck({ + content, + }); + if (msgSecCheckRes.code !== 0) { + // 未通过检测 + return msgSecCheckRes; + } + res.result = msgSecCheckRes; + // 若通过检测,则继续执行自己的业务 + // ... + // ... + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/code2Session.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/code2Session.js new file mode 100644 index 0000000..88c9616 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/code2Session.js @@ -0,0 +1,32 @@ +'use strict'; +module.exports = { + /** + * code2Session + * @url template/openapi/qq/pub/code2Session 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { + code, + anonymousCode + } = data; + let code2SessionRes = await vk.openapi.qq.auth.code2Session({ + code, + needKey: true + }); + if (code2SessionRes.code !== 0) { + return code2SessionRes; + } + console.log('code2SessionRes: ', code2SessionRes); + res.openid = code2SessionRes.openid; + res.unionid = code2SessionRes.unionid; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/imgSecCheck.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/imgSecCheck.js new file mode 100644 index 0000000..d1e8b63 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/imgSecCheck.js @@ -0,0 +1,39 @@ +'use strict'; +module.exports = { + /** + * 图片违规检测示例 + * @url template/openapi/qq/pub/imgSecCheck 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { base64 } = data; + /** + * 实际开发中,图片可能是多张图,比如多达9张图 + * 如果在一个请求中循环检测,可能会超时。 + * 方案1:前端选择完图片就自动一张一张检测和上传(即9张图会有9个请求) + * 方案2:使用Promise.all + * 特别注意:目前微信小程序的这个API有1M大小的限制。(此为微信官方限制) + */ + let imgSecCheckRes = await vk.openapi.qq.security.imgSecCheck({ + base64 + }); + if(imgSecCheckRes.code !== 0){ + // 未通过检测 + return imgSecCheckRes; + } + // 若通过检测,则继续执行自己的业务 + // ... + // ... + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/msgSecCheck.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/msgSecCheck.js new file mode 100644 index 0000000..125eeab --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/msgSecCheck.js @@ -0,0 +1,36 @@ +'use strict'; +module.exports = { + /** + * 文本违规检测示例 + * @url template/openapi/qq/pub/msgSecCheck 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + content, + } = data; + // 实际业务中,content可能是评论的内容等 + let msgSecCheckRes = await vk.openapi.qq.security.msgSecCheck({ + content, + }); + if (msgSecCheckRes.code !== 0) { + // 未通过检测 + return msgSecCheckRes; + } + res.result = msgSecCheckRes; + // 若通过检测,则继续执行自己的业务 + // ... + // ... + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/getTemplateList.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/getTemplateList.js new file mode 100644 index 0000000..9e3da7f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/getTemplateList.js @@ -0,0 +1,27 @@ +'use strict'; +module.exports = { + /** + * 获取模板列表 + * @url template/openapi/weixin/pub/getTemplateList 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res = await vk.openapi.weixin.request({ + method: "get", + url: "wxaapi/newtmpl/gettemplate", + data: { + + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/imgSecCheck.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/imgSecCheck.js new file mode 100644 index 0000000..a3f1e44 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/imgSecCheck.js @@ -0,0 +1,39 @@ +'use strict'; +module.exports = { + /** + * 图片违规检测示例 + * @url template/openapi/weixin/pub/imgSecCheck 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { base64 } = data; + /** + * 实际开发中,图片可能是多张图,比如多达9张图 + * 如果在一个请求中循环检测,可能会超时。 + * 方案1:前端选择完图片就自动一张一张检测和上传(即9张图会有9个请求) + * 方案2:使用Promise.all + * 特别注意:目前微信小程序的这个API有1M大小的限制。(此为微信官方限制) + */ + let imgSecCheckRes = await vk.openapi.weixin.security.imgSecCheck({ + base64 + }); + if(imgSecCheckRes.code !== 0){ + // 未通过检测 + return imgSecCheckRes; + } + // 若通过检测,则继续执行自己的业务 + // ... + // ... + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/msgSecCheck.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/msgSecCheck.js new file mode 100644 index 0000000..c314c80 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/msgSecCheck.js @@ -0,0 +1,48 @@ +'use strict'; +module.exports = { + /** + * 文本违规检测示例 + * @url template/openapi/weixin/pub/msgSecCheck 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + content, + version, + scene, + openid, + title, + nickname, + signature, + } = data; + // 实际业务中,content可能是评论的内容等 + let msgSecCheckRes = await vk.openapi.weixin.security.msgSecCheck({ + content, + version, + scene, + openid, + title, + nickname, + signature, + }); + if (msgSecCheckRes.code !== 0) { + // 未通过检测 + return msgSecCheckRes; + } + res.result = msgSecCheckRes; + // 若通过检测,则继续执行自己的业务 + // ... + // ... + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendMessage.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendMessage.js new file mode 100644 index 0000000..dfcc9fd --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendMessage.js @@ -0,0 +1,45 @@ +'use strict'; +module.exports = { + /** + * 发送订阅消息 + * @url template/openapi/weixin/pub/sendMessage 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { openid } = data; + res = await vk.openapi.weixin.subscribeMessage.send({ + touser : openid, // 接收者(用户)的 openid + template_id : "UmINo5I6IcqktIwNt2TVorkU7f4dzd4eyNjfvOiwEC0", // 所需下发的订阅模板id + page : "pages/index/index", // 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。 + data : { + character_string1:{ + value:"202008030930001" + }, + name2:{ + value:"中通快递" + }, + character_string3:{ + value:"ZT2019928321392931" + }, + thing6:{ + value:"雪花秀滋盈生人生焕颜精华露" + }, + thing8:{ + value:"杭州市xxxxxxxxx号" + } + }, + miniprogram_state : "formal", // 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版 + }); + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendTemplateMessage.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendTemplateMessage.js new file mode 100644 index 0000000..a0c179a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendTemplateMessage.js @@ -0,0 +1,59 @@ +'use strict'; +module.exports = { + /** + * 发送公众号模板消息(touser只能是用户在该公众号下的openid) + * @url template/openapi/weixin/pub/sendTemplateMessage 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res = await vk.openapi.weixin.h5.templateMessage.send({ + touser: "", // 接收者(用户)的 openid(该用户在公众号下的openid) + template_id: "", // 所需下发的订阅模板id + url: "https://www.baidu.com", // 跳转网页时填写(如填了miniprogram参数则忽略url参数) + miniprogram: { + appid: "", + pagepath: "pages/order/order?id=aaa" + }, + data: { + "first": { + "value": "您购买的订单已经发货啦,正快马加鞭向您飞奔而去。", + "color": "#173177" + }, + "keyword1": { + "value": "D201803111235825", + "color": "#173177" + }, + "keyword2": { + "value": "2018-03-11 19:56", + "color": "#173177" + }, + "keyword3": { + "value": "顺丰快递", + "color": "#173177" + }, + "keyword4": { + "value": "980456952123", + "color": "#173177" + }, + "keyword5": { + "value": "王先生 135xxxxxxxx 广东省深圳市龙华区建设东路", + "color": "#173177" + }, + "remark": { + "value": "欢迎再次购买!", + "color": "#173177" + } + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendUniformMessage.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendUniformMessage.js new file mode 100644 index 0000000..e3bedfb --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendUniformMessage.js @@ -0,0 +1,59 @@ +'use strict'; +module.exports = { + /** + * 发送公众号模板消息(touser可以是小程序下的openid,也可以是公众号下的openid) + * @url template/openapi/weixin/pub/sendTemplateMessage 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res = await vk.openapi.weixin.uniformMessage.send({ + touser: "", // 接收者(用户)的 openid(可以是小程序下的openid,也可以是公众号下的openid) + template_id: "", // 所需下发的订阅模板id + url: "https://www.baidu.com", // 跳转网页时填写(如填了miniprogram参数则忽略url参数) + miniprogram: { + appid: "", + pagepath: "pages/order/order?id=aaa" + }, + data: { + "first": { + "value": "您购买的订单已经发货啦,正快马加鞭向您飞奔而去。", + "color": "#173177" + }, + "keyword1": { + "value": "D201803111235825", + "color": "#173177" + }, + "keyword2": { + "value": "2018-03-11 19:56", + "color": "#173177" + }, + "keyword3": { + "value": "顺丰快递", + "color": "#173177" + }, + "keyword4": { + "value": "980456952123", + "color": "#173177" + }, + "keyword5": { + "value": "王先生 135xxxxxxxx 广东省深圳市龙华区建设东路", + "color": "#173177" + }, + "remark": { + "value": "欢迎再次购买!", + "color": "#173177" + } + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/addition.js b/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/addition.js new file mode 100644 index 0000000..c78de33 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/addition.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 此函数名称 + * @url template/test/pub/addition 前端调用的url参数地址 + * data 请求参数 说明 + * @params {String} uid 当前登录用户id,若用户已登录且token有效,则data中会带uid参数 + * (此参数是后端过滤器通过token获取并添加到data中的,是可信任的)(只有kh函数才带此参数) + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let { num1 , num2 } = data; + if(!num1 || !num2){ + return { + code : -1, + msg : "参数不能为空!" + } + } + num1 = parseFloat(num1); + num2 = parseFloat(num2); + res.value = parseFloat((num1 + num2).toFixed(2)); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/findGoodsInfo.js b/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/findGoodsInfo.js new file mode 100644 index 0000000..deec7d7 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/findGoodsInfo.js @@ -0,0 +1,202 @@ +module.exports = { + /** + * 此函数名称 + * @url template/test/pub/findGoodsInfo 前端调用的url参数地址 + * data 请求参数 说明 + * @params {String} uid 当前登录用户id,若用户已登录且token有效,则data中会带uid参数 + * (此参数是后端过滤器通过token获取并添加到data中的,是可信任的)(只有kh函数才带此参数) + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let { goods_id } = data; + /** + * 这里本来是需要从数据库中获取的,这里简化一下,直接返回数据了 + * 正常业务中,是需要连表查询的,分别是订单表和SKU表 双表连接查询出最终返回给前端的数据 + */ + let goodsDB = [ + { + "_id":"001", + "name": "iphone11", + "goods_thumb":"https://img14.360buyimg.com/n0/jfs/t1/59022/28/10293/141808/5d78088fEf6e7862d/68836f52ffaaad96.jpg", + "sku_list": [ + { + "_id": "001", + "goods_id": "001", + "goods_name": "iphone11", + "image": "https://img14.360buyimg.com/n0/jfs/t1/79668/22/9987/159271/5d780915Ebf9bf3f4/6a1b2703a9ed8737.jpg", + "price": 19800, + "sku_name": "红色,128G,公开版", + "sku_name_arr": ["红色", "128G", "公开版"], + "stock": 100 + }, + { + "_id": "002", + "goods_id": "001", + "goods_name": "iphone11", + "image": "https://img14.360buyimg.com/n0/jfs/t1/52252/35/10516/124064/5d7808e0E46202391/7100f3733a1c1f00.jpg", + "price": 9800, + "sku_name": "白色,256G,公开版", + "sku_name_arr": ["白色", "256G","公开版"], + "stock": 100 + }, + { + "_id": "003", + "goods_id": "001", + "goods_name": "iphone11", + "image": "https://img14.360buyimg.com/n0/jfs/t1/79668/22/9987/159271/5d780915Ebf9bf3f4/6a1b2703a9ed8737.jpg", + "price": 19800, + "sku_name": "红色,256G,公开版", + "sku_name_arr": ["红色","256G","公开版"], + "stock": 100 + } + ], + "spec_list": [ + { + "list": [ + { + "name": "红色" + }, + { + "name": "黑色" + }, + { + "name": "白色" + } + ], + "name": "颜色" + }, + { + "list": [ + { + "name": "128G" + }, + { + "name": "256G" + } + ], + "name": "内存" + }, + { + "list": [ + { + "name": "公开版" + }, + { + "name": "非公开版" + } + ], + "name": "版本" + } + ] + }, + { + "_id":"002", + "name": "迪奥香水", + "goods_thumb":"https://res.lancome.com.cn/resources/2020/9/11/15998112890781924_920X920.jpg?version=20200917220352530", + "sku_list": [ + { + "_id": "004", + "goods_id": "002", + "goods_name": "迪奥香水", + "image": "https://res.lancome.com.cn/resources/2020/9/11/15998112890781924_920X920.jpg?version=20200917220352530", + "price": 19800, + "sku_name": "50ml/瓶", + "sku_name_arr": ["50ml/瓶"], + "stock": 100 + }, + { + "_id": "005", + "goods_id": "002", + "goods_name": "迪奥香水", + "image": "https://res.lancome.com.cn/resources/2020/9/11/15998112890781924_920X920.jpg?version=20200917220352530", + "price": 9800, + "sku_name": "70ml/瓶", + "sku_name_arr": ["70ml/瓶"], + "stock": 100 + } + ], + "spec_list": [ + { + "list": [ + { + "name": "20ml/瓶" + }, + { + "name": "50ml/瓶" + }, + { + "name": "70ml/瓶" + } + ], + "name": "规格" + } + ] + }, + { + "_id":"003", + "name": "迪奥香水", + "goods_thumb":"https://res.lancome.com.cn/resources/2020/9/11/15998112890781924_920X920.jpg?version=20200917220352530", + "sku_list": [ + { + "_id": "006", + "goods_id": "003", + "goods_name": "迪奥香水", + "image": "https://res.lancome.com.cn/resources/2020/9/11/15998112890781924_920X920.jpg?version=20200917220352530", + "price": 19800, + "sku_name": "默认", + "sku_name_arr": ["默认"], + "stock": 100 + } + ], + "spec_list": [ + { + "list": [ + { + "name": "默认" + } + ], + "name": "默认" + } + ] + }, + { + "_id":"004", + "name": "迪奥香水", + "goods_thumb":"https://res.lancome.com.cn/resources/2020/9/11/15998112890781924_920X920.jpg?version=20200917220352530", + "sku_list": [ + { + "_id": "006", + "goods_id": "003", + "goods_name": "迪奥香水", + "image": "https://res.lancome.com.cn/resources/2020/9/11/15998112890781924_920X920.jpg?version=20200917220352530", + "price": 19800, + "sku_name": "默认", + "sku_name_arr": ["默认"], + "stock": 0 + } + ], + "spec_list": [ + { + "list": [ + { + "name": "默认" + } + ], + "name": "默认" + } + ] + } + ]; + res.goodsInfo = vk.pubfn.getListItem(goodsDB, "_id",goods_id); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/temporaryCache.js b/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/temporaryCache.js new file mode 100644 index 0000000..ab674b1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/temporaryCache.js @@ -0,0 +1,36 @@ +'use strict'; +module.exports = { + /** + * 临时数据缓存 + * @url template/test/pub/getTemporaryCache 前端调用的url参数地址 + * data 请求参数 说明 + * @params {String} uid 当前登录用户id,若用户已登录且token有效,则data中会带uid参数 + * (此参数是后端过滤器通过token获取并添加到data中的,是可信任的)(只有kh函数才带此参数) + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { key, value, second, mode } = data; + if(mode == "get"){ + res.value = vk.temporaryCache.get(key); + }else if(mode == "set"){ + res.value = vk.temporaryCache.set(key, value, second); + }else if(mode == "del"){ + res.value = vk.temporaryCache.del(key); + }else if(mode == "clear"){ + res.value = vk.temporaryCache.clear(); + }else if(mode == "isExpired"){ + res.value = vk.temporaryCache.isExpired(key); + }else if(mode == "getAll"){ + res.value = vk.temporaryCache.getAll(); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/云函数示例模板.md b/uniCloud-aliyun/cloudfunctions/router/service/template/云函数示例模板.md new file mode 100644 index 0000000..ccf1649 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/云函数示例模板.md @@ -0,0 +1,11 @@ +## 云函数示例模板 +#### `router/service/template` +#### 此目录一般为插件作者给开发者提供的云函数写法示例,如数据库API的使用等等。 + +``` +. +├── template──────────────────────# 云函数模板 +│ └── db_api───────────────────# 数据库API调用示例 +│ └── test─────────────────────# 普通云函数调用示例 +└───────────────────────────────── +``` diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/acceptInvite.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/acceptInvite.js new file mode 100644 index 0000000..6950698 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/acceptInvite.js @@ -0,0 +1,25 @@ +module.exports = { + /** + * 用户接受邀请 + * @url user/kh/acceptInvite 前端调用的url参数地址 + * @description 此接口用于在注册之后再填写邀请码的场景,多数情况下不会用到此接口而是在注册时填写邀请码 + * data 请求参数 说明 + * @param {String} inviteCode 邀请人的邀请码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID } = util; + let { uid, inviteCode = "" } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + res = await uniID.acceptInvite({ + uid:uid, + inviteCode:inviteCode + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/addUploadRecord.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/addUploadRecord.js new file mode 100644 index 0000000..d65cd7b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/addUploadRecord.js @@ -0,0 +1,75 @@ +module.exports = { + /** + * 添加文件上传记录 + * @url user/kh/addUploadRecord 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} url 文件外网访问url + * @param {String} name 文件名 + * @param {Number} size 文件大小 + * @param {String} file_id 文件id + * @param {String} provider 供应商 + * @param {String} category_id 分类ID + * @param {Number} width 图片\视频的宽度 + * @param {Number} height 图片\视频的高度 + * @param {Number} orientation 图片\视频的旋转方向 + * @param {Number} duration 视频的总时长 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { + url, + name: original_name, + size, + provider, + file_id, + category_id, + width, + height, + orientation, + duration + } = data; + let type = "other"; + + if (vk.pubfn.test(url, "image")) { + type = "image"; + } else if (vk.pubfn.test(url, "video")) { + type = "video"; + } else if (vk.pubfn.test(url, "audio")) { + type = "video"; // 这里audio也分类为video + } + + if (vk.pubfn.isNull(original_name)) original_name = url; + let dataJson = { + user_id: uid, + sort: 0, + status: 0, + type, + url, + display_name: original_name, + original_name, + size, + file_id, + provider, + width, + height, + orientation, + duration + }; + if (vk.pubfn.isNotNull(category_id)) { + dataJson["category_id"] = category_id; + } + await vk.baseDao.add({ + dbName: "vk-files", + dataJson + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindAlipay.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindAlipay.js new file mode 100644 index 0000000..d45e4be --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindAlipay.js @@ -0,0 +1,24 @@ +module.exports = { + /** + * 绑定支付宝 + * @url user/kh/bindAlipay 前端调用的url参数地址 + * @description 将当前登录用户绑定支付宝 + * data 请求参数 说明 + * @param {String} code 支付宝登录返回的code + * @param {String} platform 客户端类型:mp-weixin、app-plus,默认uni-id会自动取客户端类型,但是在云函数url化等场景无法取到客户端类型,可以使用此参数指定 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + // 业务逻辑开始----------------------------------------------------------- + let { data = {}, userInfo, util } = event; + let { uniID, vk, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 绑定 + res = await uniID.bindAlipay(event.data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindEmail.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindEmail.js new file mode 100644 index 0000000..2840e23 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindEmail.js @@ -0,0 +1,23 @@ +module.exports = { + /** + * 绑定邮箱 + * @url user/kh/bindEmail 前端调用的url参数地址 + * @description 将当前登录用户绑定邮箱 + * data 请求参数 说明 + * @param {String} email 用户邮箱 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util } = event; + let { uniID } = util; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + if (!data.code) return { code: -1, msg: "验证码不能为空!" } + // 绑定邮箱 + res = await uniID.bindEmail(event.data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindMobile.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindMobile.js new file mode 100644 index 0000000..06af23a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindMobile.js @@ -0,0 +1,23 @@ +module.exports = { + /** + * 绑定手机号 + * @url user/kh/bindMobile 前端调用的url参数地址 + * @description 将当前登录用户绑定手机号 + * data 请求参数 说明 + * @param {String} mobile 用户手机号 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util } = event; + let { uniID } = util; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + if (!data.code) return { code: -1, msg: "验证码不能为空!" } + // 绑定手机号 + res = await uniID.bindMobile(data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindNewEmail.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindNewEmail.js new file mode 100644 index 0000000..e726fc7 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindNewEmail.js @@ -0,0 +1,72 @@ +module.exports = { + /** + * 换绑新的邮箱 + * @url user/kh/bindNewEmail 前端调用的url参数地址 + * @description 将当前登录用户换绑新的邮箱 + * data 请求参数 说明 + * @param {String} oldEmail 旧邮箱码 + * @param {String} oldEmailCode 旧邮箱收到的验证码 + * @param {String} email 新邮箱码 + * @param {String} code 新邮箱收到的验证码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util } = event; + let { uniID } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + let { + oldEmail, // 旧邮箱码 + oldEmailCode, // 旧邮箱收到的验证码 + email, // 新邮箱码 + code, // 新邮箱收到的验证码 + } = data; + if (!code || !oldEmailCode) return { code: -1, msg: "验证码不能为空!" }; + if (!email || !oldEmail) return { code: -1, msg: "邮箱不能为空!" }; + // 先检查下旧邮箱码和验证码是否正确 + let verifyCodeRes; + verifyCodeRes = await uniID.verifyCode({ + email: oldEmail, + code: oldEmailCode, + type: 'unbind' + }); + if (verifyCodeRes.code !== 0) { + verifyCodeRes.msg = `旧邮箱${verifyCodeRes.msg}` + return verifyCodeRes; + } + // 先检查下新邮箱码和验证码是否正确 + verifyCodeRes = await uniID.verifyCode({ + email, + code: code, + type: 'bind' + }); + if (verifyCodeRes.code !== 0) { + verifyCodeRes.msg = `新邮箱${verifyCodeRes.msg}` + return verifyCodeRes; + } + // 解绑邮箱 + let unbindEmailRes = await uniID.unbindEmail({ + uid, + email: oldEmail + }); + if (unbindEmailRes.code !== 0) { + return unbindEmailRes; + } + await uniID.setVerifyCode({ code, email, type: "bind" }); + // 绑定新邮箱 + res = await uniID.bindEmail({ + uid, + email, + code + }); + if (res.code !== 0) { + return res; + } + res.msg = "换绑邮箱成功!"; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindNewMobile.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindNewMobile.js new file mode 100644 index 0000000..ee256c0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindNewMobile.js @@ -0,0 +1,70 @@ +module.exports = { + /** + * 换绑新的手机号 + * @url user/kh/bindNewMobile 前端调用的url参数地址 + * @description 将当前登录用户换绑新的手机号 + * data 请求参数 说明 + * @param {String} oldMobile 旧手机号码 + * @param {String} oldMobileCode 旧手机收到的验证码 + * @param {String} mobile 新手机号码 + * @param {String} code 新手机收到的验证码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util } = event; + let { uniID } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + let { + oldMobile, // 旧手机号码 + oldMobileCode, // 旧手机收到的验证码 + mobile, // 新手机号码 + code, // 新手机收到的验证码 + } = data; + if (!code || !oldMobileCode) return { code: -1, msg: "验证码不能为空!" }; + if (!mobile || !oldMobile) return { code: -1, msg: "手机号不能为空!" }; + // 先检查下旧手机号码和验证码是否正确 + let verifyCodeRes; + verifyCodeRes = await uniID.verifyCode({ + mobile: oldMobile, + code: oldMobileCode, + type: 'unbind' + }); + if (verifyCodeRes.code !== 0) { + verifyCodeRes.msg = `旧手机${verifyCodeRes.msg}` + return verifyCodeRes; + } + // 先检查下新手机号码和验证码是否正确 + verifyCodeRes = await uniID.verifyCode({ + mobile, + code: code, + type: 'bind' + }); + if (verifyCodeRes.code !== 0) { + verifyCodeRes.msg = `新手机${verifyCodeRes.msg}` + return verifyCodeRes; + } + // 解绑手机号 + let unbindMobileRes = await uniID.unbindMobile({ + uid, + mobile: oldMobile + }); + if (unbindMobileRes.code !== 0) { + return unbindMobileRes; + } + // 绑定新手机号 + res = await uniID.bindMobile({ + uid, + mobile + }); + if (res.code !== 0) { + return res; + } + res.msg = "换绑手机号成功!"; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindQQ.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindQQ.js new file mode 100644 index 0000000..e2b25fa --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindQQ.js @@ -0,0 +1,23 @@ +module.exports = { + /** + * 绑定QQ + * @url user/kh/bindQQ 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} code QQ登录返回的code + * @param {String} platform 客户端类型:mp-weixin、app-plus,默认uni-id会自动取客户端类型,但是在云函数url化等场景无法取到客户端类型,可以使用此参数指定 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + // 业务逻辑开始----------------------------------------------------------- + let { data = {}, userInfo, util } = event; + let { uniID, vk, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 绑定 + res = await uniID.bindQQ(event.data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindWeixin.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindWeixin.js new file mode 100644 index 0000000..555edc5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindWeixin.js @@ -0,0 +1,24 @@ +module.exports = { + /** + * 绑定微信 + * @url user/kh/bindWeixin 前端调用的url参数地址 + * @description 将当前登录用户绑定微信 + * data 请求参数 说明 + * @param {String} code 微信登录返回的code + * @param {String} platform 客户端类型:mp-weixin、app-plus,默认uni-id会自动取客户端类型,但是在云函数url化等场景无法取到客户端类型,可以使用此参数指定 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + // 业务逻辑开始----------------------------------------------------------- + let { data = {}, userInfo, util } = event; + let { uniID, vk, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 绑定 + res = await uniID.bindWeixin(event.data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getAlipayMiniCode.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getAlipayMiniCode.js new file mode 100644 index 0000000..24f2933 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getAlipayMiniCode.js @@ -0,0 +1,25 @@ +'use strict'; +module.exports = { + /** + * 获取支付宝小程序码 + * @url user/kh/getAlipayMiniCode 前端调用的url参数地址 + * data 请求参数 + * @param {String} page 必须是已经发布的小程序存在的页面(否则报错),例如 pages/index/index, 根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面 + * @param {String} scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { + page, + scene + } = data; + res = await vk.openapi.alipay.acode.getMiniCode(data); + res.base64 = res.qr_code_url_circle_blue; // 兼容其他小程序的返回字段 + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getInvitedUser.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getInvitedUser.js new file mode 100644 index 0000000..053534a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getInvitedUser.js @@ -0,0 +1,34 @@ +module.exports = { + /** + * 获取接受邀请的用户清单 + * @url user/kh/getInvitedUser 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let dbName = "uni-id-users"; + let index = 0; + res = await vk.baseDao.getTableData({ + dbName, + data, + fieldJson:{ token:false, password:false }, + whereJson:{ + ['inviter_uid.' + index]:uid + } + }); + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getMenu.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getMenu.js new file mode 100644 index 0000000..cc4c368 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getMenu.js @@ -0,0 +1,30 @@ +'use strict'; +module.exports = { + /** + * 获取我拥有的菜单列表 + * @url user/kh/getMenu 前端调用的url参数地址 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + role = [], + } = userInfo; + // 根据角色获取菜单 + res = await vk.system.sysDao.listMenuByRole({ + role, + treeProps:{ + level: 3 + } + }); + res.userInfo = userInfo; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getMyUserInfo.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getMyUserInfo.js new file mode 100644 index 0000000..1480d07 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getMyUserInfo.js @@ -0,0 +1,16 @@ +module.exports = { + /** + * 获取我的用户信息 + * @url user/kh/getMyUserInfo 前端调用的url参数地址 + */ + main: async (event) => { + // 业务逻辑开始----------------------------------------------------------- + let { data = {}, userInfo, util } = event; + let { uniID, vk, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + res.userInfo = userInfo; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getQQMiniCode.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getQQMiniCode.js new file mode 100644 index 0000000..e13044f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getQQMiniCode.js @@ -0,0 +1,45 @@ +'use strict'; +module.exports = { + /** + * 获取qq小程序码 + * @url user/kh/getQQMiniCode 前端调用的url参数地址 + * data 请求参数 + * @param {String} path 小程序页面路径 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { + path + } = data; + + res = await vk.openapi.qq.acode.getMiniCode(data); + if (typeof res === "object" && res.code) { + return res; + } + try { + // 二进制转base64 + let base64 = Buffer.from(res, 'binary').toString('base64'); + return { + code: 0, + base64: `data:image/png;base64,${base64}` + }; + } catch (err) { + // 转base64失败 + return { + code: -1, + msg: "生成小程序码失败", + err: { + message: err.message, + stack: err.stack + } + }; + } + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPqrcode.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPqrcode.js new file mode 100644 index 0000000..f2357a3 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPqrcode.js @@ -0,0 +1,57 @@ +'use strict'; +module.exports = { + /** + * 获取小程序码 + * @url user/kh/getWeixinMPqrcode 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} scene 自定义参数最大32个可见字符 只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~ + * @param {String} page 必须是已经发布的小程序存在的页面(否则报错),例如 pages/index/index, 根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面 + * @param {boolean} check_path 默认是true,检查page 是否存在,为 true 时 page 必须是已经发布的小程序存在的页面(否则报错);为 false 时允许小程序未发布或者 page 不存在, 但page 有数量上限(60000个)请勿滥用。 + * @param {String} env_version 要打开的小程序版本。正式版为 "release",体验版为 "trial",开发版为 "develop"。默认是正式版。 + * @param {number} width 二维码的宽度,单位 px,最小 280px,最大 1280px + * @param {boolean} auto_color 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调,默认 false + * @param {Object} line_color auto_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} 十进制表示 + * @param {boolean} is_hyaline 是否需要透明底色,为 true 时,生成透明底色的小程序 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { my_invite_code } = userInfo; + if (vk.pubfn.isNull(data.scene) && my_invite_code) { + // 若scene为空,则自动带上用户邀请码 + data.scene = `code=${my_invite_code}`; + } + if (!userInfo.role || userInfo.role.indexOf("admin") === -1) { + data.check_path = true; // 防止超限, 为 false 时允许小程序未发布或者 page 不存在, 但page 有数量上限(60000个)请勿滥用。 + } + res = await vk.openapi.weixin.wxacode.getUnlimited(data); + if (typeof res === "object" && res.code) { + return res; + } + try { + // 二进制转base64 + let base64 = Buffer.from(res, 'binary').toString('base64') + return { + code: 0, + base64: `data:image/png;base64,${base64}` + }; + } catch (err) { + // 转base64失败 + return { + code: -1, + msg: "生成小程序码失败", + err: { + message: err.message, + stack: err.stack + } + }; + } + // 业务逻辑结束----------------------------------------------------------- + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPscheme.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPscheme.js new file mode 100644 index 0000000..47e5d52 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPscheme.js @@ -0,0 +1,41 @@ +'use strict'; +module.exports = { + /** + * 获取小程序scheme码,适用于短信、邮件、外部网页等拉起小程序的业务场景。通过该接口,可以选择生成到期失效和永久有效的小程序码,目前仅针对国内非个人主体的小程序开放 + * @url user/kh/getWeixinMPscheme 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} path 小程序页面路径 + * @param {String} query 小程序页面参数 + * @param {String} env_version 默认值"release"。要打开的小程序版本。正式版为 "release",体验版为"trial",开发版为"develop",仅在微信外打开时生效 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + path, + query, + env_version + } = data; + // 超过180天有10万个限制,故这里强制设为90天 + res = await vk.openapi.weixin.urlscheme.generate({ + ...data, + // 跳转到的目标小程序信息。 + jump_wxa: { + path, // 小程序页面路径 + query, // 小程序页面参数 + env_version + }, + is_expire: true, + expire_type: 1, + expire_interval: 90, // 90天后失效 + }); + return res; + // 业务逻辑结束----------------------------------------------------------- + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPurl.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPurl.js new file mode 100644 index 0000000..5ab34d4 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPurl.js @@ -0,0 +1,38 @@ +'use strict'; +module.exports = { + /** + * 获取小程序 URL Link,适用于短信、邮件、网页、微信内等拉起小程序的业务场景。通过该接口,可以选择生成到期失效和永久有效的小程序链接,有数量限制,目前仅针对国内非个人主体的小程序开放 + * @url user/kh/getWeixinMPurl 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} path 小程序页面路径 + * @param {String} query 小程序页面参数 + * @param {String} env_version 默认值"release"。要打开的小程序版本。正式版为 "release",体验版为"trial",开发版为"develop",仅在微信外打开时生效 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + path, + query, + env_version + } = data; + // 超过180天有10万个限制,故这里强制设为90天 + res = await vk.openapi.weixin.urllink.generate({ + ...data, + path, + query, + env_version, + is_expire: true, + expire_type: 1, + expire_interval: 90, // 90天后失效 + }); + return res; + // 业务逻辑结束----------------------------------------------------------- + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/resetPwd.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/resetPwd.js new file mode 100644 index 0000000..abcd2ce --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/resetPwd.js @@ -0,0 +1,24 @@ +module.exports = { + /** + * 重置密码 + * @url user/kh/resetPwd 前端调用的url参数地址 + * @description 重置当前登录用户的密码为123456 + * data 请求参数 说明 + * @param {String} uid 当前登录用户id(可信任,仅kh目录下的函数有此值) + * @param {String} password 重置后的密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { util, data={} } = event; + let { uniID } = util; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + // 注意:虽然uid是从data中获取的,但无论前端uid传什么,最终uid都是当前登录用户的_id,因此不会出现A把B的密码改了的情况。 + let { uid, password= '123456' } = data; + res = await uniID.resetPwd({ uid, password }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/setAvatar.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/setAvatar.js new file mode 100644 index 0000000..6c08a98 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/setAvatar.js @@ -0,0 +1,37 @@ +module.exports = { + /** + * 设置头像 + * @url user/kh/setAvatar 前端调用的url参数地址 + * @description 设置当前登录用户的头像 + * data 请求参数 说明 + * @param {String} avatar 用户头像URL + * @param {Boolean} deleteOldFile 是否同时删除云储存内的头像文件 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { avatar, deleteOldFile } = data; + // 设置头像 + res = await uniID.setAvatar(event.data); + // 判断是否需要删除旧头像的云储存文件 + if(res.code ===0 && deleteOldFile && userInfo.avatar){ + try { + await uniCloud.deleteFile({ + fileList: [ + userInfo.avatar + ] + }); + }catch(err){ + res.deleteFileErr = err; + } + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/setCertification.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/setCertification.js new file mode 100644 index 0000000..fd8e98d --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/setCertification.js @@ -0,0 +1,60 @@ +var CryptoJS = require("crypto-js"); +module.exports = { + /** + * 绑定邮箱 + * @url user/kh/bindEmail 前端调用的url参数地址 + * @description 将当前登录用户绑定邮箱 + * data 请求参数 说明 + * @param {String} email 用户邮箱 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { + data = {}, util, userInfo + } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let res = { + code: 0 + }; + + // const userInfo = await this.getUserInfo(); + // 业务逻辑开始----------------------------------------------------------- + const { + realname, + address, + address_detail, + mail_address, + id_card_front, + id_card_back, + contact_mobile, + contact_qq, + contact_email, + contact_wechat_image, + contact_wechat, + bank_name, + bank_account_name, + bank_card, + screen_shot + } = data + // 验证实名信息 + // const get_person_verify_url_res = await pubFun.fadada('get_person_verify_url.api', { + // customer_id: userInfo.fadada_customer_id, + // verified_way: 2, + // page_modify: 1 + // }) + + // let {transactionNo, url} = get_person_verify_url_res.data + let transactionNo = 'fe00569db2ac43709697df16be737d96' + let url = 'aHR0cHM6Ly9yZWFsbmFtZXZlcmlmeS10ZXN0LmZhZGFkYS5jb20vZmRkQXV0aGVudGljYXRpb25TZXJ2aWNlL3YxL2FwaS9zeW5zQXV0aGVudGljYXRpb24uYWN0aW9uP3RyYW5zYWN0aW9uX25vPTE3RTM0NDM3MzZDMDczODE5NDgyODQyRjcwMkYzQkI4NjNFMzQ3OTkwQjg4N0MxOUVFRkI1MjBEMkM2NjVFMDVFMDM3MEZFRjVBQTlBOEI3JnNpZ249UkRGQ1JERTJRVEpCUkRCRU9UUkRNRE16TURjMFJURTRPRVl4UWpZeFFqQXhOVGM0TXpNek5nPT0mYXBwX2lkPTQwNTk0MiZ0aW1lc3RhbXA9MTY5ODY2MTExMTg2Mg==' + var parsedWordArray = CryptoJS.enc.Base64.parse(url); + var parsedStr = parsedWordArray.toString(CryptoJS.enc.Utf8); + console.log("parsed:",parsedStr); + + // + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/setUserInviteCode.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/setUserInviteCode.js new file mode 100644 index 0000000..980d9f2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/setUserInviteCode.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 设置用户邀请码(自动生成) + * @url user/kh/setUserInviteCode 前端调用的url参数地址 + * @description 针对未生成邀请码的用户使用此方法生成邀请码(自动生成) + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} myInviteCode 最终设置的邀请码 + */ + main: async (event) => { + let { data = {},userInfo, util, originalParam } = event; + let { uniID } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + // 判断下如果已经生成,则不再重新生成 + if(userInfo.my_invite_code){ + res = { + "code": 0, + "msg": "无需重复设置", + "myInviteCode": userInfo.my_invite_code + } + }else{ + res = await uniID.setUserInviteCode({ + uid:uid + }); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindAlipay.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindAlipay.js new file mode 100644 index 0000000..b4ad3b5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindAlipay.js @@ -0,0 +1,24 @@ +module.exports = { + /** + * 解绑支付宝 + * @url user/kh/unbindAlipay 前端调用的url参数地址 + * @description 当前登录用户解绑支付宝 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + // 业务逻辑开始----------------------------------------------------------- + let { data = {}, userInfo, util } = event; + let { uniID, vk } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + if(vk.pubfn.isNullAll(userInfo.mobile, userInfo.username)){ + return { code : -1, msg : '为了您的账号安全,请绑定手机号后再解绑支付宝!' }; + } + // 解绑 + res = await uniID.unbindAlipay(uid); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindEmail.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindEmail.js new file mode 100644 index 0000000..e762c48 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindEmail.js @@ -0,0 +1,25 @@ +module.exports = { + /** + * 解绑邮箱 + * @url user/kh/unbindEmail 前端调用的url参数地址 + * @description 当前登录用户解绑邮箱 + * data 请求参数 说明 + * @param {String} email 邮箱 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { uniID, vk } = util; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + if(vk.pubfn.isNullAll(userInfo.mobile, userInfo.username, userInfo.wx_openid, userInfo.ali_openid, userInfo.qq_openid)){ + return { code : -1, msg : '为了您的账号安全,请绑定手机号后再解绑邮箱!' }; + } + // 解绑 + res = await uniID.unbindEmail(data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindMobile.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindMobile.js new file mode 100644 index 0000000..b237d7e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindMobile.js @@ -0,0 +1,25 @@ +module.exports = { + /** + * 解绑邮箱 + * @url user/kh/unbindMobile 前端调用的url参数地址 + * @description 当前登录用户解绑手机号 + * data 请求参数 说明 + * @param {String} mobile 手机号 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { uniID, vk } = util; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + if (vk.pubfn.isNullAll(userInfo.username, userInfo.wx_openid, userInfo.ali_openid, userInfo.qq_openid)) { + return { code: -1, msg: '为了您的账号安全,请绑定微信或设置用户名后再解绑手机号!' }; + } + // 解绑 + res = await uniID.unbindMobile(data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindQQ.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindQQ.js new file mode 100644 index 0000000..f4211d2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindQQ.js @@ -0,0 +1,23 @@ +module.exports = { + /** + * 解绑QQ + * @url user/kh/unbindQQ 前端调用的url参数地址 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + // 业务逻辑开始----------------------------------------------------------- + let { data = {}, userInfo, util } = event; + let { uniID, vk } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + if(vk.pubfn.isNullAll(userInfo.mobile, userInfo.username)){ + return { code : -1, msg : '为了您的账号安全,请绑定手机号后再解绑QQ!' }; + } + // 解绑 + res = await uniID.unbindQQ(uid); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindWeixin.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindWeixin.js new file mode 100644 index 0000000..368a2ee --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindWeixin.js @@ -0,0 +1,24 @@ +module.exports = { + /** + * 解绑微信 + * @url user/kh/unbindWeixin 前端调用的url参数地址 + * @description 当前登录用户解绑微信 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + // 业务逻辑开始----------------------------------------------------------- + let { data = {}, userInfo, util } = event; + let { uniID, vk } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + if(vk.pubfn.isNullAll(userInfo.mobile, userInfo.username)){ + return { code : -1, msg : '为了您的账号安全,请绑定手机号后再解绑微信!' }; + } + // 解绑 + res = await uniID.unbindWeixin(uid); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/updatePwd.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/updatePwd.js new file mode 100644 index 0000000..e96dcbd --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/updatePwd.js @@ -0,0 +1,26 @@ +module.exports = { + /** + * 修改登录密码 + * @url user/kh/updatePwd 前端调用的url参数地址 + * @description 修改当前登录用户的登录密码 + * data 请求参数 说明 + * @param {String} oldPassword 旧密码 + * @param {String} newPassword 新密码 + * @param {String} passwordConfirmation 确认新密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { uniID } = util; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + if (userInfo.disable_update_password) { + return { code: -1, msg: "该账号不支持修改密码。" }; + } + res = await uniID.updatePwd(data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/updateUser.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/updateUser.js new file mode 100644 index 0000000..b8c4baf --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/updateUser.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 修改用户信息 + * @url user/kh/updateUser 前端调用的url参数地址 + * @description 设置当前登录用户的昵称等用户信息 + * data 请求参数 说明 + * @param {String} nickname 用户的昵称 + * @param {String} avatar 用户的头像 + * @param {Number} gender 用户的性别 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, vk } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + // 允许修改的字段列表 + let updateKeys = ["nickname", "avatar", "gender", "social_info", 'businessCard']; + let dataJson = {}; + for (let i in updateKeys) { + let key = updateKeys[i]; + if (vk.pubfn.isNotNull(data[key])) dataJson[key] = data[key]; + } + dataJson.uid = uid; + res = await uniID.updateUser(dataJson); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/checkToken.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/checkToken.js new file mode 100644 index 0000000..307d4a5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/checkToken.js @@ -0,0 +1,27 @@ +module.exports = { + /** + * 验证token是否有效 + * @url user/pub/checkToken 前端调用的url参数地址 + * @description 验证token是否有效(会返回uid) + * @param {String} uniIdToken 用户token + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} uid 当前token对应的用户uid + * @param {Object} userInfo 当前用户信息 + * @param {Array} role 当前用户角色 + * @param {Array} permission 当前用户权限 + */ + main: async (event) => { + let { util } = event; + let { uniID } = util; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + res = await uniID.checkToken(event.uniIdToken,{ + needPermission:true, + needUserInfo:true + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/checkVersion.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/checkVersion.js new file mode 100644 index 0000000..e9d7461 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/checkVersion.js @@ -0,0 +1,152 @@ +const platform_Android = 'Android'; +const platform_iOS = 'iOS'; +const package_app = 'native_app'; +const package_wgt = 'wgt'; +const app_version_db_name = 'opendb-app-versions' +module.exports = { + /** + * App升级中心 - 检测是当前版本是否需要升级 + * @url user/pub/checkVersion 前端调用的url参数地址 + * @description 验证token是否有效(会返回uid) + * @param {String} uniIdToken 用户token + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} uid 当前token对应的用户uid + * @param {Object} userInfo 当前用户信息 + * @param {Array} role 当前用户角色 + * @param {Array} permission 当前用户权限 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + let { context } = originalParam; + // 业务逻辑开始----------------------------------------------------------- + /** + * 检测升级 使用说明 + * 上传包: + * 1. 根据传参,先检测传参是否完整,appid appVersion wgtVersion 必传 + * 2. 先从数据库取出所有该平台(从上下文读取平台信息,默认 Andriod)的所有线上发行更新 + * 3. 再从所有线上发行更新中取出版本最大的一版。如果可以,尽量先检测wgt的线上发行版更新 + * 4. 使用上步取出的版本包的版本号 和传参 appVersion、wgtVersion 来检测是否有更新,必须同时大于这两项,否则返回暂无更新 + * 5. 如果库中 wgt包 版本大于传参 appVersion,但是不满足 min_uni_version < appVersion,则不会使用wgt更新,会接着判断库中 app包version 是否大于 appVersion + */ + let { + appid, + appVersion, + wgtVersion, + } = data; + + let platform = context.OS === 'ios' ? platform_iOS : platform_Android; + + // 参数非空检测 + let nullKey = vk.pubfn.isNullOneByObject({ appid, appVersion, wgtVersion, platform }); + if (nullKey) return { code: -102, msg: '参数 ' + nullKey + ' 不能为空' }; + + let versionList = await vk.baseDao.select({ + dbName: app_version_db_name, + getCount: false, + pageIndex: 1, + pageSize: 500, + getMain: true, + whereJson: { + appid, + platform, + stable_publish: true + }, + sortArr: [{ name: "create_date", type: "desc" }], + }); + if (vk.pubfn.isNull(versionList)) return { code: -101, msg: "暂无更新或检查appid是否填写正确" }; + + const appVersionInDb = versionList.find(item => item.type === package_app) || {}; + const wgtVersionInDb = versionList.find(item => item.type === package_wgt) || {}; + const hasAppPackage = !!Object.keys(appVersionInDb).length; + const hasWgtPackage = !!Object.keys(wgtVersionInDb).length; + + // 取两个版本中版本号最大的包,版本一样,使用wgt包 + let stablePublishDb = hasAppPackage ? + hasWgtPackage ? + compare(wgtVersionInDb.version, appVersionInDb.version) >= 0 ? + wgtVersionInDb : + appVersionInDb : + appVersionInDb : + wgtVersionInDb; + + const { + version, + min_uni_version + } = stablePublishDb; + + // 库中的version必须满足同时大于appVersion和wgtVersion才行,因为上次更新可能是wgt更新 + const appUpdate = compare(version, appVersion) === 1; // app包可用更新 + const wgtUpdate = compare(version, wgtVersion) === 1; // wgt包可用更新 + + if (Object.keys(stablePublishDb).length && appUpdate && wgtUpdate) { + // 判断是否可用wgt更新 + if (min_uni_version && compare(min_uni_version, appVersion) < 1) { + return { + code: 101, + msg: 'wgt更新', + ...stablePublishDb + }; + } else if (hasAppPackage && compare(appVersionInDb.version, appVersion) === 1) { + return { + code: 102, + msg: '整包更新', + ...appVersionInDb + }; + } + } else { + return { code: 0, msg: '当前版本已经是最新的,不需要更新' }; + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} + + + +/** + * 对比版本号,如需要,请自行修改判断规则 + * 支持比对 ("3.0.0.0.0.1.0.1", "3.0.0.0.0.1") ("3.0.0.1", "3.0") ("3.1.1", "3.1.1.1") 之类的 + * @param {Object} v1 + * @param {Object} v2 + * v1 > v2 return 1 + * v1 < v2 return -1 + * v1 == v2 return 0 + */ +function compare(v1 = '0', v2 = '0') { + v1 = String(v1).split('.') + v2 = String(v2).split('.') + const minVersionLens = Math.min(v1.length, v2.length); + + let result = 0; + for (let i = 0; i < minVersionLens; i++) { + const curV1 = Number(v1[i]) + const curV2 = Number(v2[i]) + + if (curV1 > curV2) { + result = 1 + break; + } else if (curV1 < curV2) { + result = -1 + break; + } + } + + if (result === 0 && (v1.length !== v2.length)) { + const v1BiggerThenv2 = v1.length > v2.length; + const maxLensVersion = v1BiggerThenv2 ? v1 : v2; + for (let i = minVersionLens; i < maxLensVersion.length; i++) { + const curVersion = Number(maxLensVersion[i]) + if (curVersion > 0) { + v1BiggerThenv2 ? result = 1 : result = -1 + break; + } + } + } + + return result; +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/code2SessionAlipay.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/code2SessionAlipay.js new file mode 100644 index 0000000..03bde08 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/code2SessionAlipay.js @@ -0,0 +1,37 @@ +module.exports = { + /** + * 获取支付宝openid + * @url user/pub/code2SessionAlipay 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} code 支付宝登录返回的code + * @param {String} platform 客户端类型:mp-weixin、app-plus,默认uni-id会自动取客户端类型,但是在云函数url化等场景无法取到客户端类型,可以使用此参数指定 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} openid 用户openid + * @param {String} accessToken 客户端为APP时返回 + * @param {String} expiresIn 客户端为APP时返回,accessToken 接口调用凭证超时时间,单位(秒) + * @param {String} refreshToken 客户端为APP时返回,用于刷新accessToken + * @param {String} reExpiresIn refreshToken超时时间,单位(秒) + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, vk } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + // 用户登录(账号+密码) + res = await uniID.code2SessionAlipay(data); + if (res.code === 0) { + let encrypted = vk.crypto.aes.encrypt({ + data: res + }); + delete res.sessionKey; // 删除明文sessionKey + delete res.accessToken; // 删除明文accessToken + delete res.refreshToken; // 删除明文refreshToken + res.encryptedKey = encrypted; // 返回前端加密内容 + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/code2SessionWeixin.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/code2SessionWeixin.js new file mode 100644 index 0000000..aa7a836 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/code2SessionWeixin.js @@ -0,0 +1,41 @@ +module.exports = { + /** + * 获取微信openid + * @url user/pub/code2SessionWeixin 前端调用的url参数地址 + * @description 支持APP、微信小程序、微信公众号 + * data 请求参数 说明 + * @param {String} code 微信登录返回的code + * @param {String} platform 客户端类型:mp-weixin、app-plus、h5-weixin,默认会自动取客户端类型,但是在云函数url化等场景无法取到客户端类型,可以使用此参数指定 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} openid 用户openid + * @param {String} unionid 用户unionid,可以取到此值时返回 + * @param {String} sessionKey 客户端为微信小程序时返回 + * @param {String} accessToken 客户端为APP时返回 + * @param {String} expiresIn 客户端为APP时返回,accessToken 接口调用凭证超时时间,单位(秒) + * @param {String} refreshToken 客户端为APP时返回,用于刷新accessToken + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, vk } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + code, + platform, + appid, + needCache + } = data; + if (!platform) platform = originalParam.context.PLATFORM; + res = await vk.openapi.weixin.auth.code2Session({ + context: originalParam.context, + appid, + code, + needKey: false, // 是否需要返回明文的sessionKey或accessToken(为了安全期间,建议设置false) + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/getPhoneNumber.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/getPhoneNumber.js new file mode 100644 index 0000000..cee1162 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/getPhoneNumber.js @@ -0,0 +1,23 @@ +'use strict'; +module.exports = { + /** + * 获取用户微信绑定的手机号 + * 微信小程序API更新了,现在只需传code可以代替encryptedData和iv + * @url user/pub/getPhoneNumber 前端调用的url参数地址 + * data 请求参数 + * @param {String} code 通过 getphonenumber 事件获取到的code(code和encryptedData+iv二选一) + * @param {String} encryptedData(code和encryptedData+iv二选一) + * @param {String} iv(code和encryptedData+iv二选一) + * @param {String} encryptedKey code2SessionWeixin 接口返回的encryptedKey + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + res = await vk.openapi.weixin.decrypt.getPhoneNumber(data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/getUserInfoByInviteCode.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/getUserInfoByInviteCode.js new file mode 100644 index 0000000..df31d92 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/getUserInfoByInviteCode.js @@ -0,0 +1,36 @@ +'use strict'; +module.exports = { + /** + * 根据邀请码获取用户社交信息 + * @url user/pub/getUserInfoByInviteCode 前端调用的url参数地址 + * data 请求参数 + * @param {String} code + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { code } = data; + // 参数非空检测 + let nullKey = vk.pubfn.isNullOneByObject({ code }); + if(nullKey) return { code:-1, msg:'参数 '+nullKey+' 不能为空' }; + res.userInfo = await vk.baseDao.findByWhereJson({ + dbName:"uni-id-users", + fieldJson:{ + _id:true, + nickname:true, + gender:true, + avatar:true, + my_invite_code:true, + social_info:true + }, + whereJson:{ + my_invite_code : code + } + }); + return res; + // 业务逻辑结束----------------------------------------------------------- + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/login.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/login.js new file mode 100644 index 0000000..ea9c9d3 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/login.js @@ -0,0 +1,55 @@ +module.exports = { + /** + * 用户登录(账号+密码) + * @url user/pub/login 前端调用的url参数地址 + * @description 用户登录(账号+密码) + * data 请求参数 说明 + * @param {String} username 用户名 + * @param {String} password 密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + // 用户登录(账号+密码) + if (typeof data.username === "number") data.username = String(data.username).trim(); + if (typeof data.password === "number") data.password = String(data.password).trim(); + + let { + needPermission, + username, + password, + queryField = ['username', 'email', 'mobile'], // 不指定queryField的情况下只会查询username + } = data; + + res = await uniID.login({ + username, + password, + needPermission, + queryField + }); + if (res.token) { + if (!res.msg) { + res.msg = res.type === "register" ? "注册成功" : "登录成功"; + } + // 日志服务 + const loginLogService = vk.require("service/user/util/login_log"); + await loginLogService.add({ + type: "login", + login_type: "password", + user_id: res.uid, + context: originalParam.context + }, util); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByAlipay.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByAlipay.js new file mode 100644 index 0000000..d255f0f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByAlipay.js @@ -0,0 +1,55 @@ +module.exports = { + /** + * 用户登录(支付宝授权) + * @url user/pub/loginByAlipay 前端调用的url参数地址 + * @description 用户登录(支付宝授权) + * data 请求参数 说明 + * @param {String} code 支付宝登录返回的code + * @param {String} type login:登录 register:注册 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + let { + code, + type, + myInviteCode, + needPermission + } = data; + res = await uniID.loginByAlipay({ + code, + type, + myInviteCode, + needPermission + }); + if (res.token) { + if (!res.msg) { + res.msg = res.type === "register" ? "注册成功" : "登录成功"; + } + let encrypted = vk.crypto.aes.encrypt({ + data: res + }); + delete res.sessionKey; // 删除明文sessionKey + delete res.accessToken; // 删除明文accessToken + res.encryptedKey = encrypted; // 返回前端加密内容 + // 日志服务 + const loginLogService = vk.require("service/user/util/login_log"); + await loginLogService.add({ + type: "login", + login_type: "alipay", + user_id: res.uid, + context: originalParam.context + }, util); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByEmail.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByEmail.js new file mode 100644 index 0000000..870e5da --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByEmail.js @@ -0,0 +1,56 @@ +module.exports = { + /** + * 用户登录(邮箱+验证码登录) + * @url user/pub/loginByEmail 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} email 邮箱 + * @param {String} code 邮箱收到的验证码 + * @param {String} type 指定操作类型,不传:存在则登录不存在则注册 login:只能登录 register:只能注册 + * @param {String} password 密码,当前用户为新注册时生效 + * @param {String} myInviteCode 设置当前注册用户自己的邀请码,当前用户为新注册时生效(不传会自动生成) + * @param {Boolean} needPermission 设置为true时会在checkToken时返回用户权限(permission),如果是在admin端,需传true + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + let { + email, + code, + type, + password, + needPermission, + myInviteCode + } = data; + res = await uniID.loginByEmail({ + email, + code, + type, + password, + myInviteCode, + needPermission + }); + if (res.token) { + if (!res.msg) { + res.msg = res.type === "register" ? "注册成功" : "登录成功"; + } + // 日志服务 + const loginLogService = vk.require("service/user/util/login_log"); + await loginLogService.add({ + type: "login", + login_type: "email", + user_id: res.uid, + context: originalParam.context + }, util); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByQQ.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByQQ.js new file mode 100644 index 0000000..56d0403 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByQQ.js @@ -0,0 +1,58 @@ +module.exports = { + /** + * QQ授权登录 + * @url user/pub/loginByQQ 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} code QQ小程序登录返回的code + * @param {String} accessToken QQ APP登录返回的access_token + * @param {String} type login:登录 register:注册 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + let { + code, + accessToken, + type, + myInviteCode, + needPermission + } = data; + res = await uniID.loginByQQ({ + code, + accessToken, + type, + myInviteCode, + needPermission + }); + if (res.token) { + if (!res.msg) { + res.msg = res.type === "register" ? "注册成功" : "登录成功"; + } + let encrypted = vk.crypto.aes.encrypt({ + data: res + }); + delete res.sessionKey; // 删除明文sessionKey + delete res.accessToken; // 删除明文accessToken + delete res.refreshToken; // 删除明文refreshToken + res.encryptedKey = encrypted; // 返回前端加密内容 + // 日志服务 + const loginLogService = vk.require("service/user/util/login_log"); + await loginLogService.add({ + type: "login", + login_type: "qq", + user_id: res.uid, + context: originalParam.context + }, util); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginBySms.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginBySms.js new file mode 100644 index 0000000..13afa4b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginBySms.js @@ -0,0 +1,95 @@ +module.exports = { + /** + * 手机号登陆(手机号+手机验证码) + * @url user/pub/loginBySms 前端调用的url参数地址 + * @description 手机号登陆(手机号+手机验证码) + * data 请求参数 说明 + * @param {String} mobile 手机号 + * @param {String} code 验证码 + * @param {String} type 指定操作类型,不传:存在则登录不存在则注册 login:只能登录 register:只能注册 + * @param {String} password 密码,当前用户为新注册时生效 + * @param {String} inviteCode 邀请人的邀请码,当前用户为新注册时生效 + * @param {String} myInviteCode 设置当前注册用户自己的邀请码,当前用户为新注册时生效(不传会自动生成) + * @param {Boolean} needPermission 设置为true时会在checkToken时返回用户权限(permission),如果是在admin端,需传true + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + let { + mobile, + code, + type, + password, + inviteCode, + myInviteCode, + needPermission, + accountType + } = data; + res = await uniID.loginBySms({ + mobile, + code, + type, + password, + inviteCode, + myInviteCode, + needPermission + }); + // 修改用户昵称为:手机尾号xxxx用户 + if (res.token) { + if (!res.msg) { + res.msg = res.type === "register" ? "注册成功" : "登录成功"; + } + // 注册法大大 + if(res.type === "register") { + const fadadaRes = await pubFun.fadada('account_register.api', { + open_id: res.uid, + account_type: accountType, + }) + + if(fadadaRes.code == 1) { + await vk.baseDao.update({ + dbName: "uni-id-users", + whereJson: { + _id: res.uid + }, + dataJson: { + fadadaCustomerId: fadadaRes.data + } + }); + } + + } + + let mobileStr = mobile.substring(7); + await vk.baseDao.update({ + dbName: "uni-id-users", + whereJson: { + _id: res.uid, + nickname: null + }, + dataJson: { + nickname: `手机尾号${mobileStr}用户`, + accountType: accountType + } + }); + // 日志服务 + const loginLogService = vk.require("service/user/util/login_log"); + await loginLogService.add({ + type: "login", + login_type: "sms", + user_id: res.uid, + context: originalParam.context + }, util); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByUniverify.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByUniverify.js new file mode 100644 index 0000000..3022718 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByUniverify.js @@ -0,0 +1,74 @@ +module.exports = { + /** + * APP端 手机一键登录 + * @url user/pub/loginByUniverify 前端调用的url参数地址 + * @param {String} access_token uni.login登录成功后,返回的access_token参数 + * @param {String} openid uni.login登录成功后,返回的openid参数 + * @param {String} type 指定操作类型,可选值为login、register,不传此参数时表现为手机号已注册则登录,手机号未注册则进行注册 + * @param {String} password 密码,type为register时生效 + * @param {String} inviteCode 邀请人的邀请码,type为register时生效 + * @param {String} myInviteCode 设置当前注册用户自己的邀请码,type为register时生效 + * @param {Boolean} needPermission 设置为true时会在checkToken时返回用户权限(permission),建议在管理控制台中使用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} uid 当前token对应的用户uid + * @param {String} type 操作类型,login为登录、register为注册 + * @param {String} mobile 登录者手机号 + * @param {String} userInfo 用户全部信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + access_token, + openid, + type, + password, + inviteCode, + myInviteCode, + needPermission + } = data; + res = await uniID.loginByUniverify({ + access_token, + openid, + type, + password, + inviteCode, + myInviteCode, + needPermission + }); + if (res.token) { + if (!res.msg) { + res.msg = res.type === "register" ? "注册成功" : "登录成功"; + } + if (res.type === "register") { + let mobileStr = res.userInfo.mobile.substring(7); + res.userInfo = await vk.baseDao.updateAndReturn({ + dbName: "uni-id-users", + whereJson: { + _id: res.uid + }, + dataJson: { + nickname: data.nickname || `手机尾号${mobileStr}用户`, + }, + }); + } + // 日志服务 + const loginLogService = vk.require("service/user/util/login_log"); + await loginLogService.add({ + type: "login", + login_type: "univerify", + user_id: res.uid, + context: originalParam.context + }, util); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByWeixin.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByWeixin.js new file mode 100644 index 0000000..729a03e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByWeixin.js @@ -0,0 +1,58 @@ +module.exports = { + /** + * 用户登录(微信授权) + * @url user/pub/loginByWeixin 前端调用的url参数地址 + * @description 支持APP、微信小程序、微信公众号 + * data 请求参数 说明 + * @param {String} code 微信登录返回的code + * @param {String} type login:登录 register:注册 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + * @param {Object} userInfo 用户信息 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + // 额外写入的自定义字段数据(可以自己增加,建议只传一些显示的信息,不要传余额字段等,因为前端不可信任) + // 注意:app的微信登录已经支持自动获取昵称和头像,前端无需再传昵称和头像。 + let custom = { + nickname: data.nickname, + avatar: data.avatar + }; + /** + * 支持多小程序登录 + * 此处data可以额外接收appid和appsecret参数(appid可以从前端传,而appsecret可以配置在全局配置中(common/uni-config-center/vk-unicloud/index.js),也可以自己从数据库获取) + * 如果不传appid,则默认使用uni-id的配置信息 + * 特别注意:如果使用多小程序登录,则同一用户(同一个微信号)在不同小程序登录时,会分别创建不同的用户(除非小程序绑定在同一个开放平台下)。 + */ + + // 打开下方注释,动态赋值appid和appsecret即可支持多小程序登录 + // data.appid = "xxxx"; + // data.appsecret = "xxxx"; + + res = await vk.openapi.weixin.loginByWeixin({ + data, + context: originalParam.context, + custom, + needKey: false, // 是否需要返回明文的sessionKey或accessToken(为了安全期间,建议设置false) + }); + if (res.token) { + // 日志服务 + const loginLogService = vk.require("service/user/util/login_log"); + await loginLogService.add({ + type: "login", + login_type: "weixin", + user_id: res.uid, + context: originalParam.context + }, util); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByWeixinPhoneNumber.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByWeixinPhoneNumber.js new file mode 100644 index 0000000..a69e63a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByWeixinPhoneNumber.js @@ -0,0 +1,99 @@ +module.exports = { + /** + * 用户登录(微信手机号授权) + * @url user/pub/loginByWeixinPhoneNumber 前端调用的url参数地址 + * @description 用户登录(微信授权) + * data 请求参数 说明 + * @param {String} code 通过 getphonenumber 事件获取到的code(code和encryptedData+iv二选一) + * @param {String} encryptedData(code和encryptedData+iv二选一) + * @param {String} iv(code和encryptedData+iv二选一) + * @param {String} encryptedKey code2SessionWeixin 接口返回的encryptedKey + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + let { + nickname, + avatar, + gender, + inviteCode, + encryptedKey, + code, + encryptedData, + iv + } = data; + + // 获取微信绑定的手机号 + res = await vk.openapi.weixin.decrypt.getPhoneNumber({ + encryptedKey, + code, + encryptedData, + iv + }); + if (res.code !== 0) return res; + let { + mobile + } = res; + let mobileCode = vk.pubfn.random(6); + // 指定操作类型,可选值为login、register,不传此参数时表现为手机号已注册则登录,手机号未注册则进行注册 + let type; + // 通过手机号登录 + await uniID.setVerifyCode({ mobile, code: mobileCode, expiresIn: 60, type: "login" }); + res = await uniID.loginBySms({ mobile, code: mobileCode, type, inviteCode }); + if (!res.token) return res; + if (!res.msg) { + res.msg = res.type === "register" ? "注册成功" : "登录成功"; + } + if (res.type === "register") { + // 解密获得openid和unionid + let decryptedRes = vk.crypto.aes.decrypt({ + data: encryptedKey, // 待解密的原文 + }); + let wx_openid = {}; + let wx_unionid = decryptedRes.unionid; + wx_openid["mp-weixin"] = decryptedRes.openid; + // 查询openid或unionid是否已经存在,如果存在,则不绑定微信. + let queryUserInfo = await vk.daoCenter.userDao.findByUserInfo({ + "wx_openid.mp-weixin": wx_openid["mp-weixin"], + "wx_unionid": wx_unionid + }); + res.bindWeixin = vk.pubfn.isNull(queryUserInfo) ? true : false; + // 需要额外添加的字段 + let mobileStr = mobile.substring(7); + let dataJson = { + nickname: nickname || `手机尾号${mobileStr}用户`, + avatar, + gender + }; + if (res.bindWeixin) { + dataJson["wx_openid"] = wx_openid; + dataJson["wx_unionid"] = wx_unionid; + } + res.userInfo = await vk.baseDao.updateAndReturn({ + dbName: "uni-id-users", + whereJson: { + _id: res.uid + }, + dataJson + }); + } + // 日志服务 + const loginLogService = vk.require("service/user/util/login_log"); + await loginLogService.add({ + type: res.type, + login_type: "weixinPhoneNumber", + user_id: res.uid, + context: originalParam.context + }, util); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/logout.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/logout.js new file mode 100644 index 0000000..d6c4653 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/logout.js @@ -0,0 +1,24 @@ +module.exports = { + /** + * 用户退出登录 + * @url user/pub/logout 前端调用的url参数地址 + * @description 用户退出登录 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { util } = event; + let { uniID } = util; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + if(event.uniIdToken){ + res = await uniID.logout(event.uniIdToken); + }else{ + res.code = 0; + res.msg = "未登录"; + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/register.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/register.js new file mode 100644 index 0000000..fb57f21 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/register.js @@ -0,0 +1,61 @@ +module.exports = { + /** + * 用户注册(账号+密码) + * @url user/pub/register 前端调用的url参数地址 + * @description 用户注册(账号+密码) + * data 请求参数 说明 + * @param {String} username 用户名,唯一 + * @param {String} password 密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 注册完成自动登录之后返回的token信息 + * @param {String} tokenExpired token过期时间 + * @param {Object} userInfo 用户信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: -1, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + if (typeof data.username === "number") data.username = String(data.username).trim(); + if (typeof data.password === "number") data.password = String(data.password).trim(); + + let { + username, + password, + needPermission, + myInviteCode + } = data; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + username: [ + { required: true, validator: vk.pubfn.validator("username"), message: '用户名以字母开头,长度在3~32之间,只能包含字母、数字和下划线', trigger: ['blur', 'change'] } + ], + password: [ + { validator: vk.pubfn.validator("password"), message: '密码长度在6~18之间,只能包含字母、数字和下划线', trigger: 'blur' } + ] + }; + // 验证规则结束 ----------------------------------------------------------- + // 开始进行验证 + let formRulesRes = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + if (formRulesRes.code !== 0) { + // 表单验证未通过 + return formRulesRes; + } + // 表单验证通过,下面写自己的业务逻辑 + res = await uniID.register({ + username, + password, + needPermission, + myInviteCode + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/resetPasswordByEmail.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/resetPasswordByEmail.js new file mode 100644 index 0000000..062f601 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/resetPasswordByEmail.js @@ -0,0 +1,52 @@ +module.exports = { + /** + * 根据邮箱+验证码重置密码 + * @url user/pub/resetPasswordByEmail 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} password 重置后的密码 + * @param {String} code 验证码 + * @param {String} email 邮箱号码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { + _id, + password, + code, + email + } = data; + let res = { code : -1, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + // 检查验证码是否正确 + res = await uniID.verifyCode({ + email, + code, + type: 'reset-pwd', // 自2022-08-13起,以从reset改为reset-pwd,与官方uni-id对齐 + }); + if(res.code !== 0){ + return res; + } + // 根据email查询用户是否存在 + let userInfo = await vk.baseDao.findByWhereJson({ + dbName:"uni-id-users", + whereJson:{ + email + } + }); + if(!userInfo){ + return { code : -1, msg : '邮箱号未注册!' }; + } + // 重置密码 + res = await uniID.resetPwd({ + uid: userInfo._id, + password + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/resetPasswordByMobile.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/resetPasswordByMobile.js new file mode 100644 index 0000000..95d96b8 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/resetPasswordByMobile.js @@ -0,0 +1,52 @@ +module.exports = { + /** + * 根据手机+验证码重置密码 + * @url user/pub/resetPasswordByMobile 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} password 重置后的密码 + * @param {String} code 验证码 + * @param {String} mobile 手机号 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { + _id, + password, + code, + mobile + } = data; + let res = { code : -1, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + // 检查验证码是否正确 + res = await uniID.verifyCode({ + mobile, + code, + type: 'reset-pwd', // 自2022-08-13起,以从reset改为reset-pwd,与官方uni-id对齐 + }); + if(res.code !== 0){ + return res; + } + // 根据mobile查询用户是否存在 + let userInfo = await vk.baseDao.findByWhereJson({ + dbName:"uni-id-users", + whereJson:{ + mobile + } + }); + if(!userInfo){ + return { code : -1, msg : '手机号未注册!' }; + } + // 重置密码 + res = await uniID.resetPwd({ + uid: userInfo._id, + password + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/sendEmailCode.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/sendEmailCode.js new file mode 100644 index 0000000..5cbf412 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/sendEmailCode.js @@ -0,0 +1,112 @@ +var vkmail; +try { + vkmail = require('vk-mail'); +} catch (err) { + console.error("请先添加公共模块:vk-mail(右键对应的云函数,点击管理公共模块或扩展库依赖,勾选vk-mail依赖)"); +} +var everyDaylimit = 30; // 限制同一个邮箱每天次数 +module.exports = { + /** + * 发送邮箱验证码 + * @url user/pub/sendEmailCode 前端调用的url参数地址 + * @description 发送邮箱验证码 + * data 请求参数 说明 + * @param {String} email 邮箱 + * @param {String} type 验证码类型 + * @param {String} serviceType 邮件服务类型,默认为qq + * @param {Boolean|String} checkUserExist 是否需要检测邮箱对应的账号是否存在或不存在,默认不检测,若为exists代表邮箱必须已注册,若为!exists代表邮箱必须未注册 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util } = event; + let { uniID, config } = util; + let { + email, + type, + serviceType = "qq", + checkUserExist = false + } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + if (!vkmail) { + return { code: -1, msg: "请先添加公共模块:vk-mail(右键对应的云函数,点击管理公共模块或扩展库依赖,勾选vk-mail依赖)" }; + } + // 参数非空检测 + let nullKey = vk.pubfn.isNullOneByObject({ email, type }); + if (nullKey) return { code: -1, msg: '参数 ' + nullKey + ' 不能为空' }; + + if (!vk.pubfn.test(email, "email")) return { code: -1, msg: "邮箱格式错误" }; + if (vk.pubfn.isNull(type)) return { code: -1, msg: "type不能为空" }; + + if (checkUserExist) { + let dcloud_appid = originalParam.context.appId; + // 检测邮箱对应的账号是否存在 + let num = await vk.daoCenter.userDao.count({ + email, + dcloud_appid: _.or(_.eq(dcloud_appid), _.exists(false)) + }); + if (checkUserExist === true || checkUserExist === "exists") { + // 邮箱必须已注册用户,如果邮箱未注册,则不发短信 + if (num === 0) { + return { code: -1, msg: `邮箱:${email} 未注册`, notExists: true }; + } + } else if (checkUserExist === "!exists") { + // 邮箱必须未注册用户,如果邮箱已注册,则不发短信 + if (num > 0) { + return { code: -1, msg: `邮箱:${email} 已注册`, exists: true }; + } + } + } + + // 针对同一个邮箱,发送验证码每天有次数限制 + const cacheKey = `sys.sendEmailCode.everyDaylimit-${email}`; + let currNum = await vk.globalDataCache.get(cacheKey); + if (!currNum) currNum = 0; + if (currNum >= everyDaylimit) { + return { code: -1, msg: "此邮箱今日已超最大次数限制,请明日再试" }; + } + + let code = vk.pubfn.random(6, "0123456789"); + let param = { + code, + type, + email + }; + // 发送验证码开始 + let emailConfig = config.vk.service.email; + // 如果配置设置了过期时间,则使用配置的过期时间,否则默认180秒 + param.expiresIn = emailConfig.codeExpiresIn || 180; + let emailService = vkmail.createTransport({ + "host": emailConfig[serviceType].host, + "port": emailConfig[serviceType].port, + "secure": emailConfig[serviceType].secure, // use SSL + "auth": emailConfig[serviceType].auth + }); + try { + // 发送邮件 + await emailService.sendMail({ + "from": emailConfig[serviceType].auth.user, + "to": data.email, + "cc": emailConfig[serviceType].auth.user, // 由于邮件可能会被当成垃圾邮件,但只要把邮件抄送给自己一份,就不会被当成垃圾邮件。 + "subject": data.subject || `验证码是${code}`, // 邮件的标题 + "text": `您的验证码是${code},打死也不要告诉别人哦!`, // 邮件的内容 + }); + // 发送验证码成功后,设置验证码 + await uniID.setVerifyCode(param); + + currNum++; + let { startTime } = vk.pubfn.getDayOffsetStartAndEnd(1, new Date()); + let second = vk.pubfn.toDecimal((startTime - Date.now()) / 1000, 0) + await vk.globalDataCache.set(cacheKey, currNum, second); + } catch (err) { + console.error(err); + return { code: -1, msg: "邮件发送失败", err }; + } + // 发送验证码结束 + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/sendSmsCode.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/sendSmsCode.js new file mode 100644 index 0000000..811d782 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/sendSmsCode.js @@ -0,0 +1,86 @@ +var everyDaylimit = 12; // 限制同一个手机号每天次数 +module.exports = { + /** + * 发送短信的验证码 + * @url user/pub/sendSmsCode 前端调用的url参数地址 + * @description 发送验证码 + * data 请求参数 说明 + * @param {String} mobile 手机号 + * @param {String} type 验证码类型 + * @param {Boolean|String} checkUserExist 是否需要检测手机号对应的账号是否存在或不存在,默认不检测,若为exists代表手机号必须已注册,若为!exists代表手机号必须未注册 + * + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {Object} requestRes 原始返回数据 + * @param {Object} requestParam 包含服务供应商和发送的手机号 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + mobile, + type, + checkUserExist = false + } = data; + if (vk.pubfn.isNull(mobile)) { + return { code: -1, msg: '手机号不能为空' }; + } + if (!vk.pubfn.test(mobile, 'mobile')) { + return { code: -1, msg: "手机号格式错误" }; + } + + if (checkUserExist) { + let dcloud_appid = originalParam.context.appId; + // 检测手机号对应的账号是否存在 + let num = await vk.daoCenter.userDao.count({ + mobile, + dcloud_appid: _.or(_.eq(dcloud_appid), _.exists(false)) + }); + if (checkUserExist === true || checkUserExist === "exists") { + // 手机号必须已注册用户,如果手机号未注册,则不发短信 + if (num === 0) { + return { code: -1, msg: `手机号:${mobile} 未注册`, notExists: true }; + } + } else if (checkUserExist === "!exists") { + // 手机号必须未注册用户,如果手机号已注册,则不发短信 + if (num > 0) { + return { code: -1, msg: `手机号:${mobile} 已注册`, exists: true }; + } + } + } + + // 针对同一个手机号,发送验证码每天有次数限制 + const cacheKey = `sys.sendSmsCode.everyDaylimit-${mobile}`; + let currNum = await vk.globalDataCache.get(cacheKey); + if (!currNum) currNum = 0; + if (currNum >= everyDaylimit) { + return { code: -1, msg: "此手机号今日已超最大次数限制,请明日再试" }; + } + + + let code = vk.pubfn.random(6, "0123456789"); + let provider = "unicloud"; + if (vk.pubfn.getData(config, "vk.service.sms.aliyun.enable")) { + provider = "aliyun"; + } + res = await vk.system.smsUtil.sendSmsVerifyCode({ + provider, + code, + type, + phone: mobile, + expiresIn: 180, // 验证码实际有效时间,必须是60的倍数 + }); + if (res.code == 0) { + currNum++; + let { startTime } = vk.pubfn.getDayOffsetStartAndEnd(1, new Date()); + let second = vk.pubfn.toDecimal((startTime - Date.now()) / 1000, 0) + await vk.globalDataCache.set(cacheKey, currNum, second); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/sys/encryptPwd.js b/uniCloud-aliyun/cloudfunctions/router/service/user/sys/encryptPwd.js new file mode 100644 index 0000000..3aefe0e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/sys/encryptPwd.js @@ -0,0 +1,28 @@ +module.exports = { + /** + * 密码加密测试 + * @url user/sys/encryptPwd 前端调用的url参数地址 + * @description 密码加密测试 + * @param {Object} data 请求参数 + * @param {String} uniIdToken 用户token + * @param {Object} util 公共工具包 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} password 加密后的字符串 + */ + main: async (event) => { + let { util } = event; + let { uniID } = util; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + const password = await uniID.encryptPwd('123456'); + res = { + code: 0, + msg: '密码加密完成', + password + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/sys/setVerifyCode.js b/uniCloud-aliyun/cloudfunctions/router/service/user/sys/setVerifyCode.js new file mode 100644 index 0000000..53d0e78 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/sys/setVerifyCode.js @@ -0,0 +1,27 @@ +module.exports = { + /** + * 设置验证码 + * @url user/sys/setVerifyCode 前端调用的url参数地址 + * @description 设置验证码(此接口正式环境不要暴露,故写在了sys目录下) + * data 请求参数 说明 + * @param {String} email 邮箱 + * @param {String} mobile 手机号 + * @param {String} type 验证码类型 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} email 邮箱 + * @param {String} mobile 手机号 + * @param {String} verifyCode 验证码(uni 1.1.2开始不再返回verifyCode) + */ + main: async (event) => { + let { data = {}, util } = event; + let { uniID } = util; + let { email, mobile, code, type } = data; + let res = {code : -1, msg : ''}; + // 业务逻辑开始----------------------------------------------------------- + res = await uniID.setVerifyCode(data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/util/login_log.js b/uniCloud-aliyun/cloudfunctions/router/service/user/util/login_log.js new file mode 100644 index 0000000..7ef51a7 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/util/login_log.js @@ -0,0 +1,72 @@ +module.exports = { + /** + * 添加登录日志 + * @param {Object} type 日志类型 login logout + * @param {String} login_type 登录类型 phone password weixin alipay + * @param {Object} user_id 用户ID + * @param {String} ip ip地址 + * @param {String} ua userAgent + * @param {String} os 操作系统 + * @param {String} platform 平台信息 + * @param {Object} context 请求上下文 + * @param {Number} state 1:登录成功 0 登录失败 + */ + add: async (event, util) => { + let { uniID, config, pubFun, vk, db, _ } = util; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + type, + login_type, + user_id, + ip, + ua, + os, + platform, + context = {}, + state = 1, + dcloud_appid + } = event; + if (context) { + ip = context.CLIENTIP; + ua = context.CLIENTUA; + os = context.OS; + platform = context.PLATFORM; + dcloud_appid = context.APPID; + } + try { + if (vk.pubfn.getData(config, "vk.service.log.login.status")) { + let nowDate = new Date(); + let { + now + } = vk.pubfn.getCommonTime(nowDate); + // 增加登录日志 + await vk.baseDao.add({ + dbName: "uni-id-log", + dataJson: { + type, + login_type, + user_id, + ip, + ua, + os, + platform, + state, + dcloud_appid, + date:{ + ...now, + date_day_str: vk.pubfn.timeFormat(nowDate, "yyyy-MM-dd"), + date_month_str: vk.pubfn.timeFormat(nowDate, "yyyy-MM") + } + } + }); + } else { + console.log("已关闭登录日志"); + } + } catch (err) { + console.log("日志写入错误"); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/统一用户中心.md b/uniCloud-aliyun/cloudfunctions/router/service/user/统一用户中心.md new file mode 100644 index 0000000..da1abc1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/统一用户中心.md @@ -0,0 +1,12 @@ +## 统一用户中心 +#### `router/service/user` +#### 此目录为集成`uni-id`账户系统的实现(开发者自己系统的逻辑尽量不要写在此处,应写在`service/admin`或`service/client`或`其他`目录下 + +``` +. +├── user──────────────────────# 统一用户中心服务(已集成uniID) +│ ── └── kh───────────────────# kh函数为必须登录后才能访问的函数(客户端用户) +│ ── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ── └── sys──────────────────# sys函数为需要授权才能访问的函数(如商家工作人员等) +└───────────────────────────────── +``` \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/逻辑层目录说明.md b/uniCloud-aliyun/cloudfunctions/router/service/逻辑层目录说明.md new file mode 100644 index 0000000..3290fa1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/逻辑层目录说明.md @@ -0,0 +1,47 @@ +## 逻辑层 +#### `router/service` 目录为逻辑层 +#### 以下的目录并非强制性,只是建议,便于统一开发规范。 + +``` +. +├── service──────────────────────# 逻辑层(用于写业务逻辑) +│ └── admin────────────────# PC后台管理端逻辑(admin框架开发中。。。) +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ └── client───────────────# 客户端逻辑(H5、小程序、APP) +│ ── └── user─────────────────# 用户服务(自己系统的逻辑) +│ ──── └── kh───────────────────# kh函数为必须登录后才能访问的函数 +│ ──── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ──── └── sys──────────────────# sys函数为需要角色授权才能访问的函数 +│ ──── └── util─────────────────# 用户服务专用的工具包 +│ ── └── order────────────────# 订单服务(自己系统的逻辑) +│ ──── └── kh───────────────────# kh函数为必须登录后才能访问的函数 +│ ──── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ──── └── sys──────────────────# sys函数为需要角色授权才能访问的函数 +│ ──── └── util─────────────────# 订单服务专用的工具包 +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ └── common───────────────# 公共逻辑(公共接口) +│ ── └── xxxxxxxxxxxxxxxx─────# +│ ── └── xxxxxxxxxxxxxxxx─────# +│ ── └── xxxxxxxxxxxxxxxx─────# +│ └── user─────────────────# 统一用户中心服务(已集成uniID)(用户中心作为核心,且为了方便插件升级,故与admin和client平级) +│ ── └── kh───────────────────# kh函数为必须登录后才能访问的函数(客户端用户) +│ ── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ── └── sys──────────────────# sys函数为后端管理人员才能访问的函数(商家后台工作人员) +│ ── └── util─────────────────# 统一用户中心服务专用的工具包 +│ └── plugs───────────────# 插件逻辑(插件专用)(会陆续新增一些实用性插件给开发者使用,如微信小程序发送订阅消息等等) +│ ── └── admin────────────────# 管理端类型插件 +│ ──── └── 插件A──────────────────# 插件A +│ ──── └── 插件B──────────────────# 插件B +│ ── └── client───────────────# 客户端类型插件 +│ ──── └── 插件A──────────────────# 插件A +│ ──── └── 插件B──────────────────# 插件B +│ └── template─────────────# 云函数模板(插件内的云函数写法模板) +│ ── └── db_api───────────────# 数据库接口调用模板 +│ └── muban.js─────────────# 云函数模板(新建一个云函数应复制粘贴这个文件) +│ └── muban_easy.js────────# 云函数模板(简易版) +└───────────────────────────────── +``` diff --git a/uniCloud-aliyun/cloudfunctions/router/util/pubFunction.js b/uniCloud-aliyun/cloudfunctions/router/util/pubFunction.js new file mode 100644 index 0000000..3456155 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/util/pubFunction.js @@ -0,0 +1,95 @@ +/** + * 自定义公共函数包 + * 这里可以写你自己的公共函数 + */ +var CryptoJS = require("crypto-js"); +const crypto = require('crypto'); +var pubFun = {}; +/** + * 公共函数写法示例 + * 调用示例: + * pubFun.test(); + * 或 + * vk.myfn.test(); + */ +pubFun.test = function(path) { + // 此处可以直接使用 vk 实例 + let timeStr = vk.pubfn.timeFormat(new Date(), "yyyy-MM-dd hh:mm:ss"); + // 逻辑 + // ... + // 逻辑 + return { + timeStr, + msg: "这是公共函数test的返回" + } +} + +const url = 'http://test.api.fabigbig.com:8888/api/' +const app_id = 405942 +const app_secret = 'ODDW0vm9FvDj2RYQRmoryVnH' + +const getFadadaSign = function(params, timestamp) { + const copyParams = { + ...params + } + //1. A.将参与摘要计算的业务参数按字典升序排列 + var sortedParams = Object.keys(params).sort().reduce((acc, curr, index) => { + acc += params[curr]; + return acc; + }, ''); + + // 1.B.将 app_secret 附加到字符串串前 + const str1 = app_secret + sortedParams + + // 步骤 2.对得到的字符串进⾏SHA1 加密 + const sha1_1 = CryptoJS.SHA1(str1).toString().toUpperCase() + console.log('sha1_1: ', sha1_1); + // 步骤 3.计算 timestamp的MD5值,并和app_id,步骤 2 中得到的字符串拼接得到新的字符串 + const timestampMd5 = CryptoJS.MD5(timestamp).toString().toUpperCase() + const str2 = app_id + timestampMd5 + sha1_1 + + + // 步骤 4.对步骤3中得到的字符串进行SHA1 加密 + const str3 = CryptoJS.SHA1(str2).toString().toUpperCase() + // 步骤 5.对步骤 4 中得到的字符串进⾏base64 加密 + var wordArray = CryptoJS.enc.Utf8.parse(str3); + const msg_digest = CryptoJS.enc.Base64.stringify(wordArray); + + return msg_digest; + +} +pubFun.getFadadaSign = getFadadaSign + +/** + * 给法大大发请求 + + * @param {Object} api + * @param {Object} params + */ +pubFun.fadada = async function(api, params) { + + + + const timestamp = vk.pubfn.timeFormat(new Date(), "yyyyMMddhhmmss"); + + const msg_digest = getFadadaSign(params, timestamp) + + const res = await vk.request({ + url: url + api, + method: "POST", + header: { + "content-type": "application/x-www-form-urlencoded;charset=UTF-8", + }, + data: { + app_id: app_id, + timestamp, + v: '2.0', + msg_digest, + ...params + } + }); + + return res; +} + +module.exports = pubFun; \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/util/urlrewrite.js b/uniCloud-aliyun/cloudfunctions/router/util/urlrewrite.js new file mode 100644 index 0000000..23326bf --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/util/urlrewrite.js @@ -0,0 +1,15 @@ +/** + * URL重写 + */ +module.exports = { + "rule": { + // 示例1:https://xxx.bspapp.com/http/router/aaa 指向云函数 template/db_api/pub/select + "^aaa$": "template/db_api/pub/select", + // 示例2:https://xxx.bspapp.com/http/router/findById/001 指向云函数 template/db_api/pub/findById?_id=001 + "^findById/(.+)": "template/db_api/pub/findById?_id=$1" + }, + "config": { + // 当设置为true时,只有符合url重写规则内的云函数才可以被url化访问。 + "accessOnlyInRule": false + } +}; diff --git a/uniCloud-aliyun/database/JQL查询.jql b/uniCloud-aliyun/database/JQL查询.jql new file mode 100644 index 0000000..35d21de --- /dev/null +++ b/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/uniCloud-aliyun/database/db_init.json b/uniCloud-aliyun/database/db_init.json new file mode 100644 index 0000000..f816546 --- /dev/null +++ b/uniCloud-aliyun/database/db_init.json @@ -0,0 +1,939 @@ +// 在本文件中可配置云数据库初始化,数据格式见:https://uniapp.dcloud.io/uniCloud/cf-database?id=db_init + +// 编写完毕后对本文件点右键,可按配置规则创建表和添加数据 + +{ + "vk-test": { + "data": [ + + ], + "index": [ + { + "IndexName": "location", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "location","Direction": "2dsphere"}],"MgoIsUnique": false} + }, + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "uni-id-users": { + "data": [ + { + "_id":"001", + "username": "admin", + "password": "03caebb36670995fc261a275d212cad65e4bbebd", + "register_date": 1596416400000, + "register_ip": "127.0.0.1", + "nickname": "超级管理员", + "role":["admin"], + "token": [], + "allow_login_background":true + } + ], + "index": [ + { + "IndexName": "username", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "username","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "mobile", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "mobile","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "email", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "email","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "wx_openid.app-plus", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "wx_openid.app-plus","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "wx_openid.mp-weixin", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "wx_openid.mp-weixin","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "wx_unionid", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "wx_unionid","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "ali_openid", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "ali_openid","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "my_invite_code", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "my_invite_code","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "inviter_uid", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "inviter_uid","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "invite_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "invite_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "role", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "role","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "register_date", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "register_date","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "opendb-verify-codes": { + "data": [], + "index": [ + { + "IndexName": "mobile", + "MgoKeySchema": { + "MgoIndexKeys": [{ + "Name": "mobile", + "Direction": "1" + }, { + "Name": "code", + "Direction": "1" + }], + "MgoIsUnique": false + } + }, + { + "IndexName": "email", + "MgoKeySchema": { + "MgoIndexKeys": [{ + "Name": "email", + "Direction": "1" + }, { + "Name": "code", + "Direction": "1" + }], + "MgoIsUnique": false + } + }, + { + "IndexName": "type", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "type","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "state", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "state","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "opendb-tempdata": { + "data": [ + + ], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "expired", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "expired","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "opendb-open-data": { + "data": [ + + ], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "expired", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "expired","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "uni-id-log":{ + "data": [], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "user_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "user_id","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "uni-id-roles":{ + "data": [ + { + "_id": "001", + "_add_time": 1596416400000, + "enable":true, + "role_id":"admin", + "role_name": "超级管理员", + "comment":"系统内置角色 - 请勿修改", + "permission": [] + }, + { + "_id": "005", + "_add_time": 1596416400000, + "enable":true, + "role_id":"query-all", + "role_name": "boss", + "comment":"系统内置角色 - 请勿修改", + "permission": [] + }, + { + "_id": "006", + "_add_time": 1596416400000, + "enable":true, + "role_id":"custom-role-1", + "role_name": "自定义角色-1", + "comment":"更细粒化的自定义角色权限示例", + "permission": [] + } + ], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "role_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "role_id","Direction": "1"}],"MgoIsUnique": true} + }, + { + "IndexName": "permission", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "permission","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "role_name", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "role_name","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "uni-id-permissions":{ + "data": [ + { + "_id": "sys-permission", + "_add_time": 1596416400000, + "permission_id":"sys-permission", + "permission_name": "系统内置权限", + "comment":"系统内置权限", + "url": "", + "sort": 103, + "enable":true + }, + { + "_id": "sys-permission-add", + "_add_time": 1596416400000, + "permission_id":"sys-permission-add", + "permission_name": "系统内置 - 增", + "comment":"所有函数名以add开头的云函数", + "url": ["*/add*"], + "icon":"vk-icon-add", + "sort": 1, + "parent_id":"sys-permission", + "enable":true, + "match_mode":1, + "curd_category":1, + "level":3 + }, + { + "_id": "sys-permission-delete", + "_add_time": 1596416400000, + "permission_id":"sys-permission-delete", + "permission_name": "系统内置 - 删", + "comment":"所有函数名以delete开头的云函数", + "url": ["*/delete*"], + "icon":"vk-icon-delete", + "sort": 2, + "parent_id":"sys-permission", + "enable":true, + "match_mode":1, + "curd_category":2, + "level":4 + }, + { + "_id": "sys-permission-update", + "_add_time": 1596416400000, + "permission_id":"sys-permission-update", + "permission_name": "系统内置 - 改", + "comment":"所有函数名以update开头的云函数", + "url": ["*/update*"], + "icon":"el-icon-edit", + "sort": 3, + "parent_id":"sys-permission", + "enable":true, + "match_mode":1, + "curd_category":3, + "level":3 + }, + { + "_id": "sys-permission-read", + "_add_time": 1596416400000, + "permission_id":"sys-permission-read", + "permission_name": "系统内置 - 查", + "comment":"包含所有的查询操作", + "url": ["*/get*","*/find*","*/select*"], + "icon":"vk-icon-text", + "sort": 4, + "parent_id":"sys-permission", + "enable":true, + "match_mode":1, + "curd_category":4, + "level":3 + }, + { + "_id": "sys-manage", + "_add_time": 1596416400000, + "permission_id":"sys-manage", + "permission_name": "用户角色权限菜单", + "comment":"", + "sort": 101, + "enable":true + }, + { + "_id": "sys-manage-user", + "_add_time": 1596416400000, + "permission_id":"sys-manage-user", + "permission_name": "系统 - 用户管理", + "comment":"", + "url": ["admin/system/user/sys/*"], + "sort": 1, + "enable":true, + "match_mode":1, + "parent_id":"sys-manage" + }, + { + "_id": "sys-manage-role", + "_add_time": 1596416400000, + "permission_id":"sys-manage-role", + "permission_name": "系统 - 角色管理", + "comment":"", + "url": ["admin/system/role/sys/*"], + "sort": 2, + "enable":true, + "match_mode":1, + "parent_id":"sys-manage" + }, + { + "_id": "sys-manage-permission", + "_add_time": 1596416400000, + "permission_id":"sys-manage-permission", + "permission_name": "系统 - 权限管理", + "comment":"", + "url": ["admin/system/permission/sys/*"], + "sort": 3, + "enable":true, + "match_mode":1, + "parent_id":"sys-manage" + }, + { + "_id": "sys-manage-menu", + "_add_time": 1596416400000, + "permission_id":"sys-manage-menu", + "permission_name": "系统 - 菜单管理", + "comment":"", + "url": ["admin/system/menu/sys/*"], + "sort": 4, + "enable":true, + "match_mode":1, + "parent_id":"sys-manage" + }, + { + "_id": "sys-manage-app", + "_add_time": 1596416400000, + "permission_id":"sys-manage-app", + "permission_name": "系统 - 应用管理", + "comment":"", + "url": ["admin/system/app/sys/*"], + "sort": 5, + "enable":true, + "match_mode":1, + "parent_id":"sys-manage" + }, + { + "_id": "sys-manage-app-upgrade-center", + "_add_time": 1596416400000, + "permission_id": "sys-manage-app-upgrade-center", + "permission_name": "系统 - App升级中心", + "comment":"", + "url": ["admin/system/app-upgrade-center/sys/*"], + "sort": 6, + "enable": true, + "match_mode": 1, + "parent_id": "sys-manage" + }, + { + "_id": "system-uni", + "_add_time": 1596416400000, + "permission_id":"system-uni", + "permission_name": "系统设置", + "comment":"", + "sort": 102, + "enable":true + }, + { + "_id": "system-uni-uni-id-files", + "_add_time": 1596416400000, + "permission_id":"system-uni-uni-id-files", + "permission_name": "系统 - 素材管理", + "comment":"", + "url": ["admin/system_uni/uni-id-files/*"], + "sort": 1, + "enable":true, + "match_mode":1, + "parent_id":"system-uni" + }, + { + "_id": "system-uni-vk-global-data", + "_add_time": 1596416400000, + "permission_id":"system-uni-vk-global-data", + "permission_name": "系统 - 缓存管理", + "comment":"", + "url": ["admin/system_uni/global-data/sys/*"], + "sort": 2, + "enable":true, + "match_mode":1, + "parent_id":"system-uni" + }, + { + "_id": "system-uni-vk-components-dynamic", + "_add_time": 1596416400000, + "permission_id":"system-uni-vk-components-dynamic", + "permission_name": "系统 - 动态组件数据管理", + "comment":"", + "url": ["admin/system_uni/components-dynamic/sys/*"], + "sort": 3, + "enable":true, + "match_mode":1, + "parent_id":"system-uni" + }, + { + "_id": "system-uni-uni-id-log", + "_add_time": 1596416400000, + "permission_id":"system-uni-uni-id-log", + "permission_name": "系统 - 用户登录日志管理", + "comment":"", + "url": ["admin/system_uni/uni-id-log/sys/*"], + "sort": 4, + "enable":true, + "match_mode":1, + "parent_id":"system-uni" + }, + { + "_id": "system-uni-opendb-admin-log", + "_add_time": 1596416400000, + "permission_id":"system-uni-opendb-admin-log", + "permission_name": "系统 - 操作日志管理", + "comment":"", + "url": ["admin/system_uni/admin-log/sys/*"], + "sort": 5, + "enable":true, + "match_mode":1, + "parent_id":"system-uni" + } + ], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "permission_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "permission_id","Direction": "1"}],"MgoIsUnique": true} + }, + { + "IndexName": "parent_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "parent_id","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "url", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "url","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "sort", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "sort","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "opendb-admin-menus":{ + "data": [ + { + "_id": "sys-admin", + "_add_time": 1596416400000, + "menu_id":"sys-admin", + "name": "用户角色权限", + "icon":"el-icon-s-tools", + "url": "", + "comment":"系统内置", + "sort": 100, + "enable":true + }, + { + "_id": "sys-user-manage", + "_add_time": 1596416400000, + "menu_id":"sys-user-manage", + "name": "用户管理", + "icon":"el-icon-s-custom", + "url": "/pages_plugs/system/user/list", + "comment":"1个角色可以分配多个角色", + "sort": 1, + "parent_id":"sys-admin", + "enable":true + }, + { + "_id": "sys-role-manage", + "_add_time": 1596416400000, + "menu_id":"sys-role-manage", + "name": "角色管理", + "icon":"el-icon-user", + "url": "/pages_plugs/system/role/list", + "comment":"1个角色可以分配多个权限和菜单", + "sort": 2, + "parent_id":"sys-admin", + "enable":true + }, + { + "_id": "sys-permission-manage", + "_add_time": 1596416400000, + "menu_id":"sys-permission-manage", + "name": "权限管理", + "icon":"vk-icon-lock", + "url": "/pages_plugs/system/permission/list", + "comment":"1个权限可以匹配多个云函数", + "sort": 3, + "parent_id":"sys-admin", + "enable":true + }, + { + "_id": "sys-menus-manage", + "_add_time": 1596416400000, + "menu_id":"sys-menus-manage", + "name": "菜单管理", + "icon":"el-icon-tickets", + "url": "/pages_plugs/system/menu/list", + "comment":"控制admin左侧菜单的显示和隐藏", + "sort": 4, + "parent_id":"sys-admin", + "enable":true + }, + { + "_id": "sys-app-manage", + "_add_time": 1596416400000, + "menu_id":"sys-app-manage", + "name": "应用管理", + "icon":"el-icon-cloudy", + "url": "/pages_plugs/system/app/list", + "comment":"应用管理", + "sort": 5, + "parent_id":"sys-admin", + "enable":true + }, + { + "_id": "sys-app-upgrade-center", + "_add_time": 1596416400000, + "menu_id":"sys-app-upgrade-center", + "name": "App升级中心", + "icon":"vk-icon-shengji3-xianxing", + "url": "/pages_plugs/system/app-upgrade-center/list", + "comment":"管理和发布新的app版本", + "sort": 6, + "parent_id":"sys-admin", + "enable":true + }, + { + "_id": "system-uni", + "_add_time": 1596416400000, + "enable": true, + "icon": "el-icon-s-tools", + "menu_id": "system-uni", + "name": "系统设置", + "sort": 110 + }, + { + "_id": "system-uni-uni-id-files", + "sort": 1, + "url": "/pages_plugs/system_uni/uni-id-files/list", + "_add_time": 1596416400000, + "enable": true, + "icon": "el-icon-folder-opened", + "menu_id": "system-uni-uni-id-files", + "name": "素材管理", + "parent_id": "system-uni" + }, + { + "_id": "system-uni-vk-global-data", + "enable": true, + "icon": "", + "menu_id": "system-uni-vk-global-data", + "name": "系统缓存管理", + "parent_id": "system-uni", + "sort": 2, + "url": "/pages_plugs/system_uni/vk-global-data", + "_add_time": 1596416400000 + }, + { + "_id": "system-uni-vk-components-dynamic", + "sort": 3, + "url": "/pages_plugs/system_uni/vk-components-dynamic", + "_add_time": 1596416400000, + "enable": true, + "icon": "", + "menu_id": "system-uni-vk-components-dynamic", + "name": "动态组件数据", + "parent_id": "system-uni" + }, + { + "_id": "system-uni-vk-pay-orders", + "sort": 4, + "url": "/pages_plugs/system_uni/vk-pay-orders", + "_add_time": 1596416400000, + "enable": true, + "icon": "", + "menu_id": "system-uni-vk-pay-orders", + "name": "支付订单明细", + "parent_id": "system-uni" + }, + { + "_id": "system-uni-uni-id-log", + "sort": 8, + "url": "/pages_plugs/system_uni/uni-id-log", + "_add_time": 1596416400000, + "enable": true, + "icon": "", + "menu_id": "system-uni-uni-id-log", + "name": "用户登录日志", + "parent_id": "system-uni" + }, + { + "_id": "system-uni-opendb-admin-log", + "sort": 9, + "url": "/pages_plugs/system_uni/opendb-admin-log", + "_add_time": 1596416400000, + "enable": true, + "icon": "", + "menu_id": "system-uni-opendb-admin-log", + "name": "系统操作日志", + "parent_id": "system-uni" + } + ], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "menu_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "menu_id","Direction": "1"}],"MgoIsUnique": true} + }, + { + "IndexName": "parent_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "parent_id","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "url", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "url","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "sort", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "sort","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "opendb-app-list": { + "data": [ + { + "_id":"001", + "appid": "__UNI__01F080F", + "type": "client", + "name": "用户端", + "description": "此为用户端应用", + "create_date": 1596416400000, + "_add_time": 1596416400000, + "_add_time_str": "2020-08-03 09:00:00" + }, + { + "_id":"002", + "appid": "__UNI__570A7FB", + "type": "admin", + "name": "管理端", + "description": "此为管理端应用", + "create_date": 1596416400000, + "_add_time": 1596416400000, + "_add_time_str": "2020-08-03 09:00:00" + } + ], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "appid", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "appid","Direction": "1"}],"MgoIsUnique": true} + }, + { + "IndexName": "name", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "name","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "type", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "type","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "create_date", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "create_date","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "enable_upgrade_center", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "enable_upgrade_center", "Direction": "1" }], "MgoIsUnique": false } + } + ] + }, + "opendb-app-versions": { + "data": [], + "index": [{ + "IndexName": "_add_time", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "_add_time", "Direction": "1" }], "MgoIsUnique": false } + }, + { + "IndexName": "appid", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "appid", "Direction": "1" }], "MgoIsUnique": false } + }, + { + "IndexName": "name", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "name", "Direction": "1" }], "MgoIsUnique": false } + }, + { + "IndexName": "platform", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "platform", "Direction": "1" }], "MgoIsUnique": false } + }, + { + "IndexName": "type", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "type", "Direction": "1" }], "MgoIsUnique": false } + }, + { + "IndexName": "uni_platform", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "uni_platform", "Direction": "1" }], "MgoIsUnique": false } + }, + { + "IndexName": "create_env", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "create_env", "Direction": "1" }], "MgoIsUnique": false } + }, + { + "IndexName": "stable_publish", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "stable_publish", "Direction": "1" }], "MgoIsUnique": false } + } + ] + }, + "opendb-admin-log":{ + "data": [ + + ], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "user_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "user_id","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "title", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "title","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "vk-components-dynamic":{ + "data": [], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "data_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "data_id","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "title", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "title","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "type", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "type","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "sort", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "sort","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "show", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "show","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "name", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "name","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "vk-global-data":{ + "data":[ + + ], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "key", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "key","Direction": "1"}],"MgoIsUnique": true} + }, + { + "IndexName": "expired_at", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "expired_at","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "vk-files": { + "data": [], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "user_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "user_id","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "sort", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "sort","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "status", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "status","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "type", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "type","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "display_name", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "display_name","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "url", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "url","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "vk-files-categories": { + "data": [], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "name", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "name","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "sort", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "sort","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "vk-pay-orders": { + "data": [], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "out_trade_no", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "out_trade_no","Direction": "1"}],"MgoIsUnique": true} + }, + { + "IndexName": "user_order_success", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "user_order_success","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "transaction_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "transaction_id","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "total_fee", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "total_fee","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "pid", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "pid","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "vk-pay-config": { + "data": [], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "jjx-spot-category": { + "data": [], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "parent_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "parent_id","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "level", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "level","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "jjx-spot-goods": { + "data": [], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "user_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "user_id","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "jjx-spot-cooperate": { + "data": [], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "userId", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "user_id","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "user_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "user_id","Direction": "1"}],"MgoIsUnique": false} + } + ] + } +} diff --git a/uni_modules/uni-config-center/changelog.md b/uni_modules/uni-config-center/changelog.md new file mode 100644 index 0000000..57dbcb5 --- /dev/null +++ b/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/uni_modules/uni-config-center/package.json b/uni_modules/uni-config-center/package.json new file mode 100644 index 0000000..bace866 --- /dev/null +++ b/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/uni_modules/uni-config-center/readme.md b/uni_modules/uni-config-center/readme.md new file mode 100644 index 0000000..03f7fc2 --- /dev/null +++ b/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/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js b/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js new file mode 100644 index 0000000..00ba62f --- /dev/null +++ b/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;t 一般uni-id升级大版本时为不兼容更新,从低版本迁移到高版本请参考:[uni-id迁移指南](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=migration) + +## 重要升级说明 + +**uni-id 3.x版本,搭配的uniCloud admin版本需大于1.2.10。** + +### 缓存角色权限 + +自`uni-id 3.0.0`起,支持在token内缓存用户的角色权限,默认开启此功能,各登录接口的needPermission参数不再生效。如需关闭请在config内配置`"removePermissionAndRoleFromToken": true`。 + +为什么要缓存角色权限?要知道云数据库是按照读写次数来收取费用的,并且读写数据库会拖慢接口响应速度。未配置`"removePermissionAndRoleFromToken": true`的情况下,可以在调用checkToken接口时不查询数据库获取用户角色权限。 + +详细checkToken流程如下: + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/ed45d350-5a4d-11eb-b997-9918a5dda011.jpg) + +可以看出,旧版token(removePermissionAndRoleFromToken为true时生成的)在checkToken时如需返回权限需要进行两次数据库查询。新版token不需要查库即可返回权限信息。 + +**注意** + +- 由于角色权限缓存在token内,可能会存在权限已经更新但是用户token未过期之前依然是旧版角色权限的情况。可以调短一些token过期时间来减少这种情况的影响。 +- admin角色token内不包含permission,如需自行判断用户是否有某个权限,要注意admin角色需要额外判断一下,写法如下 + ```js + const { + role, + permission + } = await uniID.checkToken(event.uniIdToken) + if(role.includes('admin') || permission.includes('your permission id')) { + // 当前角色拥有'your permission id'对应的权限 + } + ``` \ No newline at end of file diff --git a/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/LICENSE.md b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/LICENSE.md new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/LICENSE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/index.js b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/index.js new file mode 100644 index 0000000..5003d30 --- /dev/null +++ b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/index.js @@ -0,0 +1 @@ +"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e.default:e}var t=e(require("crypto")),r=e(require("buffer")),n=e(require("stream")),i=e(require("util"));const o={PARAM_ERROR:{errCode:"param-error"},PARAM_REQUIRED:{errCode:"param-required"},USER_NOT_EXIST:{errCode:"user-not-exist"},ROLE_NOT_EXIST:{errCode:"role-not-exist"},PERMISSION_NOT_EXIST:{errCode:"permission-not-exist"},MULTI_USER_MATCHED:{errCode:"multi-user-matched"},USER_INFO_ERROR:{errCode:"user-info-error"},USER_ACCOUNT_CONFLICT:{errCode:"user-account-conflict"},USER_ACCOUNT_CLOSED:{errCode:"user-account-closed"},ACCOUNT_EXISTS:{errCode:"account-exists"},ACCOUNT_NOT_EXISTS:{errCode:"account-not-exists"},ACCOUNT_BOUND:{errCode:"account-bound"},UNBIND_FAILED:{errCode:"unbind-failed"},INVALID_INVITE_CODE:{errCode:"invalid-invite-code"},SET_INVITE_CODE_FAILED:{errCode:"set-invite-code-failed"},GET_THIRD_PARTY_ACCOUNT_FAILED:{errCode:"get-third-party-account-failed"},GET_THIRD_PARTY_USER_INFO_FAILED:{errCode:"get-third-party-user-info-failed"}},s={0:{errCode:0,errMsg:""},10001:{errCode:"account-banned"},10002:o.USER_NOT_EXIST,10003:o.MULTI_USER_MATCHED,10004:o.USER_INFO_ERROR,10005:o.USER_ACCOUNT_CONFLICT,10006:o.USER_ACCOUNT_CLOSED,10102:{errCode:"password-error"},10103:{errCode:"password-error-exceed-limit"},10201:o.ACCOUNT_EXISTS,10202:o.ACCOUNT_NOT_EXISTS,10203:o.INVALID_INVITE_CODE,10301:o.ACCOUNT_EXISTS,10302:o.ACCOUNT_NOT_EXISTS,10401:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10402:o.ACCOUNT_EXISTS,10403:o.ACCOUNT_NOT_EXISTS,10501:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10502:o.ACCOUNT_EXISTS,10503:o.ACCOUNT_NOT_EXISTS,10601:o.ACCOUNT_EXISTS,10602:o.ACCOUNT_NOT_EXISTS,10701:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10702:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10703:o.ACCOUNT_EXISTS,10704:o.ACCOUNT_NOT_EXISTS,10705:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10706:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10801:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10802:o.ACCOUNT_EXISTS,10803:o.ACCOUNT_NOT_EXISTS,20101:o.PARAM_REQUIRED,20102:o.ACCOUNT_EXISTS,30101:o.PARAM_REQUIRED,30201:{errCode:"check-device-feature-failed"},30202:{errCode:"token-not-exist"},30203:{errCode:"token-expired"},30204:{errCode:"check-token-failed"},40201:o.USER_NOT_EXIST,40202:{errCode:"invalid-old-password"},50101:o.PARAM_REQUIRED,50102:o.PARAM_ERROR,50201:o.PARAM_REQUIRED,50203:o.PARAM_ERROR,50202:{errCode:"invalid-verify-code"},50301:{errCode:"send-sms-code-failed"},60101:o.ACCOUNT_BOUND,60201:o.ACCOUNT_BOUND,60301:o.GET_THIRD_PARTY_ACCOUNT_FAILED,60302:o.ACCOUNT_BOUND,60401:o.GET_THIRD_PARTY_ACCOUNT_FAILED,60402:o.ACCOUNT_BOUND,60501:o.GET_THIRD_PARTY_ACCOUNT_FAILED,60502:o.ACCOUNT_BOUND,70101:o.UNBIND_FAILED,70201:o.UNBIND_FAILED,70301:o.UNBIND_FAILED,70401:o.UNBIND_FAILED,70501:o.UNBIND_FAILED,80301:o.USER_NOT_EXIST,80401:o.SET_INVITE_CODE_FAILED,80402:o.SET_INVITE_CODE_FAILED,80501:o.INVALID_INVITE_CODE,80502:o.USER_NOT_EXIST,80503:{errCode:"modify-invite-code-is-not-allowed"},80601:o.GET_THIRD_PARTY_ACCOUNT_FAILED,80602:o.GET_THIRD_PARTY_ACCOUNT_FAILED,80701:o.GET_THIRD_PARTY_ACCOUNT_FAILED,80702:o.GET_THIRD_PARTY_ACCOUNT_FAILED,80801:{errCode:"decrypt-weixin-data-failed"},80802:{errCode:"decrypt-weixin-data-failed"},80803:{errCode:"invalid-weixin-appid"},80804:o.PARAM_REQUIRED,80805:o.PARAM_REQUIRED,80806:o.PARAM_REQUIRED,80901:o.GET_THIRD_PARTY_USER_INFO_FAILED,90001:{errCode:"database-operation-failed"},90002:o.PARAM_REQUIRED,90003:o.PARAM_ERROR,90004:o.USER_NOT_EXIST,90005:o.ROLE_NOT_EXIST,90006:o.PERMISSION_NOT_EXIST};class a extends Error{constructor(e){super(e.message),this.errMsg=e.message||"",Object.defineProperties(this,{message:{get(){return`errCode: ${e.code||""} | errMsg: `+this.errMsg},set(e){this.errMsg=e}}})}}const c=Object.prototype.toString,u=Object.prototype.hasOwnProperty;function d(e,t){return u.call(e,t)}function p(e){return"[object Object]"===c.call(e)}function l(e){return"function"==typeof e}function f(e){return!!e&&("object"==typeof e||"function"==typeof e)&&"function"==typeof e.then}function m(e){return Object.prototype.toString.call(e).slice(8,-1).toLowerCase()}const h=/_(\w)/g,g=/[A-Z]/g;function y(e){return e.replace(h,(e,t)=>t?t.toUpperCase():"")}function w(e){return e.replace(g,e=>"_"+e.toLowerCase())}function v(e,t){let r,n;switch(t){case"snake2camel":n=y,r=h;break;case"camel2snake":n=w,r=g}for(const i in e)if(d(e,i)&&r.test(i)){const r=n(i);e[r]=e[i],delete e[i],p(e[r])?e[r]=v(e[r],t):Array.isArray(e[r])&&(e[r]=e[r].map(e=>v(e,t)))}return e}function _(e){return v(e,"snake2camel")}function b(e){return v(e,"camel2snake")}function T(e){return function(e,t="-"){e=e||new Date;const r=[];return r.push(e.getFullYear()),r.push(("00"+(e.getMonth()+1)).substr(-2)),r.push(("00"+e.getDate()).substr(-2)),r.join(t)}(e=e||new Date)+" "+function(e,t=":"){e=e||new Date;const r=[];return r.push(("00"+e.getHours()).substr(-2)),r.push(("00"+e.getMinutes()).substr(-2)),r.push(("00"+e.getSeconds()).substr(-2)),r.join(t)}(e)}function E(){"development"===process.env.NODE_ENV&&console.log(...arguments)}function C(e=6){let t="";for(let r=0;r-1?"&":"?"}access_token=${t.accessToken}`}return`${e}${r}`}class G{constructor(e){this.options=Object.assign({baseUrl:"https://api.weixin.qq.com",timeout:5e3},e)}async _requestWxOpenapi({name:e,url:t,data:r,options:n}){const i={method:"GET",dataType:"json",dataAsQueryString:!0,timeout:this.options.timeout};return await H({name:"auth."+e,url:`${this.options.baseUrl}${K(t,r)}`,data:r,options:n,defaultOptions:i})}async code2Session(e){return await this._requestWxOpenapi({name:"code2Session",url:"/sns/jscode2session",data:{grant_type:"authorization_code",appid:this.options.appId,secret:this.options.secret,js_code:e}})}async getOauthAccessToken(e){const t=await this._requestWxOpenapi({name:"getOauthAccessToken",url:"/sns/oauth2/access_token",data:{grant_type:"authorization_code",appid:this.options.appId,secret:this.options.secret,code:e}});return t.expiresIn&&(t.expired=Date.now()+1e3*t.expiresIn),t}async getUserInfo({accessToken:e,openid:t}={}){const{nickname:r,headimgurl:n}=await this._requestWxOpenapi({name:"getUserInfo",url:"/sns/userinfo",data:{accessToken:e,openid:t,appid:this.options.appId,secret:this.options.secret,scope:"snsapi_userinfo"}});return{nickname:r,avatar:n}}}async function Q({name:e,url:t,data:r,options:n,defaultOptions:i}){let o;n=Object.assign({},i,n,{data:b(Object.assign({},r))});try{o=await uniCloud.httpclient.request(t,n)}catch(t){return function(e,t){throw new a({code:t.code||-2,message:t.message||e+" fail"})}(e,t)}let s=o.data;const c=o.headers["content-type"];if(!Buffer.isBuffer(s)||0!==c.indexOf("text/plain")&&0!==c.indexOf("application/json"))Buffer.isBuffer(s)&&(s={buffer:s,contentType:c});else try{s=JSON.parse(s.toString())}catch(e){s=s.toString()}return _(function(e,t){if(t.ret||t.error){const r=t.ret||t.error||t.errcode||-2,n=t.msg||t.error_description||t.errmsg||e+" fail";throw new a({code:r,message:n})}return delete t.ret,delete t.msg,delete t.error,delete t.error_description,delete t.errcode,delete t.errmsg,{...t,errMsg:e+" ok",errCode:0}}(e,s||{errCode:-2,errMsg:"Request failed"}))}class X{constructor(e){this.options=Object.assign({baseUrl:"https://graph.qq.com",timeout:5e3},e)}async _requestQQOpenapi({name:e,url:t,data:r,options:n}){const i={method:"GET",dataType:"json",dataAsQueryString:!0,timeout:this.options.timeout};var o,s;return await Q({name:"auth."+e,url:(o=this.options.baseUrl,s=t,/^https?:/.test(s)?s:o+s),data:r,options:n,defaultOptions:i})}async getOpenidByToken({accessToken:e}={}){const t=await this._requestQQOpenapi({name:"getOpenidByToken",url:"/oauth2.0/me",data:{accessToken:e,unionid:1,fmt:"json"}});if(t.clientId!==this.options.appId)throw new a({code:"APPID_NOT_MATCH",message:"appid not match"});return{openid:t.openid,unionid:t.unionid}}async code2Session({code:e}={}){return await this._requestQQOpenapi({name:"getOpenidByToken",url:"https://api.q.qq.com/sns/jscode2session",data:{grant_type:"authorization_code",appid:this.options.appId,secret:this.options.secret,js_code:e}})}}const Y={RSA:"RSA-SHA1",RSA2:"RSA-SHA256"};var z={code2Session:{returnValue:{openid:"userId"}}};class W extends class{constructor(e={}){if(!e.appId)throw new Error("appId required");if(!e.privateKey)throw new Error("privateKey required");const t={gateway:"https://openapi.alipay.com/gateway.do",timeout:5e3,charset:"utf-8",version:"1.0",signType:"RSA2",timeOffset:-(new Date).getTimezoneOffset()/60,keyType:"PKCS8"};e.sandbox&&(e.gateway="https://openapi.alipaydev.com/gateway.do"),this.options=Object.assign({},t,e);const r="PKCS8"===this.options.keyType?"PRIVATE KEY":"RSA PRIVATE KEY";this.options.privateKey=this._formatKey(this.options.privateKey,r),this.options.alipayPublicKey&&(this.options.alipayPublicKey=this._formatKey(this.options.alipayPublicKey,"PUBLIC KEY"))}_formatKey(e,t){return`-----BEGIN ${t}-----\n${e}\n-----END ${t}-----`}_formatUrl(e,t){let r=e;const n=["app_id","method","format","charset","sign_type","sign","timestamp","version","notify_url","return_url","auth_token","app_auth_token"];for(const e in t)if(n.indexOf(e)>-1){const n=encodeURIComponent(t[e]);r=`${r}${r.includes("?")?"&":"?"}${e}=${n}`,delete t[e]}return{execParams:t,url:r}}_getSign(e,r){const n=r.bizContent||null;delete r.bizContent;const i=Object.assign({method:e,appId:this.options.appId,charset:this.options.charset,version:this.options.version,signType:this.options.signType,timestamp:T((o=this.options.timeOffset,new Date(Date.now()+6e4*((new Date).getTimezoneOffset()+60*(o||0)))))},r);var o;n&&(i.bizContent=JSON.stringify(b(n)));const s=b(i),a=Object.keys(s).sort().map(e=>{let t=s[e];return"[object String]"!==Array.prototype.toString.call(t)&&(t=JSON.stringify(t)),`${e}=${t}`}).join("&"),c=t.createSign(Y[this.options.signType]).update(a,"utf8").sign(this.options.privateKey,"base64");return Object.assign(s,{sign:c})}async _exec(e,t={},r={}){const n=this._getSign(e,t),{url:i,execParams:o}=this._formatUrl(this.options.gateway,n),{status:s,data:a}=await uniCloud.httpclient.request(i,{method:"POST",data:o,dataType:"text",timeout:this.options.timeout});if(200!==s)throw new Error("request fail");const c=JSON.parse(a),u=e.replace(/\./g,"_")+"_response",d=c[u],p=c.error_response;if(d){if(!r.validateSign||this._checkResponseSign(a,u)){if(!d.code||"10000"===d.code){return{errCode:0,errMsg:d.msg||"",..._(d)}}const e=d.sub_code?`${d.sub_code} ${d.sub_msg}`:""+(d.msg||"unkonwn error");throw new Error(e)}throw new Error("check sign error")}if(p)throw new Error(p.sub_msg||p.msg||"request fail");throw new Error("request fail")}_checkResponseSign(e,r){if(!this.options.alipayPublicKey||""===this.options.alipayPublicKey)return console.warn("options.alipayPublicKey is empty"),!0;if(!e)return!1;const n=this._getSignStr(e,r),i=JSON.parse(e).sign,o=t.createVerify(Y[this.options.signType]);return o.update(n,"utf8"),o.verify(this.options.alipayPublicKey,i,"base64")}_getSignStr(e,t){let r=e.trim();const n=e.indexOf(t+'"'),i=e.lastIndexOf('"sign"');return r=r.substr(n+t.length+1),r=r.substr(0,i),r=r.replace(/^[^{]*{/g,"{"),r=r.replace(/\}([^}]*)$/g,"}"),r}}{constructor(e){super(e),this._protocols=z}async code2Session(e){return await this._exec("alipay.system.oauth.token",{grantType:"authorization_code",code:e})}}function J(e){var t=e[0];return t<"0"||t>"7"?"00"+e:e}function Z(e){var t=e.toString(16);return t.length%2?"0"+t:t}function ee(e){if(e<=127)return Z(e);var t=Z(e);return Z(128+t.length/2)+t}function te(e,t){return e(t={exports:{}},t.exports),t.exports}var re=te((function(e,t){var n=r.Buffer;function i(e,t){for(var r in e)t[r]=e[r]}function o(e,t,r){return n(e,t,r)}n.from&&n.alloc&&n.allocUnsafe&&n.allocUnsafeSlow?e.exports=r:(i(r,t),t.Buffer=o),o.prototype=Object.create(n.prototype),i(n,o),o.from=function(e,t,r){if("number"==typeof e)throw new TypeError("Argument must not be a number");return n(e,t,r)},o.alloc=function(e,t,r){if("number"!=typeof e)throw new TypeError("Argument must be a number");var i=n(e);return void 0!==t?"string"==typeof r?i.fill(t,r):i.fill(t):i.fill(0),i},o.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return n(e)},o.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return r.SlowBuffer(e)}})),ne=(re.Buffer,re.Buffer);function ie(e){if(this.buffer=null,this.writable=!0,this.readable=!0,!e)return this.buffer=ne.alloc(0),this;if("function"==typeof e.pipe)return this.buffer=ne.alloc(0),e.pipe(this),this;if(e.length||"object"==typeof e)return this.buffer=e,this.writable=!1,process.nextTick(function(){this.emit("end",e),this.readable=!1,this.emit("close")}.bind(this)),this;throw new TypeError("Unexpected data type ("+typeof e+")")}i.inherits(ie,n),ie.prototype.write=function(e){this.buffer=ne.concat([this.buffer,ne.from(e)]),this.emit("data",e)},ie.prototype.end=function(e){e&&this.write(e),this.emit("end",e),this.emit("close"),this.writable=!1,this.readable=!1};var oe=ie,se=r.Buffer,ae=r.SlowBuffer,ce=ue;function ue(e,t){if(!se.isBuffer(e)||!se.isBuffer(t))return!1;if(e.length!==t.length)return!1;for(var r=0,n=0;n=128&&--n,n}var we={derToJose:function(e,t){e=ge(e);var r=me(t),n=r+1,i=e.length,o=0;if(48!==e[o++])throw new Error('Could not find expected "seq"');var s=e[o++];if(129===s&&(s=e[o++]),i-o0)return function(e){if((e=String(e)).length>100)return;var t=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(!t)return;var r=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*r;case"weeks":case"week":case"w":return 6048e5*r;case"days":case"day":case"d":return r*mt;case"hours":case"hour":case"hrs":case"hr":case"h":return r*ft;case"minutes":case"minute":case"mins":case"min":case"m":return r*lt;case"seconds":case"second":case"secs":case"sec":case"s":return r*pt;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}(e);if("number"===r&&isFinite(e))return t.long?function(e){var t=Math.abs(e);if(t>=mt)return gt(e,t,mt,"day");if(t>=ft)return gt(e,t,ft,"hour");if(t>=lt)return gt(e,t,lt,"minute");if(t>=pt)return gt(e,t,pt,"second");return e+" ms"}(e):function(e){var t=Math.abs(e);if(t>=mt)return Math.round(e/mt)+"d";if(t>=ft)return Math.round(e/ft)+"h";if(t>=lt)return Math.round(e/lt)+"m";if(t>=pt)return Math.round(e/pt)+"s";return e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))};function gt(e,t,r,n){var i=t>=1.5*r;return Math.round(e/r)+" "+n+(i?"s":"")}var yt=function(e,t){var r=t||Math.floor(Date.now()/1e3);if("string"==typeof e){var n=ht(e);if(void 0===n)return;return Math.floor(r+n/1e3)}return"number"==typeof e?r+e:void 0},wt=te((function(e,t){var r;t=e.exports=G,r="object"==typeof process&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?function(){var e=Array.prototype.slice.call(arguments,0);e.unshift("SEMVER"),console.log.apply(console,e)}:function(){},t.SEMVER_SPEC_VERSION="2.0.0";var n=Number.MAX_SAFE_INTEGER||9007199254740991,i=t.re=[],o=t.src=[],s=0,a=s++;o[a]="0|[1-9]\\d*";var c=s++;o[c]="[0-9]+";var u=s++;o[u]="\\d*[a-zA-Z-][a-zA-Z0-9-]*";var d=s++;o[d]="("+o[a]+")\\.("+o[a]+")\\.("+o[a]+")";var p=s++;o[p]="("+o[c]+")\\.("+o[c]+")\\.("+o[c]+")";var l=s++;o[l]="(?:"+o[a]+"|"+o[u]+")";var f=s++;o[f]="(?:"+o[c]+"|"+o[u]+")";var m=s++;o[m]="(?:-("+o[l]+"(?:\\."+o[l]+")*))";var h=s++;o[h]="(?:-?("+o[f]+"(?:\\."+o[f]+")*))";var g=s++;o[g]="[0-9A-Za-z-]+";var y=s++;o[y]="(?:\\+("+o[g]+"(?:\\."+o[g]+")*))";var w=s++,v="v?"+o[d]+o[m]+"?"+o[y]+"?";o[w]="^"+v+"$";var _="[v=\\s]*"+o[p]+o[h]+"?"+o[y]+"?",b=s++;o[b]="^"+_+"$";var T=s++;o[T]="((?:<|>)?=?)";var E=s++;o[E]=o[c]+"|x|X|\\*";var C=s++;o[C]=o[a]+"|x|X|\\*";var A=s++;o[A]="[v=\\s]*("+o[C]+")(?:\\.("+o[C]+")(?:\\.("+o[C]+")(?:"+o[m]+")?"+o[y]+"?)?)?";var I=s++;o[I]="[v=\\s]*("+o[E]+")(?:\\.("+o[E]+")(?:\\.("+o[E]+")(?:"+o[h]+")?"+o[y]+"?)?)?";var S=s++;o[S]="^"+o[T]+"\\s*"+o[A]+"$";var x=s++;o[x]="^"+o[T]+"\\s*"+o[I]+"$";var k=s++;o[k]="(?:^|[^\\d])(\\d{1,16})(?:\\.(\\d{1,16}))?(?:\\.(\\d{1,16}))?(?:$|[^\\d])";var O=s++;o[O]="(?:~>?)";var P=s++;o[P]="(\\s*)"+o[O]+"\\s+",i[P]=new RegExp(o[P],"g");var R=s++;o[R]="^"+o[O]+o[A]+"$";var j=s++;o[j]="^"+o[O]+o[I]+"$";var D=s++;o[D]="(?:\\^)";var q=s++;o[q]="(\\s*)"+o[D]+"\\s+",i[q]=new RegExp(o[q],"g");var N=s++;o[N]="^"+o[D]+o[A]+"$";var U=s++;o[U]="^"+o[D]+o[I]+"$";var L=s++;o[L]="^"+o[T]+"\\s*("+_+")$|^$";var V=s++;o[V]="^"+o[T]+"\\s*("+v+")$|^$";var M=s++;o[M]="(\\s*)"+o[T]+"\\s*("+_+"|"+o[A]+")",i[M]=new RegExp(o[M],"g");var B=s++;o[B]="^\\s*("+o[A]+")\\s+-\\s+("+o[A]+")\\s*$";var F=s++;o[F]="^\\s*("+o[I]+")\\s+-\\s+("+o[I]+")\\s*$";var $=s++;o[$]="(<|>)?=?\\s*\\*";for(var H=0;H<35;H++)r(H,o[H]),i[H]||(i[H]=new RegExp(o[H]));function K(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof G)return e;if("string"!=typeof e)return null;if(e.length>256)return null;if(!(t.loose?i[b]:i[w]).test(e))return null;try{return new G(e,t)}catch(e){return null}}function G(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof G){if(e.loose===t.loose)return e;e=e.version}else if("string"!=typeof e)throw new TypeError("Invalid Version: "+e);if(e.length>256)throw new TypeError("version is longer than 256 characters");if(!(this instanceof G))return new G(e,t);r("SemVer",e,t),this.options=t,this.loose=!!t.loose;var o=e.trim().match(t.loose?i[b]:i[w]);if(!o)throw new TypeError("Invalid Version: "+e);if(this.raw=e,this.major=+o[1],this.minor=+o[2],this.patch=+o[3],this.major>n||this.major<0)throw new TypeError("Invalid major version");if(this.minor>n||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>n||this.patch<0)throw new TypeError("Invalid patch version");o[4]?this.prerelease=o[4].split(".").map((function(e){if(/^[0-9]+$/.test(e)){var t=+e;if(t>=0&&t=0;)"number"==typeof this.prerelease[r]&&(this.prerelease[r]++,r=-2);-1===r&&this.prerelease.push(0)}t&&(this.prerelease[0]===t?isNaN(this.prerelease[1])&&(this.prerelease=[t,0]):this.prerelease=[t,0]);break;default:throw new Error("invalid increment argument: "+e)}return this.format(),this.raw=this.version,this},t.inc=function(e,t,r,n){"string"==typeof r&&(n=r,r=void 0);try{return new G(e,r).inc(t,n).version}catch(e){return null}},t.diff=function(e,t){if(J(e,t))return null;var r=K(e),n=K(t),i="";if(r.prerelease.length||n.prerelease.length){i="pre";var o="prerelease"}for(var s in r)if(("major"===s||"minor"===s||"patch"===s)&&r[s]!==n[s])return i+s;return o},t.compareIdentifiers=X;var Q=/^[0-9]+$/;function X(e,t){var r=Q.test(e),n=Q.test(t);return r&&n&&(e=+e,t=+t),e===t?0:r&&!n?-1:n&&!r?1:e0}function W(e,t,r){return Y(e,t,r)<0}function J(e,t,r){return 0===Y(e,t,r)}function Z(e,t,r){return 0!==Y(e,t,r)}function ee(e,t,r){return Y(e,t,r)>=0}function te(e,t,r){return Y(e,t,r)<=0}function re(e,t,r,n){switch(t){case"===":return"object"==typeof e&&(e=e.version),"object"==typeof r&&(r=r.version),e===r;case"!==":return"object"==typeof e&&(e=e.version),"object"==typeof r&&(r=r.version),e!==r;case"":case"=":case"==":return J(e,r,n);case"!=":return Z(e,r,n);case">":return z(e,r,n);case">=":return ee(e,r,n);case"<":return W(e,r,n);case"<=":return te(e,r,n);default:throw new TypeError("Invalid operator: "+t)}}function ne(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof ne){if(e.loose===!!t.loose)return e;e=e.value}if(!(this instanceof ne))return new ne(e,t);r("comparator",e,t),this.options=t,this.loose=!!t.loose,this.parse(e),this.semver===ie?this.value="":this.value=this.operator+this.semver.version,r("comp",this)}t.rcompareIdentifiers=function(e,t){return X(t,e)},t.major=function(e,t){return new G(e,t).major},t.minor=function(e,t){return new G(e,t).minor},t.patch=function(e,t){return new G(e,t).patch},t.compare=Y,t.compareLoose=function(e,t){return Y(e,t,!0)},t.rcompare=function(e,t,r){return Y(t,e,r)},t.sort=function(e,r){return e.sort((function(e,n){return t.compare(e,n,r)}))},t.rsort=function(e,r){return e.sort((function(e,n){return t.rcompare(e,n,r)}))},t.gt=z,t.lt=W,t.eq=J,t.neq=Z,t.gte=ee,t.lte=te,t.cmp=re,t.Comparator=ne;var ie={};function oe(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof oe)return e.loose===!!t.loose&&e.includePrerelease===!!t.includePrerelease?e:new oe(e.raw,t);if(e instanceof ne)return new oe(e.value,t);if(!(this instanceof oe))return new oe(e,t);if(this.options=t,this.loose=!!t.loose,this.includePrerelease=!!t.includePrerelease,this.raw=e,this.set=e.split(/\s*\|\|\s*/).map((function(e){return this.parseRange(e.trim())}),this).filter((function(e){return e.length})),!this.set.length)throw new TypeError("Invalid SemVer Range: "+e);this.format()}function se(e){return!e||"x"===e.toLowerCase()||"*"===e}function ae(e,t,r,n,i,o,s,a,c,u,d,p,l){return((t=se(r)?"":se(n)?">="+r+".0.0":se(i)?">="+r+"."+n+".0":">="+t)+" "+(a=se(c)?"":se(u)?"<"+(+c+1)+".0.0":se(d)?"<"+c+"."+(+u+1)+".0":p?"<="+c+"."+u+"."+d+"-"+p:"<="+a)).trim()}function ce(e,t,n){for(var i=0;i0){var o=e[i].semver;if(o.major===t.major&&o.minor===t.minor&&o.patch===t.patch)return!0}return!1}return!0}function ue(e,t,r){try{t=new oe(t,r)}catch(e){return!1}return t.test(e)}function de(e,t,r,n){var i,o,s,a,c;switch(e=new G(e,n),t=new oe(t,n),r){case">":i=z,o=te,s=W,a=">",c=">=";break;case"<":i=W,o=ee,s=z,a="<",c="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(ue(e,t,n))return!1;for(var u=0;u=0.0.0")),p=p||e,l=l||e,i(e.semver,p.semver,n)?p=e:s(e.semver,l.semver,n)&&(l=e)})),p.operator===a||p.operator===c)return!1;if((!l.operator||l.operator===a)&&o(e,l.semver))return!1;if(l.operator===c&&s(e,l.semver))return!1}return!0}ne.prototype.parse=function(e){var t=this.options.loose?i[L]:i[V],r=e.match(t);if(!r)throw new TypeError("Invalid comparator: "+e);this.operator=r[1],"="===this.operator&&(this.operator=""),r[2]?this.semver=new G(r[2],this.options.loose):this.semver=ie},ne.prototype.toString=function(){return this.value},ne.prototype.test=function(e){return r("Comparator.test",e,this.options.loose),this.semver===ie||("string"==typeof e&&(e=new G(e,this.options)),re(e,this.operator,this.semver,this.options))},ne.prototype.intersects=function(e,t){if(!(e instanceof ne))throw new TypeError("a Comparator is required");var r;if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),""===this.operator)return r=new oe(e.value,t),ue(this.value,r,t);if(""===e.operator)return r=new oe(this.value,t),ue(e.semver,r,t);var n=!(">="!==this.operator&&">"!==this.operator||">="!==e.operator&&">"!==e.operator),i=!("<="!==this.operator&&"<"!==this.operator||"<="!==e.operator&&"<"!==e.operator),o=this.semver.version===e.semver.version,s=!(">="!==this.operator&&"<="!==this.operator||">="!==e.operator&&"<="!==e.operator),a=re(this.semver,"<",e.semver,t)&&(">="===this.operator||">"===this.operator)&&("<="===e.operator||"<"===e.operator),c=re(this.semver,">",e.semver,t)&&("<="===this.operator||"<"===this.operator)&&(">="===e.operator||">"===e.operator);return n||i||o&&s||a||c},t.Range=oe,oe.prototype.format=function(){return this.range=this.set.map((function(e){return e.join(" ").trim()})).join("||").trim(),this.range},oe.prototype.toString=function(){return this.range},oe.prototype.parseRange=function(e){var t=this.options.loose;e=e.trim();var n=t?i[F]:i[B];e=e.replace(n,ae),r("hyphen replace",e),e=e.replace(i[M],"$1$2$3"),r("comparator trim",e,i[M]),e=(e=(e=e.replace(i[P],"$1~")).replace(i[q],"$1^")).split(/\s+/).join(" ");var o=t?i[L]:i[V],s=e.split(" ").map((function(e){return function(e,t){return r("comp",e,t),e=function(e,t){return e.trim().split(/\s+/).map((function(e){return function(e,t){r("caret",e,t);var n=t.loose?i[U]:i[N];return e.replace(n,(function(t,n,i,o,s){var a;return r("caret",e,t,n,i,o,s),se(n)?a="":se(i)?a=">="+n+".0.0 <"+(+n+1)+".0.0":se(o)?a="0"===n?">="+n+"."+i+".0 <"+n+"."+(+i+1)+".0":">="+n+"."+i+".0 <"+(+n+1)+".0.0":s?(r("replaceCaret pr",s),a="0"===n?"0"===i?">="+n+"."+i+"."+o+"-"+s+" <"+n+"."+i+"."+(+o+1):">="+n+"."+i+"."+o+"-"+s+" <"+n+"."+(+i+1)+".0":">="+n+"."+i+"."+o+"-"+s+" <"+(+n+1)+".0.0"):(r("no pr"),a="0"===n?"0"===i?">="+n+"."+i+"."+o+" <"+n+"."+i+"."+(+o+1):">="+n+"."+i+"."+o+" <"+n+"."+(+i+1)+".0":">="+n+"."+i+"."+o+" <"+(+n+1)+".0.0"),r("caret return",a),a}))}(e,t)})).join(" ")}(e,t),r("caret",e),e=function(e,t){return e.trim().split(/\s+/).map((function(e){return function(e,t){var n=t.loose?i[j]:i[R];return e.replace(n,(function(t,n,i,o,s){var a;return r("tilde",e,t,n,i,o,s),se(n)?a="":se(i)?a=">="+n+".0.0 <"+(+n+1)+".0.0":se(o)?a=">="+n+"."+i+".0 <"+n+"."+(+i+1)+".0":s?(r("replaceTilde pr",s),a=">="+n+"."+i+"."+o+"-"+s+" <"+n+"."+(+i+1)+".0"):a=">="+n+"."+i+"."+o+" <"+n+"."+(+i+1)+".0",r("tilde return",a),a}))}(e,t)})).join(" ")}(e,t),r("tildes",e),e=function(e,t){return r("replaceXRanges",e,t),e.split(/\s+/).map((function(e){return function(e,t){e=e.trim();var n=t.loose?i[x]:i[S];return e.replace(n,(function(t,n,i,o,s,a){r("xRange",e,t,n,i,o,s,a);var c=se(i),u=c||se(o),d=u||se(s);return"="===n&&d&&(n=""),c?t=">"===n||"<"===n?"<0.0.0":"*":n&&d?(u&&(o=0),s=0,">"===n?(n=">=",u?(i=+i+1,o=0,s=0):(o=+o+1,s=0)):"<="===n&&(n="<",u?i=+i+1:o=+o+1),t=n+i+"."+o+"."+s):u?t=">="+i+".0.0 <"+(+i+1)+".0.0":d&&(t=">="+i+"."+o+".0 <"+i+"."+(+o+1)+".0"),r("xRange return",t),t}))}(e,t)})).join(" ")}(e,t),r("xrange",e),e=function(e,t){return r("replaceStars",e,t),e.trim().replace(i[$],"")}(e,t),r("stars",e),e}(e,this.options)}),this).join(" ").split(/\s+/);return this.options.loose&&(s=s.filter((function(e){return!!e.match(o)}))),s=s.map((function(e){return new ne(e,this.options)}),this)},oe.prototype.intersects=function(e,t){if(!(e instanceof oe))throw new TypeError("a Range is required");return this.set.some((function(r){return r.every((function(r){return e.set.some((function(e){return e.every((function(e){return r.intersects(e,t)}))}))}))}))},t.toComparators=function(e,t){return new oe(e,t).set.map((function(e){return e.map((function(e){return e.value})).join(" ").trim().split(" ")}))},oe.prototype.test=function(e){if(!e)return!1;"string"==typeof e&&(e=new G(e,this.options));for(var t=0;t":0===t.prerelease.length?t.patch++:t.prerelease.push(0),t.raw=t.format();case"":case">=":r&&!z(r,t)||(r=t);break;case"<":case"<=":break;default:throw new Error("Unexpected operation: "+e.operator)}}))}if(r&&e.test(r))return r;return null},t.validRange=function(e,t){try{return new oe(e,t).range||"*"}catch(e){return null}},t.ltr=function(e,t,r){return de(e,t,"<",r)},t.gtr=function(e,t,r){return de(e,t,">",r)},t.outside=de,t.prerelease=function(e,t){var r=K(e,t);return r&&r.prerelease.length?r.prerelease:null},t.intersects=function(e,t,r){return e=new oe(e,r),t=new oe(t,r),e.intersects(t)},t.coerce=function(e){if(e instanceof G)return e;if("string"!=typeof e)return null;var t=e.match(i[k]);if(null==t)return null;return K(t[1]+"."+(t[2]||"0")+"."+(t[3]||"0"))}})),vt=(wt.SEMVER_SPEC_VERSION,wt.re,wt.src,wt.parse,wt.valid,wt.clean,wt.SemVer,wt.inc,wt.diff,wt.compareIdentifiers,wt.rcompareIdentifiers,wt.major,wt.minor,wt.patch,wt.compare,wt.compareLoose,wt.rcompare,wt.sort,wt.rsort,wt.gt,wt.lt,wt.eq,wt.neq,wt.gte,wt.lte,wt.cmp,wt.Comparator,wt.Range,wt.toComparators,wt.satisfies,wt.maxSatisfying,wt.minSatisfying,wt.minVersion,wt.validRange,wt.ltr,wt.gtr,wt.outside,wt.prerelease,wt.intersects,wt.coerce,wt.satisfies(process.version,"^6.12.0 || >=8.0.0")),_t=["RS256","RS384","RS512","ES256","ES384","ES512"],bt=["RS256","RS384","RS512"],Tt=["HS256","HS384","HS512"];vt&&(_t.splice(3,0,"PS256","PS384","PS512"),bt.splice(3,0,"PS256","PS384","PS512"));var Et=/^\s+|\s+$/g,Ct=/^[-+]0x[0-9a-f]+$/i,At=/^0b[01]+$/i,It=/^0o[0-7]+$/i,St=/^(?:0|[1-9]\d*)$/,xt=parseInt;function kt(e){return e!=e}function Ot(e,t){return function(e,t){for(var r=-1,n=e?e.length:0,i=Array(n);++r-1&&e%1==0&&e-1&&e%1==0&&e<=9007199254740991}(e.length)&&!function(e){var t=Ht(e)?qt.call(e):"";return"[object Function]"==t||"[object GeneratorFunction]"==t}(e)}function Ht(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function Kt(e){return!!e&&"object"==typeof e}var Gt=function(e,t,r,n){var i;e=$t(e)?e:(i=e)?Ot(i,function(e){return $t(e)?Vt(e):Mt(e)}(i)):[],r=r&&!n?function(e){var t=function(e){if(!e)return 0===e?e:0;if((e=function(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||Kt(e)&&"[object Symbol]"==qt.call(e)}(e))return NaN;if(Ht(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=Ht(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(Et,"");var r=At.test(e);return r||It.test(e)?xt(e.slice(2),r?2:8):Ct.test(e)?NaN:+e}(e))===1/0||e===-1/0){return 17976931348623157e292*(e<0?-1:1)}return e==e?e:0}(e),r=t%1;return t==t?r?t-r:t:0}(r):0;var o=e.length;return r<0&&(r=Lt(o+r,0)),function(e){return"string"==typeof e||!Ft(e)&&Kt(e)&&"[object String]"==qt.call(e)}(e)?r<=o&&e.indexOf(t,r)>-1:!!o&&function(e,t,r){if(t!=t)return function(e,t,r,n){for(var i=e.length,o=r+(n?1:-1);n?o--:++o-1},Qt=Object.prototype.toString;var Xt=function(e){return!0===e||!1===e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Boolean]"==Qt.call(e)},Yt=/^\s+|\s+$/g,zt=/^[-+]0x[0-9a-f]+$/i,Wt=/^0b[01]+$/i,Jt=/^0o[0-7]+$/i,Zt=parseInt,er=Object.prototype.toString;function tr(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}var rr=function(e){return"number"==typeof e&&e==function(e){var t=function(e){if(!e)return 0===e?e:0;if((e=function(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==er.call(e)}(e))return NaN;if(tr(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=tr(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(Yt,"");var r=Wt.test(e);return r||Jt.test(e)?Zt(e.slice(2),r?2:8):zt.test(e)?NaN:+e}(e))===1/0||e===-1/0){return 17976931348623157e292*(e<0?-1:1)}return e==e?e:0}(e),r=t%1;return t==t?r?t-r:t:0}(e)},nr=Object.prototype.toString;var ir=function(e){return"number"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Number]"==nr.call(e)};var or=Function.prototype,sr=Object.prototype,ar=or.toString,cr=sr.hasOwnProperty,ur=ar.call(Object),dr=sr.toString,pr=function(e,t){return function(r){return e(t(r))}}(Object.getPrototypeOf,Object);var lr=function(e){if(!function(e){return!!e&&"object"==typeof e}(e)||"[object Object]"!=dr.call(e)||function(e){var t=!1;if(null!=e&&"function"!=typeof e.toString)try{t=!!(e+"")}catch(e){}return t}(e))return!1;var t=pr(e);if(null===t)return!0;var r=cr.call(t,"constructor")&&t.constructor;return"function"==typeof r&&r instanceof r&&ar.call(r)==ur},fr=Object.prototype.toString,mr=Array.isArray;var hr=function(e){return"string"==typeof e||!mr(e)&&function(e){return!!e&&"object"==typeof e}(e)&&"[object String]"==fr.call(e)},gr=/^\s+|\s+$/g,yr=/^[-+]0x[0-9a-f]+$/i,wr=/^0b[01]+$/i,vr=/^0o[0-7]+$/i,_r=parseInt,br=Object.prototype.toString;function Tr(e,t){var r;if("function"!=typeof t)throw new TypeError("Expected a function");return e=function(e){var t=function(e){if(!e)return 0===e?e:0;if((e=function(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==br.call(e)}(e))return NaN;if(Er(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=Er(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(gr,"");var r=wr.test(e);return r||vr.test(e)?_r(e.slice(2),r?2:8):yr.test(e)?NaN:+e}(e))===1/0||e===-1/0){return 17976931348623157e292*(e<0?-1:1)}return e==e?e:0}(e),r=t%1;return t==t?r?t-r:t:0}(e),function(){return--e>0&&(r=t.apply(this,arguments)),e<=1&&(t=void 0),r}}function Er(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}var Cr=function(e){return Tr(2,e)},Ar=["RS256","RS384","RS512","ES256","ES384","ES512","HS256","HS384","HS512","none"];vt&&Ar.splice(3,0,"PS256","PS384","PS512");var Ir={expiresIn:{isValid:function(e){return rr(e)||hr(e)&&e},message:'"expiresIn" should be a number of seconds or string representing a timespan'},notBefore:{isValid:function(e){return rr(e)||hr(e)&&e},message:'"notBefore" should be a number of seconds or string representing a timespan'},audience:{isValid:function(e){return hr(e)||Array.isArray(e)},message:'"audience" must be a string or array'},algorithm:{isValid:Gt.bind(null,Ar),message:'"algorithm" must be a valid string enum value'},header:{isValid:lr,message:'"header" must be an object'},encoding:{isValid:hr,message:'"encoding" must be a string'},issuer:{isValid:hr,message:'"issuer" must be a string'},subject:{isValid:hr,message:'"subject" must be a string'},jwtid:{isValid:hr,message:'"jwtid" must be a string'},noTimestamp:{isValid:Xt,message:'"noTimestamp" must be a boolean'},keyid:{isValid:hr,message:'"keyid" must be a string'},mutatePayload:{isValid:Xt,message:'"mutatePayload" must be a boolean'}},Sr={iat:{isValid:ir,message:'"iat" should be a number of seconds'},exp:{isValid:ir,message:'"exp" should be a number of seconds'},nbf:{isValid:ir,message:'"nbf" should be a number of seconds'}};function xr(e,t,r,n){if(!lr(r))throw new Error('Expected "'+n+'" to be a plain object.');Object.keys(r).forEach((function(i){var o=e[i];if(o){if(!o.isValid(r[i]))throw new Error(o.message)}else if(!t)throw new Error('"'+i+'" is not allowed in "'+n+'"')}))}var kr={audience:"aud",issuer:"iss",subject:"sub",jwtid:"jti"},Or=["expiresIn","notBefore","noTimestamp","audience","issuer","subject","jwtid"],Pr=function(e,t,r,n){var i;if("function"!=typeof r||n||(n=r,r={}),r||(r={}),r=Object.assign({},r),i=n||function(e,t){if(e)throw e;return t},r.clockTimestamp&&"number"!=typeof r.clockTimestamp)return i(new st("clockTimestamp must be a number"));if(void 0!==r.nonce&&("string"!=typeof r.nonce||""===r.nonce.trim()))return i(new st("nonce must be a non-empty string"));var o=r.clockTimestamp||Math.floor(Date.now()/1e3);if(!e)return i(new st("jwt must be provided"));if("string"!=typeof e)return i(new st("jwt must be a string"));var s,a=e.split(".");if(3!==a.length)return i(new st("jwt malformed"));try{s=it(e,{complete:!0})}catch(e){return i(e)}if(!s)return i(new st("invalid token"));var c,u=s.header;if("function"==typeof t){if(!n)return i(new st("verify must be called asynchronous if secret or public key is provided as a callback"));c=t}else c=function(e,r){return r(null,t)};return c(u,(function(t,n){if(t)return i(new st("error in secret or public key callback: "+t.message));var c,d=""!==a[2].trim();if(!d&&n)return i(new st("jwt signature is required"));if(d&&!n)return i(new st("secret or public key must be provided"));if(d||r.algorithms||(r.algorithms=["none"]),r.algorithms||(r.algorithms=~n.toString().indexOf("BEGIN CERTIFICATE")||~n.toString().indexOf("BEGIN PUBLIC KEY")?_t:~n.toString().indexOf("BEGIN RSA PUBLIC KEY")?bt:Tt),!~r.algorithms.indexOf(s.header.alg))return i(new st("invalid algorithm"));try{c=nt.verify(e,s.header.alg,n)}catch(e){return i(e)}if(!c)return i(new st("invalid signature"));var p=s.payload;if(void 0!==p.nbf&&!r.ignoreNotBefore){if("number"!=typeof p.nbf)return i(new st("invalid nbf value"));if(p.nbf>o+(r.clockTolerance||0))return i(new ct("jwt not active",new Date(1e3*p.nbf)))}if(void 0!==p.exp&&!r.ignoreExpiration){if("number"!=typeof p.exp)return i(new st("invalid exp value"));if(o>=p.exp+(r.clockTolerance||0))return i(new dt("jwt expired",new Date(1e3*p.exp)))}if(r.audience){var l=Array.isArray(r.audience)?r.audience:[r.audience];if(!(Array.isArray(p.aud)?p.aud:[p.aud]).some((function(e){return l.some((function(t){return t instanceof RegExp?t.test(e):t===e}))})))return i(new st("jwt audience invalid. expected: "+l.join(" or ")))}if(r.issuer&&("string"==typeof r.issuer&&p.iss!==r.issuer||Array.isArray(r.issuer)&&-1===r.issuer.indexOf(p.iss)))return i(new st("jwt issuer invalid. expected: "+r.issuer));if(r.subject&&p.sub!==r.subject)return i(new st("jwt subject invalid. expected: "+r.subject));if(r.jwtid&&p.jti!==r.jwtid)return i(new st("jwt jwtid invalid. expected: "+r.jwtid));if(r.nonce&&p.nonce!==r.nonce)return i(new st("jwt nonce invalid. expected: "+r.nonce));if(r.maxAge){if("number"!=typeof p.iat)return i(new st("iat required when maxAge is specified"));var f=yt(r.maxAge,p.iat);if(void 0===f)return i(new st('"maxAge" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'));if(o>=f+(r.clockTolerance||0))return i(new dt("maxAge exceeded",new Date(1e3*f)))}if(!0===r.complete){var m=s.signature;return i(null,{header:u,payload:p,signature:m})}return i(null,p)}))},Rr=function(e,t,r,n){"function"==typeof r?(n=r,r={}):r=r||{};var i="object"==typeof e&&!Buffer.isBuffer(e),o=Object.assign({alg:r.algorithm||"HS256",typ:i?"JWT":void 0,kid:r.keyid},r.header);function s(e){if(n)return n(e);throw e}if(!t&&"none"!==r.algorithm)return s(new Error("secretOrPrivateKey must have a value"));if(void 0===e)return s(new Error("payload is required"));if(i){try{!function(e){xr(Sr,!0,e,"payload")}(e)}catch(e){return s(e)}r.mutatePayload||(e=Object.assign({},e))}else{var a=Or.filter((function(e){return void 0!==r[e]}));if(a.length>0)return s(new Error("invalid "+a.join(",")+" option for "+typeof e+" payload"))}if(void 0!==e.exp&&void 0!==r.expiresIn)return s(new Error('Bad "options.expiresIn" option the payload already has an "exp" property.'));if(void 0!==e.nbf&&void 0!==r.notBefore)return s(new Error('Bad "options.notBefore" option the payload already has an "nbf" property.'));try{!function(e){xr(Ir,!1,e,"options")}(r)}catch(e){return s(e)}var c=e.iat||Math.floor(Date.now()/1e3);if(r.noTimestamp?delete e.iat:i&&(e.iat=c),void 0!==r.notBefore){try{e.nbf=yt(r.notBefore,c)}catch(e){return s(e)}if(void 0===e.nbf)return s(new Error('"notBefore" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'))}if(void 0!==r.expiresIn&&"object"==typeof e){try{e.exp=yt(r.expiresIn,c)}catch(e){return s(e)}if(void 0===e.exp)return s(new Error('"expiresIn" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'))}Object.keys(kr).forEach((function(t){var n=kr[t];if(void 0!==r[t]){if(void 0!==e[n])return s(new Error('Bad "options.'+t+'" option. The payload already has an "'+n+'" property.'));e[n]=r[t]}}));var u=r.encoding||"utf8";if("function"!=typeof n)return nt.sign({header:o,payload:e,secret:t,encoding:u});n=n&&Cr(n),nt.createSign({header:o,privateKey:t,payload:e,encoding:u}).once("error",n).once("done",(function(e){n(null,e)}))};let jr=[];class Dr{constructor(e){this.options=Object.assign({baseUrl:"https://appleid.apple.com",timeout:1e4},e)}async _fetch(e,t){const{baseUrl:r}=this.options;return uniCloud.httpclient.request(r+e,t)}async verifyIdentityToken(e){const t=e.split(".")[0],{kid:r}=JSON.parse(Buffer.from(t,"base64").toString());if(!jr.length)try{jr=await this.getAuthKeys()}catch(e){return{code:10705,msg:e.message}}const n=this.getUsedKey(jr,r);if(!Object.keys(n).length&&!this.fetched)try{jr=await this.getAuthKeys()}catch(e){return{code:10705,msg:e.message}}let i=null;try{i=Pr(e,function(e,t){var r=Buffer.from(e,"base64"),n=Buffer.from(t,"base64"),i=r.toString("hex"),o=n.toString("hex");i=J(i),o=J(o);var s=i.length/2,a=o.length/2,c=ee(s),u=ee(a),d="30"+ee(s+a+c.length/2+u.length/2+2)+"02"+c+i+"02"+u+o;return"-----BEGIN RSA PUBLIC KEY-----\n"+Buffer.from(d,"hex").toString("base64").match(/.{1,64}/g).join("\n")+"\n-----END RSA PUBLIC KEY-----\n"}(n.n,n.e),{algorithms:n.alg})}catch(e){return{code:10705,msg:e.message}}return{code:0,msg:i}}async getAuthKeys(){const{status:e,data:t}=await this._fetch("/auth/keys",{method:"GET",dataType:"json",timeout:this.options.timeout});if(200!==e)throw new Error("request https://appleid.apple.com/auth/keys fail");return t.keys}getUsedKey(e,t){let r={};for(let n=0;nvoid 0===e))return{code:N,messageValues:{param:this.t("dcloud-appid")}};const r=await P.doc(e).get(),n=r&&r.data&&r.data[0];if(!n)return{code:10002};const i=Object.keys(q).reduce((e,t)=>{const r=t,i=function(e,t){return t.split(".").reduce((e,t)=>e&&e[t],e)}(n,t);return i&&e.push({[r]:i}),e},[]);let o;const s={dcloud_appid:Mr.in(t),_id:Mr.neq(n._id)},a={dcloud_appid:Mr.exists(!1),_id:Mr.neq(n._id)};switch(i.length){case 0:return{code:10004};case 1:o=Mr.or([Mr.and([i[0],s]),Mr.and([i[0],a])]);break;default:o=Mr.or([Mr.and([Mr.or(i),s]),Mr.and([Mr.or(i),a])])}const c=await P.where(o).limit(1).get();return c&&c.data&&c.data[0]?{code:10005}:{code:0}}const Fr=uniCloud.database().command;const $r=uniCloud.database();const Hr=uniCloud.database();const Kr=uniCloud.database();async function Gr(e){const t=["apiKey","apiSecret"];for(let r=0,n=t.length;r0){u=a.and(a.or(c),a.or({dcloud_appid:a.in(s)},{dcloud_appid:a.exists(!1)}));if((await P.where(u).limit(1).get()).data.length>0)return{code:10201,messageValues:{type:this.t("username")}}}const d={role:o,nickname:t,dcloud_appid:s,register_date:Date.now()};if(e&&(d.username=e),r){const{passwordHash:e,version:t}=this.encryptPwd(r);d.password=e,t&&(d.password_secret_version=t)}return n&&(d.mobile=n,d.mobile_confirmed=1),i&&(d.email=i,d.email_confirmed=1),{code:0,uid:(await P.add(d)).id}},getUserInfo:async function({uid:e,field:t}){if(!e)return{code:N,messageValues:{param:this.t("user-id")}};let r;if(t&&t.length){const n={};for(let e=0;evoid 0===e.dcloud_appid||e.dcloud_appid.includes(this.context.APPID));if(0===i.length)return{code:10002};if(i.length>1)return{code:10005};const o=i[0]._id;return this.resetPwd({uid:o,password:r})},setAvatar:async function(e){return await P.doc(e.uid).update({avatar:e.avatar}),{code:0,msg:""}},updatePwd:async function(e){const t=await P.doc(e.uid).get();if(t&&t.data&&t.data.length>0){if(0===this._checkPwd(t.data[0],e.oldPassword).code){const{passwordHash:r,version:n}=this.encryptPwd(e.newPassword),i={password:r,token:[]};n&&(i.password_secret_version=n);return E("upRes",await P.doc(t.data[0]._id).update(i)),{code:0,msg:""}}return{code:40202}}return{code:40201}},updateUser:async function(e){const t=e.uid;if(!t)return{code:N,messageValues:{param:this.t("user-id")}};delete e.uid;const{username:r,email:n}=e,{usernameToLowerCase:i,emailToLowerCase:o}=this._getConfig();let s=r&&r.trim(),a=n&&n.trim();return s&&(i&&(s=s.toLowerCase()),e.username=s),a&&(o&&(a=a.toLowerCase()),e.email=a),E("update -> upRes",await P.doc(t).update(e)),{code:0,msg:""}},banAccount:async function({uid:e}={}){return $.call(this,{uid:e,status:B})},unbanAccount:async function({uid:e}={}){return $.call(this,{uid:e,status:M})},closeAccount:async function({uid:e}={}){return $.call(this,{uid:e,status:F})},openAccount:async function({uid:e}={}){return $.call(this,{uid:e,status:M})},_getAlipayApi:function(){const e=this.context.PLATFORM,t=this._getConfig();if(!t.oauth||!t.oauth.alipay)throw new Error(this.t("config-param-require",{param:e+".alipay"}));return["appid","privateKey"].forEach(r=>{if(!t.oauth.alipay[r])throw new Error(this.t("config-param-require",{param:`${e}.alipay.${r}`}))}),Ur({...t.oauth.alipay})},_getValidInviteCode:async function({inviteCode:e}){let t,r=10;e?(r=1,t=e):t=Vr();let n=!1;try{for(;r>0&&!n;){r--;if(0===(await P.where({my_invite_code:t}).get()).data.length){n=!0;break}t=Vr()}t=Vr()}catch(e){}return n?{code:0,inviteCode:t}:e?{code:80401}:{code:80402}},_addUser:async function(e,{needPermission:t,autoSetDcloudAppid:r=!0}={}){const n=this._getConfig(),i={...e,dcloud_appid:r?[this.context.APPID]:[],register_date:Date.now()},o=(await P.add(i)).id;let s;if(n.removePermissionAndRoleFromToken)s=await this.createToken({uid:o,needPermission:t});else{const t=e.role||[];let r;r=0===t.length||t.includes("admin")?[]:await this._getPermissionListByRoleList(t),s=await this.createToken({uid:o,role:t,permission:r})}const{token:a,tokenExpired:c}=s;return await P.doc(o).update({token:[a]}),{token:a,tokenExpired:c,uid:o,type:"register",userInfo:Object.assign({},i,{token:[a]})}},_loginExec:async function(e,t={}){if(e.status===B)return{code:10001};if(e.status===F)return{code:10006};const r=this._getConfig();let n=e.token||[];"string"==typeof n&&(n=[n]);const i=this._getExpiredToken(n);let o;if(n=n.filter(e=>-1===i.indexOf(e)),r.removePermissionAndRoleFromToken){const r=t.needPermission;o=await this.createToken({uid:e._id,needPermission:r})}else{const t=e.role||[];let r;r=0===t.length||t.includes("admin")?[]:await this._getPermissionListByRoleList(t),o=await this.createToken({uid:e._id,role:t,permission:r})}const{token:s,tokenExpired:a}=o;n.push(s),e.token=n;const c={last_login_date:Date.now(),last_login_ip:this.context.CLIENTIP,token:n,...t.extraData};await P.doc(e._id).update(c);const u=Object.assign({},e,c);return{code:0,msg:"",token:s,uid:u._id,username:u.username,type:"login",userInfo:u,tokenExpired:a}},_registerExec:async function(e,{needPermission:t,autoSetDcloudAppid:r=!0}={}){const{my_invite_code:n}=e;if(this._getConfig().autoSetInviteCode||n){const t=await this._getValidInviteCode({inviteCode:n});if(t.code)return t;e.my_invite_code=t.inviteCode}const{PLATFORM:i,appId:o,appid:s,APPID:a,uniPlatform:c,appName:u,appVersion:d,appVersionCode:p,channel:l,clientIP:f,CLIENTIP:m,OS:h,osName:g}=this.context;return e.register_env={appid:o||s||a||"",uni_platform:c||i||"",os_name:g||h||"",app_name:u||"",app_version:d||"",app_version_code:p||"",channel:l?l+"":"",client_ip:f||m||""},{code:0,msg:"",...await this._addUser(e,{needPermission:t,autoSetDcloudAppid:r})}},_getWeixinApi:function(){const e=this.context.PLATFORM,t=this._getConfig();if(!t.oauth||!t.oauth.weixin)throw new Error(this.t("config-param-require",{param:e+".weixin"}));return["appid","appsecret"].forEach(r=>{if(!t.oauth.weixin[r])throw new Error(this.t("config-param-require",{param:`${e}.weixin.${r}`}))}),qr({...t.oauth.weixin})},_getQQApi:function(){const e=this.context.PLATFORM,t=this._getConfig();if(!t.oauth||!t.oauth.qq)throw new Error(this.t("config-param-require",{param:e+".qq"}));return["appid","appsecret"].forEach(r=>{if(!t.oauth.qq[r])throw new Error(this.t("config-param-require",{param:`${e}.qq.${r}`}))}),Nr({...t.oauth.qq})},_getMatchedUser:function(e,t){if(0===e.length)return{code:10002};let r;const n={},i={};for(let r=e.length-1;r>=0;r--){const o=e[r];for(let s=0;s0?{code:10003,messageValues:{target:"用户"}}:{code:0,msg:"",userMatched:r,fieldMatched:s,isFallbackValueMatched:!!s&&i[s]}},_getCurrentAppUser:function(e){const t=this.context.APPID;return e.filter(e=>void 0===e.dcloud_appid||null===e.dcloud_appid||e.dcloud_appid.indexOf(t)>-1||e.dcloud_appid.indexOf(null)>-1)},_checkLoginUserList:function(e){if(e&&1!==e.length)return e[0].status===F?{code:10006}:{code:10005}},setAuthorizedAppLogin:async function({uid:e,dcloudAppidList:t}={}){if("array"!==m(t))return{code:U,messageValues:{param:"dcloudAppidList",reason:this.t("type-array-required",{param:this.t("dcloud-appid-list")})}};if(t&&0!==t.length){const r=await Br.bind(this)({uid:e,dcloudAppidList:t});if(r.code)return r}return await P.doc(e).update({dcloud_appid:Mr.set(t)}),{code:0}},authorizeAppLogin:async function({uid:e,dcloudAppid:t}={}){const r=await Br.bind(this)({uid:e,dcloudAppidList:[t]});return r.code?r:(await P.doc(e).update({dcloud_appid:Mr.push(t)}),{code:0})},forbidAppLogin:async function({uid:e,dcloudAppid:t}={}){return e?(await P.doc(e).update({dcloud_appid:Mr.pull(t)}),{code:0}):{code:N,messageValues:{param:this.t("user-id")}}},acceptInvite:async function({uid:e,inviteCode:t}){const r=await P.where({_id:Fr.neq(e),inviter_uid:Fr.not(Fr.all([e])),my_invite_code:t}).get();if(1!==r.data.length)return{code:80501,msg:"邀请码无效"};const n=[r.data[0]._id].concat(r.data[0].inviter_uid||[]),i=await P.doc(e).field({my_invite_code:!0,inviter_uid:!0}).get();if(0===i.data.length)return{code:80502};if(i.data[0].inviter_uid&&i.data[0].inviter_uid.length>0)return{code:80503,msg:"邀请码不可修改"};const o=Date.now();return await P.doc(e).update({inviter_uid:n,invite_time:o}),await P.where({inviter_uid:e}).update({inviter_uid:Fr.push(n)}),{code:0,msg:""}},getInvitedUser:async function({uid:e,level:t=1,limit:r=20,offset:n=0,needTotal:i=!1}){const o={code:0,msg:"",invitedUser:(await P.where({["inviter_uid."+(t-1)]:e}).field({_id:!0,username:!0,mobile:!0,invite_time:!0}).orderBy("invite_time","desc").skip(n).limit(r).get()).data};if(i){const r=await P.where({["inviter_uid."+(t-1)]:e}).count();o.total=r.total}return o},setUserInviteCode:async function({uid:e,myInviteCode:t}){const r=await this._getValidInviteCode({inviteCode:t});return r.code?r:(await P.doc(e).update({my_invite_code:r.inviteCode}),{code:0,msg:"",myInviteCode:r.inviteCode})},loginByAlipay:async function(e){"string"==typeof e&&(e={code:e});const{needPermission:t,code:r,myInviteCode:n,role:i,type:o}=e,{openid:s}=await this._getAlipayApi().code2Session(r);if(!s)return{code:10501,messageValues:{account:this.t("alipay-account")}};let a=await P.where({ali_openid:s}).get();if(a=this._getCurrentAppUser(a.data),a&&a.length>0){if("register"===o)return{code:10502,messageValues:{type:this.t("alipay-account")}};if(1!==a.length)return{code:10005};const e=a[0],r=await this._loginExec(e,{needPermission:t});if(0!==r.code)return r;const{userInfo:n}=r;return{...r,openid:s,mobileConfirmed:1===n.mobile_confirmed,emailConfirmed:1===n.email_confirmed}}{if("login"===o)return{code:10503,messageValues:{type:this.t("alipay-account")}};const e={ali_openid:s};e.my_invite_code=n,e.role=i;const r=await this._registerExec(e,{needPermission:t});return 0!==r.code?r:{...r,openid:s,mobileConfirmed:!1,emailConfirmed:!1}}},loginByEmail:async function(e){let{email:t,code:r,password:n,myInviteCode:i,type:o,needPermission:s,role:a}=e||{};if(t=t&&t.trim(),!t)return{code:N,messageValues:{param:"邮箱"}};const{emailToLowerCase:c}=this._getConfig();let u=t;c&&(u=t.toLowerCase());const d=await this.verifyCode({email:u,code:r,type:o||"login"});if(0!==d.code)return d;let p={email:t,email_confirmed:1};const l={field:"email",value:t},f=$r.command;u!==t&&(p=f.or(p,{email:u,email_confirmed:1}),l.fallbackValue=u);let m=await P.where(p).get();if(m=this._getCurrentAppUser(m.data),m&&m.length>0){if("register"===o)return{code:10301,messageValues:{type:"邮箱"}};const e=this._getMatchedUser(m,[l]);if(e.code)return e;const{userMatched:t}=e,r=await this._loginExec(t,{needPermission:s});return 0!==r.code?r:{...r,email:u}}{if("login"===o)return{code:10302,messageValues:{type:"邮箱"}};const e={email:u,email_confirmed:1},t=n&&n.trim();if(t){const{passwordHash:r,version:n}=this.encryptPwd(t);e.password=r,n&&(e.password_secret_version=n)}e.my_invite_code=i,e.role=a;const r=await this._registerExec(e,{needPermission:s});return 0!==r.code?r:{...r,email:u}}},loginBySms:async function({mobile:e,code:t,password:r,inviteCode:n,myInviteCode:i,type:o,needPermission:s,role:a}){if(!(e=e&&e.trim()))return{code:N,messageValues:{param:this.t("mobile")}};const c=this._getConfig();if(c.forceInviteCode&&!o)throw new Error(this.t("login-with-invite-type-required"));const u=await this.verifyCode({mobile:e,code:t,type:o||"login"});if(0!==u.code)return u;const d={mobile:e,mobile_confirmed:1};let p=await P.where(d).get();if(p=this._getCurrentAppUser(p.data),p&&p.length>0){if("register"===o)return{code:10201,messageValues:{type:this.t("mobile")}};if(1!==p.length)return{code:10005};const t=p[0],r=await this._loginExec(t,{needPermission:s});return 0!==r.code?r:{...r,mobile:e}}{const t=Date.now();if("login"===o)return{code:10202,messageValues:{type:this.t("mobile")}};const u={mobile:e,mobile_confirmed:1,register_ip:this.context.CLIENTIP,register_date:t},d=r&&r.trim();if(d){const{passwordHash:e,version:t}=this.encryptPwd(d);u.password=e,t&&(u.password_secret_version=t)}if(n){const e=await P.where({my_invite_code:n}).get();if(1!==e.data.length)return{code:10203};u.inviter_uid=[e.data[0]._id].concat(e.data[0].inviter_uid||[]),u.invite_time=t}else if(c.forceInviteCode)return{code:10203};u.my_invite_code=i,u.role=a;const p=await this._registerExec(u,{needPermission:s});return 0!==p.code?p:{...p,mobile:e}}},loginByWeixin:async function(e){"string"==typeof e&&(e={code:e});const{needPermission:t,platform:r,code:n,myInviteCode:i,role:o,type:s}=e,a=r||this.context.PLATFORM,c="mp-weixin"===a,{openid:u,unionid:d,sessionKey:p,accessToken:l,refreshToken:f,expired:m}=await this._getWeixinApi()[c?"code2Session":"getOauthAccessToken"](n);if(!u)return{code:10401,messageValues:{account:"微信openid"}};let h;h=c?{sessionKey:p}:{accessToken:l,refreshToken:f,accessTokenExpired:m};const g=Hr.command,y=[{wx_openid:{[a]:u}}];d&&y.push({wx_unionid:d});let w=await P.where(g.or(...y)).get();if(w=this._getCurrentAppUser(w.data),w&&w.length>0){if("register"===s)return{code:10402,messageValues:{type:this.t("wechat-account")}};if(1!==w.length)return{code:10005};const e=w[0],r={wx_openid:{[a]:u}};d&&(r.wx_unionid=d);const n=await this._loginExec(e,{needPermission:t,extraData:r});if(0!==n.code)return n;const{userInfo:i}=n;return{...n,openid:u,unionid:d,...h,mobileConfirmed:1===i.mobile_confirmed,emailConfirmed:1===i.email_confirmed}}{if("login"===s)return{code:10403,messageValues:{type:this.t("wechat-account")}};const e={wx_openid:{[a]:u},wx_unionid:d};e.my_invite_code=i,e.role=o;const r=await this._registerExec(e,{needPermission:t});return 0!==r.code?r:{...r,openid:u,unionid:d,...h,mobileConfirmed:!1,emailConfirmed:!1}}},loginByQQ:async function({code:e,accessToken:t,myInviteCode:r,needPermission:n,role:i,type:o}={}){const s=this.context.PLATFORM,a="mp-qq"===s,{openid:c,unionid:u,sessionKey:d}=await this._getQQApi()[a?"code2Session":"getOpenidByToken"]({code:e,accessToken:t});if(!c)return{code:10801,messageValues:{account:"qq openid"}};const p={accessToken:t,sessionKey:d},l=Kr.command,f=[{qq_openid:{[s]:c}}];u&&f.push({qq_unionid:u});let m=await P.where(l.or(...f)).get();if(m=this._getCurrentAppUser(m.data),m&&m.length>0){if("register"===o)return{code:10802,messageValues:{type:this.t("qq-account")}};if(1!==m.length)return{code:10005};const e=m[0],t={qq_openid:{[s]:c}};u&&(t.qq_unionid=u);const r=await this._loginExec(e,{needPermission:n,extraData:t});if(0!==r.code)return r;const{userInfo:i}=r;return{...r,openid:c,unionid:u,...p,mobileConfirmed:1===i.mobile_confirmed,emailConfirmed:1===i.email_confirmed}}{if("login"===o)return{code:10803,messageValues:{type:this.t("qq-account")}};const e={qq_openid:{[s]:c},qq_unionid:u};e.my_invite_code=r,e.role=i;const t=await this._registerExec(e);return 0!==t.code?t:{...t,openid:c,unionid:u,...p,mobileConfirmed:!1,emailConfirmed:!1}}},loginByUniverify:async function({openid:e,access_token:t,password:r,inviteCode:n,myInviteCode:i,type:o,needPermission:s,role:a}){const c=this._getConfig(),u=c&&c.service&&c.service.univerify;if(!u)throw new Error(this.t("uni-verify-config-required"));if(c.forceInviteCode&&!o)throw new Error(this.t("login-with-invite-type-required"));const d=await Gr.bind(this)({...u,openid:e,access_token:t});if(0!==d.code)return d;const p=String(d.phoneNumber);let l=await P.where({mobile:p,mobile_confirmed:1}).get();if(l=this._getCurrentAppUser(l.data),l&&l.length>0){if("register"===o)return{code:10601,messageValues:{type:this.t("mobile")}};if(1!==l.length)return{code:10005};const e=l[0],t=await this._loginExec(e,{needPermission:s});return 0!==t.code?t:{...t,mobile:p}}if("login"===o)return{code:10602,messageValues:{type:this.t("mobile")}};const f=Date.now(),m={mobile:p,my_invite_code:i,mobile_confirmed:1,role:a},h=r&&r.trim();if(h){const{passwordHash:e,version:t}=this.encryptPwd(h);m.password=e,t&&(m.password_secret_version=t)}if(n){let e=await P.where({my_invite_code:n}).get();if(1!==e.data.length)return{code:10203};e=e.data[0],m.inviter_uid=[e._id].concat(e.inviter_uid||[]),m.invite_time=f}else if(c.forceInviteCode)return{code:10203};m.my_invite_code=i;const g=await this._registerExec(m,{needPermission:s});return 0!==g.code?g:{...g,mobile:p}},loginByApple:async function({nickName:e,fullName:t,identityToken:r,myInviteCode:n,type:i,needPermission:o,role:s}){const a=this._getConfig(),c=a&&a.oauth&&a.oauth.apple,u=c&&c.bundleId;if(!u)throw new Error(this.t("config-param-require",{param:"(app || app-plus).apple.bundleId"}));if(!r)return{code:N,messageValues:{param:"identityToken"}};t=e||(t&&Object.keys(t).length>0?t.familyName+t.givenName:"");const{code:d,msg:p}=await Lr().verifyIdentityToken(r);if(0!==d)return{code:d,msg:p,messageValues:{account:this.t("apple-account")}};const{iss:l,sub:f,aud:m,email:h}=p;if("https://appleid.apple.com"!==l)return{code:10706,messageValues:{account:this.t("apple-account")}};if(!f)return{code:10701,messageValues:{account:this.t("apple-account")}};if(u!==m)return{code:10702,messageValues:{account:this.t("apple-account")}};const g=t||"User-"+(h?h.split("@")[0]:Math.random().toString(32).slice(2));let y=await P.where({apple_openid:f}).get();if(y=this._getCurrentAppUser(y.data),y&&y.length>0){if("register"===i)return{code:10703,messageValues:{type:this.t("apple-account")}};if(1!==y.length)return{code:10005};const e=y[0],t=await this._loginExec(e,{needPermission:o});return 0!==t.code?t:{...t,openid:f}}if("login"===i)return{code:10704,messageValues:{type:this.t("apple-account")}};const w={nickname:g,apple_openid:f,my_invite_code:n,role:s},v=await this._registerExec(w,{needPermission:o});return 0!==v.code?v:{...v,openid:f}},login:async function({username:e,password:t,queryField:r=[],needPermission:n}){const i=Qr.command,o=[];r&&r.length||(r=["username"]),r.length>1&&console.warn(this.t("query-field-warning"));const{usernameToLowerCase:s,emailToLowerCase:a,passwordErrorLimit:c,passwordErrorRetryTime:u}=this._getConfig(),d={email:{email_confirmed:1},mobile:{mobile_confirmed:1}},p={},l=e&&e.trim();if(!l)return{code:N,messageValues:{param:this.t("username")}};s&&(p.username=l.toLowerCase()),a&&(p.email=l.toLowerCase());const f=[];r.forEach(t=>{o.push({[t]:e,...d[t]});const r={field:t,value:e};"username"===t&&p.username!==e?(o.push({[t]:p.username,...d[t]}),r.fallbackValue=p.username):"email"===t&&p.email!==e&&(o.push({[t]:p.email,...d[t]}),r.fallbackValue=p.email),f.push(r)});let m=await P.where(i.or(...o)).get();m=this._getCurrentAppUser(m.data);const h=this.context.CLIENTIP,g=this._getMatchedUser(m,f);if(g.code)return g;const{userMatched:y}=g;let w=y.login_ip_limit||[];w=w.filter(e=>e.last_error_time>Date.now()-1e3*u);let v=w.find(e=>e.ip===h);if(v&&v.error_times>=c)return{code:10103};const _=t&&t.trim();if(!_)return{code:N,messageValues:{param:"密码"}};const b=this._checkPwd(y,_);if(0===b.code){const e=w.indexOf(v);e>-1&&w.splice(e,1);const t={login_ip_limit:w},{passwordHash:r,passwordVersion:i}=b;r&&i&&(t.password=r,t.password_secret_version=i);const o=await this._loginExec(y,{needPermission:n,extraData:t});return o.code,o}return v?(v.error_times++,v.last_error_time=Date.now()):(v={ip:h,error_times:1,last_error_time:Date.now()},w.push(v)),await P.doc(y._id).update({login_ip_limit:w}),{code:10102,msg:"密码错误"}},register:async function(e){const t=[],r=[{name:"username",desc:this.t("username")},{name:"email",desc:this.t("email"),extraCond:{email_confirmed:1}},{name:"mobile",desc:this.t("mobile"),extraCond:{mobile_confirmed:1}}],{usernameToLowerCase:n,emailToLowerCase:i}=this._getConfig();r.forEach(r=>{const o=r.name;let s=e[o]&&e[o].trim();s?(("username"===r.name&&n||"email"===r.name&&i)&&(s=s.toLowerCase()),e[o]=s,t.push({[o]:s,...r.extraCond})):delete e[o]});const{username:o,email:s,mobile:a,myInviteCode:c,needPermission:u,autoSetDcloudAppid:d=!0}=e;if("needPermission"in e&&delete e.needPermission,"autoSetDcloudAppid"in e&&delete e.autoSetDcloudAppid,0===t.length)return{code:20101,messageValues:{param:this.t("user-unique-param")}};const p=Xr.command;let l=await P.where(p.or(...t)).get();if(l=this._getCurrentAppUser(l.data),l&&l.length>0){const t=l[0];if(t.status===F)return{code:10006};for(let n=0;nt[e]===i.extraCond[e])),t[i.name]===e[i.name]&&o)return{code:20102,messageValues:{type:i.desc}}}}const f=e.password&&e.password.trim();if(!f)return{code:N,messageValues:{param:this.t("password")}};const{passwordHash:m,version:h}=this.encryptPwd(f);e.password=m,h&&(e.password_secret_version=h),e.my_invite_code=c,delete e.myInviteCode;const g=await this._registerExec(e,{needPermission:u,autoSetDcloudAppid:d});return 0!==g.code?g:{...g,username:o,email:s,mobile:a}},logout:async function(e){const t=await this.checkToken(e);if(t.code)return t;const r=Yr.command;return await P.doc(t.uid).update({token:r.pull(e)}),{code:0,msg:""}},getRoleByUid:async function({uid:e}){if(!e)return{code:N,messageValues:{param:this.t("user-id")}};const t=await P.doc(e).get();return 0===t.data.length?{code:L}:{code:0,msg:"",role:t.data[0].role||[]}},getPermissionByRole:async function({roleID:e}){if(!e)return{code:N,messageValues:{param:"roleID"}};if("admin"===e){return{code:0,msg:"",permission:(await D.limit(1e3).get()).data.map(e=>e.permission_id)}}const t=await j.where({role_id:e}).get();return 0===t.data.length?{code:V}:{code:0,msg:"",permission:t.data[0].permission||[]}},getPermissionByUid:async function({uid:e}={}){const t=await P.aggregate().match({_id:e}).project({role:!0}).unwind("$role").lookup({from:"uni-id-roles",localField:"role",foreignField:"role_id",as:"roleDetail"}).unwind("$roleDetail").replaceRoot({newRoot:"$roleDetail"}).end(),r=[],n=[];return t.data.forEach(e=>{n.push(e.role_id),r.push(...e.permission)}),{code:0,msg:"",role:n,permission:A(r)}},bindRole:async function({uid:e,roleList:t,reset:r=!1}){const n={};return"string"==typeof t&&(t=[t]),n.role=r?t:zr.push(t),await P.doc(e).update(n),{code:0,msg:""}},bindPermission:async function({roleID:e,permissionList:t,reset:r=!1}){const n={};return"string"==typeof t&&(t=[t]),n.permission=r?t:zr.push(t),await j.where({role_id:e}).update(n),{code:0,msg:""}},unbindRole:async function({uid:e,roleList:t}){return"string"==typeof t&&(t=[t]),await P.doc(e).update({role:zr.pull(zr.in(t))}),{code:0,msg:""}},unbindPermission:async function({roleID:e,permissionList:t}){return"string"==typeof t&&(t=[t]),await j.where({role_id:e}).update({permission:zr.pull(zr.in(t))}),{code:0,msg:""}},addRole:async function({roleID:e,roleName:t,comment:r,permission:n=[]}){return e?"admin"===e?{code:U,messageValues:{param:"roleID",reason:this.t("add-role-admin-is-not-allowed")}}:(await j.add({role_id:e,role_name:t,comment:r,permission:n,create_date:Date.now()}),{code:0,msg:""}):{code:N,messageValues:{param:this.t("role-id")}}},addPermission:async function({permissionID:e,permissionName:t,comment:r}){return e?(await D.add({permission_id:e,permission_name:t,comment:r,create_date:Date.now()}),{code:0,msg:""}):{code:N,messageValues:{param:this.t("permission-id")}}},getRoleList:async function({limit:e=20,offset:t=0,needTotal:r=!0}){const n={code:0,msg:"",roleList:(await j.skip(t).limit(e).get()).data};if(r){const{total:e}=await j.where({_id:zr.exists(!0)}).count();n.total=e}return n},getRoleInfo:async function(e){const t=await j.where({role_id:e}).get();return 0===t.data.length?{code:V}:{code:0,...t.data[0]}},updateRole:async function({roleID:e,roleName:t,comment:r,permission:n}){return e?(await j.where({role_id:e}).update({role_name:t,comment:r,permission:n}),{code:0,msg:""}):{code:N,messageValues:{param:this.t("role-id")}}},deleteRole:async function({roleID:e}){const t=m(e);if("string"===t)e=[e];else if("array"!==t)throw new Error("typeof roleID must be array or string");return await j.where({role_id:zr.in(e)}).remove(),await P.where({role:zr.elemMatch(zr.in(e))}).update({role:zr.pullAll(e)}),{code:0,msg:""}},getPermissionList:async function({limit:e=20,offset:t=0,needTotal:r=!0}){const n={code:0,msg:"",permissionList:(await D.skip(t).limit(e).get()).data};if(r){const{total:e}=await D.where({_id:zr.exists(!0)}).count();n.total=e}return n},getPermissionInfo:async function(e){const t=await D.where({permission_id:e}).get();return 0===t.data.length?{code:N,messageValues:{param:this.t("permission-id")}}:{code:0,...t.data[0]}},updatePermission:async function({permissionID:e,permissionName:t,comment:r}){return e?(await D.where({permission_id:e}).update({permission_name:t,comment:r}),{code:0,msg:""}):{code:N,messageValues:{param:this.t("permission-id")}}},deletePermission:async function({permissionID:e}){const t=m(e);if("string"===t)e=[e];else if("array"!==t)throw new Error("typeof permissionID must be array or string");return await D.where({permission_id:zr.in(e)}).remove(),await j.where({permission:zr.elemMatch(zr.in(e))}).update({permission:zr.pullAll(e)}),{code:0,msg:""}},bindAlipay:async function({uid:e,code:t,platform:r}){const n=r||this.context.PLATFORM,{openid:i}=await this._getAlipayApi({platform:n}).code2Session(t);if(!i)return{code:60401,messageValues:{account:this.t("alipay-account")}};let o=await P.where({ali_openid:i}).get();return o=this._getCurrentAppUser(o.data),o&&o.length>0?{code:60402,messageValues:{type:this.t("alipay-account")}}:(await P.doc(e).update({ali_openid:i}),{code:0,openid:i,msg:""})},bindEmail:async function(e){let{uid:t,email:r,code:n}=e||{};if(r=r&&r.trim(),!r)return{code:N,messageValues:{param:this.t("email")}};if(!n)return{code:N,messageValues:{param:this.t("verify-code")}};const{emailToLowerCase:i}=this._getConfig();i&&(r=r.toLowerCase());let o=await P.where({email:r,email_confirmed:1}).get();if(o=this._getCurrentAppUser(o.data),o&&o.length>0)return{code:60201,messageValues:{type:this.t("email")}};const s=await this.verifyCode({email:r,code:n,type:"bind"});return 0!==s.code?s:(await P.doc(t).update({email:r,email_confirmed:1}),{code:0,msg:"",email:r})},bindMobile:async function(e){let{uid:t,mobile:r,code:n,openid:i,access_token:o,type:s="sms"}=e||{};if("univerify"===s){const e=this._getConfig(),t=e&&e.service&&e.service.univerify;if(!t)throw new Error("请在config.json中配置service.univerify下一键登录相关参数");const n=await Gr.bind(this)({...t,openid:i,access_token:o});if(0!==n.code)return n;r=""+n.phoneNumber}let a=await P.where({mobile:r,mobile_confirmed:1}).get();if(a=this._getCurrentAppUser(a.data),a&&a.length>0)return{code:60101,messageValues:{type:"手机号"}};if("sms"===s&&"code"in e){if(!r)return{code:N,messageValues:{param:this.t("mobile")}};if(!n)return{code:N,messageValues:{param:this.t("verify-code")}};const e=await this.verifyCode({mobile:r,code:n,type:"bind"});if(0!==e.code)return e}return await P.doc(t).update({mobile:r,mobile_confirmed:1}),{code:0,msg:"",mobile:r}},bindWeixin:async function({uid:e,code:t,platform:r}){const n=r||this.context.PLATFORM,i="mp-weixin"===n,{openid:o,unionid:s,sessionKey:a,accessToken:c,refreshToken:u,expired:d}=await this._getWeixinApi({platform:n})[i?"code2Session":"getOauthAccessToken"](t);if(!o)return{code:60301,messageValues:{account:"微信openid"}};const p=Wr.command,l=[{wx_openid:{[n]:o}}];s&&l.push({wx_unionid:s});let f=await P.where(p.or(...l)).get();if(f=this._getCurrentAppUser(f.data),f&&f.length>0)return{code:60302,messageValues:{type:this.t("wechat-account")}};const m={wx_openid:{[n]:o}};let h;return s&&(m.wx_unionid=s),await P.doc(e).update(m),h=i?{sessionKey:a}:{accessToken:c,refreshToken:u,accessTokenExpired:d},{code:0,msg:"",openid:o,unionid:s,...h}},bindQQ:async function({uid:e,code:t,accessToken:r,platform:n}={}){const i=n||this.context.PLATFORM,o="mp-qq"===i,{openid:s,unionid:a,sessionKey:c}=await this._getQQApi()[o?"code2Session":"getOpenidByToken"]({code:t,accessToken:r});if(!s)return{code:60501,messageValues:{account:"qq openid"}};const u=Jr.command,d=[{qq_openid:{[i]:s}}];a&&d.push({qq_unionid:a});let p=await P.where(u.or(...d)).get();if(p=this._getCurrentAppUser(p.data),p&&p.length>0)return{code:60502,messageValues:{type:this.t("qq-account")}};const l={qq_openid:{[i]:s}};return a&&(l.qq_unionid=a),await P.doc(e).update(l),{code:0,msg:"",openid:s,unionid:a,...{accessToken:r,sessionKey:c}}},unbindAlipay:async function(e){const t=Zr.command,r=await P.doc(e).update({ali_openid:t.remove()});return E("upRes:",r),1===r.updated?{code:0,msg:""}:{code:70401}},unbindEmail:async function(e){let{uid:t,email:r,code:n}=e||{};if(r=r&&r.trim(),!t||!r)return{code:N,messageValues:{param:t?this.t("email"):this.t("user-id")}};const{emailToLowerCase:i}=this._getConfig();if("code"in e){const e=await this.verifyCode({email:r,code:n,type:"unbind"});if(0!==e.code)return e}const o=en.command;let s={_id:t,email:r};if(i){const e=r.toLowerCase();e!==r&&(s=o.or(s,{_id:t,email:e}))}return 1===(await P.where(s).update({email:o.remove(),email_confirmed:o.remove()})).updated?{code:0,msg:""}:{code:70201}},unbindMobile:async function(e){const{uid:t,mobile:r,code:n}=e||{};if("code"in e){const e=await this.verifyCode({mobile:r,code:n,type:"unbind"});if(0!==e.code)return e}const i=tn.command;return 1===(await P.where({_id:t,mobile:r}).update({mobile:i.remove(),mobile_confirmed:i.remove()})).updated?{code:0,msg:""}:{code:70101}},unbindWeixin:async function(e){const t=rn.command,r=await P.doc(e).update({wx_openid:t.remove(),wx_unionid:t.remove()});return E("upRes:",r),1===r.updated?{code:0,msg:""}:{code:70301}},unbindQQ:async function(e){const t=nn.command,r=await P.doc(e).update({qq_openid:t.remove(),qq_unionid:t.remove()});return E("upRes:",r),1===r.updated?{code:0,msg:""}:{code:70501}},getSupportedLoginType:function({appid:e,platform:t}={}){if(!e||!t)throw new Error("Parameter appid and platform is required");const r=this._getConfig({appid:e,platform:t}),n=["username-password","mobile-password","email-password"];for(const e in on)on[e](r)&&n.push(e);return{supportedLoginType:n}},code2SessionAlipay:async function(e){let t=e;"string"==typeof e&&(t={code:e});try{const e=t.platform||this.context.PLATFORM,r=await this._getAlipayApi({platform:e}).code2Session(t.code);return r.openid?{code:0,msg:"",...r}:{code:80701,messageValues:{account:this.t("alipay-account")}}}catch(e){return console.error(e),{code:80702,messageValues:{account:this.t("alipay-account")}}}},code2SessionWeixin:async function(e){let t=e;"string"==typeof e&&(t={code:e});try{const e=t.platform||this.context.PLATFORM,r=await this._getWeixinApi({platform:e})["mp-weixin"===e?"code2Session":"getOauthAccessToken"](t.code);return r.openid?{code:0,msg:"",...r}:{code:80601,messageValues:{account:"微信openid"}}}catch(e){return console.error(e),{code:80602,messageValues:{account:"微信openid"}}}},verifyAppleIdentityToken:async function({identityToken:e,platform:t}){const r=t||this.context.PLATFORM,{code:n,msg:i}=await Lr({clientType:r}).verifyIdentityToken(e);return 0!==n?{code:n,msg:i}:{code:n,msg:"验证通过",...i}},wxBizDataCrypt:async function({code:e,sessionKey:r,encryptedData:n,iv:i}){if(!n)return{code:N,messageValues:{param:"encryptedData"}};if(!i)return{code:N,messageValues:{param:"iv"}};if(!e&&!r)return{code:N,messageValues:{param:"sessionKey"}};const o=this._getWeixinApi();if(!r){const t=await o.code2Session(e);if(!t.sessionKey)return{code:80801};r=t.sessionKey}r=Buffer.from(r,"base64"),n=Buffer.from(n,"base64"),i=Buffer.from(i,"base64");try{var s=t.createDecipheriv("aes-128-cbc",r,i);s.setAutoPadding(!0);var a=s.update(n,"binary","utf8");a+=s.final("utf8"),a=JSON.parse(a)}catch(e){return console.error(e),{code:80802}}return a.watermark.appid!==o.options.appId?{code:80803}:{code:0,msg:"",...a}},getWeixinUserInfo:async function({accessToken:e,openid:t}={}){const r=this.context.PLATFORM;if("app"!==r&&"app-plus"!==r)throw new Error(this.t("limit-client-platform"));try{return{code:0,msg:"",...await this._getWeixinApi().getUserInfo({accessToken:e,openid:t})}}catch(e){return console.error(e),{code:80901}}},encryptPwd:function(e,{value:r,version:n}={}){if(!(e=e&&e.trim()))throw new Error(this.t("param-required",{param:this.t("password")}));if(!r){const e=this._getConfig(),{passwordSecret:t}=e;if("array"===m(t)){const e=t.sort((e,t)=>e.version-t.version);r=e[e.length-1].value,n=e[e.length-1].version}else r=t}if(!r)throw new Error(this.t("param-error",{param:"passwordSecret",reason:"invalid passwordSecret"}));const i=t.createHmac("sha1",r.toString("ascii"));return i.update(e),{passwordHash:i.digest("hex"),version:n}},checkToken:async function(e,{needPermission:t,needUserInfo:r=!0}={}){const n=this._getConfig(),i=this._verifyToken(e);if(i.code)return i;const{uid:o,needPermission:s,role:a,permission:c,exp:u,iat:d,...p}=i,l=a&&c;t=void 0===t?s:t;const f=n.removePermissionAndRoleFromToken||!l||r,m=!n.removePermissionAndRoleFromToken&&!l||n.removePermissionAndRoleFromToken&&l||n.tokenExpiresThreshold&&u-Date.now()/1e3this._createTokenInternal({signContent:e,config:o})):this._createTokenInternal({signContent:a,config:o})},_updateToken:async function({uid:e,tokenList:t,removeToken:r=[],addToken:n=[]}={}){if(!t){const r=await P.doc(e).get(),n=r.data&&r.data[0];t=n&&n.token||[]}"string"==typeof t&&(t=[t]);const i=this._getExpiredToken(t);(t=t.filter(e=>-1===i.indexOf(e))).push(...n);for(let e=0;ee.version-t.version);let c;if(c=n?a.find(e=>e.version===n):a[0],!c)return{code:3};const u=a[a.length-1],{passwordHash:d}=this.encryptPwd(t,c);if(d===r){const e={code:0};if(c!==u){const{passwordHash:r,version:n}=this.encryptPwd(t,u);e.passwordHash=r,e.passwordVersion=n}return e}return{code:4,message:""}},_verifyToken:function(e){const t=this._getConfig();let r;try{r=Pr(e,t.tokenSecret)}catch(e){return"TokenExpiredError"===e.name?{code:30203,err:e}:{code:30204,err:e}}return t.bindTokenToDevice&&r.clientId&&r.clientId!==this._getClientUaHash()?{code:30201}:{code:0,message:"",...r}},_getExpiredToken:function(e){const t=this._getConfig(),r=[];return e.forEach(e=>{try{Pr(e,t.tokenSecret)}catch(t){r.push(e)}}),r},_getPermissionListByRoleList:async function(e){if(!Array.isArray(e))return[];if(0===e.length)return[];if(e.includes("admin")){return(await D.limit(500).get()).data.map(e=>e.permission_id)}const t=await j.where({role_id:sn.in(e)}).get(),r=[];return t.data.forEach(e=>{Array.prototype.push.apply(r,e.permission)}),A(r)},_getClientUaHash:function(){const e=t.createHash("md5"),r=/MicroMessenger/i.test(this.context.CLIENTUA)?this.context.CLIENTUA.replace(/(MicroMessenger\S+).*/i,"$1"):this.context.CLIENTUA;return e.update(r),e.digest("hex")},_createTokenInternal:function({signContent:e,config:t}){if(t.tokenExpiresIn&&t.tokenExpiresThreshold&&t.tokenExpiresIn<=t.tokenExpiresThreshold)throw new Error(this.t("token-expires-config-warning"));return"object"===m(e)&&e.uid?(t.bindTokenToDevice&&(e.clientId=this._getClientUaHash()),{token:Rr(e,t.tokenSecret,{expiresIn:t.tokenExpiresIn}),tokenExpired:Date.now()+1e3*t.tokenExpiresIn}):{code:30101,messageValues:{param:this.t("user-id")}}},setVerifyCode:async function({mobile:e,email:t,code:r,expiresIn:n,type:i}){if(t=t&&t.trim(),e=e&&e.trim(),t){const{emailToLowerCase:e}=this._getConfig();e&&(t=t.toLowerCase())}if(!e&&!t)return{code:50101,messageValues:{param:"手机号或邮箱"}};if(e&&t)return{code:50102,messageValues:{param:"参数",reason:"手机号和邮箱不可同时存在"}};r||(r=C()),n||(n=180);const o=Date.now(),s={mobile:e,email:t,type:i,code:r,state:0,ip:this.context.CLIENTIP,created_at:o,expired_at:o+1e3*n};return await R.add(s),{code:0,mobile:e,email:t}},verifyCode:async function({mobile:e,email:t,code:r,type:n}){if(t=t&&t.trim(),e=e&&e.trim(),t){const{emailToLowerCase:e}=this._getConfig();e&&(t=t.toLowerCase())}if(!e&&!t)return{code:50201,messageValues:{param:"手机号或邮箱"}};if(e&&t)return{code:50203,messageValues:{param:"参数",reason:"手机号和邮箱不可同时存在"}};if(!r)return{code:50202,messageValues:{type:this.t(e?"sms":"email")}};const i=an.command,o=Date.now(),s={mobile:e,email:t,type:n,code:r,state:0,expired_at:i.gt(o)},a=await R.where(s).orderBy("created_at","desc").limit(1).get();if(a&&a.data&&a.data.length>0){const e=a.data[0];return await R.doc(e._id).update({state:1}),{code:0,msg:"验证通过"}}return{code:50202,messageValues:{type:this.t(e?"sms":"email")}}},sendSmsCode:async function({mobile:e,code:t,type:r,templateId:n}){if(!e)return{code:N,messageValues:{param:this.t("mobile")}};if(t||(t=C()),!r)return{code:N,messageValues:{param:this.t("verify-code-type")}};const i=this._getConfig();let o=i&&i.service&&i.service.sms;if(!o)throw new Error(this.t("config-param-required",{param:"service.sms"}));o=Object.assign({codeExpiresIn:300},o);const s=["smsKey","smsSecret"];for(let e=0,t=s.length;e=0?o:{code:0,msg:""}}catch(e){return console.error(e),{code:50301}}}});let un;try{un=require("uni-config-center")}catch(e){throw new Error("Plugin[uni-config-center] was not found")}class dn{constructor({context:e,clientInfo:t,config:r}={}){const n=un({pluginId:"uni-id"});this.pluginConfig=n,this.config=r||this._getConfigContent(),this._configCache={},Object.defineProperty(this,"context",{get(){let r;r=t?{OS:t.os,CLIENTIP:t.clientIP,CLIENTUA:t.userAgent,PLATFORM:t.platform,APPID:t.appId,LOCALE:t.locale,DEVICEID:t.deviceId}:Object.assign({},e||global.__ctx__||{});const n=["CLIENTIP","PLATFORM","APPID","LOCALE"];for(let e=0;ee.dcloudAppid===t)||e.find(e=>e.isDefaultConfig):e}_parseConfigContent(e){return Array.isArray(e)?e:e[0]?Object.values(e):e}_getConfigContent(){if(this.pluginConfig&&this.pluginConfig.hasFile("config.json")){let e;try{e=this.pluginConfig.config()}catch(e){throw new Error("Invalid uni-id config file\n"+e.message)}return this._parseConfigContent(e)}{let e;try{e=require("./config.json")}catch(e){if("MODULE_NOT_FOUND"===e.code||"ENOENT"===e.code)throw new Error("uni-id config file[uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json] not found");throw e}return this._parseConfigContent(e)}}init(){throw new Error("uniID.init has been deprecated, use uniID.createInstance instead")}setInterceptor(e,t){this.interceptorMap.set(e,t)}_getConfig({appid:e,platform:t}={}){const r=`${e=e||this.context.APPID}_${t=t||this.context.PLATFORM}`;if(this._configCache[r])return this._configCache[r];if(!(this.config&&0!==Object.keys(this.config).length))throw new Error(this.t("config-file-not-found"));const n=this._getAppConfig(this.config,e);"app"!==t&&"app-plus"!==t||(t=n.preferedAppPlatform||t),"web"!==t&&"h5"!==t||(t=n.preferedWebPlatform||t);const i=Object.assign(n,n[t])||{},o=Object.assign({bindTokenToDevice:!1,tokenExpiresIn:7200,tokenExpiresThreshold:1200,passwordErrorLimit:6,passwordErrorRetryTime:3600,usernameToLowerCase:!0,emailToLowerCase:!0},i);return["passwordSecret","tokenSecret","tokenExpiresIn","passwordErrorLimit","passwordErrorRetryTime"].forEach(e=>{if(!o||!o[e])throw new Error(this.t("config-param-required",{param:e}))}),this._configCache[r]=o,o}}for(const e in cn)dn.prototype[e]=cn[e];function pn(e){const t=new dn(e);return new Proxy(t,{get(e,t){if(t in e&&0!==t.indexOf("_")){if("function"==typeof e[t])return(r=e[t],function(){const e=r.apply(this,arguments);return f(e)?e.then(e=>(x.bind(this)(e),e)):(x.bind(this)(e),e)}).bind(e);if("context"!==t&&"config"!==t)return e[t]}var r}})}dn.prototype.createInstance=pn;var ln=pn();module.exports=ln; diff --git a/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/uni-config-center/index.js b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/uni-config-center/index.js new file mode 100644 index 0000000..00ba62f --- /dev/null +++ b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/node_modules/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;t { + return await vk.router({ event, context, vk }); +}; +``` + +修改为 + +```js +'use strict'; +// 注意:此为云函数路由入口文件,请勿修改此文件代码,你自己的云函数逻辑应写在service目录下 +const vkCloud = require('vk-unicloud'); // 引入 vk-unicloud +const vk = vkCloud.createInstance(require('./config.js')); // 通过 vkCloud.createInstance 创建 vk 实例 +exports.main = async (event, context) => { + return await vk.router({ event, context, vk }); +}; +``` + +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.20(2022-09-29) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.19(2022-09-29) +* 1、【修复】升级HBX后带来的部分兼容性问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.18(2022-09-26) +* 1、【优化】`vk.pubfn.getCurrentPage()` API 在最新版HBX上的兼容性。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.17(2022-09-22) +* 1、【重要】微信公众号万能API调用接口支持在阿里云空间执行(自动使用阿里云代理模式)[传送门 - 阿里云固定IP设置](https://uniapp.dcloud.net.cn/uniCloud/cf-functions.html#aliyun-eip) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.16(2022-09-18) +* 1、【修复】`vk.crypto.aes.encrypt`、`vk.crypto.aes.decrypt` 在非 `router` 目录结构的云函数中运行可能会报错的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.15(2022-09-17) +* 1、【修复】`vk.crypto.aes.encrypt`、`vk.crypto.aes.decrypt` 在非 `router` 目录结构的云函数中运行可能会报错的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.14(2022-09-16) +* 1、【修复】`vk.baseDao.getTableData` 的查询条件某个字段的值指定为null时,可能会报错的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.13(2022-09-12) +* 1、【修复】`vk.baseDao.getTableData` 内使用 `_.geoNear` 无效的问题。 +* 2、【优化】前端使用 `vk.request` 请求时,若本地缓存中有 `uni_id_token`,则请求头会带上 `uni_id_token` 的值 +* 3、【优化】`router` 函数 `url化后`,若没有直接传 `uni_id_token` 参数,则会尝试从请求头中获取 `uni_id_token` +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.12(2022-09-12) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.11(2022-09-11) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.10(2022-09-11) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.9(2022-09-08) +* 1、【修复】`vk.baseDao.getTableData` 内使用 `_.geoNear` 无效的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.8(2022-09-05) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.7(2022-08-29) +* 1、【重要】新增 `监听token更新` API [传送门](https://vkdoc.fsq.pub/client/vk.userCenter.html?t=20220829#vk-onrefreshtoken-%E7%9B%91%E5%90%ACtoken%E6%9B%B4%E6%96%B0%E4%BA%8B%E4%BB%B6) +* 2、【优化】`云对象` 新增 `this.getUniCloudRequestId`(获取当前请求id)[传送门](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#this-getunicloudrequestid-%E8%8E%B7%E5%8F%96%E5%BD%93%E5%89%8D%E8%AF%B7%E6%B1%82id) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.6(2022-08-26) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.5(2022-08-25) +* 1、【优化】`vk.pubfn.getCommonTime` 更新文档 [传送门](https://vkdoc.fsq.pub/client/jsapi.html?t=20220825#vk-pubfn-getcommontime-%E8%8E%B7%E5%8F%96%E6%97%B6%E9%97%B4%E8%8C%83%E5%9B%B4) +* 2、【优化】其他细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.4(2022-08-23) +* 1、【修复】快手小程序自动跳登录页面的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.3(2022-08-22) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.2(2022-08-22) +* 1、【重要】前端 `微信登录` 、 `微信获取openid` 等接口不再返回 `sessionKey` 取而代之的是返回 `encryptedKey`(加密后的数据,云函数解密后可获得 `sessionKey`) +* 2、【重要】新增配置 `vk.crypto.aes` 用于返回给前端加密数据时的加密密钥 + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/a4ca3d72-358e-4437-8766-d0b14e269697.png) + +* 3、【新增】`vk.crypto.aes.encrypt` 用于加密数据 +* 4、【新增】`vk.crypto.aes.decrypt` 用于解密数据 + +```js +// 加密数据 +let encryptedKey = vk.crypto.aes.encrypt({ + data: { + sessionKey: "XXXXX" + } +}); +console.log('encryptedKey: ', encryptedKey) + +// 解密 sessionKey 示例 +let decryptedRes = vk.crypto.aes.decrypt({ + data: encryptedKey, // 待解密的原文 +}); +console.log('decryptedRes: ', decryptedRes) +let sessionKey = decryptedRes.sessionKey; +console.log('sessionKey: ', sessionKey) +``` + +**特别注意** + +* 1、本次更新需要替换 `router/service/user/pub/` 目录 + +* 2、如果你使用了 `使用微信小程序绑定的手机号一键登录` 的API,则请看此处调整代码 [传送门](https://vkdoc.fsq.pub/client/vk.userCenter.html?t=20220822#vk-usercenter-loginbyweixinphonenumber-%E9%80%9A%E8%BF%87%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%BB%91%E5%AE%9A%E7%9A%84%E6%89%8B%E6%9C%BA%E5%8F%B7%E7%99%BB%E5%BD%95) + +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.1(2022-08-22) +* 1、【重要】前端 `微信登录` 、 `微信获取openid` 等接口不再返回 `sessionKey` 取而代之的是返回 `encryptedKey`(加密后的数据,云函数解密后可获得 `sessionKey`) +* 2、【重要】新增配置 `vk.crypto.aes` 用于返回给前端加密数据时的加密密钥 + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/a4ca3d72-358e-4437-8766-d0b14e269697.png) + +* 3、【新增】`vk.crypto.aes.encrypt` 用于加密数据 +* 4、【新增】`vk.crypto.aes.decrypt` 用于解密数据 + +```js +// 加密数据 +let encryptedKey = vk.crypto.aes.encrypt({ + data: { + sessionKey: "XXXXX" + } +}); +console.log('encryptedKey: ', encryptedKey) + +// 解密 sessionKey 示例 +let decryptedRes = vk.crypto.aes.decrypt({ + data: encryptedKey, // 待解密的原文 +}); +console.log('decryptedRes: ', decryptedRes) +let sessionKey = decryptedRes.sessionKey; +console.log('sessionKey: ', sessionKey) +``` + +**特别注意** + +* 1、本次更新需要替换 `router/service/user/pub/` 目录 + +* 2、如果你使用了 `使用微信小程序绑定的手机号一键登录` 的API,则请看此处调整代码 [传送门](https://vkdoc.fsq.pub/client/vk.userCenter.html?t=20220822#vk-usercenter-loginbyweixinphonenumber-%E9%80%9A%E8%BF%87%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%BB%91%E5%AE%9A%E7%9A%84%E6%89%8B%E6%9C%BA%E5%8F%B7%E7%99%BB%E5%BD%95) + +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.0(2022-08-22) +* 1、【重要】前端 `微信登录` 、 `微信获取openid` 等接口不再返回 `sessionKey` 取而代之的是返回 `encryptedKey`(加密后的数据,云函数解密后可获得 `sessionKey`) +* 2、【重要】新增配置 `vk.crypto.aes` 用于返回给前端加密数据时的加密密钥 +* 3、【新增】`vk.crypto.aes.encrypt` 用于加密数据 +* 4、【新增】`vk.crypto.aes.decrypt` 用于解密数据 +```js +// 加密数据 +let encryptedKey = vk.crypto.aes.encrypt({ + data: { + sessionKey: "XXXXX" + } +}); +console.log('encryptedKey: ', encryptedKey) + +// 解密 sessionKey 示例 +let decryptedRes = vk.crypto.aes.decrypt({ + data: encryptedKey, // 待解密的原文 +}); +console.log('decryptedRes: ', decryptedRes) +let sessionKey = decryptedRes.sessionKey; +console.log('sessionKey: ', sessionKey) +``` +**特别注意** + +本次更新需要替换 `router/service/user/pub/` 目录 + +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.15(2022-08-20) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.14(2022-08-20) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.13(2022-08-19) +* 1、【优化】发送短信验证码接口和组件新增参数 `checkUserExist` : 是否需要检测手机号对应的账号是否存在,默认false:不检测 设置为true:会检测,如果检测到用户不存在,则不发短信。(如通过手机号找回密码的业务,如果手机号都未注册,则没有必要发短信)(需要替换文件:`router/service/user/pub/sendSmsCode.js`) +* 2、【修复】数据库API,`_.geoNear` 部分情况下会失效的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.12(2022-08-15) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.11(2022-08-15) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.10(2022-08-13) +* 1、【调整】根据手机验证码重置账号密码的短信验证 `type` 从 `reset` 改为 `reset-pwd`(与unicloud官方对齐) +* 2、【调整】根据邮箱验证码重置账号密码的邮件验证 `type` 从 `reset` 改为 `reset-pwd`(与unicloud官方对齐) +* 3、【修复】vk.pubfn.test("aaahttps://www.baidu.com","url") 会返回 true 的bug +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.9(2022-07-30) +* 1、【优化】云对象 `this.getCloudInfo()` 内增加 `functionName`、`functionType` [传送门](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#this-getcloudinfo-%E8%8E%B7%E5%8F%96%E4%BA%91%E7%AB%AF%E4%BF%A1%E6%81%AF) +* 2、【优化】云对象 `this.getClientInfo()` 内增加 `source` [传送门](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#this-getclientinfo-%E8%8E%B7%E5%8F%96%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%BF%A1%E6%81%AF) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.8(2022-07-28) +* 1、【新增】`uni-id` 配置 `removeDcloudAppid` 默认false,若设置true,则注册成功后,会自动删除 `dcloud_appid` 字段,以达到禁用隔离不同端用户的功能。(需配合中间件registerInitFilter) +* 2、【新增】`vk.openapi.weixin.urllink.generate` 云函数生成小程序url链接API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html#%E8%8E%B7%E5%8F%96%E5%B0%8F%E7%A8%8B%E5%BA%8Furl%E9%93%BE%E6%8E%A5) +* 3、【新增】`vk.userCenter.getWeixinMPurl` 前端直接生成小程序url链接API [传送门](https://vkdoc.fsq.pub/client/vk.userCenter.html#vk-usercenter-getweixinmpurl-%E7%94%9F%E6%88%90%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8Furl%E9%93%BE%E6%8E%A5) +* 4、【优化】`vk.openapi.weixin.wxacode.getUnlimited` 和 `vk.openapi.weixin.urlscheme.generate` 支持参数 `env_version` [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html#%E8%8E%B7%E5%8F%96%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%A0%81) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.7(2022-07-23) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.6(2022-07-22) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.5(2022-07-22) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.4(2022-07-21) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.3(2022-07-20) +* 1、【修复】`_.geoNear` 和 `lastWhereJson` 同时使用时报错的bug +* 2、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.2(2022-07-18) +* 1、`vk.pubfn.batchRun` 新增另外一种调用方式。[传送门](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-batchrun) +* 2、新增 `vk.uploadFile` 代替 `vk.callFunctionUtil.uploadFile`(保留旧写法) [传送门](https://vkdoc.fsq.pub/client/pages/uploadFile.html) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.1(2022-07-12) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.0(2022-07-09) +* 1、【优化】`vk.baseDao.update` `vk.baseDao.updateById` `vk.baseDao.updateAndReturn` API的 `dataJson` 参数若有 `_id`,则自动忽略 `_id`(因_id不可修改,原先是直接报错) +* 2、【优化】其他细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.12(2022-07-04) +* 1、【新增】微信小程序服务端万能API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html#%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E4%B8%87%E8%83%BDapi%E8%B0%83%E7%94%A8%E6%8E%A5%E5%8F%A3) +* 2、【新增】微信公众号服务端万能API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin-h5.html) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.11(2022-06-28) +* 1、【优化】`万能连表` 支持使用数组下标对应的值进行连表,如用户表根据inviter_uid的第一个值进行连表达到只查出第一个上级用户信息的效果 [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/selects.html#%E5%9C%BA%E6%99%AF11) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.10(2022-06-25) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.9(2022-06-22) +* 1、【重要】新增安全规则:未标记 `isCloudObject:true` 的对象定义为私有对象(如 `service/user/util/login_log.js`),前端禁止访问(只能被云函数/云对象 `require` 方式调用)。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.8(2022-06-22) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.7(2022-06-22) +* 1、【新增】数据库表内的字段重命名api [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/question.html#%E5%A6%82%E4%BD%95%E6%9B%B4%E6%94%B9%E5%AD%97%E6%AE%B5%E5%90%8D) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.6(2022-06-20) +* 1、【新增】云函数专用api `vk.pubfn.randomAsync`(异步)产生指定位数的不重复随机数(支持任意字符,s默认纯数字)[点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-randomasync) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.5(2022-06-17) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.4(2022-06-15) +* 1、【调整】`vk.getVuex` 当数据不存在时,返回值由 `undefined` 调整为 `空字符串`(undefined在部分平台会有问题) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.3(2022-06-11) +* 1、【重要】`uni-id` 新增配置参数 `"preferedWebPlatform": "h5",`,用于解决因HBX3.4.14版本导致的 `h5` 变为 `web` 带来的一系列问题。(完美兼容,你无需改自己的逻辑代码了) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.2(2022-06-10) +* 1、【调整】`vk.getVuex` 当数据不存在时,返回值由 `空字符串` 调整为 `undefined` +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.1(2022-06-08) +* 1、【优化】`云对象` 的内置api `this.getClientInfo` 可以获取到更多信息(uni.getSystemInfo返回的客户端信息) +* 2、【优化】`云函数` 的 `originalParam.context` 可以获取到更多信息(uni.getSystemInfo返回的客户端信息) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.0(2022-06-07) +* 1、【新增】`vk.callFunction` api [点击查看详情](https://vkdoc.fsq.pub/client/question/question.html#%E4%BA%91%E5%87%BD%E6%95%B0-%E4%BA%91%E5%AF%B9%E8%B1%A1-%E4%B8%AD%E5%A6%82%E4%BD%95%E8%B0%83%E7%94%A8%E5%8F%A6%E4%B8%80%E4%B8%AA%E4%BA%91%E5%87%BD%E6%95%B0-%E4%BA%91%E5%AF%B9%E8%B1%A1) +> * 1.1、支持在云对象中请求其他云对象内的函数。 +> * 1.2、支持在云对象中请求云函数。 +> * 1.3、支持在云函数内请求其他云函数。 +> * 1.4、支持在云函数内请求云对象内的函数。 +* 2、【优化】`pub` 类型的函数无需 `need_user_info:true`,也能从token中解析并获取到uid(无数据库请求,不影响性能) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.15(2022-06-02) +* 1、【优化】为了兼容DCloud推出的uniCloud响应体规范,请求后的返回值会自动加上errCode和errMsg,其中errCode=code,errMsg=msg +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.14(2022-06-02) +* 1、【优化】为了兼容DCloud推出的uniCloud响应体规范,请求后的返回值会自动加上errCode和errMsg,其中errCode=code,errMsg=msg +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.13(2022-05-30) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.12(2022-05-30) +* 1、【修复】`云对象` 模式下 `sys类型函数` 在非admin目录下时,请求会提示 `need_user_info` 的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.11(2022-05-28) +* 1、【修复】`interceptor.login` 前端自定义login拦截器,在某些情况下无法正常拦截的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.10(2022-05-27) +* 1、【修复】当 `云对象` 在 `service` 层根目录时,`pub.对象名.js` pub权限失效的问题。 +* 2、【优化】其他一些细节。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.9(2022-05-26) +* 1、【新增】`vk.baseDao.selects` 和 `vk.baseDao.getTableData` 新增 `lastSortArr` 参数,用于聚合后再排序。 +* 注意:`lastWhereJson` 和 `lastSortArr` 在数据量大的情况下是有性能问题的,(建议主表的where条件中先进行筛选,如只查本季度数据,只要主表过滤完后数据量不大,则没有性能问题。) +* 2、【修复】`lastWhereJson` 后,返回的 `total` 不准确的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.8(2022-05-25) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.7(2022-05-14) +* 1、【新增】`vk.pubfn.getFileType(url)` 根据文件url获取文件类型 +* 2、【新增】`vk.pubfn.getFileSuffix(url)` 根据文件url获取文件后缀名 +* 3、【新增】`vk.pubfn.checkFileSuffix(url,["png", "jpg", "jpeg", "gif", "bmp", "svg"])` 根据文件url判断是否满足指定后缀名中的任意1个 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.6(2022-05-13) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.5(2022-05-05) +* 1、【重要】vk实例对象已调整为页面内置对象,vk实例对象内的api在任意地方都可以直接通过vk.xxx()使用,不再需要 this.vk.xxx() 或 uni.vk.xxx() 的方式来调用。 +* 2、【重要】vk实例对象已调整为云函数内置对象,vk实例对象内的api在任意地方都可以直接通过vk.xxx()使用,不再需要 this.vk.xxx() 或 uniCloud.vk.xxx() 的方式来调用。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.3(2022-04-28) +* 1、【新增】`vk.openapi.weixin.uniformMessage.send` 小程序转公众号消息模板接口 [点击查看](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html#%E5%B0%8F%E7%A8%8B%E5%BA%8F%E8%BD%AC%E5%85%AC%E4%BC%97%E5%8F%B7%E6%A8%A1%E6%9D%BF%E6%B6%88%E6%81%AF) +* 2、【新增】`vk.openapi.weixin.h5.templateMessage.send` 公众号消息模板接口 [点击查看](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html#%E5%8D%95%E7%8B%AC%E5%85%AC%E4%BC%97%E5%8F%B7%E6%A8%A1%E6%9D%BF%E6%B6%88%E6%81%AF) + +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.2(2022-04-21) +* 1、【重要】`uni-id` 配置新增 `tokenMaxLimit` 每个账户的最大token数量,0为不限,淘汰策略:新的淘汰旧的(注意,即使设置为0,框架也会自动淘汰已过期的token)[点击查看](https://vkdoc.fsq.pub/client/uniCloud/config/uni-id.html) +* 2、【重要】微信登录支持多小程序:如果使用多小程序登录,则同一用户(同一个微信号)在不同小程序登录时,会分别创建不同的用户(除非小程序绑定在同一个开放平台下) +* 3、【新增】全局参数 `targetTimezone` 可设置默认时区(中国为8,8代表东8区,-8代表西8区) + +> [查看前端全局配置](https://vkdoc.fsq.pub/client/pages/config.html) + +> [查看云函数全局配置](https://vkdoc.fsq.pub/client/uniCloud/config/vk-unicloud.html) + +* 4、【新增】全局参数 `functionNameToUrl` 和 `isRequestDefault` [点击查看](https://vkdoc.fsq.pub/client/pages/callFunctionForUrl.html#%E6%B3%A8%E6%84%8F-%E4%BA%91%E5%87%BD%E6%95%B0url%E5%8C%96%E6%96%B9%E5%BC%8F%E8%B0%83%E7%94%A8%E9%9C%80%E8%A6%81%E9%85%8D%E7%BD%AE%E4%BD%A0%E7%9A%84%E4%BA%91%E5%87%BD%E6%95%B0url%E8%B7%AF%E5%BE%84%E5%9C%B0%E5%9D%80) +* 5、【优化】微信注册时支持新增自定义字段,如:nickname和avatar等。 +* 6、【优化】当云函数全局配置文件出错时,优化报错提示。 + +**本次更新除了常规升级框架外,还需要下载最新版框架示例项目,从最新版中复制 以下文件 替换 你项目中的对应文件。** + +* 1、`router/middleware/modules/returnUserInfoFilter.js` (此为用户登录注册全局中间件) +* 2、`router/service/user/pub/loginByWeixin.js` (此为微信登录云函数) + +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.1(2022-04-14) +* 1、【新增】前端请求多服务空间的极简方式(通过配置直接指定调用环境)[点击查看](https://vkdoc.fsq.pub/client/question/q9.html#%E6%96%B9%E5%BC%8F%E4%BA%8C) +* 2、【新增】`vk.userCenter.resetPasswordByEmail`(根据邮箱证码重置账号密码) [点击查看](https://vkdoc.fsq.pub/client/vk.userCenter.html#vk-usercenter-resetpasswordbyemail-%E6%A0%B9%E6%8D%AE%E9%82%AE%E7%AE%B1%E8%AF%81%E7%A0%81%E9%87%8D%E7%BD%AE%E8%B4%A6%E5%8F%B7%E5%AF%86%E7%A0%81) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.0(2022-04-01) +* 1、【重要】新增 `云对象` 路由模式 [什么是云对象?](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html) +* 2、【重要】自此,在VK框架中,可以做到云对象和云函数同时存在。即在VK框架中,同时支持 `云对象路由模式` 和 `云函数路由模式`。 +* 3、【新增】本地运行支持云对象 [点击查看](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#%E6%9C%AC%E5%9C%B0%E8%BF%90%E8%A1%8C) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.7.6(2022-03-26) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.7.5(2022-03-22) +* 1、【新增】`vk.userCenter.bindNewMobile` 换绑新的手机号接口 [查看详情](https://vkdoc.fsq.pub/client/vk.userCenter.html#vk-usercenter-bindnewmobile-%E6%8D%A2%E7%BB%91%E6%89%8B%E6%9C%BA%E5%8F%B7) +* 2、【新增】`vk.userCenter.bindNewEmail` 换绑新的邮箱接口 [查看详情](https://vkdoc.fsq.pub/client/vk.userCenter.html#vk-usercenter-bindnewemail-%E6%8D%A2%E7%BB%91%E9%82%AE%E7%AE%B1) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.7.4(2022-03-21) +* 1、【优化】H5环境下,微信登录、微信绑定、微信解绑API,使之自动识别微信公众号环境(h5-weixin)的配置。 +注意:微信公众号的 `uni-id` 配置属性是 `h5-weixin`,非 `h5`。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.7.3(2022-03-18) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.7.2(2022-03-14) +* 1、【修复】`vk.navigateTo` 以 ./ 开头时 如:vk.navigateTo("./order-list") 判断是否需要登录不准确的问题。 +## 2.7.1(2022-03-14) +* 1、【优化】`app.config.js` 中的 `checkTokenPages` 检测页面是否需要登录支持 首页(启动页)的检测 +* 2、【优化】其他细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.7.0(2022-02-26) +###【重要】由于uni官方限制自定义表不可以用 `opendb-` 和 `uni-` 开头,故以下数据库表名只能进行调整 + +* 1、`opendb-components-dynamic` 改为 `vk-components-dynamic` +* 2、`opendb-global-data` 改为 `vk-global-data` +* 3、`uni-id-files` 改为 `vk-files` +* 4、`uni-id-files-categories` 改为 `vk-files-categories` + +___更改表名势必会对老项目产生影响。___ + +### 老项目更新注意事项: +* 1、老项目更新后,还需要从 `unicloud控制台` 把表名改成对应的新表名 +* 2、在项目代码中全局搜索旧表名,替换成新表名 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.6.15(2022-02-24) +* 1、【优化】`万能连表` 支持副表外键是数组类型(只要数组内任意元素与主表外键匹配即可)[点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/selects.html#%E5%9C%BA%E6%99%AF6) +* 2、【优化】其他一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.6.14(2022-01-20) +* 1、【优化】一些细节。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.13(2022-01-14) +* 1、【优化】一些细节。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.12(2022-01-08) +* 【修复】`vk.openapi.weixin.security.imgSecCheck` 图片安全检测失效的问题 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.11(2021-12-24) +* 1、【修复】`vk.pubfn.string2Number` 会将空字符串转为0的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.10(2021-12-17) +* 1、【优化】一些细节。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.9(2021-12-16) +* 1、【修复】`vk.pubfn.priceFilter` 、`vk.pubfn.percentageFilter` 、`vk.pubfn.discountFilter` 部分情况下,默认值不生效的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.8(2021-12-14) +* 1、【优化】一些细节。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.7(2021-12-14) +* 1、【优化】一些细节。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.6(2021-12-10) +* 1、【修复】少数情况下,http请求可能获取不到数据的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.5(2021-12-07) +* 1、【修复】公众号登录可能会获取不到昵称和头像的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.4(2021-12-07) +* 1、【优化】上传api的url自动去除原文件名的中文部分。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.3(2021-11-29) +* 1、【新增】`vk.baseDao` 内api支持连接其他服务空间的数据库 [点击查看](https://vkdoc.fsq.pub/client/question/q9.html#%E4%BA%91%E5%87%BD%E6%95%B0%E7%AB%AF%E8%AF%B7%E6%B1%82%E5%A4%9A%E6%9C%8D%E5%8A%A1%E7%A9%BA%E9%97%B4%E7%A4%BA%E4%BE%8B%E4%BB%A3%E7%A0%81) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.2(2021-11-26) +* 1、【新增】`await vk.pubfn.batchRun` 批量循环并发执行异步函数(云函数内专用, 使用场景: 批量发送短信、邮件、消息通知等。)[点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-batchrun) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.1(2021-11-26) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.0(2021-11-19) +* 1、【重要】移除了内置的 `npm` 方式安装的 `uView` 组件库,开发者可以选择自己喜欢的组件库进行开发。[点击查看](https://vkdoc.fsq.pub/client/quickstart.html#%E8%87%AA-client%E7%AB%AF%E6%A1%86%E6%9E%B6-2-6-0-%E8%B5%B7-%E4%B8%8D%E5%86%8D%E5%86%85%E7%BD%AE%E4%BB%BB%E4%BD%95-ui-%E6%A1%86%E6%9E%B6-%E4%BD%A0%E5%8F%AF%E4%BB%A5%E9%80%89%E6%8B%A9%E8%87%AA%E5%B7%B1%E5%96%9C%E6%AC%A2%E7%9A%84-ui-%E7%BB%84%E4%BB%B6%E5%BA%93%E8%BF%9B%E8%A1%8C%E5%BC%80%E5%8F%91%E3%80%82) +* 2、【重要】移除内置组件 `vk-u-goods-sku-popup`(推荐 `vk-data-goods-sku-popup` 代替)[点击查看](https://ext.dcloud.net.cn/plugin?id=2848) +* 3、【重要】移除内置组件 `vk-u-number-box`(推荐 `u-number-box` 代替) +* 4、【重要】移除内置组件 `vk-u-grid-button` +* 5、【重要】移除内置组件 `vk-u-swiper` +* 6、【重要】重构内置组件 `vk-u-verification-code` 并改名为 `vk-data-verification-code` +* 如想要继续使用这些组件,可以把这些组件复制到项目根目录的 `components` 目录(没有则新建)(目录名和组件名需一致,如 `vk-u-grid-button/vk-u-grid-button`) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.5.6(2021-11-13) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.5.5(2021-11-11) +* 1、【新增】`vk.pubfn.getOffsetTime` 获得指定时间偏移 year年 month月 day天 hours时 minutes分 seconds秒前或后的时间戳 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getoffsettime-%E8%8E%B7%E5%BE%97%E6%8C%87%E5%AE%9A%E6%97%B6%E9%97%B4%E5%81%8F%E7%A7%BB-year%E5%B9%B4-month%E6%9C%88-day%E5%A4%A9-hours%E6%97%B6-minutes%E5%88%86-seconds%E7%A7%92%E5%89%8D%E6%88%96%E5%90%8E%E7%9A%84%E6%97%B6%E9%97%B4%E6%88%B3) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.5.4(2021-11-10) +* 1、【优化】前端请求云函数的一处细节。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.5.3(2021-11-09) +* 1、【优化】`vk.pubfn.base64ToFile` 支持 APP 环境执行 +* 2、【优化】`vk.pubfn.fileToBase64` 支持 APP 环境执行 +* 3、【修复】`vk.baseDao.selects` 当 `localKey` 为 `a.b.c` 这样的形式时会报错的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.5.2(2021-11-03) +* 1、【修复】`vk.baseDao.adds` 无返回值的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.5.1(2021-11-02) +* 1、【新增】`vk.h5` 前端API接口(H5专用的一些接口,只有H5环境时,才有该对象,不会增大小程序的包体积) +* 2、【新增】`vk.h5.wx`(wx为公众号js_sdk接口) [微信小程序环境内js_sdk文档](https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html) [微信公众号环境内js_sdk文档](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html) +* 3、【新增】`vk.navigateToHome` 跳转到首页 (app.config.js 的 index.url) +* 4、【新增】`vk.navigateToLogin` 跳转到登录页 (app.config.js 的 login.url) +* 5、【修复】`vk.callFunctionUtil.updateRequestGlobalParam` 全局公共请求参数的一处逻辑问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.5.0(2021-11-02) +* 1、【新增】`vk.h5` 前端API接口(H5专用的一些接口,只有H5环境时,才有该对象,不会增大小程序的包体积) +* 2、【新增】`vk.h5.wx`(wx为公众号js_sdk接口) [微信小程序环境内js_sdk文档](https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html) [微信公众号环境内js_sdk文档](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html) +* 3、【新增】`vk.navigate.navigateToHome` 跳转到首页 +* 4、【新增】`vk.navigate.navigateToLogin` 跳转到登录页 +* 5、【修复】`vk.callFunctionUtil.updateRequestGlobalParam` 全局公共请求参数的一处逻辑问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.4.12(2021-10-30) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.4.11(2021-10-28) +* 1、【优化】`vk.pubfn.hidden(str, first, last);` 的 `first` 和 `last` 默认为0 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-hidden-%E5%B0%86%E6%89%8B%E6%9C%BA%E5%8F%B7%E3%80%81%E8%B4%A6%E5%8F%B7%E7%AD%89%E9%9A%90%E8%97%8F%E4%B8%AD%E9%97%B4%E5%AD%97%E6%AE%B5) +* 2、【优化】其他一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.4.10(2021-10-26) +* 【优化】在 `template` 模板中使用 `vk.pubfn`(可以用简写法 `$fn` 代替 `vk.pubfn`) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.4.9(2021-10-23) +* 【优化】`vk.userCenter` 接口细节,现在参数 `loading:true` 或 `loading:false` 均可以关闭 `loading提示框` +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.4.8(2021-10-16) +* 【优化】当配置文件编译错误时,增加对应的错误提示。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.4.7(2021-10-15) +* 【优化】当 `router/util/pubFunction.js` 内的代码出现编译错误时,控制台能打印编译错误信息。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.4.6(2021-10-07) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.4.5(2021-09-30) +* 1、【优化】`vk.pubfn.string2Number` 新增第二位参数option +```js +/** + * 将能转成数字的字符串转数字(支持字符串、对象、数组) + * @param {Any} obj + * @param {Object} option 哪些格式需要排除 + * 默认排除 + * mobile:true 手机号,如 15200000001 + * idCard:true 身份证,如 330154202109301214 + * startFrom0:true 第一位是0,且长度大于1的,同时第二位不是.的字符串 如 01,057189101254 + */ +vk.pubfn.string2Number(obj, option); +``` + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.3(2021-09-30) +* 1、【优化】`vk.pubfn.string2Number` 新增第二位参数option,默认排除手机号、身份证、第一位是0,且长度大于1的字符串(可自由设置) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.2(2021-09-30) +* 1、【新增】`vk.pubfn.string2Number` 将能转成数字的字符串值转Number类型(支持字符串、对象、数组)(深度遍历) +* 2、【优化】`vk.callFunctionUtil.updateRequestGlobalParam` 设置全局请求参数 `regExp` 参数支持数组(满足数组内任意正则即算匹配) [点击查看](https://vkdoc.fsq.pub/client/pages/updateRequestGlobalParam.html) + + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.1(2021-09-28) +* 1、【重要】支持微信公众号登录(有头像和昵称)详情见示例项目:`pages_template/openapi/h5-weixin/h5-weixin` +* 2、【优化】APP使用微信登录时,有头像和昵称 详情见示例项目:`pages_template/uni-id/weixin/weixin` + +公众号配置文件在 `uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json` + +```js +"h5-weixin": { + "oauth": { + "weixin": { + "appid": "微信公众号appid", + "appsecret": "微信公众号appsecret" + } + } +}, +``` +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.0(2021-09-28) +* 1、【重要】支持微信公众号登录(有头像和昵称)详情见示例项目:`pages_template/openapi/h5-weixin/h5-weixin` +* 2、【优化】APP使用微信登录时,有头像和昵称 详情见示例项目:`pages_template/uni-id/weixin/weixin` + +公众号配置文件在 `uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json` + +```js +"h5-weixin": { + "oauth": { + "weixin": { + "appid": "微信公众号appid", + "appsecret": "微信公众号appsecret" + } + } +}, +``` +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.3.29(2021-09-27) +* 1、【新增】`vk.pubfn.snake2camelJson` 对象内的属性名 - 蛇形转驼峰 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-snake2cameljson-%E5%AF%B9%E8%B1%A1%E5%86%85%E7%9A%84%E5%B1%9E%E6%80%A7%E5%90%8D-%E8%9B%87%E5%BD%A2%E8%BD%AC%E9%A9%BC%E5%B3%B0) +* 2、【新增】`vk.pubfn.camel2snakeJson` 对象内的属性名 - 驼峰转蛇形 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-camel2snakejson-%E5%AF%B9%E8%B1%A1%E5%86%85%E7%9A%84%E5%B1%9E%E6%80%A7%E5%90%8D-%E9%A9%BC%E5%B3%B0%E8%BD%AC%E8%9B%87%E5%BD%A2) +* 3、【新增】`vk.pubfn.snake2camel` 字符串 - 蛇形转驼峰 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-snake2camel-%E5%AD%97%E7%AC%A6%E4%B8%B2-%E8%9B%87%E5%BD%A2%E8%BD%AC%E9%A9%BC%E5%B3%B0) +* 4、【新增】`vk.pubfn.camel2snake` 字符串 - 驼峰转蛇形 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-camel2snake-%E5%AD%97%E7%AC%A6%E4%B8%B2-%E9%A9%BC%E5%B3%B0%E8%BD%AC%E8%9B%87%E5%BD%A2) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.3.28(2021-09-16) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.27(2021-09-14) +* 【优化】`vk.pubfn.dateDiff` 新增后缀参数 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-datediff-%E5%B0%86%E6%97%B6%E9%97%B4%E6%98%BE%E7%A4%BA%E6%88%901%E7%A7%92%E5%89%8D%E3%80%811%E5%A4%A9%E5%89%8D) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.26(2021-09-14) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.25(2021-09-13) +* 1、【优化】文件上传逻辑 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.24(2021-09-08) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.23(2021-09-07) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.22(2021-09-01) +* 1、【优化】文件上传逻辑 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.21(2021-08-31) +* 1、【新增】配置`vk.db.unicloud.getTableData.sortArr`,可以设置`vk.baseDao.getTableData`全局默认排序规则 +* 2、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.20(2021-08-26) +* 1、【新增】`app.config.js` 新增参数 `globalErrorCode` 可以修改全局异常的提示信息 [点击查看](https://vkdoc.fsq.pub/client/pages/config.html) +* 2、【新增】`javascript代码块提示.json` 最近新增的api的代码提示 [点击查看](https://vkdoc.fsq.pub/client/codeTips.html) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.19(2021-08-26) +* 1、【新增】`app.config.js` 新增参数 `globalErrorCode` 可以修改全局异常的提示信息 [点击查看](https://vkdoc.fsq.pub/client/pages/config.html) +* 2、【新增】`javascript代码块提示.json` 最近新增的api的代码提示 [点击查看](https://vkdoc.fsq.pub/client/codeTips.html) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.18(2021-08-24) +* 1、【修复】腾讯云的图片上传无法回显图片的问题。 +* 2、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.17(2021-08-24) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.16(2021-08-24) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.15(2021-08-24) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.14(2021-08-23) +* 【修复】腾讯云的图片上传无法回显图片的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.13(2021-08-23) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.12(2021-08-23) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.11(2021-08-21) +* 【新增】`vk.pubfn.sleep` 进程等待(主要用于在云函数中需要故意等待几秒的情况)[点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-sleep-%E8%BF%9B%E7%A8%8B%E5%BC%BA%E5%88%B6%E7%AD%89%E5%BE%85-%E4%BC%91%E7%9C%A0) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.10(2021-08-21) +* 【优化】`vk.pubfn.timeFormat` 等API,当参数time为字符串时间戳时的特殊处理 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.9(2021-08-21) +* 【新增】`vk.pubfn.getDayOffsetStartAndEnd` 获得相对当前时间的偏移 count 天的起止日期(日的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getdayoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E5%A4%A9%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 【新增】`vk.pubfn.getMonthOffsetStartAndEnd` 获得相对当前时间的偏移 count 月的起止日期(月的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getmonthoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E6%9C%88%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 【新增】`vk.pubfn.getYearOffsetStartAndEnd`获得相对当前时间的偏移 count 年的起止日期(年的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getyearoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E5%B9%B4%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.8(2021-08-21) +* 【新增】`vk.pubfn.getDayOffsetStartAndEnd` 获得相对当前时间的偏移 count 天的起止日期(日的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getdayoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E5%A4%A9%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 【新增】`vk.pubfn.getMonthOffsetStartAndEnd` 获得相对当前时间的偏移 count 月的起止日期(月的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getmonthoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E6%9C%88%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 【新增】`vk.pubfn.getYearOffsetStartAndEnd`获得相对当前时间的偏移 count 年的起止日期(年的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getyearoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E5%B9%B4%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.7(2021-08-21) +* 【新增】`vk.pubfn.getDayOffsetStartAndEnd` 获得相对当前时间的偏移 count 天的起止日期(日的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getdayoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E5%A4%A9%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 【新增】`vk.pubfn.getMonthOffsetStartAndEnd` 获得相对当前时间的偏移 count 月的起止日期(月的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getmonthoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E6%9C%88%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 【新增】`vk.pubfn.getYearOffsetStartAndEnd`获得相对当前时间的偏移 count 年的起止日期(年的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getyearoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E5%B9%B4%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.6(2021-08-19) +* 【优化】`vk.baseDao.selects`新增参数`addFields` [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/question.html#%E5%88%86%E7%BB%84count) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.5(2021-08-19) +* 【优化】`vk.baseDao.selects`新增参数`addFields` [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/question.html#%E5%88%86%E7%BB%84count) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.4(2021-08-19) +* 【新增】`vk.baseDao.updateAndReturn` API [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/api.html#%E6%9B%B4%E6%96%B0%E5%B9%B6%E8%BF%94%E5%9B%9E%E6%9B%B4%E6%96%B0%E5%90%8E%E7%9A%84%E6%95%B0%E6%8D%AE-%E5%8E%9F%E5%AD%90%E6%93%8D%E4%BD%9C) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.3(2021-08-19) +* 【新增】`vk.baseDao.updateAndReturn` API [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/api.html#%E6%9B%B4%E6%96%B0%E5%B9%B6%E8%BF%94%E5%9B%9E%E6%9B%B4%E6%96%B0%E5%90%8E%E7%9A%84%E6%95%B0%E6%8D%AE-%E5%8E%9F%E5%AD%90%E6%93%8D%E4%BD%9C) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.2(2021-08-19) +* 【新增】`vk.baseDao.updateAndReturn` API [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/api.html#%E6%9B%B4%E6%96%B0%E5%B9%B6%E8%BF%94%E5%9B%9E%E6%9B%B4%E6%96%B0%E5%90%8E%E7%9A%84%E6%95%B0%E6%8D%AE-%E5%8E%9F%E5%AD%90%E6%93%8D%E4%BD%9C) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.1(2021-08-16) +####【重要】文档已搬家(gitee文档地址仅作为备用地址)[查看新版文档地址](https://vkdoc.fsq.pub/) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.0(2021-08-16) +####【重要】文档已搬家(gitee文档地址仅作为备用地址)[查看新版文档地址](https://vkdoc.fsq.pub/) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.13(2021-08-12) +#### 【优化】一些细节(为兼容Vue3做铺垫) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.12(2021-08-11) +#### 【优化】一些细节(为兼容Vue3做铺垫) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.11(2021-08-11) +#### 【优化】一些细节(为兼容Vue3做铺垫) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.10(2021-08-06) +#### 【优化】一些细节 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.9(2021-08-06) +#### 【优化】一些细节 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.8(2021-08-05) +### 更新内容 +#### 1、【修复】因`uni-id`配置隔离导致的微信`vk.openapi.weixin` API 兼容性问题。 +#### 2、【新增】`vk.pubfn.isArray` 判断变量是否是数组类型 +#### 3、【新增】`vk.pubfn.isObject` 判断变量是否是对象类型 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.2.7(2021-08-04) +### 更新内容 +#### 【优化】一些细节 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.6(2021-07-28) +### 更新内容 +#### 【新增】前端 `vk.callFunction` 支持请求其他服务空间的云函数 +```js +const myCloud = uniCloud.init({ + provider: 'aliyun', + spaceId: 'xxxx-yyy', + clientSecret: 'xxxx' +}); +vk.callFunction({ + url: 'template/db_api/pub/count', + title:'请求中...', + unicloud: myCloud, + success(data) { + console.log(data); + } +}); +``` +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.2.4(2021-07-12) +### 更新内容 +####【修复】已知问题 +## 2.2.3(2021-07-12) +### 更新内容 +####【修复】首次使用框架,上传部署后访问云函数可能会出现 `createInstance is undefined` 的问题。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.2.2(2021-07-12) +### 更新内容 +####【修复】连表查询时,因`lastWhereJson`而导致`getCount`错误的问题。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.1(2021-07-12) +### 更新内容 +####【修复】连表查询时,因`lastWhereJson`而导致`getCount`错误的问题。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.0(2021-07-09) +### 更新内容 +#### 1、【重要调整】删除了`config`公共模块,升级为`uni-config-center`模式 [点击查看升级教程](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4219337&doc_id=975983) +#### 1、【重要调整】删除了`config`公共模块,升级为`uni-config-center`模式 [点击查看升级教程](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4219337&doc_id=975983) +#### 1、【重要调整】删除了`config`公共模块,升级为`uni-config-center`模式 [点击查看升级教程](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4219337&doc_id=975983) + +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.14(2021-07-07) +### 更新内容 +####【修复】已知bug +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.13(2021-07-05) +### 更新内容 +####【修复】已知bug +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.12(2021-06-28) +### 更新内容 +#### 1、【修复】`user/kh/getMenu`云函数获取菜单错误的bug。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.11(2021-06-22) +### 更新内容 +#### 1、【优化】`vk.pubfn.timeFormat` 若参数不符合规则,则原值显示。 +#### 2、【优化】`vk.pubfn.random` 新增第三个参数`arr` (产生的随机数不会和此数组的任意一项重复) [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3268613&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.10(2021-06-22) +### 更新内容 +#### 1、【优化】`vk.pubfn.timeFormat` 若参数不符合规则,则原值显示。 +#### 2、【优化】`vk.pubfn.random` 新增第三个参数`arr` (产生的随机数不会和此数组的任意一项重复) [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3268613&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.9(2021-06-16) +### 更新内容 +####【修复】`vk.baseDao.add` 因hbx 3.1.18版本导致的本地运行时 `_add_time_str` 错误的问题。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.8(2021-06-12) +### 更新内容 +####【修复】`vk.pubfn.copyObject` 若参数值为undefined则会报异常的问题。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.1.7(2021-06-10) +####【优化】`vk.callFunctionUtil.uploadFile` 自动识别文件类型,无需传`fileType`参数 +####【修复】已知问题。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.1.6(2021-06-04) +### 更新内容 +####【修复】`返回树状结构`时最后一级子节点没有继承主表`foreignDB`属性的bug。[查询返回树状结构文档](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3906510&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.1.5(2021-06-04) +### 更新内容 +####【修复】`返回树状结构`时最后一级子节点没有继承主表`foreignDB`属性的bug。[查询返回树状结构文档](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3906510&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.1.4(2021-06-03) +### 更新内容 +####【新增】`onActionIntercepted`(被中间件拦截时执行) 和 `onActionError`(云函数执行异常时执行) 类型中间件 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3035637&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.3(2021-06-03) +### 更新内容 +####【新增】`onActionIntercepted`(被中间件拦截时执行) 和 `onActionError`(云函数执行异常时执行) 类型中间件 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3035637&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.2(2021-05-31) +### 更新内容 +####【优化】过滤器 `timeFilter`、`dateDiff` 能正确识别10位数时间戳和13位时间戳。[点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3269404&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.1(2021-05-31) +### 更新内容 +####【优化】`云函数URL化` 路由模式下,URL重写支持只允许部分云函数可被访问。(可以做到只暴露指定的API接口,增加URL化后的安全性) +#### `router/util/urlrewrite.js`文件配置内容如下 [点击URL重写规则](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3916806&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.0.11(2021-05-27) +### 更新内容 +#### 【优化】`vk.baseDao.select` 也支持 `getOne` 、 `getMain` +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.0.10(2021-05-27) +### 更新内容 +#### 【修复】`vk.callFunctionUtil.uploadFile` 上传视频时后缀名可能会错误的问题。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.0.9(2021-05-26) +### 更新内容 +#### 【优化】`vk.baseDao.selects` 中按距离查询的逻辑 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3028633&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.0.8(2021-05-25) +### 更新内容 +#### 【优化】`vk.baseDao.selects` 新增两个属性`getOne` 、 `getMain` [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4054561&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.0.7(2021-05-25) +### 更新内容 +#### 【优化】`vk.baseDao.selects` 新增两个属性`getOne` 、 `getMain` [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4054561&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + + +## 2.0.6(2021-05-25) +### 更新内容 +#### 【优化】`vk.baseDao.selects` 新增两个属性`getOne` 、 `getMain` [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4054561&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + + + +## 2.0.5(2021-05-21) +### 更新内容 +#### 【优化】`vk.baseDao.getTableData` 和 `vk.baseDao.selects` 连表查询逻辑。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.0.4(2021-05-21) +【调整】`vk.baseDao.getTableData` 默认排序规则调整为`_id`降序,之前是`_add_time`降序(因不是每个表都有`_add_time`字段) +## 2.0.3(2021-05-21) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +####【优化】`vk.baseDao` API的查询性能。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.0.2(2021-05-16) +### 更新内容 +#### 【优化】修复验证码发送的已知bug +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.0.1(2021-05-15) +### 更新内容 +#### 【优化】用户角色权限,支持admin使用 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4003879&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.0.0(2021-05-15) +### 更新内容 +#### 【优化】用户角色权限,支持admin使用 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4003879&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.9.4(2021-05-10) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【优化】`vk.baseDao.selects` 支持分组查询,对应 `groupJson` 参数 [点击查看万能连表场景6](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3028633&doc_id=975983) +#### 2、【优化】`vk.globalDataCache.get` 支持如果缓存有值,则读取缓存,如果缓存无值,则执行函数,并将函数return的结果保存到缓存 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3442025&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.9.3(2021-04-23) +### 更新内容 +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +#### 1、【重要】【新增】 `pages-dev.json` 机制,写法与`pages.json` 相同,但里面的页面只有运行(开发)环境时才会被HBX打包,发行(正式)环境下不会被HBX打包进去。[点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3928718&doc_id=975983) +```js +可以将一些测试页面写在 `pages-dev.json`内,这些测试页面在正式发布时是不会被HBX打包到源码里的。 +``` +#### 2、【重要】【新增】阿里云和unicloud短信聚合API (阿里云短信的实现不依赖阿里云SDK核心库,无需`npm install @alicloud/pop-core`)[点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/%E4%B8%8A%E4%BC%A0%20%E4%BA%91%E5%82%A8%E5%AD%98%E6%88%96%E9%98%BF%E9%87%8C%E4%BA%91OSS?sort_id=3673784) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.9.2(2021-04-19) +### 更新内容 +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +#### 【优化】`vk.selects` 支持主表外键是数组的情况下(如`uni-id-users`表的`role`字段)连表查出`roleList` [点击查看场景5](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3028633&doc_id=975983) +#### 1、【重要】【全网首家】`云函数url化` 支持以纯链接形式访问路由后的云函数 如: `https://xxx.bspapp.com/http/router/client/user/pub/findGoodsInfo?id=1` +#### 2、【重要】【全网首家】`云函数url化` 支持URL重写 [点击查看URL重写详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3916806&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.9.1(2021-04-16) +### 更新内容 +#### 【优化】`vk.selects` 支持主表外键是数组的情况下(如`uni-id-users`表的`role`字段)连表查出`roleList` [点击查看场景5](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3028633&doc_id=975983) + +## 1.9.0(2021-04-15) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】`vk.selects` 支持返回树状结构 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3906510&doc_id=975983) +#### 2、【新增】`vk.pubfn.deepClone` 深度克隆(与`vk.pubfn.copyObject`的区别:可以克隆函数) +#### 3、【优化】`vk.setData` 内部逻辑 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 1.8.24(2021-04-13) +### 更新内容 +#### 1、【调整】`vk.request`默认的`header`与官方对其(之前默认是`{"content-type": "application/json; charset=UTF-8"}`) +#### 2、【优化】`uni-id` 模式调整为:兼容单实例多并发模式 +## 1.8.23(2021-04-12) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +####【优化】云函数中 `vk.request`新增参数`needOriginalRes` 默认为`false`,若为`true`,则会返回原始数据(包含请求头等数据) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 1.8.22(2021-04-07) +### 更新内容 +####【修复】`console.log`在小程序端可能会无法打印出代码所在位置的问题。 +## 1.8.21(2021-04-07) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +### 1、【优化】如需要在云函数中主动抛出异常,且能让前端框架自动识别后进行alert弹窗提示,则可使用以下方式 +```js +// 注意: 必须以msg:为前缀,否则框架无法识别(只支持字符串) +throw new Error("msg:这里是错误的提示"); +``` +#### 2、【新增】`app.config.js` 新增 `tokenExpiredAutoDelete` 属性,默认`true` 若设为`false`,则`token`失效时,依然保留前端的`token缓存`。 +``` +官方原生语法中,连表查询和非连表查询在使用`_.geoNear`时用较大差别; +而 vk.baseDao.selects(万能连表)写法跟 vk.baseDao.select(单表查询) 写法保持统一,使上手更简单。 +``` +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.8.20(2021-03-29) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +####【优化】`vk.baseDao.selects` 支持`_.geoNear`API(将记录按照离给定点从近到远输出。)[点击查看万能连表场景4](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3028633&doc_id=975983) +``` +官方原生语法中,连表查询和非连表查询在使用`_.geoNear`时用较大差别; +而 vk.baseDao.selects(万能连表)写法跟 vk.baseDao.select(单表查询) 写法保持统一,使上手更简单。 +``` +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.8.19(2021-03-27) +### 更新内容 +#### 1、【新增】`百度开放平台API接口` (营业执照识别、身份证识别等) [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3803034&doc_id=975983) +#### 2、【优化】`kh`目录下的函数默认会获取 `userInfo`(当前登录用户信息),如果此云函数不需要用户信息,可以在前端多传一个参数`need_user_info:false` 可以减少一次数据库查询(加快响应速度)(快100ms左右) [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3790840&doc_id=975983) +#### 3、【优化】`returnUserInfoFilter` 过滤器的内部逻辑 +#### 4、【优化】`vk.callFunction` 新增参数 `needAlert`(默认为true) 来代替 `noAlert`(默认为false) 二选一即可(建议后面都使用`needAlert`参数,它更语义化) + +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.8.18(2021-03-24) +### 更新内容 +#### 1、【重要】`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3541759&doc_id=975983) +#### 2、【新增】`vk.pubfn.timeUtil.isLeapYear` 判断是否是闰年 +#### 3、【新增】`vk.pubfn.timeUtil.isQingming` 判断是否是清明节 +#### 4、【新增】清明节灰色页面实现方案 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3782115&doc_id=975983) +```js +/** + * 判断是否是闰年 + * @param {Number | Date} year 需要计算的年份或时间,默认使用当前时间的年份 + */ +vk.pubfn.timeUtil.isLeapYear(2021); +/** + * 判断是否是清明节 + * @param {Object} date 时间对象 + */ +vk.pubfn.timeUtil.isQingming(new Date()); +``` +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + + +## 1.8.17(2021-03-20) +### 更新内容 +#### 【优化】`vk.userCenter.code2SessionWeixin` 的内部逻辑。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.8.16(2021-03-20) +### 更新内容 +#### 1、【优化】`vk.callFunctionUtil.uploadFile` 新增参数 `suffix`,可直接自定义文件后缀名 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3673784&doc_id=975983) + +## 1.8.15(2021-03-19) +### 更新内容 +#### 1、【修复】微信小程序服务端API在保存`token`时,缓存时间错误的问题。 +#### 2、【修复】`vk.callFunctionUtil.uploadFile` 上传视频返回`.png`的问题 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3673784&doc_id=975983) + +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.8.14(2021-03-19) +### 更新内容 +#### 【新增】APP本机号码一键登录API `vk.userCenter.loginByUniverify` +## 1.8.13(2021-03-17) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【优化】在安装了`vuex`后,移除了名为`uni_id_user_info`的本地缓存(重复了)(`userInfo`使用`vk.getVuex('$user.userInfo')`获取) +#### 2、【修复】微信小程序服务端API在获取`token`时,没有正确使用缓存的问题。 + +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.8.12(2021-03-12) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】现在可以在js文件中直接通过 `uni.vk` 来使用 `vk` 对象内的API +#### 2、【新增】`app.config.js` 新增参数 `checkSharePages` 控制页面是否可以被小程序分享 +#### 3、【优化】发行模式下,`console.log` 将不会打印任何日志。 +```js +若发行模式下需要强制打印,可用 `vk.log` 代替 `console.log` +``` +## 1.8.11(2021-03-10) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【新增】`vk.callFunctionUtil.uploadFile` 支持前端直传至`阿里云oss` [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3673784&doc_id=975983) +#### 2、【新增】`app.config.js` 新增 `myfn` 参数,可用来拓展自定义公共函数 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3673929&doc_id=975983) + +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.8.10(2021-03-06) +### 更新内容 +#### 【优化】`vk.setVuex` 和 `vk.setData` 的赋值逻辑 +```js +如数据源$data +{ + a:1, + b:"1", +}; +执行 vk.setVuex("$data.a.b.c",1); +结果: +{ + a:{ + b:{ + c:1 + } + }, + b:"1" +} +``` +## 1.8.9(2021-03-05) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【新增】`vk.openapi.weixin.subscribeMessage.send` 微信小程序发送订阅消息 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3569379&doc_id=975983) +#### 2、【优化】`vk.baseDao.add` 和 `vk.baseDao.adds` 新增参数 `cancelAddTime` 为`true`,则不会有`_add_time`和`_add_time_str`字段生成 +#### 3、【优化】`vk.baseDao.add` 和 `vk.baseDao.adds` 支持添加自定义 `_id` + +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 1.8.8(2021-03-04) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 【重要】`vuex` 的使用方式有较大更新。(有性能提升)[点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3654596&doc_id=975983) + +## 1.8.7(2021-02-24) +### 更新内容 +#### 【修复】`vk.openapi.weixin.auth.code2Session` 会报`vk is not defined`的错误。 + +## 1.8.6(2021-02-24) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 【修复】`vk.baseDao.deleteById` 会报`vk is not defined`的错误。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 1.8.5(2021-02-23) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 【优化】`vk.baseDao.selects` 支持副表与副表的副表进行连表 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3028633&doc_id=975983) +``` +1.1、支持无限张副表和主表进行连接(横向无限张表) +1.2、支持副表与副表的副表进行连接(竖向无限层连接) +``` + + + +## 1.8.4(2021-02-16) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 微信小程序服务端API [点击查看文档](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3569379&doc_id=975983) +#### 1、【新增】`获取AccessToken` : `vk.openapi.weixin.auth.getAccessToken` +#### 2、【新增】`code换取openid` : `vk.openapi.weixin.auth.code2Session` +#### 3、【新增】`获取微信绑定的手机号` : `vk.openapi.weixin.decrypt.getPhoneNumber` +#### 4、【新增】`文本违规检测` : `vk.openapi.weixin.security.msgSecCheck` +#### 5、【新增】`图片违规检测` : `vk.openapi.weixin.security.imgSecCheck` +#### 6、【新增】`获取小程序码` : `vk.openapi.weixin.wxacode.getUnlimited` +#### 7、【新增】`小程序Scheme码` : `vk.openapi.weixin.urlscheme.generate` + +## 1.8.3(2021-02-11) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 【优化】`main.js` 代码结构。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 1.8.2(2021-02-08) +### 支持 `uni-pay` 模块 +## 1.8.1(2021-02-08) +### 优化插件目录结构 +完整框架项目地址:https://ext.dcloud.net.cn/plugin?id=2204 +## 1.8.0(2021-02-07) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】升级至`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/1.8%E4%BB%A5%E4%B8%8B%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%E8%87%B31.8%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97%20%E5%8D%87%E7%BA%A7%E6%88%90%20uni_modules%E7%89%88%E6%9C%AC?sort_id=3541759) +#### 2、【重要】本次更新文件有重大改动,升级成功后将变成`uni_modules`版本,下次更新框架只需要在hbx编译器中一键更新。 +#### 3、【新增】【小程序API】`vk.userCenter.loginByWeixinPhoneNumber` 前端可以使用微信小程序一键进行手机号登录 +#### 4、【新增】【小程序API】`vk.userCenter.getPhoneNumber` 前端一键获取微信小程序绑定的手机号 +#### 5、【新增】【小程序API】`vk.openapi.weixin.decrypt.getPhoneNumber` 云函数解析微信小程序绑定的手机号 +#### 6、【新增】【小程序API】`vk.userCenter.getWeixinMPqrcode` 前端一键生成带参数的小程序码 +#### 7、【新增】【小程序API】`vk.userCenter.getWeixinMPscheme` 前端一键生成带参数的小程序scheme码(支持从手机短信跳转到小程序) +#### 8、【优化】`middleware/modules/returnUserInfoFilter` 中间件的处理逻辑。 +#### 9、【优化】`javascript代码块提示.json` 输入`vk.`可以快速提示代码块 `根目录/使用帮助/代码快捷提示` + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】升级至`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/1.8%E4%BB%A5%E4%B8%8B%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%E8%87%B31.8%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97%20%E5%8D%87%E7%BA%A7%E6%88%90%20uni_modules%E7%89%88%E6%9C%AC?sort_id=3541759) +#### 2、【重要】本次更新文件有重大改动,升级成功后将变成`uni_modules`版本,下次更新框架只需要在hbx编译器中一键更新。 +#### 3、【新增】【小程序API】`vk.userCenter.loginByWeixinPhoneNumber` 前端可以使用微信小程序一键进行手机号登录 +#### 4、【新增】【小程序API】`vk.userCenter.getPhoneNumber` 前端一键获取微信小程序绑定的手机号 +#### 5、【新增】【小程序API】`vk.openapi.weixin.decrypt.getPhoneNumber` 云函数解析微信小程序绑定的手机号 +#### 6、【新增】【小程序API】`vk.userCenter.getWeixinMPqrcode` 前端一键生成带参数的小程序码 +#### 7、【新增】【小程序API】`vk.userCenter.getWeixinMPscheme` 前端一键生成带参数的小程序scheme码(支持从手机短信跳转到小程序) +#### 8、【优化】`middleware/modules/returnUserInfoFilter` 中间件的处理逻辑。 +#### 9、【优化】`javascript代码块提示.json` 输入`vk.`可以快速提示代码块 `根目录/使用帮助/代码快捷提示` + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 \ No newline at end of file diff --git a/uni_modules/vk-unicloud/components/vk-data-verification-code/vk-data-verification-code.vue b/uni_modules/vk-unicloud/components/vk-data-verification-code/vk-data-verification-code.vue new file mode 100644 index 0000000..bc06dfd --- /dev/null +++ b/uni_modules/vk-unicloud/components/vk-data-verification-code/vk-data-verification-code.vue @@ -0,0 +1,320 @@ + + + + + diff --git a/uni_modules/vk-unicloud/index.js b/uni_modules/vk-unicloud/index.js new file mode 100644 index 0000000..63d85e3 --- /dev/null +++ b/uni_modules/vk-unicloud/index.js @@ -0,0 +1,7 @@ +/** + * vk-unicloud框架客户端(前端) + * author VK + */ +import vk from './vk_modules/vk-unicloud-page' + +export default vk; \ No newline at end of file diff --git a/uni_modules/vk-unicloud/package.json b/uni_modules/vk-unicloud/package.json new file mode 100644 index 0000000..ef506ef --- /dev/null +++ b/uni_modules/vk-unicloud/package.json @@ -0,0 +1,86 @@ +{ + "id": "vk-unicloud", + "displayName": "vk-unicloud-router开发框架核心库 - 已集成uni-id 框架内置了众多API。", + "version": "2.15.3", + "description": "此为vk-unicloud-router框架核心库(新手建议下载完整框架项目)已集成uni-id支持云函数url化。众多现成API,内置小白也能轻松上手的数据库API。使你项目刚起步进度就是百分之50", + "keywords": [ + "vk-unicloud-router", + "云函数路由、云对象路由", + "vk云开发", + "内置uni-id、uview、数据库baseDao", + "内置众多API、工具包" +], + "author": "VK", + "repository": "https://gitee.com/vk-uni/vk-uni-cloud-router", + "engines": { + "HBuilderX": "^3.1.0" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "370725567" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "无" + }, + "npmurl": "https://vkdoc.fsq.pub/", + "type": "unicloud-template-function" + }, + "uni_modules": { + "dependencies": ["uni-config-center","uni-id"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "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", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "u" + } + } + } + } +} diff --git a/uni_modules/vk-unicloud/readme.md b/uni_modules/vk-unicloud/readme.md new file mode 100644 index 0000000..231ce94 --- /dev/null +++ b/uni_modules/vk-unicloud/readme.md @@ -0,0 +1,572 @@ +### uniCloud云函数路由框架研究Q群:22466457 如有问题或建议可以在群内讨论。 +### 插件名称:`vk-unicloud-router` +### 作者:VK + +## 序 +##### 如果你热爱编程,想快速入门云开发,欢迎使用`vk-unicloud`系列开发框架 +##### 无需转变开发习惯,0成本上手云开发。 +##### 框架内置了众多API、工具包,为你的业务扫平障碍。使你的项目刚起步进度就是50%(微信登录、短信、验证码、缓存、生成小程序码等等) +##### 从此你又get一个新技能,只需用js,轻松搞定前后台整体业务。 +##### 完整框架项目地址: +##### `client端`框架地址: [https://ext.dcloud.net.cn/plugin?id=2204](https://ext.dcloud.net.cn/plugin?id=2204) +##### `admin端`框架地址:[https://ext.dcloud.net.cn/plugin?id=5043](https://ext.dcloud.net.cn/plugin?name=vk-unicloud-admin) +##### `client端`框架文档:[点击查看](https://vkdoc.fsq.pub/client/) +##### `admin端`框架文档:[点击查看](https://vkdoc.fsq.pub/admin/) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +## 主要功能 以及 对开发者的价值 +#### 1、实现云函数路由模式(同时支持对云对象的路由) +* 1.1、路由模式不使用任何第三方包,兼容性强,运行稳定 +* 1.2、减少云函数数量,云函数有个数限制(用一个云函数即可实现多个云函数效果) +* 1.3、部分通用的代码块可以放在公共区执行,具有公共函数的效果,增加代码复用率,便于维护。 +* 1.4、可以在开发环境和生产环境中任意切换,开发时,用开发环境,开发过程中不会影响到线上环境。(具体切换方法在文档最后) +* 1.5、美化云函数请求过程中的日志排版,使请求日志一目了然。(再也不用为日志分散,难找而头疼) +* 1.6、可以强制关闭云端服务(适用于需要临时关闭后端服务的情况,如腾讯云迁移数据到阿里云时需要先关闭服务,否则迁移过程中会有新数据产生) + +#### 2、实现 `全局过滤器`,过滤非法请求。您无需关心用户角色权限问题。 + +#### 3、众多现成的 `JS API`,让您无需重复造轮子。(持续增加中) + +#### 4、众多现成的 `云函数 API`,为您的业务扫平障碍,让您可以专注于自身业务开发。(微信登录、短信、验证码、缓存、生成小程序码等等)(持续增加中) + +#### 5、全面支持 `url化` 的云函数请求,您无需关心url化后参数的获取问题 + +#### 6、已集成 `uni-id` 当前版本: `3.3.28`(已支持真实发送邮箱验证码和短信验证码) +* 6.1、由于每个应用基本都会用上用户系统,官方建议所有 `uniCloud` 应用均使用 `uni-id` 作为用户体系, +有了统一的账户规范,并且围绕这套账户规范,有各种各样插件,那么开发者可以随意整合这些插件,让数据连同。 + +* 6.2、同时方便其他用户使用 `unicloud` 插件发布者发布的前后端一体插件,只需要导入一个云函数即可。 +(如导入一个社区插件,可能要导入几十个云函数,而使用此云函数路由后,只需导入一个云函数,且已集成 `uni-id`,打通账号体系)。 + +#### 7、在 `uni-id` 基础上升级为 `vk.userCenter` 用户中心API 通过this.vk.userCenter 即可调用 [传送门](https://vkdoc.fsq.pub/client/vk.userCenter.html) + +#### 8、封装 `uni.callFunction` 和 `uni.request` 使之合二为一 通过this.vk.callFunction 调用 + +#### 9、`vk.baseDao` 数据库API,使小白也能轻松上手对数据库的调用。 [传送门](https://vkdoc.fsq.pub/client/uniCloud/db/api.html) + +#### 10、`vk.baseDao.selects` 数据库万能连表查询API [传送门](https://vkdoc.fsq.pub/client/uniCloud/db/selects.html) + +#### 11、`商品SKU选择器组件`(打造uni插件市场功能最全的SKU选择器组件)[传送门](https://ext.dcloud.net.cn/plugin?id=2848) + +#### 12、对 `Vuex` 进行了深度封装(支持持久化),现在可以很方便的使用Vuex进行读取和储存。[传送门](https://vkdoc.fsq.pub/client/pages/vuex.html) + +#### 13、自定义过滤器(在业务云函数执行之前(或之后),统一拦截,进行过滤后再放行,支持设置多个过滤器,并按指定顺序执行)[传送门](https://vkdoc.fsq.pub/client/uniCloud/middleware/filter.html) + +#### 14、支持设置需要登录的页面列表或不需要登录的页面列表(通过本地token检测,无网络请求,支持通配符写法)[传送门](https://vkdoc.fsq.pub/client/pages/config.html) + +#### 15、支持设置可以被分享的页面列表或禁止分享的页面列表(支持通配符写法)[传送门](https://vkdoc.fsq.pub/client/pages/config.html) + +#### 16、`vk.localStorage` 封装本地缓存的curd,同时具有监听缓存被更新和被删除的功能。[传送门](https://vkdoc.fsq.pub/client/pages/localStorage.html) + +#### 17、美化云函数请求过程中的日志排版,使请求日志一目了然。 + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/4a44fbf8-6b5e-43a6-b443-51a108dec125.png) + +#### 18、可以 `强制关闭` 云端服务(适用于需要临时关闭后端服务的情况,如腾讯云迁移数据到阿里云时需要先关闭服务,否则迁移过程中会有新数据产生) + +#### 19、全局数据缓存API,现在可以很方便的在云函数中使用缓存。 [传送门](https://vkdoc.fsq.pub/client/uniCloud/cache/cache.html) + +#### 20【全网首家】云函数URL化之URL重写 [传送门](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/urlrewrite.html) + +#### 21、千人群交流开发心得,助你避坑,作者亲自在群内解答框架使用问题,让你轻松上手 `uniCloud云开发`。 + +#### 22、其他好处… + +### 目前已集成的服务端API + +#### 1、微信小程序服务端API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html) + +#### 2、微信公众号服务端API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin-h5.html) + +#### 3、百度开放平台服务端API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/baidu.html) + +#### 4、短信发送 [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/sms.html) + +#### 5、邮箱发送 [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/mail.html) + +#### 6、Redis [传送门](https://vkdoc.fsq.pub/vk-redis/) + +##### 插件部分API功能体验地址 + +![插件首页体验地址](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-vk-cloud-router-test/51de83e0-e9ae-11ea-81ea-f115fe74321c.png?x-oss-process=image/resize,h_250 "插件首页体验地址") + +## 快速上手 - 安装步骤 + +## 后端(云函数端)安装步骤 +打开 `uniCloud/cloudfunctions` 目录 + +#### 前置工作:修改云函数全局配置文件(用到微信登录的必须要配置)[微信小程序配置详细教程](https://vkdoc.fsq.pub/client/question/q12.html) +#### 注意: +* 1、开发微信小程序和APP微信登录需要额外配置 manifest.json 以及 uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json 这2个配置文件,且改动配置后需要重新上传 公共模块 和 router 函数。 +* 2、若你的电脑没有安装 Node.js,则无法使用 npm 命令。 +* 3、Node.js 安装包及源码下载地址为:[https://nodejs.org/en/download/](https://nodejs.org/en/download/) +* 4、Node.js 安装教程:[https://www.runoob.com/nodejs/nodejs-install-setup.html](https://www.runoob.com/nodejs/nodejs-install-setup.html) + +查看 `uni-id/config.json` 代码格式 [点击查看](https://vkdoc.fsq.pub/client/uniCloud/config/uni-id.html) + + +#### 正式安装 + +直接右键`uniCloud`目录 点击 `运行云服务空间初始化向导` 即可 + +## 前端(页面端)安装步骤 + +### Vue2.0版本 + +`main.js` 引入 `vk-unicloud-page` 库 + +```js +// 引入 vk框架前端 +import vk from './uni_modules/vk-unicloud'; +Vue.use(vk); +``` + +完整 `main.js` 示例 + +```js +import Vue from 'vue' +import App from './App' +import store from './store' +import config from '@/app.config.js' + +// 引入 vk框架前端 +import vk from './uni_modules/vk-unicloud'; +Vue.use(vk); + +// 初始化 vk框架 +Vue.prototype.vk.init({ + Vue, // Vue实例 + config, // 全局配置 +}); + +Vue.config.productionTip = false + +App.mpType = 'app' + +const app = new Vue({ + store, + ...App +}); +app.$mount(); + +``` + +### Vue3.0版本 + +`main.js` 引入 `vk-unicloud-page` 库 + +完整 `main.js` 示例 + +```js +import App from './App' +import store from './store' +import config from '@/app.config.js' + +// 引入 vk框架前端 +import vk from './uni_modules/vk-unicloud'; + +import { createSSRApp } from 'vue' + +export function createApp() { + const app = createSSRApp(App) + + // 使用 vuex + app.use(store) + + // 使用 vk框架前端 + app.use(vk); + + // 初始化 vk框架 + app.config.globalProperties.vk.init({ + Vue: app, // Vue实例 + config, // 配置 + }); + + return { app } +} +``` + +### 自 client端框架 2.6.0 起,不再内置任何 UI 框架,你可以选择自己喜欢的 UI 组件库进行开发。 + +### 集成 `vk-uview-ui`(vue2.0版) + +___若不想集成 `vk-uview-ui` 可跳过此处___ + +适合开发:H5、App(vue版本)、微信小程序、支付宝小程序(其他小程序未验证) + +> 插件市场导入 `vk-uview-ui` 框架:[点击前往](https://ext.dcloud.net.cn/plugin?id=6692) + +* 1、main.js 引入 vk-uview-ui + +```js +import uView from './uni_modules/vk-uview-ui'; +Vue.use(uView); +``` + +* 2、App.vue 引入基础样式(注意style标签需声明scss属性支持) + +```html + +``` + +* 3、uni.scss 引入全局 scss 变量文件 + +```css +@import "@/uni_modules/vk-uview-ui/theme.scss"; +``` + + +### 集成 `vk-uview-ui`(vue3.0版) + +___若不想集成 `vk-uview-ui` 可跳过此处___ + +适合开发:H5、App(vue版本)、微信小程序(其他小程序未验证) + +> 插件市场导入 `vk-uview-ui` 框架:[点击前往](https://ext.dcloud.net.cn/plugin?id=6692) + +不建议把老项目 升级到 Vue3.0 (升级非常麻烦,建议新项目才考虑是否使用Vue3.0) + +___注意:目前(2020-11-18) `uniapp` 的 `Vue3.0` 版本只兼容:H5、App、微信小程序___ + +* 1、前置步骤:修改 `manifest.json` 内的 `vue` 版本为 `vue3` +* 2、项目根目录新增 `index.html` 文件,文件代码为 +```html + + + + + + + + + + + + +
+ +
+ + + +``` + +* 3、main.js 引入 vk-uview-ui + +```js +// 引入 uView UI +import uView from './uni_modules/vk-uview-ui'; + +import { createSSRApp } from 'vue' + +export function createApp() { + const app = createSSRApp(App) + + // 使用 uView UI + app.use(uView) + + return { app } +} + +``` + +* 4、App.vue 引入基础样式(注意style标签需声明scss属性支持) + +```html + +``` + +* 5、uni.scss 引入全局 scss 变量文件 + +```css +@import "@/uni_modules/vk-uview-ui/theme.scss"; +``` + + +### 集成 `uview-ui`(nvue2.0版) + +___若不想集成 `uview-ui` 可跳过此处___ + +适合开发:App(nvue版本),如果你只开发App,推荐用这个UI + +> 插件市场导入 `uview-ui` 框架:[点击前往](https://ext.dcloud.net.cn/plugin?id=1593) + +* 1、main.js 引入 uview-ui + +```js +import uView from './uni_modules/uview-ui'; +Vue.use(uView); +``` + +* 2、App.vue 引入基础样式(注意style标签需声明scss属性支持) + +```html + +``` + +* 3、uni.scss 引入全局 scss 变量文件 + +```css +@import "@/uni_modules/uview-ui/theme.scss"; +``` + +### 集成 `uview-ui`(nvue3.0版) + +别想了,uniapp官方也还没支持。 + +### 组件库并不限制只能从以上选择,理论上支持任何UI组件库进行开发。 + +### 卸载 `uView1` 的步骤 + +* 1、main.js 删除 uView1 + +```js +import uView from 'uview-ui' +Vue.use(uView); +``` + +* 2、App.vue 删除基础样式 + +```html + +``` + +* 3、uni.scss 删除全局 scss 变量文件 + +```css +@import "uview-ui/theme.scss"; +``` + +* 4、pages.json 删除 easycom 规则 + +```js +"easycom": { + "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue", +}, +``` + +* 5、package.json 删除 uview-ui 依赖 + +```js +"dependencies": { + "uview-ui": "^1.8.3" +}, +``` + +* 6、package-lock.json 删除 uview-ui 依赖 + +```js +"dependencies": { + "uview-ui": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-1.8.3.tgz", + "integrity": "sha512-DqKc+qRrOZLPcyfWv4b0HspSS9n1Cd6BbgKiYEv9rjTAnWoqJV7rXsvWqZdr5iKGP5EMNbNS741GLNw4sIHbpw==" + } +} +``` + +### 完整安装文档:[查看完整安装文档](https://vkdoc.fsq.pub/client/quickstart.html) + +## 云函数框架目录结构 + +``` +. +├── common─────────────────# 自定义官方公共模块包 +│ └── config──────────────────# 全局配置公共模块 +│ └── uni-id──────────────────# uni-id官方公共模块 +│ └── vk-unicloud─────────────# vk-unicloud公共模块 +├── router─────────────────# 正式环境云函数主入口(函数路由器) +│ └── dao──────────────────# dao层(数据库交互公共API) +│ └── middleware───────────# 中间层(过滤器、拦截器) +│ └── node_modules─────────# npm包 +│ └── service──────────────# 逻辑层(用于写业务逻辑) +│ ── └── 逻辑层目录结构在下方单独展示 +│ └── util─────────────────# 工具包 +│ ── └── pubFunction.js───────# 公共函数包 +│ ── └── smsUtil.js───────────# 全局过滤器 +│ └── config.js────────────# 入口函数初始化配置 +│ └── index.js─────────────# 入口函数 +│ └── package.json─────────# 第三方依赖配置文件(若使用npm,自动生成) +└─└── package-lock.json────# 第三方依赖配置文件(若使用npm,自动生成) +. +├── router-test───────────────# 函数路由(开发测试环境) +│ └── ...─────────# ... +│ └── ...─────────# ... +└── └── ...─────────# ... +``` + +### 逻辑层目录结构 +#### `router/service` 目录为逻辑层 +#### 以下的目录并非强制性,只是建议,便于统一开发规范。 + +``` +. +├── service──────────────────────# 逻辑层(用于写业务逻辑) +│ └── admin────────────────# 后台管理端逻辑(admin框架开发中。。。) +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ └── client───────────────# 客户端逻辑(H5、小程序、APP) +│ ── └── user─────────────────# 用户服务(自己系统的逻辑) +│ ──── └── kh───────────────────# kh函数为必须登录后才能访问的函数 +│ ──── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ──── └── util─────────────────# 用户服务专用的工具包 +│ ── └── order────────────────# 订单服务(自己系统的逻辑) +│ ──── └── kh───────────────────# kh函数为必须登录后才能访问的函数 +│ ──── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ──── └── util─────────────────# 订单服务专用的工具包 +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ └── common───────────────# 公共逻辑(公共接口) +│ ── └── xxxxxxxxxxxxxxxx─────# +│ ── └── xxxxxxxxxxxxxxxx─────# +│ ── └── xxxxxxxxxxxxxxxx─────# +│ └── user─────────────────# 统一用户中心服务(已集成uniID)(用户中心作为核心,且为了方便插件升级,故与admin和client平级) +│ ── └── kh───────────────────# kh函数为必须登录后才能访问的函数(客户端用户) +│ ── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ── └── sys──────────────────# sys函数为后端管理人员才能访问的函数(商家后台工作人员) +│ ── └── util─────────────────# 统一用户中心服务专用的工具包 +│ └── plugs───────────────# 插件逻辑(插件专用)(会陆续新增一些实用性插件给开发者使用,如微信小程序发送订阅消息等等) +│ ──└── plugs-A───────────────────# 插件A +│ ────└── admin───────────────────# 插件A admin端 +│ ────└── client──────────────────# 插件A client端 +│ ──└── plugs-B───────────────────# 插件B +│ ────└── admin───────────────────# 插件B admin端 +│ ────└── client──────────────────# 插件B client端 +│ └── template─────────────# 云函数模板(插件内的云函数写法模板) +│ ── └── db_api───────────────# 数据库接口调用模板 +│ └── muban.js─────────────# 云函数模板(新建一个云函数应复制粘贴这个文件) +│ └── muban_easy.js────────# 云函数模板(简易版) +└───────────────────────────────── +``` + + +## 云函数service模板文件示例 +```js +module.exports = { + /** + * 此函数名称 + * @url user/sys/test1 前端调用的url参数地址 + * @description 此函数描述 + * @param {Object} data 请求参数 + * @param {String} uniIdToken 用户token + * @param {String} userInfo 当前登录用户信息(同理,是可信任的)(只有kh函数才带此参数) + * @param {Object} util 公共工具包 + * @param {Object} filterResponse 过滤器返回的数据 + * @param {Object} originalParam 原始请求参数(包含了原始event和context) + * data 请求参数 说明 + * @param {String} uid 当前登录用户id,若用户已登录且token有效,则data中会带uid参数 + * (此参数是后端过滤器通过token获取并添加到data中的,是可信任的)(只有kh函数才带此参数) + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} +``` +#### 成功时返回 +```js +// 注意:所有成功请求必须返回code:0 code为其他值,代表失败,如兑换失败,您的积分不足! +// 如成功时返回 res.code = 0 表示执行成功; +return { + code : 0, + msg : '兑换成功!' +} +``` +#### 失败时返回 +```js +return { + code : -1, + msg : '兑换失败,您的积分不足!' +} + +``` + +## this.vk.callFunction函数的参数说明 +```js +/** + * 云函数请求封装 - 统一入口 + * @description 通过云函数路由,1个云函数实现多个云函数的效果。 + * @param {String} url 请求路径,该路径实为router云函数的service目录下的路径 + * @param {Object} data 请求参数 + * @param {String} title 遮罩层提示语,为空或不传则代表不显示遮罩层。 + * @param {Boolean} isRequest 是否使用云函数url化地址访问云函数,默认false + * @param {Boolean} needAlert 为true代表请求错误时,会有alert弹窗提示。默认为true + * @param {Function} success 请求成功时,执行的回调函数 + * @param {Function} fail 请求失败时,执行的回调函数 + * @param {Function} complete 无论请求成功与否,都会执行的回调函数 + */ +``` + + +## 前端调用云函数示例 + +```js + +this.vk.callFunction({ + url: 'user/kh/setAvatar', + title:'请求中...', + data:{ + avatar: "https://xxxxxxx.jpg" + }, + success(data) { + // 修改成功 + } +}); + +``` + +## 云函数url化方式调用云函数示例 + +[点击查看『云函数url化』方式调用云函数示例](https://vkdoc.fsq.pub/client/pages/callFunctionForUrl.html) + +## 前端非法token拦截器 + +[点击查看『前端非法token拦截器』](https://vkdoc.fsq.pub/client/pages/interceptor1.html) + +## vk.baseDao数据库API + +[点击查看『vk.baseDao』数据库API](https://vkdoc.fsq.pub/client/uniCloud/db/api.html) + +## 设置全局请求参数 + +[点击查看『设置全局请求参数』](https://vkdoc.fsq.pub/client/pages/updateRequestGlobalParam.html) + +## 列表渲染前后端一体模板 + +[点击查看『列表渲染』前后端一体模板](https://vkdoc.fsq.pub/client/pages/list.html) + +## 商品SKU选择器组件 + +[点击查看『商品SKU选择器组件』](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=2912199&doc_id=975983) + +## 如何切换 正式环境 和 开发环境 + +[点击查看如何『切换正式环境和开发环境』](https://vkdoc.fsq.pub/client/question/q1.html) + +## 本插件更新步骤 +[点击查看本插件『更新步骤』](https://vkdoc.fsq.pub/client/changeGuide.html) + +## uniCloud云函数路由框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 \ No newline at end of file diff --git a/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/LICENSE.md b/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/LICENSE.md new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/LICENSE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/index.js b/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/index.js new file mode 100644 index 0000000..4db5060 --- /dev/null +++ b/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/index.js @@ -0,0 +1 @@ +"use strict";function _interopDefault(e){return e&&"object"==typeof e&&"default"in e?e.default:e}var crypto$1=_interopDefault(require("crypto")),commonjsGlobal="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},util={regExpTest:function(e,t){let n=!1;if("string"==typeof e){new RegExp(e).test(t)&&(n=!0)}else if("object"==typeof e)for(let i=0;i{let{serviceParam:t,middlewareService:n=[]}=e,i={code:403,msg:"access denied",filterStack:[]},{url:a}=t;for(let e in n){let r=n[e],{mode:o="onActionExecuting",enable:s=!0}=r;if(s&&"onActionExecuting"===o&&util_1.regExpTest(r.regExp,a)){t.filterResponse=i;let e=await r.main(t);if(e.filterId=r.id,i.filterStack.push(e),0!==e.code){i=e;break}i=Object.assign(i,e)}}return i},onActionExecuted=async(e={})=>{let{serviceParam:t,middlewareService:n=[],serviceRes:i}=e,{url:a}=t;for(let e in n){let r=n[e],{mode:o,enable:s=!0}=r;if(s&&"onActionExecuted"===o&&util_1.regExpTest(r.regExp,a)){let e=await r.main(t,i);if(e){if(0!==e.code){i=e;break}i=Object.assign(i,e)}}}return i},onActionIntercepted=async(e={})=>{let{serviceParam:t,middlewareService:n=[],filterResponse:i}=e,{url:a}=t;for(let e in n){let r=n[e],{mode:o,enable:s=!0}=r;if(s&&"onActionIntercepted"===o&&util_1.regExpTest(r.regExp,a)){let e=await r.main(t,i);if(e){if(0!==e.code){i=e;break}i=Object.assign(i,e)}}}return i},onActionError=async(e={})=>{let{serviceParam:t,middlewareService:n=[],serviceRes:i}=e,{url:a}=t;for(let e in n){let r=n[e],{mode:o,enable:s=!0}=r;if(s&&"onActionError"===o&&util_1.regExpTest(r.regExp,a)){let e=await r.main(t,i);if(e){if(0!==e.code){i=e;break}i=Object.assign(i,e)}}}return i},checkIsLogin={main:async e=>{let{url:t,data:n={},util:i}=e,{uniID:a}=i,{need_user_info:r}=n,o={code:-1,msg:""};void 0===r&&(r=-1==t.indexOf("."));let s=0==t.indexOf("admin/");s&&(r=!0),(t.indexOf("sys.")>-1||t.indexOf("sys_")>-1||t.indexOf("/sys")>-1)&&(r=!0);let u=t.indexOf("/sys/")>-1,l=await a.checkToken(e.uniIdToken,{needPermission:u,needUserInfo:r});if(l.code&&l.code>0)return l;if(l.userInfo){let e=l.userInfo;e.permission=l.permission,delete e.token,delete e.password,o.userInfo=e}if(o.uid=l.uid,l.token&&(o.token=l.token,o.tokenExpired=l.tokenExpired),s){if(!o.userInfo)return{code:403,msg:"need_user_info必须为true"};{let e=o.userInfo.role||[];if(!o.userInfo.allow_login_background&&!e.includes("admin"))return{code:403,msg:"您无权限登录后台"}}}return o.code=0,o.msg="ok",o}},checkSysAuth={main:async e=>{let{url:t,util:n}=e,{uniID:i,config:a,pubFun:r,vk:o,db:s,_:u}=n,l={code:-1,msg:""};const c=checkIsLogin;if(l=await c.main(e),0!==l.code)return l;if(!l.userInfo)return{code:403,msg:"请去除need_user_info:false"};if(l.userInfo.role||(l.userInfo.role=[]),l.userInfo.role.includes("admin"))return l;if(!l.userInfo.allow_login_background&&0==t.indexOf("admin/"))return{code:403,msg:"您无权限登录后台"};let d=[];if(l.userInfo.role.includes("admin-lv3")){let e=await listPermission({whereJson:{level:u.in([1,2,3])},justNeedID:!0},n);o.pubfn.isNotNull(e)&&(d=d.concat(e))}if(l.userInfo.role.includes("admin-lv2")){let e=await listPermission({whereJson:{level:u.in([1,2])},justNeedID:!0},n);o.pubfn.isNotNull(e)&&(d=d.concat(e))}if(l.userInfo.role.includes("admin-lv1")){let e=await listPermission({whereJson:{level:u.in([1])},justNeedID:!0},n);o.pubfn.isNotNull(e)&&(d=d.concat(e))}if(l.userInfo.role.includes("query-all")){let e=await listPermission({whereJson:{curd_category:4,level:u.neq(4)},justNeedID:!0},n);o.pubfn.isNotNull(e)&&(d=d.concat(e))}let p=await listRole({role:l.userInfo.role},n);for(let e in p){let{permission:t}=p[e];o.pubfn.isNotNull(t)&&(d=d.concat(t))}if(0==d.length)return{code:403,msg:"权限不足"};d=[...new Set(d)];let f=await listPermission({whereJson:{permission_id:u.in(d),match_mode:u.in([1,2])}},n),g=!1;for(let e=0;e0}async function listRole(e,t){let{vk:n,db:i,_:a}=t,{role:r}=e;return n.pubfn.isNull(r)?[]:(await n.baseDao.select({dbName:"uni-id-roles",whereJson:{role_id:a.in(r),enable:!0},fieldJson:{permission:!0}})).rows}var filterService=[{id:"pub",regExp:function(e=""){return"pub"===getType(e)},description:"pub函数为所有人都可以访问的函数",index:100,mode:"onActionExecuting",main:async function(e){let{url:t,data:n={},util:i}=e,{uniID:a}=i,r={};if(e.data.need_user_info)r=await checkIsLogin.main(e);else if(e.uniIdToken){let t=await a.checkToken(e.uniIdToken,{needPermission:!1,needUserInfo:!1});0===t.code&&(r.uid=t.uid)}return r.code=0,r.msg="ok",r}},{id:"kh",regExp:function(e=""){return"kh"===getType(e)},description:"kh函数为必须登录后才能访问的函数(客户端用户)",index:200,mode:"onActionExecuting",main:checkIsLogin.main},{id:"sys",regExp:function(e=""){return"sys"===getType(e)},description:"sys函数为后端管理人员才能访问的函数(商家后台工作人员)",index:300,mode:"onActionExecuting",main:checkSysAuth.main},{id:"access_denied",regExp:function(e=""){return"access denied"===getType(e)},description:"sys函数为后端管理人员才能访问的函数(商家后台工作人员)",index:100,mode:"onActionExecuting",main:function(){return{code:403,msg:"禁止访问私有函数!"}}}];function getType(e=""){let t="";return e.indexOf("/sys/")>-1?t="sys":e.indexOf("/kh/")>-1?t="kh":e.indexOf("/pub/")>-1&&(t="pub"),e.indexOf("/sys.")>-1||e.indexOf("/sys_")>-1||0===e.indexOf("sys.")||0===e.indexOf("sys_")?t="sys":e.indexOf("/kh.")>-1||e.indexOf("/kh_")>-1||0===e.indexOf("kh.")||0===e.indexOf("kh_")?t="kh":(e.indexOf("/pub.")>-1||e.indexOf("/pub_")>-1||0===e.indexOf("pub.")||0===e.indexOf("pub_"))&&(t="pub"),e.indexOf(".sys_")>-1?t="sys":e.indexOf(".kh_")>-1?t="kh":e.indexOf(".pub_")>-1&&(t="pub"),""==t&&e.indexOf(".")>-1&&(t="kh"),e.indexOf("._")>-1&&(t="access denied"),t}function getMiddleware(e){let t=[];if(e){let n=[...filterService,...e];n.sort((function(e,t){return e.index-t.index})),t=n.filter((e,t,i)=>{var a=[];return n.forEach((e,t)=>{a.push(e.id)}),a.indexOf(e.id)===t})}else t=filterService;return t}var getMiddleware_1=getMiddleware,filter={onActionExecuting:onActionExecuting,onActionExecuted:onActionExecuted,onActionIntercepted:onActionIntercepted,onActionError:onActionError,getMiddleware:getMiddleware_1},routerUtil={filterService:filter,getQueryStringParameters:function(e){let{event:t,vk:n}=e,i={};if(t.httpMethod){let{path:e=""}=t;if("/"===e[0]&&(e=e.substring(1)),e){let a,{urlrewrite:r={}}=n.getUnicloud(),{rule:o}=r,s=n.pubfn.getData(r,"config.accessOnlyInRule"),u=!1;if(o)for(let t in o){let i=o[t],r=n.pubfn.regExpExecToTemplate(e,t,i);if(r){u=!0;let t=r.split("?");e=t[0],a=n.pubfn.urlStringToJson(t[1]);break}}if(!u&&s)return{mpserverlessComposedResponse:!0,statusCode:403,code:403,headers:{"content-type":"application/json"},body:JSON.stringify({code:403,msg:"access denied"})};if(i={data:{}},n.pubfn.isNotNull(a)&&(i.data=Object.assign(i.data,a)),t.queryStringParameters){let e=t.queryStringParameters;"string"==typeof e&&(e=JSON.parse(e)),i.data=Object.assign(i.data,e)}if(t.body){let e=t.body,a=t.headers&&t.headers["content-type"]?t.headers["content-type"]:"";if(a.indexOf("multipart/form-data;")>-1)e=n.formDataUtil.formParser(t),i.data=Object.assign(i.data,e);else{t.isBase64Encoded&&(e=Buffer.from(e,"base64").toString("utf-8"));try{"string"==typeof e&&(e=JSON.parse(e)),i.data=Object.assign(i.data,e)}catch(e){}try{"string"==typeof e&&a.indexOf("x-www-form-urlencoded")>-1&&(e=n.pubfn.urlStringToJson(e),"object"==typeof e&&(e=n.pubfn.string2Number(e),i.data=Object.assign(i.data,e)))}catch(e){}}}i.$url||(i.data.$url?i.$url=i.data.$url:i.$url=e),i.data.uni_id_token&&(i.uni_id_token=i.data.uni_id_token,delete i.data.uni_id_token)}else{if(t.queryStringParameters){let e=t.queryStringParameters;"string"==typeof e.data&&(e.data=JSON.parse(e.data)),i=Object.assign(i,e)}if(t.body){let e=t.body;t.isBase64Encoded&&(e=Buffer.from(e,"base64").toString("utf-8"));try{"string"==typeof e&&(e=JSON.parse(e)),i=Object.assign(i,e)}catch(e){}}}try{let e=t.headers["uni-id-token"]||t.headers.uni_id_token;!i.uni_id_token&&e&&(i.uni_id_token=e)}catch(e){}}else i=JSON.parse(JSON.stringify(t));return i.data||(i.data={}),i.uniIdToken||(i.uniIdToken=i.uni_id_token),i.url=i.$url||"",i},returnError:returnError,filterInterception:async function({serviceParam:e,middlewareService:t,filterResponse:n}){try{n=await filter.onActionIntercepted({serviceParam:e,middlewareService:t,filterResponse:n})}catch(n){return await returnError({code:500,msg:`云函数 ${e.url} 的中间件 onActionIntercepted 运行异常!`,err:n,serviceParam:e,middlewareService:t})}return n},requireService:async function(e={}){let t,{vk:n,serviceParam:i}=e,{url:a,data:r,uniIdToken:o,util:s,filterResponse:u={},originalParam:l={}}=i;if(a.indexOf(".")>-1){let e,i=a.lastIndexOf("."),c=n.require("service/"+a.substring(0,i));if(t=n.pubfn.objectAssign({},c),!t.isCloudObject)throw new Error("msg:禁止访问私有对象内的函数!");let d=a.substring(i+1);if(0==d.indexOf("_"))throw new Error("msg:禁止访问私有函数!");if("function"!=typeof t[d]){try{l.event&&l.event.httpMethod&&l.event.path&&(a=l.event.path.substring(1))}catch(e){}throw{code:404,name:"cloudObject",message:`not found【${a}】`}}Object.assign(t,{vk:n,methodName:d,isCloudObject:!0,getClientInfo:function(){let{context:e={}}=l,t={...e,os:e.OS,appId:e.APPID,locale:e.LOCALE,clientIP:e.CLIENTIP,userAgent:e.CLIENTUA,platform:e.PLATFORM,deviceId:e.DEVICEID,source:e.SOURCE,uniIdToken:o,uid:u.uid,userInfo:u.userInfo,filterResponse:u,originalParam:l};return n.pubfn.objectKeySort(t)},getUserInfo:async function(){if(u.userInfo&&u.userInfo._id)return u.userInfo;if(!e&&u.uid){let t=await s.uniID.checkToken(o,{needUserInfo:!0});if(0!==t.code)throw new Error("msg:token失效:"+t.errMsg);t.userInfo&&t.userInfo._id&&(delete t.userInfo.token,delete t.userInfo.password,e=t.userInfo)}return e},getUtil:function(){return s},getMethodName:function(){return d},getParams:function(){return r},getCloudInfo:function(){let{SPACEINFO:e={},FUNCTION_NAME:t,FUNCTION_TYPE:n}=l.context||{},{provider:i,spaceId:a}=e;return{provider:i,spaceId:a,functionName:t,functionType:"cloudobject"}},getUniIdToken:function(){return o},getUniCloudRequestId:function(){return l.context.requestId},getHttpInfo:function(){return l.event}})}else t=n.require("service/"+a);return t},serviceRun:async function(e={}){let t,{serviceParam:n={},serviceMain:i}=e,{filterResponse:a}=n;if(a.uid&&(n.uid=a.uid),a.userInfo&&(n.userInfo=a.userInfo),i.isCloudObject){let{methodName:e="main"}=i;if("function"==typeof i._before){let e=await i._before();if("string"==typeof e)return{code:-1,msg:e};if("object"==typeof e&&0!==e.code)return{code:e.code,msg:e.msg};if("boolean"==typeof e&&!1===e)return{code:-1,msg:""}}if(t=await i[e](n.data),"function"==typeof i._after){let e=await i._after({res:t||{}});"object"==typeof e&&(t=e)}}else t=await i.main(n);return"object"==typeof t&&(void 0===t.vk_uni_token&&"object"==typeof a&&a.token&&void 0!==a.tokenExpired&&(t.vk_uni_token={token:a.token,tokenExpired:a.tokenExpired}),t=routerUtil.returnRes(t)),t},errorCatch:async function(e={}){let{err:t,type:n,serviceParam:i,middlewareService:a,serviceMain:r={}}=e,{url:o,originalParam:s={}}=i;t||(t={});let{code:u}=t,l=t.message||t.msg||t.errMsg||"";if("run"===n&&"function"==typeof r._after){let e=await r._after({err:t});if(e)return e}let c={code:500,msg:l,err:t,serviceParam:i,middlewareService:a};try{s.event&&s.event.httpMethod&&s.event.path&&(o=s.event.path.substring(1))}catch(t){}return"MODULE_NOT_FOUND"==u&&l.indexOf("service/")>-1||"ENOENT"==u&&l.indexOf("service")>-1||404==u&&["cloudFunction","cloudObject"].indexOf(t.name)>-1?(t.stack=`Error: not found【${o}】`,Object.assign(c,{code:404,msg:`not found【${o}】`})):"MODULE_NOT_FOUND"==u&&l.indexOf("Cannot find module")>-1?Object.assign(c,{code:500,msg:l}):"InternalServerError"==u&&l.indexOf("_id_ dup key")>-1?Object.assign(c,{code:500,msg:"vk.baseDao.add : _id不能重复添加"}):0===l.indexOf("Cannot read property 'mp-weixin' of undefined")?Object.assign(c,{code:501,msg:"请先绑定微信"}):l.indexOf("Response timeout for 10000ms")>-1?Object.assign(c,{code:502,msg:"timeout 请求超时,请重试!"}):l.indexOf("msg:token失效")>-1?Object.assign(c,{code:30202,errMsg:l,msg:l}):l.indexOf("msg:禁止访问私有对象内的函数")>-1||l.indexOf("msg:禁止访问私有函数")>-1?Object.assign(c,{code:403,msg:l.substring(4)}):0===l.indexOf("msg:")?Object.assign(c,{code:501,msg:l.substring(4)}):"ReferenceError"===t.name?Object.assign(c,{code:501,msg:`云函数 ${o} 变量引用错误:${l}`}):"TypeError"===t.name?Object.assign(c,{code:501,msg:`云函数 ${o} 运行异常,类型错误:${l}`}):"InternalServerError"==u?Object.assign(c,{code:"InternalServerError",msg:"内部错误"}):"Error"===t.name?Object.assign(c,{code:t.code,msg:l}):t.stack?Object.assign(c,{code:500,msg:"require"==n?`云函数 ${o} 编译异常!`:`云函数 ${o} 运行异常!`}):"string"==typeof t?Object.assign(c,{code:-1,msg:t}):Object.assign(c,t),await returnError(c)},returnRes:function(e={}){return"object"==typeof e&&(void 0!==e.code||void 0!==e.errCode&&(e.code=e.errCode,e.msg=e.errMsg)),e}},routerUtil_1=routerUtil;async function returnError(e={}){let{code:t,msg:n,err:i,serviceParam:a,middlewareService:r}=e;console.error(n);let o={code:t,msg:n};i&&(i.stack?(console.error(i.stack),o.err={message:i.message,stack:i.stack,code:i.code}):o.err=i);try{o.requestId=a.originalParam.context.requestId}catch(i){}let s=await filter.onActionError({serviceParam:a,middlewareService:r,serviceRes:o});return routerUtil.returnRes(s)}try{process.env.TZ="Asia/Shanghai"}catch(e){}async function main(e){let{event:t,context:n,vk:i}=e;!i&&this&&(i=this);let{config:a,uniID:r,uniPay:o,db:s,middlewareService:u,pubFun:l,customUtil:c,crypto:d}=i.getUnicloud();if(i.pubfn.getData(a,"vk.system.serviceShutdown"))return routerUtil_1.returnRes({code:405,msg:i.pubfn.getData(a,"vk.system.serviceShutdownDescription")});if(["h5","web"].indexOf(n.PLATFORM)>-1){let e=i.pubfn.getUniIdConfig(a,"preferedWebPlatform","h5");n.PLATFORM=e}else if(["app-plus","app"].indexOf(n.PLATFORM)>-1){let e=i.pubfn.getUniIdConfig(a,"preferedAppPlatform","app-plus");n.PLATFORM=e}let p={event:t,context:n},f=routerUtil_1.getQueryStringParameters(e),{url:g,data:m,uniIdToken:b}=f;if([403].indexOf(f.code)>-1)return routerUtil_1.returnRes(f);if(g&&"function"==typeof g.trim&&(g=g.trim()),m){m.vk_appId&&(n.APPID=m.vk_appId),m.vk_appid&&(n.APPID=m.vk_appid),m.vk_platform&&(n.PLATFORM=m.vk_platform),m.vk_locale&&(n.LOCALE=m.vk_locale);let e={};if("object"==typeof t.headers&&(t.headers["vk-appId"]&&(e.appId=t.headers["vk-appId"]),t.headers["vk-appid"]&&(e.appid=t.headers["vk-appid"]),t.headers["vk-platform"]&&(e.platform=t.headers["vk-platform"]),t.headers["vk-locale"]&&(e.locale=t.headers["vk-locale"]),t.headers["vk-device-id"]&&(e.deviceId=t.headers["vk-device-id"]),t.headers["vk-client-ip"]&&(e.clientIP=t.headers["vk-client-ip"]),t.headers["vk-os"]&&(e.os=t.headers["vk-os"])),"object"==typeof m.vk_context&&(e=i.pubfn.objectAssign(e,m.vk_context),delete m.vk_context),"object"==typeof e&&i.pubfn.isNotNull(e)&&(e.appId&&(n.APPID=e.appId),e.appid&&(n.APPID=e.appid),e.platform&&(n.PLATFORM=e.platform),e.locale&&(n.LOCALE=e.locale),e.clientIP&&!n.CLIENTIP&&(n.CLIENTIP=e.clientIP),e.os&&(n.OS=e.os),e.deviceId&&(n.DEVICEID=e.deviceId),"function"===n.SOURCE&&(e.clientIP&&(n.CLIENTIP=e.clientIP),e.userAgent&&(n.CLIENTUA=e.userAgent))),i.pubfn.isNullOne(n.APPID,n.PLATFORM)){let e=i.pubfn.getData(a,"vk.context");i.pubfn.isNotNull(e)&&(n.APPID||(n.APPID=e.APPID),n.PLATFORM||(n.PLATFORM=e.PLATFORM),n.LOCALE||(n.LOCALE=e.LOCALE),n.CLIENTIP||(n.CLIENTIP=e.CLIENTIP))}}const h=r.createInstance({context:n});s.command.$=s.command.aggregate;let y={vk:i,config:a,pubFun:l,uniID:h,uniPay:o,db:s,_:s.command,$:s.command.aggregate,customUtil:c,crypto:d,env:{APPID:n.APPID,CLIENTIP:n.CLIENTIP,DEVICEID:n.DEVICEID,LOCALE:n.LOCALE,OS:n.OS,PLATFORM:n.PLATFORM,CLIENTUA:n.CLIENTUA}};try{uniCloud.vk=i,uniCloud.env=y.env,uniCloud.context=n}catch(e){}let w={url:g,data:m,uniIdToken:b,util:y,originalParam:p};const _=routerUtil_1.filterService.getMiddleware(u);try{let e=await routerUtil_1.filterService.onActionExecuting({serviceParam:w,middlewareService:_});if(0!==e.code)return routerUtil_1.returnRes(await routerUtil_1.filterInterception({serviceParam:w,middlewareService:_,filterResponse:e}));delete m.uid,e.uid&&(m.uid=e.uid),w.filterResponse=e}catch(e){return await routerUtil_1.returnError({code:500,msg:`云函数 ${g} 的中间件 onActionExecuting 运行异常!`,err:e,serviceParam:w,middlewareService:_})}let k,v;try{k=await routerUtil_1.requireService({vk:i,serviceParam:w})}catch(e){return await routerUtil_1.errorCatch({err:e,type:"require",serviceParam:w,middlewareService:_})}try{v=await routerUtil_1.serviceRun({serviceParam:w,serviceMain:k})}catch(e){return await routerUtil_1.errorCatch({err:e,type:"run",serviceParam:w,middlewareService:_,serviceMain:k})}try{v=await routerUtil_1.filterService.onActionExecuted({serviceParam:w,middlewareService:_,serviceRes:v})}catch(e){return await routerUtil_1.returnError({code:500,msg:`云函数 ${g} 的中间件 onActionExecuted 运行异常!`,err:e,serviceParam:w,middlewareService:_})}return routerUtil_1.returnRes(v)}var router=main,md5=function(e){return crypto$1.createHash("md5").update(e).digest("hex")},util$1={},baseDao={init:function(e){util$1=e},add:async function(e){let{db:t,_:n,vk:i,config:a}=util$1,{dbName:r,dataJson:o,db:s,cancelAddTime:u,cancelAddTimeStr:l}=e;if(i.pubfn.isNull(r))throw new Error("vk.baseDao.add 中 dbName 不能为空");if(i.pubfn.isNull(o))throw new Error("vk.baseDao.add 中 dataJson 不能为空");let c=s||t;if(!o._add_time){let e=i.pubfn.getData(a,"vk.db.unicloud.cancelAddTime");void 0===u&&e&&(u=e);let t=i.pubfn.getData(a,"vk.db.unicloud.cancelAddTimeStr");if(void 0===l&&t&&(l=t),!u){let e=new Date;o._add_time=e.getTime(),l||(o._add_time_str=i.pubfn.timeFormat(e,"yyyy-MM-dd hh:mm:ss"))}}let d=await c.collection(r).add(o);return d.id?d.id:null},adds:async function(e){let{db:t,_:n,vk:i,config:a}=util$1,{dbName:r,dataJson:o,db:s,cancelAddTime:u,cancelAddTimeStr:l}=e;if(i.pubfn.isNull(r))throw new Error("vk.baseDao.adds 中 dbName 不能为空");if(i.pubfn.isNull(o))throw new Error("vk.baseDao.adds 中 dataJson 不能为空");if("[object Array]"!==Object.prototype.toString.call(o))throw new Error("vk.baseDao.adds 中 dataJson 必须是数组对象");let c=s||t,d=i.pubfn.getData(a,"vk.db.unicloud.cancelAddTime");void 0===u&&d&&(u=d);let p=i.pubfn.getData(a,"vk.db.unicloud.cancelAddTimeStr");if(void 0===l&&p&&(l=p),!u){let e=new Date,t=e.getTime(),n=i.pubfn.timeFormat(e,"yyyy-MM-dd hh:mm:ss");for(let e in o)o[e]._add_time||(o[e]._add_time=t,l||(o[e]._add_time_str=n))}let f=await c.collection(r).add(o);return f.ids?f.ids:f.id?f.id:null},del:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r,db:o}=e,s=o||n,u=0;if(t.pubfn.isNotNull(r)){let e=await s.collection(a).where(r).remove();e?u=e.deleted:(console.error(e.errMsg),u=-1)}else console.error("whereJson条件不能为空");return u},delete:async function(e){return await baseDao.del(e)},remove:async function(e){return await baseDao.del(e)},deleteById:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,id:r,db:o}=e,s=o||n,u=0;if(t.pubfn.isNull(r))throw new Error("deleteById的id不能为空,且必须是字符串");let l=await s.collection(a).doc(r).remove();return l?u=l.deleted:(console.error(l.errMsg),u=0),u},update:async function(e){let t,{vk:n,db:i,_:a}=util$1,{dbName:r,whereJson:o,dataJson:s,db:u}=e,l=u||i,c=0;if(n.pubfn.isNull(o))throw new Error("update的whereJson不能为空,且必须是对象形式");if(n.pubfn.isNull(s))throw new Error("update的dataJson不能为空,且必须是对象形式");return s._id&&delete s._id,t=void 0===o?await l.collection(r).update(s):await l.collection(r).where(o).update(s),t?c=t.updated:console.error(t.errMsg),c},updateById:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,id:r,dataJson:o,getUpdateData:s,db:u}=e,l=u||n,c=0;if(t.pubfn.isNull(r))throw new Error("updateById的id不能为空,且必须是字符串");if(t.pubfn.isNull(o))throw new Error("updateById的dataJson不能为空,且必须是对象形式");o._id===r&&delete o._id;let d=await l.collection(a).doc(r).update(o);return s?d?await baseDao.findById({db:l,dbName:a,id:r}):null:(d?c=d.updated:(console.error(d.errMsg),c=0),c)},updateAndReturn:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,id:r,whereJson:o,dataJson:s,db:u}=e,l=u||n;if(t.pubfn.isNullAll(r,o))throw new Error("updateAndReturn的id和whereJson两者不能都为空");if(t.pubfn.isNull(s))throw new Error("updateAndReturn的dataJson不能为空,且必须是对象形式");if(s._id&&delete s._id,t.pubfn.isNotNull(r)){return(await l.collection(a).doc(r).updateAndReturn(s)).doc}if(t.pubfn.isNotNull(o)){return(await l.collection(a).where(o).updateAndReturn(s)).doc}throw new Error("updateAndReturn的id和whereJson两者不能都为空")},setById:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,id:r,dataJson:o,db:s}=e,u=s||n;if(t.pubfn.isNull(o))throw new Error("setById的dataJson不能为空,且必须是对象形式");if(t.pubfn.isNullAll(r,o._id))throw new Error("id或dataJson._id不能均为空");if(t.pubfn.isNotNullAll(r,o._id)&&r!==o._id)throw new Error("id和dataJson._id必须一致");t.pubfn.isNotNull(o._id)&&(r=o._id,delete o._id);let l=await u.collection(a).doc(r).set(o);return l.updated>0?l.type="update":(l.type="add",l.id=l.upsertedId),l},select:async function(e={}){let{vk:t,db:n,_:i}=util$1;"string"==typeof e.pageIndex&&(e.pageIndex=parseInt(e.pageIndex)),"string"==typeof e.pageSize&&(e.pageSize=parseInt(e.pageSize));let{dbName:a,whereJson:r,pageSize:o=10,getOne:s=!1,getMain:u=!1}=e;if(o<=0&&(o=999999999),o>500)return await baseDao.selectAll(e);let l=await baseDao.getSelectData(e),{result:c,hasMore:d,total:p,getCount:f,pageIndex:g,fieldJson:m}=l;return c=c.skip((g-1)*o).limit(o),t.pubfn.isNotNull(m)&&(c=c.field(m)),c.get().then(e=>{let t={};return f?(t.total=p,t.hasMore=d):(t.total=e.data?e.data.length:0,t.hasMore=t.total>=o),t.rows=e.data,t.code=0,t.msg="查询成功",t.pagination={pageIndex:g,pageSize:o},s&&(t.rows=t.rows[0]),u?t.rows:t})},findById:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,id:r,fieldJson:o,db:s}=e,u=(s||n).collection(a).doc(r);o&&(u=u.field(o));let l=await u.get();return"[object Array]"===Object.prototype.toString.call(l.data)?l.data[0]:l.data},findByWhereJson:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r,fieldJson:o,sortArr:s,db:u}=e,l=u||n;if(t.pubfn.isNotNull(r)){let e=l.collection(a).where(r);if(s)for(let t in s){let n=s[t],i=n.name,a=n.type;null!=a&&""!=a||(a="asc"),e=e.orderBy(i,a)}o&&(e=e.field(o));let t=await e.limit(1).get();if(t.data&&t.data.length>0)return t.data[0]}else console.error("whereJson条件不能为空");return null},count:async function(e){let t,{vk:n,db:i,_:a}=util$1,{dbName:r,whereJson:o,foreignDB:s,foreignKey:u,groupJson:l,lastWhereJson:c,db:d}=e,p=d||i;if(n.pubfn.isNotNull(s)||n.pubfn.isNotNull(l)){let e=p.collection(r).aggregate();return n.pubfn.isNotNull(o)&&e.match(o),n.pubfn.isNotNull(l)&&e.group(l),n.pubfn.isNotNull(s)&&(e=baseDao.addForeignDB({foreignDB:s,foreignKey:u,result:e})),n.pubfn.isNotNull(c)&&(e=e.match(c)),e=await e.count("total").end(),e.data[0]?e.data[0].total:0}return t=n.pubfn.isNotNull(o)?await p.collection(r).where(o).count():await p.collection(r).count(),t.total},getSelectData:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r,pageIndex:o=1,pageSize:s=10,getCount:u=!1,db:l}=e;s<0&&(o=1,s=999999999,u=!0);let c=l||n,d=e.sortArr,p=e.fieldJson,f=0,g=!1;if(u){let e;e=t.pubfn.isNotNull(r)?await c.collection(a).where(r).count():await c.collection(a).count(),f=e.total,o1e3&&(u=1e3));let l=await baseDao.getSelectData(e),{result:c,hasMore:d,total:p,getCount:f,pageIndex:g,pageSize:m,fieldJson:b}=l;m>0&&!p&&!f&&(p=m),i.pubfn.isNotNull(b)&&(c=c.field(b));let h={};if(f&&0===p)h={data:[]};else{let t=p;mr&&(n=r-t);let o=c.skip(t).limit(n).get();i.push(o)}try{h=(await Promise.all(i)).reduce((e,t)=>({data:e.data.concat(t.data),errMsg:e.errMsg}))}catch(t){throw console.error("vk.baseDao.select-异常",e,t),new Error("msg:vk.baseDao.select-异常")}}let y={};return y.total=f?p:h.data?h.data.length:0,y.hasMore=d,y.rows=h.data,y.code=0,y.msg="查询成功",y.pagination={pageIndex:g,pageSize:m},o&&(y.rows=y.rows[0]),s?y.rows:y},sum:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,fieldName:r,whereJson:o,db:s}=e,u=s||n;const l=u.command.aggregate;let c=u.collection(a).aggregate();t.pubfn.isNotNull(o)&&c.match(o),c.group({_id:null,num:l.sum("$"+r)});let d=await c.end();return d.data&&d.data[0]?d.data[0].num:0},avg:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,fieldName:r,whereJson:o,db:s}=e,u=s||n;const l=u.command.aggregate;let c=u.collection(a).aggregate();t.pubfn.isNotNull(o)&&c.match(o),c.group({_id:null,num:l.avg("$"+r)});let d=await c.end();return d.data&&d.data[0]?d.data[0].num:null},max:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,fieldName:r,whereJson:o,db:s}=e,u=s||n;const l=u.command.aggregate;let c=u.collection(a).aggregate();t.pubfn.isNotNull(o)&&c.match(o),c.group({_id:null,num:l.max("$"+r)});let d=await c.end();return d.data&&d.data[0]?d.data[0].num:null},min:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,fieldName:r,whereJson:o,db:s}=e,u=s||n;const l=u.command.aggregate;let c=u.collection(a).aggregate();t.pubfn.isNotNull(o)&&c.match(o),c.group({_id:null,num:l.min("$"+r)});let d=await c.end();return d.data&&d.data[0]?d.data[0].num:null},sample:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r,size:o,fieldJson:s,db:u}=e,l=u||n;l.command.aggregate;let c=l.collection(a).aggregate();return t.pubfn.isNotNull(r)&&c.match(r),c.sample({size:o}).limit(o),t.pubfn.isNotNull(s)&&c.project(s),(await c.end()).data},selects:async function(e={}){let{vk:t,db:n,_:i}=util$1;if(t.pubfn.isNotNull(e.treeProps))return await baseDao.tree(e);"string"==typeof e.pageIndex&&(e.pageIndex=parseInt(e.pageIndex)),"string"==typeof e.pageSize&&(e.pageSize=parseInt(e.pageSize));let{db:a,dbName:r,foreignKey:o="_id",pageIndex:s=1,pageSize:u=10,getCount:l=!1,getOne:c=!1,getMain:d=!1,whereJson:p={},unwindJson:f,groupJson:g,sortArr:m=[],foreignDB:b=[],lastWhereJson:h,lastSortArr:y=[],fieldJson:w={},addFields:_}=e,k=a||n;-1==u&&(s=1,u=999999999,l=!1),c&&(u=1,l=!1);let v,x=0,N=!1;if(t.pubfn.isNotNull(p))for(let e in p)p[e]&&"object"==typeof p[e]&&"geoNear"===p[e].operator&&(v=t.pubfn.copyObject(p[e]),v.keyName=e,v.limit=s*u,delete p[e]);if(l){if(t.pubfn.isNullAll(g,f,h)){let e;e=t.pubfn.isNotNull(p)?await k.collection(r).where(p).count():await k.collection(r).count(),x=e.total}else{let e=k.collection(r).aggregate();t.pubfn.isNotNull(p)&&(t.pubfn.isNotNull(v)?e=baseDao.getGeoNearJson({runDB:k,result:e,geoNearJson:v,whereJson:p}):e.match(p)),t.pubfn.isNotNull(f)&&(e=baseDao.getTnwind({result:e,unwindJson:f})),t.pubfn.isNotNull(g)&&e.group(g),t.pubfn.isNotNull(h)&&(t.pubfn.isNotNull(b)&&(e=baseDao.addForeignDB({foreignDB:b,foreignKey:o,result:e})),e.match(h)),e=await e.count("total").end(),x=e.data[0]?e.data[0].total:0}s=u),$.rows=O,$.code=0,$.msg="查询成功",$.pagination={pageIndex:s,pageSize:u},c&&($.rows=$.rows[0]),d?$.rows:$},listToObjectByLimit1:function(e){let{vk:t,db:n,_:i}=util$1,{list:a,foreignDB:r}=e;if(t.pubfn.isNotNull(r))for(let e in a)for(let n in r){let{as:i,limit:o,foreignDB:s,dbName:u}=r[n];i||(i=u),t.pubfn.isNotNull(s)&&(a[e][i]=baseDao.listToObjectByLimit1({list:a[e][i],foreignDB:s})),1===o&&(t.pubfn.isArray(a[e][i])?a[e][i]&&a[e][i].length>0?a[e][i]=a[e][i][0]:a[e][i]={}:void 0===a[e][i]&&(a[e][i]={}))}return a},addForeignDB:function(e){let{vk:t,db:n,_:i}=util$1,{foreignDB:a,foreignKey:r,result:o}=e;const s=i.aggregate;for(let e in a){let n,{dbName:u,foreignKey:l,localKey:c,localKeyType:d="",foreignKeyType:p="",as:f,limit:g,getOne:m,whereJson:b,fieldJson:h,sortArr:y,foreignDB:w,addFields:_}=a[e];f||(f=u),n=t.pubfn.isNotNull(c)?c:"object"==typeof r?r[e]:r;let k,v="string"==typeof n?"$"+n:n,x="string"==typeof l?"$"+l:l,N="$$foreignKey"+baseDao.getForeignKeyName(n),$="foreignKey"+baseDao.getForeignKeyName(n);k="array"===d.toLowerCase()?[s.cond({if:s.isArray(N),then:s.in([x,N]),else:s.eq([x,N])})]:"array"===p.toLowerCase()?[s.cond({if:s.isArray(x),then:s.in([N,x]),else:s.eq([x,N])})]:[s.eq([x,N])];let D=s.pipeline().match(i.expr(s.and(k)));if(t.pubfn.isNotNull(b)&&(D=D.match(b)),t.pubfn.isNotNull(y)){let e={};for(let t in y){let n=y[t],i=n.name,a=n.type;a=null==a||""==a||"asc"==a?1:-1,e[i]=a}D=D.sort(e)}g&&(D=D.limit(g)),t.pubfn.isNotNull(w)&&(D=baseDao.addForeignDB({foreignDB:w,result:D})),t.pubfn.isNotNull(h)&&(h=baseDao.foreignDBToProject({fieldJson:h,foreignDB:w}),D=D.project(h)),t.pubfn.isNotNull(_)&&(D=D.addFields(_)),D=D.done();let T={};T[$]=v;let O={from:u,let:T,pipeline:D,as:f};o=o.lookup(O),(1===g&&!1!==m||!0===m)&&(o=o.unwind({path:"$"+f,preserveNullAndEmptyArrays:!0}))}return o},getForeignKeyName:function(e){return"string"==typeof e?e.replace(new RegExp("\\.","g"),"__"):"__vk__foreignKey1"},addWhereJson:function(e,t={},n="whereJson"){let{vk:i,db:a,_:r}=util$1,{formData:o,columns:s}=e;for(let e in s){let a,u=s[e],{key:l,mode:c,defaultValue:d,type:p="",lastWhereJson:f,auxiliary:g=!0,trim:m=!0,isNumber:b=!1}=u;if("lastWhereJson"===n&&!f)continue;if("lastWhereJson"!==n&&f)continue;let h=l;if(i.pubfn.isNotNull(u.fieldName)&&(h=u.fieldName),a=i.pubfn.isNotNull(u.value)?u.value:o[l],i.pubfn.isNull(a)&&i.pubfn.isNotNull(d)&&(a=d),i.pubfn.isNull(c)&&(c=["address","province","city","area"].indexOf(p)>-1?"address":"[object Array]"===Object.prototype.toString.call(a)&&a.length>=2?"[]":"="),i.pubfn.isNotNull(a))if("string"==typeof a&&m&&"function"==typeof a.trim&&(a=a.trim()),b&&!isNaN(a)&&(a=Number(a)),"custom"===c);else if("%%"===c)try{t[h]=new RegExp(a)}catch(e){}else if("%*"===c)try{t[h]=new RegExp("^"+a)}catch(e){}else if("*%"===c)try{t[h]=new RegExp(a+"$")}catch(e){}else if(">"===c)t[h]=t[h]?t[h].gt(a):r.gt(a);else if(">="===c)t[h]=t[h]?t[h].gte(a):r.gte(a);else if("<"===c)t[h]=t[h]?t[h].lt(a):r.lt(a);else if("<="===c)t[h]=t[h]?t[h].lte(a):r.lte(a);else if("in"===c)t[h]=r.in(a);else if("nin"===c)t[h]=r.nin(a);else if("!="===c)t[h]=r.neq(a);else if("[]"===c)t[h]=r.gte(a[0]).lte(a[1]);else if("[)"===c)t[h]=r.gte(a[0]).lt(a[1]);else if("(]"===c)t[h]=r.gt(a[0]).lte(a[1]);else if("()"===c)t[h]=r.gt(a[0]).lt(a[1]);else if("address"===c){let e={};a.province&&a.province.code&&(e["province.code"]=a.province.code),a.city&&a.city.code&&(e["city.code"]=a.city.code),a.area&&a.area.code&&(e["area.code"]=a.area.code),t[h]=e}else t[h]=g?"___empty-array___"===a?[]:"___empty-object___"===a?{}:"___non-existent___"===a?r.exists(!1):"___existent___"===a?r.exists(!0):a:a}return t},addLastWhereJson:function(e,t={}){return baseDao.addWhereJson(e,t,"lastWhereJson")},getTableData:async function(e){let{vk:t,db:n,_:i,config:a}=util$1,{db:r,dbName:o,data:s={},getCount:u=!0,getMain:l,whereJson:c,unwindJson:d,fieldJson:p,sortArr:f,treeProps:g,groupJson:m,foreignKey:b,foreignDB:h,lastWhereJson:y,lastSortArr:w,addFields:_}=e,{pageIndex:k,pageSize:v,pagination:x,sortRule:N,lastSortRule:$,formData:D,columns:T}=s;x&&(k=x.pageIndex,v=x.pageSize);let O,A={},I={},S=[],E={};if(t.pubfn.isNotNull(f))S=f;else{let e=t.pubfn.getData(a,"vk.db.unicloud.getTableData.sortArr");t.pubfn.isNotNull(e)?S=e:S.push({name:"_id",type:"desc"})}if(t.pubfn.isNotNull(N)&&(S=N),t.pubfn.isNotNull($)&&(w=$),I=baseDao.addWhereJson(s),E=baseDao.addLastWhereJson(s),t.pubfn.isNotNull(c)&&(c.operator&&c.operands&&["or","and"].indexOf(c.operator)>-1?I=i.and([I,c]):t.pubfn.objectAssign(I,c)),t.pubfn.isNotNull(p)&&t.pubfn.objectAssign(A,p),t.pubfn.isNotNull(y)&&t.pubfn.objectAssign(E,y),t.pubfn.isNotNull(I))for(let e in I)"object"==typeof I[e]&&I[e]&&"geoNear"===I[e].operator&&(O=!0);return t.pubfn.isNullAll(h,m,g,d,O)?await t.baseDao.select({db:r,dbName:o,getMain:l,getCount:u,pageIndex:k,pageSize:v,fieldJson:A,whereJson:I,sortArr:S}):await t.baseDao.selects({db:r,dbName:o,foreignKey:b,getMain:l,getCount:u,pageIndex:k,pageSize:v,whereJson:I,unwindJson:d,fieldJson:A,sortArr:S,treeProps:g,groupJson:m,foreignDB:h,lastWhereJson:E,lastSortArr:w,addFields:_})},startTransaction:async function(e){let{vk:t,db:n,_:i}=util$1;return await n.startTransaction()},rollbackTransaction:async function(e){let{db:t,msg:n="【异常】操作失败",tips:i="事务已回滚。",err:a={},code:r=-1}=e;console.error("transaction error",a);let o={code:r,msg:n,tips:i};await t.rollback();let s={message:a.message,stack:a.stack};try{s.body=JSON.parse(a.message),"object"==typeof s.body&&void 0!==s.body.code&&(s.body.msg,1)&&(o.msg=s.body.msg)}catch(e){}return console.error("transaction errJson",s),o.err=s,o},group:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r,groupJson:o,sortArr:s,pageIndex:u=1,pageSize:l=10,getCount:c=!1,lookupJson:d,db:p}=e,f=p||n;l<=0&&(l=999999999);i.aggregate;let g,m=f.collection(a).aggregate();if(t.pubfn.isNotNull(r)&&(m=m.match(r)),t.pubfn.isNotNull(o)&&(m=m.group(o)),t.pubfn.isNotNull(s)){let e={};for(let t in s){let n=s[t],i=n.name,a=n.type;a=null==a||""==a||"asc"==a?1:-1,e[i]=a}m=m.sort(e)}m=m.skip((u-1)*l).limit(l),t.pubfn.isNotNull(d)&&(g=d.returnObject,delete d.returnObject,m=m.lookup(d)),m=await m.end();let b,h=m.data;if(g)for(let e in h)h[e][d.as]=h[e][d.as][0];let y=!1;if(c){let e=f.collection(a).aggregate();t.pubfn.isNotNull(r)&&(e=e.match(r)),t.pubfn.isNotNull(o)&&(e=e.group(o));let n=await e.count("total").end();b=n.data[0]?n.data[0].total:0,u=l;return{hasMore:y,total:b,rows:h,code:0,key:1,pageIndex:u,pageSize:l}},tree:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r={},pageIndex:o=1,pageSize:s=10,getCount:u=!1,sortArr:l=[],fieldJson:c={},lastWhereJson:d,treeProps:p={}}=e;e.foreignDB||(e.foreignDB=[]);let{id:f="_id",parent_id:g="parent_id",children:m="children",level:b=10,limit:h=500}=p;if(b<1||b>20)throw new Error("msg:treeProps.level的范围必须在[1,20]");delete e.treeProps,e.whereJson||(e.whereJson={[g]:null}),e.foreignDB.unshift({dbName:a,localKey:f,foreignKey:g,as:m,limit:h,whereJson:p.whereJson,fieldJson:p.fieldJson||e.fieldJson,sortArr:p.sortArr,foreignDB:t.pubfn.copyObject(e.foreignDB)});let y=t.pubfn.copyObject(e.foreignDB);for(let n=1;n{"[object object]"===Object.prototype.toString.call(e.content)&&(e.content=JSON.stringify(e.content)),void 0===e.dataType&&(e.dataType="json"),"default"!=e.dataType&&""!==e.dataType||delete e.dataType,e.useContent&&(e.content=JSON.stringify(e.data)),e.method||(e.method="POST"),e.method=e.method.toUpperCase(),void 0===e.headers&&void 0!==e.header&&(e.headers=e.header);let t=await uniCloud.httpclient.request(e.url,e);return!e.needOriginalRes&&t&&t.data?t.data:t};var vk_request=request;const callFunction=async(e={})=>{let{name:t,url:n,data:i={},uniIdToken:a,clientInfo:r={},event:o={},uniCloud:s}=e;if(o&&o.originalParam&&o.originalParam.context){let e=o.originalParam.context;a=o.uniIdToken,r={...e,appId:e.APPID,platform:e.PLATFORM,locale:e.LOCALE,clientIP:e.CLIENTIP,os:e.OS,userAgent:e.CLIENTUA,deviceId:e.DEVICEID,uniIdToken:a}}let u,l=s||uniCloud;u=l.$context&&l.$context.FUNCTION_NAME?l.$context.FUNCTION_NAME:l.$options&&l.$options.context&&l.$options.context.FUNCTION_NAME?l.$options.context.FUNCTION_NAME:"router",a||r.uniIdToken&&(a=r.uniIdToken);let c={...i,vk_context:{appId:r.appId,platform:r.platform,locale:r.locale,clientIP:r.clientIP,os:r.os,userAgent:r.userAgent,deviceId:r.deviceId}};t||(t=u);let d=await l.callFunction({name:t,data:{$url:n,uniIdToken:a,data:c}});return d&&d.result};var vk_callFunction=callFunction,util$2={formValidateItem:function(e,t,n){let i={code:0,msg:"ok"},a=getData(e,t);void 0===a&&(a=e[t]);for(let e in n){let r=n[e];if(void 0===a&&r.required){i={type:"undefined",code:-1,msg:"字段:"+t+" 名称错误,请检查!",key:t,value:a};break}if(r.required&&(null==a||null==a||""===a||0==a.length)){i={type:"required",code:-1,msg:r.message,key:t,value:a};break}if(r.type&&void 0!==a){if(Object.prototype.toString.call(a).toLowerCase().toLowerCase()!==`[object ${r.type}]`.toLowerCase()){i={type:"type",code:-1,msg:r.message,key:t,value:a};break}}if(r.len&&a.length!=r.len){i={type:"len",code:-1,msg:r.message,key:t,value:a};break}if(r.min&&isNotNull(a))if("number"==r.type){if(ar.max){i={type:"max",code:-1,msg:r.message,key:t,value:a};break}}else if(a.length>r.max){i={type:"max",code:-1,msg:r.message,key:t,value:a};break}if("function"==typeof r.validator){let e,n,o=0,s=r.validator(r,a,(function(e){return n||(n=e),e}));if(n||(n=s),void 0!==n&&!0!==n&&(o=-1,"object"==typeof n?e||(e=n.message||n.msg,n.code&&(o=n.code)):"string"==typeof n&&(e||(e=n))),o){i={type:"validator",code:o,msg:e||r.message,key:t,value:a};break}}}return i}},formValidate=function(e={}){let t={code:0,msg:"ok"},{data:n,rules:i}=e;if(i)for(let e in i){let a=i[e];if(t=util$2.formValidateItem(n,e,a),0!=t.code)break}return t};function isNotNull(e){return-1===[void 0,null,""].indexOf(e)}function getData(e,t,n){let i=JSON.parse(JSON.stringify(e));t=t.replace(/\s+/g,"")+".";let a="";for(let e=0;e0&&(n=util$3.treeToArrayFn(l[o],t,n,l[a])),s&&delete l[o]}return n},util$3.arrayToTree=function(e,t){let n=deepClone(e),{id:i="_id",parent_id:a="parent_id",children:r="children",deleteParentId:o=!1,need_field:s}=t,u=[],l={};for(let e=0;e=10&&(e=Number(e)),"number"==typeof e)10==e.toString().length&&(e*=1e3),n=new Date(e);else if("object"==typeof e)n=new Date(e.getTime());else if("string"==typeof e){let i=t=util$4.getTargetTimezone(t),a=t>=0?"+":"";t>=0&&t<10?i="0"+t:t<0&&t>-10&&(i="-0"+-1*t);let r,o=e.split(" "),s=o[0]||"",u=o[1]||"";r=s.indexOf("-")>-1?s.split("-"):s.split("/");let l=u.split(":"),c={year:Number(r[0]),month:Number(r[1])||1,day:Number(r[2])||1,hour:Number(l[0])||0,minute:Number(l[1])||0,second:Number(l[2])||0};for(let e in c)c[e]>=0&&c[e]<10&&(c[e]="0"+c[e]);let d=`${c.year}-${c.month}-${c.day}T${c.hour}:${c.minute}:${c.second}${a}${i}:00`;n=new Date(d)}return n},getTimeByTimeZone:function(e,t){let n=util$4.getDateObject(e);t=util$4.getTargetTimezone(t);let i=60*n.getTimezoneOffset()*1e3+60*t*60*1e3,a=n.getTime()+i;return n=new Date(a),n},timeFormat:function(e,t="yyyy-MM-dd hh:mm:ss",n){try{if(!e)return"";n=util$4.getTargetTimezone(n);let i=util$4.getTimeByTimeZone(e,n),a={"M+":i.getMonth()+1,"d+":i.getDate(),"h+":i.getHours(),"m+":i.getMinutes(),"s+":i.getSeconds(),"q+":Math.floor((i.getMonth()+3)/3),S:i.getMilliseconds(),Z:`${n>=0?"+":"-"}${Math.abs(n).toString().padStart(2,"0")}:00`};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(i.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in a)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?a[e]:("00"+a[e]).substr((""+a[e]).length)));return t}catch(e){return time}},getDateInfo:function(e=new Date,t){let n=util$4.getTimeByTimeZone(e,t),i=n.getFullYear()+"",a=n.getMonth()+1<10?"0"+(n.getMonth()+1):n.getMonth()+1,r=n.getDate()<10?"0"+n.getDate():n.getDate(),o=n.getHours()<10?"0"+n.getHours():n.getHours(),s=n.getMinutes()<10?"0"+n.getMinutes():n.getMinutes(),u=n.getSeconds()<10?"0"+n.getSeconds():n.getSeconds(),l=n.getMilliseconds(),c=n.getDay(),d=Math.floor((n.getMonth()+3)/3);return{year:Number(i),month:Number(a),day:Number(r),hour:Number(o),minute:Number(s),second:Number(u),millisecond:Number(l),week:Number(c),quarter:Number(d)}},getCommonTime:function(e=new Date,t){let n={},i=util$4.getDateObject(e);t=util$4.getTargetTimezone(t);const a=60*i.getTimezoneOffset()*1e3+60*t*60*1e3,{year:r,month:o,day:s,hour:u,minute:l,second:c,millisecond:d,week:p,quarter:f}=util$4.getDateInfo(i,t);n.now={year:r,month:o,day:s,hour:u,minute:l,second:c,millisecond:d,week:p,quarter:f,date_str:util$4.timeFormat(i,"yyyy-MM-dd hh:mm:ss",t),date_day_str:util$4.timeFormat(i,"yyyy-MM-dd",t),date_month_str:util$4.timeFormat(i,"yyyy-MM",t)};let g=new Date(r,o,0).getDate(),m=new Date(r,12,0).getDate();n.todayStart=new Date(`${r}/${o}/${s}`).getTime()-a,n.today12End=new Date(`${r}/${o}/${s}`).getTime()+43199999-a,n.todayEnd=new Date(`${r}/${o}/${s}`).getTime()+86399999-a,n.monthStart=new Date(`${r}/${o}/1`).getTime()-a,n.monthEnd=new Date(`${r}/${o}/${g}`).getTime()+86399999-a,n.yearStart=new Date(r+"/1/1").getTime()-a,n.yearEnd=new Date(`${r}/12/${m}`).getTime()+86399999-a,n.hourStart=new Date(`${r}/${o}/${s} ${u}:00:00`).getTime()-a,n.hourEnd=new Date(`${r}/${o}/${s} ${u}:59:59`).getTime()-a;let b=r,h=o-1;0===h&&(h=12,b=r-1);let y=new Date(b,h,0).getDate();n.lastMonthStart=new Date(`${b}/${h}/1`).getTime()-a,n.lastMonthEnd=new Date(`${b}/${h}/${y}`).getTime()+86399999-a,n.yesterdayStart=n.todayStart-864e5,n.yesterday12End=n.today12End-864e5,n.yesterdayEnd=n.todayEnd-864e5;let w=util$4.getWeekOffsetStartAndEnd(0,i,t);n.weekStart=w.startTime,n.weekEnd=w.endTime,n.months=[],n.months[0]={startTime:n.monthStart,endTime:n.monthEnd,startTimeStr:util$4.timeFormat(n.monthStart,"yyyy-MM-dd hh:mm:ss",t),endTimeStr:util$4.timeFormat(n.monthEnd,"yyyy-MM-dd hh:mm:ss",t),monthStart:n.monthStart,monthEnd:n.monthEnd};for(let e=1;e<=12;e++){let i=new Date(r,e,0).getDate(),o=new Date(`${r}/${e}/1`).getTime()-a,s=new Date(`${r}/${e}/${i}`).getTime()+86399999-a;n.months[e]={startTime:o,endTime:s,startTimeStr:util$4.timeFormat(o,"yyyy-MM-dd hh:mm:ss",t),endTimeStr:util$4.timeFormat(s,"yyyy-MM-dd hh:mm:ss",t),monthStart:o,monthEnd:s}}n.days=[],n.days[0]={startTime:n.todayStart,endTime:n.todayEnd,startTimeStr:util$4.timeFormat(n.todayStart,"yyyy-MM-dd hh:mm:ss",t),endTimeStr:util$4.timeFormat(n.todayEnd,"yyyy-MM-dd hh:mm:ss",t)};for(let e=1;e<=g;e++){let i=n.monthStart+864e5*(e-1),{startTime:a,endTime:r}=util$4.getDayOffsetStartAndEnd(0,i,t);n.days[e]={startTime:a,endTime:r,startTimeStr:util$4.timeFormat(a,"yyyy-MM-dd hh:mm:ss",t),endTimeStr:util$4.timeFormat(r,"yyyy-MM-dd hh:mm:ss",t)}}for(let e in n)"number"==typeof n[e]&&13===n[e].toString().length&&(n[e+"Str"]=util$4.timeFormat(n[e],"yyyy-MM-dd hh:mm:ss",t));return n},getMonthStartAndEnd:function(e,t){t=util$4.getTargetTimezone(t);let n={startTime:null,endTime:null},{year:i,month:a}=e;if(i>0&&a>0){const e=60*(new Date).getTimezoneOffset()*1e3+60*t*60*1e3;let r=new Date(i,a,0).getDate();n.startTime=new Date(`${i}/${a}/1`).getTime()-e,n.endTime=new Date(`${i}/${a}/${r}`).getTime()+86399999-e}return n},getHourOffsetStartAndEnd:function(e=0,t=new Date,n){let i=util$4.getDateObject(t);n=util$4.getTargetTimezone(n);let a={};const r=60*i.getTimezoneOffset()*1e3+60*n*60*1e3;i=new Date(i.getTime()+36e5*e);let o=util$4.getDateInfo(i);return a.startTime=new Date(`${o.year}/${o.month}/${o.day} ${o.hour}:00:00`).getTime()-r,a.endTime=new Date(`${o.year}/${o.month}/${o.day} ${o.hour}:00:00`).getTime()+3599999-r,a},getDayOffsetStartAndEnd:function(e=0,t=new Date,n){let i=util$4.getDateObject(t);n=util$4.getTargetTimezone(n);let a={};const r=60*i.getTimezoneOffset()*1e3+60*n*60*1e3;i=new Date(i.getTime()+864e5*e);let o=util$4.getDateInfo(i);return a.startTime=new Date(`${o.year}/${o.month}/${o.day}`).getTime()-r,a.endTime=new Date(`${o.year}/${o.month}/${o.day}`).getTime()+86399999-r,a},getWeekOffsetStartAndEnd:function(e=0,t=new Date,n){let i={},a=util$4.getDateObject(t);n=util$4.getTargetTimezone(n);const r=60*a.getTimezoneOffset()*1e3+60*n*60*1e3;let o=0===a.getDay()?7:a.getDay();a.setDate(a.getDate()-o+1+7*e);let s=util$4.getDateInfo(a);a.setDate(a.getDate()+7);let u=util$4.getDateInfo(a);return i.startTime=new Date(`${s.year}/${s.month}/${s.day}`).getTime()-r,i.endTime=new Date(`${u.year}/${u.month}/${u.day}`).getTime()-1-r,i},getMonthOffsetStartAndEnd:function(e=0,t=new Date,n){let i={},a=util$4.getDateObject(t),r=util$4.getDateInfo(a),o=r.month+e,s=r.year;o>12?(s+=Math.floor(o/12),o=Math.abs(o)%12):o<=0&&(s=s-1-Math.floor(Math.abs(o)/12),o=12-Math.abs(o)%12);let u=new Date(s,o,0).getDate();return i.startTime=util$4.getDateObject(`${s}/${o}/01`,n).getTime(),i.endTime=util$4.getDateObject(`${s}/${o}/${u}`,n).getTime()+86399999,i},getQuarterOffsetStartAndEnd:function(e=0,t=new Date,n){let i={},a=util$4.getDateObject(t);a.setMonth(a.getMonth()+3*e),n=util$4.getTargetTimezone(n);const r=60*a.getTimezoneOffset()*1e3+60*n*60*1e3;let o=util$4.getDateInfo(a).month;[1,2,3].indexOf(o)>-1?o=1:[4,5,6].indexOf(o)>-1?o=4:[7,8,9].indexOf(o)>-1?o=7:[10,11,12].indexOf(o)>-1&&(o=10),a.setMonth(o-1);let s=util$4.getDateInfo(a);a.setMonth(a.getMonth()+3);let u=util$4.getDateInfo(a);return i.startTime=new Date(`${s.year}/${s.month}/1`).getTime()-r,i.endTime=new Date(`${u.year}/${u.month}/1`).getTime()-1-r,i},getYearOffsetStartAndEnd:function(e=0,t=new Date,n){let i={},a=util$4.getDateObject(t);n=util$4.getTargetTimezone(n);const r=60*a.getTimezoneOffset()*1e3+60*n*60*1e3;let o=util$4.getDateInfo(a).year+e;return i.startTime=new Date(o+"/1/1").getTime()-r,i.endTime=new Date(o+"/12/31").getTime()+86399999-r,i},getOffsetTime:function(e=new Date,t,n){let i=util$4.getDateObject(e),a=util$4.getDateInfo(i);n=util$4.getTargetTimezone(n);const r=60*i.getTimezoneOffset()*1e3+60*n*60*1e3;let o=t.year||t.y||0,s=t.month||t.m||0,u=t.day||t.d||0,l=t.hour||t.hours||t.hh||0,c=t.minute||t.minutes||t.mm||0,d=t.second||t.seconds||t.ss||0,{mode:p="after"}=t;"before"==p&&(o*=-1,s*=-1,u*=-1,l*=-1,c*=-1,d*=-1);let f={year:a.year+o,month:a.month+s,day:a.day+u,hour:a.hour+l,minute:a.minute+c,second:a.second+d};return i=new Date(f.year,f.month-1,f.day,f.hour,f.minute,f.second),i.getTime()-r},isLeapYear:function(e){if(void 0===e){let{now:t}=util$4.getCommonTime();e=t.year}else if("object"==typeof e){let{now:t}=util$4.getCommonTime(e);e=t.year}return e%4==0&&e%100!=0||e%400==0},isQingming:function(e=new Date){let{now:t}=util$4.getCommonTime(e),{year:n,month:i,day:a}=t,r=!1;return util$4.isLeapYear(n)||util$4.isLeapYear(n-1)?4===i&&4===a&&(r=!0):4===i&&5===a&&(r=!0),r},getFullTime:function(e,t=0,n){if(!e)return"";n=util$4.getTargetTimezone(n);let i=util$4.getDateObject(e);const a=60*i.getTimezoneOffset()*1e3+60*n*60*1e3,r=i.getTime()+a;i=new Date(r);let o=i.getFullYear()+"",s=i.getMonth()+1<10?"0"+(i.getMonth()+1):i.getMonth()+1,u=i.getDate()<10?"0"+i.getDate():i.getDate(),l=i.getHours()<10?"0"+i.getHours():i.getHours(),c=i.getMinutes()<10?"0"+i.getMinutes():i.getMinutes(),d=i.getSeconds()<10?"0"+i.getSeconds():i.getSeconds();return 2===t?{YYYY:Number(o),MM:Number(s),DD:Number(u),hh:Number(l),mm:Number(c),ss:Number(d),year:Number(o),month:Number(s),day:Number(u),hour:Number(l),minute:Number(c),second:Number(d)}:1===t?o+""+s+u+l+c+d:o+"-"+s+"-"+u+" "+l+":"+c+":"+d}},timeUtil=util$4,pubfn={};pubfn.formValidate=formValidate,pubfn.treeUtil=treeUtil,pubfn.timeUtil=timeUtil,pubfn.sleep=e=>new Promise(t=>setTimeout(t,e)),pubfn.timeFormat=pubfn.timeUtil.timeFormat,pubfn.getDateInfo=pubfn.timeUtil.getDateInfo,pubfn.getFullTime=pubfn.timeUtil.getFullTime,pubfn.getCommonTime=pubfn.timeUtil.getCommonTime,pubfn.getOffsetTime=pubfn.timeUtil.getOffsetTime,pubfn.getHourOffsetStartAndEnd=pubfn.timeUtil.getHourOffsetStartAndEnd,pubfn.getDayOffsetStartAndEnd=pubfn.timeUtil.getDayOffsetStartAndEnd,pubfn.getWeekOffsetStartAndEnd=pubfn.timeUtil.getWeekOffsetStartAndEnd,pubfn.getWeekStartAndEnd=pubfn.timeUtil.getWeekOffsetStartAndEnd,pubfn.getMonthOffsetStartAndEnd=pubfn.timeUtil.getMonthOffsetStartAndEnd,pubfn.getQuarterOffsetStartAndEnd=pubfn.timeUtil.getQuarterOffsetStartAndEnd,pubfn.getYearOffsetStartAndEnd=pubfn.timeUtil.getYearOffsetStartAndEnd,pubfn.getMonthStartAndEnd=pubfn.timeUtil.getMonthStartAndEnd,pubfn.validator=function(e){return function(t,n,i){let a=pubfn.test(n,e);return"function"!=typeof i||!a&&n?i(!1):void i()}},pubfn.test=function(e,t="",n=!1){let i;if(t=t.toLowerCase(),n&&(""===e||null==e))return!0;switch(t){case"mobile":return new RegExp(/^1[3|4|5|6|7|8|9][0-9]{9}$/).test(e);case"tel":return new RegExp(/^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/).test(e);case"card":return new RegExp(/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/).test(e);case"mobilecode":return new RegExp(/^[0-9]{6}$/).test(e);case"username":return new RegExp(/^[a-zA-Z]([-_a-zA-Z0-9]{2,31})$/).test(e);case"pwd":case"password":return new RegExp(/^([a-zA-Z0-9_@]){6,18}$/).test(e);case"paypwd":return new RegExp(/^[0-9]{6}$/).test(e);case"postal":return new RegExp(/[1-9]\d{5}(?!\d)/).test(e);case"qq":return new RegExp(/^[1-9][0-9]{4,9}$/).test(e);case"email":return new RegExp(/^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/).test(e);case"money":return new RegExp(/^\d*(?:\.\d{0,2})?$/).test(e);case"url":return new RegExp(/^(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/).test(e);case"ip":return new RegExp(/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/).test(e);case"date":return new RegExp(/^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/).test(e);case"time":return new RegExp(/^(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d$/).test(e);case"datetime":return new RegExp(/^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\s+(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d$/).test(e);case"english+number":return new RegExp(/^[a-zA-Z0-9]+$/).test(e);case"english+number+_":return new RegExp(/^[a-zA-Z0-9_]+$/).test(e);case"english+number+_-":return new RegExp(/^[a-zA-Z0-9_-]+$/).test(e);case"version":return new RegExp(/^([1-9]\d|[1-9])(.([1-9]\d|\d)){2}$/).test(e);case"number":return new RegExp(/^[0-9]+$/).test(e);case"english":return new RegExp(/^[a-zA-Z]+$/).test(e);case"chinese":return new RegExp(/^[\u4e00-\u9fa5]+$/gi).test(e);case"lower":return new RegExp(/^[a-z]+$/).test(e);case"upper":return new RegExp(/^[A-Z]+$/).test(e);case"html":return new RegExp(/<("[^"]*"|'[^']*'|[^'">])*>/).test(e);case"image":return i=e.split("?")[0],new RegExp(/\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)$/).test(i);case"video":return i=e.split("?")[0],new RegExp(/\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv|m3u8|3gp)$/).test(i);case"audio":return i=e.split("?")[0],new RegExp(/\.(mp3)$/).test(i);default:return!0}},pubfn.checkStr=pubfn.test,pubfn.priceFilter=function(e,t=""){return pubfn.isNull(e)?t:isNaN(e)?e:("string"==typeof e&&(e=parseFloat(e)),(e/100).toFixed(2))},pubfn.priceLeftFilter=function(e){let t="";return e&&(t=pubfn.priceFilter(e).split(".")[0]),t},pubfn.priceRightFilter=function(e){let t="";return e&&(t=pubfn.priceFilter(e).split(".")[1]),t},pubfn.percentageFilter=function(e,t=!0,n=""){return pubfn.isNull(e)?n:(isNaN(e)||("string"==typeof e&&(e=parseFloat(e)),e=parseFloat((100*e).toFixed(2)),t&&(e+="%")),e)},pubfn.discountFilter=function(e,t=!0,n=""){return pubfn.isNull(e)?n:isNaN(e)?e:("string"==typeof e&&(e=parseFloat(e)),(e=parseFloat((10*e).toFixed(2)))>10?"折扣不可以大于原价":10==e?"原价":0==e?"免费":e<0?"折扣不可以小于0":(t&&(e+=" 折"),e))},pubfn.objectDeleteInvalid=function(e){return Object.keys(e).forEach(t=>{void 0===e[t]&&delete e[t]}),e},pubfn.objectAssign=function(e,t,n=!0){return n&&pubfn.objectDeleteInvalid(t),Object.assign(e,t)},pubfn.copyObject=function(e){return void 0!==e?JSON.parse(JSON.stringify(e)):e},pubfn.deepClone=function(e){if([null,void 0,NaN,!1].includes(e))return e;if("object"!=typeof e&&"function"!=typeof e)return e;let t="[object Array]"===Object.prototype.toString.call(e)?[]:{};for(let n in e)e.hasOwnProperty(n)&&(t[n]="object"==typeof e[n]?pubfn.deepClone(e[n]):e[n]);return t},pubfn.formAssign=function(e,t){let n=pubfn.copyObject(e);return pubfn.objectAssign(n,t)},pubfn.arr_concat=function(e,t,n){n||(n="id"),e||(e=[]),t||(t=[]);let i=e.concat(t),a=[];if(-1!=n){let e=[];for(let t in i)-1==e.indexOf(i[t][n])&&(e.push(i[t][n]),a.push(i[t]))}else a=i;return a},pubfn.getData=function(e,t,n){let i=JSON.parse(JSON.stringify(e));t=t.replace(/\s+/g,"")+".";let a="";for(let e=0;ee[t])},pubfn.random=function(e,t,n){let i;if(pubfn.isNull(n))i=pubfn.randomFn(e,t);else{let a=0,r=1e5;do{a++,i=pubfn.randomFn(e,t)}while(n.indexOf(i)>-1&&ae){n+="0123456789"[i[e].charCodeAt()%10]}else n="0"+n;return n},pubfn.hidden=function(e="",t=0,n=0){let i=e.length-t-n,a="";for(let e=0;e-1&&(n=!0);return n},pubfn.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)},pubfn.isObject=function(e){return"[object Object]"===Object.prototype.toString.call(e)},pubfn.calcFreights=function(e,t){return pubfn.calcFreightDetail(e,t).total_amount},pubfn.calcFreightDetail=function(e,t){let{first_weight:n,first_weight_price:i,continuous_weight:a,continuous_weight_price:r,max_weight:o}=e;o||(o=1e9);let s=t,u=0,l=o,c=!1,d=0;for(;t>0;)c?(d++,t-=a,l-=a):(c=!0,u++,l=o,t-=n,l-=n),l<=0&&(c=!1);let p=i*u+r*d;return{weight:s,first_weight:n,first_weight_price:i,first_weight_count:u,continuous_weight:a,continuous_weight_price:r,continuous_weight_count:d,first_weight_amount:u*i,continuous_weight_amount:r*d,total_amount:p,formula:`${i} * ${u} + ${r} * ${d} = ${p}`}},pubfn.getNewObject=function(e,t){let n=pubfn.copyObject(e),i={};if(t&&t.length>0)for(let e in t){let a=t[e];pubfn.isNotNull(n[a])&&(i[a]=n[a])}else i=n;return i},pubfn.deleteObjectKeys=function(e,t=[]){var n={};if(e)for(let i in e)-1==t.indexOf(i)&&(n[i]=e[i]);return n},pubfn.arrayToTree=pubfn.treeUtil.arrayToTree,pubfn.treeToArray=pubfn.treeUtil.treeToArray,pubfn.wildcardTestOne=function(e,t){if(!t)return!1;let n=t.replace(new RegExp("\\*"),"(.*)"),i=0!==t.indexOf("*")?"^":"",a="*"!==t[t.length-1]?"$":"";return new RegExp(i+n+a).test(e)},pubfn.wildcardTest=function(e,t){let n=0;if("string"==typeof t)pubfn.wildcardTestOne(e,t)&&n++;else if("object"==typeof t)for(let i=0;i0?l=r+"天":o>0?l=o+"小时":s>0?l=s+"分钟":u>0&&(l=u+"秒"),l+=t},pubfn.dateDiff2=function(e,t="1秒"){if(!e)return"";"string"!=typeof e||isNaN(e)||(e=Number(e)),"number"==typeof e&&(10==e.toString().length&&(e*=1e3),e=new Date(e),e=pubfn.timeFormat(e)),"string"==typeof e&&(e=e=e.replace("T"," "),e=new Date(e.replace(/-/g,"/")));var n=new Date,i=864e5,a=36e5,r=e.getTime()-n.getTime(),o=Math.floor(r/i),s=Math.floor(r%i/a),u=Math.floor(r%i%a/6e4),l=Math.round(r%i%a%6e4/1e3),c=t;return o>0?c=o+"天":s>0?c=s+"小时":u>0?c=u+"分钟":l>0&&(c=l+"秒"),c},pubfn.numStr=function(e){"string"==typeof e&&(e=parseFloat(e));var t=e;if(e<1e3)t=e;else if(e<1e4){t=Math.floor(e/100)/10+"千"}else if(e<1e6){t=Math.floor(e/1e3)/10+"万"}else if(e<1e7){t=Math.floor(e/1e6)+"百万"}else if(e<1e8){t=Math.floor(e/1e7)+"千万"}else if(e>=1e8){t=Math.floor(e/1e7)/10+"亿"}return t},pubfn.calcSize=function(e=0,t,n,i=2,a="auto"){let r=0,o="";if((e=parseFloat(e))parseObjectKeys(e,t)))}return e}pubfn.snake2camel=function(e){return e.replace(isSnakeCase,(e,t)=>t?t.toUpperCase():"")},pubfn.camel2snake=function(e){return e.replace(isCamelCase,e=>"_"+e.toLowerCase())},pubfn.snake2camelJson=function(e){return parseObjectKeys(e,"snake2camel")},pubfn.camel2snakeJson=function(e){return parseObjectKeys(e,"camel2snake")},pubfn.string2Number=function(e,t={}){switch(Object.prototype.toString.call(e).slice(8,-1).toLowerCase()){case"string":if(e&&!isNaN(e)){let{mobile:n=!0,idCard:i=!0,startFrom0:a=!0,maxLength:r=14}=t;return e.length>r||(n&&pubfn.test(e,"mobile")||i&&pubfn.test(e,"card")||a&&e.length>1&&0===e.indexOf("0")&&1!==e.indexOf("."))?e:Number(e)}return e;case"object":const n=Object.keys(e);for(let t=0;t-1&&(t=e.substring(n+1)),t},pubfn.checkFileSuffix=function(e,t){let n=!1,i=pubfn.getFileSuffix(e);for(let e=0;e-1){n=!0;break}return n},pubfn.splitArray=function(e,t){let n=[];for(let i=0;i-1){var o=a.indexOf('"',r),s=a.substring(r,o);if(o>r){var u=a.indexOf("---",o),l=a.substring(o+1,u).trim();n[s]=l}}}return n},pubfn.getPlatform=function(e){return"web"===e?e="h5":"app"===e&&(e="app-plus"),e},pubfn.getClientUAByContext=function(e={}){return e.ua||e.CLIENTUA},pubfn.getPlatformForUniId=function(e={}){let t=e.PLATFORM;if(t=pubfn.getPlatform(t),"h5"===t){pubfn.getClientUAByContext(e).toLowerCase().indexOf("micromessenger")>-1&&(t="h5-weixin")}return t},pubfn.getUniCloudContext=function(){let e;try{e=uniCloud.context}catch(e){}return e},pubfn.getUniCloudFunctionName=function(){let e;try{let t=pubfn.getUniCloudContext();e=t.FUNCTION_NAME||t.function_name}catch(e){}return e},pubfn.getUniCloudProvider=function(){let e;try{e=uniCloud.context.SPACEINFO.provider}catch(e){}return e},pubfn.getUniCloudRequestId=function(){let e;try{e=pubfn.getUniCloudContext().requestId}catch(e){}return e},pubfn.getUniIdConfig=function(e={},t,n){const i=e.uni;let a;if(pubfn.isArray(i)){let e=uniCloud.env&&uniCloud.env.APPID?uniCloud.env.APPID:uniCloud.$context.APPID;a=pubfn.getListItem(i,"dcloudAppid",e),pubfn.isNull(a)&&(a=pubfn.getListItem(i,"isDefaultConfig",!0))}else a=i;if(pubfn.isNotNull(t)){let e=pubfn.getData(a,t);return pubfn.isNull(e)?n:e}return a},pubfn.batchRun=async function(e){let{main:t,data:n=[],concurrency:i=50}=e;if(pubfn.isArray(t))return pubfn.batchRun2(e);let a=n.length,r=[];if(0==a)return{stack:r,total:a};if(1===i){for(let e=0;e=a)break;let u=t(n[s],s);e.push(u)}try{await Promise.all(e).then(e=>{r=r.concat(e)})}catch(e){console.error(e)}}return{stack:r,total:a}}},pubfn.batchRun2=async function(e){let{main:t,concurrency:n=100}=e,i=t.length,a=[];if(0==i)return{stack:a,total:i};if(1===n){for(let e=0;e=i)break;let s=(0,t[o])();e.push(s)}try{await Promise.all(e).then(e=>{a=a.concat(e)})}catch(e){console.error(e)}}return{stack:a,total:i}}},pubfn.randomAsync=async function(e,t,n,i=500){let a;if("function"==typeof n){let r=0;do{r++,a=pubfn.randomFn(e,t)}while(!await n(a)&&r0?(new Date).getTime()+1e3*n:0};dataCache[e]=i},util$5.del=function(e){delete dataCache[e]},util$5.clear=function(e){if(e)for(let t in dataCache)0==t.indexOf(e)&&delete dataCache[t];else dataCache={}},util$5.isExpired=function(e){let t=!0,n=dataCache[e];return n&&(0==n.expired||n.expired>(new Date).getTime())&&(t=!1),t},util$5.getAll=function(e){let t={};if(e)for(let n in dataCache)0==n.indexOf(e)&&(t[e]=dataCache[e]);else t=dataCache;for(let e in t)util$5.isExpired(e)&&(delete t[e],delete dataCache[e]);return t};var temporaryCache=util$5,globalDataCache={},util$6={},globalDataDao={};globalDataCache.init=function(e){globalDataDao=(util$6=e).vk.system.globalDataDao},globalDataCache.get=async function(e,t=0,n,i=!0){return"function"==typeof n?globalDataCache.autoGet(e,t,n,i):globalDataCache._get(e)},globalDataCache.autoGet=async function(e,t=0,n,i=!0){let a,{vk:r}=util$6;try{a=await globalDataCache._get(e),r.pubfn.isNull(a)&&"function"==typeof n&&(a=await n(),void 0!==a&&i&&await r.globalDataCache.set(e,a,t))}catch(e){return}return a},globalDataCache._get=async function(e){let t;try{let n=await globalDataDao.find(e);if(n){let{value:i,expired_at:a}=n;globalDataCache.isExpired(n)?await globalDataCache.del(e):t=i}}catch(e){return}return t},globalDataCache.set=async function(e,t,n=0,i){let a;e&&void 0!==e.key&&void 0!==e.value?(a=e.key,t=e.value,n=e.second,i=e.comment):a=e;let r={code:0,msg:"ok"};try{if(!a)return{code:-1,msg:"key值不能为空"};let e=n>0?(new Date).getTime()+1e3*n:0;r=await globalDataDao.set({key:a,value:t,expired_at:e,comment:i})}catch(e){return console.error(e),{code:-1,msg:"异常"}}return r},globalDataCache.del=async function(e){await globalDataDao.del(e)},globalDataCache.clear=async function(e){if(e)return await globalDataDao.deleteByWhere({key:new RegExp("^"+e)})},globalDataCache.list=async function(e){return await globalDataDao.list(e)},globalDataCache.count=async function(e){return await globalDataDao.count(e)},globalDataCache.isExpired=function(e){let t=!0;return e&&(!e.expired_at||0==e.expired_at||e.expired_at>(new Date).getTime())&&(t=!1),t},globalDataCache.inc=async function(e,t=1,n=0){let i;e&&void 0!==e.key&&void 0!==e.value?(i=e.key,t=e.value,n=e.second):i=e;let a={code:0,msg:"ok"};try{if(!i)return{code:-1,msg:"key值不能为空"};let e=n>0?(new Date).getTime()+1e3*n:0;a=await globalDataDao.inc({key:i,value:t,expired_at:e})}catch(e){return{code:-1,msg:"异常",err:e}}return a},globalDataCache.uniqueAdd=async function(e,t=1,n=5){let{vk:i}=util$6,a={code:0,msg:"ok"};try{if(!e)return{code:-1,msg:"key值不能为空"};let r=n>0?(new Date).getTime()+1e3*n:0;await i.globalDataCache.deleteExpired(e);a.id=await globalDataDao.add({key:e,value:t,expired_at:r})}catch(e){return console.error(e),{code:-1,msg:"异常"}}return a},globalDataCache.deleteExpired=async function(e){await globalDataDao.deleteExpired(e)};var globalDataCache_1=globalDataCache,util$7={aes:{}};const aesKey="5fb2cd73c7b53918728417c50762e6d45fb2cd73c7b53918728417c50762e6d4",AESMODE={AES192:"aes192",AES256ECB:"aes-256-ecb"};util$7.aes.MODE=AESMODE,util$7.aes.encrypt=function(e){let{data:t,key:n,mode:i=AESMODE.AES192}=e,a=uniCloud.vk,{crypto:r,config:o}=a.getUnicloud();if(n||(n=a.pubfn.getData(o.vk,"crypto.aes",aesKey)),"object"==typeof t&&(t=JSON.stringify(t)),i===AESMODE.AES256ECB)return encryptUseAes256Ecb(t,n);if(i===AESMODE.AES192)return encryptUseAes192(t,n);throw new Error(`msg:不支持 ${i} 加密算法`)},util$7.aes.decrypt=function(e){let{data:t,key:n,mode:i=AESMODE.AES192}=e,a=uniCloud.vk,{crypto:r,config:o}=a.getUnicloud();if(a.pubfn.isNull(t))throw new Error("msg:待解密原文不能为空");if(n||(n=a.pubfn.getData(o.vk,"crypto.aes",aesKey)),i===AESMODE.AES256ECB)return decryptUseAes256Ecb(t,n);if(i===AESMODE.AES192)return decryptUseAes192(t,n);throw new Error(`msg:不支持 ${i} 加密算法`)};var crypto=util$7;function encryptUseAes192(e,t){let n=uniCloud.vk,{crypto:i}=n.getUnicloud();const a=i.createCipher(AESMODE.AES192,t);let r=a.update(e,"utf8","hex");return r+=a.final("hex"),r}function decryptUseAes192(e,t){let n,i=uniCloud.vk,{crypto:a}=i.getUnicloud();try{const i=a.createDecipher(AESMODE.AES192,t);n=i.update(e,"hex","utf8"),n+=i.final("utf8");try{n=JSON.parse(n)}catch(e){}}catch(e){throw"msg:解密失败"}return n}function encryptUseAes256Ecb(e,t){let n=uniCloud.vk,{crypto:i}=n.getUnicloud(),a=Buffer.from(e),r=t;r.length>32&&(r=r.substring(0,32)),r=Buffer.from(r);const o=i.createCipheriv(AESMODE.AES256ECB,r,"");o.setAutoPadding(!1);const s=16-a.length%16,u=Buffer.alloc(s,s);a=Buffer.concat([a,u]);let l=o.update(a,null,"base64");return l+=o.final("base64"),l}function decryptUseAes256Ecb(e,t){let n=uniCloud.vk,{crypto:i}=n.getUnicloud(),a=t;a.length>32&&(a=a.substring(0,32)),a=Buffer.from(a);try{const t=i.createDecipheriv(AESMODE.AES256ECB,a,"");t.setAutoPadding(!1);let n=t.update(e,"base64");n+=t.final();const r=n.charCodeAt(n.length-1);n=n.slice(0,n.length-r);try{n=JSON.parse(n)}catch(e){}return n}catch(e){throw"解密失败"}}var alipay={},ALIPAY_ALGORITHM_MAPPING={RSA:"RSA-SHA1",RSA2:"RSA-SHA256"};alipay.sign=function(e,t,n){let i=JSON.parse(JSON.stringify(t)),a=Object.assign({method:e,app_id:n.appid,charset:n.charset||"utf-8",version:n.version||"1.0",sign_type:n.signType||"RSA2"},i);n.appCertSn&&n.alipayRootCertSn&&(a=Object.assign({app_cert_sn:n.appCertSn,alipay_root_cert_sn:n.alipayRootCertSn},a));const r=i.bizContent||i.biz_content;r&&(a.biz_content=JSON.stringify(r));const o=alipay.sortObj(a);let s=alipay.objectToUrl(o);const u="PKCS8"===(n.keyType||"PKCS8")?"PRIVATE KEY":"RSA PRIVATE KEY";let l=alipay.formatKey(n.privateKey,u);const c=crypto$1.createSign(ALIPAY_ALGORITHM_MAPPING[a.sign_type]).update(s,"utf8").sign(l,"base64");return Object.assign(o,{sign:c})},alipay.formatUrl=function(e,t="https://openapi.alipay.com/gateway.do"){let n=t;const i=["app_id","method","format","charset","sign_type","sign","timestamp","version","notify_url","return_url","auth_token","app_auth_token","ws_service_url"];for(const t in e)if(i.indexOf(t)>-1){const i=encodeURIComponent(e[t]);n=`${n}${n.includes("?")?"&":"?"}${t}=${i}`,delete e[t]}return{execParams:e,url:n}},alipay.sortObj=function(e){new Array;let t=Object.keys(e).sort(),n={};for(let i in t)n[t[i]]=e[t[i]];return n},alipay.objectToUrl=function(e){let t="";for(let n in e)e[n]&&(t+=`&${n}=${e[n]}`);return t&&(t=t.substring(1)),t},alipay.formatKey=function(e,t){return`-----BEGIN ${t}-----\n${e}\n-----END ${t}-----`},alipay.getRequestRes=function(e,t){return e[t.replace(new RegExp("\\.","g"),"_")+"_response"]||e.error_response};var util$8=alipay,alipay$1={},util$9={};const serviceUrl="https://openapi.alipay.com/gateway.do",configKey="mp-alipay.oauth.alipay";function returnRes(e){return e.code=e.sub_code||e.code||0,e.msg=e.sub_msg||e.msg||"",e}alipay$1.init=function(e){util$9=e},alipay$1.getConfig=function(){let{vk:e,config:t}=util$9;return e.pubfn.getUniIdConfig(t)},alipay$1.request=async function(e={}){let{vk:t}=util$9,{method:n,data:i={},successText:a}=e,r=alipay$1.auth.getAppidInfo(e),o=Date.now(),s={timestamp:t.pubfn.timeFormat(o,"yyyy-MM-dd hh:mm:ss"),...i};const u=util$8.sign(n,s,r),{url:l,execParams:c}=util$8.formatUrl(u,serviceUrl);let d=await t.request({url:l,method:"POST",data:c}),p=await util$8.getRequestRes(d,n);return p.code&&"10000"!==p.code||(p.code=0,p.msg=a),p=returnRes(p),p},alipay$1.auth={},alipay$1.auth.getAppidInfo=function(e={}){let{appid:t,privateKey:n}=e,{vk:i,config:a}=util$9;const r=alipay$1.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.alipay.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};if(t=r.appid,n=r.privateKey,i.pubfn.isNullOne(t,n))throw console.log("config",e),new Error(`你使用了多小程序登录模式,但未找到${t}对应的 privateKey 请先在 uni-config-center/vk-unicloud/index.js 中配置支付宝小程序(vk.oauth.alipay.list)的appid和privateKey`)}}else{let e=i.pubfn.getData(r,configKey)||{};if(t=e.appid,n=e.privateKey,i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error(`请先在 uni-config-center/uni-id/config.json 中配置支付宝小程序(${configKey})的appid和privateKey`)}return{appid:t,privateKey:n}},alipay$1.auth.code2Session=async function(e={}){let{vk:t,uniID:n}=util$9,{platform:i,needKey:a=!1}=e;i||(i="mp-alipay");let r=await alipay$1.auth.code2SessionMp(e);try{let e=t.crypto.aes.encrypt({data:r});r.encryptedKey=e}catch(e){}return a||(delete r.sessionKey,delete r.accessToken,delete r.refreshToken),delete r.privateKey,r.platform=i,r.openid=r.userId,r},alipay$1.auth.code2SessionMp=async function(e={}){let{appid:t}=alipay$1.auth.getAppidInfo(e),n=e.code||e.js_code,{vk:i}=util$9,a=await alipay$1.request({method:"alipay.system.oauth.token",data:{code:n,grant_type:"authorization_code"}});return{...i.pubfn.snake2camelJson(a),appid:t,code:0,msg:"ok"}},alipay$1.security={},alipay$1.security.msgSecCheck=async function(e={}){return{code:-1,msg:"支付宝未提供此API"}},alipay$1.security.imgSecCheck=async function(e={}){return{code:-1,msg:"支付宝未提供此API"}},alipay$1.acode={},alipay$1.acode.getMiniCode=async function(e={}){let{page:t,scene:n="miniCode=1",line_color:i}=e,a={url_param:t,query_param:n,describe:"推广",color:i};return await alipay$1.request({method:"alipay.open.app.qrcode.create",data:{biz_content:a},successText:"生成成功"})},alipay$1.subscribeMessage={},alipay$1.subscribeMessage.send=async function(e={}){let{touser:t,form_id:n,template_id:i,page:a,data:r}=e,{appid:o}=alipay$1.auth.getAppidInfo(e),s={to_user_id:t,form_id:n,user_template_id:i,page:a,data:r};return await alipay$1.request({method:"alipay.open.app.mini.templatemessage.send",data:{biz_content:s},successText:"发送成功"})};var alipay_1=alipay$1,baidu={},util$a={};baidu.init=function(e){util$a=e},baidu.open={},baidu.open.auth={},baidu.open.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$a;if(!t){let e=i.pubfn.getData(a,"vk.service.openapi.baidu")||{};t=e.appid,n=e.appsecret}if(i.pubfn.isNullOne(t,n))throw new Error("请在uniCloud/cloudfunctions/common/uni-config-center/vk-unicloud/index.js中配置并检查百度开放平台的appid和appsecret是否正确,参数路径:vk.service.openapi.baidu");return{appid:t,appsecret:n}},baidu.open.auth.getAccessTokenFn=async function(e={}){let{appid:t,appsecret:n}=baidu.open.auth.getAppidInfo(e),{vk:i,config:a}=util$a,r=await i.request({url:`https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=${t}&client_secret=${n}`,method:"GET"});return r.error_code?(console.error("getAccessToken失败:",r),{code:r.error_code,msg:r.error_msg,err:r}):{...r,code:0,msg:"ok"}},baidu.open.auth.getAccessToken=async function(e={}){let t,{appid:n,appsecret:i}=baidu.open.auth.getAppidInfo(e),{cache:a=!0}=e,{vk:r}=util$a,o="openapi-baidu-"+n;if(a&&(t=await r.globalDataCache.get(o)),r.pubfn.isNull(t)){let n=await baidu.open.auth.getAccessTokenFn(e);0===n.code&&(t=n.access_token,await r.globalDataCache.set(o,t,n.expires_in-3600),await r.globalDataCache.deleteExpired())}return t},baidu.open.ocr={},baidu.open.ocr.business_license=async function(e={}){let{image:t,url:n}=e;return await baidu.open.request({...e,action:"ocr/v1/business_license",actionVersion:"2.0",data:{image:t,url:n}})},baidu.open.ocr.idcard=async function(e={}){let{image:t,url:n,id_card_side:i,detect_risk:a,detect_photo:r}=e;return await baidu.open.request({...e,action:"ocr/v1/idcard",actionVersion:"2.0",data:{image:t,url:n,id_card_side:i,detect_risk:a,detect_photo:r}})},baidu.open.request=async function(e={}){let{vk:t}=util$a,n=await baidu.open.auth.getAccessToken(e);if(!n)return{code:-1,msg:"获取access_token失败,请检查vk-unicloud配置下vk.service.openapi.baidu配置的appid和appsecret是否正确"};let{action:i,actionVersion:a="2.0",header:r={"content-type":"application/x-www-form-urlencoded"},data:o}=e,s=await t.request({url:`https://aip.baidubce.com/rest/${a}/${i}?access_token=${n}`,method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},data:o});return s.error_code?{code:s.error_code,msg:s.error_msg,err:s}:{...s,code:0,msg:"ok"}};var baidu_1=baidu,douyin={},util$b={};const serviceUrl$1="https://developer.toutiao.com",configKey$1="mp-toutiao.oauth.toutiao";function returnRes$1(e){return e.code=e.err_no||0,e.msg=e.err_tips||"",e}douyin.init=function(e){util$b=e},douyin.getConfig=function(){let{vk:e,config:t}=util$b;return e.pubfn.getUniIdConfig(t)},douyin.request=async function(e={}){let{vk:t}=util$b,{url:n,data:i={}}=e,{appid:a,appsecret:r}=douyin.auth.getAppidInfo(e);if(!0===i.access_token){let t=await douyin.auth.getAccessToken(e);if(!t)return{code:-1,msg:`获取access_token失败,请检查uni-id配置${configKey$1}配置下的appid和appsecret是否正确`};i.access_token=t}-1===n.indexOf("http")&&(n=`${serviceUrl$1}/${n}`);let o=await t.request({contentType:"json",dataType:"json",...e,url:n});return o=returnRes$1(o),o},douyin.auth={},douyin.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$b;const r=douyin.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.toutiao.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};if(t=r.appid,n=r.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",e),new Error(`你使用了多小程序登录模式,但未找到${t}对应的 appsecret 请先在 uni-config-center/vk-unicloud/index.js 中配置抖音小程序(vk.oauth.toutiao.list)的appid和appsecret`)}}else{let e=i.pubfn.getData(r,configKey$1)||{};if(t=e.appid,n=e.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error(`请先在 uni-config-center/uni-id/config.json 中配置抖音小程序(${configKey$1})的appid和appsecret`)}return{appid:t,appsecret:n}},douyin.auth.getAccessTokenFn=async function(e={}){let{appid:t,appsecret:n}=douyin.auth.getAppidInfo(e),{vk:i,config:a}=util$b,r=await i.request({url:serviceUrl$1+"/api/apps/v2/token",method:"POST",data:{appid:t,secret:n,grant_type:"client_credential"},contentType:"json",dataType:"json"});return r.err_no?(console.error("getAccessToken失败:",r),{code:r.err_no,msg:r.err_tips,err:r}):{code:0,msg:"ok",access_token:r.data.access_token,expires_in:r.data.expires_in}},douyin.auth.getAccessToken=async function(e={}){let t,{appid:n,appsecret:i}=douyin.auth.getAppidInfo(e),{cache:a=!0}=e,{vk:r}=util$b,o="mp-toutiao-access_token-"+n;if(a&&(t=await r.globalDataCache.get(o)),r.pubfn.isNull(t)){let n=await douyin.auth.getAccessTokenFn(e);0===n.code&&(t=n.access_token,await r.globalDataCache.set(o,t,240),await r.globalDataCache.deleteExpired())}return t},douyin.auth.code2Session=async function(e={}){let{vk:t,uniID:n}=util$b,{platform:i,needKey:a=!1}=e;i||(i="mp-toutiao");let r=await douyin.auth.code2SessionMp(e);try{let e=t.crypto.aes.encrypt({data:r});r.encryptedKey=e}catch(e){}return a||(delete r.sessionKey,delete r.accessToken,delete r.refreshToken),delete r.appsecret,r.platform=i,r},douyin.auth.code2SessionMp=async function(e={}){let{appid:t,appsecret:n}=douyin.auth.getAppidInfo(e),i=e.code||e.js_code,a=e.anonymousCode,{vk:r}=util$b,o=await douyin.request({url:"api/apps/v2/jscode2session",method:"POST",data:{appid:t,secret:n,code:i,anonymous_code:a}});return o.code?(40018!==o.code&&40019!==o.code||(o.msg="无效code,请重新获取"),o):{...r.pubfn.snake2camelJson(o.data),appid:t,appsecret:n,code:0,msg:"ok"}},douyin.security={},douyin.security.msgSecCheck=async function(e={}){let{content:t,tasks:n}=e,{appid:i,appsecret:a}=douyin.auth.getAppidInfo(e),r=await douyin.auth.getAccessToken(e);if(!r)return{code:-1,msg:`获取access_token失败,请检查uni-id配置${configKey$1}配置下的appid和appsecret是否正确`};n||(n=[{content:t}]);let o=await douyin.request({url:"api/v2/tags/text/antidirt",method:"POST",header:{"X-Token":r},data:{tasks:n}});try{let e,t;o.data.map((n,i)=>{n.predicts.map((n,a)=>{n.hit&&(e||(e=!0,t=i))})}),e?(o.taskIndex=t,o.code=87014):o.code=0}catch(e){}return 40001===o.code&&(o.msg="access_token错误"),87014===o.code&&(o.msg="内容含有违法违规内容,请检查!"),0===o.code&&(o.msg="ok"),o},douyin.security.imgSecCheck=async function(e={}){let{image:t,access_token:n=!0}=e,i=e.base64||e.image_data,{appid:a,appsecret:r}=douyin.auth.getAppidInfo(e);if(i){let e=i.indexOf("base64,");e>-1&&(i=i.substring(e+"base64,".length))}let o=await douyin.request({url:"api/apps/censor/image",method:"POST",data:{app_id:a,access_token:n,image:t,image_data:i}});try{let e;o.predicts.map((t,n)=>{t.hit&&(e=!0)}),o.code=e?87014:0}catch(e){}return 87014===o.code&&(o.msg="内容含有违法违规内容,请检查!"),0===o.code&&(o.msg="ok"),o},douyin.acode={},douyin.acode.getMiniCode=async function(e={}){let{path:t,appname:n="douyin",width:i,line_color:a,background:r,set_icon:o,access_token:s=!0}=e,{appid:u,appsecret:l}=douyin.auth.getAppidInfo(e),c=await douyin.request({url:"api/apps/qrcode",method:"POST",data:{access_token:s,appname:n,path:t,width:i,line_color:a,background:r,set_icon:o},dataType:"default",useContent:!0,header:{"content-type":"application/json;charset=utf8"}});if(c.length<500){let e=c.toString();try{return e=JSON.parse(e),{code:e.errcode,msg:e.errmsg}}catch(e){}return{code:-1,err:err}}return c},douyin.subscribeMessage={},douyin.subscribeMessage.send=async function(e={}){let{touser:t,template_id:n,page:i,data:a,access_token:r=!0}=e,{appid:o,appsecret:s}=douyin.auth.getAppidInfo(e);return await douyin.request({url:"api/apps/subscribe_notification/developer/v1/notify",method:"POST",data:{access_token:r,app_id:o,tpl_id:n,open_id:t,data:a,page:i}})};var douyin_1=douyin,qq={},util$c={};const serviceUrl$2="https://api.q.qq.com",configKey$2="mp-qq.oauth.qq";function returnRes$2(e){return e.code=e.errcode||e.errCode||0,e.msg=e.errmsg||e.errMsg||"",e}qq.init=function(e){util$c=e},qq.getConfig=function(){let{vk:e,config:t}=util$c;return e.pubfn.getUniIdConfig(t)},qq.request=async function(e={}){let{vk:t}=util$c,{url:n,method:i,data:a={}}=e;if(-1===n.indexOf("http")&&(n=`${serviceUrl$2}/${n}`),!0===a.access_token){delete a.access_token;let t=await qq.auth.getAccessToken(e);if(!t)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-qq配置的appid和appsecret是否正确"};n+=-1===n.indexOf("?")?"?":"&",n+="access_token="+t}let r=await t.request({...e,url:n});return r=returnRes$2(r),r},qq.auth={},qq.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$c;const r=qq.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.qq.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};if(t=r.appid,n=r.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",e),new Error(`你使用了多小程序登录模式,但未找到${t}对应的 appsecret 请先在 uni-config-center/vk-unicloud/index.js 中配置QQ小程序(vk.oauth.qq.list)的appid和appsecret`)}}else{let e=i.pubfn.getData(r,configKey$2)||{};if(t=e.appid,n=e.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error("请先在 uni-config-center/uni-id/config.json 中配置QQ小程序(mp-qq.oauth.qq)的appid和appsecret")}return{appid:t,appsecret:n}},qq.auth.getAccessTokenFn=async function(e={}){let{appid:t,appsecret:n}=qq.auth.getAppidInfo(e),{vk:i,config:a}=util$c,r=await i.request({url:`https://api.q.qq.com/api/getToken?grant_type=client_credential&appid=${t}&secret=${n}`,method:"GET"});return r.errcode?(console.error("getAccessToken失败:",r),{code:r.errcode,msg:r.errmsg,err:r}):{code:0,msg:"ok",access_token:r.access_token,expires_in:r.expires_in}},qq.auth.getAccessToken=async function(e={}){let t,{appid:n,appsecret:i}=qq.auth.getAppidInfo(e),{cache:a=!0}=e,{vk:r}=util$c,o="mp-qq-access_token-"+n;if(a&&(t=await r.globalDataCache.get(o)),r.pubfn.isNull(t)){let n=await qq.auth.getAccessTokenFn(e);0===n.code&&(t=n.access_token,await r.globalDataCache.set(o,t,240),await r.globalDataCache.deleteExpired())}return t},qq.auth.code2Session=async function(e={}){let{vk:t,uniID:n}=util$c,{platform:i,needKey:a=!1}=e;i||(i="mp-qq");let r=await qq.auth.code2SessionMpWeixin(e);try{let e=t.crypto.aes.encrypt({data:r});r.encryptedKey=e}catch(e){}return a||(delete r.sessionKey,delete r.accessToken,delete r.refreshToken),delete r.appsecret,r.platform=i,r},qq.auth.code2SessionMpWeixin=async function(e={}){let{appid:t,appsecret:n}=qq.auth.getAppidInfo(e),i=e.code||e.js_code,{vk:a}=util$c,r=await qq.request({url:`sns/jscode2session?appid=${t}&secret=${n}&js_code=${i}&grant_type=authorization_code`,method:"GET"});return r.code?(-101600007===r.code&&(r.msg="appid错误"),-101222100===r.code&&(r.msg="appsecret错误"),-2100===r.code&&(r.msg="无效code,请重新获取"),r):(r=a.pubfn.snake2camelJson(r),{appid:t,appsecret:n,...r,code:0,msg:"ok"})},qq.security={},qq.security.msgSecCheck=async function(e={}){let{content:t,access_token:n=!0}=e,{appid:i,appsecret:a}=qq.auth.getAppidInfo(e),r=await qq.request({url:"api/json/security/MsgSecCheck",method:"POST",data:{access_token:n,appid:i,content:t}});return 40001===r.code&&(r.msg="access_token错误"),87014===r.code&&(r.msg="内容含有违法违规内容,请检查!"),r},qq.security.imgSecCheck=async function(e={}){let{vk:t}=util$c,{dataBuffer:n,formData:i,base64:a}=e,{appid:r,appsecret:o}=qq.auth.getAppidInfo(e),s=await qq.auth.getAccessToken(e);if(!s)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-qq配置的appid和appsecret是否正确"};if(a&&!n){let e="base64,",t=a.indexOf(e);t>-1&&(a=a.substring(t+e.length)),n=new Buffer(a,"base64")}n&&!i&&(i=new t.formDataUtil.FormData,i.append("appid",r),i.append("media",n,{filename:Date.now()+".png",contentType:"image/png"}));let u=await qq.request({url:"api/json/security/ImgSecCheck?access_token="+s,content:i.getBuffer(),headers:i.getHeaders()});switch(u.code){case 40001:u.msg="access_token错误";break;case 87014:u.msg="图片内容含有违法违规内容,请检查!";break;case 40006:u.msg="图片大小不能超过1M"}return u},qq.acode={},qq.acode.getMiniCode=async function(e={}){let{path:t,access_token:n=!0}=e,{appid:i,appsecret:a}=qq.auth.getAppidInfo(e),r=await qq.request({url:"api/json/qqa/CreateMiniCode",method:"POST",data:{access_token:n,appid:i,path:t},dataType:"default",useContent:!0,header:{"content-type":"application/json;charset=utf8"}});if(r.length<500){let e=r.toString();try{e=JSON.parse(e)}catch(e){}return r=returnRes$2(e),40001===r.code&&(r.msg="access_token错误"),41030===r.code&&(r.msg="小程序页面不存在!"),r}return r},qq.subscribeMessage={},qq.subscribeMessage.send=async function(e={}){let{vk:t}=util$c,{touser:n,template_id:i,page:a,data:r,emphasis_keyword:o,oac_appid:s,use_robot:u}=e,l=await qq.auth.getAccessToken(e);if(!l)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-qq配置的appid和appsecret是否正确"};let c=await t.request({url:`${serviceUrl$2}/api/json/subscribe/SendSubscriptionMessage?access_token=${l}`,method:"POST",data:{touser:n,template_id:i,page:a,data:r,emphasis_keyword:o,oac_appid:s,use_robot:u},useContent:!0,header:{"content-type":"application/json;charset=utf8"}});switch(c=returnRes$2(c),c.code){case 40003:c.msg="touser字段openid为空或者不正确";break;case 40037:c.msg="订阅模板id为空不正确";break;case 43101:c.msg="用户未订阅该消息";break;case 40036:c.msg="您的小程序不支持发送长期订阅消息";break;case 47003:c.msg="模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错";break;case 41030:c.msg="page路径不正确,需要保证在现网版本小程序中存在"}return c};var qq_1=qq,weixin={},util$d={};function returnRes$3(e){return e.code=e.errcode||0,e.msg=e.errmsg||"",e}weixin.init=function(e){util$d=e},weixin.getConfig=function(){let{vk:e,config:t}=util$d;return e.pubfn.getUniIdConfig(t)},weixin.request=async function(e={}){let{vk:t}=util$d,{url:n,method:i,data:a,access_token:r}=e;if(r||(r=await weixin.auth.getAccessToken(e)),!r)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};-1===n.indexOf("http")&&(n="https://api.weixin.qq.com/"+n),i||(i=t.pubfn.isNull(a)?"GET":"POST"),i&&"POST"===i.toUpperCase()&&void 0===e.useContent&&(e.useContent=!0),n+=-1===n.indexOf("?")?"?":"&",n+="access_token="+r;let o=await t.request({...e,url:n});return o=returnRes$3(o),o},weixin.decrypt={},weixin.decrypt.getPhoneNumber=async function(e={}){let{vk:t}=util$d,{code:n}=e;if(!n&&e.encryptedData)return await weixin.decrypt.getPhoneNumberByEncryptedData(e);let i={code:0,msg:"ok"},a=t.pubfn.isNullOneByObject({code:n});if(a)return{code:-1,msg:a+"不能为空"};let r=await t.openapi.weixin.request({method:"POST",url:"wxa/business/getuserphonenumber",data:{code:n}});return 0!==r.code?r:(i.data=r.phone_info,i.phone=i.data.phoneNumber,i.mobile=i.data.phoneNumber,i)},weixin.decrypt.getPhoneNumberByEncryptedData=async function(e={}){let t,{vk:n}=util$d,{encryptedData:i,iv:a,sessionKey:r,encryptedKey:o,code:s}=e,u={code:0,msg:"ok"},l=n.pubfn.isNullOneByObject({encryptedData:i,iv:a});if(l)return{code:-1,msg:l+"不能为空"};if(o){let e=n.crypto.aes.decrypt({data:o});t=e.appid,r=e.sessionKey}else{t=weixin.auth.getAppidInfo(e).appid}return u.data=weixin.decrypt.decryptData({appid:t,encryptedData:i,iv:a,sessionKey:r}),u.phone=u.data.phoneNumber,u.mobile=u.data.phoneNumber,u},weixin.decrypt.decryptData=function(e={}){let t,{appid:n,encryptedData:i,iv:a,sessionKey:r}=e,{vk:o,crypto:s}=util$d,u=new Buffer(r,"base64"),l=new Buffer(i,"base64"),c=new Buffer(a,"base64");try{let e=s.createDecipheriv("aes-128-cbc",u,c);e.setAutoPadding(!0),t=e.update(l,"binary","utf8"),t+=e.final("utf8"),t=JSON.parse(t)}catch(e){throw new Error(e)}return t.watermark.appid!==n?{code:-1,msg:"appid不一致"}:t},weixin.auth={},weixin.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$d;const r=weixin.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.weixin.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};if(t=r.appid,n=r.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",e),new Error(`你使用了多小程序登录模式,但未找到${t}对应的 appsecret 请先在 uni-config-center/vk-unicloud/index.js 中配置微信小程序(vk.oauth.weixin.list)的appid和appsecret`)}}else{let e=i.pubfn.getData(r,"mp-weixin.oauth.weixin")||{};if(t=e.appid,n=e.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error("请先在 uni-config-center/uni-id/config.json 中配置微信小程序(mp-weixin)的appid和appsecret")}return{appid:t,appsecret:n}},weixin.auth.getAccessTokenFn=async function(e={}){let{appid:t,appsecret:n}=weixin.auth.getAppidInfo(e),{vk:i,config:a}=util$d,r=await i.request({url:`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${t}&secret=${n}`,method:"GET"});return r.errcode?(console.error("getAccessToken失败:",r),{code:r.errcode,msg:r.errmsg,err:r}):{code:0,msg:"ok",access_token:r.access_token,expires_in:r.expires_in}},weixin.auth.getAccessToken=async function(e={}){let t,{appid:n,appsecret:i}=weixin.auth.getAppidInfo(e),{cache:a=!0}=e,{vk:r}=util$d,o="mp-weixin-"+n;if(a&&(t=await r.globalDataCache.get(o)),r.pubfn.isNull(t)){let n=await weixin.auth.getAccessTokenFn(e);0===n.code&&(t=n.access_token,await r.globalDataCache.set(o,t,240),await r.globalDataCache.deleteExpired())}return t},weixin.auth.code2Session=async function(e={}){let t,{vk:n,uniID:i}=util$d,{platform:a,context:r,needKey:o=!1}=e;a||(a=n.pubfn.getPlatformForUniId(r)||"mp-weixin"),t="mp-weixin"===a?await weixin.auth.code2SessionMpWeixin(e):"h5-weixin"===a?await weixin.h5.auth.code2Session(e):await i.code2SessionWeixin(e);try{let e=n.crypto.aes.encrypt({data:t});t.encryptedKey=e}catch(e){}return o||(delete t.sessionKey,delete t.accessToken,delete t.refreshToken),delete t.appsecret,t.platform=a,t},weixin.auth.code2SessionMpWeixin=async function(e={}){let{appid:t,appsecret:n}=weixin.auth.getAppidInfo(e),i=e.code||e.js_code,{vk:a}=util$d,r=await a.request({url:`https://api.weixin.qq.com/sns/jscode2session?appid=${t}&secret=${n}&js_code=${i}&grant_type=authorization_code`,method:"GET"});if(r.errcode){let e=r.errmsg;return 40163===r.errcode&&(e="该code已被使用,请重新获取"),40029===r.errcode&&(e="无效code,请重新获取"),{...r,code:r.errcode,msg:e}}return r=a.pubfn.snake2camelJson(r),{appid:t,appsecret:n,...r,code:0,msg:"ok"}},weixin.wxacode={},weixin.wxacode.getUnlimited=async function(e={}){let{vk:t}=util$d,{access_token:n,page:i,scene:a,check_path:r,env_version:o,width:s,auto_color:u,line_color:l,is_hyaline:c}=e;if(n||(n=await weixin.auth.getAccessToken(e)),!n)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let d=await t.request({url:"https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+n,method:"POST",data:{page:i,scene:a,check_path:r,env_version:o,width:s,auto_color:u,line_color:l,is_hyaline:c},dataType:"default",useContent:!0,headers:{encoding:null}});if(d.length<500){let e=d.toString();try{e=JSON.parse(e)}catch(e){}return d=returnRes$3(e),40001===d.code&&(d.msg="access_token错误"),41030===d.code&&(d.msg="小程序页面不存在!"),d}return Buffer.isBuffer(d)?d:returnRes$3(d)},weixin.urlscheme={},weixin.urlscheme.generate=async function(e={}){let{vk:t}=util$d,{access_token:n,jump_wxa:i,is_expire:a,expire_time:r,expire_type:o,expire_interval:s}=e;if(n||(n=await weixin.auth.getAccessToken(e)),!n)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let u=await t.request({url:"https://api.weixin.qq.com/wxa/generatescheme?access_token="+n,method:"POST",data:{jump_wxa:i,is_expire:a,expire_time:r,expire_type:o,expire_interval:s},useContent:!0});return u=returnRes$3(u),40001===u.code&&(u.msg="access_token错误"),40165===u.code&&(u.msg="小程序页面不存在!"),u},weixin.urllink={},weixin.urllink.generate=async function(e={}){let{vk:t}=util$d,{access_token:n,path:i,query:a,is_expire:r,expire_type:o,expire_time:s,expire_interval:u,cloud_base:l,env_version:c}=e;if(n||(n=await weixin.auth.getAccessToken(e)),!n)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let d=await t.request({url:"https://api.weixin.qq.com/wxa/generate_urllink?access_token="+n,method:"POST",data:{path:i,query:a,is_expire:r,expire_type:o,expire_time:s,expire_interval:u,cloud_base:l,env_version:c},useContent:!0});return d=returnRes$3(d),40001===d.code&&(d.msg="access_token错误"),40165===d.code&&(d.msg="小程序页面不存在!"),d},weixin.security={},weixin.security.msgSecCheck=async function(e={}){let{vk:t}=util$d,{content:n,version:i,scene:a,openid:r,title:o,nickname:s,signature:u}=e,l=await weixin.auth.getAccessToken(e);if(!l)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let c=await t.request({url:"https://api.weixin.qq.com/wxa/msg_sec_check?access_token="+l,method:"POST",data:{content:n,version:i,scene:a,openid:r,title:o,nickname:s,signature:u},useContent:!0});return c=returnRes$3(c),40001===c.code&&(c.msg="access_token错误"),87014===c.code&&(c.msg="内容含有违法违规内容,请检查!"),2===i&&c.result&&100!==c.result.label&&(c.code=c.result.label,c.msg="内容含有违法违规内容,请检查!"),c},weixin.security.imgSecCheck=async function(e={}){let{vk:t}=util$d,{dataBuffer:n,formData:i,base64:a}=e,r=await weixin.auth.getAccessToken(e);if(!r)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};if(a&&!n){let e="base64,",t=a.indexOf(e);t>-1&&(a=a.substring(t+e.length)),n=new Buffer(a,"base64")}n&&!i&&(i=new t.formDataUtil.FormData,i.append("media",n,{filename:Date.now()+".png",contentType:"image/png"}));let o=await t.request({url:"https://api.weixin.qq.com/wxa/img_sec_check?access_token="+r,content:i.getBuffer(),headers:i.getHeaders()});switch(o=returnRes$3(o),o.code){case 40001:o.msg="access_token错误";break;case 87014:o.msg="图片内容含有违法违规内容,请检查!";break;case 40006:o.msg="图片大小不能超过1M"}return o},weixin.riskControl={},weixin.riskControl.getUserRiskRank=async function(e={}){let{vk:t}=util$d,{appid:n,openid:i,scene:a,mobile_no:r,client_ip:o,email_address:s,extended_info:u,is_test:l}=e,c=await weixin.auth.getAccessToken(e);if(!c)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let d=await t.request({url:"https://api.weixin.qq.com/wxa/getuserriskrank?access_token="+c,method:"POST",data:{appid:n,openid:i,scene:a,mobile_no:r,client_ip:o,email_address:s,extended_info:u,is_test:l},useContent:!0});return d=returnRes$3(d),40001===d.code&&(d.msg="access_token错误"),d},weixin.subscribeMessage={},weixin.subscribeMessage.send=async function(e={}){let{vk:t}=util$d,{touser:n,template_id:i,page:a,data:r,miniprogram_state:o="formal",lang:s="zh_CN"}=e,u=await weixin.auth.getAccessToken(e);if(!u)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let l=await t.request({url:"https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token="+u,method:"POST",data:{touser:n,template_id:i,page:a,data:r,miniprogram_state:o,lang:s},useContent:!0});switch(l=returnRes$3(l),l.code){case 40003:l.msg="touser字段openid为空或者不正确";break;case 40037:l.msg="订阅模板id为空不正确";break;case 43101:l.msg="用户未订阅该消息";break;case 47003:l.msg="模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错";break;case 41030:l.msg="page路径不正确,需要保证在现网版本小程序中存在"}return l},weixin.uniformMessage={},weixin.uniformMessage.send=async function(e={}){let{vk:t}=util$d,{appid:n,touser:i,template_appid:a,template_id:r,url:o,miniprogram:s,data:u}=e,l=await weixin.auth.getAccessToken(e);if(!l)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};if(!a){a=weixin.h5.auth.getAppidInfo({appid:a}).appid}let c=await t.request({url:"https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token="+l,method:"POST",data:{touser:i,mp_template_msg:{appid:a,template_id:r,url:o,miniprogram:s,data:u}},useContent:!0});switch(c=returnRes$3(c),c.code){case 40003:c.msg="touser字段openid为空或者不正确";break;case 40037:c.msg="订阅模板id为空不正确";break;case 43101:c.msg="用户未订阅该消息";break;case 47003:c.msg="模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错";break;case 41030:c.msg="page路径不正确,需要保证在现网版本小程序中存在"}return c},weixin.livebroadcast={},weixin.livebroadcast.getLiveInfo=async function(e={}){let{vk:t}=util$d,{pageIndex:n=1,pageSize:i=100}=e,a=await weixin.auth.getAccessToken(e);if(!a)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};if(n<=0)return{code:-1,msg:"pageIndex必须是大于0的整数"};let r=(n-1)*i,o=i,s=await t.request({url:"https://api.weixin.qq.com/wxa/business/getliveinfo?access_token="+a,method:"POST",data:{start:r,limit:o},useContent:!0});switch(s=returnRes$3(s),s.code){case 941e4:s.msg="直播间列表为空"}return s},weixin.app={},weixin.app.auth={},weixin.app.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$d;const r=weixin.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.weixin.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};t=r.appid,n=r.appsecret}}else{let e=i.pubfn.getData(r,"app-plus.oauth.weixin")||{};t=e.appid,n=e.appsecret}if(i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error("请先在 uni-config-center/uni-id/config.json 中配置微信app登录(app-plus)的appid和appsecret");return{appid:t,appsecret:n}},weixin.app.auth.getAccessToken=async function(e={}){let{appid:t,appsecret:n}=weixin.app.auth.getAppidInfo(e),{vk:i,config:a}=util$d,{code:r}=e,o=await i.request({url:`https://api.weixin.qq.com/sns/oauth2/access_token?appid=${t}&secret=${n}&code=${r}&grant_type=authorization_code`,method:"GET"});return o.errcode?(console.error("getAccessToken失败:",o),{code:o.errcode,msg:o.errmsg,err:o}):{...o,code:0,msg:"ok"}},weixin.app.auth.getUserInfo=async function(e={}){let{vk:t,config:n}=util$d,{access_token:i,openid:a,lang:r="zh-CN"}=e;if(!i)return{code:-1,msg:"access_token不能为空"};let o=await t.request({url:`https://api.weixin.qq.com/sns/userinfo?access_token=${i}&openid=${a}$lang=${r}`,method:"GET"});return o.errcode?(console.error("getUserInfo失败:",o),{code:o.errcode,msg:o.errmsg,err:o}):{...o,code:0,msg:"ok",avatar:o.headimgurl,gender:o.sex}},weixin.h5={},weixin.h5.request=async function(e={}){let{vk:t}=util$d,{url:n,method:i,data:a,access_token:r}=e;if(r||(r=await weixin.h5.auth.getAccessToken(e)),!r)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的h5-weixin配置的appid和appsecret是否正确"};-1===n.indexOf("http")&&(n="https://api.weixin.qq.com/"+n),i||(i=t.pubfn.isNull(a)?"GET":"POST"),i&&"POST"===i.toUpperCase()&&void 0===e.useContent&&(e.useContent=!0),n+=-1===n.indexOf("?")?"?":"&",n+="access_token="+r;let o=await t.request({...e,url:n});return o=returnRes$3(o),o},weixin.h5.auth={},weixin.h5.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$d;const r=weixin.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.weixin.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};t=r.appid,n=r.appsecret}}else{let e=i.pubfn.getData(r,"h5-weixin.oauth.weixin")||{};t=e.appid,n=e.appsecret}if(i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error("请先配置微信公众号appid和appsecret");return{appid:t,appsecret:n}},weixin.h5.auth.code2Session=async function(e={}){let{appid:t,appsecret:n}=weixin.h5.auth.getAppidInfo(e),{code:i}=e,{vk:a}=util$d,r=await a.request({url:`https://api.weixin.qq.com/sns/oauth2/access_token?appid=${t}&secret=${n}&code=${i}&grant_type=authorization_code`,method:"GET"});if(r.errcode){let e=r.errmsg;return 40163===r.errcode&&(e="该code已被使用,请重新获取"),40029===r.errcode&&(e="无效code,请重新获取"),{...r,code:r.errcode,msg:e}}return r=a.pubfn.snake2camelJson(r),{appid:t,appsecret:n,...r,code:0,msg:"ok"}},weixin.h5.auth.getAccessToken=async function(e={}){let t,{appid:n,appsecret:i}=weixin.h5.auth.getAppidInfo(e),{cache:a=!0}=e,{vk:r}=util$d,o="h5-weixin-"+n;if(a&&(t=await r.globalDataCache.get(o)),r.pubfn.isNull(t)){let n=await weixin.h5.auth.getAccessTokenFn(e);if(0===n.code)t=n.access_token,await r.globalDataCache.set(o,t,240),await r.globalDataCache.deleteExpired();else if(console.log("获取微信公众号access_token失败:",n),40164===n.code)throw{code:n.code,msg:"请将固定IP全部加入微信公众号IP白名单,详见搜索文档:固定ip",err:n}}return t},weixin.h5.auth.getAccessTokenFn=async function(e={}){let t,{appid:n,appsecret:i}=weixin.h5.auth.getAppidInfo(e),{vk:a,config:r}=util$d;if("aliyun"===a.pubfn.getUniCloudProvider()){let e=await uniCloud.httpProxyForEip.get("https://api.weixin.qq.com/cgi-bin/token",{grant_type:"client_credential",appid:n,secret:i});if("string"==typeof e)try{e=JSON.parse(e)}catch(e){t={errcode:-1,errmsg:"异常"+e.message}}t="object"==typeof e?e.body:{errcode:-1,errmsg:"异常:getRes未获取到值"}}else t=await a.request({url:`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${n}&secret=${i}`,method:"GET"});return t.errcode?(console.error("getAccessToken失败:",t),{code:t.errcode,msg:t.errmsg,err:t}):{code:0,msg:"ok",access_token:t.access_token,expires_in:t.expires_in}},weixin.h5.subscribeMessage={},weixin.h5.subscribeMessage.send=async function(e={}){let{vk:t}=util$d,{touser:n,template_id:i,page:a,data:r,miniprogram:o}=e,s=await weixin.h5.auth.getAccessToken(e);if(!s)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的h5-weixin配置的appid和appsecret是否正确"};let u=await t.request({url:"https://api.weixin.qq.com/cgi-bin/message/subscribe/bizsend?access_token="+s,method:"POST",data:{touser:n,template_id:i,page:a,data:r,miniprogram:o},useContent:!0});switch(u=returnRes$3(u),u.code){case 40003:u.msg="touser字段openid为空或者不正确";break;case 40037:u.msg="订阅模板id为空不正确";break;case 43101:u.msg="用户未订阅该消息";break;case 47003:u.msg="模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错";break;case 41030:u.msg="page路径不正确,需要保证在现网版本小程序中存在"}return u},weixin.h5.templateMessage={},weixin.h5.templateMessage.send=async function(e={}){let{vk:t}=util$d,{touser:n,template_id:i,url:a,miniprogram:r,data:o}=e,s=await weixin.h5.auth.getAccessToken(e);if(!s)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的h5-weixin配置的appid和appsecret是否正确"};let u=await t.request({url:"https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+s,method:"POST",data:{touser:n,template_id:i,url:a,miniprogram:r,data:o},useContent:!0});switch(u=returnRes$3(u),u.code){case 40003:u.msg="touser字段openid为空或者不正确";break;case 40037:u.msg="订阅模板id为空不正确";break;case 43101:u.msg="用户未订阅该消息";break;case 47003:u.msg="模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错";break;case 41030:u.msg="page路径不正确,需要保证在现网版本小程序中存在"}return u},weixin.loginByWeixin=async function(e={},t,n){let i,a,r;e.context?(i=e.data||{},a=e.context,r=e.custom,e.appid&&(i.appid=e.appid),e.appsecret&&(i.appsecret=e.appsecret)):(i=e,a=t,r=n);let o,s,{vk:u,uniID:l,_:c}=util$d,{code:d,platform:p,type:f,appid:g}=i;if(p||(p=u.pubfn.getPlatformForUniId(a),i.platform=p),g&&["mp-weixin","h5-weixin","app-plus"].indexOf(p)>-1){let e;"mp-weixin"===p?e=weixin.auth.getAppidInfo(i):"h5-weixin"===p?e=weixin.h5.auth.getAppidInfo(i):"app-plus"===p&&(e=weixin.app.auth.getAppidInfo(i));let{appid:t,appsecret:n}=e,r=u.pubfn.copyObject(weixin.getConfig());u.pubfn.setData(r,p+".oauth.weixin",{appid:t,appsecret:n}),i.platform=p,s=l.createInstance({context:a,config:r})}s||(s=l);try{delete i.role,o=await s.loginByWeixin(i);try{if(o.uid&&!o.msg&&(o.msg="register"===o.type?"注册成功":"登录成功"),o.uid&&"register"===o.type){let e={},t={last_login_date:Date.now(),last_login_ip:a.CLIENTIP};if(["h5-weixin","app-plus"].indexOf(p)>-1){let t=await u.openapi.weixin.app.auth.getUserInfo({access_token:o.accessToken,openid:o.openid});e={nickname:t.nickname,avatar:t.headimgurl}}["mp-weixin"].indexOf(p)>-1&&(e={nickname:i.nickname,avatar:i.avatar}),u.pubfn.isNotNull(r)&&(e=u.pubfn.objectAssign(e,r)),u.pubfn.isNotNull(t)&&(e=u.pubfn.objectAssign(e,t)),u.pubfn.isNotNull(e)&&(o.userInfo=await u.baseDao.updateAndReturn({dbName:"uni-id-users",whereJson:{_id:o.uid||"___",nickname:c.exists(!1)},dataJson:e}))}}catch(e){console.error("保存用户头像昵称异常:",e)}if(0===o.code)try{let t=u.crypto.aes.encrypt({data:{code:0,sessionKey:o.sessionKey,openid:o.openid,unionid:o.unionid,uid:o.uid,accessToken:o.accessToken,accessTokenExpired:o.accessTokenExpired,refreshToken:o.refreshToken}});o.encryptedKey=t,e.needKey||(delete o.sessionKey,delete o.accessToken,delete o.refreshToken)}catch(e){}}catch(e){console.error("loginByWeixin异常:",e);let t=e.message||"";throw e.message.indexOf("code been used")>-1&&(t="该code已被使用,请重新获取"),e.message.indexOf("invalid code")>-1&&(t="无效code,请重新获取"),new Error("msg:"+t)}return o};var weixin_1=weixin,openapi={};openapi.alipay=alipay_1,openapi.baidu=baidu_1,openapi.douyin=douyin_1,openapi.qq=qq_1,openapi.weixin=weixin_1,openapi.init=function(e){openapi.alipay.init(e),openapi.baidu.init(e),openapi.douyin.init(e),openapi.qq.init(e),openapi.weixin.init(e)};var openapi_1=openapi,builder=class{constructor(){this._shouldUseCache=!1,this._cachedBuffer=null,this._lineBreak="\r\n",this._boundary="------FormDataBaseBoundary"+Math.random().toString(36).substring(2),this.dataList=[]}_addData(e){if(this._shouldUseCache=!1,0===this.dataList.length)return void this.dataList.push(e);const t=this.dataList[this.dataList.length-1];switch(`${Buffer.isBuffer(t)?"buffer":"other"}_${Buffer.isBuffer(e)?"buffer":"other"}`){case"buffer_buffer":this.dataList.push(this._lineBreak),this.dataList.push(e);break;case"buffer_other":this.dataList.push(this._lineBreak+e);break;case"other_buffer":this.dataList[this.dataList.length-1]=t+"\r\n",this.dataList.push(e);break;case"other_other":this.dataList[this.dataList.length-1]=t+"\r\n"+e}}append(e,t,n){this._addData("--"+this._boundary);let i=`Content-Disposition: form-data; name="${encodeURIComponent(e)}"`;if(Buffer.isBuffer(t)){if(!n.filename||!n.contentType)throw new Error("filename and contentType required");i+=`; filename="${encodeURIComponent(n.filename)}"`,this._addData(i),this._addData("Content-Type: "+n.contentType),this._addData(""),this._addData(t)}else this._addData(i),this._addData(""),this._addData(t)}getHeaders(e){const t={"Content-Type":"multipart/form-data; boundary="+this._boundary};return Object.assign(t,e)}getBuffer(){if(this._shouldUseCache)return this._cachedBuffer;this._shouldUseCache=!0;let e=Buffer.alloc(0);return this.dataList.forEach(t=>{e=Buffer.isBuffer(t)?Buffer.concat([e,t]):Buffer.concat([e,Buffer.from(""+t)])}),e=Buffer.concat([e,Buffer.from(`${this._lineBreak}--${this._boundary}--`)]),this._cachedBuffer=e,e}};const BOUNDARY_REG=/^multipart\/.+?(?:;\s*boundary=(?:(?:"(.+)")|(?:([^\s]+))))$/i,LEADING_REG=/Content-Disposition:\sform-data;\sname="(.+?)"(?:;\sfilename="(.+?)")?/i,TYPE_REG=/Content-Type:\s(.+?)$/i,lineBreak="\r\n";function split(e,t){let n=0,i=0,a=[];for(;-1!==(i=e.indexOf(t,n));)a.push(e.slice(n,i)),n=i+t.length,i=e.indexOf(t,n);return a}function readParam(e){let t=e.indexOf("\r\n")+"\r\n".length,n=t,i=e.lastIndexOf("\r\n"),a=[];for(;-1!==(n=e.indexOf("\r\n",t));)if(a.push(e.slice(t,n)),t=n+"\r\n".length,0===a[a.length-1].length){a.push(e.slice(t,i));break}return a}var parser=e=>{const t=(e.headers["content-type"]||e.headers["Content-Type"]).match(BOUNDARY_REG),n=t[1]||t[2],i=split(Buffer.from(e.body,"base64"),Buffer.from("--"+n)).map(e=>readParam(e).filter(e=>e.length>0)).filter(e=>2===e.length||3===e.length||4===e.length).map(e=>{const t={},n=e[0].toString().match(LEADING_REG);switch(t.name=decodeURIComponent(n[1]),e.length){case 2:t.value=e[1].toString();break;case 3:t.filename=decodeURIComponent(n[2]),t.contentType=e[1].toString().match(TYPE_REG)[1],t.fileContent=e[2];break;case 4:t.filename=decodeURIComponent(n[2]),t.contentType=e[1].toString().match(TYPE_REG)[1],t.fileContent=e[3]}return t}),a={};return i.forEach(e=>{const t=e.name;delete e.name,a[t]=e.fileContent?e:e.value}),a},formDataUtils={FormData:builder,formParser:parser};const dbName_role="uni-id-roles",dbName_menu="opendb-admin-menus",dbName_permission="uni-id-permissions";var dao={},util$e={};dao.init=function(e){util$e=e},dao.findRoleById=async(e="___")=>{let t,{vk:n,db:i,_:a}=util$e;return t=await n.baseDao.findByWhereJson({dbName:dbName_role,whereJson:{role_id:e}}),t},dao.roleBindPermission=async(e={})=>{let{vk:t,db:n,_:i}=util$e,a={code:0,msg:""},{role_id:r="___",permissionList:o=[],reset:s=!1}=e;if(!s){let e=await dao.findRoleById(r),{permission:t=[]}=e;o=t.concat(o),o=[...new Set(o)]}return a.num=await t.baseDao.update({dbName:dbName_role,whereJson:{role_id:r},dataJson:{permission:i.set(o)}}),a},dao.roleBindMenu=async(e={})=>{let{vk:t,db:n,_:i}=util$e,a={code:0,msg:""},{role_id:r="___",menuList:o=[],reset:s=!1,addPermission:u=!1}=e,l=[],c=await dao.findRoleById(r),{menu:d=[],permission:p=[]}=c;if(s?l=compareArray(o,d):(o=d.concat(o),o=[...new Set(o)]),a.num=await t.baseDao.update({dbName:dbName_role,whereJson:{role_id:r},dataJson:{menu:i.set(o)}}),u){let e=await dao.findMenuByIdsToPermission(o),n=[];if(s&&t.pubfn.isNotNull(l)){n=compareArray(e,await dao.findMenuByIdsToPermission(l))}p=p.concat(e),p=compareArray(n,p),p=[...new Set(p)],dao.roleBindPermission({role_id:r,permissionList:p,reset:!0})}return a},dao.findPermissionById=async(e="___")=>{let t,{vk:n,db:i,_:a}=util$e;return t=await n.baseDao.findByWhereJson({dbName:dbName_permission,whereJson:{permission_id:e}}),t},dao.findMenuByIdsToPermission=async e=>{let{vk:t,db:n,_:i}=util$e,a=await dao.findMenuByIds(e);if(t.pubfn.isNull(a))return[];let r=[];for(let e in a){let n=a[e].permission;t.pubfn.isNotNull(n)&&(r=r.concat(n))}return r=[...new Set(r)],r},dao.listPermissionToTree=async(e={})=>{let t,{vk:n,db:i,_:a}=util$e,{getCount:r=!1,pageSize:o=500,pageIndex:s=1,whereJson:u={parent_id:a.in([null,""])},sortArr:l=[{name:"sort",type:"asc"}],treeProps:c={}}=e,{level:d=3,limit:p=500,whereJson:f}=c;u&&!u.permission_id&&(u.permission_id=a.exists(!0)),t=await n.baseDao.selects({dbName:dbName_permission,pageIndex:s,pageSize:o,getCount:r,whereJson:u,sortArr:l,treeProps:{id:"permission_id",parent_id:"parent_id",children:"children",level:d,limit:p,whereJson:f,sortArr:l}});let g={id:"permission_id",parent_id:"parent_id",children:"children"},m=t.rows;m=n.pubfn.treeToArray(m,g),t.list=n.pubfn.copyObject(m);for(let e in m){let t=m[e],i="",a="";if(n.pubfn.isNotNull(t.level)){i=` - ${["未分类","子弹级","炸弹级","榴弹级","核弹级"][t.level]}(LV:${t.level})`}if(n.pubfn.isNotNull(t.curd_category)){a=" - "+["未分类","增","删","改","查","特殊"][t.curd_category]}m[e].label=`${t.permission_name}(${t.permission_id})${a}${i}`}return m=n.pubfn.arrayToTree(m,g),t.rows=m,t},dao.findMenuById=async(e="___")=>{let t,{vk:n,db:i,_:a}=util$e;return t=await n.baseDao.findByWhereJson({dbName:dbName_menu,whereJson:{menu_id:e}}),t},dao.findMenuByIds=async e=>{let t,{vk:n,db:i,_:a}=util$e;return n.pubfn.isNull(e)?[]:(t=(await n.baseDao.select({dbName:dbName_menu,pageIndex:1,pageSize:500,whereJson:{menu_id:a.in(e)}})).rows,t)},dao.listMenuByRole=async(e={})=>{let{vk:t,db:n,_:i}=util$e,a={code:0,msg:"",menus:[],menuList:[]},{role:r,treeProps:o={}}=e,s=[],u={enable:!0},l={enable:!0};if(!(r.indexOf("admin")>-1)){if(t.pubfn.isNull(r))return a;let e=await t.baseDao.select({dbName:dbName_role,pageSize:500,whereJson:{role_id:i.in(r),enable:!0},fieldJson:{menu:!0}});for(let n in e.rows){let{menu:i}=e.rows[n];t.pubfn.isNotNull(i)&&(s=s.concat(i))}if(0==s.length)return a;s=[...new Set(s)],u.menu_id=i.in(s),l.menu_id=i.in(s)}u.parent_id=i.in([null,""]);let c=[{name:"sort",type:"asc"}],{level:d=3,limit:p=500}=o,f=await t.baseDao.selects({dbName:dbName_menu,pageIndex:1,pageSize:500,whereJson:u,sortArr:c,treeProps:{id:"menu_id",parent_id:"parent_id",children:"children",level:d,limit:p,whereJson:l,sortArr:c}});return a.menus=f.rows,a.menuList=t.pubfn.treeToArray(f.rows,{id:"menu_id",parent_id:"parent_id",children:"children"}),a},dao.menuBindPermission=async(e={})=>{let{vk:t,db:n,_:i}=util$e,a={code:0,msg:""},{menu_id:r="___",permissionList:o=[],reset:s=!1}=e;if(!s){let e=await dao.findMenuById(r),{permission:t=[]}=e;o=t.concat(o),o=[...new Set(o)]}return a.num=await t.baseDao.update({dbName:dbName_menu,whereJson:{menu_id:r},dataJson:{permission:i.set(o)}}),a},dao.listMenuToTree=async(e={})=>{let t,{vk:n,db:i,_:a}=util$e,{getCount:r=!1,pageSize:o=500,pageIndex:s=1,whereJson:u={parent_id:a.in([null,""]),menu_id:a.exists(!0)},sortArr:l=[{name:"sort",type:"asc"}],treeProps:c={}}=e,{level:d=3,limit:p=500,whereJson:f}=c;u&&!u.menu_id&&(u.menu_id=a.exists(!0)),t=await n.baseDao.selects({dbName:dbName_menu,pageIndex:s,pageSize:o,getCount:r,whereJson:u,sortArr:l,treeProps:{id:"menu_id",parent_id:"parent_id",children:"children",level:d,limit:p,whereJson:f,sortArr:l}});let g={id:"menu_id",parent_id:"parent_id",children:"children"},m=t.rows;m=n.pubfn.treeToArray(m,g),t.list=n.pubfn.copyObject(m);for(let e in m){let t=m[e];m[e].label=`${t.name}(${t.menu_id})`}return m=n.pubfn.arrayToTree(m,g),t.rows=m,t};var sysDao=dao;function compareArray(e,t){let n=new Set(e);return t.filter(e=>!n.has(e))}const dbName="vk-global-data";var dao$1={},util$f={};dao$1.init=function(e){util$f=e},dao$1.find=async e=>{let{vk:t,db:n,_:i}=util$f,a={};return a=await t.baseDao.findById({dbName:dbName,id:e}),a},dao$1.del=async e=>{let{vk:t,db:n,_:i}=util$f,a={};return a=await t.baseDao.deleteById({dbName:dbName,id:e}),a},dao$1.deleteByWhere=async e=>{let{vk:t,db:n,_:i}=util$f,a={};return a=await t.baseDao.del({dbName:dbName,whereJson:e}),a},dao$1.deleteExpired=async e=>{let{vk:t,db:n,_:i}=util$f,a={},r={};"string"==typeof e?r._id=e:"object"==typeof e&&(r=e);let o=(new Date).getTime();return a=await t.baseDao.del({dbName:dbName,whereJson:{...r,expired_at:i.gt(0).lte(o)}}),a},dao$1.update=async e=>{let{vk:t,db:n,_:i}=util$f,a={},{key:r,value:o,comment:s,expired_at:u}=e;return a=await t.baseDao.updateById({dbName:dbName,id:r,dataJson:{value:i.set(o),comment:s,expired_at:u}}),a},dao$1.add=async e=>{let{vk:t,db:n,_:i}=util$f,a={},{key:r,value:o,comment:s,expired_at:u}=e;return a=await t.baseDao.add({dbName:dbName,dataJson:{_id:r,key:r,value:o,comment:s,expired_at:u}}),a},dao$1.count=async e=>{let{vk:t,db:n,_:i}=util$f,a={};return a=await t.baseDao.count({dbName:dbName,whereJson:e}),a},dao$1.set=async e=>{let{vk:t,db:n,_:i}=util$f,a={code:0,msg:"ok"},r=new Date;e._add_time=r.getTime(),e._add_time_str=t.pubfn.timeFormat(r,"yyyy-MM-dd hh:mm:ss");let o=await n.collection(dbName).doc(e.key).set(e);return o.upsertedId?(a.id=o.upsertedId,a.mode="add"):(a.mode="update",a.updated=o.updated),a.num=1,a},dao$1.inc=async e=>{let{vk:t,db:n,_:i}=util$f,{key:a,value:r,expired_at:o}=e,s={},u=await t.baseDao.updateById({dbName:dbName,id:a,dataJson:{value:i.inc(r),expired_at:o}});if(0==u){0===await dao$1.count({_id:a})&&(s.id=await dao$1.add(e),s.num=1,s.mode="add")}else s.num=u,s.mode="update";return s},dao$1.list=async e=>{let{vk:t,db:n,_:i}=util$f,a={},{pageIndex:r,pageSize:o,whereJson:s,sortArr:u}=e;return a=await t.baseDao.select({dbName:dbName,pageIndex:r,pageSize:o,whereJson:s,sortArr:u}),a};var globalDataDao$1=dao$1,util$g={},smsUtil={init:function(e){util$g=e}},aliyun={specialUrlEncode:function(e){return(e=encodeURIComponent(e)).replace(/\+/g,"%20").replace(/\*/g,"%2A").replace(/%7E/g,"~")},sign:function(e,t){let{crypto:n}=util$g;return n.createHmac("sha1",e).update(t).digest("base64")}};smsUtil.sendSms=async function(e){let{vk:t,config:n}=util$g,{provider:i,appid:a,smsKey:r,smsSecret:o,signName:s,phone:u,templateId:l,data:c}=e,d={};if("aliyun"===i){let i=t.pubfn.getData(n,"vk.service.sms.aliyun");t.pubfn.isNotNull(i)&&(r||(e.smsKey=i.accessKeyId),o||(e.smsSecret=i.accessKeySecret),s||(e.signName=i.signName)),d=await smsUtil.sendSmsByAliyun(e)}else{if("unicloud"!==i)return{code:-1,msg:`暂不支持${i}供应商`};{let i=t.pubfn.getUniIdConfig(n,"service.sms");t.pubfn.isNotNull(i)&&(r||(e.smsKey=i.smsKey),o||(e.smsSecret=i.smsSecret),s||(e.signName=i.signName)),d=await smsUtil.sendSmsByUnicloud(e)}}return d.requestParam={provider:i,phone:u},d},smsUtil.sendSmsByAliyun=async function(e){let{vk:t,config:n}=util$g,{provider:i,appid:a,smsKey:r,smsSecret:o,signName:s,phone:u,templateId:l,data:c}=e,d={code:0,msg:""};try{if(t.pubfn.isNullOne(r,o))return{code:-1,msg:"阿里云短信配置错误,请检查vk-unicloud配置下的vk.service.sms.aliyun配置的accessKeyId和accessKeySecret是否正确"};let e="https://dysmsapi.aliyuncs.com",n=t.pubfn.timeFormat(new Date,"yyyy-MM-ddThh:mm:ssZ",0),i=(new Date).getTime().toString().substring(7)+t.pubfn.random(30);"object"==typeof c&&(c=JSON.stringify(c));let a={SignatureMethod:"HMAC-SHA1",SignatureNonce:i,AccessKeyId:r,SignatureVersion:"1.0",Timestamp:n,Format:"json",Action:"SendSms",Version:"2017-05-25",PhoneNumbers:u,SignName:s,TemplateParam:c,TemplateCode:l};delete a.Signature;let p=[];for(let e in a)p.push(e);p.sort();let f=!1,g="";for(let e in p){let t=p[e];g+="&"+aliyun.specialUrlEncode(t)+"="+aliyun.specialUrlEncode(a[t])}g=g.substring(1);let m="GET&"+aliyun.specialUrlEncode("/")+"&"+aliyun.specialUrlEncode(g),b=aliyun.sign(o+"&",m),h=aliyun.specialUrlEncode(b),y="Signature="+h+"&"+g;f&&(console.log("\r\n随机数\r\n"),console.log(a.SignatureNonce),console.log("\r\n=========\r\n"),console.log(a.Timestamp),console.log("\r\n====sortedQueryString====\r\n"),console.log(g),console.log("\r\n=====stringToSign====\r\n"),console.log(m),console.log("\r\n=====sign====\r\n"),console.log(b),console.log("\r\n=====signature====\r\n"),console.log(h),console.log("\r\n=========\r\n"),console.log(e+"/?"+y));t.pubfn.urlStringToJson(y);let w=await t.request({url:`${e}?${y}`,method:"GET"});return d="OK"===w.Code?{code:0,msg:"ok",requestRes:w}:{code:-1,msg:w.Message,requestRes:w},d}catch(e){return{code:-1,msg:"短信发送失败",err:{message:e.message,stack:e.stack}}}},smsUtil.sendSmsByUnicloud=async function(e){let{vk:t,config:n}=util$g,{provider:i,appid:a,smsKey:r,smsSecret:o,signName:s,phone:u,templateId:l,data:c}=e,d={code:0,msg:""};try{if(t.pubfn.isNullOne(r,o))return{code:-1,msg:"unicloud短信配置错误,请检查uni-id配置下的service.sms配置的smsKey和smsSecret是否正确"};let e=await uniCloud.sendSms({smsKey:r,smsSecret:o,phone:u,templateId:l,data:c});d=0==e.code||0==e.errCode?{code:0,msg:"ok",requestRes:e}:{code:-1,msg:e.errMessage||e.errMsg,requestRes:e}}catch(e){return{code:-1,msg:"短信发送失败",err:{message:e.message,stack:e.stack}}}return d},smsUtil.sendSmsVerifyCode=async function(e){let t,{vk:n,config:i,uniID:a}=util$g,{provider:r,phone:o,code:s,type:u,expiresIn:l=180}=e,c={code:0,msg:""};if("unicloud"===r){t=n.pubfn.getUniIdConfig(i,"service.sms.templateId");let e=n.pubfn.getUniIdConfig(i,"service.sms.codeExpiresIn");e&&(l=e);let a=n.pubfn.getUniIdConfig(i,"service.sms.name"),u=Math.ceil(l/60).toString();c=await n.system.smsUtil.sendSms({provider:r,phone:o,templateId:t,data:{code:s,name:a,action:"身份验证",expMinute:u}})}else t=n.pubfn.getData(i,`vk.service.sms.${r}.templateCode.verifyCode`),c=await n.system.smsUtil.sendSms({provider:r,phone:o,templateId:t,data:{code:s}});return 0===c.code&&await a.setVerifyCode({mobile:o,code:s,expiresIn:l,type:u}),c};var smsUtil_1=smsUtil,system={};system.sysDao=sysDao,system.globalDataDao=globalDataDao$1,system.smsUtil=smsUtil_1,system.init=function(e){let t=["sysDao","globalDataDao","smsUtil"];for(let n in t){let i=t[n];"function"==typeof system[i].init&&system[i].init(e)}};var system_1=system,vkunicloud={};class VK{constructor(e){this.router=router,this.md5=md5,this.baseDao=vkBaseDao,this.request=vk_request,this.callFunction=vk_callFunction,this.pubfn=_function,this.temporaryCache=temporaryCache,this.globalDataCache=globalDataCache_1,this.crypto=crypto,this.openapi=openapi_1,this.formDataUtil=formDataUtils,this.system=system_1,this.baseDir=null,e&&this.init(e)}require(e){return vkunicloud.requireFn(this.baseDir+"/"+e)}requireFn(e){try{return vkunicloud.requireFn(e)}catch(e){let{message:t=""}=e;return void(-1==t.indexOf("Cannot find module")&&-1==t.indexOf("no such file or directory")&&console.error(e))}}use(e,t){for(let n in e)e[n]&&"function"==typeof e[n].init&&e[n].init(t),this[n]=e[n]}getGlobalObject(){return"object"==typeof globalThis?globalThis:"object"==typeof self?self:"object"==typeof window?window:"object"==typeof commonjsGlobal?commonjsGlobal:void 0}init(e={}){let t=this;if(e.requireFn&&(vkunicloud.requireFn=e.requireFn),e.baseDir&&(t.baseDir=e.baseDir),e.configCenter||(e.configCenter=t.requireFn("uni-config-center")),e.uniID||(e.uniID=t.requireFn("uni-id")),e.uniPay||(e.uniPay=t.requireFn("uni-pay")),e.middlewareService||(e.middlewareService=t.requireFn("./middleware/index")),e.daoCenter||(e.daoCenter=t.requireFn("./dao/index")),e.crypto||(e.crypto=t.requireFn("crypto")),e.urlrewrite||(e.urlrewrite=t.requireFn("./util/urlrewrite")),e.config||(e.config=e.configCenter({pluginId:"vk-unicloud"}).requireFile("index.js")),!e.config)throw new Error("配置文件:uniCloud/cloudfunctions/common/uni-config-center/vk-unicloud/index.js \n编译错误,请检查!");if(!e.db)try{e.db=uniCloud.database()}catch(e){}if(t.vkPay=t.requireFn("vk-uni-pay"),e.pubFun||(e.pubFun=t.requireFn("./util/pubFunction")),e.pubFun&&(t.myfn=e.pubFun),e.redis||(e.redis=t.requireFn("vk-redis")),e.redis)t.redisUtil=e.redis,t.redis=e.redis.redis,t.newRedis=e.redis.newRedis;else try{t.redis=uniCloud.redis}catch(e){}e.uniMap||(e.uniMap=t.requireFn("uni-map-common")),e.uniMap&&(t.uniMap=e.uniMap),e.db&&(vkunicloud.db=e.db,vkunicloud._=e.db.command),vkunicloud.pubfn=t.pubfn,e.configCenter&&(vkunicloud.configCenter=e.configCenter),e.config&&(vkunicloud.config=e.config),e.uniID&&(vkunicloud.uniID=e.uniID),e.uniPay&&(vkunicloud.uniPay=e.uniPay),e.middlewareService&&(vkunicloud.middlewareService=e.middlewareService),e.pubFun&&(vkunicloud.pubFun=e.pubFun),e.customUtil&&(vkunicloud.customUtil=e.customUtil),e.crypto&&(vkunicloud.crypto=e.crypto),e.urlrewrite&&(vkunicloud.urlrewrite=e.urlrewrite);const n={vk:t,...vkunicloud};t.use({daoCenter:e.daoCenter,baseDao:t.baseDao,openapi:t.openapi,globalDataCache:t.globalDataCache,system:t.system,pubFun:e.pubFun},n);try{let n=t.getGlobalObject();"object"==typeof n&&e.middlewareService&&(n.vk=t)}catch(e){}}getUnicloud(){return vkunicloud}createInstance(e){return new VK(e)}}var src=new VK;module.exports=src; diff --git a/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/package.json b/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/package.json new file mode 100644 index 0000000..cb547fc --- /dev/null +++ b/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/package.json @@ -0,0 +1,16 @@ +{ + "name": "vk-unicloud", + "version": "2.15.3", + "description": "【云函数端SDK】VK云函数路由模式uniCloud开发框架,在router目录下执行 npm i vk-unicloud 进行安装和升级", + "main": "index.js", + "homepage": "https://gitee.com/vk-uni/vk-uni-cloud-router.git", + "repository": { + "type": "git", + "url": "git+https://gitee.com/vk-uni/vk-uni-cloud-router.git" + }, + "files": [ + "dist" + ], + "author": "VK", + "license": "Apache-2.0" +} \ No newline at end of file diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/index.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/index.js new file mode 100644 index 0000000..e3eebe7 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/index.js @@ -0,0 +1,190 @@ +/** + * vk-unicloud框架客户端(前端) + * author VK + */ +import userCenter from './libs/vk-unicloud/vk-unicloud-user-center' +import callFunctionUtil from './libs/vk-unicloud/vk-unicloud-callFunctionUtil' +import pubfn from './libs/function/index' +import modal from './libs/function/modal' +import navigate from './libs/function/vk.navigate' +import localStorage from './libs/function/vk.localStorage' +import sessionStorage from './libs/function/vk.sessionStorage' +import aliyunOSSUtil from './libs/function/aliyunOSSUtil' +import openapi from './libs/openapi/index' +import requestUtil from './libs/function/vk.request' +import importObject from './libs/function/vk.importObject' + +import filters from './libs/function/vk.filters' +import mixin from './libs/mixin/mixin.js' +import initPermission from './libs/function/permission' +import storeMixin from './libs/store/mixin/mixin' +import initGlobalError from './libs/store/libs/error' +import consoleLog from './libs/install/console.log' +import updateManager from './libs/function/updateManager.js' +// #ifdef H5 +import h5 from './libs/function/vk.h5' +// #endif + + + +var vk = { + userCenter, + callFunctionUtil, + /** + * 发起一个云函数请求 + */ + callFunction: callFunctionUtil.callFunction, + getToken: callFunctionUtil.getToken, + checkToken: callFunctionUtil.checkToken, + uploadFile: callFunctionUtil.uploadFile, + getConfig: callFunctionUtil.getConfig, + emitRefreshToken: callFunctionUtil.emitRefreshToken, + onRefreshToken: callFunctionUtil.onRefreshToken, + offRefreshToken: callFunctionUtil.offRefreshToken, + pubfn, + + // #ifdef H5 + h5, + // #endif + + alert: modal.alert, + toast: modal.toast, + confirm: modal.confirm, + prompt: modal.prompt, + showActionSheet: modal.showActionSheet, + showLoading: modal.showLoading, + hideLoading: modal.hideLoading, + setLoading: modal.setLoading, + + navigate, + // 保留当前页面,并进行页面跳转 + navigateTo: navigate.navigateTo, + // 关闭当前页面,并进行页面跳转 + redirectTo: navigate.redirectTo, + // 并关闭所有页面,并进行页面跳转 + reLaunch: navigate.reLaunch, + // 并关闭所有非tab页面,并进行tab面跳转 + switchTab: navigate.switchTab, + // 页面返回 + navigateBack: navigate.navigateBack, + // 跳转到首页 + navigateToHome: navigate.navigateToHome, + // 跳转到登录页 + navigateToLogin: navigate.navigateToLogin, + // 跳转到小程序 + navigateToMiniProgram: navigate.navigateToMiniProgram, + // 触发全局的自定义事件,附加参数都会传给监听器回调函数。 + $emit: navigate.$emit, + // 监听全局的自定义事件,事件由 uni.$emit 触发,回调函数会接收事件触发函数的传入参数。 + $on: navigate.$on, + // 触发全局的自定义事件,附加参数都会传给监听器回调函数。 + $once: navigate.$once, + // 移除全局自定义事件监听器。 + $off: navigate.$off, + // 本地持久 + localStorage: localStorage, + // 本地会话缓存 + sessionStorage: sessionStorage, + + // 获取应用语言列表 + getLocaleList: pubfn.getLocaleList, + // 获取应用当前语言 + getLocale: pubfn.getLocale, + // 获取应用当前语言对象 + getLocaleObject: pubfn.getLocaleObject, + // 设置应用当前语言 + setLocale: pubfn.setLocale, + + + // 本地持久缓存 + ...localStorage, + // 本地会话缓存 + ...sessionStorage, + // 阿里云oss + aliyunOSSUtil, + // 更新管理器 + updateManager, + // 开放API + openapi, + // 请求库 + requestUtil, + // 发起URL请求 + request: requestUtil.request, + // 导出云对象 + importObject +}; +// vk实例初始化 +vk.init = function(obj = {}) { + let { + Vue, // Vue实例 + config, // 配置 + store, // vuex简写法则(新版本无需传store) + } = obj; + if (typeof store !== "undefined") { + // 兼容旧版本 + Vue.use(store); + } else { + // 新版本无需传store + Vue.mixin(storeMixin); + if (config.globalError) { + Vue.use(initGlobalError); + } + } + // 自定义云函数路由配置 + vk.callFunctionUtil.setConfig(config); + // 重写 console.log + Vue.use(consoleLog); +}; + +vk.getGlobalObject = function() { + if (typeof globalThis === "object") return globalThis; + if (typeof self === "object") return self; + if (typeof window === "object") return window; + if (typeof global === "object") return global; +}; +// 加载拓展功能 +vk.use = function(obj, util) { + for (let name in obj) { + if (obj[name] && typeof obj[name].init === "function") { + obj[name].init(util); + } + vk[name] = obj[name]; + } +}; + +const install = Vue => { + // 全局混入 + Vue.mixin(mixin); + // #ifndef VUE3 + // 加载全局过滤器开始 + for (let i in filters) { + Vue.filter(i, filters[i]); + } + Vue.prototype.vk = vk; + Vue.prototype.$fn = vk.pubfn; + + // #endif + + // #ifdef VUE3 + // 将vk挂载到Vue实例 + Vue.config.globalProperties.vk = vk; + Vue.config.globalProperties.$fn = vk.pubfn; + // #endif + + // 将vk挂载到uni对象 + if (typeof uni == "object") uni.vk = vk; + // 将vk挂载到全局 + let vkGlobalThis = vk.getGlobalObject(); + if (typeof vkGlobalThis == "object") vkGlobalThis.vk = vk; + let util = { vk }; + // 加载插件 + vk.use({ + callFunctionUtil: vk.callFunctionUtil, + openapi: vk.openapi + }, util); + initPermission(Vue); +} + +export default { + install +} diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/aliyunOSSUtil.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/aliyunOSSUtil.js new file mode 100644 index 0000000..6ec7911 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/aliyunOSSUtil.js @@ -0,0 +1,274 @@ +/** + * 阿里云oss工具类 + */ +var aliyunOSSUtil = {}; +var counterNum = 0; + +/** + * 上传至阿里云oss +vk.callFunctionUtil.uploadFile({ + filePath:tempFilePath, + fileType:"image", + provider:"aliyun", + index, + onUploadProgress:function(res){ + // 上传过程中 + if (res.progress > 0) { + if(list[index]){ + list[index].progress = res.progress; + + } + } + }, + success:function(res){ + // 上传成功 + + }, + fail:function(res){ + // 上传失败 + + } +}); + */ +aliyunOSSUtil.uploadFile = function(obj) { + let { + filePath, + fileType = "image", + name = "file", + header = { + "x-oss-forbid-overwrite": true, + }, + index = 0, + file = {}, + needSave = false, + category_id, + title, + cloudPathRemoveChinese = true, // 删除文件名中的中文 + cloudDirectory, + } = obj; + let vk = getApp().globalData.vk; + if (title) vk.showLoading(title); + let fileNameObj = createFileName(obj); + let aliyunOSS = getConfig(); + let fileName = fileNameObj.fileFullName; + let formData = vk.pubfn.copyObject(aliyunOSS.uploadData); + formData["key"] = fileName; // 存储在oss的文件路径 + /** + * 特别说明 + * 若已知本地图片,则使用formData["name"] = filePath + * 若已知base64,则是用formData["file"] = file;// file base64字符串转成blob对象 + */ + if (filePath.indexOf(";base64,") > -1) { + formData["file"] = dataURLtoBlob(filePath); + } else { + formData["name"] = filePath; + } + let Logger = {}; + Logger.startTime = new Date().getTime(); + Logger.filePath = filePath; + return new Promise((resolve, reject) => { + let uploadTask = uni.uploadFile({ + url: aliyunOSS.action, + filePath, + name, + header, + formData: formData, + success: function(res) { + if (title) vk.hideLoading(); + if (![200, 201].includes(res.statusCode)) { + if (typeof obj.fail === "function") obj.fail(res); + Logger.error = res; + } else { + // 上传成功 + res.fileID = fileNameObj.url; + res.url = fileNameObj.url; + Logger.result = res; + if (typeof obj.success === "function") obj.success(res); + resolve(res); + if (needSave) { + // 保存文件记录到数据库 + vk.userCenter.addUploadRecord({ + data: { + url: res.fileID, + name: file.name, + size: file.size, + file_id: res.fileID, + provider: "aliyun", + category_id + }, + filePath, + fileType, + success: function() { + if (typeof obj.addSuccess == "function") obj.addSuccess(res); + }, + fail: function(res) { + if (typeof obj.addFail === "function") obj.addFail(res); + } + }); + } + } + }, + fail: function(res) { + if (title) vk.hideLoading(); + Logger.error = res; + if (res.errMsg && res.errMsg.indexOf('fail url not in domain list') > -1) { + vk.toast('上传域名未在白名单中'); + } + if (typeof obj.fail === "function") obj.fail(res); + }, + complete: function() { + let vk = getApp().globalData.vk; + let config = vk.callFunctionUtil.config; + if (config.debug) { + Logger.endTime = new Date().getTime(); + Logger.runTime = (Logger.endTime - Logger.startTime); + let colorArr = config.logger.colorArr; + let colorStr = colorArr[counterNum % colorArr.length]; + counterNum++; + console.log("%c--------【开始】【阿里云oss文件上传】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;'); + console.log("【本地文件】: ", Logger.filePath); + console.log("【返回数据】: ", Logger.result); + console.log("【预览地址】: ", Logger.result.fileID); + console.log("【上传耗时】: ", Logger.runTime, "毫秒"); + console.log("【上传时间】: ", vk.pubfn.timeFormat(Logger.startTime, "yyyy-MM-dd hh:mm:ss")); + if (Logger.error) console.error("【error】:", Logger.error); + console.log("%c--------【结束】【阿里云oss文件上传】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;'); + } + } + }); + uploadTask.onProgressUpdate((res) => { + if (res.progress > 0) { + if (typeof obj.onUploadProgress === "function") obj.onUploadProgress(res); + } + }); + }); +}; + + +export default aliyunOSSUtil; + + +// 获取配置 +function getConfig() { + let vk = getApp().globalData.vk; + let aliyunOSS = vk.getConfig("service.aliyunOSS"); + let configData = {}; + if (aliyunOSS && aliyunOSS.uploadData && aliyunOSS.uploadData.OSSAccessKeyId) { + try { + // 只有开启按userId分组且开启了vk的vuex功能,才可以自动按userId分组 + if (aliyunOSS.groupUserId && typeof vk.getVuex === "function") { + let userInfo = vk.getVuex("$user.userInfo"); + if (vk.pubfn.isNotNull(userInfo) && userInfo._id) { + aliyunOSS.dirname += `/${userInfo._id}`; + } + } + } catch (err) {} + configData = { + uploadData: { + OSSAccessKeyId: aliyunOSS.uploadData.OSSAccessKeyId, + policy: aliyunOSS.uploadData.policy, + signature: aliyunOSS.uploadData.signature, + success_action_status: 200, + key: "test.png" + }, + action: aliyunOSS.action, + dirname: aliyunOSS.dirname, + host: aliyunOSS.host, + }; + } + return configData; +} +// 生成文件名 +function createFileName(obj = {}) { + let { + file, + filePath, + index = 0, + cloudPathRemoveChinese = true, + cloudDirectory + } = obj; + let vk = getApp().globalData.vk; + let aliyunOSS = getConfig(); + let dirname = aliyunOSS.dirname; + let host = aliyunOSS.host; + let fileObj = {}; + + let suffix = getFileSuffix(obj); + let oldName = index + "." + suffix; + if (file && file.name) { + let suffixName = file.name.substring(file.name.lastIndexOf(".") + 1); + if (suffixName && suffixName.length < 5) oldName = file.name; + // 只保留["数字","英文",".","-"] + if (cloudPathRemoveChinese) { + oldName = oldName.replace(/[^a-zA-Z.-d]/g, ''); + } + if (oldName.indexOf(".") == 0) oldName = "0" + oldName; + } + let date = new Date(); + let dateYYYYMMDD = vk.pubfn.timeFormat(date, "yyyy/MM/dd"); + let dateTime = date.getTime().toString(); // 时间戳 + // 时间戳后8位 + let dateTimeEnd8 = dateTime.substring(dateTime.length - 8, dateTime.length); + let randomNumber = vk.pubfn.random(8); // 8位随机数 + // 文件路径 = 固定路径名 + 业务路径 + + // 业务路径 + let servicePath = ""; + if (cloudDirectory) { + // 如果自定义了上传目录,则使用自定义的上传目录 + if (cloudDirectory.lastIndexOf("/") !== cloudDirectory.length-1) { + cloudDirectory = cloudDirectory + "/"; + } + servicePath = cloudDirectory; + } else { + // 否则,使用年月日作为上传目录 + servicePath = dateYYYYMMDD + "/"; + } + // 文件名 = 时间戳后8位 - 随机数8位 + 后缀名 + let fileNickName = dateTimeEnd8 + randomNumber + "-" + oldName; + // 文件相对路径 = 业务目录 + 文件名 + let fileRelativePath = servicePath + fileNickName; + // 文件名全称(包含文件路径) = 根目录 + 文件相对路径 + let fileFullName = dirname + "/" + fileRelativePath; + // 外网地址 = 外网域名 + 文件名全称 + let url = host + "/" + fileFullName; + fileObj.url = url; + fileObj.fileFullName = fileFullName; + fileObj.fileNickName = fileNickName; + return fileObj; +} + +function getFileSuffix(obj = {}) { + let { + file, + filePath, + suffix = "png" + } = obj; + if (filePath) { + let suffixName = filePath.substring(filePath.lastIndexOf(".") + 1); + if (suffixName && suffixName.length < 5) suffix = suffixName; + } + if (file) { + if (file.path) { + let suffixName = file.path.substring(file.path.lastIndexOf(".") + 1); + if (suffixName && suffixName.length < 5) suffix = suffixName; + } + if (file.name) { + let suffixName = file.name.substring(file.name.lastIndexOf(".") + 1); + if (suffixName && suffixName.length < 5) suffix = suffixName; + } + } + return suffix; +} + +function dataURLtoBlob(dataurl) { + let arr = dataurl.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 }); +} diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/debounce.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/debounce.js new file mode 100644 index 0000000..485521e --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/debounce.js @@ -0,0 +1,34 @@ +let timeoutArr = []; +/** + * 防抖函数 + * 防抖原理:一定时间内,只有最后一次或第一次调用,回调函数才会执行 + * @param {Function} fn 要执行的回调函数 + * @param {Number} time 延时的时间 + * @param {Boolean} isImmediate 是否立即执行 默认true + * @param {String} timeoutName 定时器ID + * @return null +vk.pubfn.debounce(() => { + +}, 1000); + */ +function debounce(fn, time = 500, isImmediate = true, timeoutName = "default") { + // 清除定时器 + if(!timeoutArr[timeoutName]) timeoutArr[timeoutName] = null; + if (timeoutArr[timeoutName] !== null) clearTimeout(timeoutArr[timeoutName]); + // 立即执行一次 + if (isImmediate) { + var callNow = !timeoutArr[timeoutName]; + timeoutArr[timeoutName] = setTimeout(() => { + timeoutArr[timeoutName] = null; + }, time); + if (callNow){ + if(typeof fn === 'function') return fn(); + } + } else { + // 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时time毫秒后执行fn回调方法 + timeoutArr[timeoutName] = setTimeout(() => { + if(typeof fn === 'function') return fn(); + }, time); + } +} +export default debounce diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/deepClone.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/deepClone.js new file mode 100644 index 0000000..3db999a --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/deepClone.js @@ -0,0 +1,23 @@ +// 判断arr是否为一个数组,返回一个bool值 +function isArray (arr) { + return Object.prototype.toString.call(arr) === '[object Array]'; +} + +// 深度克隆 +function deepClone (obj) { + // 对常见的“非”值,直接返回原来值 + if([null, undefined, NaN, false].includes(obj)) return obj; + if(typeof obj !== "object" && typeof obj !== 'function') { + //原始类型直接返回 + return obj; + } + var o = isArray(obj) ? [] : {}; + for(let i in obj) { + if(obj.hasOwnProperty(i)){ + o[i] = typeof obj[i] === "object" ? deepClone(obj[i]) : obj[i]; + } + } + return o; +} + +export default deepClone; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/deepMerge.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/deepMerge.js new file mode 100644 index 0000000..81d2d18 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/deepMerge.js @@ -0,0 +1,30 @@ +import deepClone from "./deepClone"; + +// JS对象深度合并 +function deepMerge(target = {}, source = {}) { + target = deepClone(target); + if (typeof target !== 'object' || typeof source !== 'object') return false; + for (var prop in source) { + if (!source.hasOwnProperty(prop)) continue; + if (prop in target) { + if (typeof target[prop] !== 'object') { + target[prop] = source[prop]; + } else { + if (typeof source[prop] !== 'object') { + target[prop] = source[prop]; + } else { + if (target[prop].concat && source[prop].concat) { + target[prop] = target[prop].concat(source[prop]); + } else { + target[prop] = deepMerge(target[prop], source[prop]); + } + } + } + } else { + target[prop] = source[prop]; + } + } + return target; +} + +export default deepMerge; \ No newline at end of file diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/index.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/index.js new file mode 100644 index 0000000..dbd1091 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/index.js @@ -0,0 +1,2430 @@ +/** + * 通用公共函数 + */ +var pubfn = {}; +// 防抖 +import debounce from './debounce.js' +// 限流 +import throttle from './throttle.js' +// url参数 +import queryParams from './queryParams.js' +// H5版本的复制 +import setClipboardData from './setClipboardData.js' +// 时间 +import timeUtil from './timeUtil.js' +// 树形结构转换 +import treeUtil from './treeUtil.js' + +/** + * 树形结构转换 + */ +pubfn.treeUtil = treeUtil; +/** + * 时间工具类 + */ +pubfn.timeUtil = timeUtil; +/** + * 防抖函数 + */ +pubfn.debounce = debounce; +/** + * 节流函数 + */ +pubfn.throttle = throttle; +/** + * 对象转url参数 + * @param {*} data,对象 + * @param {*} isPrefix,是否自动加上"?" + * 此函数参考uView + * vk.pubfn.queryParams(json); + */ +pubfn.queryParams = queryParams; +/** + * 设置剪贴板 + */ +pubfn.setClipboardData = setClipboardData; + +/** + * 休眠,等待(单位毫秒) + * @param {Number} ms 毫秒 + * await vk.pubfn.sleep(1000); + */ +pubfn.sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); + +/** + * 日期格式化 + * @param {Date || Number} date 需要格式化的时间 + * vk.pubfn.timeFormat(new Date(),"yyyy-MM-dd hh:mm:ss"); + */ +pubfn.timeFormat = pubfn.timeUtil.timeFormat; +/** + * 解析日期对象属性 + * @param {Date || Number} date 需要转换的时间 + * vk.pubfn.getDateInfo(new Date()); + */ +pubfn.getDateInfo = pubfn.timeUtil.getDateInfo; + +/** + * 日期对象转换(此API已弃用,建议用vk.pubfn.timeFormat代替) + * @param {Date || Number} date 需要转换的时间 + * @param {Number} type 转换方式 + * type = 0 返回 2020-08-03 12:12:12 + * type = 1 返回 20200803121212 + * type = 2 返回 { YYYY, MM, DD, hh, mm, ss } + */ +pubfn.getFullTime = pubfn.timeUtil.getFullTime; + +/** + * 获取时间范围 + * @param {Date} date 日期对象 可以指定时间计算节点,默认使用当前时间进行计算 + * 返回的是时间戳(防止时区问题) + * 返回数据如下: + { + todayStart 今日开始时间 + todayEnd 今日结束时间 + today12End 今日上午结束时间 + monthStart 本月开始时间 + monthEnd 本月结束时间 + yearStart 本年开始时间 + yearEnd 本年结束时间 + weekStart 本周开始时间 + weekEnd 本周结束时间 + now 现在的时间点(含月年日时分秒) + months 本年度每月的开始和结束时间 months[1] 代表1月 + } + * vk.pubfn.getCommonTime(); + */ +pubfn.getCommonTime = pubfn.timeUtil.getCommonTime; + +/** + * 获得指定时间偏移 year年 month月 day天 hours时 minutes分 seconds秒前或后的时间戳 + * 返回时间戳形式 +vk.pubfn.getOffsetTime(new Date(), { + year:0, + month:0, + day:0, + hours:0, + minutes:0, + seconds:0, + mode:"after", // after 之后 before 之前 +}); + */ +pubfn.getOffsetTime = pubfn.timeUtil.getOffsetTime; + +/** + * 获得相对当前时间的偏移 count 小时的起止日期(小时的开始和结束) + * @param {Number} count 默认0 (0代表当前小时 为-1代表上一个小时 为1代表下一个小时以此类推) + * @param {Date || Number} date 指定从哪个时间节点开始计算 + * vk.pubfn.getHourOffsetStartAndEnd(0); + */ +pubfn.getHourOffsetStartAndEnd = pubfn.timeUtil.getHourOffsetStartAndEnd; + + +/** + * 获得相对当前时间的偏移 count 天的起止日期(日的开始和结束) + * @param {Number} count 默认0 (0代表今日 为-1代表昨日 为1代表明日以此类推) + * @param {Date || Number} date 指定从那天开始计算 + * vk.pubfn.getDayOffsetStartAndEnd(0); + */ +pubfn.getDayOffsetStartAndEnd = pubfn.timeUtil.getDayOffsetStartAndEnd; + +/** + * 获得相对当前周addWeekCount个周的起止日期 + * @param {Number} addWeekCount 默认0 (0代表本周 为-1代表上周 为1代表下周以此类推 为2代表下下周) + * vk.pubfn.getWeekOffsetStartAndEnd(0); + */ +pubfn.getWeekOffsetStartAndEnd = pubfn.timeUtil.getWeekOffsetStartAndEnd; // 新版写法 +pubfn.getWeekStartAndEnd = pubfn.timeUtil.getWeekOffsetStartAndEnd; // 兼容老版本写法 + +/** + * 获得相对当前时间的偏移 count 月的起止日期(月的开始和结束) + * @param {Number} count 默认0 (0代表本月 为-1代表上月 为1代表下月以此类推) + * @param {Date || Number} date 指定从那天开始计算 + * vk.pubfn.getMonthOffsetStartAndEnd(0); + */ +pubfn.getMonthOffsetStartAndEnd = pubfn.timeUtil.getMonthOffsetStartAndEnd; + +/** + * 获得相对当前时间的偏移 count 个季度的起止日期(季度的开始和结束时间戳) + * @param {Number} count 默认0(0代表本季度 -1代表上个季度 1代表下个季度以此类推) + * @param {Date || Number} date 指定从哪个时间节点开始计算 + * vk.pubfn.getQuarterOffsetStartAndEnd(0); + */ +pubfn.getQuarterOffsetStartAndEnd = pubfn.timeUtil.getQuarterOffsetStartAndEnd; + + +/** + * 获得相对当前时间的偏移 count 年的起止日期(年的开始和结束) + * @param {Number} count 默认0 (0代表今年 为-1代表去年 为1代表明年以此类推) + * @param {Date || Number} date 指定从那天开始计算 + * vk.pubfn.getYearOffsetStartAndEnd(0); + */ +pubfn.getYearOffsetStartAndEnd = pubfn.timeUtil.getYearOffsetStartAndEnd; + +/** + * 获得指定年份和月份后的该月的开始时间和结束时间 + * 返回数据如下:(时间戳形式) + { + startTime 该月开始时间 + endTime 该月结束时间 + } +vk.pubfn.getMonthStartAndEnd({ + year:2021 + month:1 +}); + */ +pubfn.getMonthStartAndEnd = pubfn.timeUtil.getMonthStartAndEnd; + +/** + * Vue 全局表单验证器扩展 +rules: { + receiver_mobile:[ + { validator:vk.pubfn.validator("mobile"), message: '手机号格式错误', trigger: 'blur' } + ], +}, + */ +pubfn.validator = function(type) { + return function(rule, value, callback) { + let key = pubfn.test(value, type); + if (typeof callback === "function") { + if (key || !value) { + callback(); + } else { + return callback(false); + } + } else { + return callback(false); + } + } +}; + +/** + * 检测文本是否满足指定格式 + * @param {String} str 需要检测的文本 + * @param {String} type 检测类型(忽略大小写) + * @param {Boolean} allowEmpty 是否允许为空 + * 包含 + * mobile 手机号码 + * tel 座机 + * card 身份证 + * mobileCode 6位数字验证码 + * username 账号以字母开头,长度在3~32之间,只能包含字母、数字和下划线 + * pwd 密码长度在6~18之间,只能包含字母、数字和下划线 + * password 与pwd效果一致,密码长度在6~18之间,只能包含字母、数字和下划线 + * paypwd 支付密码 6位纯数字 + * postal 邮政编码 + * qq QQ号 + * email 邮箱 + * money 金额(小数点只允许2位) + * url 网址 + * ip IP地址 + * date 日期 2020-08-03 + * time 时间 12:12:12 + * dateTime 日期+时间 2020-08-03 12:12:12 + * number 纯数字 + * english 纯英文 + * chinese 纯中文 + * english+number 英文+数字 + * english+number+_ 英文+数字+_ + * english+number+_- 英文+数字+_- + * lower 小写 + * upper 大写 + * version 版本号 xx.xx.xx (xx必须是数字) + * html html格式 + * image 图片 + * video 视频 + * audio 音频 + * vk.pubfn.test(str, type, allowEmpty); + */ +pubfn.test = function(str, type = "", allowEmpty=false) { + type = type.toLowerCase(); + let newStr; + if (allowEmpty && (str === "" || str === null || str === undefined)) { + return true; + } + switch (type) { + case 'mobile': //手机号码 + return new RegExp(/^1[3|4|5|6|7|8|9][0-9]{9}$/).test(str); + case 'tel': //座机 + return new RegExp(/^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/).test(str); + case 'card': //身份证 + return new RegExp(/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/).test(str); + case 'mobilecode': //6位数字验证码 + return new RegExp(/^[0-9]{6}$/).test(str); + case 'username': //账号以字母开头,长度在3~32之间,只能包含字母、数字和下划线 + return new RegExp(/^[a-zA-Z]([-_a-zA-Z0-9]{2,31})$/).test(str) + case 'pwd': //密码长度在6~18之间,只能包含字母、数字和下划线和@ + return new RegExp(/^([a-zA-Z0-9_@]){6,18}$/).test(str) + case 'password': //密码长度在6~18之间,只能包含字母、数字和下划线和@ + return new RegExp(/^([a-zA-Z0-9_@]){6,18}$/).test(str) + case 'paypwd': //支付密码 6位纯数字 + return new RegExp(/^[0-9]{6}$/).test(str) + case 'postal': //邮政编码 + return new RegExp(/[1-9]\d{5}(?!\d)/).test(str); + case 'qq': //QQ号 + return new RegExp(/^[1-9][0-9]{4,9}$/).test(str); + case 'email': //邮箱 + return new RegExp(/^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/).test(str); + case 'money': //金额(小数点2位) + return new RegExp(/^\d*(?:\.\d{0,2})?$/).test(str); + case 'url': //网址 + return new RegExp(/^(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/).test(str); + case 'ip': //IP + return new RegExp(/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/).test( + str); + case 'date': //日期 2014-01-01 + return new RegExp(/^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/).test(str); + case 'time': //时间 12:00:00 + return new RegExp(/^(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d$/).test(str); + case 'datetime': //日期+时间 2014-01-01 12:00:00 + return new RegExp(/^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\s+(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d$/).test(str); + case 'english+number': //英文+数字(空字符串算通过) + return new RegExp(/^[a-zA-Z0-9]+$/).test(str); + case 'english+number+_': //英文+数字+_(空字符串算通过) + return new RegExp(/^[a-zA-Z0-9_]+$/).test(str); + case 'english+number+_-': //英文+数字+_-(空字符串算通过) + return new RegExp(/^[a-zA-Z0-9_-]+$/).test(str); + case 'version': //版本号 xx.xx.xx(xx必须是数字) + return new RegExp(/^([1-9]\d|[1-9])(.([1-9]\d|\d)){2}$/).test(str); + case 'number': //数字(空字符串算通过) + return new RegExp(/^[0-9]+$/).test(str); + case 'english': //英文(空字符串算通过) + return new RegExp(/^[a-zA-Z]+$/).test(str); + case 'chinese': //中文(空字符串算通过) + return new RegExp(/^[\u4e00-\u9fa5]+$/gi).test(str); + case 'lower': //小写(空字符串算通过) + return new RegExp(/^[a-z]+$/).test(str); + case 'upper': //大写(空字符串算通过) + return new RegExp(/^[A-Z]+$/).test(str); + case 'html': //HTML标记 + return new RegExp(/<("[^"]*"|'[^']*'|[^'">])*>/).test(str); + case 'image': //是否图片格式 + newStr = str.split("?")[0]; + return new RegExp(/\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)$/).test(newStr); + case 'video': //是否视频格式 + newStr = str.split("?")[0]; + return new RegExp(/\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv|m3u8|3gp)$/).test(newStr); + case 'audio': //是否音频格式 + newStr = str.split("?")[0]; + return new RegExp(/\.(mp3)$/).test(newStr); + default: + return true; + } +}; +// 保留之前的函数名 +pubfn.checkStr = pubfn.test; +/** + * 删除对象中所有值为无效值的属性(如:undefined) + * @param {Object} obj + * vk.pubfn.objectDeleteInvalid(obj); + */ +pubfn.objectDeleteInvalid = function(obj = {}) { + Object.keys(obj).forEach(item => { + if (obj[item] === undefined) { + delete obj[item]; + } + }); + return obj; +}; +/** + * 对象属性拷贝(浅拷贝) + * @description 将 obj2 的属性赋值给 obj1(如果obj1中有对应的属性,则会被obj2的属性值覆盖) + * @param {Object} obj1 + * @param {Object} obj2 + * vk.pubfn.objectAssign(obj1, obj2); + * vk.pubfn.objectAssign(obj1, obj2, true); + * vk.pubfn.objectAssign(obj1, obj2, false); + */ +pubfn.objectAssign = function(obj1, obj2, deleteInvalid = true) { + if (deleteInvalid) pubfn.objectDeleteInvalid(obj2); + return Object.assign(obj1, obj2); +}; +/** + * 复制一份对象-没有映射关系 + * @description 主要用于解除映射关系(不支持克隆函数) + * @param {Object} obj + * let newObj = vk.pubfn.copyObject(obj); + */ +pubfn.copyObject = function(obj) { + if (typeof obj !== "undefined") { + return JSON.parse(JSON.stringify(obj)); + } else { + return obj; + } +}; +/** + * 深度克隆一个对象-没有映射关系 + * @description 主要用于解除映射关系(支持克隆函数) + * @param {Object} obj + * let newObj = vk.pubfn.deepClone(obj); + */ +pubfn.deepClone = function(obj) { + // 对常见的“非”值,直接返回原来值 + if ([null, undefined, NaN, false].includes(obj)) return obj; + if (typeof obj !== "object" && typeof obj !== 'function') { + //原始类型直接返回 + return obj; + } + let o = Object.prototype.toString.call(obj) === '[object Array]' ? [] : {}; + for (let i in obj) { + if (obj.hasOwnProperty(i)) { + o[i] = typeof obj[i] === "object" ? pubfn.deepClone(obj[i]) : obj[i]; + } + } + return o; +}; +/** + * 表单自动填充数据 + * @description 主要用于表单修改时,数据库没有默认字段会报错的问题 + * @param {Object} defaultData 默认数据 + * @param {Object} itemData 当前数据 + * that.form1 = vk.pubfn.formAssign(defaultData,itemData); + */ +pubfn.formAssign = function(defaultData, itemData) { + let newDefaultData = pubfn.copyObject(defaultData); + return pubfn.objectAssign(newDefaultData, itemData); +}; + + +/** + * 两个(元素为对象)的数组合并,并去除重复的数据 + * @param {Array} arr1 第一个数组(arr1和aar2没有顺序要求) + * @param {Array} aar2 第二个数组 + * @param {String} flag 判断标识,默认用id来判断,若flag传-1,代表不去除重复数据 + * let arr = vk.pubfn.arr_concat(arr1, arr2, "_id"); + */ +pubfn.arr_concat = function(arr1, arr2, flag) { + if (!flag) flag = "id"; // 默认用id来判断是否是同一个对象元素 + if (!arr1) arr1 = []; + if (!arr2) arr2 = []; + let arr3 = arr1.concat(arr2); // 新旧数据合并 + let arr = []; // 定义一个临时数组 存放对象 + if (flag != -1) { + let arr_id = []; // 定义一个临时数组 存放id + for (let i in arr3) { // 循环遍历当前数组 + // 判断当前数组下标为i的元素是否已经保存到临时数组 + // 如果已保存,则跳过,否则将此元素保存到临时数组中 + if (arr_id.indexOf(arr3[i][flag]) == -1) { + arr_id.push(arr3[i][flag]); // 添加id到数组 + arr.push(arr3[i]); // 添加对象到数组 + } + } + } else { + arr = arr3; + } + return arr; +}; +/** + * 自动根据字符串路径获取对象中的值支持.和[] , 且任意一个值为undefined时,不会报错,会直接返回undefined + * @param {Object} dataObj 数据源 + * @param {String} name 支持a.b 和 a[b] + * @param {String} defaultValue undefined时的默认值 + * vk.pubfn.getData(dataObj, name); + */ +pubfn.getData = function(dataObj, name, defaultValue) { + let newDataObj; + if (pubfn.isNotNull(dataObj)) { + newDataObj = JSON.parse(JSON.stringify(dataObj)); + let k = "", + d = ".", + l = "[", + r = "]"; + name = name.replace(/\s+/g, k) + d; + let tstr = k; + for (let i = 0; i < name.length; i++) { + let theChar = name.charAt(i); + if (theChar != d && theChar != l && theChar != r) { + tstr += theChar; + } else if (newDataObj) { + if (tstr != k) newDataObj = newDataObj[tstr]; + tstr = k; + } + } + } + if (typeof newDataObj === "undefined" && typeof defaultValue !== "undefined") newDataObj = defaultValue; + return newDataObj; +}; +/** + * 自动根据字符串路径设置对象中的值 支持.和[] + * @param {Object} dataObj 数据源 + * @param {String} name 支持a.b 和 a[b] + * @param {String} value 值 + * vk.pubfn.setData(dataObj, name, value); + */ +pubfn.setData = function(dataObj, name, value) { + // 通过正则表达式 查找路径数据 + let dataValue; + if (typeof value === "object") { + dataValue = pubfn.copyObject(value); + } else { + dataValue = value; + } + let regExp = new RegExp("([\\w$-]+)|\\[(:\\d)\\]", "g"); + const patten = name.match(regExp); + // 遍历路径 逐级查找 最后一级用于直接赋值 + for (let i = 0; i < patten.length - 1; i++) { + let keyName = patten[i]; + if (typeof dataObj[keyName] !== "object") dataObj[keyName] = {}; + dataObj = dataObj[keyName]; + } + // 最后一级 + dataObj[patten[patten.length - 1]] = dataValue; +}; + +/** + * 检测参数是否为空 其中 undefined、null、{}、[]、"" 均为空值 true 空值 false 有值 + * vk.pubfn.isNull(value); + */ +pubfn.isNull = function(value) { + let key = false; + if ( + typeof value == "undefined" || + Object.prototype.toString.call(value) == "[object Null]" || + JSON.stringify(value) == "{}" || + JSON.stringify(value) == "[]" || + value === "" || + JSON.stringify(value) === undefined + ) { + key = true; + } + return key; +}; +/** + * 检测参数是否不为空 结果与 vk.pubfn.isNull 相反 + * vk.pubfn.isNotNull(value); + */ +pubfn.isNotNull = function(value) { + return !pubfn.isNull(value); +}; +/** + * 检测所有参数 - 是否至少有一个为空 + * vk.pubfn.isNullOne(value1,value2,value3); + */ +pubfn.isNullOne = function(...strS) { + let key = false; + for (let i = 0; i < strS.length; i++) { + let str = strS[i]; + if (pubfn.isNull(str)) { + key = true; + break; + } + } + + return key; +}; +/** + * 检测整个对象是否没有一个属性是空值,如果有空值,则返回首个是空值的属性名 + let nullKey = vk.pubfn.isNullOneByObject({ value1,value2,value3 }); + if(nullKey) return { code : -1, msg : `${nullKey}不能为空` }; + */ +pubfn.isNullOneByObject = function(obj) { + let key; + for (let name in obj) { + let val = obj[name]; + if (pubfn.isNull(val)) { + key = name; + break; + } + } + return key; +}; +/** + * 检测所有参数 - 是否全部为空 + * vk.pubfn.isNullAll(value1,value2,value3); + */ +pubfn.isNullAll = function(...strS) { + let key = true; + for (let i = 0; i < strS.length; i++) { + let str = strS[i]; + if (pubfn.isNotNull(str)) { + key = false; + break; + } + } + return key; +}; + +/** + * 检测所有参数 - 是否全部都不为空 + * vk.pubfn.isNotNullAll(value1,value2,value3); + */ +pubfn.isNotNullAll = function(...strS) { + return !pubfn.isNullOne(...strS); +}; +/** + * 获取对象数组中的某一个item,根据指定的键名和键值 + * @description 主要用于在一个对象数组中快速获取 _id = 1 的对象 + * @param {Array} list 数据源 + * @param {String} key 键名(不可为空) + * @param {String} value 键值 (不可为空) + * vk.pubfn.getListItem(list, key, value); + */ +pubfn.getListItem = function(list, key, value) { + let item; + for (let i = 0; i < list.length; i++) { + if (list[i][key] === value) { + item = list[i]; + break; + } + } + return item; +}; +/** + * 获取对象数组中某个元素的index,根据指定的键名和键值 + * @description 主要用于在一个对象数组中快速获取 _id = 1 的index + * @param {Array} list 数据源 + * @param {String} key 键名 + * @param {String} value 键值 + * vk.pubfn.getListIndex(list, key, value); + */ +pubfn.getListIndex = function(list, key, value) { + let index = -1; + for (let i = 0; i < list.length; i++) { + if (list[i][key] === value) { + index = i; + break; + } + } + return index; +}; +/** + * 获取对象数组中某个元素的index,根据指定的键名和键值 + * @description 主要用于在一个对象数组中快速获取 _id = 1 的index + * @param {Array} list 数据源 + * @param {String} key 键名 + * @param {String} value 键值 + * vk.pubfn.getListItemIndex(list, key, value); + */ +pubfn.getListItemIndex = function(list, key, value) { + let obj = {}; + let item; + let index = -1; + for (let i = 0; i < list.length; i++) { + if (list[i][key] === value) { + index = i; + item = list[i]; + break; + } + } + obj = { + item, + index + } + return obj; +}; +/** + * 数组转对象 - 将对象数组转成json + * 如[{"_id":"001","name":"name1","sex":1},{"_id":"002","name":"name2","sex":2}] + * 转成 + * {"001",{"_id":"001","name":"name1","sex":1},"002":{"_id":"002","name":"name2","sex":2}} + * vk.pubfn.arrayToJson(list, "_id"); + */ +pubfn.arrayToJson = function(list, key) { + let json = {}; + for (let i in list) { + let item = list[i]; + json[item[key]] = item; + } + return json; +}; +pubfn.listToJson = pubfn.arrayToJson; + +/** + * 从数组中提取指定字段形式成为新的数组 + * 如[{"_id":"001","name":"name1","sex":1},{"_id":"002","name":"name2","sex":2}] + * 提取_id字段转成 + * ["001","002"] + * let idArr = vk.pubfn.arrayObjectGetArray(list, "_id"); + */ +pubfn.arrayObjectGetArray = function(list, key) { + return list.map(obj => { return obj[key] }); +}; + +/** + * 产生指定位数的随机数(支持任意字符,默认纯数字) + * @param {Number} length 随机数固定位数 + * @param {String} range 指定的字符串中随机范围 + * @param {Array} arr 产生的随机数不会和此数组的任意一项重复 + * vk.pubfn.random(6); + * vk.pubfn.random(6, "abcdefghijklmnopqrstuvwxyz0123456789"); + * vk.pubfn.random(1,"12",["1","2"]); + */ +pubfn.random = function(length, range, arr) { + let s; + if (pubfn.isNull(arr)) { + s = pubfn.randomFn(length, range); + } else { + let i = 0; + let maxForCount = 100000; + do { + i++; + s = pubfn.randomFn(length, range); + } while (arr.indexOf(s) > -1 && i < maxForCount); + if (i === maxForCount) { + s = undefined; + } + } + return s; +}; +/** + * 产生指定位数的随机数(支持任意字符,默认纯数字) + * @param {Number} length 随机数固定位数 + * @param {String} range 指定的字符串中随机范围 + * vk.pubfn.random(6); + * vk.pubfn.random(6, "abcdefghijklmnopqrstuvwxyz0123456789"); + */ +pubfn.randomFn = function(length, range) { + let s = ""; + let list = "123456789"; + //0123456789QWERTYUIPASDFGHJKLZXCVBNM + if (pubfn.isNotNull(range)) { + if (range == "a-z,0-9") { + range = "abcdefghijklmnopqrstuvwxyz0123456789"; + } else if (range == "A-Z,0-9") { + range = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + } else if (range == "a-z,A-Z,0-9" || range == "A-Z,a-z,0-9") { + range = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + } + list = range; + } + for (let i = 0; i < length; i++) { + let code = list[Math.floor(Math.random() * list.length)]; + s += code; + } + return s; +}; + +/** + * 将字符串id转化为指定位数的纯数字字符串id(会重复) + * vk.pubfn.stringIdToNumberId(uid,8); + */ +pubfn.stringIdToNumberId = function(str, length) { + let s = ""; + let list = "0123456789"; + for (let i = 0; i < length; i++) { + if (str.length > i) { + let index = str[i].charCodeAt() % 10; + s += list[index]; + } else { + s = "0" + s; + } + } + return s; +}; + +/** + * 将手机号,账号等隐藏中间字段 + * @param {String} str 需要转换的字符串 + * @param {Number} first 前面显示的字符数量 + * @param {Number} last 后面显示的字符数量 + * vk.pubfn.hidden(str, first, last); + */ +pubfn.hidden = function(str = "", first = 0, last = 0) { + let len = str.length - first - last; + let xing = ''; + for (let i = 0; i < len; i++) { + xing += '*'; + } + return str.substring(0, first) + xing + str.substring(str.length - last); +}; +/** + * 判断常量数组A是否至少有一个元素在常量数组B中存在(两数组有交集) + * @param {Array} arr1 数组A + * @param {Array} arr2 数组B + * vk.pubfn.checkArrayIntersection(arr1, arr2); + */ +pubfn.checkArrayIntersection = function(arr1 = [], arr2 = []) { + let checkKey = false; + for (let i = 0; i < arr2.length; i++) { + if (arr1.indexOf(arr2[i]) > -1) { + checkKey = true; + } + } + return checkKey; +}; +/** + * 检测数据源是否满足表达式规则 + * @param {Object} data 数据源 + * @param {String} expText 表达式文本 + * vk.pubfn.checkDataExpText(data, expText); + */ +pubfn.checkDataExpText = function(data = {}, expText) { + expText = expText.replace(new RegExp("\\s", "g"), ""); + //console.log("expText:",expText); + let orArr = expText.split("||"); + //console.log("orArr",orArr); + let checkKey = false; + for (let index1 = 0; index1 < orArr.length; index1++) { + let orItem = orArr[index1]; + let andArr = orItem.split("&&"); + //console.log("andArr",andArr); + let itemKey = true; + for (let index2 = 0; index2 < andArr.length; index2++) { + let andItem = andArr[index2]; + //console.log("andItem",andItem); + if (andItem.indexOf("!=") > -1) { + let andItemArr = andItem.split("!="); + let key = andItemArr[0]; + let value = andItemArr[1]; + let formValue = pubfn.getData(data,key); + + itemKey = String(formValue) !== value ? true : false; + + } else if (andItem.indexOf("==") > -1) { + let andItemArr = andItem.split("=="); + let key = andItemArr[0]; + let value = andItemArr[1]; + let formValue = pubfn.getData(data,key); + + itemKey = String(formValue) == value ? true : false; + + } else if (andItem.indexOf(">=") > -1) { + let andItemArr = andItem.split(">="); + let key = andItemArr[0]; + let value = andItemArr[1]; + let formValue = pubfn.getData(data,key); + if (isNaN(value)) { + if (typeof formValue !== "undefined") itemKey = String(formValue) >= value ? true : false; + if (typeof formValue === "undefined" || formValue === null) itemKey = false; + } else { + if (typeof formValue !== "undefined") itemKey = formValue >= Number(value) ? true : false; + if (typeof formValue === "undefined" || formValue === null) itemKey = false; + } + } else if (andItem.indexOf(">") > -1) { + let andItemArr = andItem.split(">"); + let key = andItemArr[0]; + let value = andItemArr[1]; + let formValue = pubfn.getData(data,key); + if (isNaN(value)) { + if (typeof formValue !== "undefined") itemKey = String(formValue) > value ? true : false; + if (typeof formValue === "undefined" || formValue === null) itemKey = false; + } else { + if (typeof formValue !== "undefined") itemKey = formValue > Number(value) ? true : false; + if (typeof formValue === "undefined" || formValue === null) itemKey = false; + } + } else if (andItem.indexOf("<=") > -1) { + let andItemArr = andItem.split("<="); + let key = andItemArr[0]; + let value = andItemArr[1]; + if (isNaN(value)) { + if (typeof data[key] !== "undefined") itemKey = String(data[key]) <= value ? true : false; + if (typeof data[key] === "undefined" || data[key] === null) itemKey = false; + } else { + if (typeof data[key] !== "undefined") itemKey = data[key] <= Number(value) ? true : false; + if (typeof data[key] === "undefined" || data[key] === null) itemKey = false; + } + } else if (andItem.indexOf("<") > -1) { + let andItemArr = andItem.split("<"); + let key = andItemArr[0]; + let value = andItemArr[1]; + let formValue = pubfn.getData(data,key); + if (isNaN(value)) { + if (typeof formValue !== "undefined") itemKey = String(formValue) < value ? true : false; + if (typeof formValue === "undefined" || formValue === null) itemKey = false; + } else { + if (typeof formValue !== "undefined") itemKey = formValue < Number(value) ? true : false; + if (typeof formValue === "undefined" || formValue === null) itemKey = false; + } + } else if (andItem.indexOf("{in}") > -1) { + let andItemArr = andItem.split("{in}"); + let key = andItemArr[0]; + let value = andItemArr[1]; + let formValue = pubfn.getData(data,key); + if (Array.isArray(formValue)) { + let index = formValue.findIndex(item => { + return item.toString() === value.toString(); + }); + itemKey = index > -1 ? true : false; + } else { + itemKey = false; + } + //itemKey = (Array.isArray(formValue) && formValue.indexOf(value) > -1 ) ? true : false; + } else if (andItem.indexOf("{nin}") > -1) { + let andItemArr = andItem.split("{nin}"); + let key = andItemArr[0]; + let value = andItemArr[1]; + let formValue = pubfn.getData(data,key); + if (Array.isArray(formValue)) { + let index = formValue.findIndex(item => { + return item.toString() === value.toString(); + }); + itemKey = index < 0 ? true : false; + } else { + itemKey = false; + } + //itemKey = (Array.isArray(formValue) && formValue.indexOf(value) < 0 ) ? true : false; + } else { + let andItemArr = andItem.split("="); + let key = andItemArr[0]; + let value = andItemArr[1]; + let formValue = pubfn.getData(data,key); + + itemKey = String(formValue) == value ? true : false; + + //console.log("key:",key,"value:",value,"formValue",formValue.toString(),"itemKey:",itemKey); + } + if (!itemKey) { + break; + } + } + if (itemKey) { + checkKey = true; + break; + } + } + return checkKey; +}; + +/** + * 判断变量是否是数组 + * vk.pubfn.isArray(value); + */ +pubfn.isArray = function(value) { + return Object.prototype.toString.call(value) === "[object Array]" ? true : false; +}; +/** + * 判断变量是否是对象 + * vk.pubfn.isObject(value); + */ +pubfn.isObject = function(value) { + return Object.prototype.toString.call(value) === "[object Object]" ? true : false; +}; + + + +/** + * 计算运费 + * @param {Object} freightItem 运费模板 + { + first_weight Number 首重(KG) + first_weight_price Number 首重 首重价格(100=1元) + continuous_weight Number 续重(KG) + continuous_weight_price Number 续重价格(100=1元) + max_weight Number 重量达到此值时(KG),会多计算首重的价格,并少一次续重的价格 倍乘(相当于拆分多个包裹) + } + * @param {Number} weight 运费重量 + * 返回值 + * @return {Number} 最终运费金额(100=1元) + * vk.pubfn.calcFreights(freightItem, weight); + */ +pubfn.calcFreights = function(freightItem, weight) { + let freightRes = vk.pubfn.calcFreightDetail(freightItem, weight); + return freightRes.total_amount; +}; + +/** + * 计算运费,返回细节 + * @param {Object} freightItem 运费模板 + { + first_weight Number 首重(KG) + first_weight_price Number 首重 首重价格(100=1元) + continuous_weight Number 续重(KG) + continuous_weight_price Number 续重价格(100=1元) + max_weight Number 重量达到此值时(KG),会多计算首重的价格,并少一次续重的价格 倍乘(相当于拆分多个包裹) + } + * @param {Number} weight 需要计算的商品重量 + * 返回值 + * @return {Number} weight 运费重量(KG) + * @return {Number} first_weight_price 首重金额(100=1元) + * @return {Number} continuous_weight_price 续重金额(100=1元) + * @return {Number} total_amount 最终运费金额(100=1元) + * @return {String} formula 运费计算公式字符串 + * let freightRes = vk.pubfn.calcFreightDetail(freightItem, weight); + */ +pubfn.calcFreightDetail = function(freightItem, weight) { + let { + first_weight, // 首重(KG) + first_weight_price, // 首重价格(元) + continuous_weight, // 续重(KG) + continuous_weight_price, // 续重价格(元) + max_weight, // 拆包裹,每个包裹最大重量(KG) + } = freightItem; + if (!max_weight) max_weight = 1000000000; + let originalWeight = weight; + let money = 0; // 运费 + let first_weight_count = 0; // 包裹数量 + let packagesSurplusWeight = max_weight; // 包裹剩余重量 + let first_weight_key = false; // 是否已减过首重 + let continuous_weight_count = 0; // 续重次数 + let logArr = []; + let logRun = false; + while (weight > 0) { + if (!first_weight_key) { + // 首重 + first_weight_key = true; + first_weight_count++; + packagesSurplusWeight = max_weight; // 还原包裹剩余重量 + weight -= first_weight; + packagesSurplusWeight -= first_weight; + } else { + // 续重 + continuous_weight_count++; + weight -= continuous_weight; + packagesSurplusWeight -= continuous_weight; + } + if (logRun) logArr.push({ + "总重量剩余": weight, + "当前包裹重量剩余": packagesSurplusWeight, + "当前第几个包裹": first_weight_count, + "续重计算次数": continuous_weight_count + }); + + if (packagesSurplusWeight <= 0) { + // 需要增加一个新的包裹 + first_weight_key = false; // 新包裹设置没有减过首重 + } + } + if (logRun) console.log(JSON.stringify(logArr)); + let total_amount = first_weight_price * first_weight_count + continuous_weight_price * continuous_weight_count; + let res = { + weight: originalWeight, // 商品重量(KG) + first_weight, // 首重步长 + first_weight_price, // 首重单价 + first_weight_count, // 首重计算次数 + continuous_weight, // 续重步长 + continuous_weight_price, // 续重单价 + continuous_weight_count, // 续重计算次数 + first_weight_amount: first_weight_count * first_weight_price, // 首重总金额 + continuous_weight_amount: continuous_weight_price * continuous_weight_count, // 续重总金额 + total_amount, // 最终运费金额 + formula: `${first_weight_price} * ${first_weight_count} + ${continuous_weight_price} * ${continuous_weight_count} = ${total_amount}`, // 运费计算公式 + }; + return res; +}; + + +/** + * 从一个对象中取多个属性,并生成一个全新的对象,会过滤空字符串,空数组,空对象 + * @param {Object} obj 对象 + * @param {Array} keys 键名数组 + * vk.pubfn.getNewObject(obj, keys); + */ +pubfn.getNewObject = function(obj, keys) { + let selectedObj = pubfn.copyObject(obj); + let newObject = {}; + if (keys && keys.length > 0) { + for (let i in keys) { + let key = keys[i]; + if (pubfn.isNotNull(selectedObj[key])) { + newObject[key] = selectedObj[key]; + } + } + } else { + newObject = selectedObj; + } + return newObject; +}; + +/** + * 对象删除指定的字段,返回新的对象 + * @param {Object} data 操作对象 + * @param {Array} deleteKeys 需要删除的键名(数组形式) + * vk.pubfn.deleteObjectKeys(data, deleteKeys); + */ +pubfn.deleteObjectKeys = function(data, deleteKeys = []) { + let newData = {}; + if (data) { + for (let key in data) { + if (deleteKeys.indexOf(key) == -1) { + newData[key] = data[key]; + } + } + } + return newData; +} + +/** + * 数组结构转树形结构 + * @param {Array} treeData 数据源 + * @param {Object} treeProps 树结构配置 + * { id:"_id", parent_id:"parent_id", children:"children",need_field:["_id","name"],deleteParentId:true } + * vk.pubfn.arrayToTree(treeData, treeProps); + */ +pubfn.arrayToTree = pubfn.treeUtil.arrayToTree; +/** + * 树形结构转数组结构 + * @param {Array} treeData 数据源 + * @param {Object} treeProps 树结构配置 + * { id:"_id", parent_id:"parent_id", children:"children", deleteChildren:true } + * vk.pubfn.treeToArray(treeData, treeProps); + */ +pubfn.treeToArray = pubfn.treeUtil.treeToArray; + +/** + * 通配符匹配 + * @param {String} text 被匹配的文本 + * @param {String} expText 通配符规则 + * vk.pubfn.wildcardTestOne(text, expText); + */ +pubfn.wildcardTestOne = function(text, expText) { + if (!expText) return false; + let regExpText = expText.replace(new RegExp("\\*"), "(.*)"); + let startText = expText.indexOf("*") !== 0 ? "^" : ""; + let endText = expText[expText.length - 1] !== "*" ? "$" : ""; + let regExp = new RegExp(startText + regExpText + endText); + return regExp.test(text); +}; +/** + * 通配符匹配 expText支持数组 + * @param {String} text 被匹配的文本 + * @param {String | Array} expText 通配符规则 + * vk.pubfn.wildcardTest(text, expText); + */ +pubfn.wildcardTest = function(text, expText) { + let matchNum = 0; // 被匹配的次数 + let regExp1 = new RegExp("\\*"); + if (typeof expText === "string") { + // 字符串 + if (pubfn.wildcardTestOne(text, expText)) { + matchNum++; + } + } else if (typeof expText === "object") { + // 数组 + for (let i = 0; i < expText.length; i++) { + let expTextItem = expText[i]; + if (pubfn.wildcardTestOne(text, expTextItem)) { + matchNum++; + } + } + } + return matchNum; +} + +/** + * 正则匹配 + * @param {String} text 被匹配的文本 + * @param {String} expText 正则表达式规则 + * vk.pubfn.regExpTestOne(text, expText); + */ +pubfn.regExpTestOne = function(text, expText) { + if (!expText) return false; + let regExp = new RegExp(expText); + return regExp.test(text); +}; + +/** + * 正则匹配 + * @param {String} text 被匹配的文本 + * @param {String || Array} wildcardExp 正则表达式规则 + * vk.pubfn.regExpTest(text, regExp); + */ +pubfn.regExpTest = function(text, expText) { + let matchNum = 0; // 被匹配的次数 + if (typeof expText === "string") { + // 字符串 + if (pubfn.regExpTestOne(text, expText)) { + matchNum++; + } + } else if (typeof expText === "object") { + // 数组 + for (let i = 0; i < expText.length; i++) { + let expTextItem = expText[i]; + if (pubfn.regExpTestOne(text, expTextItem)) { + matchNum++; + } + } + } + return matchNum; +} + +/** + * 产生订单号,不依赖数据库,高并发时性能高(理论上会重复,但概率非常非常低) + * @param {String} prefix 前缀 + * @param {Number} num 位数,建议在25-30之间,默认25 + * vk.pubfn.createOrderNo(); + */ +pubfn.createOrderNo = function(prefix = "", num = 25) { + // 获取当前时间字符串格式如20200803093000123 + let fullTime = vk.pubfn.timeFormat(new Date(), "yyyyMMddhhmmss"); + fullTime = fullTime.substring(2); + let randomNum = num - (prefix + fullTime).length; + return prefix + fullTime + pubfn.random(randomNum); +}; + +const isSnakeCase = new RegExp('_(\\w)', 'g'); +const isCamelCase = new RegExp('[A-Z]', 'g'); + +function parseObjectKeys(obj, type) { + let parserReg; + let parser; + switch (type) { + case 'snake2camel': + parser = pubfn.snake2camel + parserReg = isSnakeCase + break + case 'camel2snake': + parser = pubfn.camel2snake + parserReg = isCamelCase + break + } + for (const key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + if (parserReg.test(key)) { + const keyCopy = parser(key) + obj[keyCopy] = obj[key] + delete obj[key] + if (Object.prototype.toString.call((obj[keyCopy])) === '[object Object]') { + obj[keyCopy] = parseObjectKeys(obj[keyCopy], type) + } else if (Array.isArray(obj[keyCopy])) { + obj[keyCopy] = obj[keyCopy].map((item) => { + return parseObjectKeys(item, type) + }) + } + } + } + } + return obj +} +/** + * 字符串 - 蛇形转驼峰 + * @param {String} value + * vk.pubfn.snake2camel(value); + */ +pubfn.snake2camel = function(value) { + return value.replace(isSnakeCase, (_, c) => (c ? c.toUpperCase() : '')) +} +/** + * 字符串 - 驼峰转蛇形 + * @param {String} value + * vk.pubfn.camel2snake(value); + */ +pubfn.camel2snake = function(value) { + return value.replace(isCamelCase, str => '_' + str.toLowerCase()) +} + +/** + * 对象内的属性名 - 蛇形转驼峰 + * @param {Object} obj + * vk.pubfn.snake2camelJson(obj); + */ +pubfn.snake2camelJson = function(obj) { + return parseObjectKeys(obj, 'snake2camel'); +}; +/** + * 对象内的属性名 - 驼峰转蛇形 + * @param {Object} obj + * vk.pubfn.camel2snakeJson(obj); + */ +pubfn.camel2snakeJson = function(obj) { + return parseObjectKeys(obj, 'camel2snake'); +}; + +/** + * 将能转成数字的字符串转数字(支持字符串、对象、数组) + * @param {Any} obj + * @param {Object} option 哪些格式需要排除 + * 默认排除 + * mobile:true 手机号,如 15200000001 + * idCard:true 身份证,如 330154202109301214 + * startFrom0:true 第一位是0,且长度大于1的,同时第二位不是.的字符串 如 01,057189101254 + * maxLength:14 超过此长度的字符串排除 + * vk.pubfn.string2Number(obj, option); + */ +pubfn.string2Number = function(obj, option = {}) { + const type = Object.prototype.toString.call(obj).slice(8, -1).toLowerCase(); + switch (type) { + case 'string': + if (obj && !isNaN(obj)) { + let { + mobile = true, + idCard = true, + startFrom0 = true, + maxLength = 14, + } = option; + if (obj.length > maxLength) { + return obj; + } else if (mobile && pubfn.test(obj, "mobile")) { + return obj; + } else if (idCard && pubfn.test(obj, "card")) { + return obj; + } else if (startFrom0 && obj.length > 1 && obj.indexOf("0") === 0 && obj.indexOf(".") !== 1) { + return obj; + } + return Number(obj); + } else { + return obj; + } + case 'object': + const keys = Object.keys(obj); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + obj[key] = pubfn.string2Number(obj[key]); + } + return obj; + case 'array': + for (let i = 0; i < obj.length; i++) { + obj[i] = pubfn.string2Number(obj[i]); + } + return obj; + default: + return obj; + } +}; + +/** + * 保留小数 + * @param {Number} val 原值 + * @param {Number} precision 精度 + * vk.pubfn.toDecimal(val, 2); + */ +pubfn.toDecimal = function(val, precision = 0) { + if (typeof val === "string") val = Number(val); + return parseFloat(val.toFixed(precision)); +}; + +/** + * 判断文件url的类型 + * @param {String} url 文件的url路径 + * vk.pubfn.getFileType(url); + * 返回值为字符串 + * image 图片 + * video 视频 + * audio 音频 + * other 其他 + */ +pubfn.getFileType = function(url) { + let fileType; + if (pubfn.checkFileSuffix(url, ["png", "jpg", "jpeg", "gif", "bmp", "svg"])) { + fileType = "image"; + } else if (pubfn.checkFileSuffix(url, ["avi", "mp4", "3gp", "mov", "rmvb", "rm", "flv", "mkv"])) { + fileType = "video"; + } else if (pubfn.checkFileSuffix(url, ["mp3"])) { + fileType = "audio"; + } else { + fileType = "other"; + } + return fileType; +}; +/** + * 获取文件url的后缀名 + * @param {String} url 文件的url路径,必须带 + * vk.pubfn.getFileSuffix(url); + */ +pubfn.getFileSuffix = function(url) { + let suffix; + let index = url.lastIndexOf("."); + if (index > -1) { + suffix = url.substring(index + 1); + } + return suffix; +}; + +/** + * 判断文件url是否在指定后缀名数组内 + * @param {String} url 文件的url路径 + * @param {Array} list 后缀名列表 + * vk.pubfn.checkFileSuffix(url,["png", "jpg", "jpeg", "gif", "bmp", "svg"]); + */ +pubfn.checkFileSuffix = function(url, list) { + let key = false; + let suffix = pubfn.getFileSuffix(url); + for (let i = 0; i < list.length; i++) { + if (list.indexOf(suffix) > -1) { + key = true; + break; + } + } + return key; +}; +// 前端专属开始 ----------------------------------------------------------- +/** + * 将时间显示成1秒前、1天前 + * @description 主要用于 文章最后回复时间: 1分钟前 + * @param {String || Number} startTime 需要计算的时间 如文章最后回复时间 + * vk.pubfn.dateDiff(startTime); + */ +pubfn.dateDiff = function(startTime, suffix = "前") { + if (!startTime) { + return ""; + } + if (typeof startTime === "string" && !isNaN(startTime)) startTime = Number(startTime); + if (typeof startTime == "number") { + if (startTime.toString().length == 10) startTime *= 1000; + startTime = new Date(startTime); + startTime = pubfn.timeFormat(startTime); + } + if (typeof startTime == "string") { + startTime = startTime.replace("T", " "); + startTime = startTime; + startTime = new Date(startTime.replace(/-/g, "/")); //将-转化为/,使用new Date + } + let endTime = new Date(); //获取当前时间 + let nd = 1000 * 24 * 60 * 60; //一天的毫秒数 + let nh = 1000 * 60 * 60; //一小时的毫秒数 + let nm = 1000 * 60; //一分钟的毫秒数 + let ns = 1000; //一秒钟的毫秒数long diff;try { + let diff = endTime.getTime() - startTime.getTime(); + let day = Math.floor(diff / nd); //计算差多少天 + let hour = Math.floor(diff % nd / nh); //计算差多少小时 + let min = Math.floor(diff % nd % nh / nm); //计算差多少分钟 + let sec = Math.round(diff % nd % nh % nm / ns); //计算差多少秒//输出结果 + let showStr = "1 秒"; + if (day > 0) { + showStr = day + "天"; + } else if (hour > 0) { + showStr = hour + "小时"; + } else if (min > 0) { + showStr = min + "分钟"; + } else if (sec > 0) { + showStr = sec + "秒"; + } + showStr += suffix; + return showStr; +} +/** + * 将时间显示成1秒、1天 + * @description 主要用于 到期时间剩余 : 3天 这样的场景 + * @param {String || Number} endTime 需要计算的时间 如到期时间 + * vk.pubfn.dateDiff2(endTime); + */ +pubfn.dateDiff2 = function(startTime, str = "1秒") { + if (!startTime) { + return ""; + } + if (typeof startTime === "string" && !isNaN(startTime)) startTime = Number(startTime); + if (typeof startTime == "number") { + if (startTime.toString().length == 10) startTime *= 1000; + startTime = new Date(startTime); + startTime = pubfn.timeFormat(startTime); + } + if (typeof startTime == "string") { + startTime = startTime.replace("T", " "); + startTime = startTime; + startTime = new Date(startTime.replace(/-/g, "/")); //将-转化为/,使用new Date + } + let endTime = new Date(); //获取当前时间 + let nd = 1000 * 24 * 60 * 60; //一天的毫秒数 + let nh = 1000 * 60 * 60; //一小时的毫秒数 + let nm = 1000 * 60; //一分钟的毫秒数 + let ns = 1000; //一秒钟的毫秒数long diff;try { + let diff = startTime.getTime() - endTime.getTime(); + let day = Math.floor(diff / nd); + let hour = Math.floor(diff % nd / nh); + let min = Math.floor(diff % nd % nh / nm); + let sec = Math.round(diff % nd % nh % nm / ns); + let showStr = str; + if (day > 0) { + showStr = day + "天"; + } else if (hour > 0) { + showStr = hour + "小时"; + } else if (min > 0) { + showStr = min + "分钟"; + } else if (sec > 0) { + showStr = sec + "秒"; + } + return showStr; +}; +/** + * 将大数字转中文 + * @description 主要用于展示浏览量等不需要非常精确显示的场景 + * 如: + * 3210 -> 3千 + * 31210 -> 3万 + * 1523412 -> 1百万 + * 15234120 ->1千万 + * @param {Number} n 需要转换的数字 + * vk.pubfn.numStr(n); + */ +pubfn.numStr = function(n) { + if (typeof n == "string") { + n = parseFloat(n); + } + let str = n; + if (n < 1000) { + str = n; + } else if (n < 10000) { + let n1 = Math.floor(n / 100); + str = n1 / 10 + "千" + } else if (n < 1000000) { + let n1 = Math.floor(n / 1000); + str = n1 / 10 + "万" + } else if (n < 10000000) { + let n1 = Math.floor(n / 1000000); + str = n1 + "百万" + } else if (n < 100000000) { + let n1 = Math.floor(n / 10000000); + str = n1 + "千万" + } else if (n >= 100000000) { + let n1 = Math.floor(n / 10000000); + str = n1 / 10 + "亿" + } + return str; +}; +/** + * 金额显示过滤器(已分为单位,将100 转成 1) + * @param {Number} money 金额 + * vk.pubfn.priceFilter(money); + */ +pubfn.priceFilter = function(money, defaultValue = "") { + if (pubfn.isNull(money)) { + return defaultValue; + } + if (isNaN(money)) { + return money; + } + if (typeof money == "string") { + money = parseFloat(money); + } + return (money / 100).toFixed(2); +}; +// 金额过滤器 - 只显示小数点左边 +pubfn.priceLeftFilter = function(n) { + let s = ""; + if (n) { + s = pubfn.priceFilter(n).split(".")[0]; + } + return s; +}; +// 金额过滤器 - 只显示小数点右边 +pubfn.priceRightFilter = function(n) { + let s = ""; + if (n) { + s = pubfn.priceFilter(n).split(".")[1]; + } + return s; +}; +/** + * 百分比过滤器 将 0.01 显示成 1% 1 显示成 100% + * @param {Number} value 百分比值 + * @param {Boolean} needShowSymbol 显示 % 这个符号 + * @param {String | Number} defaultValue value为空时的默认值 + * vk.pubfn.percentageFilter(money); + */ +pubfn.percentageFilter = function(value, needShowSymbol = true, defaultValue = "") { + if (pubfn.isNull(value)) { + return defaultValue; + } + if (isNaN(value)) { + return value; + } + if (typeof value == "string") { + value = parseFloat(value); + } + value = parseFloat((value * 100).toFixed(2)); + if (needShowSymbol) { + value += "%"; + } + return value; +}; +/** + * 折扣过滤器 将 0.1 显示成 1折 1 显示成 原价 0 显示成免费 + * @param {Number} value 折扣值 + * @param {Boolean} needShowSymbol 显示 折 这个中文字符 + * @param {String | Number} defaultValue value为空时的默认值 + * vk.pubfn.discountFilter(value); + */ +pubfn.discountFilter = function(value, needShowSymbol = true, defaultValue = "") { + if (pubfn.isNull(value)) { + return defaultValue; + } + if (isNaN(value)) { + return value; + } + if (typeof value == "string") { + value = parseFloat(value); + } + value = parseFloat((value * 10).toFixed(2)); + if (value > 10) { + return "折扣不可以大于原价"; + } + if (value == 10) { + return "原价"; + } + if (value == 0) { + return "免费"; + } + if (value < 0) { + return "折扣不可以小于0"; + } + if (needShowSymbol) { + value += " 折"; + } + return value; +}; +/** + * 将字符串格式的时间转为时间戳 + * @param {String} dateString 格式为:2020-08-08 12:12:12 + */ +pubfn.toTimeLong = function(dateString) { + if (!dateString) { + return ""; + } + dateString = dateString.substring(0, 19); + dateString = dateString.replace(new RegExp(/-/, "g"), '/'); + let time = new Date(dateString).getTime(); + if (isNaN(time)) { + time = ""; + } + return time; +}; + +/** + * 单位进制换算 + * length 换算前大小 + * arr 进制的数组,如["B","KB","MB","GB"] + * ary 进制,如KB-MB-GB,进制1024 + * precision 数值精度 + * vk.pubfn.calcSize(length,["B","KB","MB","GB"],1024,3); + */ +pubfn.calcSize = function(length = 0, arr, ary, precision = 2, showType = "auto") { + length = parseFloat(length); + let size = 0; + let type = ""; + if (length < ary || arr.length <= 1) { + type = arr[0]; + size = parseFloat(length.toFixed(precision)); + } else { + for (let i = 1; i < arr.length; i++) { + let currentType = arr[i]; + length = length / ary; + if (showType === "auto") { + if (length < ary) { + type = currentType; + size = parseFloat(length.toFixed(precision)); + break; + } + } else { + if (showType === currentType) { + type = currentType; + size = parseFloat(length.toFixed(precision)); + break; + } + } + } + } + return { + size: size, + type: type, + title: size + " " + type + } +}; + +/** + * 将一个大数组拆分成N个小数组(分割数组) + * @param {Array} array 大数组 + * @param {Number} size 小数组每组最大多少个 + * 代码示例 + * let newArray = vk.pubfn.splitArray(array, 2); + */ +pubfn.splitArray = function(array, size) { + let data = []; + for (let i = 0; i < array.length; i += size) { + data.push(array.slice(i, i + size)) + } + return data +}; + +/** + * 将对象内的属性按照ASCII字符顺序进行排序,返回排序后的对象 + * @param {Object} obj 需要排序对象 + * 代码示例 + * let newObj = vk.pubfn.objectKeySort(obj); + */ +pubfn.objectKeySort = function(obj) { + let keys = Object.keys(obj).sort(); + let newObject = {}; + for (let i in keys) { + newObject[keys[i]] = (obj[keys[i]]); + } + return newObject; +}; + +// 以下是前端专属API----------------------------------------------------------- + +/** + * 手机端长列表分页加载数据 2.0版本 + * @param {Vue页面对象} that 页面数据对象this + * @param {String} url 请求地址(云函数路径) + * @param {String} listName 后端返回的list数组的字段名称,默认rows(二选一即可) + * @param {String} listKey 后端返回的list数组的字段名称,默认rows(二选一即可) + * @param {String} formKey 表单请求的对象数据源字段名称,默认queryForm1 + * @param {Object} data 额外数据 + * @param {function} dataPreprocess 数据预处理函数 + * + * 代码示例 + vk.pubfn.getListData2({ + that : this, + url : "template/db_api/pub/select", + data : { + a : 1 + }, + dataPreprocess : function(list){ + return list; + } + }); + */ +pubfn.getListData2 = function(obj = {}) { + let vk = uni.vk; + let { + that, + listName, + listKey = "rows", + formKey = "queryForm1", + url, + dataPreprocess, + idKeyName = "_id" + } = obj; + if (listName) listKey = listName; + /** + * 2.0与1.0的区别 + * 2.0使用的queryForm1作为查询,而1.0是form1 + * 2.0云函数端是getTableData,而1.0是selects + */ + let queryForm1 = that[formKey] || that.queryForm1 || that.queryForm; + // 标记为请求中 + that.loading = true; + let hasMore = true; + if (queryForm1.pagination.pageIndex === 1) { + that.firstLoading = true; + } + vk.callFunction({ + url: url, + data: queryForm1, + success: function(data) { + let list = data[listKey] || []; + // 数据预处理 + if (typeof dataPreprocess == "function") { + list = dataPreprocess(list); + } + if (queryForm1.pagination.pageIndex > 1) { + // 翻页 + if (list.length == 0) { + // 无数据时 + hasMore = false; + queryForm1.pagination.pageIndex--; + list = that.data.list; + } else { + // 有数据时 + if (list.length < queryForm1.pagination.pageSize) { + hasMore = false; + } + // 数据合并 + list = vk.pubfn.arr_concat(that.data.list, list, idKeyName); + } + } else if (queryForm1.pagination.pageIndex == 1) { + // 第一页 + if (list.length < queryForm1.pagination.pageSize) { + hasMore = false; + } + if (list.length == 0) { + that.state.isEmpty = true; + } else { + that.state.isEmpty = false; + } + } + // 如果后端返回了hasMore,则使用后端的hasMore值 + if (typeof data.hasMore !== "undefined") { + hasMore = data.hasMore; + } + data = { + ...data, + total: data.total, + list: list, + hasMore: hasMore, + pageIndex: data.pageIndex, + pageSize: data.pageSize + }; + that.state.loadmore = hasMore ? "loadmore" : "nomore"; // 更新状态 + that.data = vk.pubfn.objectAssign(that.data, data); // 更新数据 + if (typeof obj.success == "function") obj.success(data); + }, + fail: function(err) { + that.state.loadmore = "loadmore"; + if (queryForm1.pagination.pageIndex > 1) { + queryForm1.pagination.pageIndex--; + } + if (typeof obj.fail == "function") { + obj.fail(data); + } else if (err && err.msg) { + vk.toast(err.msg, "none"); + } + }, + complete: function(res) { + that.loading = false; + if (queryForm1.pagination.pageIndex === 1) { + that.state.firstLoading = false; + } + if (typeof obj.complete == "function") obj.complete(res); + } + }); +}; + +/** + * 手机端长列表分页加载数据(1.0版本) + * @param {Vue页面对象} that 页面数据对象this + * @param {String} url 请求地址(云函数路径) + * @param {String} listName 后端返回的list数组的字段名称,默认rows + * @param {String} listKey 后端返回的list数组的字段名称,默认rows + * @param {String} formKey 表单请求的对象数据源字段名称,默认form1 + * @param {Object} data 额外数据 + * @param {function} dataPreprocess 数据预处理函数 + * + * 代码示例 + vk.pubfn.getListData({ + that : this, + url : "template/db_api/pub/select", + listKey : "rows", + formKey : "form1", + data : { + a : 1 + }, + dataPreprocess : function(list){ + return list; + } + }); + */ +pubfn.getListData = function(obj = {}) { + let { + that, + listName, + listKey = "rows", + formKey = "form1", + url, + dataPreprocess, + loading + } = obj; + let vk = uni.vk; + if (listName) listKey = listName; + let { data = {} } = that; + let form1 = that[formKey] || {}; + let { pageKey = true } = data; + if (!form1.pageIndex) form1.pageIndex = 1; + if (!form1.pageSize) form1.pageSize = 20; + let addTime = form1.addTime; + let endTime = form1.endTime; + if (endTime) endTime += " 23:59:59"; + if (!pageKey && form1.pageIndex > 1) { + form1.pageIndex--; + return false; + } + + if (addTime) form1.addTimeLong = pubfn.toTimeLong(addTime); + if (endTime) form1.endTimeLong = pubfn.toTimeLong(endTime); + if (obj.data && JSON.stringify(obj.data) != "{}") { + pubfn.objectAssign(form1, obj.data); + } + let title = obj.title; + if (typeof obj.title == "undefined" && !loading) { + title = form1.pageIndex == 1 ? "请求中..." : ""; + } + vk.callFunction({ + url: url, + data: form1, + title: title, + loading: loading, + success: function(data) { + let list = data[listKey] || []; + // 数据预处理 + if (typeof dataPreprocess == "function") { + list = dataPreprocess(list); + } + if (form1.pageIndex > 1) { + // 翻页 + if (list.length == 0) { + // 无数据时 + pageKey = false; + form1.pageIndex--; + list = that.data.list; + } else { + // 有数据时 + if (list.length < form1.pageSize) { + pageKey = false; + } + let oldList = that.data.list; + // 数据合并 + list = pubfn.arr_concat(oldList, list, "_id"); + } + } else if (form1.pageIndex == 1) { + if (list.length < form1.pageSize) { + pageKey = false; + } + } + //console.log(pageKey,list.length,form1.pageSize); + data = { + ...data, + total: data.total, + list: list, + pageKey: pageKey, + loadmore: pageKey ? "loadmore" : "nomore" // 更新状态 + }; + that.data = pubfn.objectAssign(that.data, data); // 更新数据 + if (typeof obj.success == "function") obj.success(data); + }, + fail: function(err) { + if (form1.pageIndex > 1) { form1.pageIndex--; } + if (typeof obj.fail == "function") { + obj.fail(data); + } else if (err && err.msg) { + vk.toast(err.msg, "none"); + } + }, + complete: function(res) { + if (typeof obj.complete == "function") obj.complete(res); + }, + }); +}; + +/** + * 动态组件数据获取 + * @description 主要用于动态组件的数据获取 + * @param {Vue页面对象} that 页面数据对象this + * @param {String} ids 动态数据组件的ID + * + * 代码示例 + * 如:放置一个动态数据的 公告组件 和 一个轮播图组件 + * view 核心:自定义组件接收一个 Object 类型的属性 datas + + + 在页面数据变量中新增 componentsDynamic + data() { + return { + // 动态组件数据集合 + componentsDynamic:{} + } + } + 在页面初始化方法中执行下面的函数 + this.vk.pubfn.getComponentsDynamicData({ + that : this, + ids : ["notice-bar-01","index-swiper-01"] + }); + */ +pubfn.getComponentsDynamicData = function(obj = {}) { + let { + that, + keyName = "componentsDynamic", + title, + url = "plugs/components_dynamic/client/pub/getComponentsDynamicData", + ids + } = obj; + let vk = uni.vk; + let form1 = { + ids: ids + }; + if (obj.data && JSON.stringify(obj.data) != "{}") { + pubfn.objectAssign(form1, obj.data); + } + // 读取缓存开始----------------------------------------------------------- + let cacheKey = "pub-componentsDynamic"; + let cacheData = uni.getStorageSync(cacheKey) || {}; + let cacheDataKey = JSON.stringify(ids); + if (cacheData[cacheDataKey]) { + // 渲染本地数据 + that[keyName] = cacheData[cacheDataKey]; + } + // 读取缓存结束----------------------------------------------------------- + vk.callFunction({ + url: url, + data: form1, + title: title, + success: function(data) { + if (JSON.stringify(cacheData[cacheDataKey]) !== JSON.stringify(data.componentsDynamic)) { + // 渲染服务器数据 + that[keyName] = data.componentsDynamic; + // 同时将组件数据进行缓存 + cacheData[cacheDataKey] = data.componentsDynamic; + uni.setStorageSync(cacheKey, cacheData); + } + if (typeof obj.success == "function") obj.success(data); + }, + fail: function(err) { + console.error(err); + if (typeof obj.fail == "function") obj.fail(data); + }, + complete: function() { + if (typeof obj.complete == "function") obj.complete(data); + }, + }); +}; + +/** + * 将../../ 形式的页面相对路径 转成 页面绝对路径 + * @param {String} url 需要转换的url + * vk.pubfn.getPageFullPath(url); + */ +pubfn.getPageFullPath = function(url) { + let fullPath = url; + if (fullPath.indexOf("/") !== 0) { + if (fullPath.indexOf("./") === 0) { + //fullPath = "." + fullPath; + fullPath = fullPath.substring(2); + } + let urlSplit = fullPath.split("../"); + // 向上目录级数,0:根目录 1:向上1级 + let level = urlSplit.length; + // 尾部路径 + let urlEnd = urlSplit[level - 1]; + // 获取当前页面的页面全路径 + let pages = getCurrentPages(); + let currentPage = pages[pages.length - 1]; + let currentPagePath = currentPage.route; + // 分割成目录,最后一段是页面名称 + let urlArr = currentPagePath.split("/"); + let urlSplicing = ""; + // 开始拼接 + for (let i = 0; i < urlArr.length - level; i++) { + urlSplicing += urlArr[i] + "/"; + } + // 完整页面路径 + fullPath = urlSplicing + urlEnd; + if (fullPath.indexOf("/") != 0) { + fullPath = "/" + fullPath; + } + } + return fullPath; +}; +/** + * 获取平台信息 + * let platform = vk.pubfn.getPlatform(); + */ +pubfn.getPlatform = function() { + let platform; + // #ifdef APP-PLUS || APP-NVUE || APP-PLUS-NVUE + platform = "app-plus"; + // #endif + // #ifdef H5 + platform = "h5"; + // #endif + // #ifdef MP-WEIXIN + platform = "mp-weixin"; + // #endif + // #ifdef MP-ALIPAY + platform = "mp-alipay"; + // #endif + // #ifdef MP-BAIDU + platform = "mp-baidu"; + // #endif + // #ifdef MP-TOUTIAO + platform = "mp-toutiao"; + // #endif + // #ifdef MP-QQ + platform = "mp-qq"; + // #endif + // #ifdef MP-360 + platform = "mp-360"; + // #endif + // #ifdef MP-KUAISHOU + platform = "mp-toutiao"; + // #endif + return platform; +}; +/** + * 获取当前页面实例 + * 返回数据 + * fullPath 当前打开页面的完整路径(带页面参数) + * pagePath 当前打开页面的路径(不含参数) + * options 当前打开页面的参数 + * route 当前打开页面路由地址 + * $vm 当前打开页面的vue实例 + * vk.pubfn.getCurrentPage(); + */ +pubfn.getCurrentPage = function() { + let res = {}; + let pages = getCurrentPages(); + let page = pages[pages.length - 1]; + if (page.route.indexOf("/") == 0) page.route = page.route.substring(1); + let pagePath = `/${page.route}`; + let fullPath = `/${page.route}`; + let options = page.options; + if (page.$page) { + if (typeof page.$page.fullPath !== "undefined") { + fullPath = page.$page.fullPath; + } else if (typeof options === "object") { + let optionsStr = pubfn.queryParams(options); + fullPath = pagePath + optionsStr; + } + } + res.fullPath = fullPath; + res.pagePath = pagePath; + res.options = options; + res.route = page.route; + res.$vm = page.$vm; + return res; +}; +/** + * 获取当前页面路由 + * vk.pubfn.getCurrentPageRoute(); + */ +pubfn.getCurrentPageRoute = function(removeSlash) { + let pages = getCurrentPages(); + let page = pages[pages.length - 1]; + if (removeSlash) { + return page.route; + } else { + return "/" + page.route; + } +}; +/** + * 文件转base64 + +方式一 + +vk.pubfn.fileToBase64({ + file:res.tempFiles[0], + success:function(base64){ + + } +}); + +方式二 + +vk.pubfn.fileToBase64({ file }).then(base64 => { + +}); + */ +pubfn.fileToBase64 = function(obj = {}) { + let { file } = obj; + let filePath = typeof file === "object" ? file.path : file; + return new Promise(function(resolve, reject) { + // #ifdef H5 + let reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = function(res) { + let base64 = this.result; + if (base64.indexOf(";base64,") == -1) { + base64 = "data:image/jpeg;base64," + base64; + } + if (obj.success) obj.success(base64); + if (obj.complete) obj.complete(base64); + resolve(base64); + }; + reader.onerror = function(err) { + if (obj.fail) obj.fail(err); + if (obj.complete) obj.complete(err); + reject(err); + }; + // #endif + // #ifdef MP + uni.getFileSystemManager().readFile({ + filePath: filePath, + encoding: "base64", + success: function(res) { + let base64 = res.data; + if (base64.indexOf(";base64,") == -1) { + base64 = "data:image/jpeg;base64," + base64; + } + if (obj.success) obj.success(base64); + if (obj.complete) obj.complete(base64); + resolve(base64); + }, + fail: function(err) { + if (obj.fail) obj.fail(err); + reject(err); + }, + complete: obj.complete + }); + // let base64 = uni.getFileSystemManager().readFileSync(file.path, 'base64'); + // if(obj.success) obj.success(base64); + // if(obj.complete) obj.complete(base64); + // resolve(base64); + // #endif + // #ifdef APP-PLUS + plus.io.resolveLocalFileSystemURL(pubfn.getLocalFilePath(filePath), function(entry) { + entry.file(function(file) { + let fileReader = new plus.io.FileReader(); + fileReader.onload = function(data) { + if (obj.success) obj.success(data.target.result); + if (obj.complete) obj.complete(data.target.result); + resolve(data.target.result); + } + fileReader.onerror = function(err) { + if (obj.fail) obj.fail(err); + reject(err); + } + fileReader.readAsDataURL(file) + }, function(err) { + if (obj.fail) obj.fail(err); + reject(err); + }) + }, function(err) { + if (obj.fail) obj.fail(err); + reject(err); + }) + // #endif + }); +}; + +/** + * base64转文件 +方式一 + +vk.pubfn.base64ToFile({ + base64:base64, + success:function(file){ + + } +}); + +方式二 + +vk.pubfn.base64ToFile({ base64 }).then(file => { + +}); + */ +pubfn.base64ToFile = function(obj = {}) { + let { + base64 = "", + filePath + } = obj; + let extName = base64.split(',')[0].match(/data\:\S+\/(\S+);/); + if (extName) { + extName = extName[1]; + } else { + reject(new Error('base64 error')); + } + if (!filePath) { + filePath = pubfn.random(32, "abcdefghijklmnopqrstuvwxyz0123456789") + '.' + extName; + } + let index = base64.indexOf("base64,"); + let base64Data = base64; + if (index > -1) { + base64Data = base64.substring(base64.indexOf("base64,") + 7); + } + let savePath; + return new Promise(function(resolve, reject) { + // #ifdef MP + savePath = wx.env.USER_DATA_PATH + '/' + filePath; + let fs = uni.getFileSystemManager(); + fs.writeFile({ + filePath: savePath, + data: base64Data, + encoding: "base64", + success: function(res) { + let file = { + path: savePath, + lastModifiedDate: new Date(), + name: filePath + }; + if (obj.success) obj.success(file); + resolve(file); + }, + fail: function(res) { + if (obj.fail) obj.fail(res); + reject(res); + }, + complete: obj.complete + }); + // #endif + // #ifdef H5 + savePath = filePath; + let blob = pubfn.base64toBlob(base64); + let file = pubfn.blobToFile(blob, savePath); + if (obj.success) obj.success(file); + if (obj.complete) obj.complete(file); + resolve(file); + // #endif + // #ifdef APP-PLUS + let fileName = filePath; + let basePath = '_user_resources'; + let dirPath = 'vk_temp'; + savePath = basePath + '/' + dirPath + '/' + fileName; + let bitmap = new plus.nativeObj.Bitmap(fileName); + bitmap.loadBase64Data(base64, function() { + bitmap.save(savePath, {}, function() { + bitmap.clear(); + let file = { + path: savePath, + lastModifiedDate: new Date(), + name: filePath + }; + if (obj.success) obj.success(file); + if (obj.complete) obj.complete(file); + resolve(file); + }, function(error) { + bitmap.clear(); + if (obj.fail) obj.fail(error); + reject(error); + }) + }, function(error) { + bitmap.clear(); + if (obj.fail) obj.fail(error); + reject(error); + }) + // #endif + }); +}; +/** + * 将base64转换为blob (H5独有) + vk.pubfn.base64toBlob(base64); + */ +pubfn.base64toBlob = function(base64) { + let arr = base64.split(','); + let mime = arr[0].match(/:(.*?);/)[1]; + let bstr = atob(arr[1]); + let n = bstr.length; + let u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + return new Blob([u8arr], { type: mime }); +}; +/** + * //将blob转换为file + vk.pubfn.blobToFile(base64); + */ +pubfn.blobToFile = function(blob, fileName) { + blob.lastModifiedDate = new Date(); + blob.name = fileName; + blob.path = URL.createObjectURL(blob); + return blob; +}; + +/** + * 小程序订阅消息 前端无需再写 #ifdef MP-WEIXIN + vk.pubfn.requestSubscribeMessage({ + tmplIds: ['NcspDBQpH6CGHos3mMADrrQpEv2gHmtfOPa5KTLs92E'] + }); + */ +pubfn.requestSubscribeMessage = function(obj) { + // #ifdef MP-WEIXIN + return uni.requestSubscribeMessage(obj); + // #endif +}; + +/** + * 检测是否需要登录 此方法目前为测试版 + * vk.pubfn.checkLogin(); + */ +pubfn.checkLogin = function(obj = {}) { + let vk = uni.vk; + let loginUrl = vk.getConfig("login.url"); + try { + let url; + try { + url = obj.url || vk.pubfn.getCurrentPageRoute(); + } catch (err) { + url = vk.getConfig("index.url") || "/pages/index/index"; + } + vk.navigate.checkNeedLogin({ + url: url, + success: function(res) { + if (res.needLogin) { + // 记录下原本要跳转的页面 + url = vk.pubfn.getPageFullPath(obj.fullPath || url); + vk.navigate.setOriginalPage({ url }); + if (obj.isOnLaunch) vk.navigate.isOnLaunchToLogin = true; // 标记为首次启动的页面需要登录 + uni.reLaunch({ + url: loginUrl, + success: () => { + // #ifdef MP-WEIXIN + setTimeout(() => { + uni.hideHomeButton(); + }, 400); + // #endif + } + }); + } else { + // #ifdef H5 + // 解决微信公众号登录无法跳回原页面的问题 + if (!obj.options || !obj.options.code || !obj.options.state) { + vk.navigate.setOriginalPage(null); + } + // #endif + // #ifndef H5 + vk.navigate.setOriginalPage(null); + // #endif + } + } + }); + } catch (err) { + console.error("catch", err); + uni.reLaunch({ + url: loginUrl + }); + // #ifdef MP-WEIXIN + uni.hideHomeButton(); + // #endif + } +}; +/** + * 获取文件本地路径 + * @param {Object} path + */ +pubfn.getLocalFilePath = function(path) { + if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path.indexOf('_downloads') === 0) { + return path + } + if (path.indexOf('file://') === 0) { + return path + } + if (path.indexOf('/storage/emulated/0/') === 0) { + return path + } + if (path.indexOf('/') === 0 && typeof plus !== "undefined") { + let localFilePath = plus.io.convertAbsoluteFileSystem(path) + if (localFilePath !== path) { + return localFilePath + } else { + path = path.substr(1) + } + } + return '_www/' + path +}; + +/** + * 获取当前支持的应用语言 + * let localeList = vk.pubfn.getLocaleList(); + */ +pubfn.getLocaleList = function() { + let localeList = [ + { value: "zh-Hans", label: "简体中文" }, + { value: "zh-Hant", label: "繁體中文" }, + { value: "en", label: "English" } + ]; + return localeList; +}; +/** + * 获取当前应用语言 + * let locale = vk.pubfn.getLocale(); + */ +pubfn.getLocale = function() { + let localeValue; + if (typeof uni.getLocale === "function") { + localeValue = uni.getLocale(); + } else { + localeValue = "zh-Hans"; // 默认中文简体 + } + let localeObj = { + "zh_CN": "zh-Hans", // 中国大陆(简体) + "zh_HK": "zh-Hant", // 香港(繁体) + "zh_MO": "zh-Hant", // 澳门(繁体) + "zh_SG": "zh-Hans", // 新加坡(简体) + "zh_TW": "zh-Hant", // 台湾(繁体) + }; + if (localeObj[localeValue]) localeValue = localeObj[localeValue]; + return localeValue; +}; +/** + * 获取当前应用语言 + * let localeObj = vk.pubfn.getLocaleObject(); + */ +pubfn.getLocaleObject = function() { + let value = pubfn.getLocale(); + let list = pubfn.getLocaleList(); + return pubfn.getListItem(list, "value", value); +}; +/** + * 设置当前应用语言 + */ +pubfn.setLocale = function(...e) { + return uni.setLocale(...e); +}; + +/** + * 将obj2的数据赋值给obj1,并使vue双向绑定(vue2对象新增属性不会双向绑定) + * @description 将 obj2 的属性赋值给 obj1 (如果obj1中有对应的属性,则会被obj2的属性值覆盖) + * @param {Object} obj1 + * @param {Object} obj2 + * @param {Object} that 页面实例 + * vk.pubfn.objectAssignForVue(obj1, obj2, that); + */ +pubfn.objectAssignForVue = function(obj1, obj2, that) { + pubfn.objectDeleteInvalid(obj2); + for (let key in obj2) { + that.$set(obj1, key, obj2[key]); + } +}; + +// 前端专属结束 ----------------------------------------------------------- +export default pubfn; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/modal.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/modal.js new file mode 100644 index 0000000..98bd6a5 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/modal.js @@ -0,0 +1,326 @@ +/** + * 函数 - 弹窗 + */ +import { Message, MessageBox, Loading } from 'element-ui'; +let loadingInstance = null +const localeObj = { + title: { + "zh-Hans": "提示", + "zh-Hant": "提示", + "en": "Tips" + }, + confirmText: { + "zh-Hans": "确定", + "zh-Hant": "確定", + "en": "OK" + }, + cancelText: { + "zh-Hans": "取消", + "zh-Hant": "取消", + "en": "Cancel" + }, + placeholderText: { + "zh-Hans": "请输入", + "zh-Hant": "請輸入", + "en": "Please enter" + } +}; +export default { + /** + vk.alert("内容"); + vk.alert("内容","提示","好的",function(){ + + }); + */ + alert: function(a = " ", b, c, d) { + let vk = uni.vk; + let locale = vk.getLocale(); + let obj = { + title: localeObj.title[locale], + confirmText: localeObj.confirmText[locale], + placeholderText: localeObj.placeholderText[locale], + content: a, + showCancel: false + }; + if (typeof d === 'function') { + obj.title = b; + obj.confirmText = c; + obj.success = d; + } else if (typeof c === 'function') { + obj.title = b; + obj.success = c; + } else if (typeof b === 'function') { + obj.success = b; + } else if (b != undefined) { + obj.title = b; + if (c != undefined) { + obj.confirmText = c; + } + } + if (typeof obj.content === 'number') { + obj.content = obj.content + ""; + } else if (typeof obj.content === 'object') { + obj.content = JSON.stringify(obj.content); + } + return MessageBox({ + title: obj.title, + message: obj.content, + confirmButtonText: obj.confirmText, + }) + // return uni.showModal(obj); + }, + /** + vk.confirm("内容","提示","确定","取消",(res) => { + if(res.confirm){ + + } + }); + */ + confirm: function(a, b, c, d, e) { + let vk = uni.vk; + let locale = vk.getLocale(); + let obj = { + showCancel: true, + cancelColor: "#999", + title: localeObj.title[locale], + confirmText: localeObj.confirmText[locale], + cancelText: localeObj.cancelText[locale], + placeholderText: localeObj.placeholderText[locale], + }; + if (typeof a === "object") { + obj = a; + } else { + if (typeof a === "string") { + obj.content = a; + } + if (typeof e === 'function') { + obj.title = b; + obj.confirmText = c; + obj.cancelText = d; + obj.success = e; + } else if (typeof d === 'function') { + obj.title = b; + obj.confirmText = c; + obj.success = d; + } else if (typeof c === 'function') { + obj.title = b; + obj.success = c; + } else if (typeof b === 'function') { + obj.success = b; + } else if (b != undefined) { + obj.title = b; + if (c != undefined) { + obj.confirmText = c; + } + } + } + return uni.showModal(obj); + }, + /** + vk.prompt("请输入","提示","确定","取消",function(res){ + if(res.confirm){ + console.log(res.content); + } + },"输入框内初始内容"); + */ + prompt: function(a, b, c, d, e, f) { + let vk = uni.vk; + let locale = vk.getLocale(); + let obj = { + showCancel: true, + editable: true, + cancelColor: "#999", + title: localeObj.title[locale], + confirmText: localeObj.confirmText[locale], + cancelText: localeObj.cancelText[locale], + placeholderText: localeObj.placeholderText[locale], + }; + if (typeof a === "object") { + obj = a; + } else { + if (typeof a === "string") { + obj.placeholderText = a; + } + if (typeof e === 'function') { + obj.title = b; + obj.confirmText = c; + obj.cancelText = d; + obj.success = e; + obj.content = f; + } else if (typeof d === 'function') { + obj.title = b; + obj.confirmText = c; + obj.success = d; + obj.content = e; + } else if (typeof c === 'function') { + obj.title = b; + obj.success = c; + obj.content = d; + } else if (typeof b === 'function') { + obj.success = b; + obj.content = c; + } + } + return uni.showModal(obj); + }, + /** + vk.toast("提示内容","none"); + */ + toast: function(a, b, c, d, e) { + let vk = uni.vk; + if (typeof a === 'number') { + a = a.toString(); + } else if (typeof a === 'object') { + a = JSON.stringify(a); + } + let title = a; + let icon = "none"; + let type = "info"; + let image = ""; + let mask = false; + let duration = 1500; + let fn; + + if (typeof e !== "undefined") { + if (typeof e == "function") fn = e; + if (typeof e == "number") duration = e; + if (typeof e == "boolean") mask = e; + } + if (typeof d !== "undefined") { + if (typeof d == "function") fn = d; + if (typeof d == "number") duration = d; + if (typeof d == "boolean") mask = d; + } + if (typeof c !== "undefined") { + if (typeof c == "function") fn = c; + if (typeof c == "number") duration = c; + if (typeof c == "boolean") mask = c; + } + + if (typeof b !== "undefined") { + if (typeof b == "function") fn = b; + if (typeof b == "number") duration = b; + if (typeof b == "boolean") mask = b; + if (typeof b == 'string') { + if (b == "ok") b = "success"; + if (b == "success" || b == "loading" || b == "none" || b == "error") { + icon = b; + } else { + image = b; + } + } + } + + + return Message({ + message: title, + type: icon, + duration: duration, + onClose: function(res) { + if (typeof fn === 'function') { + setTimeout(function() { + fn(res); + }, duration); + } + } + }) + + // return uni.showToast({ + // title: title, + // icon: icon, + // image: image, + // mask: mask, + // duration: duration, + // success: function(res) { + // if (typeof fn === 'function') { + // setTimeout(function() { + // fn(res); + // }, duration); + // } + // } + // }); + }, + /** + * 操作菜单 + vk.showActionSheet({ + title:"", + list:["位置","@好友"], + color:"rgb(0, 0, 0)", + success:function(res){ + if(res.index==0){ + + }else if(res.index==1){ + + } + } + }); + */ + showActionSheet: function(object) { + let vk = uni.vk; + let title = object.title; + let list = object.list; + let color = object.color || "#000000"; + let success = object.success; + let fail = object.fail; + let complete = object.complete; + return uni.showActionSheet({ + itemList: list, + itemColor: color, + success: function(res) { + let index = res.tapIndex; + let text = list[index]; + let g = { index, text }; + //console.log(g); + if (typeof success == "function") success(g); + }, + fail: function(res) { + //console.log(res); + if (typeof fail == "function") fail(res); + }, + complete: function(res) { + if (typeof complete == "function") complete(res); + } + }); + }, + showLoading: function(obj) { + if (typeof obj == "string") { + let title = obj; + obj = { + title: title, + mask: true + }; + } + loadingInstance = Loading.service({ + text: obj.title + }) + // uni.showLoading(obj); + }, + hideLoading: function() { + if(loadingInstance != null) { + loadingInstance.close(); + } + uni.hideLoading(); + }, + // 设置当前页面的loading变量的值 + setLoading: function(loading = true, obj = true) { + try { + let vk = uni.vk; + if (typeof obj === "boolean") { + let pages = getCurrentPages(); + let page = pages[pages.length - 1]; + let that = page.$vm; + that.loading = loading; + } else if (typeof obj === "object") { + let { data, name, that } = obj; + if (!data) data = that; + vk.pubfn.setData(data, name, loading); + } else if (typeof obj === "string") { + let pages = getCurrentPages(); + let page = pages[pages.length - 1]; + let that = page.$vm; + let name = obj; + vk.pubfn.setData(that, name, loading); + } + } catch (err) {} + }, +} diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/permission.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/permission.js new file mode 100644 index 0000000..e79e439 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/permission.js @@ -0,0 +1,33 @@ +function $hasRole(...args) { + const userRoles = this.$store.state.$user.userInfo.role || []; + return args.some(arg => { + if (Array.isArray(arg)) { + return arg.every(role => userRoles.includes(role)); + } else { + return userRoles.includes(arg); + } + }); +} + +function $hasPermission(...args) { + const userPermission = this.$store.state.$user.permission || [] + return args.some(arg => { + if (Array.isArray(arg)) { + return arg.every(permission => userPermission.includes(permission)); + } else { + return userPermission.includes(arg); + } + }); +} + +export default function(Vue) { + // #ifndef VUE3 + Vue.prototype.$hasRole = $hasRole; + Vue.prototype.$hasPermission = $hasPermission; + // #endif + + // #ifdef VUE3 + Vue.config.globalProperties.$hasRole = $hasRole; + Vue.config.globalProperties.$hasPermission = $hasPermission; + // #endif +} \ No newline at end of file diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/queryParams.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/queryParams.js new file mode 100644 index 0000000..e2cc086 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/queryParams.js @@ -0,0 +1,60 @@ +/** + * 对象转url参数 + * @param {*} data,对象 + * @param {*} isPrefix,是否自动加上"?" + * 此函数参考uView + */ +function queryParams(data = {}, isPrefix = true, arrayFormat = 'brackets') { + let newData = JSON.parse(JSON.stringify(data)); + let prefix = isPrefix ? '?' : '' + let _result = [] + if (['indices', 'brackets', 'repeat', 'comma'].indexOf(arrayFormat) == -1) arrayFormat = 'brackets'; + for (let key in newData) { + let value = newData[key] + // 去掉为空的参数 + if (['', undefined, null].indexOf(value) >= 0) { + continue; + } + // 如果值为数组,另行处理 + if (value.constructor === Array) { + // e.g. {ids: [1, 2, 3]} + switch (arrayFormat) { + case 'indices': + // 结果: ids[0]=1&ids[1]=2&ids[2]=3 + for (let i = 0; i < value.length; i++) { + _result.push(key + '[' + i + ']=' + value[i]) + } + break; + case 'brackets': + // 结果: ids[]=1&ids[]=2&ids[]=3 + value.forEach(_value => { + _result.push(key + '[]=' + _value) + }) + break; + case 'repeat': + // 结果: ids=1&ids=2&ids=3 + value.forEach(_value => { + _result.push(key + '=' + _value) + }) + break; + case 'comma': + // 结果: ids=1,2,3 + let commaStr = ""; + value.forEach(_value => { + commaStr += (commaStr ? "," : "") + _value; + }) + _result.push(key + '=' + commaStr) + break; + default: + value.forEach(_value => { + _result.push(key + '[]=' + _value) + }) + } + } else { + _result.push(key + '=' + value) + } + } + return _result.length ? prefix + _result.join('&') : '' +} + +export default queryParams; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/setClipboardData.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/setClipboardData.js new file mode 100644 index 0000000..71d5773 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/setClipboardData.js @@ -0,0 +1,51 @@ + +// #ifdef H5 + uni.setClipboardData = function setClipboardData({ + data, + success, + fail, + complete + } = {}) { + try { + const x = window.scrollX + const y = window.scrollY + const input = document.createElement('input') + input.setAttribute('readonly', 'readonly') + input.setAttribute('value', data) + input.style.position = 'absolute' + input.style.width = '100px' + input.style.left = '-10000px' + document.body.appendChild(input) + input.focus() + window.scrollTo(x, y) + input.setSelectionRange(0, input.value.length) + document.execCommand('copy') + document.body.removeChild(input) + setTimeout(() => { + const res = { + errMsg: 'setClipboardData:ok', + data + } + success && success(res) + complete && complete(res) + }) + } catch (e) { + setTimeout(() => { + const res = { + errMsg: 'setClipboardData:fail' + } + fail && fail(res) + complete && complete(res) + }) + } + } + // #endif + +// JS对象深度合并 +function setClipboardData(obj = {}) { + uni.setClipboardData({ + ...obj + }); +} + +export default setClipboardData; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/throttle.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/throttle.js new file mode 100644 index 0000000..60cd436 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/throttle.js @@ -0,0 +1,37 @@ +let timeoutArr = []; +let flagArr = []; +/** + * 节流函数 + * 节流原理:在一定时间内,只能触发一次 + * @param {Function} fn 要执行的回调函数 + * @param {Number} time 延时的时间 + * @param {Boolean} isImmediate 是否立即执行 + * @param {String} timeoutName 定时器ID + * @return null +vk.pubfn.throttle(function() { + +}, 1000); + */ +function throttle(fn, time = 500, isImmediate = true, timeoutName = "default") { + if(!timeoutArr[timeoutName]) timeoutArr[timeoutName] = null; + if (isImmediate) { + if (!flagArr[timeoutName]) { + flagArr[timeoutName] = true; + // 如果是立即执行,则在time毫秒内开始时执行 + if(typeof fn === 'function') fn(); + timeoutArr[timeoutName] = setTimeout(() => { + flagArr[timeoutName] = false; + }, time); + } + } else { + if (!flagArr[timeoutName]) { + flagArr[timeoutName] = true; + // 如果是非立即执行,则在time毫秒内的结束处执行 + timeoutArr[timeoutName] = setTimeout(() => { + flagArr[timeoutName] = false; + if(typeof fn === 'function') fn(); + }, time); + } + } +}; +export default throttle \ No newline at end of file diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/timeUtil.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/timeUtil.js new file mode 100644 index 0000000..dc2b4c3 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/timeUtil.js @@ -0,0 +1,642 @@ +/** + * 时间工具类 + */ +var util = {}; +util.getTargetTimezone = function(val) { + if (typeof val === "number") { + return val; + } + let vk = uni.vk; + let defaultValue = 8; + let targetTimezone = defaultValue; + try { + const config = vk.callFunctionUtil.getConfig(); + targetTimezone = config.targetTimezone; + if (typeof targetTimezone !== "number") { + targetTimezone = defaultValue; + } + } catch (err) {} + return targetTimezone; +}; + +// 尽可能的将参数转成正确的时间对象 +util.getDateObject = function(date, targetTimezone) { + if (!date) return ""; + let nowDate; + // 如果是字符串,且纯数字,则强制转数值 + if (typeof date === "string" && !isNaN(date) && date.length >= 10) date = Number(date); + if (typeof date === "number") { + if (date.toString().length == 10) date *= 1000; + nowDate = new Date(date); // 转时间对象 + } else if (typeof date === "object") { + nowDate = new Date(date.getTime()); // 新建一个时间对象 + } else if (typeof date === "string") { + targetTimezone = util.getTargetTimezone(targetTimezone); + let targetTimezoneStr = targetTimezone; + let targetTimezoneF = targetTimezone >= 0 ? "+" : ""; + if (targetTimezone >= 0 && targetTimezone < 10) { + targetTimezoneStr = `0${targetTimezone}`; + } else if (targetTimezone < 0 && targetTimezone > -10) { + targetTimezoneStr = `-0${targetTimezone*-1}`; + } + let arr1 = date.split(" "); + let arr1_1 = arr1[0] || ""; + let arr1_2 = arr1[1] || ""; + let arr2; + if (arr1_1.indexOf("-") > -1) { + arr2 = arr1_1.split("-"); + } else { + arr2 = arr1_1.split("/"); + } + let arr3 = arr1_2.split(":"); + let dateObj = { + year: Number(arr2[0]), + month: Number(arr2[1]) || 1, + day: Number(arr2[2]) || 1, + hour: Number(arr3[0]) || 0, + minute: Number(arr3[1]) || 0, + second: Number(arr3[2]) || 0, + }; + for (let key in dateObj) { + if (dateObj[key] >= 0 && dateObj[key] < 10) dateObj[key] = `0${dateObj[key]}`; + } + // 格式 2022-10-01T00:00:00+08:00 + let dateStr = `${dateObj.year}-${dateObj.month}-${dateObj.day}T${dateObj.hour}:${dateObj.minute}:${dateObj.second}${targetTimezoneF}${targetTimezoneStr}:00`; + nowDate = new Date(dateStr); + } + return nowDate; +}; + +// 获取时间在不同时区下的时间对象 +util.getTimeByTimeZone = function(date, targetTimezone) { + let nowDate = util.getDateObject(date); + targetTimezone = util.getTargetTimezone(targetTimezone); + let timezoneOffset = nowDate.getTimezoneOffset(); + let offset = timezoneOffset * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + let targetTime = nowDate.getTime() + offset; + nowDate = new Date(targetTime); + return nowDate; +}; + + +/** + * 日期格式化 + * @param {Date || Number} date 需要格式化的时间 + * vk.pubfn.timeFormat(new Date(),"yyyy-MM-dd hh:mm:ss"); + */ +util.timeFormat = function(date, fmt = 'yyyy-MM-dd hh:mm:ss', targetTimezone) { + try { + if (!date) return ""; + targetTimezone = util.getTargetTimezone(targetTimezone); + let nowDate = util.getTimeByTimeZone(date, targetTimezone); + let opt = { + "M+": nowDate.getMonth() + 1, //月份 + "d+": nowDate.getDate(), //日 + "h+": nowDate.getHours(), //小时 + "m+": nowDate.getMinutes(), //分 + "s+": nowDate.getSeconds(), //秒 + "q+": Math.floor((nowDate.getMonth() + 3) / 3), //季度 + "S": nowDate.getMilliseconds(), //毫秒 + "Z": `${targetTimezone >= 0 ? '+' : '-'}${Math.abs(targetTimezone).toString().padStart(2, '0')}:00` // 时区 + }; + if (/(y+)/.test(fmt)) { + fmt = fmt.replace(RegExp.$1, (nowDate.getFullYear() + "").substr(4 - RegExp.$1.length)); + } + for (let k in opt) { + if (new RegExp("(" + k + ")").test(fmt)) { + fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (opt[k]) : (("00" + opt[k]).substr(("" + opt[k]).length))); + } + } + return fmt; + } catch (err) { + // 若格式错误,则原值显示 + return time; + } +}; + + +/** + * 解析日期对象属性 + * @param {Date || Number} date 需要转换的时间 + * vk.pubfn.getDateInfo(new Date()); + */ +util.getDateInfo = function(date = new Date(), targetTimezone) { + let nowDate = util.getTimeByTimeZone(date, targetTimezone); + let year = nowDate.getFullYear() + ''; + let month = (nowDate.getMonth() + 1 < 10 ? '0' + (nowDate.getMonth() + 1) : nowDate.getMonth() + 1); + let day = (nowDate.getDate() < 10 ? '0' + (nowDate.getDate()) : nowDate.getDate()); + let hour = (nowDate.getHours() < 10 ? '0' + (nowDate.getHours()) : nowDate.getHours()); + let minute = (nowDate.getMinutes() < 10 ? '0' + (nowDate.getMinutes()) : nowDate.getMinutes()); + let second = (nowDate.getSeconds() < 10 ? '0' + (nowDate.getSeconds()) : nowDate.getSeconds()); + let millisecond = nowDate.getMilliseconds(); //毫秒 + let week = nowDate.getDay(); // 周 + let quarter = Math.floor((nowDate.getMonth() + 3) / 3); //季度 + return { + year: Number(year), + month: Number(month), + day: Number(day), + hour: Number(hour), + minute: Number(minute), + second: Number(second), + millisecond: Number(millisecond), + week: Number(week), + quarter: Number(quarter), + }; +}; + + +/** + * 获取时间范围 + * @param {Date} date 日期对象 可以指定时间计算节点,默认使用当前时间进行计算 + * 返回的是时间戳 + * 返回数据如下: + { + todayStart 今日开始时间(时间戳) + todayEnd 今日结束时间(时间戳) + today12End 今日上午结束时间(时间戳) + monthStart 本月开始时间(时间戳) + monthEnd 本月结束时间(时间戳) + yearStart 本年开始时间(时间戳) + yearEnd 本年结束时间(时间戳) + weekStart 本周开始时间(时间戳) + weekEnd 本周结束时间(时间戳) + hourStart 当前小时开始时间(时间戳) + hourEnd 当前小时结束时间(时间戳) + yesterdayStart 昨天开始时间(时间戳) + yesterday12End 昨天上午结束时间(时间戳) + yesterdayEnd 昨天结束时间(时间戳) + lastMonthStart 上月开始时间(时间戳) + lastMonthEnd 上月结束时间(时间戳) + now 现在的时间点(含月年日时分秒) + months 本年度每月的开始和结束时间 months[1] 代表1月 + days 本月每天的开始和结束时间 days[1] 代表1日 + } + * vk.pubfn.getCommonTime(); + */ +util.getCommonTime = function(date = new Date(), targetTimezone) { + let res = {}; + let nowDate = util.getDateObject(date); + targetTimezone = util.getTargetTimezone(targetTimezone); + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + const { year, month, day, hour, minute, second, millisecond, week, quarter } = util.getDateInfo(nowDate, targetTimezone); + const oneDayTime = 24 * 60 * 60 * 1000; + // 现在的时间 + res.now = { + year, + month, + day, + hour, + minute, + second, + millisecond, + week, + quarter, + date_str: util.timeFormat(nowDate, "yyyy-MM-dd hh:mm:ss", targetTimezone), + date_day_str: util.timeFormat(nowDate, "yyyy-MM-dd", targetTimezone), + date_month_str: util.timeFormat(nowDate, "yyyy-MM", targetTimezone), + }; + // 获取本月最大天数 + let month_last_day = new Date(year, month, 0).getDate(); + // 获取今年12月最大天数 + let year_last_day = new Date(year, 12, 0).getDate(); + // 今日开始时间 + res.todayStart = new Date(`${year}/${month}/${day}`).getTime() - timeDif; + // 今日12点时间 + res.today12End = new Date(`${year}/${month}/${day}`).getTime() + (12 * 60 * 60 * 1000 - 1) - timeDif; + // 今日结束时间 + res.todayEnd = new Date(`${year}/${month}/${day}`).getTime() + (oneDayTime - 1) - timeDif; + // 本月开始时间 + res.monthStart = new Date(`${year}/${month}/1`).getTime() - timeDif; + // 本月结束时间 + res.monthEnd = new Date(`${year}/${month}/${month_last_day}`).getTime() + (oneDayTime - 1) - timeDif; + // 本年开始时间 + res.yearStart = new Date(`${year}/1/1`).getTime() - timeDif; + // 本年结束时间 + res.yearEnd = new Date(`${year}/12/${year_last_day}`).getTime() + (oneDayTime - 1) - timeDif; + // 当前小时开始时间 + res.hourStart = new Date(`${year}/${month}/${day} ${hour}:00:00`).getTime() - timeDif; + // 当前小时结束时间 + res.hourEnd = new Date(`${year}/${month}/${day} ${hour}:59:59`).getTime() - timeDif; + // 计算上月开始----------------------------------------------------------- + let year_last = year; + let month_last = month - 1; + if (month_last === 0) { + month_last = 12; + year_last = year - 1; + } + let month_last_day_last = new Date(year_last, month_last, 0).getDate(); + // 上月开始时间 + res.lastMonthStart = new Date(`${year_last}/${month_last}/1`).getTime() - timeDif; + // 上月结束时间 + res.lastMonthEnd = new Date(`${year_last}/${month_last}/${month_last_day_last}`).getTime() + (oneDayTime - 1) - timeDif; + // 计算上月结束----------------------------------------------------------- + + // 昨天开始时间 + res.yesterdayStart = res.todayStart - 1000 * 3600 * 24; + // 昨天上午结束时间 + res.yesterday12End = res.today12End - 1000 * 3600 * 24; + // 昨天结束时间 + res.yesterdayEnd = res.todayEnd - 1000 * 3600 * 24; + + let weekObj = util.getWeekOffsetStartAndEnd(0, nowDate, targetTimezone); + // 本周开始时间 + res.weekStart = weekObj.startTime; + // 本周结束时间 + res.weekEnd = weekObj.endTime; + // 本年1-12月的起止时间 + res.months = []; + res.months[0] = { + startTime: res.monthStart, + endTime: res.monthEnd, + startTimeStr: util.timeFormat(res.monthStart, "yyyy-MM-dd hh:mm:ss", targetTimezone), + endTimeStr: util.timeFormat(res.monthEnd, "yyyy-MM-dd hh:mm:ss", targetTimezone), + monthStart: res.monthStart, // 兼容旧版 + monthEnd: res.monthEnd, // 兼容旧版 + }; + for (let i = 1; i <= 12; i++) { + // 获取此月最大天数 + let month_last_day = new Date(year, i, 0).getDate(); + // 此月开始时间 + let startTime = new Date(`${year}/${i}/1`).getTime() - timeDif; + // 此月结束时间 + let endTime = new Date(`${year}/${i}/${month_last_day}`).getTime() + (oneDayTime - 1) - timeDif; + res.months[i] = { + startTime, + endTime, + startTimeStr: util.timeFormat(startTime, "yyyy-MM-dd hh:mm:ss", targetTimezone), + endTimeStr: util.timeFormat(endTime, "yyyy-MM-dd hh:mm:ss", targetTimezone), + monthStart: startTime, // 兼容旧版 + monthEnd: endTime, // 兼容旧版 + }; + } + // 本月1号到最后一天每天的起止时间 + res.days = []; + res.days[0] = { + startTime: res.todayStart, + endTime: res.todayEnd, + startTimeStr: util.timeFormat(res.todayStart, "yyyy-MM-dd hh:mm:ss", targetTimezone), + endTimeStr: util.timeFormat(res.todayEnd, "yyyy-MM-dd hh:mm:ss", targetTimezone) + }; + for (let i = 1; i <= month_last_day; i++) { + let nowTime = res.monthStart + ((i - 1) * oneDayTime); + let { startTime, endTime } = util.getDayOffsetStartAndEnd(0, nowTime, targetTimezone); + res.days[i] = { + startTime, + endTime, + startTimeStr: util.timeFormat(startTime, "yyyy-MM-dd hh:mm:ss", targetTimezone), + endTimeStr: util.timeFormat(endTime, "yyyy-MM-dd hh:mm:ss", targetTimezone) + }; + } + for (let key in res) { + if (typeof res[key] === "number" && res[key].toString().length === 13) { + res[`${key}Str`] = util.timeFormat(res[key], "yyyy-MM-dd hh:mm:ss", targetTimezone); + } + } + return res; +}; + +/** + * 获得指定年份和月份后的该月的开始时间和结束时间 + * 返回数据如下:(时间戳形式) + { + startTime 该月开始时间 + endTime 该月结束时间 + } +vk.pubfn.getMonthStartAndEnd({ + year:2021 + month:1 +}); + */ +util.getMonthStartAndEnd = function(obj, targetTimezone) { + targetTimezone = util.getTargetTimezone(targetTimezone); + let res = { + startTime: null, + endTime: null + }; + let { year, month } = obj; + if (year > 0 && month > 0) { + const dif = new Date().getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + let month_last_day = new Date(year, month, 0).getDate(); + // 开始时间 + res.startTime = new Date(`${year}/${month}/1`).getTime() - timeDif; + // 结束时间 + res.endTime = new Date(`${year}/${month}/${month_last_day}`).getTime() + (24 * 60 * 60 * 1000 - 1) - timeDif; + } + return res; +} + +/** + * 获得相对当前时间的偏移 count 小时的起止日期(返回小时的开始和结束时间戳) + * @param {Number} count 默认0(0代表当前小时 -1代表上一个小时 1代表下一个小时以此类推) + * @param {Date || Number} date 指定从哪个时间节点开始计算 + * vk.pubfn.getHourOffsetStartAndEnd(0); + */ +util.getHourOffsetStartAndEnd = function(count = 0, date = new Date(), targetTimezone) { + let nowDate = util.getDateObject(date); + targetTimezone = util.getTargetTimezone(targetTimezone); + let res = {}; + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + // 一天的毫秒数 + let offsetMillisecond = 1000 * 60 * 60; + // 相对于当前日期count个天的日期 + nowDate = new Date(nowDate.getTime() + (offsetMillisecond * 1 * count)); + let dateInfo = util.getDateInfo(nowDate); + // 获得当天的起始时间 + res.startTime = new Date(`${dateInfo.year}/${dateInfo.month}/${dateInfo.day} ${dateInfo.hour}:00:00`).getTime() - timeDif; + // 获得当天的结束时间 + res.endTime = new Date(`${dateInfo.year}/${dateInfo.month}/${dateInfo.day} ${dateInfo.hour}:00:00`).getTime() + (offsetMillisecond - 1) - timeDif; + return res; +} + + +/** + * 获得相对当前时间的偏移 count 天的起止日期(返回日的开始和结束) + * @param {Number} count 默认0(0代表今日 -1代表昨日 1代表明日以此类推) + * @param {Date || Number} date 指定从哪个时间节点开始计算 + * vk.pubfn.getDayOffsetStartAndEnd(0); + */ +util.getDayOffsetStartAndEnd = function(count = 0, date = new Date(), targetTimezone) { + let nowDate = util.getDateObject(date); + targetTimezone = util.getTargetTimezone(targetTimezone); + let res = {}; + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + // 一天的毫秒数 + let offsetMillisecond = 1000 * 60 * 60 * 24; + // 相对于当前日期count个天的日期 + nowDate = new Date(nowDate.getTime() + (offsetMillisecond * 1 * count)); + let dateInfo = util.getDateInfo(nowDate); + // 获得当天的起始时间 + res.startTime = new Date(`${dateInfo.year}/${dateInfo.month}/${dateInfo.day}`).getTime() - timeDif; + // 获得当天的结束时间 + res.endTime = new Date(`${dateInfo.year}/${dateInfo.month}/${dateInfo.day}`).getTime() + (offsetMillisecond - 1) - timeDif; + return res; +} + +/** + * 获得相对当前周count个周的起止日期(返回周的开始和结束) + * @param {Number} count 默认0(0代表本周 -1代表上周 1代表下周以此类推) + * vk.pubfn.getWeekOffsetStartAndEnd(0); + */ +util.getWeekOffsetStartAndEnd = function(count = 0, date = new Date(), targetTimezone) { + let res = {}; + let nowDate = util.getDateObject(date); + targetTimezone = util.getTargetTimezone(targetTimezone); + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + let nowDay = nowDate.getDay() === 0 ? 7 : nowDate.getDay(); + nowDate.setDate(nowDate.getDate() - nowDay + 1 + count * 7); + let dateInfo1 = util.getDateInfo(nowDate); + nowDate.setDate(nowDate.getDate() + 7); + let dateInfo2 = util.getDateInfo(nowDate); + // 开始时间 + res.startTime = new Date(`${dateInfo1.year}/${dateInfo1.month}/${dateInfo1.day}`).getTime() - timeDif; + // 结束时间 + res.endTime = new Date(`${dateInfo2.year}/${dateInfo2.month}/${dateInfo2.day}`).getTime() - 1 - timeDif; + return res; +} + +/** + * 获得相对当前时间的偏移 count 个月的起止日期(月的开始和结束时间戳) + * @param {Number} count 默认0(0代表本月 -1代表上月 1代表下月以此类推) + * @param {Date || Number} date 指定从哪个时间节点开始计算 + * vk.pubfn.getMonthOffsetStartAndEnd(0); + */ +util.getMonthOffsetStartAndEnd = function(count = 0, date = new Date(), targetTimezone) { + let res = {}; + let nowDate = util.getDateObject(date); + targetTimezone = util.getTargetTimezone(targetTimezone); + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + let dateInfo = util.getDateInfo(nowDate); + let month = dateInfo.month + count; + let year = dateInfo.year; + if (month > 12) { + year = year + Math.floor(month / 12); + month = Math.abs(month) % 12; + } else if (month <= 0) { + year = year - 1 - Math.floor(Math.abs(month) / 12); + month = 12 - Math.abs(month) % 12; + } + let month_last_day = new Date(year, month, 0).getDate(); + // 开始时间 + res.startTime = new Date(`${year}/${month}/1`).getTime() - timeDif; + // 结束时间 + res.endTime = new Date(`${year}/${month}/${month_last_day}`).getTime() + (24 * 60 * 60 * 1000 - 1) - timeDif; + return res; +} + + +/** + * 获得相对当前时间的偏移 count 个季度的起止日期(季度的开始和结束时间戳) + * @param {Number} count 默认0(0代表本季度 -1代表上个季度 1代表下个季度以此类推) + * @param {Date || Number} date 指定从哪个时间节点开始计算 + * vk.pubfn.getQuarterOffsetStartAndEnd(0); + */ +util.getQuarterOffsetStartAndEnd = function(count = 0, date = new Date(), targetTimezone) { + let res = {}; + let nowDate = util.getDateObject(date); + nowDate.setMonth(nowDate.getMonth() + count * 3); + targetTimezone = util.getTargetTimezone(targetTimezone); + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + let dateInfo = util.getDateInfo(nowDate); + let month = dateInfo.month; + if ([1, 2, 3].indexOf(month) > -1) { + // 第1季度 + month = 1; + } else if ([4, 5, 6].indexOf(month) > -1) { + // 第2季度 + month = 4; + } else if ([7, 8, 9].indexOf(month) > -1) { + // 第3季度 + month = 7; + } else if ([10, 11, 12].indexOf(month) > -1) { + // 第4季度 + month = 10; + } + nowDate.setMonth(month - 1); // 因为0代表1月,所以这里要减1 + let dateInfo1 = util.getDateInfo(nowDate); + nowDate.setMonth(nowDate.getMonth() + 3); + let dateInfo2 = util.getDateInfo(nowDate); + // 开始时间 + res.startTime = new Date(`${dateInfo1.year}/${dateInfo1.month}/1`).getTime() - timeDif; + // 结束时间 + res.endTime = new Date(`${dateInfo2.year}/${dateInfo2.month}/1`).getTime() - 1 - timeDif; + return res; +} + +/** + * 获得相对当前时间的偏移 count 年的起止日期(年的开始和结束时间戳) + * @param {Number} count 默认0 (0代表今年 -1代表去年 1代表明年以此类推) + * @param {Date || Number} date 指定从哪个时间节点开始计算 + * vk.pubfn.getYearOffsetStartAndEnd(0); + */ +util.getYearOffsetStartAndEnd = function(count = 0, date = new Date(), targetTimezone) { + let res = {}; + let nowDate = util.getDateObject(date); + targetTimezone = util.getTargetTimezone(targetTimezone); + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + let dateInfo = util.getDateInfo(nowDate); + let year = dateInfo.year + count; + // 开始时间 + res.startTime = new Date(`${year}/1/1`).getTime() - timeDif; + // 结束时间 + res.endTime = new Date(`${year}/12/31`).getTime() + (24 * 60 * 60 * 1000 - 1) - timeDif; + return res; +}; + + +/** + * 获得指定时间偏移 year年 month月 day天 hours时 minutes分 seconds秒前或后的时间戳 + * 返回时间戳 +vk.pubfn.getOffsetTime(new Date(), { + year:0, + month:0, + day:0, + hours:0, + minutes:0, + seconds:0, + mode:"after", // after 之后 before 之前 +}); + +vk.pubfn.getOffsetTime(new Date(), { + y:0, + m:0, + d:0, + hh:0, + mm:0, + ss:0, + mode:"after" // after 之后 before 之前 +}); + */ +util.getOffsetTime = function(date = new Date(), obj, targetTimezone) { + let nowDate = util.getDateObject(date); + let dateInfo = util.getDateInfo(nowDate); + + targetTimezone = util.getTargetTimezone(targetTimezone); + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + + let year = obj.year || obj.y || 0; + let month = obj.month || obj.m || 0; + let day = obj.day || obj.d || 0; + let hour = obj.hour || obj.hours || obj.hh || 0; + let minute = obj.minute || obj.minutes || obj.mm || 0; + let second = obj.second || obj.seconds || obj.ss || 0; + let { mode = "after" } = obj; + if (mode == "before") { + year *= -1; + month *= -1; + day *= -1; + hour *= -1; + minute *= -1; + second *= -1; + } + let offsetObj = { + year: dateInfo.year + year, + month: dateInfo.month + month, + day: dateInfo.day + day, + hour: dateInfo.hour + hour, + minute: dateInfo.minute + minute, + second: dateInfo.second + second + }; + nowDate = new Date(offsetObj.year, offsetObj.month - 1, offsetObj.day, offsetObj.hour, offsetObj.minute, offsetObj.second); + return nowDate.getTime() - timeDif; +} + +/** + * 判断是否是闰年 + * @param {Number | Date} year 需要计算的年份或时间,默认使用当前时间的年份 + * vk.pubfn.timeUtil.isLeapYear(year); + */ +util.isLeapYear = function(year) { + if (typeof year === "undefined") { + let { now } = util.getCommonTime(); + year = now.year; + } else if (typeof year === "object") { + let { now } = util.getCommonTime(year); + year = now.year; + } + if (((year % 4) == 0) && ((year % 100) != 0) || ((year % 400) == 0)) { + return true; + } else { + return false; + } +} + + +/** + * 判断是否是清明节 + * @param {Date} date 日期对象 可以指定时间计算节点,默认使用当前时间进行计算 +vk.pubfn.timeUtil.isQingming(new Date()); + */ +util.isQingming = function(data = new Date()) { + let { now } = util.getCommonTime(data); + let { year, month, day } = now; + let key = false; + // 清明节的日期是不固定的,规律是:闰年开始的前2年是4月4日,闰年开始的第3年和第4年是4月5日 + if (util.isLeapYear(year) || util.isLeapYear(year - 1)) { + if (month === 4 && day === 4) { + key = true; + } + } else { + if (month === 4 && day === 5) { + key = true; + } + } + return key; +} + +/** + * 日期对象转换(已弃用,建议不要使用此API) + * @param {Date || Number} date 需要转换的时间 + * @param {Number} type 转换方式 + * type = 0 返回 2020-08-03 12:12:12 + * type = 1 返回 20200803121212 + * type = 2 返回 { YYYY, MM, DD, hh, mm, ss } + */ +util.getFullTime = function(date, type = 0, targetTimezone) { + if (!date) return ""; + targetTimezone = util.getTargetTimezone(targetTimezone); + let nowDate = util.getDateObject(date); + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + const east8time = nowDate.getTime() + timeDif; + nowDate = new Date(east8time); + + let YYYY = nowDate.getFullYear() + ''; + let MM = (nowDate.getMonth() + 1 < 10 ? '0' + (nowDate.getMonth() + 1) : nowDate.getMonth() + 1); + let DD = (nowDate.getDate() < 10 ? '0' + (nowDate.getDate()) : nowDate.getDate()); + let hh = (nowDate.getHours() < 10 ? '0' + (nowDate.getHours()) : nowDate.getHours()); + let mm = (nowDate.getMinutes() < 10 ? '0' + (nowDate.getMinutes()) : nowDate.getMinutes()); + let ss = (nowDate.getSeconds() < 10 ? '0' + (nowDate.getSeconds()) : nowDate.getSeconds()); + if (type === 2) { + return { + YYYY: Number(YYYY), + MM: Number(MM), + DD: Number(DD), + hh: Number(hh), + mm: Number(mm), + ss: Number(ss), + + year: Number(YYYY), + month: Number(MM), + day: Number(DD), + hour: Number(hh), + minute: Number(mm), + second: Number(ss), + }; + } else if (type === 1) { + return YYYY + "" + MM + "" + DD + "" + hh + "" + mm + "" + ss; + } else { + return YYYY + "-" + MM + "-" + DD + " " + hh + ":" + mm + ":" + ss; + } +}; + + +export default util; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/treeUtil.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/treeUtil.js new file mode 100644 index 0000000..1853d13 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/treeUtil.js @@ -0,0 +1,93 @@ + +import deepClone from './deepClone' +var util = {}; +/** + * 将树形结构转成数组结构 + * @param {Array} treeData 数据源 + * @param {Object} treeProps 树结构配置 { id : "menu_id", children : "children" } + * vk.pubfn.treeToArray(treeData); + */ +util.treeToArray = function(treeData, treeProps) { + let newTreeData = deepClone(treeData); + return util.treeToArrayFn(newTreeData, treeProps); +}; +util.treeToArrayFn = function(treeData, treeProps = {}, arr=[], current_parent_id) { + let { id="_id", parent_id="parent_id", children = "children", deleteChildren = true } = treeProps; + for(let i in treeData){ + let item = treeData[i]; + if(current_parent_id) item[parent_id] = current_parent_id; + arr.push(item); + if(item[children] && item[children].length>0){ + arr = util.treeToArrayFn(item[children], treeProps, arr, item[id]); + } + if(deleteChildren){ + delete item[children]; + } + } + return arr; +}; +/** + * 数组结构转树形结构 +let tree = vk.pubfn.arrayToTree(arrayData,{ + id:"code", + parent_id:"parent_code", +}); + */ + +util.arrayToTree = function(originalArrayData,treeProps) { + let arrayData = deepClone(originalArrayData); + let { + id="_id", + parent_id="parent_id", + children = "children", + deleteParentId = false, + need_field + } = treeProps; + let result = []; + let temp = {}; + for (let i = 0; i < arrayData.length; i++) { + temp[arrayData[i][id]] = arrayData[i]; // 以id作为索引存储元素,可以无需遍历直接定位元素 + } + for (let j = 0; j < arrayData.length; j++) { + let currentElement = arrayData[j]; + let newCurrentElement = {}; + if(need_field){ + need_field = uniqueArr(need_field.concat([id,parent_id,children])); + for(let keyName in currentElement){ + if(need_field.indexOf(keyName) === -1){ + delete currentElement[keyName]; + } + } + } + let tempCurrentElementParent = temp[currentElement[parent_id]]; // 临时变量里面的当前元素的父元素 + if (tempCurrentElementParent) { + // 如果存在父元素 + if (!tempCurrentElementParent[children]) { + // 如果父元素没有chindren键 + tempCurrentElementParent[children] = []; // 设上父元素的children键 + } + if(deleteParentId){ + delete currentElement[parent_id]; + } + tempCurrentElementParent[children].push(currentElement); // 给父元素加上当前元素作为子元素 + } else { + // 不存在父元素,意味着当前元素是一级元素 + result.push(currentElement); + } + } + return result; +}; + +// 最简单数组去重法 +function uniqueArr(array) { + let n = []; //一个新的临时数组 + //遍历当前数组 + for (let i = 0; i < array.length; i++) { + //如果当前数组的第i已经保存进了临时数组,那么跳过, + //否则把当前项push到临时数组里面 + if (n.indexOf(array[i]) == -1) n.push(array[i]); + } + return n; +} + +export default util; \ No newline at end of file diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/updateManager.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/updateManager.js new file mode 100644 index 0000000..470e3fe --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/updateManager.js @@ -0,0 +1,61 @@ +var updateManager = {}; +/** + * 本API返回全局唯一的版本更新管理器对象: updateManager,用于管理小程序更新。 + * vk.updateManager.updateReady(); + */ +updateManager.updateReady = function(obj) { + // #ifdef MP + updateManagerByMP(obj); + // #endif +}; + + +export default updateManager; + + +function updateManagerByMP(obj = {}) { + let { + title = "更新提示", + content = "新版本已经准备好,点击更新!", + autoUpdate = true, + showCancel = false, + confirmText = "一键更新" + } = obj; + const updateManager = uni.getUpdateManager(); + + updateManager.onCheckForUpdate(function(res) { + // 请求完新版本信息的回调 + // console.log(res.hasUpdate); + }); + + updateManager.onUpdateReady(function(res) { + uni.showModal({ + title, + content, + showCancel, + confirmText, + success(res) { + if (res.confirm) { + if (typeof obj.success === "function") { + obj.success({ + applyUpdate: updateManager.applyUpdate + }); + } + if (typeof obj.complete === "function") obj.complete(); + if (autoUpdate) { + // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启 + updateManager.applyUpdate(); + } + } + }, + + }); + }); + + updateManager.onUpdateFailed(function(res) { + // 新的版本下载失败 + console.error("onUpdateFailed", res); + if (typeof obj.fail === "function") obj.fail(res); + if (typeof obj.complete === "function") obj.complete(); + }); +} diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.filters.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.filters.js new file mode 100644 index 0000000..1b338ff --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.filters.js @@ -0,0 +1,63 @@ +/** + * vk.filters + * 全局过滤器 + */ +import pubfn from './index.js' +var util = {}; +// 将时间显示成1秒前、1天前 +util.dateDiff = function(starttime, showType) { + return pubfn.dateDiff(starttime, showType); +} +util.dateDiff2 = function(starttime, showType) { + return pubfn.dateDiff2(starttime, showType); +}; +// 计数器1 +util.numStr = function(n) { + return pubfn.numStr(n); +}; + +util.timeStr = function(date) { + return pubfn.timeFormat(date); +}; +/** + * 日期对象转字符串 + * @description 最终转成 2020-08-01 12:12:12 + * @param {Date || Number} date 需要转换的时间 + * date参数支持 + * 支持:时间戳 + * 支持:2020-08 + * 支持:2020-08-24 + * 支持:2020-08-24 12 + * 支持:2020-08-24 12:12 + * 支持:2020-08-24 12:12:12 + */ +util.timeFilter = function(date, fmt) { + return pubfn.timeFormat(date, fmt); +}; +// 金额过滤器 +util.priceFilter = function(n, defaultValue = " - ") { + return pubfn.priceFilter(n, defaultValue); +}; +// 金额过滤器 - 只显示小数点左边 +util.priceLeftFilter = function(n) { + return pubfn.priceLeftFilter(n); +}; +// 金额过滤器 - 只显示小数点右边 +util.priceRightFilter = function(n) { + return pubfn.priceRightFilter(n); +}; +// 百分比过滤器 +util.percentageFilter = function(n, needShowSymbol, defaultValue = " - ") { + return pubfn.percentageFilter(n, needShowSymbol, defaultValue); +}; +// 折扣过滤器 +util.discountFilter = function(n, needShowSymbol, defaultValue = " - ") { + return pubfn.discountFilter(n, needShowSymbol, defaultValue); +}; +// 大小过滤器 sizeFilter(1024,3,["B","KB","MB","GB"]) +util.sizeFilter = function(...obj) { + let res = pubfn.calcSize(...obj); + return res.title; +}; + +export default util; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.h5.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.h5.js new file mode 100644 index 0000000..d77d5b3 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.h5.js @@ -0,0 +1,60 @@ +// #ifdef H5 +/** + * H5专用的一些函数,会涉及到window等H5专用的内置对象。 + */ +var h5 = {}; + +// 引入 微信公众号 js_sdk 包 +import wx from './weixin-js-sdk' +h5.wx = wx; + +/** + * 获取当前H5所在的环境 + * let env = vk.h5.getEnv(); + */ +h5.getEnv = function() { + let ua = window.navigator.userAgent.toLowerCase(); + if (ua.match(/MicroMessenger/i) == 'micromessenger' && (ua.match(/miniprogram/i) == 'miniprogram')) { + // 微信小程序 + return "mp-weixin"; + } + if (ua.match(/MicroMessenger/i) == 'micromessenger') { + // 微信公众号 + return "h5-weixin"; + } + if (ua.match(/alipay/i) == 'alipay' && ua.match(/miniprogram/i) == 'miniprogram') { + return "mp-alipay"; + } + if (ua.match(/alipay/i) == 'alipay') { + return "h5-alipay"; + } + // 外部 H5 + return "h5"; +}; + +/** + * 获取当前项目根目录访问地址 + * https://www.aaa.com/pages/index/index?a=1&b=1 + * http://192.168.66.66:8080/pages/index/index?a=1&b=1 + * 获取当前H5的url地址的https://www.aaa.com 部分 + * let getRootPath = vk.h5.getRootPath(); + * let getRootPath = vk.h5.getRootPath({ projectName:true }); + */ +h5.getRootPath = function(obj={}) { + let { + projectName: _projectName = false + } = obj; + let wwwPath = window.location.href; + let pathName = window.location.pathname; + let pos = wwwPath.indexOf(pathName); + let localhostPaht = wwwPath.substring(0, pos); + let projectName = pathName.substring(0, pathName.substr(1).indexOf('/') + 1); + let rootPath = localhostPaht; + if (_projectName) { + rootPath = localhostPaht + projectName; + } + return rootPath; +}; + +export default h5; +// #endif diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.importObject.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.importObject.js new file mode 100644 index 0000000..a0fb08b --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.importObject.js @@ -0,0 +1,59 @@ +/** + * 导出云对象实例 + * @param {String} name 云对象路径,如:client/pub + * @example const pubObject = uni.vk.importObject('client/pub'); // 导入云对象 + * 注意,只能在声明 async 的函数内使用,如: +async test(){ + let res = await pubObject.getList({ + title: "请求中", + data: { + a: 1, + b: "2" + } + }); +} + */ +var importObject = function(name, importObjectOptions = {}) { + const newObj = new Proxy(importObject, { + get: function(target, key, receiver) { + /** + * 导出云对象内的某个方法 + * @param {Object} data 请求参数,如 { a:1, b:"2" } 云对象内可通过 let { a, b } = data; 获取参数 + * @param {String} title 遮罩层提示语,为空或不传则代表不显示遮罩层。 + * @param {Boolean} needAlert 为true代表请求错误时,会有弹窗提示。默认为true + * @param {Object} loading 与title二选一,格式为 { name: "loading", that: that } name是变量名,that是数据源,当发起请求时,自动that[name] = true; 请求结束后,自动that[name] = false; + */ + return async function(options) { + // 如果importObjectOptions中指定了easy为true,代表options的值就是请求参数 + if (importObjectOptions.easy) { + options = { + data: options + } + } + // 如果importObjectOptions中指定了data,代表有默认请求参数,需要加到请求参数中 + if (importObjectOptions.data) { + if (typeof importObjectOptions.data === "function") { + options.data = Object.assign({}, importObjectOptions.data(), options.data) + } else { + options.data = Object.assign({}, importObjectOptions.data, options.data) + } + } + return uni.vk.callFunction({ + ...importObjectOptions, + ...options, + url: `${name}.${key}` + }); + } + }, + // set: function(target, key, value, receiver) { + // console.log("set"); + // console.log("target",target); + // console.log("key",key); + // console.log("value",value); + // console.log("receiver", receiver); + // }, + }); + return newObj; +}; + +export default importObject; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.localStorage.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.localStorage.js new file mode 100644 index 0000000..63dca97 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.localStorage.js @@ -0,0 +1,131 @@ +/** + * vk依赖扩展 - localStorage 本地缓存 + * pub - 公共的可随时删除的缓存 + * kh - 跟登录账号有关联的缓存 + * sys - 系统级缓存 - 一般不删除 + * + * 储存缓存 + * vk.setStorageSync(key, data); + * 获取缓存 + * vk.getStorageSync(key); + */ +var localStorage = {}; +/** + * 将 data 存储在本地缓存中指定的 key 中,会覆盖掉原来该 key 对应的内容,这是一个同步接口。 + * @param {String} key 本地缓存中的指定的 key + * @param {Any} data 需要存储的内容,只支持原生类型、及能够通过 JSON.stringify 序列化的对象 + */ +localStorage.setStorageSync = function(key, data) { + uni.setStorageSync(key, data); + watchLocalStorage({ type: "set", key, data }); +}; + +/** + * 从本地缓存中异步获取指定 key 对应的内容。 + * @param {String} key 本地缓存中的指定的 key + */ +localStorage.getStorageSync = function(key) { + let data = uni.getStorageSync(key); + // get 没有必要监听 + // watchLocalStorage({ type:"get", key, data }); + return data; +}; + +/** + * 同步获取当前 storage 的相关信息。 + */ +localStorage.getStorageInfoSync = function() { + let info = uni.getStorageInfoSync(); + let sizeInfo = calcSize(Number(info.currentSize), 1024, 3, ["KB", "MB", "GB"]); + info.sizeInfo = sizeInfo; + return info; +}; + +/** + * 从本地缓存中同步移除指定 key。 + * @param {String} key 本地缓存中的指定的 key + */ +localStorage.removeStorageSync = function(key) { + uni.removeStorageSync(key); + watchLocalStorage({ type: "remove", key }); +}; +/** + * 从本地缓存中异步移除指定 key。 + */ +localStorage.removeStorage = function(obj) { + uni.removeStorage({ + key: obj.key, + success: (res) => { + watchLocalStorage({ type: "remove", key: obj.key }); + if (obj.success) obj.success(res); + }, + fail: obj.fail, + complete: obj.complete + }); +}; + +/** + * 同步清理本地数据缓存。若key有值,则清除键值为指定字符串开头的缓存 + * @param {String} key 本地缓存中的指定的 key + * vk.clearStorageSync(); + */ +localStorage.clearStorageSync = function(key) { + if (key) { + let { keys } = uni.getStorageInfoSync(); + if (keys) { + keys.map((keyName) => { + if (keyName.indexOf(key) == 0) { + localStorage.removeStorage({ + key: keyName + }); + } + }); + } + } else { + uni.clearStorage(); + watchLocalStorage({ type: "clear" }); + } +}; + +export default localStorage; + + + +/** + * 单位进制换算 + * length 换算前大小 + * ary 进制,如KB-MB-GB,进制1024 + * precision 数值精度 + * arr 进制的数组,如["B","KB","MB","GB"] + * calcSize(length,1024,3,["B","KB","MB","GB"]); + */ +function calcSize(length = 0, ary, precision, arr) { + var size = parseFloat(length); + var mySize = 0; + var type = ""; + if (size < ary || arr.length <= 1) { + type = arr[0]; + mySize = parseFloat(size.toFixed(precision)); + } else { + for (var i = 1; i < arr.length; i++) { + var g = arr[i]; + size = size / ary; + if (size < ary) { + type = g; + mySize = parseFloat(size.toFixed(precision)); + break; + } + } + } + return { + size: mySize, + type: type, + title: mySize + " " + type + } +}; + +function watchLocalStorage(obj) { + if (typeof localStorage.watch === "function") { + localStorage.watch(obj); + } +} \ No newline at end of file diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.navigate.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.navigate.js new file mode 100644 index 0000000..f4cb84b --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.navigate.js @@ -0,0 +1,462 @@ +/** + * 函数 - 页面导航 + */ +// #ifndef VUE3 +var config; +try { + config = require('@/app.config.js'); + if (typeof config.default === "object") { + config = config.default; + } +} catch (e) { + config = {}; +} +// #endif + +// #ifdef VUE3 +import config from '@/app.config.js' +// #endif + + +var util = {}; +var lastNavigate = { + url: "", + time: 0 +}; +/** + * 保留当前页面,跳转到应用内的某个页面,使用vk.navigateBack可以返回到原页面。 + * vk.navigateTo(url); + */ +util.navigateTo = function(obj) { + let vk = uni.vk; + if (typeof obj == "string") { + let url = obj; + obj = { + url: url + }; + } else if (typeof obj == "undefined") { + obj = {}; + } + if (!obj.url) { + vk.toast("url不能为空!"); + return false; + } + let time = Date.now(); + if (lastNavigate.url === obj.url && (time - lastNavigate.time) < 200) { + return false; + } + lastNavigate = { url: obj.url, time }; + util.checkNeedLogin({ + url: obj.url, + success: function(res) { + if (res.needLogin) { + obj.url = vk.pubfn.getPageFullPath(obj.url); + vk.navigate.setOriginalPage(obj); + obj.url = config.login.url; + // login拦截器开始----------------------------------------------------------- + let { interceptor = {} } = config; + if (typeof interceptor.login === "function") { + let key = interceptor.login({ + vk, + params: obj, + res: { + ...res, + code: 30204, + msg: "本地token校验未通过" + } + }); + if (typeof key === "undefined" || key !== true) return false; + } + // login拦截器结束----------------------------------------------------------- + } else { + vk.navigate.setOriginalPage(null); + } + util._navigateTo(obj); + } + }); +}; +util._navigateTo = function(obj) { + let { interceptor = {} } = config; + if (typeof interceptor.navigateTo === "function") { + let vk = uni.vk; + obj.pagePath = vk.pubfn.getPageFullPath(obj.url); + let key = interceptor.navigateTo({ + ...obj, + vk + }); + if (typeof key == "boolean" && key === false) return false; + } + let { + url, + animationType = "pop-in", + animationDuration = 300, + events, + mode = "navigateTo" + } = obj; + // 此处写法仅为支持vue3,vue3不支持uni[apiName]的形式调用 + let navigateFn; + if (mode === "navigateTo") { + navigateFn = uni.navigateTo; + } else if (mode === "redirectTo") { + navigateFn = uni.redirectTo; + } else if (mode === "reLaunch") { + navigateFn = uni.reLaunch; + } else if (mode === "switchTab") { + navigateFn = uni.switchTab; + } else { + navigateFn = uni.navigateTo; + } + // 此处写法仅为支持vue3,vue3不支持uni[apiName]的形式调用 + navigateFn({ + url: url, + animationType: animationType, + animationDuration: animationDuration, + events: events, // 参考 https://uniapp.dcloud.io/api/router?id=navigateto + success: function(res) { + if (typeof obj.success == "function") obj.success(res); + }, + fail: function(err) { + if (err.errMsg.indexOf("not found") > -1) { + let vk = uni.vk; + let errUrl = vk.pubfn.getPageFullPath(url); + vk.toast(`页面 ${errUrl} 不存在`, "none"); + console.error(err); + return false; + } + uni.switchTab({ + url: url, + success: obj.success, + fail: function() { + uni.redirectTo({ + url: url, + success: obj.success, + fail: function(err) { + console.error(err); + if (typeof obj.fail == "function") obj.fail(err); + } + }); + } + }); + }, + complete: function(res) { + if (typeof obj.complete == "function") obj.complete(res); + } + }); +}; + +/** + * 关闭当前页面,跳转到应用内的某个页面。 + * vk.redirectTo(url); + */ +util.redirectTo = function(obj) { + obj = util.paramsInit(obj); + obj.mode = "redirectTo"; + util.navigateTo(obj); +}; + +/** + * 关闭所有页面,打开到应用内的某个页面。 + * vk.reLaunch(url); + */ +util.reLaunch = function(obj) { + obj = util.paramsInit(obj); + obj.mode = "reLaunch"; + util.navigateTo(obj); +}; + +/** + * 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。 + * vk.switchTab(url); + */ +util.switchTab = function(obj) { + obj = util.paramsInit(obj); + obj.mode = "switchTab"; + util.navigateTo(obj); +}; +/** + * 关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层。 + * vk.navigateBack(); + */ +util.navigateBack = function(obj) { + let vk = uni.vk; + if (typeof obj == "number") { + let delta = obj; + obj = { + delta: delta + }; + } else if (typeof obj == "undefined") { + obj = {}; + } + let { + delta = 1, + animationType = "pop-out", + animationDuration = 300 + } = obj; + uni.navigateBack({ + delta: delta, + animationType: animationType, + animationDuration: animationDuration, + success: function() { + if (typeof obj.success == "function") obj.success(); + }, + fail: function(res) { + console.error(res); + if (typeof obj.fail == "function") obj.fail(); + }, + complete: function() { + if (typeof obj.complete == "function") obj.complete(); + } + }); +}; +/** + * 跳转到登录前的页面 + * vk.navigate.originalTo(); + */ +util.originalTo = function() { + let vk = uni.vk; + let originalPage = vk.navigate.getOriginalPage(); + vk.navigate.setOriginalPage(null); + util.redirectTo(originalPage); +}; + +/** + * 获取登录前的页面 + * vk.navigate.getOriginalPage(); + */ +util.getOriginalPage = function() { + if (typeof uni.vk.getVuex === "function") { + // 有安装vuex则使用vuex + return uni.vk.getVuex('$app.originalPage'); + } else { + // 未安装则使用本地缓存 + return uni.vk.getStorageSync('vk.navigate.originalPage'); + } +}; + +/** + * 设置登录前的页面 + * vk.navigate.setOriginalPage(originalPage); + */ +util.setOriginalPage = function(originalPage) { + uni.vk.navigate.originalPage = originalPage; // 兼容老版本 + if (typeof uni.vk.getVuex === "function") { + // 有安装vuex则使用vuex + return uni.vk.setVuex('$app.originalPage', originalPage); + } else { + // 未安装则使用本地缓存 + return uni.vk.setStorageSync('vk.navigate.originalPage', originalPage); + } +}; + + +/** + * 跳转到首页 + * vk.navigateToHome(); + */ +util.navigateToHome = function(obj = {}) { + let vk = uni.vk; + let { + mode = "reLaunch" + } = obj; + vk[mode](config.index.url); +}; + +/** + * 跳转到登录页 + * vk.navigateToLogin(); + */ +util.navigateToLogin = function(obj = {}) { + let vk = uni.vk; + let { + mode = "reLaunch" + } = obj; + vk[mode](config.login.url); +}; + +/** + * 检测是否满足条件(内部方法) + util.checkWildcardTest({ + url:url, + pagesRule:config.checkTokenPages, + success:function(res){ + if(res.success){ + + } + } + }) + */ +util.checkWildcardTest = function(obj) { + let vk = uni.vk; + let { + url, + pagesRule + } = obj; + // ../ 转成绝对路径 + url = vk.pubfn.getPageFullPath(url); + let key = false; + if (vk.pubfn.isNotNull(pagesRule)) { + let { mode = 0, list = [] } = pagesRule; + if (mode > 0) { + let regExpKey = false; + let path = util.getPagePath(url); + for (let i = 0; i < list.length; i++) { + let pageRegExp = list[i]; + regExpKey = vk.pubfn.wildcardTest(path, pageRegExp); + if (regExpKey) { + break; + } + } + if (mode === 1 && regExpKey) { + key = true; + } else if (mode === 2 && !regExpKey) { + key = true; + } + } + } + return { + url, + key + }; +}; + + +/** + * 检测是否需要登录(内部方法) + util.checkNeedLogin({ + url:url, + success:function(res){ + if(res.needLogin){ + + } + } + }) + */ +util.checkNeedLogin = function(obj) { + let vk = uni.vk; + let { url, success } = obj; + let needLogin = false; // 用户是否需要重新登录 + let pageNeedLogin = false; // 该页面是否需要登录才能访问 + let pagesRule = config.checkTokenPages; + if (pagesRule) { + let res = util.checkWildcardTest({ + url, + pagesRule + }); + pageNeedLogin = res.key; + if (pageNeedLogin) { + // 本地判断token有效期(联网会浪费性能) + if (!vk.checkToken()) { + needLogin = true; + } + } + } + success({ + url, + needLogin, + pageNeedLogin + }); +}; + + +// 获取?前面的地址 +util.getPagePath = function(url) { + let pathIndex = url.indexOf("?"); + let path = url; + if (pathIndex > -1) { + path = path.substring(0, pathIndex); + } + return path; +}; + +util.paramsInit = function(obj) { + let vk = uni.vk; + if (typeof obj == "string") { + let url = obj; + obj = { + url: url + }; + } else if (typeof obj == "undefined") { + obj = {}; + } + if (!obj.url) { + vk.toast("url不能为空!"); + return false; + } + return obj; +} + + + +/** + * 跳转到小程序 + vk.navigateToMiniProgram({ + appId: 'appId', + path: 'pages/index/index', + extraData:{ + //发送数据携带的参数 + }, + success(res) { + // 打开成功 + + } + }) + */ +util.navigateToMiniProgram = function(obj) { + let vk = uni.vk; + // #ifdef H5 + vk.toast("不支持打开小程序", "none"); + // #endif + + // #ifndef H5 + uni.navigateToMiniProgram(obj); + // #endif +}; + + +/** + * 检测是否可以分享(内部方法) + util.checkAllowShare({ + url:url, + }); + */ +util.checkAllowShare = function(obj) { + let vk = uni.vk; + let { url, success } = obj; + let pagesRule = config.checkSharePages || {}; + if (pagesRule && pagesRule.mode > 0) { + let res = util.checkWildcardTest({ + url, + pagesRule + }); + // #ifdef MP + let menus = pagesRule.menus || ['shareAppMessage', 'shareTimeline']; + if (res.key) { + //console.log("允许分享"); + uni.showShareMenu({ + withShareTicket: false, + menus + }); + } else { + //console.log("禁止分享"); + uni.hideShareMenu({ + menus + }) + } + // #endif + } +}; + +util.$emit = function(...obj) { + return uni.$emit(...obj); +}; +util.$on = function(...obj) { + return uni.$on(...obj); +}; +util.$once = function(...obj) { + return uni.$once(...obj); +}; +util.$off = function(...obj) { + return uni.$off(...obj); +}; + +export default util; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.request.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.request.js new file mode 100644 index 0000000..ee3e9ca --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.request.js @@ -0,0 +1,434 @@ +var requestUtil = {}; + + +requestUtil.config = { + // 请求配置 + request: { + // 公共请求参数(每次请求都会带上的参数) + dataParam: {} + }, + requestGlobalParamKeyName: "vk_url_request_global_param", + debug: process.env.NODE_ENV !== "production", + // 日志风格 + logger: { + colorArr: [ + "#0095ff", + "#67C23A" + ] + }, +}; +var counterNum = 0; +/** + * request 请求库 + * 注意: 该请求库目前主要是框架自身使用,且近期变动频率较高,目前请勿使用在你自己的业务中。 + * @param {String} url 服务器接口地址 + * @param {Object/String/ArrayBuffer} data 请求的参数 App(自定义组件编译模式)不支持ArrayBuffer类型 + * @param {Object} header 设置请求的 header,header 中不能设置 Referer。 App、H5端会自动带上cookie,且H5端不可手动修改 + * @param {String} method 默认 POST 可选 GET + * @param {Number} timeout 超时时间,单位 ms 默认3000(30秒) + * @param {String} dataType 默认json 如果设为 json,会尝试对返回的数据做一次 JSON.parse + * @param {String} responseType 默认 text 设置响应的数据类型。合法值:text、arraybuffer App和支付宝小程序不支持 + * @param {Boolean} sslVerify 默认 true 是否需要验证ssl证书 仅App安卓端支持(HBuilderX 2.3.3+) 仅App安卓端支持(HBuilderX 2.3.3+) + * @param {Boolean} withCredentials 默认 false 跨域请求时是否携带凭证(cookies) 仅H5支持(HBuilderX 2.6.15+) + * @param {Boolean} firstIpv4 默认 false DNS解析时优先使用ipv4 仅 App-Android 支持 (HBuilderX 2.8.0+) + * @param {String} success 成功回调 + * @param {String} fail 失败回调 + * @param {String} complete 完成回调 + * 以下为特殊参数 + * @param {String} errorCodeName 服务器返回的错误码的字段名,若不为空,则会对返回结果进行判断 + * @param {String} errorMsgName 服务器返回的错误码的字符串含义,若不为空,且errorCodeName对应的值不为0,则会alert弹窗 + * @param {Boolean} needAlert 服务器返回的错误时,是否需要alert弹出提示 + * + * 调用示例 +vk.request({ + url: `https://www.xxx.com/api/xxxx`, + method:"POST", + header:{ + "content-type": "application/json; charset=utf-8", + }, + data:{ + + }, + success: function(data){ + + }, + fail: function(err){ + + } +}); + */ + +requestUtil.request = function(obj = {}) { + let vk = uni.vk; + // 去除值为 undefined 的参数 + if (typeof obj.data === "object") { + obj.data = vk.pubfn.copyObject(obj.data); + } + // 注入自定义全局参数开始----------------------------------------------------------- + let config = requestUtil.config; + let globalParam = uni.getStorageSync(config.requestGlobalParamKeyName) || {}; + // 根据正则规格自动匹配全局请求参数 + for (let i in globalParam) { + let customDate = globalParam[i]; + if (customDate.regExp) { + if (typeof customDate.regExp === "object") { + // 数组形式 + for (let i = 0; i < customDate.regExp.length; i++) { + let regExp = new RegExp(customDate.regExp[i]); + if (regExp.test(obj.url)) { + obj.data = Object.assign(customDate.data, obj.data); + break; + } + } + } else { + // 字符串形式 + let regExp = new RegExp(customDate.regExp); + if (regExp.test(obj.url)) { + obj.data = Object.assign(customDate.data, obj.data); + } + } + } + } + // 根据指定globalParamName匹配全局请求参数 + let customDate = requestUtil.getRequestGlobalParam(obj.globalParamName); + if (customDate && JSON.stringify(customDate) !== "{}") { + if (customDate.regExp) { + obj.data = Object.assign(customDate.data, obj.data); // 新版本 + } else { + obj.data = Object.assign(customDate, obj.data); // 兼容旧版本 + } + } + // 注入自定义全局参数结束----------------------------------------------------------- + + if (!obj.method) obj.method = "POST"; // 默认POST请求 + if (typeof obj.dataType === "undefined") obj.dataType = "json"; + if (obj.dataType == "default" || obj.dataType === "") delete obj.dataType; + if (typeof obj.header === "undefined" && typeof obj.headers !== "undefined") { + obj.header = obj.headers; + } + + // 自动注入token到请求头开始----------------------------------------------------------- + // 注意:自2.15.1开始,需要手动指定uniIdToken: true 才会自动添加token到请求头里 + if (typeof vk.getToken === "function" && obj.uniIdToken) { + let uni_id_token; + if (obj.uniIdToken === true) { + uni_id_token = vk.getToken(); + } else if (typeof obj.uniIdToken === "boolean") { + uni_id_token = obj.uniIdToken; + } + if (uni_id_token) { + if (!obj.header) obj.header = {}; + obj.header["uni-id-token"] = uni_id_token; + } + } + // 自动注入token到请求头结束----------------------------------------------------------- + let interceptor = obj.interceptor; + delete obj.interceptor; + if (interceptor && typeof interceptor.invoke === "function") { + let interceptorRes = interceptor.invoke(obj); + if (interceptorRes === false) { + return; + } + } + if (typeof obj.timeout === "undefined") obj.timeout = 30000; // 超时时间,单位 ms(默认30秒) + let Logger = {}; + if (config.debug) { + Logger.params = (typeof obj.data == "object") ? vk.pubfn.copyObject(obj.data) : obj.data; + Logger.startTime = new Date().getTime(); + let url = obj.url; + let path = obj.url.split("?")[0]; + if (path.indexOf("://") > -1) { + path = path.substring(path.indexOf("://") + 3); + Logger.domainName = path.substring(0, path.indexOf("/")); + } else { + Logger.domainName = ""; + } + Logger.action = path.substring(path.indexOf("/") + 1); + Logger.url = url; + } + if (obj.title) vk.showLoading(obj.title); + if (obj.loading) vk.setLoading(true, obj.loading); + let promiseAction = new Promise(function(resolve, reject) { + uni.request({ + ...obj, + success: (res) => { + if (interceptor && typeof interceptor.success === "function") { + let interceptorRes = interceptor.success(res); + if (interceptorRes === false) { + return; + } + } + requestSuccess({ + res, + params: obj, + Logger, + resolve, + reject + }); + }, + fail: (res) => { + if (interceptor && typeof interceptor.fail === "function") { + let interceptorRes = interceptor.fail(res); + if (interceptorRes === false) { + return; + } + } + requestFail({ + res, + params: obj, + Logger, + reject + }); + }, + complete: (res) => { + if (interceptor && typeof interceptor.complete === "function") { + let interceptorRes = interceptor.complete(res); + if (interceptorRes === false) { + return; + } + } + requestComplete({ + res, + params: obj, + Logger + }); + } + }); + }); + promiseAction.catch(error => {}); + return promiseAction; +} +// 请求成功回调 +function requestSuccess(obj = {}) { + let vk = uni.vk; + let config = requestUtil.config; + let { + res = {}, + params, + Logger, + resolve, + reject + } = obj; + let { + title, + needOriginalRes, + dataType, + errorCodeName, + errorMsgName, + success, + loading + } = params; + let data = res.data || {}; + if (vk.pubfn.isNotNullAll(errorCodeName, data[errorCodeName])) { + data.code = data[errorCodeName]; + delete data[errorCodeName]; + } + if (vk.pubfn.isNotNullAll(errorMsgName, data[errorMsgName])) { + data.msg = data[errorMsgName]; + if (typeof data[errorMsgName] === "string") { + delete data[errorMsgName]; + } + } + if (config.debug) Logger.result = (typeof data == "object") ? vk.pubfn.copyObject(data) : data; + if ([1301, 1302, 30201, 30202, 30203, 30204].indexOf(data.code) > -1 && data.msg.indexOf("token") > -1) { + // 执行 login 拦截器函数(跳转到页面页面) + let { interceptor = {} } = vk.callFunctionUtil; + if (typeof interceptor.login === "function") { + interceptor.login({ + res: data, + params, + vk + }); + } + reject(data); + } else if (res.statusCode >= 400 || data.code) { + requestFail({ + res: data, + params, + Logger, + reject + }); + } else { + if (title) vk.hideLoading(); + if (loading) vk.setLoading(false, loading); + if (needOriginalRes) data.originalRes = vk.pubfn.copyObject(res); + if (data.vk_uni_token) vk.callFunctionUtil.saveToken(data.vk_uni_token); + if (data.userInfo && data.needUpdateUserInfo) vk.callFunctionUtil.updateUserInfo(data); + if (typeof success === "function") success(data); + if (typeof resolve === "function") resolve(data); + } +} + +// 请求失败回调 +function requestFail(obj = {}) { + let vk = uni.vk; + let config = requestUtil.config; + let { + res = {}, + params, + Logger, + reject + } = obj; + let { + title, + needAlert, + fail, + loading + } = params; + if (typeof needAlert === "undefined") { + needAlert = (typeof fail === "function") ? false : true; + } + + let errMsg = ""; + let sysErr = false; + if (typeof res.code !== "undefined") { + errMsg = res.msg; + } else { + sysErr = true; + errMsg = JSON.stringify(res); + } + if (errMsg.indexOf("fail timeout") > -1) { + sysErr = true; + errMsg = "请求超时,请重试!"; + } + if (config.debug) Logger.error = res; + if (title) vk.hideLoading(); + if (loading) vk.setLoading(false, loading); + let runKey = true; + // 自定义拦截器开始----------------------------------------------------------- + let { interceptor = {} } = vk.callFunctionUtil.getConfig(); + if (interceptor.request && typeof interceptor.request.fail == "function") { + runKey = interceptor.request.fail({ + vk, + res: res, + params: params + }); + if (runKey === undefined) runKey = true; + } + // 自定义拦截器结束----------------------------------------------------------- + if (runKey) { + if (needAlert && vk.pubfn.isNotNull(errMsg)) { + if (sysErr) { + vk.toast("网络开小差了!", "none"); + } else { + vk.alert(errMsg); + } + } + if (typeof fail === "function") fail(res); + if (typeof reject === "function") reject(res); + } + +} + +// 请求完成回调 +function requestComplete(obj = {}) { + let vk = uni.vk; + let config = requestUtil.config; + let { + res = {}, + params, + Logger + } = obj; + let { + title, + needOriginalRes, + complete + } = params; + if (config.debug) { + Logger.endTime = new Date().getTime(); + Logger.runTime = (Logger.endTime - Logger.startTime); + let colorArr = config.logger.colorArr; + let colorStr = colorArr[counterNum % colorArr.length]; + counterNum++; + console.log("%c--------【开始】【服务器请求】【" + Logger.action + "】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;'); + console.log("【请求地址】: ", Logger.url); + console.log("【请求参数】: ", Logger.params); + console.log("【返回数据】: ", Logger.result); + console.log("【请求状态】: ", res.statusCode, "【http状态码】"); + console.log("【总体耗时】: ", Logger.runTime, "毫秒【含页面渲染】"); + console.log("【请求时间】: ", vk.pubfn.timeFormat(Logger.startTime, "yyyy-MM-dd hh:mm:ss")); + if (Logger.error) { + let errorLog = console.warn || console.error; + if (Logger.error.err && Logger.error.err.stack) { + console.error("【Error】: ", Logger.error); + console.error("【Stack】: ", Logger.error.err.stack); + } else { + errorLog("【Error】: ", Logger.error); + } + } + console.log("%c--------【结束】【服务器请求】【" + Logger.action + "】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;'); + } + let data = res.data; + if (needOriginalRes) data.originalRes = vk.pubfn.copyObject(res); + if (typeof complete === "function") complete(data); +} + +/** + * 修改请求配置中的公共请求参数 + * 若把shop-manage改成*则代表全局 + vk.requestUtil.updateRequestGlobalParam({ + "shop-manage":{ + regExp:"^xxx/kh/", + data:{ + shop_id : shop_id + } + } + }); + 对应的request中增加参数globalParamName:"shop-manage" + vk.request({ + url: 'xxx/xxxxxx', + title: '请求中...', + globalParamName:"shop-manage",// 如果设置了正则规则,则不需要此参数 + data: {}, + success(data) { + } + }); + */ +requestUtil.updateRequestGlobalParam = (data = {}, setKey) => { + let vk = uni.vk; + let config = requestUtil.config; + if (setKey) { + // 覆盖对象 + config.request.dataParam = data; + } else { + // 覆盖参数(有就覆盖,没有则新增) + config.request.dataParam = Object.assign(config.request.dataParam, data); + } + vk.setStorageSync(config.requestGlobalParamKeyName, config.request.dataParam); +} + +/** + * 获取请求配置中的公共请求参数 + vk.requestUtil.getRequestGlobalParam(); + */ +requestUtil.getRequestGlobalParam = (globalParamName = "*") => { + let vk = uni.vk; + let config = requestUtil.config; + let data = config.request.dataParam; + if (!data || JSON.stringify(data) === "{}") { + data = uni.getStorageSync(config.requestGlobalParamKeyName) || {}; + config.request.dataParam = data; + } + let param = data[globalParamName] || {}; + return JSON.parse(JSON.stringify(param)); +} + +/** + * 删除请求配置中的公共请求参数 + * globalParamName 不传代表删除所有 + vk.requestUtil.deleteRequestGlobalParam(globalParamName); + */ +requestUtil.deleteRequestGlobalParam = (globalParamName) => { + let vk = uni.vk; + let config = requestUtil.config; + let globalParam = uni.getStorageSync(config.requestGlobalParamKeyName) || {}; + if (globalParamName) { + delete globalParam[globalParamName]; + } else { + globalParam = {}; + } + config.request.dataParam = globalParam; + vk.setStorageSync(config.requestGlobalParamKeyName, globalParam); +} + +export default requestUtil; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.sessionStorage.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.sessionStorage.js new file mode 100644 index 0000000..fd29637 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.sessionStorage.js @@ -0,0 +1,146 @@ +/** + * vk依赖扩展 - sessionStorage 本地会话缓存(仅H5可用) + * sessionStorage 属性允许你访问一个,对应当前源的 session Storage 对象。 + * 它与 localStorage 相似,不同之处在于 localStorage 里面存储的数据没有过期时间设置 + * 而存储在 sessionStorage 里面的数据在页面会话结束时会被清除。 + * pub - 公共的可随时删除的缓存 + * kh - 跟登录账号有关联的缓存 + * sys - 系统级缓存 - 一般不删除 + * + * 储存缓存 + * vk.setSessionStorageSync(key, data); + * 获取缓存 + * vk.getSessionStorageSync(key); + */ +var storage = {}; +/** + * 将 data 存储在本地缓存中指定的 key 中,会覆盖掉原来该 key 对应的内容,这是一个同步接口。 + * @param {String} key 本地缓存中的指定的 key + * @param {Any} data 需要存储的内容,只支持原生类型、及能够通过 JSON.stringify 序列化的对象 + * vk.setSessionStorageSync(key, data); + */ +storage.setSessionStorageSync = function(key, data = "") { + // #ifdef H5 + let type = typeof data; + let value = { + type: typeof data, + data: data + }; + sessionStorage.setItem(key, JSON.stringify(value)); + watchSessionStorage({ type: "set", key, data }); + // #endif + + // #ifndef H5 + console.warn("非H5环境不支持此API"); + // #endif +}; + +/** + * 从本地缓存中异步获取指定 key 对应的内容。 + * @param {String} key 本地缓存中的指定的 key + * vk.getSessionStorageSync(key); + */ +storage.getSessionStorageSync = function(key) { + // #ifdef H5 + let data; + try { + let value = JSON.parse(sessionStorage.getItem(key)); + data = value.data; + } catch (err) { + data = sessionStorage.getItem(key); + } + // get 没有必要监听 + // watchSessionStorage({ type:"get", key, data }); + return data; + // #endif + + // #ifndef H5 + console.warn("非H5环境不支持此API"); + // #endif +}; + +/** + * 从本地缓存中同步移除指定 key。 + * @param {String} key 本地缓存中的指定的 key + * vk.removeSessionStorageSync(key); + */ +storage.removeSessionStorageSync = function(key) { + // #ifdef H5 + sessionStorage.removeItem(key); + watchSessionStorage({ type: "remove", key }); + // #endif + + // #ifndef H5 + console.warn("非H5环境不支持此API"); + // #endif +}; + +/** + * 同步清理本地数据缓存。若key有值,则清除键值为指定字符串开头的缓存 + * @param {String} key 本地缓存中的指定的 key + * vk.clearSessionStorageSync(); + */ +storage.clearSessionStorageSync = function(key) { + // #ifdef H5 + if (key) { + let keys = Object.keys(sessionStorage); + if (keys) { + keys.map((keyName) => { + if (keyName.indexOf(key) == 0) { + sessionStorage.removeItem(keyName); + } + }); + } + } else { + sessionStorage.clear(); + watchSessionStorage({ type: "clear" }); + } + // #endif + + // #ifndef H5 + console.warn("非H5环境不支持此API"); + // #endif +}; + +export default storage; + + + +/** + * 单位进制换算 + * length 换算前大小 + * ary 进制,如KB-MB-GB,进制1024 + * precision 数值精度 + * arr 进制的数组,如["B","KB","MB","GB"] + * calcSize(length,1024,3,["B","KB","MB","GB"]); + */ +function calcSize(length = 0, ary, precision, arr) { + var size = parseFloat(length); + var mySize = 0; + var type = ""; + if (size < ary || arr.length <= 1) { + type = arr[0]; + mySize = parseFloat(size.toFixed(precision)); + } else { + for (var i = 1; i < arr.length; i++) { + var g = arr[i]; + size = size / ary; + if (size < ary) { + type = g; + mySize = parseFloat(size.toFixed(precision)); + break; + } + } + } + return { + size: mySize, + type: type, + title: mySize + " " + type + } +}; + +function watchSessionStorage(obj) { + if (typeof storage.watch === "function") { + storage.watch(obj); + } +} diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/weixin-js-sdk.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/weixin-js-sdk.js new file mode 100644 index 0000000..b605321 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/weixin-js-sdk.js @@ -0,0 +1,890 @@ +function n(o, e) { + if (!o.jWeixin) { + var n, + c = { + config: "preVerifyJSAPI", + onMenuShareTimeline: "menu:share:timeline", + onMenuShareAppMessage: "menu:share:appmessage", + onMenuShareQQ: "menu:share:qq", + onMenuShareWeibo: "menu:share:weiboApp", + onMenuShareQZone: "menu:share:QZone", + previewImage: "imagePreview", + getLocation: "geoLocation", + openProductSpecificView: "openProductViewWithPid", + addCard: "batchAddCard", + openCard: "batchViewCard", + chooseWXPay: "getBrandWCPayRequest", + openEnterpriseRedPacket: "getRecevieBizHongBaoRequest", + startSearchBeacons: "startMonitoringBeacons", + stopSearchBeacons: "stopMonitoringBeacons", + onSearchBeacons: "onBeaconsInRange", + consumeAndShareCard: "consumedShareCard", + openAddress: "editAddress" + }, + a = (function() { + var e = {}; + for (var n in c) e[c[n]] = n; + return e; + })(), + i = o.document, + t = i.title, + r = navigator.userAgent.toLowerCase(), + s = navigator.platform.toLowerCase(), + d = !(!s.match("mac") && !s.match("win")), + u = -1 != r.indexOf("wxdebugger"), + l = -1 != r.indexOf("micromessenger"), + p = -1 != r.indexOf("android"), + f = -1 != r.indexOf("iphone") || -1 != r.indexOf("ipad"), + m = (n = + r.match(/micromessenger\/(\d+\.\d+\.\d+)/) || + r.match(/micromessenger\/(\d+\.\d+)/)) ? + n[1] : + "", + g = { + initStartTime: L(), + initEndTime: 0, + preVerifyStartTime: 0, + preVerifyEndTime: 0 + }, + h = { + version: 1, + appId: "", + initTime: 0, + preVerifyTime: 0, + networkType: "", + isPreVerifyOk: 1, + systemType: f ? 1 : p ? 2 : -1, + clientVersion: m, + url: encodeURIComponent(location.href) + }, + v = {}, + S = { _completes: [] }, + y = { state: 0, data: {} }; + O(function() { + g.initEndTime = L(); + }); + var I = !1, + _ = [], + w = { + config: function(e) { + B("config", (v = e)); + var t = !1 !== v.check; + O(function() { + if (t) + M( + c.config, { + verifyJsApiList: C(v.jsApiList), + verifyOpenTagList: C(v.openTagList) + }, + (function() { + (S._complete = function(e) { + (g.preVerifyEndTime = L()), (y.state = 1), (y.data = e); + }), + (S.success = function(e) { + h.isPreVerifyOk = 0; + }), + (S.fail = function(e) { + S._fail ? S._fail(e) : (y.state = -1); + }); + var t = S._completes; + return ( + t.push(function() { + !(function() { + if ( + !( + d || + u || + v.debug || + m < "6.0.2" || + h.systemType < 0 + ) + ) { + var i = new Image(); + (h.appId = v.appId), + (h.initTime = g.initEndTime - g + .initStartTime), + (h.preVerifyTime = + g.preVerifyEndTime - g + .preVerifyStartTime), + w.getNetworkType({ + isInnerInvoke: !0, + success: function(e) { + h.networkType = + e + .networkType; + var n = + "https://open.weixin.qq.com/sdk/report?v=" + + h.version + + "&o=" + + h + .isPreVerifyOk + + "&s=" + + h + .systemType + + "&c=" + + h + .clientVersion + + "&a=" + + h.appId + + "&n=" + + h + .networkType + + "&i=" + + h.initTime + + "&p=" + + h + .preVerifyTime + + "&u=" + + h.url; + i.src = n; + } + }); + } + })(); + }), + (S.complete = function(e) { + for (var n = 0, i = t.length; n < i; ++n) t[n] + (); + S._completes = []; + }), + S + ); + })() + ), + (g.preVerifyStartTime = L()); + else { + y.state = 1; + for (var e = S._completes, n = 0, i = e.length; n < i; ++n) + e[n](); + S._completes = []; + } + }), + w.invoke || + ((w.invoke = function(e, n, i) { + o.WeixinJSBridge && WeixinJSBridge.invoke(e, x(n), i); + }), + (w.on = function(e, n) { + o.WeixinJSBridge && WeixinJSBridge.on(e, n); + })); + }, + ready: function(e) { + 0 != y.state ? e() : (S._completes.push(e), !l && v.debug && e()); + }, + error: function(e) { + m < "6.0.2" || (-1 == y.state ? e(y.data) : (S._fail = e)); + }, + checkJsApi: function(e) { + M( + "checkJsApi", { jsApiList: C(e.jsApiList) }, + ((e._complete = function(e) { + if (p) { + var n = e.checkResult; + n && (e.checkResult = JSON.parse(n)); + } + e = (function(e) { + var n = e.checkResult; + for (var i in n) { + var t = a[i]; + t && ((n[t] = n[i]), delete n[i]); + } + return e; + })(e); + }), + e) + ); + }, + onMenuShareTimeline: function(e) { + P( + c.onMenuShareTimeline, { + complete: function() { + M( + "shareTimeline", { + title: e.title || t, + desc: e.title || t, + img_url: e.imgUrl || "", + link: e.link || location.href, + type: e.type || "link", + data_url: e.dataUrl || "" + }, + e + ); + } + }, + e + ); + }, + onMenuShareAppMessage: function(n) { + P( + c.onMenuShareAppMessage, { + complete: function(e) { + "favorite" === e.scene ? + M("sendAppMessage", { + title: n.title || t, + desc: n.desc || "", + link: n.link || location.href, + img_url: n.imgUrl || "", + type: n.type || "link", + data_url: n.dataUrl || "" + }) : + M( + "sendAppMessage", { + title: n.title || t, + desc: n.desc || "", + link: n.link || location.href, + img_url: n.imgUrl || "", + type: n.type || "link", + data_url: n.dataUrl || "" + }, + n + ); + } + }, + n + ); + }, + onMenuShareQQ: function(e) { + P( + c.onMenuShareQQ, { + complete: function() { + M( + "shareQQ", { + title: e.title || t, + desc: e.desc || "", + img_url: e.imgUrl || "", + link: e.link || location.href + }, + e + ); + } + }, + e + ); + }, + onMenuShareWeibo: function(e) { + P( + c.onMenuShareWeibo, { + complete: function() { + M( + "shareWeiboApp", { + title: e.title || t, + desc: e.desc || "", + img_url: e.imgUrl || "", + link: e.link || location.href + }, + e + ); + } + }, + e + ); + }, + onMenuShareQZone: function(e) { + P( + c.onMenuShareQZone, { + complete: function() { + M( + "shareQZone", { + title: e.title || t, + desc: e.desc || "", + img_url: e.imgUrl || "", + link: e.link || location.href + }, + e + ); + } + }, + e + ); + }, + updateTimelineShareData: function(e) { + M( + "updateTimelineShareData", { title: e.title, link: e.link, imgUrl: e.imgUrl }, + e + ); + }, + updateAppMessageShareData: function(e) { + M( + "updateAppMessageShareData", { + title: e.title, + desc: e.desc, + link: e.link, + imgUrl: e + .imgUrl + }, + e + ); + }, + startRecord: function(e) { + M("startRecord", {}, e); + }, + stopRecord: function(e) { + M("stopRecord", {}, e); + }, + onVoiceRecordEnd: function(e) { + P("onVoiceRecordEnd", e); + }, + playVoice: function(e) { + M("playVoice", { localId: e.localId }, e); + }, + pauseVoice: function(e) { + M("pauseVoice", { localId: e.localId }, e); + }, + stopVoice: function(e) { + M("stopVoice", { localId: e.localId }, e); + }, + onVoicePlayEnd: function(e) { + P("onVoicePlayEnd", e); + }, + uploadVoice: function(e) { + M( + "uploadVoice", { + localId: e.localId, + isShowProgressTips: 0 == e.isShowProgressTips ? 0 : 1 + }, + e + ); + }, + downloadVoice: function(e) { + M( + "downloadVoice", { + serverId: e.serverId, + isShowProgressTips: 0 == e.isShowProgressTips ? 0 : 1 + }, + e + ); + }, + translateVoice: function(e) { + M( + "translateVoice", { + localId: e.localId, + isShowProgressTips: 0 == e.isShowProgressTips ? 0 : 1 + }, + e + ); + }, + chooseImage: function(e) { + M( + "chooseImage", { + scene: "1|2", + count: e.count || 9, + sizeType: e.sizeType || ["original", "compressed"], + sourceType: e.sourceType || ["album", "camera"] + }, + ((e._complete = function(e) { + if (p) { + var n = e.localIds; + try { + n && (e.localIds = JSON.parse(n)); + } catch (e) {} + } + }), + e) + ); + }, + getLocation: function(e) {}, + previewImage: function(e) { + M(c.previewImage, { current: e.current, urls: e.urls }, e); + }, + uploadImage: function(e) { + M( + "uploadImage", { + localId: e.localId, + isShowProgressTips: 0 == e.isShowProgressTips ? 0 : 1 + }, + e + ); + }, + downloadImage: function(e) { + M( + "downloadImage", { + serverId: e.serverId, + isShowProgressTips: 0 == e.isShowProgressTips ? 0 : 1 + }, + e + ); + }, + getLocalImgData: function(e) { + !1 === I ? + ((I = !0), + M( + "getLocalImgData", { localId: e.localId }, + ((e._complete = function(e) { + if (((I = !1), 0 < _.length)) { + var n = _.shift(); + wx.getLocalImgData(n); + } + }), + e) + )) : + _.push(e); + }, + getNetworkType: function(e) { + M( + "getNetworkType", {}, + ((e._complete = function(e) { + e = (function(e) { + var n = e.errMsg; + e.errMsg = "getNetworkType:ok"; + var i = e.subtype; + if ((delete e.subtype, i)) e.networkType = i; + else { + var t = n.indexOf(":"), + o = n.substring(t + 1); + switch (o) { + case "wifi": + case "edge": + case "wwan": + e.networkType = o; + break; + default: + e.errMsg = "getNetworkType:fail"; + } + } + return e; + })(e); + }), + e) + ); + }, + openLocation: function(e) { + M( + "openLocation", { + latitude: e.latitude, + longitude: e.longitude, + name: e.name || "", + address: e.address || "", + scale: e.scale || 28, + infoUrl: e.infoUrl || "" + }, + e + ); + }, + getLocation: function(e) { + M( + c.getLocation, { type: (e = e || {}).type || "wgs84" }, + ((e._complete = function(e) { + delete e.type; + }), + e) + ); + }, + hideOptionMenu: function(e) { + M("hideOptionMenu", {}, e); + }, + showOptionMenu: function(e) { + M("showOptionMenu", {}, e); + }, + closeWindow: function(e) { + M("closeWindow", {}, (e = e || {})); + }, + hideMenuItems: function(e) { + M("hideMenuItems", { menuList: e.menuList }, e); + }, + showMenuItems: function(e) { + M("showMenuItems", { menuList: e.menuList }, e); + }, + hideAllNonBaseMenuItem: function(e) { + M("hideAllNonBaseMenuItem", {}, e); + }, + showAllNonBaseMenuItem: function(e) { + M("showAllNonBaseMenuItem", {}, e); + }, + scanQRCode: function(e) { + M( + "scanQRCode", { + needResult: (e = e || {}).needResult || 0, + scanType: e.scanType || ["qrCode", "barCode"] + }, + ((e._complete = function(e) { + if (f) { + var n = e.resultStr; + if (n) { + var i = JSON.parse(n); + e.resultStr = i && i.scan_code && i.scan_code.scan_result; + } + } + }), + e) + ); + }, + openAddress: function(e) { + M( + c.openAddress, {}, + ((e._complete = function(e) { + e = (function(e) { + return ( + (e.postalCode = e.addressPostalCode), + delete e.addressPostalCode, + (e.provinceName = e.proviceFirstStageName), + delete e.proviceFirstStageName, + (e.cityName = e.addressCitySecondStageName), + delete e.addressCitySecondStageName, + (e.countryName = e.addressCountiesThirdStageName), + delete e.addressCountiesThirdStageName, + (e.detailInfo = e.addressDetailInfo), + delete e.addressDetailInfo, + e + ); + })(e); + }), + e) + ); + }, + openProductSpecificView: function(e) { + M( + c.openProductSpecificView, { + pid: e.productId, + view_type: e.viewType || 0, + ext_info: e.extInfo + }, + e + ); + }, + addCard: function(e) { + for (var n = e.cardList, i = [], t = 0, o = n.length; t < o; ++t) { + var r = n[t], + a = { card_id: r.cardId, card_ext: r.cardExt }; + i.push(a); + } + M( + c.addCard, { card_list: i }, + ((e._complete = function(e) { + var n = e.card_list; + if (n) { + for (var i = 0, t = (n = JSON.parse(n)).length; i < t; ++i) { + var o = n[i]; + (o.cardId = o.card_id), + (o.cardExt = o.card_ext), + (o.isSuccess = !!o.is_succ), + delete o.card_id, + delete o.card_ext, + delete o.is_succ; + } + (e.cardList = n), delete e.card_list; + } + }), + e) + ); + }, + chooseCard: function(e) { + M( + "chooseCard", { + app_id: v.appId, + location_id: e.shopId || "", + sign_type: e.signType || "SHA1", + card_id: e.cardId || "", + card_type: e.cardType || "", + card_sign: e.cardSign, + time_stamp: e.timestamp + "", + nonce_str: e.nonceStr + }, + ((e._complete = function(e) { + (e.cardList = e.choose_card_info), delete e.choose_card_info; + }), + e) + ); + }, + openCard: function(e) { + for (var n = e.cardList, i = [], t = 0, o = n.length; t < o; ++t) { + var r = n[t], + a = { card_id: r.cardId, code: r.code }; + i.push(a); + } + M(c.openCard, { card_list: i }, e); + }, + consumeAndShareCard: function(e) { + M( + c.consumeAndShareCard, { consumedCardId: e.cardId, consumedCode: e.code }, + e + ); + }, + chooseWXPay: function(e) { + M(c.chooseWXPay, V(e), e); + }, + openEnterpriseRedPacket: function(e) { + M(c.openEnterpriseRedPacket, V(e), e); + }, + startSearchBeacons: function(e) { + M(c.startSearchBeacons, { ticket: e.ticket }, e); + }, + stopSearchBeacons: function(e) { + M(c.stopSearchBeacons, {}, e); + }, + onSearchBeacons: function(e) { + P(c.onSearchBeacons, e); + }, + openEnterpriseChat: function(e) { + M( + "openEnterpriseChat", { useridlist: e.userIds, chatname: e.groupName }, + e + ); + }, + launchMiniProgram: function(e) { + M( + "launchMiniProgram", { + targetAppId: e.targetAppId, + path: (function(e) { + if ("string" == typeof e && 0 < e.length) { + var n = e.split("?")[0], + i = e.split("?")[1]; + return (n += ".html"), void 0 !== i ? n + "?" + i : n; + } + })(e.path), + envVersion: e.envVersion + }, + e + ); + }, + openBusinessView: function(e) { + M( + "openBusinessView", { + businessType: e.businessType, + queryString: e.queryString || "", + envVersion: e.envVersion + }, + ((e._complete = function(n) { + if (p) { + var e = n.extraData; + if (e) + try { + n.extraData = JSON.parse(e); + } catch (e) { + n.extraData = {}; + } + } + }), + e) + ); + }, + miniProgram: { + navigateBack: function(e) { + (e = e || {}), + O(function() { + M( + "invokeMiniProgramAPI", { + name: "navigateBack", + arg: { + delta: e + .delta || 1 + } + }, + e + ); + }); + }, + navigateTo: function(e) { + O(function() { + M( + "invokeMiniProgramAPI", { name: "navigateTo", arg: { url: e.url } }, + e + ); + }); + }, + redirectTo: function(e) { + O(function() { + M( + "invokeMiniProgramAPI", { name: "redirectTo", arg: { url: e.url } }, + e + ); + }); + }, + switchTab: function(e) { + O(function() { + M( + "invokeMiniProgramAPI", { name: "switchTab", arg: { url: e.url } }, + e + ); + }); + }, + reLaunch: function(e) { + O(function() { + M( + "invokeMiniProgramAPI", { name: "reLaunch", arg: { url: e.url } }, + e + ); + }); + }, + postMessage: function(e) { + O(function() { + M( + "invokeMiniProgramAPI", { name: "postMessage", arg: e.data || {} }, + e + ); + }); + }, + getEnv: function(e) { + O(function() { + e({ miniprogram: "miniprogram" === o.__wxjs_environment }); + }); + } + } + }, + T = 1, + k = {}; + return ( + i.addEventListener( + "error", + function(e) { + if (!p) { + var n = e.target, + i = n.tagName, + t = n.src; + if ("IMG" == i || "VIDEO" == i || "AUDIO" == i || "SOURCE" == i) + if (-1 != t.indexOf("wxlocalresource://")) { + e.preventDefault(), e.stopPropagation(); + var o = n["wx-id"]; + if ((o || ((o = T++), (n["wx-id"] = o)), k[o])) return; + (k[o] = !0), + wx.ready(function() { + wx.getLocalImgData({ + localId: t, + success: function(e) { + n.src = e.localData; + } + }); + }); + } + } + }, + !0 + ), + i.addEventListener( + "load", + function(e) { + if (!p) { + var n = e.target, + i = n.tagName; + n.src; + if ("IMG" == i || "VIDEO" == i || "AUDIO" == i || "SOURCE" == i) { + var t = n["wx-id"]; + t && (k[t] = !1); + } + } + }, + !0 + ), + e && (o.wx = o.jWeixin = w), + w + ); + } + + function M(n, e, i) { + o.WeixinJSBridge ? + WeixinJSBridge.invoke(n, x(e), function(e) { + A(n, e, i); + }) : + B(n, i); + } + + function P(n, i, t) { + o.WeixinJSBridge ? + WeixinJSBridge.on(n, function(e) { + t && t.trigger && t.trigger(e), A(n, e, i); + }) : + B(n, t || i); + } + + function x(e) { + return ( + ((e = e || {}).appId = v.appId), + (e.verifyAppId = v.appId), + (e.verifySignType = "sha1"), + (e.verifyTimestamp = v.timestamp + ""), + (e.verifyNonceStr = v.nonceStr), + (e.verifySignature = v.signature), + e + ); + } + + function V(e) { + return { + timeStamp: e.timestamp + "", + nonceStr: e.nonceStr, + package: e.package, + paySign: e.paySign, + signType: e.signType || "SHA1" + }; + } + + function A(e, n, i) { + ("openEnterpriseChat" != e && "openBusinessView" !== e) || + (n.errCode = n.err_code), + delete n.err_code, + delete n.err_desc, + delete n.err_detail; + var t = n.errMsg; + t || + ((t = n.err_msg), + delete n.err_msg, + (t = (function(e, n) { + var i = e, + t = a[i]; + t && (i = t); + var o = "ok"; + if (n) { + var r = n.indexOf(":"); + "confirm" == (o = n.substring(r + 1)) && (o = "ok"), + "failed" == o && (o = "fail"), + -1 != o.indexOf("failed_") && (o = o.substring(7)), + -1 != o.indexOf("fail_") && (o = o.substring(5)), + ("access denied" != + (o = (o = o.replace(/_/g, " ")).toLowerCase()) && + "no permission to execute" != o) || + (o = "permission denied"), + "config" == i && "function not exist" == o && (o = "ok"), + "" == o && (o = "fail"); + } + return (n = i + ":" + o); + })(e, t)), + (n.errMsg = t)), + (i = i || {})._complete && (i._complete(n), delete i._complete), + (t = n.errMsg || ""), + v.debug && !i.isInnerInvoke && alert(JSON.stringify(n)); + var o = t.indexOf(":"); + switch (t.substring(o + 1)) { + case "ok": + i.success && i.success(n); + break; + case "cancel": + i.cancel && i.cancel(n); + break; + default: + i.fail && i.fail(n); + } + i.complete && i.complete(n); + } + + function C(e) { + if (e) { + for (var n = 0, i = e.length; n < i; ++n) { + var t = e[n], + o = c[t]; + o && (e[n] = o); + } + return e; + } + } + + function B(e, n) { + if (!(!v.debug || (n && n.isInnerInvoke))) { + var i = a[e]; + i && (e = i), + n && n._complete && delete n._complete, + console.log('"' + e + '",', n || ""); + } + } + + function L() { + return new Date().getTime(); + } + + function O(e) { + l && + (o.WeixinJSBridge ? + e() : + i.addEventListener && + i.addEventListener("WeixinJSBridgeReady", e, !1)); + } +}; + +export default n(window); \ No newline at end of file diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/install/console.log.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/install/console.log.js new file mode 100644 index 0000000..e4beb6a --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/install/console.log.js @@ -0,0 +1,18 @@ +let debug = process.env.NODE_ENV !== 'production'; +const install = Vue => { + let vk = Vue.prototype ? Vue.prototype.vk : Vue.config.globalProperties.vk; + if (vk) { + vk.log = console.log; + if (typeof vk.getConfig === "function") { + debug = vk.getConfig().debug; + } + if(!debug){ + console.log = function(...obj){}; + } + } +} + +export default { + install +} + diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/mixin/mixin.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/mixin/mixin.js new file mode 100644 index 0000000..68910e3 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/mixin/mixin.js @@ -0,0 +1,40 @@ +var isOnLaunch = true; +export default { + data() { + return {} + }, + onLoad() { + // 将vk实例挂载到app.globalData上,方便在非Vue页面自身函数中调用vk实例(因为获取不到this) + let app = getApp({ allowDefault: true }); + if (app && app.globalData && !app.globalData.vk) { + app.globalData.vk = this.vk; + } + if (this.vk) { + const url = this.vk.pubfn.getCurrentPageRoute(); + // 检测是否可以分享(小程序专属) + this.vk.navigate.checkAllowShare({ url }); + // 检测是否需要登录,只有首次启动的页面才需要检测,其他页面通过 vk.navigateTo 跳转前会自动判断。 + if (isOnLaunch && !this.vk.checkToken() && getCurrentPages().length == 1) { + isOnLaunch = false; // 重新标记为非首次页面 + const currentPage = this.vk.pubfn.getCurrentPage() || {}; + let pagePath = currentPage.pagePath || `/${currentPage.route}` || url; + let fullPath = currentPage.fullPath; + let options = currentPage.options; + this.vk.pubfn.checkLogin({ url: pagePath, fullPath, options, isOnLaunch: true }); // 检测是否需要登录 + } + } + }, + created() { + // 将vk实例挂载到app.globalData上,方便在非Vue页面自身函数中调用vk实例(因为获取不到this) + let app = getApp({ allowDefault: true }); + if (app && app.globalData && !app.globalData.vk) { + app.globalData.vk = this.vk; + } + }, + methods: { + $getData(data, key, defaultValue) { + let { vk } = this; + return vk.pubfn.getData(data, key, defaultValue); + } + } +} diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/openapi/baidu/index.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/openapi/baidu/index.js new file mode 100644 index 0000000..5fa7d5f --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/openapi/baidu/index.js @@ -0,0 +1,170 @@ +/** + * 百度API + */ +var baidu = {}; +var vk = {}; +var baiduOpenApiAccessTokenCacheName = "vk_openapi_baidu_open_token"; +baidu.init = function(util={}) { + vk = util.vk; +}; + +// 百度开放平台api +baidu.open = {}; +// 文字识别 +baidu.open.ocr = {}; + +/** + * 营业执照识别 + * 以下data参数三选一即可 + * @param {File} file 文件对象 + * @param {String} image 图像base64编码后进行urlencode + * @param {String} url 图片完整URL + * +vk.openapi.baidu.open.ocr.business_license({ + title:"识别中...", + data: { + file: res.tempFiles[0] + }, + success: (res) => { + that.data = res.data; + }, +}); + */ +baidu.open.ocr.business_license = function(obj={}){ + obj.action = "ocr/v1/business_license"; + let file = obj.data.file; + if(file){ + vk.pubfn.fileToBase64({ file }).then(base64 => { + obj.data.image = base64; + delete obj.data.file; + baidu.request(obj); + }); + }else{ + baidu.request(obj); + } +} + +/** + * 身份证识别 + * 以下data参数三选一即可 + * @param {File} file 文件对象 + * @param {String} image 图像base64编码后进行urlencode + * @param {String} url 图片完整URL +vk.openapi.baidu.open.ocr.idcard({ + title:"识别中...", + data: { + image:base64, + id_card_side:"front", // front:身份证含照片的一面 back:身份证带国徽的一面 + }, + success: (res) => { + that.data = res.data; + }, +}); + */ +baidu.open.ocr.idcard = function(obj={}){ + obj.action = "ocr/v1/idcard"; + let file = obj.data.file; + if(!obj.data.id_card_side) obj.data.id_card_side = "front"; + if(file){ + vk.pubfn.fileToBase64({ file }).then(base64 => { + obj.data.image = base64; + delete obj.data.file; + baidu.request(obj); + }); + }else{ + baidu.request(obj); + } +} + +/** + * 百度开放平台通用请求接口 + * @param {String} action 接口名称 + * @param {String} actionVersion 接口版本名称 默认2.0 + * @param {String} title loading文字 + * @param {object} data 请求参数 + * @param {String} success 成功回调 + * @param {String} fail 失败回调 + * @param {String} complete 完成回调 + * 使用示例 +vk.openapi.baidu.request({ + action: 'ocr/v1/business_license', + title:"识别中...", + data: { + image:base64 + }, + success: (data) => { + that.data = data; + }, +}); + */ +baidu.request = function(obj={}){ + let { + title + } = obj; + if(title) vk.showLoading(title); + let baiduApiAccessToken = vk.getStorageSync(baiduOpenApiAccessTokenCacheName); + if(baiduApiAccessToken && baiduApiAccessToken.expTime > new Date().getTime()){ + // 获取缓存中的token + obj.accessToken = baiduApiAccessToken.accessToken; + request(obj); + }else{ + // 发起请求获取token + vk.callFunction({ + url: 'plugs/baidu/client/pub/getAccessToken', + success:function(tokenRes) { + vk.setStorageSync(baiduOpenApiAccessTokenCacheName,{ + accessToken : tokenRes.access_token, + expTime : 2590000000 + new Date().getTime(), + }); + obj.accessToken = tokenRes.access_token; + request(obj); + }, + fail:function(res){ + if(title) vk.hideLoading(); + if(typeof obj.fail === "function") obj.fail(res); + if(typeof obj.complete === "function") obj.complete(res); + } + }); + } +} + +function request(obj={}){ + let { + action, + actionVersion = "2.0", + accessToken, + header = { "content-type": "application/x-www-form-urlencoded" }, + data, + title + } = obj; + vk.request({ + url: `https://aip.baidubce.com/rest/${actionVersion}/${action}?access_token=${accessToken}`, + method:"POST", + header:{ + "content-type": "application/x-www-form-urlencoded", + }, + errorCodeName:"error_code", + errorMsgName:"error_msg", + data, + needAlert:true, + success: function(data){ + if(title) vk.hideLoading(); + if(data.code){ + if(typeof obj.fail === "function") obj.fail(data); + }else{ + if(typeof obj.success === "function") obj.success(data); + } + }, + fail: function(data){ + if(title) vk.hideLoading(); + // 如果是因为token失效报的错误,则清空下本地token缓存 + if(data && data.code === 110) vk.removeStorageSync(baiduOpenApiAccessTokenCacheName); + if(typeof obj.fail === "function") obj.fail(data); + }, + complete: function(data){ + if(typeof obj.complete === "function") obj.complete(data); + } + }); +} + +export default baidu; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/openapi/index.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/openapi/index.js new file mode 100644 index 0000000..531c653 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/openapi/index.js @@ -0,0 +1,14 @@ +/** + * 开放API + */ +import baidu from './baidu' + +var openapi = {}; +openapi.baidu = baidu; +openapi.init = function(util){ + openapi.baidu.init(util); +} +// 微信小程序API +export default openapi; + + diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/store/libs/error.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/store/libs/error.js new file mode 100644 index 0000000..4cc9271 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/store/libs/error.js @@ -0,0 +1,25 @@ + +const install = Vue => { + const debug = process.env.NODE_ENV !== 'production'; + let vk = Vue.prototype ? Vue.prototype.vk : Vue.config.globalProperties.vk; + if (debug && vk) { + const oldErrorHandler = Vue.config.errorHandler; + Vue.config.errorHandler = function errorHandler(err, vm, info) { + const route = vm.$page && vm.$page.route; + let date = new Date(); + let log = { + err: err.toString(), + info, + route, + time: date.getTime(), + timeStr: date.toLocaleTimeString() + }; + if(vk.vuex) vk.vuex.dispatch('$error/add', log); + return oldErrorHandler(err, vm, info); + } + } +} + +export default { + install +} diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/store/mixin/mixin.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/store/mixin/mixin.js new file mode 100644 index 0000000..72d96ee --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/store/mixin/mixin.js @@ -0,0 +1,67 @@ +export default { + beforeCreate() { + // 将vuex方法挂在到vk实例中 beforeCreate created + let { vk, $store } = this; + if (typeof $store !== "undefined" && typeof vk.getVuexStore === "undefined") { + vk.getVuexStore = function() { + return $store; + }; + vk.vuex = (name, value) => { + $store.commit('updateStore', { name, value }); + }; + /** + * (推荐) 设置vuex + * vk.vuex.set('$user.userInfo.avatar', avatar); + */ + vk.vuex.set = (name, value) => { + $store.commit('updateStore', { name, value }); + }; + /** + * (推荐) 读取vuex(具有解除对象内存印射功能,且任意一层数据为undefined,不会报错) + * vk.vuex.get('$user.userInfo.avatar'); + */ + vk.vuex.get = (name, defaultValue) => { + let value = vk.pubfn.getData($store.state, name); + if (typeof value === "undefined") return (typeof defaultValue !== "undefined") ? defaultValue : ""; + return JSON.parse(JSON.stringify(value)); + }; + vk.vuex.getters = (name) => { + return $store.getters[name]; + }; + /** + * 触发vuex的指定actions(异步) + * $user是模块名,addFootprint是对应模块的action名称 + * vk.vuex.dispatch('$user/addFootprint', data); + */ + vk.vuex.dispatch = $store.dispatch; + /** + * 触发vuex的指定mutations + * $user是模块名,setFootprint是对应模块的action名称 + * vk.vuex.commit('$user/setFootprint', data); + */ + vk.vuex.commit = $store.commit; + + /* 另一种方式 */ + /** + * vk.setVuex('$user.userInfo.avatar', avatar); + */ + vk.setVuex = vk.vuex.set; + /** + * vk.getVuex('$user.userInfo.avatar'); + */ + vk.getVuex = vk.vuex.get; + /* 兼容老版本 */ + vk.state = vk.vuex.get; + try { + if (!vk.checkToken()) { + vk.callFunctionUtil.deleteUserInfo({ + log: false + }); + } + } catch (err) {} + } + }, + computed: { + + } +} diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/vk-unicloud/vk-unicloud-callFunctionUtil.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/vk-unicloud/vk-unicloud-callFunctionUtil.js new file mode 100644 index 0000000..2ef380d --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/vk-unicloud/vk-unicloud-callFunctionUtil.js @@ -0,0 +1,1040 @@ +var vk = {}; +var counterNum = 0; +var uniCloudEnvs = {}; // uniCloud 环境列表 +var lastToLoginTime = 0; +class CallFunctionUtil { + constructor() { + this.config = { + // 是否开启测试环境的云函数,true:使用测试环境,false:使用正式环境,默认true + isTest: false, + // 设为false可关闭打印日志 + debug: true, + // 云函数路由(主函数名) + functionName: "router", + // 云函数路由(开发测试函数名) + testFunctionName: "router-test", + // 云函数url化后对应的url地址 + functionNameToUrl: { + "router": "https://xxxxxxx.bspapp.com/http/router", + "router-test": "https://xxxxxxx.bspapp.com/http/router" + }, + // vk.callFunction的isRequest的默认值 + isRequestDefault: false, + // 默认时区(中国为8) + targetTimezone: 8, + // 客户端登录页面地址 + login: { + url: '/pages_template/uni-id/login/index/index' + }, + // 请求配置 + request: { + // 公共请求参数(每次请求都会带上的参数) + dataParam: {} + }, + // 日志风格 + logger: { + colorArr: [ + "#0095ff", + "#67C23A" + ] + }, + // 缓存键名 - token(请勿修改) + uniIdTokenKeyName: "uni_id_token", + // 缓存键名 - token过期时间(请勿修改) + uniIdTokenExpiredKeyName: "uni_id_token_expired", + // 缓存键名 - 当前登录用户信息(请勿修改) + uniIdUserInfoKeyName: "uni_id_user_info", + // 缓存键名 - 公共请求参数(请勿修改) + requestGlobalParamKeyName: "vk_request_global_param", + // 监听token刷新事件的事件名 + onRefreshTokenEventName: "onRefreshToken", + // 自定义组件配置 + components: {} + } + /** + * 获取我的token + * vk.getToken(); + */ + this.getToken = (res = {}) => { + let config = this.config; + return vk.getStorageSync(config.uniIdTokenKeyName); + } + /** + * 保存新的token + * 可通过下方的代码监听token的改变(写在app.vue的onLaunch内) + vk.$on('onRefreshToken',(data) => { + console.log('token改变监听:', data); + }); + */ + this.saveToken = (res = {}) => { + let config = this.config; + vk.setStorageSync(config.uniIdTokenKeyName, res.token); + vk.setStorageSync(config.uniIdTokenExpiredKeyName, res.tokenExpired); + this.emitRefreshToken(res); // 触发token刷新事件 + if (this.config.debug) console.log("--------【token已更新】--------"); + } + // 删除token,并删除userInfo缓存 + this.deleteToken = () => { + let config = this.config; + vk.removeStorageSync(config.uniIdTokenKeyName); + vk.removeStorageSync(config.uniIdTokenExpiredKeyName); + this.deleteUserInfo(); + this.emitRefreshToken(); // 触发token刷新事件 + if (this.config.debug) console.log("--------【token已删除】--------"); + } + // 更新userInfo缓存 + this.updateUserInfo = (res = {}) => { + let config = this.config; + let { + userInfo = {} + } = res; + if (typeof vk.setVuex === "function") { + // 有安装vuex则使用vuex + vk.setVuex('$user.userInfo', userInfo); + } else { + // 否则使用本地缓存 + vk.setStorageSync(config.uniIdUserInfoKeyName, userInfo); + } + //if (this.config.debug) console.log("--------【用户信息已更新】--------"); + } + // 删除userInfo缓存 + this.deleteUserInfo = (res = {}) => { + let { + log = true + } = res; + let config = this.config; + if (typeof vk.setVuex === "function") { + // 有安装vuex则使用vuex + vk.setVuex('$user.userInfo', {}); + vk.setVuex('$user.permission', []); + vk.removeStorageSync(config.uniIdUserInfoKeyName); + } else { + // 否则使用本地缓存 + vk.removeStorageSync(config.uniIdUserInfoKeyName); + } + if (this.config.debug && log) console.log("--------【用户信息已删除】--------"); + } + // 检查token是否有效(本地版) + // let valid = vk.callFunctionUtil.checkToken(); + this.checkToken = (res = {}) => { + let config = this.config; + let token = uni.getStorageSync(config.uniIdTokenKeyName); + let tokenExpired = uni.getStorageSync(config.uniIdTokenExpiredKeyName); + let valid = false; + if (token && tokenExpired && tokenExpired > Date.now()) { + valid = true; + } + return valid; + } + /** + * 触发监听token更新事件 + */ + this.emitRefreshToken = (data = {}) => { + let config = this.config; + return vk.$emit(config.onRefreshTokenEventName, data); // 触发token刷新事件 + } + /** + * 监听token更新事件 + */ + this.onRefreshToken = (callback) => { + let config = this.config; + return vk.$on(config.onRefreshTokenEventName, callback); + } + /** + * 移除token更新事件 + */ + this.offRefreshToken = (callback) => { + let config = this.config; + return vk.$off(config.onRefreshTokenEventName, callback); + } + /** + * 修改请求配置中的公共请求参数 + * 若把shop-manage改成*则代表全局 + vk.callFunctionUtil.updateRequestGlobalParam({ + "shop-manage":{ + regExp:"^xxx/kh/", + data:{ + shop_id : shop_id + } + } + }); + 对应的callFunction中增加参数globalParamName:"shop-manage" + vk.callFunction({ + url: 'xxx/xxxxxx', + title: '请求中...', + globalParamName:"shop-manage",// 如果设置了正则规则,则不需要此参数 + data: {}, + success(data) { + } + }); + */ + this.updateRequestGlobalParam = (data = {}, setKey) => { + let config = this.config; + if (setKey) { + // 覆盖对象 + config.request.dataParam = data; + } else { + // 覆盖参数(有就覆盖,没有则新增) + let dataParam = uni.getStorageSync(config.requestGlobalParamKeyName) || {}; + config.request.dataParam = Object.assign(dataParam, data); + } + vk.setStorageSync(config.requestGlobalParamKeyName, config.request.dataParam); + } + /** + * 获取请求配置中的公共请求参数 + vk.callFunctionUtil.getRequestGlobalParam(); + */ + this.getRequestGlobalParam = (globalParamName = "*") => { + let config = this.config; + let data = config.request.dataParam; + if (!data || JSON.stringify(data) === "{}") { + data = uni.getStorageSync(config.requestGlobalParamKeyName) || {}; + config.request.dataParam = data; + } + let param = data[globalParamName] || {}; + return JSON.parse(JSON.stringify(param)); + } + /** + * 删除请求配置中的公共请求参数 + * globalParamName 不传代表删除所有 + vk.callFunctionUtil.deleteRequestGlobalParam(globalParamName); + */ + this.deleteRequestGlobalParam = (globalParamName) => { + let config = this.config; + let globalParam = uni.getStorageSync(config.requestGlobalParamKeyName) || {}; + if (globalParamName) { + delete globalParam[globalParamName]; + } else { + globalParam = {}; + } + config.request.dataParam = globalParam; + vk.setStorageSync(config.requestGlobalParamKeyName, globalParam); + } + // 拦截器 + this.interceptor = { + // 拦截1301、1302错误码(非法token和token失效) + login: (obj = {}) => { + let nowTime = Date.now(); + if (nowTime - lastToLoginTime < 300) { + return false; + } + lastToLoginTime = nowTime; + let { + params, + res + } = obj; + let config = this.config; + let callFunction = this.callFunction; + if (config.debug) console.log("跳登录页面"); + let { tokenExpiredAutoDelete = true } = config; + if (tokenExpiredAutoDelete) this.deleteToken(); + setTimeout(() => { + if (config.login.url) { + let currentPage = getCurrentPages()[getCurrentPages().length - 1]; + if (currentPage && currentPage.route && "/" + currentPage.route === config.login.url) { + return false; + } + // 此处代码是为了防止首页启动时检测和正常检测冲突----------------------------------------------------------- + if (vk.navigate.isOnLaunchToLogin) { + setTimeout(() => { + vk.navigate.isOnLaunchToLogin = false; + }, 500); + return false; + } + // 此处代码是为了防止首页启动时检测和正常检测冲突----------------------------------------------------------- + uni.navigateTo({ + url: config.login.url, + events: { + // 监听登录成功后的事件 + loginSuccess: function(data) { + let num = 2; + let pages = getCurrentPages(); + if (pages.length >= num) { + let that = pages[pages.length - num]; + if (typeof that.onLoad == "function") { + // 重新执行页面onLoad函数 + that.onLoad(that.options); + } else if (typeof that.init == "function") { + // 重新执行页面初始化函数 + that.init(that.options); + } else { + // 重新执行一次云函数调用 + callFunction(params); + } + } else { + // 重新执行一次云函数调用 + callFunction(params); + } + } + } + }); + } else { + if (params.needAlert) { + vk.alert(res.result.msg); + } + } + }, 0); + }, + // 全局请求失败拦截器 + fail: (obj = {}) => { + return true; + } + } + /** + * 云函数请求封装 - 统一入口 + * @description 通过云函数路由,1个云函数实现多个云函数的效果。 + * @param {String} name 大云函数名称(默认router) + * @param {String} url 请求路径 + * @param {Object} data 请求参数,如 { a:1, b:"2" } 云函数内可通过 let { a, b } = data; 获取参数 + * @param {String} title 遮罩层提示语,为空或不传则代表不显示遮罩层。 + * @param {Boolean|Object} loading 若设置为false,即使title有值也不显示遮罩层 + * @param {Boolean} isRequest 是否使用云函数url化地址访问云函数,默认false + * @param {String} env 云空间环境 文档:https://vkdoc.fsq.pub/client/question/q9.html#%E5%89%8D%E7%AB%AF%E8%AF%B7%E6%B1%82%E5%A4%9A%E6%9C%8D%E5%8A%A1%E7%A9%BA%E9%97%B4 + * @param {Boolean} needAlert 为true代表请求错误时,会有弹窗提示,默认为true + * @param {Number} retryCount 系统异常重试机制(表单提交时慎用,建议只用在查询请求中,即无任何数据库修改的请求中) + * @param {Function} success 请求成功时,执行的回调函数 + * @param {Function} fail 请求失败时,执行的回调函数 + * @param {Function} complete 无论请求成功与否,都会执行的回调函数 + */ + this.callFunction = (obj = {}) => { + let that = this; + let { config } = that; + let { + url, + data = {}, + globalParamName + } = obj; + + if (!url) { + vk.toast('vk.callFunction的url参数不能为空'); + return; + } + + if (obj.retryCount) { + // 系统异常重试机制(表单提交时慎用,建议只用在查询请求中,即无任何数据库修改的请求中) + return that.callFunctionRetry(obj); + } + // 去除值为 undefined 的参数 + if (typeof data === "object") { + obj.data = vk.pubfn.copyObject(data); + } + // 注入自定义全局参数开始----------------------------------------------------------- + let globalParam = uni.getStorageSync(config.requestGlobalParamKeyName) || {}; + // 根据正则规格自动匹配全局请求参数 + for (let i in globalParam) { + let customDate = globalParam[i]; + if (customDate.regExp) { + if (typeof customDate.regExp === "object") { + // 数组形式 + for (let i = 0; i < customDate.regExp.length; i++) { + let regExp = new RegExp(customDate.regExp[i]); + if (regExp.test(url)) { + obj.data = Object.assign(customDate.data, obj.data); + break; + } + } + } else { + // 字符串形式 + let regExp = new RegExp(customDate.regExp); + if (regExp.test(url)) { + obj.data = Object.assign(customDate.data, obj.data); + } + } + } + } + // 根据指定globalParamName匹配全局请求参数 + let customDate = that.getRequestGlobalParam(globalParamName); + if (customDate && JSON.stringify(customDate) !== "{}") { + if (customDate.regExp) { + obj.data = Object.assign(customDate.data, obj.data); // 新版本 + } else { + obj.data = Object.assign(customDate, obj.data); // 兼容旧版本 + } + } + // 注入自定义全局参数结束----------------------------------------------------------- + // 若执行的函数不是pub类型函数,则先本地判断下token,可以提高效率。 + // if (url.indexOf("/pub/") == -1 && url.indexOf("/pub_") == -1) { + // 若执行的函数是kh或sys类型函数,先本地判断下token,可以提高效率。 + if (url.indexOf("/kh/") > -1 || url.indexOf("/sys/") > -1 || (url.indexOf(".") > -1 && url.indexOf("pub_") == -1 && url.indexOf("/pub/") == -1 && url.indexOf( + "/pub.") == -1 && url.indexOf("pub.") !== 0 && url.indexOf("pub_") !== 0)) { + if (!vk.checkToken()) { + // 若本地token校验未通过,则直接执行 login 拦截器函数 + return new Promise((resolve, reject) => { + // 执行 login 拦截器函数(跳转到页面页面) + let res = { code: 30204, msg: "本地token校验未通过" }; + let params = obj; + if (typeof that.interceptor.login === "function") { + that.interceptor.login({ + res, + params, + vk + }); + } + reject(res); + }); + } + } + if (typeof obj.isRequest === "undefined") { + obj.isRequest = config.isRequestDefault; + } + // 执行请求 + if (obj.isRequest) { + return that.runRequest(obj); + } else { + return that.runCallFunction(obj); + } + } + + // 设置全局默认配置 + this.setConfig = (customConfig = {}) => { + for (let key in customConfig) { + if (key === "vk") { + vk = customConfig[key]; + } else if (key === "interceptor") { + this.interceptor = Object.assign(this.interceptor, customConfig[key]); + this.config.interceptor = customConfig[key]; + } else if (key === "myfn") { + vk.myfn = customConfig[key]; + } else if (key === "loginPagePath") { + // 兼容老版本 + this.config.login.url = customConfig[key]; + } else if (key === "uniCloud") { + let uniCloudConfig = customConfig[key]; + if (uniCloudConfig && uniCloudConfig.envs) { + for (let envKey in uniCloudConfig.envs) { + let envItem = uniCloudConfig.envs[envKey]; + if (envItem && envItem.provider && envItem.spaceId) { + let initConifg = { + provider: envItem.provider, + spaceId: envItem.spaceId + }; + if (envItem.clientSecret) initConifg.clientSecret = envItem.clientSecret; + if (envItem.endpoint) initConifg.endpoint = envItem.endpoint; + uniCloudEnvs[envKey] = uniCloud.init(initConifg); + } + } + } + } else if (typeof customConfig[key] === "object" && typeof this.config[key] === "object") { + this.config[key] = Object.assign(this.config[key], customConfig[key]); + } else if (typeof customConfig[key] !== "undefined") { + this.config[key] = customConfig[key]; + } + } + } + /** + * 获取vk前端配置 + * 示例 + * vk.callFunctionUtil.getConfig(); + * vk.callFunctionUtil.getConfig("login.url"); + */ + this.getConfig = (key) => { + let config = this.config; + if (key) { + return vk.pubfn.getData(config, key); + } else { + return config; + } + } + + // 初始化 + this.init = (obj = {}) => { + vk = obj.vk; + } + /** + * 云函数上传图片 + * @param {String} title 上传时的loading提示语 + * @param {String} file 要上传的文件对象,file与filePath二选一即可 + * @param {String} filePath 要上传的文件路径,file与filePath二选一即可 + * @param {String} suffix 指定上传后的文件后缀,如果传了file 参数,则此参数可不传 + * @param {String} provider 云存储供应商,支持:unicloud、aliyun + * @param {String} cloudPath 指定上传后的云端文件路径(不指定会自动生成)cloudPath优先级大于cloudDirectory + * @param {String} cloudDirectory 指定上传后的云端文件目录(不指定会自动生成) + * @param {String} needSave 是否需要将图片信息保存到admin素材库 + * @param {String} category_id 素材库分类id,当needSave为true时生效 + * @param {String} uniCloud 上传到其他空间时使用,uniCloud和env二选一即可 + * @param {String} env 上传到其他空间时使用,uniCloud和env二选一即可 + * @param {String} cloudPathAsRealPath 阿里云目录支持,需HBX3.8.5以上版本才支持 + * @param {String} cloudPathRemoveChinese 删除文件名中的中文 + * @param {String} fileType 文件类型,可选image、video、audio 不用传,会自动识别 + * @param {Function} onUploadProgress 上传进度回调 + * @param {Function} success 上传成功时,执行的回调函数 + * @param {Function} fail 上传失败时,执行的回调函数 + * @param {Function} complete 无论上传成功与否,都会执行的回调函数 + * vk.callFunctionUtil.uploadFile + */ + this.uploadFile = (obj = {}) => { + let that = this; + let config = that.config; + if (!obj.filePath && obj.file && obj.file.path) obj.filePath = obj.file.path; + let { + filePath, + cloudPath, + title, + errorToast, + needAlert, + success, + fail, + complete, + type, + provider, + file = {}, + needSave = false, + category_id, + uniCloud: myCloud, + env = "default", + cloudPathAsRealPath = true, // 阿里云目录支持,需HBX3.8.5以上版本才支持 + cloudPathRemoveChinese = true, // 删除文件名中的中文 + cloudDirectory, + } = obj; + // 获取文件类型(image:图片 video:视频 other:其他) + let fileType = this.getFileType(obj); + obj.fileType = fileType; + if (type && !provider) provider = type; + if (!provider) { + let aliyunOSS = vk.pubfn.getData(config, "service.aliyunOSS"); + if (aliyunOSS && aliyunOSS.isDefault) { + provider = "aliyun"; + } else { + provider = "unicloud"; + } + } + if (provider === "aliyun") { + return vk.aliyunOSSUtil.uploadFile(obj); + } + if (title) vk.showLoading(title); + if (errorToast) needAlert = false; + // 生成文件名 + if (!cloudPath) cloudPath = this.createFileName(obj); + let Logger = {}; + if (config.debug) Logger.filePath = filePath; + if (config.debug) Logger.startTime = Date.now(); + let runCloud = myCloud || uniCloudEnvs[env] || uniCloud; + return new Promise((resolve, reject) => { + runCloud.uploadFile({ + filePath: filePath, + cloudPath: cloudPath, + fileType: fileType, + cloudPathAsRealPath, + onUploadProgress: function(progressEvent) { + let percentCompleted = Math.round( + (progressEvent.loaded * 100) / progressEvent.total + ); + if (typeof obj.onUploadProgress == "function") { + obj.onUploadProgress({ + progressEvent, + percentCompleted, + progress: percentCompleted + }); + } + }, + success(res) { + if (config.debug) Logger.result = typeof res == "object" ? JSON.parse(JSON.stringify(res)) : res; + if (title) vk.hideLoading(); + uniCloud.getTempFileURL({ + fileList: [res.fileID], + success(data) { + let { fileID, tempFileURL } = data.fileList[0]; + res.fileID = tempFileURL; + res.url = tempFileURL; + res.file_id = fileID; + if (config.debug) Logger.result.url = tempFileURL; + if (typeof success == "function") success(res); + resolve(res); + if (needSave) { + // 保存文件记录到数据库 + vk.userCenter.addUploadRecord({ + data: { + url: res.url, + name: file.name, + size: file.size, + file_id: res.file_id, + provider, + category_id, + }, + filePath, + fileType, + success: function() { + if (typeof obj.addSuccess == "function") obj.addSuccess(res); + }, + fail: function(res) { + if (typeof obj.addFail === "function") obj.addFail(res); + } + }); + } + } + }); + }, + fail(err) { + if (title) vk.hideLoading(); + if (config.debug) Logger.error = err; + if (errorToast) vk.toast(JSON.stringify(err), "none"); + if (needAlert) { + if (config.debug) vk.alert(JSON.stringify(err)); + } + if (typeof fail == "function") fail(err); + reject(err); + }, + complete() { + if (config.debug) { + Logger.endTime = Date.now(); + Logger.runTime = (Logger.endTime - Logger.startTime); + let colorArr = config.logger.colorArr; + let colorStr = colorArr[counterNum % colorArr.length]; + counterNum++; + console.log("%c--------【开始】【文件上传】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;'); + console.log("【本地文件】: ", Logger.filePath); + console.log("【返回数据】: ", Logger.result); + console.log("【预览地址】: ", Logger.result.fileID); + console.log("【上传耗时】: ", Logger.runTime, "毫秒"); + console.log("【上传时间】: ", vk.pubfn.timeFormat(Logger.startTime, "yyyy-MM-dd hh:mm:ss")); + if (Logger.error) console.error("【error】:", Logger.error); + console.log("%c--------【结束】【文件上传】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;'); + } + if (typeof complete == "function") complete(); + } + }); + }); + } + } + // 云函数普通请求 + runCallFunction(obj = {}) { + let that = this; + let config = that.config; + let { + url, + data, + title, + loading, + isRequest, + name, + complete, + uniCloud: myCloud, + env = "default" + } = obj; + if (title) vk.showLoading(title); + if (loading) vk.setLoading(true, loading); + if (!name) name = config.isTest ? config.testFunctionName : config.functionName; + obj.name = name; + let Logger = {}; + if (config.debug) Logger.params = typeof data == "object" ? JSON.parse(JSON.stringify(data)) : data; + let promiseAction = new Promise(function(resolve, reject) { + if (config.debug) Logger.startTime = Date.now(); + let runCloud = myCloud || uniCloudEnvs[env] || uniCloud; + runCloud.callFunction({ + name: name, + data: { + $url: url, + data: data + }, + success(res = {}) { + that.callFunctionSuccess({ + res: res.result, + params: obj, + Logger, + resolve, + reject + }); + }, + fail(res) { + that.callFunctionFail({ + res, + params: obj, + Logger, + reject, + sysFail: true + }); + }, + complete(res) { + that.callFunctionComplete({ + res, + params: obj, + Logger + }); + } + }); + }); + promiseAction.catch(error => {}); + return promiseAction; + } + + // 云函数url化请求 + runRequest(obj = {}) { + let that = this; + let config = that.config; + let { + url, + data, + title, + loading, + name, + complete + } = obj; + if (typeof obj.needAlert === "undefined") obj.needAlert = true; + if (!name) name = config.isTest ? config.testFunctionName : config.functionName; + obj.name = name; + let requestUrl = config.functionNameToUrl[name]; + let Logger = {}; + if (config.debug) Logger.params = typeof data == "object" ? JSON.parse(JSON.stringify(data)) : data; + let uniIdToken = uni.getStorageSync(config.uniIdTokenKeyName); + let tokenExpired = uni.getStorageSync(config.uniIdTokenExpiredKeyName); + if (title) vk.showLoading(title); + if (loading) vk.setLoading(true, loading); + let promiseAction = new Promise(function(resolve, reject) { + if (config.debug) Logger.startTime = Date.now(); + uni.request({ + method: "POST", + url: requestUrl, + data: { + $url: url, + data: data, + uniIdToken: uniIdToken + }, + success(res = {}) { + that.callFunctionSuccess({ + res: res.data, + params: obj, + Logger, + resolve, + reject + }); + }, + fail(res) { + that.callFunctionFail({ + res, + params: obj, + Logger, + reject, + sysFail: true + }); + }, + complete(res) { + that.callFunctionComplete({ + res, + params: obj, + Logger + }); + } + }); + }); + promiseAction.catch(error => {}); + return promiseAction; + } + + // 云函数请求成功时执行 + callFunctionSuccess(obj) { + let that = this; + let config = that.config; + let { + res = {}, + params, + Logger, + resolve, + reject + } = obj; + let { + title, + loading, + success + } = params; + if (title) vk.hideLoading(); + if (loading) vk.setLoading(false, loading); + if (typeof res.code === "undefined" && typeof res.errCode !== "undefined") res.code = res.errCode; + let code = res.code; + if (config.debug) Logger.result = typeof res == "object" ? JSON.parse(JSON.stringify(res)) : res; + if (code == 0 || res.key == 1 || (code == undefined && res.uid)) { + if (res.vk_uni_token) that.saveToken(res.vk_uni_token); + if (res.userInfo && res.needUpdateUserInfo) that.updateUserInfo(res); + if (typeof success == "function") success(res); + resolve(res); + } else if ([1301, 1302, 30201, 30202, 30203, 30204].indexOf(code) > -1 && res.msg.indexOf("token") > -1) { + // 执行 login 拦截器函数(跳转到页面页面) + if (typeof that.interceptor.login === "function") { + that.interceptor.login({ + res, + params, + vk + }); + } + reject(res); + } else { + that.callFunctionFail({ + res, + params, + Logger, + reject + }); + } + } + + // 云函数请求失败时执行 + callFunctionFail(obj) { + let that = this; + let config = that.config; + let { globalErrorCode = {} } = config; + let { + res = {}, + params, + Logger, + reject, + sysFail + } = obj; + let { + title, + loading, + errorToast, + noAlert, + needAlert, + fail, + } = params; + // 只有是系统异常时才进行重试 + if (params.needRetry) { + if (sysFail || (res.code && [90001].indexOf(res.code) > -1)) { + if (!obj.hookResult || (typeof obj.hookResult === "function" && !obj.hookResult(err))) { + Logger.sysFail = true; + if (typeof params.retry == "function") params.retry(res, params); + return false; + } + } + } + + if (typeof noAlert !== "undefined") needAlert = !noAlert; + if (typeof needAlert === "undefined") { + needAlert = (typeof fail === "function") ? false : true; + } + if (errorToast) needAlert = false; + if (title) vk.hideLoading(); + if (loading) vk.setLoading(false, loading); + let errMsg = ""; + let sysErr = false; + if (typeof res.code !== "undefined") { + if (res.msg) { + errMsg = res.msg; + } else if (res.errMsg) { + errMsg = res.errMsg; + } else if (res.message) { + errMsg = res.message; + } + } else { + sysErr = true; + errMsg = JSON.stringify(res); + } + if (typeof errMsg !== "string") errMsg = JSON.stringify(errMsg); + if (!errMsg) errMsg = ""; + if (res.code >= 90001 && errMsg.indexOf("数据库") > -1) { + sysErr = true; + } else if ([404, 500].indexOf(res.code) > -1 && errMsg.indexOf("云函数") > -1) { + sysErr = true; + } else if ((res.code === 501 && errMsg.indexOf("timeout for 10000ms") > -1) || (res.code === "SYS_ERR" && errMsg.indexOf(": request:ok") > -1)) { + errMsg = globalErrorCode["cloudfunction-unusual-timeout"] || "请求超时,但请求还在执行,请重新进入页面。"; + } else if (typeof errMsg.toLowerCase === "function" && (errMsg.toLowerCase().indexOf("timeout") > -1 || errMsg.toLowerCase().indexOf("etimedout") > -1)) { + sysErr = true; + errMsg = globalErrorCode["cloudfunction-timeout"] || "请求超时,请重试!"; + } else if (errMsg.indexOf("reaches burst limit") > -1) { + errMsg = globalErrorCode["cloudfunction-reaches-burst-limit"] || "系统繁忙,请稍后再试。"; + } else if (res.code === "InternalServerError") { + sysErr = true; + } + let runKey = true; + if (typeof that.interceptor.fail == "function") { + runKey = that.interceptor.fail({ + vk, + res: res, + params: params + }); + if (runKey === undefined) runKey = true; + } + if (runKey) { + Logger.error = res; + if (errorToast) vk.toast(errMsg, "none"); + if (needAlert && vk.pubfn.isNotNull(errMsg)) { + if (sysErr) { + let toastMsg = globalErrorCode["cloudfunction-system-error"] || "网络开小差了!"; + vk.toast(toastMsg, "none"); + } else { + vk.alert(errMsg); + } + } + if (typeof fail == "function") fail(res); + } + if (typeof reject == "function") reject(res); + } + + // 云函数请求完成后执行 + callFunctionComplete(obj) { + let that = this; + let config = that.config; + let { + res = {}, + params, + Logger + } = obj; + let { + name, + url, + isRequest, + complete, + debug: debugLog + } = params; + if (params.needRetry && Logger.sysFail) { + return false; + } + if (typeof debugLog === "undefined") debugLog = config.debug; + if (debugLog) { + Logger.endTime = Date.now(); + if (isRequest) { + Logger.label = "【url化】"; + } else { + Logger.label = ""; + } + Logger.runTime = (Logger.endTime - Logger.startTime); + let colorArr = config.logger.colorArr; + let colorStr = colorArr[counterNum % colorArr.length]; + counterNum++; + let functionType = url.indexOf(".") > -1 ? "云对象" : "云函数"; + console.log(`%c--------【开始】${Logger.label}【${functionType}请求】【${name}】【${url}】--------`, `color: ${colorStr};font-size: 12px;font-weight: bold;`); + console.log("【请求参数】: ", Logger.params); + console.log("【返回数据】: ", Logger.result); + console.log("【总体耗时】: ", Logger.runTime, "毫秒【含页面渲染】"); + console.log("【请求时间】: ", vk.pubfn.timeFormat(Logger.startTime, "yyyy-MM-dd hh:mm:ss")); + if (Logger.error) { + let errorLog = console.warn || console.error; + if (Logger.error.err && Logger.error.err.stack) { + console.error("【Error】: ", Logger.error); + console.error("【Stack】: ", Logger.error.err.stack); + } else { + errorLog("【Error】: ", Logger.error); + } + } + console.log(`%c--------【结束】${Logger.label}【${functionType}请求】【${name}】【${url}】--------`, `color: ${colorStr};font-size: 12px;font-weight: bold;`); + } + if (typeof complete == "function") complete(res); + } + // 生成文件名 + createFileName(obj = {}) { + let { + file, + filePath, + index = 0, + cloudPathRemoveChinese = true, + cloudDirectory + } = obj; + let suffix = this.getFileSuffix(obj); + let oldName = index + "." + suffix; + // 注意:小程序无法获取到 file.name + if (file && file.name) { + let suffixName = file.name.substring(file.name.lastIndexOf(".") + 1); + if (suffixName && suffixName.length < 5) oldName = file.name; + // 只保留["数字","英文",".","-"] + if (cloudPathRemoveChinese) { + oldName = oldName.replace(/[^a-zA-Z.-d]/g, ''); + } + if (oldName.indexOf(".") == 0) oldName = "0" + oldName; + } + let date = new Date(); + let dateYYYYMMDD = vk.pubfn.timeFormat(date, "yyyy/MM/dd"); + let dateTime = date.getTime().toString(); // 时间戳 + // 时间戳后8位 + let dateTimeEnd8 = dateTime.substring(dateTime.length - 8, dateTime.length); + let randomNumber = vk.pubfn.random(8); // 8位随机数 + // 文件路径 + let newFilePath = ""; + if (cloudDirectory) { + // 如果自定义了上传目录,则使用自定义的上传目录 + if (cloudDirectory.lastIndexOf("/") !== cloudDirectory.length-1) { + cloudDirectory = cloudDirectory + "/"; + } + newFilePath = cloudDirectory; + } else { + // 否则,使用年月日作为上传目录 + newFilePath = dateYYYYMMDD + "/"; + } + // 文件名 = 时间戳后8位 - 随机数8位 + 原本文件名 + let fileNickName = dateTimeEnd8 + "-" + randomNumber + "-" + oldName; + // 文件名全称(包含文件路径) = 文件路径 + 文件名 + let fileFullName = newFilePath + fileNickName; + return fileFullName; + } + + getFileSuffix(obj = {}) { + let { + file, + filePath, + suffix = "png" + } = obj; + if (filePath) { + let suffixName = filePath.substring(filePath.lastIndexOf(".") + 1); + if (suffixName && suffixName.length < 5) suffix = suffixName; + } + if (file) { + if (file.path) { + let suffixName = file.path.substring(file.path.lastIndexOf(".") + 1); + if (suffixName && suffixName.length < 5) suffix = suffixName; + } + if (file.name) { + let suffixName = file.name.substring(file.name.lastIndexOf(".") + 1); + if (suffixName && suffixName.length < 5) suffix = suffixName; + } + } + return suffix; + } + getFileType(obj = {}) { + let { + file, + filePath + } = obj; + let fileType = "other"; + let suffix = this.getFileSuffix(obj); + if (["png", "jpg", "jpeg", "gif", "bmp", "svg", "webp"].indexOf(suffix) > -1) { + fileType = "image"; + } else if (["avi", "mp3", "mp4", "3gp", "mov", "rmvb", "rm", "flv", "mkv"].indexOf(suffix) > -1) { + fileType = "video"; + } + return fileType; + } + + // 系统异常重试机制(表单提交时慎用,建议只用在查询请求中,即无任何数据库修改的请求中) + callFunctionRetry(obj = {}) { + let { retryCount } = obj; + delete obj.retryCount; + return new Promise((resolve, reject) => { + this.callRetryFn(obj, resolve, reject, retryCount); + }); + } + // 重试实现 + callRetryFn(obj, resolve, reject, retryCount) { + let that = this; + let debug = that.config.debug; + that.callFunction({ + ...obj, + needRetry: retryCount ? true : false, // 判断是否需要重试 + retry: function(err) { + obj.runCount = obj.runCount ? obj.runCount + 1 : 1; + obj.needRetry = retryCount > obj.runCount ? true : false; // 判断是否需要重试 + let errorMsg = err.message ? `异常信息:${err.message}` : ""; + if (debug) console.log(`【请求失败】正在第【${obj.runCount}】次重试:${obj.url}`); + if (obj.retryInterval) { + setTimeout(function() { + that._callRetryFn(obj, resolve, reject, retryCount); + }, obj.retryInterval); + } else { + // 如果无延迟,则不写setTimeout,因为setTimeout 即使time为0,也有一定延迟。 + that._callRetryFn(obj, resolve, reject, retryCount); + } + } + }); + } + + _callRetryFn(obj, resolve, reject, retryCount) { + if (obj.runCount < retryCount) { + this.callRetryFn(obj, resolve, reject, retryCount); + } else { + this.callFunction(obj).catch((err) => { + reject(); + }); + } + } + + +} + +export default new CallFunctionUtil diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/vk-unicloud/vk-unicloud-user-center.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/vk-unicloud/vk-unicloud-user-center.js new file mode 100644 index 0000000..770fc31 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/vk-unicloud/vk-unicloud-user-center.js @@ -0,0 +1,1068 @@ +/** + * unicloud-user-center 接口类(uni-id封装) + * author VK + */ +import callFunctionUtil from './vk-unicloud-callFunctionUtil.js' +var { callFunction, config, saveToken, deleteToken } = callFunctionUtil; +import debounce from '../function/debounce.js' + +const debounceTime = 1000; // 防抖时长 + +const localeObj = { + "zh-Hans": { + "loading": "请求中...", + "login": "登录中...", + "register": "注册中...", + "create": "生成中...", + }, + "zh-Hant": { + "loading": "請求中...", + "login": "登入中...", + "register": "注册中...", + "create": "生成中...", + }, + "en": { + "loading": "loading...", + "login": "login...", + "register": "register...", + "create": "create...", + } +}; + +function addLoading(obj, title) { + if (typeof obj.loading === "undefined" && !obj.title && title) { + let locale; + if (typeof uni.vk !== "undefined") { + locale = localeObj[uni.vk.pubfn.getLocale()]; + } else { + locale = localeObj["zh-Hans"]; + } + obj.title = locale[title] || "loading..."; + } + return obj; +} + +export default { + /** + * 用户注册(用户名+密码) + * data 请求参数 说明 + * @param {String} username 用户名 + * @param {String} password 密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 注册完成自动登录之后返回的token信息 + * @param {String} tokenExpired token过期时间 + * @param {Object} userInfo 用户信息 + * @param {String} uid 用户ID + */ + register(obj = {}) { + return debounce(() => { + addLoading(obj, "register"); + return callFunction({ + ...obj, + url: 'user/pub/register' + }); + }, debounceTime, true, "login"); + }, + /** + * 用户登录(用户名+密码) + * data 请求参数 说明 + * @param {String} username 用户名 + * @param {String} password 密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 注册完成自动登录之后返回的token信息 + * @param {String} tokenExpired token过期时间 + * @param {Object} userInfo 用户信息 + * @param {String} uid 用户ID + */ + login(obj = {}) { + addLoading(obj, "login"); + return callFunction({ + ...obj, + url: 'user/pub/login' + }); + }, + /** + * 登出(退出) + * data 请求参数 说明 + * 无 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + logout(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/pub/logout', + success(res) { + deleteToken(); + if (typeof obj.success == "function") obj.success(res); + } + }); + }, + /** + * 修改密码 + * @description 修改成功后,需要重新登录获取新的token + * data 请求参数 说明 + * @param {String} oldPassword 旧密码 + * @param {String} newPassword 新密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + updatePwd(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/updatePwd', + }); + }, + /** + * 重置密码 + * data 请求参数 说明 + * @param {String} password 重置后的密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + resetPwd(obj) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/resetPwd', + }); + }, + /** + * 设置头像 + * data 请求参数 说明 + * @param {String} avatar 头像地址 + * @param {Boolean} deleteOldFile 是否同时删除云储存内的头像文件 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + setAvatar(obj = {}) { + addLoading(obj, "loading"); + //obj.isRequest = true; + return callFunction({ + ...obj, + url: 'user/kh/setAvatar', + }); + }, + /** + * 设置昵称等用户展示的个人信息 + * data 请求参数 说明 + * @param {String} nickname 昵称 + * @param {String} avatar 头像 + * @param {Number} gender 性别 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + updateUser(obj = {}) { + addLoading(obj, "loading"); + callFunction({ + ...obj, + url: 'user/kh/updateUser' + }); + }, + /** + * 获取用户最新信息 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 错误信息 + * @param {Object} userInfo 用户信息 + */ + getCurrentUserInfo(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/getMyUserInfo', + }); + }, + /** + * token校验 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} uid 当前token对应的用户uid + * @param {Object} userInfo 当前用户信息 + * @param {Array} role 当前用户角色 + * @param {Array} permission 当前用户权限 + */ + checkToken(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/pub/checkToken', + }); + }, + /** + * 绑定手机号 + * data 请求参数 说明 + * @param {String} mobile 手机号 + * @param {String} code 手机收到的验证码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + bindMobile(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/bindMobile', + }); + }, + /** + * 解绑手机号 + * data 请求参数 说明 + * @param {String} mobile 手机号 + * @param {String} code 手机收到的验证码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + unbindMobile(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/unbindMobile', + }); + }, + /** + * 绑定新的手机号(换绑手机号) + * data 请求参数 说明 + * @param {String} oldMobile 旧手机号码 + * @param {String} oldMobileCode 旧手机收到的验证码 + * @param {String} mobile 新手机号码 + * @param {String} code 新手机收到的验证码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + bindNewMobile(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/bindNewMobile', + }); + }, + /** + * 手机号登录(手机号+手机验证码) + * data 请求参数 说明 + * @param {String} mobile 手机号 + * @param {String} code 验证码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 注册完成自动登录之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + loginBySms(obj = {}) { + return debounce(() => { + addLoading(obj, "login"); + return callFunction({ + url: 'user/pub/loginBySms', + ...obj + }); + }, debounceTime, true, "login"); + }, + /** + * 发送手机号验证码 + * data 请求参数 说明 + * @param {String} mobile 手机号 + * @param {String} type 验证码类型 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {Object} requestRes 原始返回数据 + * @param {Object} requestParam 包含服务供应商和发送的手机号 + */ + sendSmsCode(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/pub/sendSmsCode', + }); + }, + /** + * APP端 手机一键登录 + * data 请求参数 说明 + * @param {String} access_token uni.login登录成功后,返回的access_token参数 + * @param {String} openid uni.login登录成功后,返回的openid参数 + * @param {String} type 指定操作类型,可选值为login、register,不传此参数时表现为手机号已注册则登录,手机号未注册则进行注册 + * @param {String} password 密码,type为register时生效 + * @param {String} inviteCode 邀请人的邀请码,type为register时生效 + * @param {String} myInviteCode 设置当前注册用户自己的邀请码,type为register时生效 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} uid 当前token对应的用户uid + * @param {String} type 操作类型,login为登录、register为注册 + * @param {String} mobile 登录者手机号 + * @param {String} userInfo 用户全部信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + loginByUniverify(obj = {}) { + addLoading(obj, "login"); + if (typeof obj.needAlert === "undefined") obj.needAlert = true; + // #ifdef APP-PLUS + uni.login({ + provider: 'univerify', + univerifyStyle: obj.univerifyStyle, + success(res) { + let dataJson = Object.assign(obj.data, res.authResult); + callFunction({ + url: 'user/pub/loginByUniverify', + ...obj, + data: dataJson, + }); + }, + fail: obj.fail, + complete: (res) => { + uni.vk.hideLoading(); + } + }); + // #endif + // #ifndef APP-PLUS + uni.vk.toast("请在APP中使用本机号码一键登录", "none"); + // #endif + }, + + /** + * 绑定邮箱 + * data 请求参数 说明 + * @param {String} email 邮箱 + * @param {String} code 邮箱收到的验证码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + bindEmail(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/bindEmail', + }); + }, + /** + * 解绑邮箱 + * @param {String} email 邮箱 + * @param {String} code 邮箱收到的验证码 + */ + unbindEmail(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/unbindEmail', + }); + }, + /** + * 绑定新的邮箱(换绑邮箱) + * @param {String} oldEmail 旧邮箱码 + * @param {String} oldEmailCode 旧邮箱收到的验证码 + * @param {String} email 新邮箱码 + * @param {String} code 新邮箱收到的验证码 + */ + bindNewEmail(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/bindNewEmail', + }); + }, + /** + * 邮箱登录(邮箱+邮箱验证码) + * data 请求参数 说明 + * @param {String} email 邮箱 + * @param {String} code 邮箱收到的验证码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 注册完成自动登录之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + loginByEmail(obj = {}) { + addLoading(obj, "login"); + return callFunction({ + url: 'user/pub/loginByEmail', + ...obj + }); + }, + /** + * 发送邮件验证码 + * data 请求参数 说明 + * @param {String} email 邮箱 + * @param {String} type 验证码类型 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} email 手机号 + * @param {String} verifyCode 验证码 + */ + sendEmailCode(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/pub/sendEmailCode', + }); + }, + /** + * 根据邮箱+验证码重置密码 + * data 请求参数 说明 + * @param {String} password 重置后的密码 + * @param {String} code 验证码 + * @param {String} email 邮箱号码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + resetPasswordByEmail(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/pub/resetPasswordByEmail', + }); + }, + /** + * 设置验证码 + * @description 设置验证码(此接口正式环境不要暴露,故写在了sys目录下) + * data 请求参数 说明 + * @param {String} email 邮箱 + * @param {String} mobile 手机号 + * @param {String} type 验证码类型 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} email 邮箱 + * @param {String} mobile 手机号 + * @param {String} verifyCode 验证码(uni 1.1.2开始不再返回verifyCode) + */ + setVerifyCode(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/sys/setVerifyCode', + }); + }, + /** + * 微信登录获取用户code + */ + getWeixinCode() { + return new Promise((resolve, reject) => { + // #ifdef MP-WEIXIN + uni.login({ + provider: 'weixin', + success(res) { + resolve(res.code) + }, + fail(err) { + reject(new Error('微信登录失败')) + } + }) + // #endif + // #ifdef APP-PLUS + plus.oauth.getServices((services) => { + let weixinAuthService = services.find((service) => { + return service.id === 'weixin'; + }); + if (weixinAuthService) { + weixinAuthService.authorize(function(res) { + resolve(res.code); + }, function(err) { + console.log(err); + reject(new Error('微信登录失败')); + }); + } + }); + // #endif + // #ifdef H5 + resolve(); + // #endif + }) + }, + /** + * 用户登录(微信授权) + * @description 用户登录(微信授权) + * data 请求参数 说明 + * @param {String} code 微信登录返回的code + * @param {String} platform 客户端类型:mp-weixin、app-plus,默认uni-id会自动取客户端类型,但是在云函数url化等场景无法取到客户端类型,可以使用此参数指定 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + loginByWeixin(obj = {}) { + let that = this; + debounce(() => { + addLoading(obj, "login"); + let { data = {} } = obj; + that.getWeixinCode().then((code) => { + // #ifdef H5 + // H5平台需要区分环境(如微信公众号?网页H5?) + data.vk_platform = uni.vk.h5.getEnv(); + // #endif + callFunction({ + url: 'user/pub/loginByWeixin', + ...obj, + data: { + code, + ...data + } + }); + }); + }, debounceTime, true, "login"); + }, + /** + * 获取微信openid + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} openid 用户openid + * @param {String} unionid 用户unionid,可以取到此值时返回 + * @param {String} sessionKey 客户端为微信小程序时返回 + * @param {String} accessToken 客户端为APP时返回 + * @param {String} expiresIn 客户端为APP时返回,accessToken 接口调用凭证超时时间,单位(秒) + * @param {String} refreshToken 客户端为APP时返回,用于刷新accessToken + */ + code2SessionWeixin(obj = {}) { + let that = this; + addLoading(obj, "loading"); + let { data = {} } = obj; + that.getWeixinCode().then((code) => { + callFunction({ + ...obj, + url: 'user/pub/code2SessionWeixin', + data: { + code, + ...data, + } + }); + }); + }, + /** + * 绑定微信 + * @description 将当前登录用户绑定微信 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + bindWeixin(obj = {}) { + let that = this; + addLoading(obj, "loading"); + let { data = {} } = obj; + that.getWeixinCode().then((code) => { + // #ifdef H5 + // H5平台需要区分环境(如微信公众号?网页H5?) + data.vk_platform = uni.vk.h5.getEnv(); + // #endif + callFunction({ + ...obj, + url: 'user/kh/bindWeixin', + data: { + code, + ...data + } + }); + }); + }, + /** + * 解绑微信 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + unbindWeixin(obj = {}) { + addLoading(obj, "loading"); + let { data = {} } = obj; + // #ifdef H5 + // H5平台需要区分环境(如微信公众号?网页H5?) + data.vk_platform = uni.vk.h5.getEnv(); + obj.data = data; + // #endif + return callFunction({ + ...obj, + url: 'user/kh/unbindWeixin', + }); + }, + /** + * 获取微信绑定的手机号(后面会支持支付宝) + * data 请求参数 + * @param {String} encryptedData + * @param {String} iv + * @param {String} sessionKey + */ + getPhoneNumber(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/pub/getPhoneNumber' + }); + }, + /** + * 通过微信小程序绑定的手机号登录 + * data 请求参数 说明 + * @param {String} encryptedData + * @param {String} iv + * @param {String} sessionKey + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + loginByWeixinPhoneNumber(obj = {}) { + return debounce(() => { + addLoading(obj, "login"); + return callFunction({ + url: 'user/pub/loginByWeixinPhoneNumber', + ...obj + }); + }, debounceTime, true, "login"); + }, + /** + * 生成微信小程序码 + * @param {String} scene 自定义参数最大32个可见字符 只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~ + * @param {String} page 必须是已经发布的小程序存在的页面(否则报错),例如 pages/index/index, 根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面 + * @param {number} width 二维码的宽度,单位 px,最小 280px,最大 1280px + * @param {boolean} auto_color 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调,默认 false + * @param {Object} line_color auto_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} 十进制表示 + * @param {boolean} is_hyaline 是否需要透明底色,为 true 时,生成透明底色的小程序 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + getWeixinMPqrcode(obj = {}) { + addLoading(obj, "create"); + return callFunction({ + ...obj, + url: 'user/kh/getWeixinMPqrcode', + }); + }, + /** + * 生成微信小程序scheme码 + * data 请求参数 说明 + * @param {String} path 小程序页面路径 + * @param {String} query 小程序页面参数 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + getWeixinMPscheme(obj = {}) { + addLoading(obj, "create"); + return callFunction({ + ...obj, + url: 'user/kh/getWeixinMPscheme', + }); + }, + /** + * 生成微信小程序url链接 + * data 请求参数 说明 + * @param {String} path 小程序页面路径 + * @param {String} query 小程序页面参数 + * @param {String} env_version 默认值"release"。要打开的小程序版本。正式版为 "release",体验版为"trial",开发版为"develop",仅在微信外打开时生效 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + getWeixinMPurl(obj = {}) { + addLoading(obj, "create"); + return callFunction({ + ...obj, + url: 'user/kh/getWeixinMPurl', + }); + }, + /** + * 获取支付宝code + */ + getAlipayCode() { + // #ifdef APP-PLUS || MP-ALIPAY + return new Promise((resolve, reject) => { + uni.login({ + provider: 'alipay', + success(res) { + resolve(res.code); + }, + fail(err) { + reject(new Error('支付宝登录失败')); + } + }); + }); + // #endif + }, + /** + * 支付宝登录 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + loginByAlipay(obj = {}) { + let that = this; + debounce(() => { + addLoading(obj, "login"); + let { data = {} } = obj; + that.getAlipayCode().then((code) => { + callFunction({ + url: 'user/pub/loginByAlipay', + ...obj, + data: { + ...data, + code: code + } + }); + }); + }, debounceTime, true, "login"); + }, + /** + * 获取支付宝openid + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} openid 用户openid + * @param {String} accessToken 客户端为APP时返回 + * @param {String} expiresIn 客户端为APP时返回,accessToken 接口调用凭证超时时间,单位(秒) + * @param {String} refreshToken 客户端为APP时返回,用于刷新accessToken + * @param {String} reExpiresIn refreshToken超时时间,单位(秒) + */ + code2SessionAlipay(obj = {}) { + let that = this; + addLoading(obj, "loading"); + let { data = {} } = obj; + that.getAlipayCode().then((code) => { + callFunction({ + ...obj, + url: 'user/pub/code2SessionAlipay', + data: { + ...data, + code: code + } + }); + }); + }, + /** + * 绑定支付宝 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + bindAlipay(obj = {}) { + let that = this; + addLoading(obj, "loading"); + let { data = {} } = obj; + that.getAlipayCode().then((code) => { + callFunction({ + ...obj, + url: 'user/kh/bindAlipay', + data: { + ...data, + code: code + } + }); + }); + }, + /** + * 解绑支付宝 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + unbindAlipay(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/unbindAlipay', + }); + }, + /** + * 生成支付宝小程序码 + * @param {String} page 必须是已经发布的小程序存在的页面(否则报错),例如 pages/index/index, 根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面 + * @param {String} scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + getAlipayMiniCode(obj = {}) { + addLoading(obj, "create"); + return callFunction({ + ...obj, + url: 'user/kh/getAlipayMiniCode', + }); + }, + /** + * 密码加密测试(暂不用) + */ + encryptPwd(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/sys/encryptPwd', + }); + }, + // 1.1.2新增 + /** + * 设置用户邀请码(自动生成) + * @description 针对未生成邀请码的用户使用此方法生成邀请码(自动生成) + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} myInviteCode 最终设置的邀请码 + */ + setUserInviteCode(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/setUserInviteCode', + }); + }, + /** + * 用户接受邀请 + * @description 此接口用于在注册之后再填写邀请码的场景,多数情况下不会用到此接口而是在注册时填写邀请码 + * data 请求参数 说明 + * @param {String} inviteCode 邀请人的邀请码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + acceptInvite(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/acceptInvite', + }); + }, + /** + * 获取接受邀请的用户清单 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + getInvitedUser(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/getInvitedUser', + }); + }, + /** + * 根据手机验证码重置账号密码 + * data 请求参数 说明 + * @param {String} password 重置后的密码 + * @param {String} code 验证码 + * @param {String} mobile 手机号 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + resetPasswordByMobile(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/pub/resetPasswordByMobile', + }); + }, + /** + * 获取我拥有的菜单列表 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} menus 树形结构的菜单 + * @param {String} menuList 数组结构的菜单 + * @param {String} userInfo 用户信息 + */ + getMenu(obj = {}) { + return callFunction({ + ...obj, + url: 'user/kh/getMenu' + }); + }, + /** + * 添加文件上传记录 + * data 请求参数 说明 + * @param {String} url 文件外网访问url + * @param {String} name 文件名 + * @param {Number} size 文件大小 + * @param {String} file_id 文件id + * @param {String} provider 供应商 + * @param {String} category_id 分类ID + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + addUploadRecord(obj = {}) { + let { fileType, filePath } = obj; + if (fileType === "image") { + uni.getImageInfo({ + src: filePath, + success: function(res) { + return callFunction({ + ...obj, + url: 'user/kh/addUploadRecord', + data: { + ...obj.data, + orientation: res.orientation, + width: res.width, + height: res.height + } + }); + }, + fail: function(err) { + console.error(err) + } + }); + } else if (fileType === "video") { + uni.getVideoInfo({ + src: filePath, + success: function(res) { + return callFunction({ + ...obj, + url: 'user/kh/addUploadRecord', + data: { + ...obj.data, + duration: parseFloat(res.duration.toFixed(3)), + width: res.width, + height: res.height + } + }); + }, + fail: function(err) { + console.error(err) + } + }); + } else { + return callFunction({ + ...obj, + url: 'user/kh/addUploadRecord' + }); + } + }, + /** + * 获取QQ code + */ + getQQCode() { + // #ifdef APP-PLUS || MP-QQ + return new Promise((resolve, reject) => { + uni.login({ + provider: 'qq', + success(res) { + // #ifdef APP-PLUS + resolve({ + accessToken: res.authResult.access_token, + }) + // #endif + // #ifdef MP-QQ + resolve({ + code: res.code, + }) + // #endif + }, + fail(err) { + reject(new Error('QQ登录失败')); + } + }); + }); + // #endif + }, + /** + * QQ登录 + * data 请求参数 说明 + * @param {String} type 可传login或register,若为login:则不存在不会自动注册,若为register,则用户存在会报错,不传,则存在自动登录,不存在,则注册。 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + loginByQQ(obj = {}) { + let that = this; + debounce(() => { + addLoading(obj, "login"); + let { data = {} } = obj; + that.getQQCode().then(({ code, accessToken } = {}) => { + callFunction({ + url: 'user/pub/loginByQQ', + ...obj, + data: { + ...data, + code, + accessToken + } + }); + }); + }, debounceTime, true, "login"); + }, + /** + * 绑定QQ + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + bindQQ(obj = {}) { + let that = this; + addLoading(obj, "loading"); + let { data = {} } = obj; + that.getQQCode().then(({ code, accessToken } = {}) => { + callFunction({ + ...obj, + url: 'user/kh/bindQQ', + data: { + ...data, + code, + accessToken + } + }); + }); + }, + /** + * 解绑QQ + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + unbindQQ(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/unbindQQ', + }); + }, + /** + * 生成qq小程序码 + * @param {String} path 必须是已经发布的小程序存在的页面(否则报错),例如 pages/index/index, 根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + getQQMiniCode(obj = {}) { + addLoading(obj, "create"); + return callFunction({ + ...obj, + url: 'user/kh/getQQMiniCode', + }); + }, + /** + * App升级中心 - 检测是当前版本是否需要升级 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + checkVersion(obj = {}) { + return callFunction({ + ...obj, + url: 'user/pub/checkVersion', + }); + }, +}; diff --git a/uni_modules/vk-uview-ui/changelog.md b/uni_modules/vk-uview-ui/changelog.md new file mode 100644 index 0000000..bd9bffa --- /dev/null +++ b/uni_modules/vk-uview-ui/changelog.md @@ -0,0 +1,150 @@ +## 1.5.1(2023-10-13) +* 【修复】`u-parse` 在小程序上部分情况下不显示图片的问题 +* 【修复】`u-alert-tips` 使用 `closeText` 时 `close` 事件无效的问题 & 样式微调 +## 1.5.0(2023-06-01) +* 【修复】`u-parse` 在vue3真机白屏问题和h5样式污染问题 +* 【修复】`u-select` 默认值的问题 +* 【修复】`u-parse` 在app和微信小程序中 `preview` 属性不生效的问题 +## 1.4.8(2023-05-17) +* 【优化】部分组件属性的可选值的代码提示 +* 【优化】`u-circle-progres` 组件 在进度条到100%的时候发出一个 `finish` 事件 +* 【修复】`u-picker` 的时间选择器在ios下默认值无效的bug +* 【修复】`u-card` 圆角问题 +* 【修复】`u-button` 支持 `info` 类型 +## 1.4.7(2023-04-24) +* 【修复】`u-picker` 在vue3的App环境下默认值无效的bug +## 1.4.5(2022-12-05) +* 【修复】`u-row`、`u-col` 使用 `@click.stop` 会报错的问题,同时建议改用 `@click.native.stop` 来代替 `@click.stop` +## 1.4.4(2022-11-12) +* 【修复】`u-calendar` `u-modal` `u-picker` `u-popup` 组件在页面进入后马上需要弹窗时,无法正常弹窗的问题。 +## 1.4.3(2022-10-22) +* 【优化】部分组件的细节 +## 1.4.2(2022-10-15) +* 【修复】`1.4.1` 引出的 `u-subsection` 的部分问题 +## 1.4.1(2022-10-14) +* 【修复】`u-count-to` 若设置了千分位符合,会错误显示-的问题 +* 【修复】`u-subsection` 部分细节问题 +## 1.4.0(2022-10-07) +* 【修复】`u-section` 点击更多,会触发两次事件的问题 +* 【修复】`loadMore` 加载更多,icon-type为circle不会转动的问题 +* 【修复】`u-subsection` current 有转入值时,变更值,样式不更新(需用 `v-model="current"` 代替 `:current="current"`) +## 1.3.13(2022-09-28) +* 【修复】`u-avatar-cropper` 组件在vue3中会报错的问题。 +## 1.3.12(2022-08-30) +* 【优化】`u-keyboard` 组件内部细节。 +## 1.3.11(2022-08-30) +* 【修复】`u-subsection` 组件的 `list` 属性不支持动态修改的问题。 +## 1.3.10(2022-07-30) +* 【优化】上传组件部分细节 +## 1.3.9(2022-07-07) +* 【更新】省市区数据源 +* 【优化】`u-subsection` 组件支持在右上角显示数字角标 +```html + +``` + +```js +export default { + data() { + return { + list: [ + { + name: '待发货', + num: 10 + }, + { + name: '待付款', + num: 5 + }, + { + name: '待评价', + num: 15 + } + ] + } + } +} +``` +## 1.3.8(2022-06-13) +* 【优化】组件 `u-icon`,使之更方便的兼容第三方icon(满足规则自动计算customPrefix) +**规则如下:** +* 当 `name` 中包含 `-icon-` 字符串时 +* 如 `vk-icon-goods`,则组件的 `customPrefix` 属性自动识别为 `vk-icon` ,`name`属性 自动识别为 `goods` +* 如 `vk-2-icon-goods-list`,则组件的 `customPrefix` 属性自动识别为 `vk-2-icon` ,`name`属性 自动识别为 `goods-list` +## 1.3.7(2022-06-10) +* 【优化】组件 `u-action-sheet` `u-calendar` `u-dropdown-item` `u-field` `u-input` `u-keyboard` `u-modal` `u-radio-group` `u-rate` `u-search` `u-slider` `u-switch` `u-tabbar` `u-waterfall` 在 `vue3` 模式下的细节问题。 +## 1.3.6(2022-06-10) +* 【优化】组件 `u-action-sheet` `u-calendar` `u-dropdown-item` `u-field` `u-input` `u-keyboard` `u-modal` `u-radio-group` `u-rate` `u-search` `u-slider` `u-switch` `u-tabbar` `u-waterfall` 在 `vue3` 模式下的细节问题。 +## 1.3.5(2022-05-28) +* 【优化】组件 `u-mask` `u-popup` `u-select` `u-modal` `u-keyboard` `u-calendar` `u-action-sheet` `u-picker` 均新增 `blur` 属性,可用于设置弹出遮罩的模糊度,默认为0(不模糊) +* ![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/49b773a3-273f-4b1c-95e8-a42dcba1a53c.png) +## 1.3.4(2022-05-03) +* 【修复】`u-tabs` 组件细节问题。 +## 1.1.4(2022-03-22) +* 【修复】`u-field` 组件 `arrowDirection` 属性无效的问题。 +## 1.1.3(2022-03-21) +* 【优化】部分细节。 +## 1.1.2(2022-03-21) +* 【优化】部分细节。 +## 1.1.1(2022-03-17) +* 【优化】部分细节。 +## 1.1.0(2022-03-12) +* 【重要】`u-picker` 组件新增 `regionDiscern` 方法 智能识别省市区街道地址 +如将字符串 `浙江省杭州市西湖区希望路1333弄是啊我庭12号楼1203` 中识别为 +```json +{ + "province": { + "code": "330000", + "name": "浙江省" + }, + "city": { + "code": "330100", + "name": "杭州市" + }, + "area": { + "code": "330106", + "name": "西湖区" + }, + "address": "龙井路1号", + "formatted_address": "浙江省杭州市西湖区龙井路1号" +} +``` +而组件的 `addressDiscern` 方法还可以识别收货信息,如 `张三 13888888888 上海市嘉定区希望路1333弄是啊我庭12号楼1203` 中识别姓名、手机号、地址(支持多种格式) +## 1.0.13(2022-03-12) +* 【优化】部分细节。 +## 1.0.12(2022-03-09) +* 【修复】`u-radio-group` 在 vue3 模式下,设置默认值可能会无效的问题。 +## 1.0.11(2022-03-07) +* 【优化】部分细节。 +## 1.0.10(2022-03-05) +* 【修复】`u-radio` 中的值相等的判断 == 改为 === +* 【优化】部分注释的错别字。 +## 1.0.9(2022-03-03) +* 【修复】`u-parse` 在 vue3模式下编译到app无法正常显示的问题。 +## 1.0.8(2022-02-26) +* 【优化】`u-form` 组件新增2个属性 `inputAlign` 和 `clearable` 用于统一设置表单内所有 `u-input` 组件的对应属性默认值 +* 【优化】更新城市数据源信息 +## 1.0.7(2022-02-25) +* 【重要】`u-picker` 组件新增 `addressDiscern` 方法 智能识别收货信息 + +如在 `张三 13888888888 上海市嘉定区希望路1333弄是啊我庭12号楼1203` 中识别姓名、手机号、地址(支持多种格式) +即使这样的字符串也能识别 `!!!!~~~$张三~~~上海市嘉定区希望路1333弄是啊我庭12号楼1203【【【【13888888888】` +## 1.0.6(2022-02-24) +* 【优化】`u-form-item` 组件的 `prop` 属性支持 a.b 形式 +## 1.0.5(2022-01-11) +* 【修复】`u-sticky` 组件 在微信小程序中无法正常吸顶的问题 +## 1.0.4(2021-12-31) +* 【优化】`u-dropdown-item` 组件 0和"" 无法区分的问题。 +* 【修复】`u-modal` 在Vue3版本中使用了mask-close-able属性无效的问题 +## 1.0.3(2021-12-20) +【优化】u-icon在微信小程序下可能会显示null字符串的问题 +## 1.0.2(2021-12-09) +* 1、【优化】`u-button` 组件新增 `timerId` 属性 +* 之前的效果是:所有按钮一定时间内只能点击1次(`共用计算时间`)导致点击按钮A后无法马上点击按钮B +* 优化的效果是:每个按钮一定时间内只能点击1次(`分开计算时间`)且支持设置相同的 timerId 来达到指定按钮 `共用计算时间` +## 1.0.1(2021-11-22) +* 修复 u-parse 组件在微信小程序上的显示问题。 +## 1.0.0(2021-11-18) +uView Vue3.0 横空出世,继承uView1.0意志,再战江湖,风云再起!by vk 2021-11-18 diff --git a/uni_modules/vk-uview-ui/components/u-action-sheet/u-action-sheet.vue b/uni_modules/vk-uview-ui/components/u-action-sheet/u-action-sheet.vue new file mode 100644 index 0000000..c5261a1 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-action-sheet/u-action-sheet.vue @@ -0,0 +1,246 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-alert-tips/u-alert-tips.vue b/uni_modules/vk-uview-ui/components/u-alert-tips/u-alert-tips.vue new file mode 100644 index 0000000..5adeefd --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-alert-tips/u-alert-tips.vue @@ -0,0 +1,260 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue b/uni_modules/vk-uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue new file mode 100644 index 0000000..a48dd54 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue @@ -0,0 +1,290 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-avatar-cropper/weCropper.js b/uni_modules/vk-uview-ui/components/u-avatar-cropper/weCropper.js new file mode 100644 index 0000000..6dac900 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-avatar-cropper/weCropper.js @@ -0,0 +1,1256 @@ +/** + * we-cropper v1.3.9 + * (c) 2020 dlhandsome + * @license MIT + */ +'use strict'; + +var device = void 0; +var TOUCH_STATE = ['touchstarted', 'touchmoved', 'touchended']; + +function firstLetterUpper(str) { + return str.charAt(0).toUpperCase() + str.slice(1) +} + +function setTouchState(instance) { + var arg = [], + len = arguments.length - 1; + while (len-- > 0) arg[len] = arguments[len + 1]; + + TOUCH_STATE.forEach(function(key, i) { + if (arg[i] !== undefined) { + instance[key] = arg[i]; + } + }); +} + +function validator(instance, o) { + Object.defineProperties(instance, o); +} + +function getDevice() { + if (!device) { + device = uni.getSystemInfoSync(); + } + return device +} + +var tmp = {}; + +var ref = getDevice(); +var pixelRatio = ref.pixelRatio; + +var DEFAULT = { + id: { + default: 'cropper', + get: function get() { + return tmp.id + }, + set: function set(value) { + if (typeof(value) !== 'string') { + console.error(("id:" + value + " is invalid")); + } + tmp.id = value; + } + }, + width: { + default: 750, + get: function get() { + return tmp.width + }, + set: function set(value) { + if (typeof(value) !== 'number') { + console.error(("width:" + value + " is invalid")); + } + tmp.width = value; + } + }, + height: { + default: 750, + get: function get() { + return tmp.height + }, + set: function set(value) { + if (typeof(value) !== 'number') { + console.error(("height:" + value + " is invalid")); + } + tmp.height = value; + } + }, + pixelRatio: { + default: pixelRatio, + get: function get() { + return tmp.pixelRatio + }, + set: function set(value) { + if (typeof(value) !== 'number') { + console.error(("pixelRatio:" + value + " is invalid")); + } + tmp.pixelRatio = value; + } + }, + scale: { + default: 2.5, + get: function get() { + return tmp.scale + }, + set: function set(value) { + if (typeof(value) !== 'number') { + console.error(("scale:" + value + " is invalid")); + } + tmp.scale = value; + } + }, + zoom: { + default: 5, + get: function get() { + return tmp.zoom + }, + set: function set(value) { + if (typeof(value) !== 'number') { + console.error(("zoom:" + value + " is invalid")); + } else if (value < 0 || value > 10) { + console.error("zoom should be ranged in 0 ~ 10"); + } + tmp.zoom = value; + } + }, + src: { + default: '', + get: function get() { + return tmp.src + }, + set: function set(value) { + if (typeof(value) !== 'string') { + console.error(("src:" + value + " is invalid")); + } + tmp.src = value; + } + }, + cut: { + default: {}, + get: function get() { + return tmp.cut + }, + set: function set(value) { + if (typeof(value) !== 'object') { + console.error(("cut:" + value + " is invalid")); + } + tmp.cut = value; + } + }, + boundStyle: { + default: {}, + get: function get() { + return tmp.boundStyle + }, + set: function set(value) { + if (typeof(value) !== 'object') { + console.error(("boundStyle:" + value + " is invalid")); + } + tmp.boundStyle = value; + } + }, + onReady: { + default: null, + get: function get() { + return tmp.ready + }, + set: function set(value) { + tmp.ready = value; + } + }, + onBeforeImageLoad: { + default: null, + get: function get() { + return tmp.beforeImageLoad + }, + set: function set(value) { + tmp.beforeImageLoad = value; + } + }, + onImageLoad: { + default: null, + get: function get() { + return tmp.imageLoad + }, + set: function set(value) { + tmp.imageLoad = value; + } + }, + onBeforeDraw: { + default: null, + get: function get() { + return tmp.beforeDraw + }, + set: function set(value) { + tmp.beforeDraw = value; + } + } +}; + +var ref$1 = getDevice(); +var windowWidth = ref$1.windowWidth; + +function prepare() { + var self = this; + + // v1.4.0 版本中将不再自动绑定we-cropper实例 + self.attachPage = function() { + var pages = getCurrentPages(); + // 获取到当前page上下文 + var pageContext = pages[pages.length - 1]; + // 把this依附在Page上下文的wecropper属性上,便于在page钩子函数中访问 + Object.defineProperty(pageContext, 'wecropper', { + get: function get() { + console.warn( + 'Instance will not be automatically bound to the page after v1.4.0\n\n' + + 'Please use a custom instance name instead\n\n' + + 'Example: \n' + + 'this.mycropper = new WeCropper(options)\n\n' + + '// ...\n' + + 'this.mycropper.getCropperImage()' + ); + return self + }, + configurable: true + }); + }; + + self.createCtx = function() { + var id = self.id; + var targetId = self.targetId; + + if (id) { + self.ctx = self.ctx || uni.createCanvasContext(id); + self.targetCtx = self.targetCtx || uni.createCanvasContext(targetId); + } else { + console.error("constructor: create canvas context failed, 'id' must be valuable"); + } + }; + + self.deviceRadio = windowWidth / 750; +} + +var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== + 'undefined' ? self : {}; + + + + + +function createCommonjsModule(fn, module) { + return module = { + exports: {} + }, fn(module, module.exports), module.exports; +} + +var tools = createCommonjsModule(function(module, exports) { + /** + * String type check + */ + exports.isStr = function(v) { + return typeof v === 'string'; + }; + /** + * Number type check + */ + exports.isNum = function(v) { + return typeof v === 'number'; + }; + /** + * Array type check + */ + exports.isArr = Array.isArray; + /** + * undefined type check + */ + exports.isUndef = function(v) { + return v === undefined; + }; + + exports.isTrue = function(v) { + return v === true; + }; + + exports.isFalse = function(v) { + return v === false; + }; + /** + * Function type check + */ + exports.isFunc = function(v) { + return typeof v === 'function'; + }; + /** + * Quick object check - this is primarily used to tell + * Objects from primitive values when we know the value + * is a JSON-compliant type. + */ + exports.isObj = exports.isObject = function(obj) { + return obj !== null && typeof obj === 'object' + }; + + /** + * Strict object type check. Only returns true + * for plain JavaScript objects. + */ + var _toString = Object.prototype.toString; + exports.isPlainObject = function(obj) { + return _toString.call(obj) === '[object Object]' + }; + + /** + * Check whether the object has the property. + */ + var hasOwnProperty = Object.prototype.hasOwnProperty; + exports.hasOwn = function(obj, key) { + return hasOwnProperty.call(obj, key) + }; + + /** + * Perform no operation. + * Stubbing args to make Flow happy without leaving useless transpiled code + * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/) + */ + exports.noop = function(a, b, c) {}; + + /** + * Check if val is a valid array index. + */ + exports.isValidArrayIndex = function(val) { + var n = parseFloat(String(val)); + return n >= 0 && Math.floor(n) === n && isFinite(val) + }; +}); + +var tools_7 = tools.isFunc; +var tools_10 = tools.isPlainObject; + +var EVENT_TYPE = ['ready', 'beforeImageLoad', 'beforeDraw', 'imageLoad']; + +function observer() { + var self = this; + + self.on = function(event, fn) { + if (EVENT_TYPE.indexOf(event) > -1) { + if (tools_7(fn)) { + event === 'ready' ? + fn(self) : + self[("on" + (firstLetterUpper(event)))] = fn; + } + } else { + console.error(("event: " + event + " is invalid")); + } + return self + }; +} + +function wxPromise(fn) { + return function(obj) { + var args = [], + len = arguments.length - 1; + while (len-- > 0) args[len] = arguments[len + 1]; + + if (obj === void 0) obj = {}; + return new Promise(function(resolve, reject) { + obj.success = function(res) { + resolve(res); + }; + obj.fail = function(err) { + reject(err); + }; + fn.apply(void 0, [obj].concat(args)); + }) + } +} + +function draw(ctx, reserve) { + if (reserve === void 0) reserve = false; + + return new Promise(function(resolve) { + ctx.draw(reserve, resolve); + }) +} + +var getImageInfo = wxPromise(uni.getImageInfo); + +var canvasToTempFilePath = wxPromise(uni.canvasToTempFilePath); + +var base64 = createCommonjsModule(function(module, exports) { + /*! http://mths.be/base64 v0.1.0 by @mathias | MIT license */ + (function(root) { + + // Detect free variables `exports`. + var freeExports = 'object' == 'object' && exports; + + // Detect free variable `module`. + var freeModule = 'object' == 'object' && module && + module.exports == freeExports && module; + + // Detect free variable `global`, from Node.js or Browserified code, and use + // it as `root`. + var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal; + if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { + root = freeGlobal; + } + + /*--------------------------------------------------------------------------*/ + + var InvalidCharacterError = function(message) { + this.message = message; + }; + InvalidCharacterError.prototype = new Error; + InvalidCharacterError.prototype.name = 'InvalidCharacterError'; + + var error = function(message) { + // Note: the error messages used throughout this file match those used by + // the native `atob`/`btoa` implementation in Chromium. + throw new InvalidCharacterError(message); + }; + + var TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + // http://whatwg.org/html/common-microsyntaxes.html#space-character + var REGEX_SPACE_CHARACTERS = /[\t\n\f\r ]/g; + + // `decode` is designed to be fully compatible with `atob` as described in the + // HTML Standard. http://whatwg.org/html/webappapis.html#dom-windowbase64-atob + // The optimized base64-decoding algorithm used is based on @atk’s excellent + // implementation. https://gist.github.com/atk/1020396 + var decode = function(input) { + input = String(input) + .replace(REGEX_SPACE_CHARACTERS, ''); + var length = input.length; + if (length % 4 == 0) { + input = input.replace(/==?$/, ''); + length = input.length; + } + if ( + length % 4 == 1 || + // http://whatwg.org/C#alphanumeric-ascii-characters + /[^+a-zA-Z0-9/]/.test(input) + ) { + error( + 'Invalid character: the string to be decoded is not correctly encoded.' + ); + } + var bitCounter = 0; + var bitStorage; + var buffer; + var output = ''; + var position = -1; + while (++position < length) { + buffer = TABLE.indexOf(input.charAt(position)); + bitStorage = bitCounter % 4 ? bitStorage * 64 + buffer : buffer; + // Unless this is the first of a group of 4 characters… + if (bitCounter++ % 4) { + // …convert the first 8 bits to a single ASCII character. + output += String.fromCharCode( + 0xFF & bitStorage >> (-2 * bitCounter & 6) + ); + } + } + return output; + }; + + // `encode` is designed to be fully compatible with `btoa` as described in the + // HTML Standard: http://whatwg.org/html/webappapis.html#dom-windowbase64-btoa + var encode = function(input) { + input = String(input); + if (/[^\0-\xFF]/.test(input)) { + // Note: no need to special-case astral symbols here, as surrogates are + // matched, and the input is supposed to only contain ASCII anyway. + error( + 'The string to be encoded contains characters outside of the ' + + 'Latin1 range.' + ); + } + var padding = input.length % 3; + var output = ''; + var position = -1; + var a; + var b; + var c; + var buffer; + // Make sure any padding is handled outside of the loop. + var length = input.length - padding; + + while (++position < length) { + // Read three bytes, i.e. 24 bits. + a = input.charCodeAt(position) << 16; + b = input.charCodeAt(++position) << 8; + c = input.charCodeAt(++position); + buffer = a + b + c; + // Turn the 24 bits into four chunks of 6 bits each, and append the + // matching character for each of them to the output. + output += ( + TABLE.charAt(buffer >> 18 & 0x3F) + + TABLE.charAt(buffer >> 12 & 0x3F) + + TABLE.charAt(buffer >> 6 & 0x3F) + + TABLE.charAt(buffer & 0x3F) + ); + } + + if (padding == 2) { + a = input.charCodeAt(position) << 8; + b = input.charCodeAt(++position); + buffer = a + b; + output += ( + TABLE.charAt(buffer >> 10) + + TABLE.charAt((buffer >> 4) & 0x3F) + + TABLE.charAt((buffer << 2) & 0x3F) + + '=' + ); + } else if (padding == 1) { + buffer = input.charCodeAt(position); + output += ( + TABLE.charAt(buffer >> 2) + + TABLE.charAt((buffer << 4) & 0x3F) + + '==' + ); + } + + return output; + }; + + var base64 = { + 'encode': encode, + 'decode': decode, + 'version': '0.1.0' + }; + + // Some AMD build optimizers, like r.js, check for specific condition patterns + // like the following: + if ( + typeof undefined == 'function' && + typeof undefined.amd == 'object' && + undefined.amd + ) { + undefined(function() { + return base64; + }); + } else if (freeExports && !freeExports.nodeType) { + if (freeModule) { // in Node.js or RingoJS v0.8.0+ + freeModule.exports = base64; + } else { // in Narwhal or RingoJS v0.7.0- + for (var key in base64) { + base64.hasOwnProperty(key) && (freeExports[key] = base64[key]); + } + } + } else { // in Rhino or a web browser + root.base64 = base64; + } + + }(commonjsGlobal)); +}); + +function makeURI(strData, type) { + return 'data:' + type + ';base64,' + strData +} + +function fixType(type) { + type = type.toLowerCase().replace(/jpg/i, 'jpeg'); + var r = type.match(/png|jpeg|bmp|gif/)[0]; + return 'image/' + r +} + +function encodeData(data) { + var str = ''; + if (typeof data === 'string') { + str = data; + } else { + for (var i = 0; i < data.length; i++) { + str += String.fromCharCode(data[i]); + } + } + return base64.encode(str) +} + +/** + * 获取图像区域隐含的像素数据 + * @param canvasId canvas标识 + * @param x 将要被提取的图像数据矩形区域的左上角 x 坐标 + * @param y 将要被提取的图像数据矩形区域的左上角 y 坐标 + * @param width 将要被提取的图像数据矩形区域的宽度 + * @param height 将要被提取的图像数据矩形区域的高度 + * @param done 完成回调 + */ +function getImageData(canvasId, x, y, width, height, done) { + uni.canvasGetImageData({ + canvasId: canvasId, + x: x, + y: y, + width: width, + height: height, + success: function success(res) { + done(res, null); + }, + fail: function fail(res) { + done(null, res); + } + }); +} + +/** + * 生成bmp格式图片 + * 按照规则生成图片响应头和响应体 + * @param oData 用来描述 canvas 区域隐含的像素数据 { data, width, height } = oData + * @returns {*} base64字符串 + */ +function genBitmapImage(oData) { + // + // BITMAPFILEHEADER: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183374(v=vs.85).aspx + // BITMAPINFOHEADER: http://msdn.microsoft.com/en-us/library/dd183376.aspx + // + var biWidth = oData.width; + var biHeight = oData.height; + var biSizeImage = biWidth * biHeight * 3; + var bfSize = biSizeImage + 54; // total header size = 54 bytes + + // + // typedef struct tagBITMAPFILEHEADER { + // WORD bfType; + // DWORD bfSize; + // WORD bfReserved1; + // WORD bfReserved2; + // DWORD bfOffBits; + // } BITMAPFILEHEADER; + // + var BITMAPFILEHEADER = [ + // WORD bfType -- The file type signature; must be "BM" + 0x42, 0x4D, + // DWORD bfSize -- The size, in bytes, of the bitmap file + bfSize & 0xff, bfSize >> 8 & 0xff, bfSize >> 16 & 0xff, bfSize >> 24 & 0xff, + // WORD bfReserved1 -- Reserved; must be zero + 0, 0, + // WORD bfReserved2 -- Reserved; must be zero + 0, 0, + // DWORD bfOffBits -- The offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits. + 54, 0, 0, 0 + ]; + + // + // typedef struct tagBITMAPINFOHEADER { + // DWORD biSize; + // LONG biWidth; + // LONG biHeight; + // WORD biPlanes; + // WORD biBitCount; + // DWORD biCompression; + // DWORD biSizeImage; + // LONG biXPelsPerMeter; + // LONG biYPelsPerMeter; + // DWORD biClrUsed; + // DWORD biClrImportant; + // } BITMAPINFOHEADER, *PBITMAPINFOHEADER; + // + var BITMAPINFOHEADER = [ + // DWORD biSize -- The number of bytes required by the structure + 40, 0, 0, 0, + // LONG biWidth -- The width of the bitmap, in pixels + biWidth & 0xff, biWidth >> 8 & 0xff, biWidth >> 16 & 0xff, biWidth >> 24 & 0xff, + // LONG biHeight -- The height of the bitmap, in pixels + biHeight & 0xff, biHeight >> 8 & 0xff, biHeight >> 16 & 0xff, biHeight >> 24 & 0xff, + // WORD biPlanes -- The number of planes for the target device. This value must be set to 1 + 1, 0, + // WORD biBitCount -- The number of bits-per-pixel, 24 bits-per-pixel -- the bitmap + // has a maximum of 2^24 colors (16777216, Truecolor) + 24, 0, + // DWORD biCompression -- The type of compression, BI_RGB (code 0) -- uncompressed + 0, 0, 0, 0, + // DWORD biSizeImage -- The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps + biSizeImage & 0xff, biSizeImage >> 8 & 0xff, biSizeImage >> 16 & 0xff, biSizeImage >> 24 & 0xff, + // LONG biXPelsPerMeter, unused + 0, 0, 0, 0, + // LONG biYPelsPerMeter, unused + 0, 0, 0, 0, + // DWORD biClrUsed, the number of color indexes of palette, unused + 0, 0, 0, 0, + // DWORD biClrImportant, unused + 0, 0, 0, 0 + ]; + + var iPadding = (4 - ((biWidth * 3) % 4)) % 4; + + var aImgData = oData.data; + + var strPixelData = ''; + var biWidth4 = biWidth << 2; + var y = biHeight; + var fromCharCode = String.fromCharCode; + + do { + var iOffsetY = biWidth4 * (y - 1); + var strPixelRow = ''; + for (var x = 0; x < biWidth; x++) { + var iOffsetX = x << 2; + strPixelRow += fromCharCode(aImgData[iOffsetY + iOffsetX + 2]) + + fromCharCode(aImgData[iOffsetY + iOffsetX + 1]) + + fromCharCode(aImgData[iOffsetY + iOffsetX]); + } + + for (var c = 0; c < iPadding; c++) { + strPixelRow += String.fromCharCode(0); + } + + strPixelData += strPixelRow; + } while (--y) + + var strEncoded = encodeData(BITMAPFILEHEADER.concat(BITMAPINFOHEADER)) + encodeData(strPixelData); + + return strEncoded +} + +/** + * 转换为图片base64 + * @param canvasId canvas标识 + * @param x 将要被提取的图像数据矩形区域的左上角 x 坐标 + * @param y 将要被提取的图像数据矩形区域的左上角 y 坐标 + * @param width 将要被提取的图像数据矩形区域的宽度 + * @param height 将要被提取的图像数据矩形区域的高度 + * @param type 转换图片类型 + * @param done 完成回调 + */ +function convertToImage(canvasId, x, y, width, height, type, done) { + if (done === void 0) done = function() {}; + + if (type === undefined) { + type = 'png'; + } + type = fixType(type); + if (/bmp/.test(type)) { + getImageData(canvasId, x, y, width, height, function(data, err) { + var strData = genBitmapImage(data); + tools_7(done) && done(makeURI(strData, 'image/' + type), err); + }); + } else { + console.error('暂不支持生成\'' + type + '\'类型的base64图片'); + } +} + +var CanvasToBase64 = { + convertToImage: convertToImage, + // convertToPNG: function (width, height, done) { + // return convertToImage(width, height, 'png', done) + // }, + // convertToJPEG: function (width, height, done) { + // return convertToImage(width, height, 'jpeg', done) + // }, + // convertToGIF: function (width, height, done) { + // return convertToImage(width, height, 'gif', done) + // }, + convertToBMP: function(ref, done) { + if (ref === void 0) ref = {}; + var canvasId = ref.canvasId; + var x = ref.x; + var y = ref.y; + var width = ref.width; + var height = ref.height; + if (done === void 0) done = function() {}; + + return convertToImage(canvasId, x, y, width, height, 'bmp', done) + } +}; + +function methods() { + var self = this; + + var boundWidth = self.width; // 裁剪框默认宽度,即整个画布宽度 + var boundHeight = self.height; // 裁剪框默认高度,即整个画布高度 + + var id = self.id; + var targetId = self.targetId; + var pixelRatio = self.pixelRatio; + + var ref = self.cut; + var x = ref.x; + if (x === void 0) x = 0; + var y = ref.y; + if (y === void 0) y = 0; + var width = ref.width; + if (width === void 0) width = boundWidth; + var height = ref.height; + if (height === void 0) height = boundHeight; + + self.updateCanvas = function(done) { + if (self.croperTarget) { + // 画布绘制图片 + self.ctx.drawImage( + self.croperTarget, + self.imgLeft, + self.imgTop, + self.scaleWidth, + self.scaleHeight + ); + } + tools_7(self.onBeforeDraw) && self.onBeforeDraw(self.ctx, self); + + self.setBoundStyle(self.boundStyle); // 设置边界样式 + + self.ctx.draw(false, done); + return self + }; + + self.pushOrigin = self.pushOrign = function(src) { + self.src = src; + + tools_7(self.onBeforeImageLoad) && self.onBeforeImageLoad(self.ctx, self); + + return getImageInfo({ + src: src + }) + .then(function(res) { + var innerAspectRadio = res.width / res.height; + var customAspectRadio = width / height; + + self.croperTarget = res.path; + + if (innerAspectRadio < customAspectRadio) { + self.rectX = x; + self.baseWidth = width; + self.baseHeight = width / innerAspectRadio; + self.rectY = y - Math.abs((height - self.baseHeight) / 2); + } else { + self.rectY = y; + self.baseWidth = height * innerAspectRadio; + self.baseHeight = height; + self.rectX = x - Math.abs((width - self.baseWidth) / 2); + } + + self.imgLeft = self.rectX; + self.imgTop = self.rectY; + self.scaleWidth = self.baseWidth; + self.scaleHeight = self.baseHeight; + + self.update(); + + return new Promise(function(resolve) { + self.updateCanvas(resolve); + }) + }) + .then(function() { + tools_7(self.onImageLoad) && self.onImageLoad(self.ctx, self); + }) + }; + + self.removeImage = function() { + self.src = ''; + self.croperTarget = ''; + return draw(self.ctx) + }; + + self.getCropperBase64 = function(done) { + if (done === void 0) done = function() {}; + + CanvasToBase64.convertToBMP({ + canvasId: id, + x: x, + y: y, + width: width, + height: height + }, done); + }; + + self.getCropperImage = function(opt, fn) { + var customOptions = opt; + + var canvasOptions = { + canvasId: id, + x: x, + y: y, + width: width, + height: height + }; + + var task = function() { + return Promise.resolve(); + }; + + if ( + tools_10(customOptions) && + customOptions.original + ) { + // original mode + task = function() { + self.targetCtx.drawImage( + self.croperTarget, + self.imgLeft * pixelRatio, + self.imgTop * pixelRatio, + self.scaleWidth * pixelRatio, + self.scaleHeight * pixelRatio + ); + + canvasOptions = { + canvasId: targetId, + x: x * pixelRatio, + y: y * pixelRatio, + width: width * pixelRatio, + height: height * pixelRatio + }; + + return draw(self.targetCtx) + }; + } + + return task() + .then(function() { + if (tools_10(customOptions)) { + canvasOptions = Object.assign({}, canvasOptions, customOptions); + } + + if (tools_7(customOptions)) { + fn = customOptions; + } + + var arg = canvasOptions.componentContext ? [canvasOptions, canvasOptions.componentContext] : [canvasOptions]; + + return canvasToTempFilePath.apply(null, arg) + }) + .then(function(res) { + var tempFilePath = res.tempFilePath; + + return tools_7(fn) ? + fn.call(self, tempFilePath, null) : + tempFilePath + }) + .catch(function(err) { + if (tools_7(fn)) { + fn.call(self, null, err); + } else { + throw err + } + }) + }; +} + +/** + * 获取最新缩放值 + * @param oldScale 上一次触摸结束后的缩放值 + * @param oldDistance 上一次触摸结束后的双指距离 + * @param zoom 缩放系数 + * @param touch0 第一指touch对象 + * @param touch1 第二指touch对象 + * @returns {*} + */ +var getNewScale = function(oldScale, oldDistance, zoom, touch0, touch1) { + var xMove, yMove, newDistance; + // 计算二指最新距离 + xMove = Math.round(touch1.x - touch0.x); + yMove = Math.round(touch1.y - touch0.y); + newDistance = Math.round(Math.sqrt(xMove * xMove + yMove * yMove)); + + return oldScale + 0.001 * zoom * (newDistance - oldDistance) +}; + +function update() { + var self = this; + + if (!self.src) { + return + } + + self.__oneTouchStart = function(touch) { + self.touchX0 = Math.round(touch.x); + self.touchY0 = Math.round(touch.y); + }; + + self.__oneTouchMove = function(touch) { + var xMove, yMove; + // 计算单指移动的距离 + if (self.touchended) { + return self.updateCanvas() + } + xMove = Math.round(touch.x - self.touchX0); + yMove = Math.round(touch.y - self.touchY0); + + var imgLeft = Math.round(self.rectX + xMove); + var imgTop = Math.round(self.rectY + yMove); + + self.outsideBound(imgLeft, imgTop); + + self.updateCanvas(); + }; + + self.__twoTouchStart = function(touch0, touch1) { + var xMove, yMove, oldDistance; + + self.touchX1 = Math.round(self.rectX + self.scaleWidth / 2); + self.touchY1 = Math.round(self.rectY + self.scaleHeight / 2); + + // 计算两指距离 + xMove = Math.round(touch1.x - touch0.x); + yMove = Math.round(touch1.y - touch0.y); + oldDistance = Math.round(Math.sqrt(xMove * xMove + yMove * yMove)); + + self.oldDistance = oldDistance; + }; + + self.__twoTouchMove = function(touch0, touch1) { + var oldScale = self.oldScale; + var oldDistance = self.oldDistance; + var scale = self.scale; + var zoom = self.zoom; + + self.newScale = getNewScale(oldScale, oldDistance, zoom, touch0, touch1); + + // 设定缩放范围 + self.newScale <= 1 && (self.newScale = 1); + self.newScale >= scale && (self.newScale = scale); + + self.scaleWidth = Math.round(self.newScale * self.baseWidth); + self.scaleHeight = Math.round(self.newScale * self.baseHeight); + var imgLeft = Math.round(self.touchX1 - self.scaleWidth / 2); + var imgTop = Math.round(self.touchY1 - self.scaleHeight / 2); + + self.outsideBound(imgLeft, imgTop); + + self.updateCanvas(); + }; + + self.__xtouchEnd = function() { + self.oldScale = self.newScale; + self.rectX = self.imgLeft; + self.rectY = self.imgTop; + }; +} + +var handle = { + // 图片手势初始监测 + touchStart: function touchStart(e) { + var self = this; + var ref = e.touches; + var touch0 = ref[0]; + var touch1 = ref[1]; + + if (!self.src) { + return + } + + setTouchState(self, true, null, null); + + // 计算第一个触摸点的位置,并参照改点进行缩放 + self.__oneTouchStart(touch0); + + // 两指手势触发 + if (e.touches.length >= 2) { + self.__twoTouchStart(touch0, touch1); + } + }, + + // 图片手势动态缩放 + touchMove: function touchMove(e) { + var self = this; + var ref = e.touches; + var touch0 = ref[0]; + var touch1 = ref[1]; + + if (!self.src) { + return + } + + setTouchState(self, null, true); + + // 单指手势时触发 + if (e.touches.length === 1) { + self.__oneTouchMove(touch0); + } + // 两指手势触发 + if (e.touches.length >= 2) { + self.__twoTouchMove(touch0, touch1); + } + }, + + touchEnd: function touchEnd(e) { + var self = this; + + if (!self.src) { + return + } + + setTouchState(self, false, false, true); + self.__xtouchEnd(); + } +}; + +function cut() { + var self = this; + var boundWidth = self.width; // 裁剪框默认宽度,即整个画布宽度 + var boundHeight = self.height; + // 裁剪框默认高度,即整个画布高度 + var ref = self.cut; + var x = ref.x; + if (x === void 0) x = 0; + var y = ref.y; + if (y === void 0) y = 0; + var width = ref.width; + if (width === void 0) width = boundWidth; + var height = ref.height; + if (height === void 0) height = boundHeight; + + /** + * 设置边界 + * @param imgLeft 图片左上角横坐标值 + * @param imgTop 图片左上角纵坐标值 + */ + self.outsideBound = function(imgLeft, imgTop) { + self.imgLeft = imgLeft >= x ? + x : + self.scaleWidth + imgLeft - x <= width ? + x + width - self.scaleWidth : + imgLeft; + + self.imgTop = imgTop >= y ? + y : + self.scaleHeight + imgTop - y <= height ? + y + height - self.scaleHeight : + imgTop; + }; + + /** + * 设置边界样式 + * @param color 边界颜色 + */ + self.setBoundStyle = function(ref) { + if (ref === void 0) ref = {}; + var color = ref.color; + if (color === void 0) color = '#04b00f'; + var mask = ref.mask; + if (mask === void 0) mask = 'rgba(0, 0, 0, 0.3)'; + var lineWidth = ref.lineWidth; + if (lineWidth === void 0) lineWidth = 1; + + var half = lineWidth / 2; + var boundOption = [{ + start: { + x: x - half, + y: y + 10 - half + }, + step1: { + x: x - half, + y: y - half + }, + step2: { + x: x + 10 - half, + y: y - half + } + }, + { + start: { + x: x - half, + y: y + height - 10 + half + }, + step1: { + x: x - half, + y: y + height + half + }, + step2: { + x: x + 10 - half, + y: y + height + half + } + }, + { + start: { + x: x + width - 10 + half, + y: y - half + }, + step1: { + x: x + width + half, + y: y - half + }, + step2: { + x: x + width + half, + y: y + 10 - half + } + }, + { + start: { + x: x + width + half, + y: y + height - 10 + half + }, + step1: { + x: x + width + half, + y: y + height + half + }, + step2: { + x: x + width - 10 + half, + y: y + height + half + } + } + ]; + + // 绘制半透明层 + self.ctx.beginPath(); + self.ctx.setFillStyle(mask); + self.ctx.fillRect(0, 0, x, boundHeight); + self.ctx.fillRect(x, 0, width, y); + self.ctx.fillRect(x, y + height, width, boundHeight - y - height); + self.ctx.fillRect(x + width, 0, boundWidth - x - width, boundHeight); + self.ctx.fill(); + + boundOption.forEach(function(op) { + self.ctx.beginPath(); + self.ctx.setStrokeStyle(color); + self.ctx.setLineWidth(lineWidth); + self.ctx.moveTo(op.start.x, op.start.y); + self.ctx.lineTo(op.step1.x, op.step1.y); + self.ctx.lineTo(op.step2.x, op.step2.y); + self.ctx.stroke(); + }); + }; +} + +var version = "1.3.9"; + +var WeCropper = function WeCropper(params) { + var self = this; + var _default = {}; + + validator(self, DEFAULT); + + Object.keys(DEFAULT).forEach(function(key) { + _default[key] = DEFAULT[key].default; + }); + Object.assign(self, _default, params); + + self.prepare(); + self.attachPage(); + self.createCtx(); + self.observer(); + self.cutt(); + self.methods(); + self.init(); + self.update(); + + return self +}; + +WeCropper.prototype.init = function init() { + var self = this; + var src = self.src; + + self.version = version; + + typeof self.onReady === 'function' && self.onReady(self.ctx, self); + + if (src) { + self.pushOrign(src); + } else { + self.updateCanvas(); + } + setTouchState(self, false, false, false); + + self.oldScale = 1; + self.newScale = 1; + + return self +}; + +Object.assign(WeCropper.prototype, handle); + +WeCropper.prototype.prepare = prepare; +WeCropper.prototype.observer = observer; +WeCropper.prototype.methods = methods; +WeCropper.prototype.cutt = cut; +WeCropper.prototype.update = update; + +export default WeCropper; diff --git a/uni_modules/vk-uview-ui/components/u-avatar/u-avatar.vue b/uni_modules/vk-uview-ui/components/u-avatar/u-avatar.vue new file mode 100644 index 0000000..835c4bd --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-avatar/u-avatar.vue @@ -0,0 +1,270 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-back-top/u-back-top.vue b/uni_modules/vk-uview-ui/components/u-back-top/u-back-top.vue new file mode 100644 index 0000000..7970fc7 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-back-top/u-back-top.vue @@ -0,0 +1,153 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-badge/u-badge.vue b/uni_modules/vk-uview-ui/components/u-badge/u-badge.vue new file mode 100644 index 0000000..0efa751 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-badge/u-badge.vue @@ -0,0 +1,216 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-button/u-button.vue b/uni_modules/vk-uview-ui/components/u-button/u-button.vue new file mode 100644 index 0000000..b5f4b0c --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-button/u-button.vue @@ -0,0 +1,661 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-calendar/u-calendar.vue b/uni_modules/vk-uview-ui/components/u-calendar/u-calendar.vue new file mode 100644 index 0000000..fe9f2dc --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-calendar/u-calendar.vue @@ -0,0 +1,666 @@ + + + + diff --git a/uni_modules/vk-uview-ui/components/u-car-keyboard/u-car-keyboard.vue b/uni_modules/vk-uview-ui/components/u-car-keyboard/u-car-keyboard.vue new file mode 100644 index 0000000..e55db26 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-car-keyboard/u-car-keyboard.vue @@ -0,0 +1,267 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-card/u-card.vue b/uni_modules/vk-uview-ui/components/u-card/u-card.vue new file mode 100644 index 0000000..4497356 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-card/u-card.vue @@ -0,0 +1,300 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-cell-group/u-cell-group.vue b/uni_modules/vk-uview-ui/components/u-cell-group/u-cell-group.vue new file mode 100644 index 0000000..3fbca72 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-cell-group/u-cell-group.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-cell-item/u-cell-item.vue b/uni_modules/vk-uview-ui/components/u-cell-item/u-cell-item.vue new file mode 100644 index 0000000..90ee117 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-cell-item/u-cell-item.vue @@ -0,0 +1,317 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-checkbox-group/u-checkbox-group.vue b/uni_modules/vk-uview-ui/components/u-checkbox-group/u-checkbox-group.vue new file mode 100644 index 0000000..18c39e7 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-checkbox-group/u-checkbox-group.vue @@ -0,0 +1,178 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-checkbox/u-checkbox.vue b/uni_modules/vk-uview-ui/components/u-checkbox/u-checkbox.vue new file mode 100644 index 0000000..741d47c --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-checkbox/u-checkbox.vue @@ -0,0 +1,336 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-circle-progress/u-circle-progress.vue b/uni_modules/vk-uview-ui/components/u-circle-progress/u-circle-progress.vue new file mode 100644 index 0000000..b5796a4 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-circle-progress/u-circle-progress.vue @@ -0,0 +1,227 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-col/u-col.vue b/uni_modules/vk-uview-ui/components/u-col/u-col.vue new file mode 100644 index 0000000..fc47dfa --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-col/u-col.vue @@ -0,0 +1,157 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-collapse-item/u-collapse-item.vue b/uni_modules/vk-uview-ui/components/u-collapse-item/u-collapse-item.vue new file mode 100644 index 0000000..963e98f --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-collapse-item/u-collapse-item.vue @@ -0,0 +1,206 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-collapse/u-collapse.vue b/uni_modules/vk-uview-ui/components/u-collapse/u-collapse.vue new file mode 100644 index 0000000..f6e4bf0 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-collapse/u-collapse.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-column-notice/u-column-notice.vue b/uni_modules/vk-uview-ui/components/u-column-notice/u-column-notice.vue new file mode 100644 index 0000000..709ca5c --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-column-notice/u-column-notice.vue @@ -0,0 +1,238 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-count-down/u-count-down.vue b/uni_modules/vk-uview-ui/components/u-count-down/u-count-down.vue new file mode 100644 index 0000000..0d7cc21 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-count-down/u-count-down.vue @@ -0,0 +1,175 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-count-down/utils.js b/uni_modules/vk-uview-ui/components/u-count-down/utils.js new file mode 100644 index 0000000..8c75005 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-count-down/utils.js @@ -0,0 +1,62 @@ +// 补0,如1 -> 01 +function padZero(num, targetLength = 2) { + let str = `${num}` + while (str.length < targetLength) { + str = `0${str}` + } + return str +} +const SECOND = 1000 +const MINUTE = 60 * SECOND +const HOUR = 60 * MINUTE +const DAY = 24 * HOUR +export function parseTimeData(time) { + const days = Math.floor(time / DAY) + const hours = Math.floor((time % DAY) / HOUR) + const minutes = Math.floor((time % HOUR) / MINUTE) + const seconds = Math.floor((time % MINUTE) / SECOND) + const milliseconds = Math.floor(time % SECOND) + return { + days, + hours, + minutes, + seconds, + milliseconds + } +} +export function parseFormat(format, timeData) { + let { + days, + hours, + minutes, + seconds, + milliseconds + } = timeData + // 如果格式化字符串中不存在DD(天),则将天的时间转为小时中去 + if (format.indexOf('DD') === -1) { + hours += days * 24 + } else { + // 对天补0 + format = format.replace('DD', padZero(days)) + } + // 其他同理于DD的格式化处理方式 + if (format.indexOf('HH') === -1) { + minutes += hours * 60 + } else { + format = format.replace('HH', padZero(hours)) + } + if (format.indexOf('mm') === -1) { + seconds += minutes * 60 + } else { + format = format.replace('mm', padZero(minutes)) + } + if (format.indexOf('ss') === -1) { + milliseconds += seconds * 1000 + } else { + format = format.replace('ss', padZero(seconds)) + } + return format.replace('SSS', padZero(milliseconds, 3)) +} +export function isSameSecond(time1, time2) { + return Math.floor(time1 / 1000) === Math.floor(time2 / 1000) +} diff --git a/uni_modules/vk-uview-ui/components/u-count-to/u-count-to.vue b/uni_modules/vk-uview-ui/components/u-count-to/u-count-to.vue new file mode 100644 index 0000000..1825072 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-count-to/u-count-to.vue @@ -0,0 +1,266 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-divider/u-divider.vue b/uni_modules/vk-uview-ui/components/u-divider/u-divider.vue new file mode 100644 index 0000000..d09e439 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-divider/u-divider.vue @@ -0,0 +1,159 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-dropdown-item/u-dropdown-item.vue b/uni_modules/vk-uview-ui/components/u-dropdown-item/u-dropdown-item.vue new file mode 100644 index 0000000..380268a --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-dropdown-item/u-dropdown-item.vue @@ -0,0 +1,166 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-dropdown/u-dropdown.vue b/uni_modules/vk-uview-ui/components/u-dropdown/u-dropdown.vue new file mode 100644 index 0000000..b9438b4 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-dropdown/u-dropdown.vue @@ -0,0 +1,299 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-empty/u-empty.vue b/uni_modules/vk-uview-ui/components/u-empty/u-empty.vue new file mode 100644 index 0000000..2c77b24 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-empty/u-empty.vue @@ -0,0 +1,193 @@ + + + + + diff --git a/uni_modules/vk-uview-ui/components/u-field/u-field.vue b/uni_modules/vk-uview-ui/components/u-field/u-field.vue new file mode 100644 index 0000000..efa31e6 --- /dev/null +++ b/uni_modules/vk-uview-ui/components/u-field/u-field.vue @@ -0,0 +1,402 @@ +