From d572f28fad1f4dfd4f48988e279bbb65fcaac82a Mon Sep 17 00:00:00 2001 From: ldeyun Date: Mon, 30 Sep 2024 01:26:58 +0800 Subject: [PATCH] =?UTF-8?q?V1.0.0=20=E5=BE=AE=E4=BF=A1=E5=B0=8F=E7=A8=8B?= =?UTF-8?q?=E5=BA=8F=E8=BF=90=E8=A1=8C=E6=88=90=E5=8A=9F=EF=BC=9B=20H5?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=88=90=E5=8A=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + .hbuilderx/launch.json | 31 + App.vue | 56 + LICENSE | 201 + README.md | 3 + androidPrivacy.json | 3 + changelog.md | 268 + common/appInit.js | 164 + common/openApp.js | 36 + components/refreshBox/refreshBox.vue | 95 + components/uni-load-state/i18n/en.json | 6 + components/uni-load-state/i18n/index.js | 6 + components/uni-load-state/i18n/zh-Hans.json | 6 + components/uni-load-state/readme.md | 3 + components/uni-load-state/uni-load-state.vue | 171 + index.html | 20 + js_sdk/AC-Dictionary/script/HttpDictionary.js | 104 + js_sdk/AC-Dictionary/script/Message.js | 59 + js_sdk/dc-deviceinfo/deviceinfo.js | 159 + js_sdk/util/dictTools.js | 113 + js_sdk/util/jsonData.js | 48 + js_sdk/validator/ngTools_Dict.js | 129 + js_sdk/validator/ngTools_DictItem.js | 153 + js_sdk/validator/ngTools_MeterList.js | 108 + js_sdk/validator/ngTools_MeterPar.js | 457 + js_sdk/validator/ngTools_NGComponents.js | 295 + js_sdk/validator/ngTools_NGPar.js | 558 + js_sdk/validator/ngTools_SamplingLocation.js | 72 + js_sdk/validator/ngTools_depart.js | 102 + js_sdk/validator/ngtools-categories.js | 131 + js_sdk/validator/ngtools-goods.js | 257 + js_sdk/validator/ngtools_information.js | 129 + js_sdk/validator/opendb-banner.js | 130 + js_sdk/validator/uni-id-users.js | 354 + lang/en.js | 191 + lang/i18n.js | 96 + lang/zh-Hans.js | 268 + main.js | 32 + manifest.json | 180 + package.json | 90 + pages.json | 666 + pages/grid/grid.vue | 404 + pages/list/detail.vue | 373 + pages/list/list.nvue | 206 + pages/ucenter.vue | 503 + pagesPackage/components/popup.vue | 104 + pagesPackage/ngTools_Dict/add.vue | 183 + pagesPackage/ngTools_Dict/detail.vue | 162 + pagesPackage/ngTools_Dict/edit.vue | 198 + pagesPackage/ngTools_Dict/list.vue | 151 + pagesPackage/ngTools_DictItem/add.vue | 182 + pagesPackage/ngTools_DictItem/detail.vue | 159 + pagesPackage/ngTools_DictItem/edit.vue | 208 + pagesPackage/ngTools_DictItem/list.vue | 165 + pagesPackage/ngTools_MeterList/add.vue | 145 + pagesPackage/ngTools_MeterList/detail.vue | 120 + pagesPackage/ngTools_MeterList/edit.vue | 176 + pagesPackage/ngTools_MeterList/list.vue | 72 + pagesPackage/ngTools_SamplingLocation/add.vue | 129 + .../ngTools_SamplingLocation/detail.vue | 104 + .../ngTools_SamplingLocation/edit.vue | 160 + .../ngTools_SamplingLocation/list.vue | 72 + pagesPackage/ngTools_depart/add.vue | 198 + .../ngTools_depart/departList/departList.vue | 246 + .../ngTools_depart/departList/departTree.vue | 42 + .../ngTools_depart/departList/style.css | 161 + pagesPackage/ngTools_depart/depart_select.vue | 136 + pagesPackage/ngTools_depart/detail.vue | 130 + pagesPackage/ngTools_depart/edit.vue | 209 + pagesPackage/ngTools_depart/list.vue | 119 + pagesPackage/ngTools_depart/user_select.vue | 102 + pagesPackage/ngtools-goods/add.vue | 201 + pagesPackage/ngtools-goods/detail.vue | 176 + pagesPackage/ngtools-goods/edit.vue | 232 + pagesPackage/ngtools-goods/list.vue | 72 + pagesPackage/ngtools_CNG/LNGQhJs.vue | 325 + pagesPackage/ngtools_CNG/srjBgJs.vue | 365 + pagesPackage/ngtools_CNG/srjJs.vue | 313 + pagesPackage/ngtools_CNG/zxcJs.vue | 343 + pagesPackage/ngtools_Flow/SqgyJs.vue | 523 + pagesPackage/ngtools_Flow/cysllJs.vue | 299 + pagesPackage/ngtools_Flow/ljlllJs.vue | 295 + pagesPackage/ngtools_Flow/sdsllJs.vue | 293 + pagesPackage/ngtools_Par/ZBgJs.vue | 367 + pagesPackage/ngtools_Par/mdRzJs.vue | 342 + pagesPackage/ngtools_Par/qtJs.vue | 335 + pagesPackage/ngtools_Par/zJs.vue | 335 + pagesPackage/ngtools_categories/add.vue | 153 + pagesPackage/ngtools_categories/detail.vue | 128 + pagesPackage/ngtools_categories/edit.vue | 184 + pagesPackage/ngtools_categories/list.vue | 72 + pagesPackage/ngtools_information/add.vue | 153 + pagesPackage/ngtools_information/detail.vue | 382 + pagesPackage/ngtools_information/edit.vue | 184 + pagesPackage/ngtools_information/list.vue | 81 + pagesPackage/opendb-banner/add.vue | 149 + pagesPackage/opendb-banner/detail.vue | 126 + pagesPackage/opendb-banner/edit.vue | 180 + pagesPackage/opendb-banner/list.vue | 72 + .../ucenter/Sansnn-uQRCode/changelog.md | 12 + .../ucenter/Sansnn-uQRCode/common/cache.js | 1 + .../ucenter/Sansnn-uQRCode/common/queue.js | 41 + .../Sansnn-uQRCode/common/types/cache.d.ts | 3 + .../Sansnn-uQRCode/common/types/queue.d.ts | 4 + .../components/u-qrcode/u-qrcode.vue | 1131 ++ .../components/uqrcode/uqrcode.vue | 1131 ++ .../js_sdk/gcanvas/bridge/bridge-weex.js | 241 + .../context-2d/FillStyleLinearGradient.js | 18 + .../gcanvas/context-2d/FillStylePattern.js | 8 + .../context-2d/FillStyleRadialGradient.js | 17 + .../gcanvas/context-2d/RenderingContext.js | 666 + .../gcanvas/context-webgl/ActiveInfo.js | 11 + .../js_sdk/gcanvas/context-webgl/Buffer.js | 21 + .../gcanvas/context-webgl/Framebuffer.js | 21 + .../js_sdk/gcanvas/context-webgl/GLenum.js | 298 + .../js_sdk/gcanvas/context-webgl/GLmethod.js | 142 + .../js_sdk/gcanvas/context-webgl/GLtype.js | 23 + .../js_sdk/gcanvas/context-webgl/Program.js | 21 + .../gcanvas/context-webgl/Renderbuffer.js | 21 + .../gcanvas/context-webgl/RenderingContext.js | 1191 ++ .../js_sdk/gcanvas/context-webgl/Shader.js | 22 + .../context-webgl/ShaderPrecisionFormat.js | 11 + .../js_sdk/gcanvas/context-webgl/Texture.js | 22 + .../gcanvas/context-webgl/UniformLocation.js | 22 + .../gcanvas/context-webgl/classUtils.js | 3 + .../js_sdk/gcanvas/env/canvas.js | 74 + .../js_sdk/gcanvas/env/image.js | 96 + .../Sansnn-uQRCode/js_sdk/gcanvas/env/tool.js | 24 + .../Sansnn-uQRCode/js_sdk/gcanvas/index.js | 39 + .../js_sdk/uqrcode/package.json | 12 + .../Sansnn-uQRCode/js_sdk/uqrcode/uqrcode.js | 1606 ++ .../ucenter/Sansnn-uQRCode/license.md | 201 + .../ucenter/Sansnn-uQRCode/package.json | 80 + pagesPackage/ucenter/Sansnn-uQRCode/readme.md | 392 + pagesPackage/ucenter/about/about.vue | 235 + pagesPackage/ucenter/invite/invite.vue | 179 + pagesPackage/ucenter/pay/index.vue | 503 + .../ucenter/read-news-log/read-news-log.vue | 77 + pagesPackage/ucenter/settings/dc-push/push.js | 118 + pagesPackage/ucenter/settings/settings.vue | 304 + pagesPackage/uni-agree/uni-agree.nvue | 139 + pagesPackage/uni-agree/utils/uni-agree.js | 11 + static/app-plus/sharemenu/copyurl.png | Bin 0 -> 920 bytes static/app-plus/sharemenu/more.png | Bin 0 -> 1436 bytes static/app-plus/sharemenu/mp_weixin.png | Bin 0 -> 4776 bytes static/app-plus/sharemenu/qq.png | Bin 0 -> 1605 bytes static/app-plus/sharemenu/wechatfriend.png | Bin 0 -> 2024 bytes static/app-plus/sharemenu/wechatmoments.png | Bin 0 -> 1758 bytes static/app-plus/sharemenu/weibo.png | Bin 0 -> 2274 bytes static/h5/download-app/android.png | Bin 0 -> 1033 bytes static/h5/download-app/ios.png | Bin 0 -> 1206 bytes static/h5/download-app/openImg.png | Bin 0 -> 12894 bytes static/tabbar/grid.png | Bin 0 -> 2695 bytes static/tabbar/grid_active.png | Bin 0 -> 2556 bytes static/tabbar/list.png | Bin 0 -> 2897 bytes static/tabbar/list_active.png | Bin 0 -> 3024 bytes static/tabbar/me.png | Bin 0 -> 3380 bytes static/tabbar/me_active.png | Bin 0 -> 3461 bytes static/uni-center/headers.png | Bin 0 -> 20399 bytes static/uni-load-state/disconnection.png | Bin 0 -> 5687 bytes static/uni.ttf | Bin 0 -> 26164 bytes uni-starter.config.js | 49 + uni.scss | 76 + .../cloudfunctions/common/uni-stat/index.js | 23 + .../common/uni-stat/package.json | 15 + .../common/uni-stat/shared/create-api.js | 82 + .../common/uni-stat/shared/error.js | 19 + .../common/uni-stat/shared/index.js | 6 + .../common/uni-stat/shared/utils.js | 197 + .../common/uni-stat/stat/lib/date.js | 371 + .../common/uni-stat/stat/lib/index.js | 4 + .../common/uni-stat/stat/lib/uni-crypto.js | 98 + .../common/uni-stat/stat/mod/activeDevices.js | 528 + .../common/uni-stat/stat/mod/activeUsers.js | 314 + .../common/uni-stat/stat/mod/appCrashLogs.js | 37 + .../common/uni-stat/stat/mod/base.js | 485 + .../common/uni-stat/stat/mod/channel.js | 107 + .../common/uni-stat/stat/mod/device.js | 184 + .../common/uni-stat/stat/mod/errorLog.js | 141 + .../common/uni-stat/stat/mod/errorResult.js | 459 + .../common/uni-stat/stat/mod/event.js | 72 + .../common/uni-stat/stat/mod/eventLog.js | 156 + .../common/uni-stat/stat/mod/eventResult.js | 268 + .../common/uni-stat/stat/mod/index.js | 23 + .../common/uni-stat/stat/mod/loyalty.js | 491 + .../common/uni-stat/stat/mod/page.js | 83 + .../common/uni-stat/stat/mod/pageLog.js | 186 + .../common/uni-stat/stat/mod/pageResult.js | 522 + .../common/uni-stat/stat/mod/platform.js | 160 + .../common/uni-stat/stat/mod/runErrors.js | 20 + .../common/uni-stat/stat/mod/scenes.js | 80 + .../common/uni-stat/stat/mod/sessionLog.js | 343 + .../common/uni-stat/stat/mod/setting.js | 44 + .../common/uni-stat/stat/mod/shareLog.js | 104 + .../common/uni-stat/stat/mod/statResult.js | 2151 +++ .../uni-stat/stat/mod/uni-pay/dao/config.js | 12 + .../uni-stat/stat/mod/uni-pay/dao/index.js | 10 + .../stat/mod/uni-pay/dao/uniIdUsers.js | 62 + .../stat/mod/uni-pay/dao/uniPayOrders.js | 99 + .../stat/mod/uni-pay/dao/uniStatPayResult.js | 36 + .../mod/uni-pay/dao/uniStatSessionLogs.js | 78 + .../mod/uni-pay/dao/uniStatUserSessionLogs.js | 78 + .../common/uni-stat/stat/mod/uni-pay/index.js | 6 + .../uni-stat/stat/mod/uni-pay/payResult.js | 500 + .../common/uni-stat/stat/mod/uniIDUsers.js | 97 + .../uni-stat/stat/mod/userSessionLog.js | 229 + .../common/uni-stat/stat/mod/version.js | 73 + .../common/uni-stat/stat/receiver.js | 126 + .../common/uni-stat/stat/stat.js | 388 + .../uni-analyse-searchhot/index.js | 49 + .../uni-analyse-searchhot/package.json | 14 + .../uni-portal/createPublishHtml/index.js | 188 + .../createPublishHtml/lib/art-template.js | 2 + .../createPublishHtml/template.html | 238 + .../cloudfunctions/uni-portal/index.js | 25 + .../cloudfunctions/uni-portal/package.json | 7 + .../uni-sms-co/build-template-data.js | 26 + .../cloudfunctions/uni-sms-co/index.obj.js | 374 + .../cloudfunctions/uni-sms-co/package.json | 10 + .../uni-sms-co/schema-name-adapter.js | 15 + .../cloudfunctions/uni-sms-co/utils.js | 42 + .../cloudfunctions/uni-stat-cron/index.js | 6 + .../cloudfunctions/uni-stat-cron/package.json | 27 + .../uni-stat-receiver/index.obj.js | 29 + .../uni-stat-receiver/package.json | 16 + .../uni-upgrade-center/checkVersion/index.js | 167 + .../uni-upgrade-center/index.js | 91 + .../uni-upgrade-center/package.json | 7 + .../uni-app-manager.param.json | 10 + .../wxpay-virtual-co/index.obj.js | 122 + .../wxpay-virtual-co/package.json | 5 + .../wxpay-virtual-co.param.js | 16 + uniCloud-aliyun/database/JQL查询.jql | 12 + uniCloud-aliyun/database/db_init.json | 549 + uniCloud-aliyun/database/dictItem.jql | 12 + .../database/lab_custom.schema.json | 1 + .../database/ngTools_Dict.schema.json | 1 + .../database/ngTools_DictItem.schema.json | 1 + .../database/ngTools_MeterList.schema.json | 1 + .../database/ngTools_MeterPar.schema.json | 1 + .../database/ngTools_NGComponents.schema.json | 210 + .../database/ngTools_NGPar.schema.json | 1 + .../ngTools_SamplingLocation.schema.json | 34 + .../database/ngTools_depart.schema.json | 1 + .../database/ngtools-categories.schema.json | 61 + .../database/ngtools-goods.schema.json | 124 + .../database/ngtools_MeterResult.schema.json | 1 + .../database/ngtools_NGResult.schema.json | 1 + .../database/ngtools_information.schema.json | 65 + .../opendb-admin-menus.init_data.json | 453 + .../database/opendb-admin-menus.schema.json | 1 + .../database/opendb-app-list.init_data.json | 1 + .../database/opendb-app-list.schema.json | 1 + .../opendb-app-versions.init_data.json | 1 + .../database/opendb-app-versions.schema.json | 1 + .../database/opendb-banner.init_data.json | 41 + .../database/opendb-banner.schema.json | 1 + .../database/opendb-department.init_data.json | 1 + .../database/opendb-department.schema.json | 1 + .../database/opendb-device.init_data.json | 1 + .../database/opendb-device.schema.json | 1 + .../database/opendb-feedback.init_data.json | 1 + .../database/opendb-feedback.schema.json | 1 + .../opendb-news-articles.init_data.json | 17 + .../database/opendb-news-articles.schema.json | 1 + .../opendb-news-categories.init_data.json | 1 + .../opendb-news-categories.schema.json | 1 + .../opendb-news-comments.init_data.json | 1 + .../database/opendb-news-comments.schema.json | 1 + .../opendb-news-favorite.init_data.json | 1 + .../database/opendb-news-favorite.schema.json | 1 + .../database/opendb-open-data.init_data.json | 1 + .../database/opendb-open-data.schema.json | 1 + .../database/opendb-search-hot.init_data.json | 1 + .../database/opendb-search-hot.schema.json | 1 + .../database/opendb-search-log.init_data.json | 1 + .../database/opendb-search-log.schema.json | 1 + .../database/opendb-sign-in.init_data.json | 1 + .../database/opendb-sign-in.schema.json | 1 + .../database/opendb-sms-log.init_data.json | 1 + .../database/opendb-sms-log.schema.json | 1 + .../database/opendb-sms-task.init_data.json | 1 + .../database/opendb-sms-task.schema.json | 1 + .../opendb-sms-template.init_data.json | 1 + .../database/opendb-sms-template.schema.json | 1 + .../database/opendb-tempdata.init_data.json | 1 + .../database/opendb-tempdata.schema.json | 1 + .../opendb-verify-codes.init_data.json | 1 + .../database/opendb-verify-codes.schema.json | 1 + .../database/read-news-log.init_data.json | 1 + .../database/read-news-log.schema.json | 35 + .../database/uni-id-device.init_data.json | 1 + .../database/uni-id-device.schema.json | 1 + .../database/uni-id-log.init_data.json | 1 + .../database/uni-id-log.schema.json | 1 + .../uni-id-permissions.init_data.json | 1 + .../database/uni-id-permissions.schema.json | 1 + .../database/uni-id-roles.init_data.json | 9 + .../database/uni-id-roles.schema.json | 1 + .../database/uni-id-scores.init_data.json | 1 + .../database/uni-id-scores.schema.json | 1 + .../database/uni-id-tag.init_data.json | 1 + .../database/uni-id-tag.schema.json | 1 + .../database/uni-id-users.init_data.json | 10 + .../database/uni-id-users.schema.json | 1 + .../database/uni-pay-orders.init_data.json | 1 + .../database/uni-pay-orders.schema.json | 1 + .../uni-stat-active-devices.init_data.json | 1 + .../uni-stat-active-devices.schema.json | 1 + .../uni-stat-active-users.init_data.json | 1 + .../uni-stat-active-users.schema.json | 1 + .../uni-stat-app-channels.init_data.json | 1 + .../uni-stat-app-channels.schema.json | 1 + .../uni-stat-app-crash-logs.init_data.json | 1 + .../uni-stat-app-crash-logs.schema.json | 1 + .../uni-stat-app-platforms.init_data.json | 1 + .../uni-stat-app-platforms.schema.json | 1 + .../uni-stat-app-versions.init_data.json | 1 + .../uni-stat-app-versions.schema.json | 1 + .../uni-stat-error-logs.init_data.json | 1 + .../database/uni-stat-error-logs.schema.json | 1 + .../uni-stat-error-result.init_data.json | 1 + .../uni-stat-error-result.schema.json | 1 + .../uni-stat-error-source-map.init_data.json | 1 + .../uni-stat-error-source-map.schema.ext.js | 29 + .../uni-stat-error-source-map.schema.json | 1 + .../uni-stat-event-logs.init_data.json | 1 + .../database/uni-stat-event-logs.schema.json | 1 + .../uni-stat-event-result.init_data.json | 1 + .../uni-stat-event-result.schema.json | 1 + .../database/uni-stat-events.init_data.json | 1 + .../database/uni-stat-events.schema.json | 1 + .../uni-stat-loyalty-result.init_data.json | 1 + .../uni-stat-loyalty-result.schema.json | 1 + .../uni-stat-mp-scenes.init_data.json | 1 + .../database/uni-stat-mp-scenes.schema.json | 1 + .../uni-stat-page-detail-result.schema.json | 95 + .../uni-stat-page-details.schema.json | 42 + .../uni-stat-page-logs.init_data.json | 1 + .../database/uni-stat-page-logs.schema.json | 1 + .../uni-stat-page-result.init_data.json | 1 + .../database/uni-stat-page-result.schema.json | 1 + .../database/uni-stat-pages.init_data.json | 1 + .../database/uni-stat-pages.schema.json | 1 + .../uni-stat-pay-result.init_data.json | 1 + .../database/uni-stat-pay-result.schema.json | 1 + .../database/uni-stat-result.init_data.json | 1 + .../database/uni-stat-result.schema.json | 1 + .../uni-stat-run-errors.init_data.json | 1 + .../database/uni-stat-run-errors.schema.json | 1 + .../uni-stat-session-logs.init_data.json | 1 + .../uni-stat-session-logs.schema.json | 1 + .../uni-stat-share-logs.init_data.json | 1 + .../database/uni-stat-share-logs.schema.json | 1 + .../uni-stat-user-session-logs.init_data.json | 1 + .../uni-stat-user-session-logs.schema.json | 1 + uni_modules/json-gps/changelog.md | 2 + uni_modules/json-gps/js_sdk/gps.js | 132 + .../js_sdk/wa-permission/permission.js | 272 + uni_modules/json-gps/package.json | 76 + uni_modules/json-gps/readme.md | 30 + .../json-interceptor-chooseImage/changelog.md | 6 + .../js_sdk/main.js | 70 + .../json-interceptor-chooseImage/package.json | 76 + .../json-interceptor-chooseImage/readme.md | 30 + uni_modules/kevy-collapse/changelog.md | 31 + .../kevy-collapse/kevy-collapse.vue | 312 + uni_modules/kevy-collapse/package.json | 85 + uni_modules/kevy-collapse/readme.md | 122 + .../kevy-collapse/static/icon/iconfont.css | 19 + .../kevy-collapse/static/icon/iconfont.ttf | Bin 0 -> 1596 bytes .../kevy-collapse/static/icon/iconfont.woff | Bin 0 -> 992 bytes .../kevy-collapse/static/icon/iconfont.woff2 | Bin 0 -> 640 bytes uni_modules/next-search-more/changelog.md | 20 + .../next-search-more/next-search-more.vue | 239 + uni_modules/next-search-more/package.json | 79 + uni_modules/next-search-more/readme.md | 215 + uni_modules/next-tree/changelog.md | 169 + .../components/next-tree/next-tree.vue | 1034 ++ .../next-tree/components/next-tree/style.css | 269 + uni_modules/next-tree/package.json | 84 + uni_modules/next-tree/readme.md | 843 + uni_modules/sv-excel-json-each/changelog.md | 12 + .../sv-excel-json-each/js_sdk/parseExcel.js | 125 + .../js_sdk/plusFilePicker.js | 107 + uni_modules/sv-excel-json-each/package.json | 83 + uni_modules/sv-excel-json-each/readme.md | 151 + .../common/sv-excel-json-handler/index.js | 143 + .../sv-excel-json-handler/lib/cpexcel.js | 1506 ++ .../sv-excel-json-handler/lib/xlsx.style.js | 3 + .../common/sv-excel-json-handler/package.json | 12 + .../sv-excel-json-handler/util/index.js | 147 + .../sv-excel-json-each/index.obj.js | 21 + .../sv-excel-json-each/package-lock.json | 21 + .../sv-excel-json-each/package.json | 7 + uni_modules/uni-badge/changelog.md | 33 + .../components/uni-badge/uni-badge.vue | 268 + uni_modules/uni-badge/package.json | 85 + uni_modules/uni-badge/readme.md | 10 + uni_modules/uni-calendar/changelog.md | 26 + .../components/uni-calendar/calendar.js | 546 + .../components/uni-calendar/i18n/en.json | 12 + .../components/uni-calendar/i18n/index.js | 8 + .../components/uni-calendar/i18n/zh-Hans.json | 12 + .../components/uni-calendar/i18n/zh-Hant.json | 12 + .../uni-calendar/uni-calendar-item.vue | 187 + .../components/uni-calendar/uni-calendar.vue | 566 + .../components/uni-calendar/util.js | 360 + uni_modules/uni-calendar/package.json | 85 + uni_modules/uni-calendar/readme.md | 103 + uni_modules/uni-captcha/changelog.md | 45 + .../components/uni-captcha/uni-captcha.uvue | 180 + .../components/uni-captcha/uni-captcha.vue | 167 + .../uni-popup-captcha/uni-popup-captcha.uvue | 134 + .../uni-popup-captcha/uni-popup-captcha.vue | 140 + uni_modules/uni-captcha/package.json | 81 + uni_modules/uni-captcha/readme.md | 3 + uni_modules/uni-captcha/static/run.gif | Bin 0 -> 31089 bytes .../common/uni-captcha/LICENSE.md | 201 + .../common/uni-captcha/fonts/font.ttf | Bin 0 -> 7080 bytes .../common/uni-captcha/index.js | 1 + .../common/uni-captcha/package.json | 16 + .../cloudfunctions/uni-captcha-co/config.js | 17 + .../uni-captcha-co/index.obj.js | 35 + .../uni-captcha-co/package.json | 10 + uni_modules/uni-card/changelog.md | 26 + .../uni-card/components/uni-card/uni-card.vue | 270 + uni_modules/uni-card/package.json | 90 + uni_modules/uni-card/readme.md | 12 + uni_modules/uni-cloud-s2s/changelog.md | 2 + uni_modules/uni-cloud-s2s/package.json | 83 + uni_modules/uni-cloud-s2s/readme.md | 3 + .../common/uni-cloud-s2s/index.js | 1 + .../common/uni-cloud-s2s/package.json | 11 + uni_modules/uni-collapse/changelog.md | 36 + .../uni-collapse-item/uni-collapse-item.vue | 402 + .../components/uni-collapse/uni-collapse.vue | 147 + uni_modules/uni-collapse/package.json | 89 + uni_modules/uni-collapse/readme.md | 12 + uni_modules/uni-combox/changelog.md | 15 + .../components/uni-combox/uni-combox.vue | 275 + uni_modules/uni-combox/package.json | 90 + uni_modules/uni-combox/readme.md | 11 + 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-ad/config.json | 3 + .../uni-config-center/uni-id/config.json | 66 + .../uni-open-bridge/config.json | 12 + .../alipay/alipayCertPublicKey_RSA2.crt | 3 + .../uni-pay/alipay/alipayRootCert.crt | 3 + .../uni-pay/alipay/appCertPublicKey.crt | 3 + .../uni-config-center/uni-pay/config.js | 137 + .../uni-pay/wxpay/apiclient_cert.p12 | 0 .../uni-pay/wxpay/apiclient_cert.pem | 3 + .../uni-pay/wxpay/apiclient_key.pem | 3 + .../uni-pay/【重要】请先看这里.md | 137 + uni_modules/uni-countdown/changelog.md | 24 + .../components/uni-countdown/i18n/en.json | 6 + .../components/uni-countdown/i18n/index.js | 8 + .../uni-countdown/i18n/zh-Hans.json | 6 + .../uni-countdown/i18n/zh-Hant.json | 6 + .../uni-countdown/uni-countdown.vue | 271 + uni_modules/uni-countdown/package.json | 86 + uni_modules/uni-countdown/readme.md | 10 + uni_modules/uni-data-checkbox/changelog.md | 49 + .../components/uni-data-checkbox/clientdb.js | 316 + .../uni-data-checkbox/uni-data-checkbox.vue | 849 ++ uni_modules/uni-data-checkbox/package.json | 84 + uni_modules/uni-data-checkbox/readme.md | 18 + uni_modules/uni-data-picker/changelog.md | 77 + .../components/uni-data-picker/config.json | 12 + .../components/uni-data-picker/keypress.js | 45 + .../uni-data-picker/uni-data-picker.uvue | 380 + .../uni-data-picker/uni-data-picker.vue | 551 + .../uni-data-pickerview/loading.uts | 1 + .../uni-data-pickerview/uni-data-picker.js | 622 + .../uni-data-pickerview/uni-data-picker.uts | 693 + .../uni-data-pickerview.css | 76 + .../uni-data-pickerview.uvue | 69 + .../uni-data-pickerview.vue | 323 + uni_modules/uni-data-picker/package.json | 91 + uni_modules/uni-data-picker/readme.md | 22 + uni_modules/uni-data-select/changelog.md | 35 + .../uni-data-select/uni-data-select.vue | 517 + uni_modules/uni-data-select/package.json | 85 + uni_modules/uni-data-select/readme.md | 8 + uni_modules/uni-dateformat/changelog.md | 10 + .../components/uni-dateformat/date-format.js | 200 + .../uni-dateformat/uni-dateformat.vue | 88 + uni_modules/uni-dateformat/package.json | 88 + uni_modules/uni-dateformat/readme.md | 11 + uni_modules/uni-datetime-picker/changelog.md | 160 + .../uni-datetime-picker/calendar-item.vue | 177 + .../uni-datetime-picker/calendar.js | 546 + .../uni-datetime-picker/calendar.vue | 947 ++ .../uni-datetime-picker/i18n/en.json | 22 + .../uni-datetime-picker/i18n/index.js | 8 + .../uni-datetime-picker/i18n/zh-Hans.json | 22 + .../uni-datetime-picker/i18n/zh-Hant.json | 22 + .../uni-datetime-picker/keypress.js | 45 + .../uni-datetime-picker/time-picker.vue | 940 ++ .../uni-datetime-picker.vue | 1057 ++ .../components/uni-datetime-picker/util.js | 421 + uni_modules/uni-datetime-picker/package.json | 88 + uni_modules/uni-datetime-picker/readme.md | 21 + uni_modules/uni-drawer/changelog.md | 13 + .../components/uni-drawer/keypress.js | 45 + .../components/uni-drawer/uni-drawer.vue | 183 + uni_modules/uni-drawer/package.json | 87 + uni_modules/uni-drawer/readme.md | 10 + uni_modules/uni-easyinput/changelog.md | 113 + .../components/uni-easyinput/common.js | 54 + .../uni-easyinput/uni-easyinput.vue | 693 + uni_modules/uni-easyinput/package.json | 88 + uni_modules/uni-easyinput/readme.md | 11 + uni_modules/uni-fab/changelog.md | 23 + .../uni-fab/components/uni-fab/uni-fab.vue | 491 + .../components/uni-fab/uni-fab.vue.bak | 383 + uni_modules/uni-fab/package.json | 84 + uni_modules/uni-fab/readme.md | 9 + uni_modules/uni-fav/changelog.md | 19 + .../uni-fav/components/uni-fav/i18n/en.json | 4 + .../uni-fav/components/uni-fav/i18n/index.js | 8 + .../components/uni-fav/i18n/zh-Hans.json | 4 + .../components/uni-fav/i18n/zh-Hant.json | 4 + .../uni-fav/components/uni-fav/uni-fav.vue | 161 + uni_modules/uni-fav/package.json | 89 + uni_modules/uni-fav/readme.md | 10 + uni_modules/uni-feedback/changelog.md | 8 + .../js_sdk/validator/opendb-feedback.js | 98 + uni_modules/uni-feedback/package.json | 92 + .../pages/opendb-feedback/detail.vue | 113 + .../pages/opendb-feedback/edit.vue | 167 + .../pages/opendb-feedback/list.vue | 70 + .../pages/opendb-feedback/opendb-feedback.vue | 141 + uni_modules/uni-feedback/readme.md | 1 + uni_modules/uni-file-picker/changelog.md | 75 + .../uni-file-picker/choose-and-upload-file.js | 287 + .../uni-file-picker/uni-file-picker.vue | 678 + .../uni-file-picker/upload-file.vue | 325 + .../uni-file-picker/upload-image.vue | 292 + .../components/uni-file-picker/utils.js | 110 + uni_modules/uni-file-picker/package.json | 83 + uni_modules/uni-file-picker/readme.md | 11 + uni_modules/uni-forms/changelog.md | 94 + .../uni-forms-item/uni-forms-item.vue | 627 + .../components/uni-forms/uni-forms.vue | 397 + .../uni-forms/components/uni-forms/utils.js | 293 + .../components/uni-forms/validate.js | 486 + uni_modules/uni-forms/package.json | 88 + uni_modules/uni-forms/readme.md | 23 + uni_modules/uni-goods-nav/changelog.md | 18 + .../components/uni-goods-nav/i18n/en.json | 6 + .../components/uni-goods-nav/i18n/index.js | 8 + .../uni-goods-nav/i18n/zh-Hans.json | 6 + .../uni-goods-nav/i18n/zh-Hant.json | 6 + .../uni-goods-nav/uni-goods-nav.vue | 229 + uni_modules/uni-goods-nav/package.json | 88 + uni_modules/uni-goods-nav/readme.md | 10 + uni_modules/uni-grid/changelog.md | 13 + .../uni-grid-item/uni-grid-item.vue | 127 + .../uni-grid/components/uni-grid/uni-grid.vue | 142 + uni_modules/uni-grid/package.json | 86 + uni_modules/uni-grid/readme.md | 11 + uni_modules/uni-group/changelog.md | 16 + .../components/uni-group/uni-group.vue | 134 + uni_modules/uni-group/package.json | 87 + uni_modules/uni-group/readme.md | 9 + uni_modules/uni-icons/changelog.md | 42 + .../uni-icons/components/uni-icons/icons.js | 1169 ++ .../components/uni-icons/uni-icons.uvue | 91 + .../components/uni-icons/uni-icons.vue | 110 + .../uni-icons/components/uni-icons/uni.ttf | Bin 0 -> 26164 bytes .../components/uni-icons/uniicons.css | 664 + .../components/uni-icons/uniicons.ttf | Bin 0 -> 35824 bytes .../components/uni-icons/uniicons_file.ts | 664 + .../components/uni-icons/uniicons_file_vue.js | 649 + uni_modules/uni-icons/package.json | 89 + uni_modules/uni-icons/readme.md | 8 + uni_modules/uni-id-common/changelog.md | 34 + uni_modules/uni-id-common/package.json | 84 + uni_modules/uni-id-common/readme.md | 3 + .../common/uni-id-common/index.js | 1 + .../common/uni-id-common/package.json | 16 + uni_modules/uni-id-pages/changelog.md | 174 + .../uni-id-pages/common/check-id-card.js | 16 + .../uni-id-pages/common/login-page.mixin.js | 96 + .../uni-id-pages/common/login-page.scss | 126 + uni_modules/uni-id-pages/common/password.js | 85 + uni_modules/uni-id-pages/common/store.js | 174 + .../components/cloud-image/cloud-image.vue | 73 + .../uni-id-pages-agreements.vue | 167 + .../uni-id-pages-avatar.vue | 200 + .../uni-id-pages-bind-mobile.vue | 160 + .../uni-id-pages-email-form.vue | 248 + .../uni-id-pages-fab-login.vue | 568 + .../uni-id-pages-sms-form.vue | 242 + .../uni-id-pages-user-profile.vue | 171 + uni_modules/uni-id-pages/config.js | 67 + uni_modules/uni-id-pages/init.js | 95 + uni_modules/uni-id-pages/package.json | 102 + .../pages/common/webview/webview.vue | 35 + .../pages/login/login-smscode.vue | 120 + .../pages/login/login-withoutpwd.vue | 257 + .../pages/login/login-withpwd.vue | 177 + .../pages/register/register-admin.vue | 178 + .../pages/register/register-by-email.vue | 216 + .../uni-id-pages/pages/register/register.vue | 181 + .../uni-id-pages/pages/register/validator.js | 56 + .../pages/retrieve/retrieve-by-email.vue | 218 + .../uni-id-pages/pages/retrieve/retrieve.vue | 241 + .../userinfo/bind-mobile/bind-mobile.vue | 131 + .../pages/userinfo/change_pwd/change_pwd.vue | 130 + .../pages/userinfo/cropImage/cropImage.vue | 39 + .../userinfo/cropImage/limeClipper/README.md | 227 + .../cropImage/limeClipper/images/photo.svg | 19 + .../cropImage/limeClipper/images/rotate.svg | 15 + .../userinfo/cropImage/limeClipper/index.css | 160 + .../cropImage/limeClipper/limeClipper.vue | 820 + .../userinfo/cropImage/limeClipper/utils.js | 244 + .../pages/userinfo/deactivate/deactivate.vue | 117 + .../realname-verify/face-verify-icon.svg | 1 + .../realname-verify/realname-verify.vue | 315 + .../pages/userinfo/set-pwd/set-pwd.vue | 171 + .../uni-id-pages/pages/userinfo/userinfo.vue | 272 + uni_modules/uni-id-pages/readme.md | 15 + .../uni-id-pages/static/app-plus/apple.png | Bin 0 -> 10282 bytes .../static/app-plus/uni-fab-login/alipay.png | Bin 0 -> 3978 bytes .../static/app-plus/uni-fab-login/apple.png | Bin 0 -> 3226 bytes .../static/app-plus/uni-fab-login/douyin.png | Bin 0 -> 3163 bytes .../app-plus/uni-fab-login/facebook.png | Bin 0 -> 3065 bytes .../static/app-plus/uni-fab-login/google.png | Bin 0 -> 4333 bytes .../static/app-plus/uni-fab-login/qq.png | Bin 0 -> 3449 bytes .../app-plus/uni-fab-login/sinaweibo.png | Bin 0 -> 4081 bytes .../static/app-plus/uni-fab-login/taobao.png | Bin 0 -> 4339 bytes .../app-plus/uni-fab-login/univerify.png | Bin 0 -> 3365 bytes .../uni-id-pages/static/limeClipper/photo.svg | 19 + .../static/limeClipper/rotate.svg | 15 + .../static/login/uni-fab-login/sms.png | Bin 0 -> 4285 bytes .../static/login/uni-fab-login/user.png | Bin 0 -> 2997 bytes .../static/login/uni-fab-login/weixin.png | Bin 0 -> 3934 bytes .../uni-id-pages/static/login/weixin.png | Bin 0 -> 11483 bytes .../uni-id-co/common/constants.js | 108 + .../cloudfunctions/uni-id-co/common/error.js | 70 + .../uni-id-co/common/sensitive-aes-cipher.js | 64 + .../uni-id-co/common/universal.js | 47 + .../cloudfunctions/uni-id-co/common/utils.js | 270 + .../uni-id-co/common/validator.js | 443 + .../uni-id-co/config/permission.js | 90 + .../cloudfunctions/uni-id-co/index.obj.js | 694 + .../cloudfunctions/uni-id-co/lang/en.js | 62 + .../cloudfunctions/uni-id-co/lang/index.js | 22 + .../cloudfunctions/uni-id-co/lang/zh-hans.js | 64 + .../cloudfunctions/uni-id-co/lib/README.md | 3 + .../lib/third-party/alipay/account/index.js | 16 + .../third-party/alipay/account/protocols.js | 10 + .../lib/third-party/alipay/alipayBase.js | 231 + .../lib/third-party/apple/account/index.js | 76 + .../third-party/apple/rsa-public-key-pem.js | 64 + .../uni-id-co/lib/third-party/index.js | 36 + .../lib/third-party/qq/account/index.js | 97 + .../lib/third-party/qq/account/protocol.js | 0 .../uni-id-co/lib/third-party/qq/normalize.js | 85 + .../lib/third-party/share/create-api.js | 73 + .../lib/third-party/weixin/account/index.js | 111 + .../lib/third-party/weixin/normalize.js | 95 + .../uni-id-co/lib/third-party/weixin/utils.js | 87 + .../uni-id-co/lib/utils/account.js | 98 + .../uni-id-co/lib/utils/captcha.js | 76 + .../uni-id-co/lib/utils/config.js | 135 + .../uni-id-co/lib/utils/fission.js | 192 + .../uni-id-co/lib/utils/login.js | 246 + .../uni-id-co/lib/utils/logout.js | 49 + .../uni-id-co/lib/utils/password.js | 261 + .../cloudfunctions/uni-id-co/lib/utils/qq.js | 152 + .../uni-id-co/lib/utils/register.js | 229 + .../uni-id-co/lib/utils/relate.js | 164 + .../cloudfunctions/uni-id-co/lib/utils/sms.js | 79 + .../uni-id-co/lib/utils/unified-login.js | 106 + .../uni-id-co/lib/utils/univerify.js | 27 + .../uni-id-co/lib/utils/update-user-info.js | 25 + .../uni-id-co/lib/utils/utils.js | 18 + .../uni-id-co/lib/utils/verify-code.js | 152 + .../uni-id-co/lib/utils/weixin.js | 234 + .../uni-id-co/middleware/access-control.js | 59 + .../uni-id-co/middleware/auth.js | 17 + .../uni-id-co/middleware/index.js | 8 + .../uni-id-co/middleware/rbac.js | 39 + .../uni-id-co/middleware/uni-id-log.js | 39 + .../uni-id-co/middleware/validate.js | 7 + .../middleware/verify-request-sign.js | 85 + .../uni-id-co/module/account/close-account.js | 16 + .../module/account/get-account-info.js | 69 + .../module/account/get-realname-info.js | 45 + .../uni-id-co/module/account/index.js | 9 + .../module/account/reset-pwd-by-email.js | 128 + .../module/account/reset-pwd-by-sms.js | 128 + .../uni-id-co/module/account/set-pwd.js | 83 + .../uni-id-co/module/account/update-pwd.js | 69 + .../uni-id-co/module/admin/add-user.js | 131 + .../uni-id-co/module/admin/index.js | 4 + .../uni-id-co/module/admin/update-user.js | 138 + .../module/dev/get-supported-login-type.js | 70 + .../uni-id-co/module/dev/index.js | 3 + .../uni-id-co/module/external/index.js | 5 + .../uni-id-co/module/external/login.js | 68 + .../uni-id-co/module/external/register.js | 93 + .../module/external/update-user-info.js | 208 + .../get-auth-result.js | 135 + .../get-certify-id.js | 99 + .../module/facial-recognition-verify/index.js | 4 + .../uni-id-co/module/fission/accept-invite.js | 25 + .../module/fission/get-invited-user.js | 80 + .../uni-id-co/module/fission/index.js | 4 + .../uni-id-co/module/login/index.js | 20 + .../uni-id-co/module/login/login-by-alipay.js | 70 + .../uni-id-co/module/login/login-by-apple.js | 77 + .../uni-id-co/module/login/login-by-baidu.js | 9 + .../module/login/login-by-dingtalk.js | 9 + .../uni-id-co/module/login/login-by-douyin.js | 9 + .../module/login/login-by-email-code.js | 9 + .../module/login/login-by-email-link.js | 9 + .../module/login/login-by-facebook.js | 9 + .../uni-id-co/module/login/login-by-google.js | 9 + .../uni-id-co/module/login/login-by-qq.js | 167 + .../uni-id-co/module/login/login-by-sms.js | 99 + .../uni-id-co/module/login/login-by-taobao.js | 9 + .../module/login/login-by-toutiao.js | 9 + .../module/login/login-by-univerify.js | 69 + .../uni-id-co/module/login/login-by-weibo.js | 9 + .../module/login/login-by-weixin-mobile.js | 106 + .../uni-id-co/module/login/login-by-weixin.js | 176 + .../uni-id-co/module/login/login.js | 94 + .../uni-id-co/module/logout/index.js | 3 + .../uni-id-co/module/logout/logout.js | 15 + .../module/multi-end/authorize-app-login.js | 37 + .../uni-id-co/module/multi-end/index.js | 5 + .../module/multi-end/remove-authorized-app.js | 30 + .../module/multi-end/set-authorized-app.js | 36 + .../uni-id-co/module/multi-end/utils.js | 38 + .../uni-id-co/module/register/index.js | 5 + .../module/register/register-admin.js | 72 + .../module/register/register-user-by-email.js | 87 + .../module/register/register-user.js | 68 + .../uni-id-co/module/relate/bind-alipay.js | 63 + .../uni-id-co/module/relate/bind-apple.js | 62 + .../module/relate/bind-mobile-by-mp-weixin.js | 104 + .../module/relate/bind-mobile-by-sms.js | 92 + .../module/relate/bind-mobile-by-univerify.js | 70 + .../uni-id-co/module/relate/bind-qq.js | 110 + .../uni-id-co/module/relate/bind-weixin.js | 100 + .../uni-id-co/module/relate/index.js | 13 + .../uni-id-co/module/relate/unbind-alipay.js | 32 + .../uni-id-co/module/relate/unbind-apple.js | 32 + .../uni-id-co/module/relate/unbind-qq.js | 33 + .../uni-id-co/module/relate/unbind-weixin.js | 38 + .../uni-id-co/module/utils/index.js | 5 + .../uni-id-co/module/utils/refresh-token.js | 24 + .../secure-network-handshake-by-weixin.js | 73 + .../uni-id-co/module/utils/set-push-cid.js | 132 + .../uni-id-co/module/verify/create-captcha.js | 35 + .../uni-id-co/module/verify/index.js | 7 + .../module/verify/refresh-captcha.js | 36 + .../module/verify/send-email-code.js | 60 + .../module/verify/send-email-link.js | 12 + .../uni-id-co/module/verify/send-sms-code.js | 71 + .../uni-id-co/package-lock.json | 2843 ++++ .../cloudfunctions/uni-id-co/package.json | 32 + .../database/opendb-frv-logs.schema.json | 1 + uni_modules/uni-image-menu/changelog.md | 0 .../uni-image-menu/js_sdk/uni-image-menu.js | 169 + uni_modules/uni-image-menu/package.json | 76 + uni_modules/uni-image-menu/readme.md | 19 + uni_modules/uni-indexed-list/changelog.md | 17 + .../uni-indexed-list-item.vue | 144 + .../uni-indexed-list/uni-indexed-list.vue | 367 + uni_modules/uni-indexed-list/package.json | 89 + uni_modules/uni-indexed-list/readme.md | 11 + uni_modules/uni-link/changelog.md | 17 + .../uni-link/components/uni-link/uni-link.vue | 128 + uni_modules/uni-link/package.json | 87 + uni_modules/uni-link/readme.md | 11 + uni_modules/uni-list/changelog.md | 46 + .../components/uni-list-ad/uni-list-ad.vue | 107 + .../uni-list-chat/uni-list-chat.scss | 58 + .../uni-list-chat/uni-list-chat.vue | 593 + .../uni-list-item/uni-list-item.vue | 534 + .../components/uni-list/uni-list - 副本.vue | 106 + .../uni-list/components/uni-list/uni-list.vue | 123 + .../components/uni-list/uni-refresh.vue | 65 + .../components/uni-list/uni-refresh.wxs | 87 + uni_modules/uni-list/package.json | 88 + uni_modules/uni-list/readme.md | 346 + uni_modules/uni-load-more/changelog.md | 19 + .../components/uni-load-more/i18n/en.json | 5 + .../components/uni-load-more/i18n/index.js | 8 + .../uni-load-more/i18n/zh-Hans.json | 5 + .../uni-load-more/i18n/zh-Hant.json | 5 + .../uni-load-more/uni-load-more.vue | 399 + uni_modules/uni-load-more/package.json | 86 + uni_modules/uni-load-more/readme.md | 14 + uni_modules/uni-nav-bar/changelog.md | 51 + .../components/uni-nav-bar/uni-nav-bar.vue | 357 + .../components/uni-nav-bar/uni-status-bar.vue | 24 + uni_modules/uni-nav-bar/package.json | 86 + uni_modules/uni-nav-bar/readme.md | 15 + uni_modules/uni-notice-bar/changelog.md | 18 + .../uni-notice-bar/uni-notice-bar.vue | 426 + uni_modules/uni-notice-bar/package.json | 87 + uni_modules/uni-notice-bar/readme.md | 13 + uni_modules/uni-number-box/changelog.md | 29 + .../uni-number-box/uni-number-box.vue | 221 + uni_modules/uni-number-box/package.json | 82 + uni_modules/uni-number-box/readme.md | 13 + .../uni-open-bridge-common/changelog.md | 25 + .../uni-open-bridge-common/package.json | 84 + uni_modules/uni-open-bridge-common/readme.md | 5 + .../uni-open-bridge-common/bridge-error.js | 26 + .../common/uni-open-bridge-common/config.js | 124 + .../common/uni-open-bridge-common/consts.js | 30 + .../common/uni-open-bridge-common/index.js | 317 + .../uni-open-bridge-common/package.json | 15 + .../common/uni-open-bridge-common/storage.js | 111 + .../uni-open-bridge-common/uni-cloud-cache.js | 324 + .../uni-open-bridge-common/validator.js | 31 + .../uni-open-bridge-common/weixin-server.js | 203 + uni_modules/uni-open-bridge/changelog.md | 0 uni_modules/uni-open-bridge/package.json | 84 + uni_modules/uni-open-bridge/readme.md | 577 + .../cloudfunctions/uni-open-bridge/basic.js | 131 + .../cloudfunctions/uni-open-bridge/config.js | 197 + .../cloudfunctions/uni-open-bridge/consts.js | 19 + .../uni-open-bridge/index.mp-weixin.js | 93 + .../uni-open-bridge/index.obj.js | 62 + .../uni-open-bridge/index.task.js | 86 + .../uni-open-bridge/package.json | 10 + .../uni-open-bridge/task-h5-weixin.js | 67 + .../uni-open-bridge/task-mp-weixin.js | 41 + uni_modules/uni-pagination/changelog.md | 27 + .../components/uni-pagination/i18n/en.json | 5 + .../components/uni-pagination/i18n/es.json | 5 + .../components/uni-pagination/i18n/fr.json | 5 + .../components/uni-pagination/i18n/index.js | 12 + .../uni-pagination/i18n/zh-Hans.json | 5 + .../uni-pagination/i18n/zh-Hant.json | 5 + .../uni-pagination/uni-pagination.vue | 465 + uni_modules/uni-pagination/package.json | 83 + uni_modules/uni-pagination/readme.md | 11 + uni_modules/uni-pay/changelog.md | 86 + .../uni-pay/components/uni-pay/uni-pay.vue | 927 ++ uni_modules/uni-pay/js_sdk/appleiap.js | 123 + uni_modules/uni-pay/js_sdk/js_sdk.js | 158 + uni_modules/uni-pay/package.json | 83 + .../ad-interactive-webview.vue | 18 + .../uni-pay/pages/pay-desk/pay-desk.vue | 116 + uni_modules/uni-pay/pages/success/success.vue | 233 + uni_modules/uni-pay/readme.md | 31 + uni_modules/uni-pay/static/alipay.png | Bin 0 -> 935 bytes uni_modules/uni-pay/static/wxpay.png | Bin 0 -> 1141 bytes .../cloudfunctions/common/uni-pay/LICENSE.md | 201 + .../cloudfunctions/common/uni-pay/index.js | 12698 ++++++++++++++++ .../common/uni-pay/package.json | 16 + .../cloudfunctions/uni-pay-co/common/error.js | 65 + .../uni-pay-co/config/permission.js | 9 + .../cloudfunctions/uni-pay-co/dao/index.js | 8 + .../uni-pay-co/dao/opendbOpenData.js | 104 + .../cloudfunctions/uni-pay-co/dao/readme.md | 1 + .../uni-pay-co/dao/uniIdUsers.js | 25 + .../uni-pay-co/dao/uniPayOrders.js | 108 + .../cloudfunctions/uni-pay-co/index.obj.js | 305 + .../cloudfunctions/uni-pay-co/lang/en.js | 33 + .../cloudfunctions/uni-pay-co/lang/index.js | 22 + .../cloudfunctions/uni-pay-co/lang/zh-hans.js | 33 + .../cloudfunctions/uni-pay-co/libs/alipay.js | 181 + .../uni-pay-co/libs/certutil.js | 1 + .../cloudfunctions/uni-pay-co/libs/common.js | 303 + .../cloudfunctions/uni-pay-co/libs/crypto.js | 159 + .../cloudfunctions/uni-pay-co/libs/index.js | 13 + .../cloudfunctions/uni-pay-co/libs/qrcode.js | 1 + .../cloudfunctions/uni-pay-co/libs/wxpay.js | 114 + .../uni-pay-co/middleware/access-control.js | 50 + .../uni-pay-co/middleware/auth.js | 28 + .../uni-pay-co/middleware/index.js | 7 + .../uni-pay-co/notify/appleiap.js | 81 + .../cloudfunctions/uni-pay-co/notify/test.js | 81 + .../uni-pay-co/notify/【重要】请先看这里.md | 52 + .../cloudfunctions/uni-pay-co/package.json | 17 + .../uni-pay-co/service/index.js | 5 + .../cloudfunctions/uni-pay-co/service/pay.js | 1128 ++ .../uni-pay-co/uni-pay-co.param.js | 28 + .../database/opendb-open-data.index.json | 14 + .../database/uni-pay-orders.index.json | 98 + uni_modules/uni-popup/changelog.md | 84 + .../components/uni-popup-dialog/keypress.js | 45 + .../uni-popup-dialog/uni-popup-dialog.vue | 316 + .../uni-popup-message/uni-popup-message.vue | 143 + .../uni-popup-share/uni-popup-share.vue | 187 + .../components/uni-popup/i18n/en.json | 7 + .../components/uni-popup/i18n/index.js | 8 + .../components/uni-popup/i18n/zh-Hans.json | 7 + .../components/uni-popup/i18n/zh-Hant.json | 7 + .../components/uni-popup/keypress.js | 45 + .../uni-popup/components/uni-popup/message.js | 22 + .../uni-popup/components/uni-popup/popup.js | 26 + .../uni-popup/components/uni-popup/share.js | 16 + .../components/uni-popup/uni-popup.uvue | 90 + .../components/uni-popup/uni-popup.vue | 503 + uni_modules/uni-popup/package.json | 88 + uni_modules/uni-popup/readme.md | 17 + uni_modules/uni-rate/changelog.md | 25 + .../uni-rate/components/uni-rate/uni-rate.vue | 361 + uni_modules/uni-rate/package.json | 88 + uni_modules/uni-rate/readme.md | 12 + uni_modules/uni-row/changelog.md | 10 + .../uni-row/components/uni-col/uni-col.vue | 317 + .../uni-row/components/uni-row/uni-row.vue | 190 + uni_modules/uni-row/package.json | 87 + uni_modules/uni-row/readme.md | 10 + uni_modules/uni-scss/changelog.md | 8 + uni_modules/uni-scss/index.scss | 1 + uni_modules/uni-scss/package.json | 82 + uni_modules/uni-scss/readme.md | 4 + uni_modules/uni-scss/styles/index.scss | 7 + .../uni-scss/styles/setting/_border.scss | 3 + .../uni-scss/styles/setting/_color.scss | 66 + .../uni-scss/styles/setting/_radius.scss | 55 + .../uni-scss/styles/setting/_space.scss | 56 + .../uni-scss/styles/setting/_styles.scss | 167 + .../uni-scss/styles/setting/_text.scss | 24 + .../uni-scss/styles/setting/_variables.scss | 146 + .../uni-scss/styles/tools/functions.scss | 19 + uni_modules/uni-scss/theme.scss | 31 + uni_modules/uni-scss/variables.scss | 62 + uni_modules/uni-search-bar/changelog.md | 35 + .../components/uni-search-bar/i18n/en.json | 4 + .../components/uni-search-bar/i18n/index.js | 8 + .../uni-search-bar/i18n/zh-Hans.json | 4 + .../uni-search-bar/i18n/zh-Hant.json | 4 + .../uni-search-bar/uni-search-bar.vue | 298 + uni_modules/uni-search-bar/package.json | 86 + uni_modules/uni-search-bar/readme.md | 14 + uni_modules/uni-section/changelog.md | 2 + .../components/uni-section/uni-section.vue | 167 + uni_modules/uni-section/package.json | 87 + uni_modules/uni-section/readme.md | 8 + .../uni-segmented-control/changelog.md | 9 + .../uni-segmented-control.vue | 145 + .../uni-segmented-control/package.json | 87 + uni_modules/uni-segmented-control/readme.md | 13 + uni_modules/uni-share/changelog.md | 18 + .../uni-share/js_sdk/uni-image-menu.js | 204 + uni_modules/uni-share/js_sdk/uni-share.js | 98 + uni_modules/uni-share/package.json | 80 + uni_modules/uni-share/readme.md | 95 + uni_modules/uni-sign-in/changelog.md | 12 + .../components/uni-sign-in/uni-sign-in.vue | 307 + uni_modules/uni-sign-in/package.json | 84 + uni_modules/uni-sign-in/pages/demo/demo.vue | 15 + uni_modules/uni-sign-in/readme.md | 86 + uni_modules/uni-sign-in/static/background.png | Bin 0 -> 30068 bytes .../cloudfunctions/common/sign-in/index.js | 106 + .../common/sign-in/package.json | 12 + .../rewarded-video-ad-notify-url/index.js | 64 + .../rewarded-video-ad-notify-url/package.json | 15 + .../uni-clientDB-actions/signIn.js | 90 + uni_modules/uni-sign-in/utils/ad.js | 253 + uni_modules/uni-steps/changelog.md | 16 + .../components/uni-steps/uni-steps.vue | 269 + uni_modules/uni-steps/package.json | 89 + uni_modules/uni-steps/readme.md | 13 + uni_modules/uni-swipe-action/changelog.md | 43 + .../uni-swipe-action-item/bindingx.js | 302 + .../uni-swipe-action-item/index.wxs | 323 + .../components/uni-swipe-action-item/isPC.js | 12 + .../uni-swipe-action-item/mpalipay.js | 195 + .../uni-swipe-action-item/mpother.js | 260 + .../components/uni-swipe-action-item/mpwxs.js | 84 + .../uni-swipe-action-item/render.js | 270 + .../uni-swipe-action-item.vue | 347 + .../components/uni-swipe-action-item/wx.wxs | 341 + .../uni-swipe-action/uni-swipe-action.vue | 60 + uni_modules/uni-swipe-action/package.json | 84 + uni_modules/uni-swipe-action/readme.md | 11 + uni_modules/uni-swiper-dot/changelog.md | 12 + .../uni-swiper-dot/uni-swiper-dot.vue | 218 + uni_modules/uni-swiper-dot/package.json | 87 + uni_modules/uni-swiper-dot/readme.md | 11 + uni_modules/uni-table/changelog.md | 27 + .../components/uni-table/uni-table.vue | 455 + .../components/uni-tbody/uni-tbody.vue | 29 + .../uni-table/components/uni-td/uni-td.vue | 90 + .../components/uni-th/filter-dropdown.vue | 511 + .../uni-table/components/uni-th/uni-th.vue | 285 + .../components/uni-thead/uni-thead.vue | 129 + .../components/uni-tr/table-checkbox.vue | 179 + .../uni-table/components/uni-tr/uni-tr.vue | 171 + uni_modules/uni-table/i18n/en.json | 9 + uni_modules/uni-table/i18n/es.json | 9 + uni_modules/uni-table/i18n/fr.json | 9 + uni_modules/uni-table/i18n/index.js | 12 + uni_modules/uni-table/i18n/zh-Hans.json | 9 + uni_modules/uni-table/i18n/zh-Hant.json | 9 + uni_modules/uni-table/package.json | 83 + uni_modules/uni-table/readme.md | 13 + uni_modules/uni-tag/changelog.md | 21 + .../uni-tag/components/uni-tag/uni-tag.vue | 252 + uni_modules/uni-tag/package.json | 87 + uni_modules/uni-tag/readme.md | 13 + uni_modules/uni-title/changelog.md | 10 + .../components/uni-title/uni-title.vue | 171 + uni_modules/uni-title/package.json | 88 + uni_modules/uni-title/readme.md | 14 + uni_modules/uni-tooltip/changelog.md | 10 + .../components/uni-tooltip/uni-tooltip.vue | 68 + uni_modules/uni-tooltip/package.json | 83 + uni_modules/uni-tooltip/readme.md | 8 + uni_modules/uni-transition/changelog.md | 24 + .../uni-transition/createAnimation.js | 131 + .../uni-transition/uni-transition.vue | 286 + uni_modules/uni-transition/package.json | 85 + uni_modules/uni-transition/readme.md | 11 + uni_modules/uni-ui/changelog.md | 541 + .../uni-ui/components/uni-ui/uni-ui.vue | 7 + uni_modules/uni-ui/package.json | 129 + uni_modules/uni-ui/readme.md | 247 + .../uni-upgrade-center-app/changelog.md | 70 + .../images/app_update_close.png | Bin 0 -> 7644 bytes .../uni-upgrade-center-app/images/bg_top.png | Bin 0 -> 30486 bytes .../uni-upgrade-center-app/package.json | 81 + .../pages/upgrade-popup.vue | 554 + uni_modules/uni-upgrade-center-app/readme.md | 126 + .../uniCloud/database/db_init.json | 1 + .../utils/call-check-version.js | 32 + .../utils/check-update.js | 158 + uni_modules/uni-upgrade-center/changelog.md | 51 + .../js_sdk/validator/opendb-app-list.js | 44 + .../js_sdk/validator/opendb-app-versions.js | 151 + uni_modules/uni-upgrade-center/menu.json | 10 + uni_modules/uni-upgrade-center/package.json | 91 + .../pages/components/show-info.vue | 52 + .../pages/mixin/version_add_detail_mixin.js | 187 + uni_modules/uni-upgrade-center/pages/utils.js | 26 + .../uni-upgrade-center/pages/version/add.vue | 412 + .../pages/version/detail.vue | 337 + .../uni-upgrade-center/pages/version/list.vue | 368 + uni_modules/uni-upgrade-center/readme.md | 233 + .../uniCloud/database/db_init.json | 10 + uni_modules/yjly-dictItemSelect/changelog.md | 0 .../yjly-dictItemSelect.vue | 78 + uni_modules/yjly-dictItemSelect/package.json | 83 + uni_modules/yjly-dictItemSelect/readme.md | 1 + .../yjly-ngtools-NGComponents/changelog.md | 0 .../yjly-ngtools-NGComponents.vue | 418 + .../yjly-ngtools-NGComponents/package.json | 83 + .../yjly-ngtools-NGComponents/readme.md | 1 + .../yjly-ngtools-ParResult/changelog.md | 0 .../yjly-ngtools-ParResult.vue | 556 + .../yjly-ngtools-ParResult/package.json | 83 + uni_modules/yjly-ngtools-ParResult/readme.md | 1 + .../yjly-ngtools-meterPar/changelog.md | 0 .../yjly-ngtools-meterPar.vue | 449 + .../yjly-ngtools-meterPar/package.json | 83 + uni_modules/yjly-ngtools-meterPar/readme.md | 1 + .../yjly-ngtools-meterResult/changelog.md | 0 .../yjly-ngtools-meterResult.vue | 321 + .../yjly-ngtools-meterResult/package.json | 83 + .../yjly-ngtools-meterResult/readme.md | 1 + 格式化.xlsx | Bin 0 -> 41137 bytes 1071 files changed, 138711 insertions(+) create mode 100644 .gitignore create mode 100644 .hbuilderx/launch.json create mode 100644 App.vue create mode 100644 LICENSE create mode 100644 README.md create mode 100644 androidPrivacy.json create mode 100644 changelog.md create mode 100644 common/appInit.js create mode 100644 common/openApp.js create mode 100644 components/refreshBox/refreshBox.vue create mode 100644 components/uni-load-state/i18n/en.json create mode 100644 components/uni-load-state/i18n/index.js create mode 100644 components/uni-load-state/i18n/zh-Hans.json create mode 100644 components/uni-load-state/readme.md create mode 100644 components/uni-load-state/uni-load-state.vue create mode 100644 index.html create mode 100644 js_sdk/AC-Dictionary/script/HttpDictionary.js create mode 100644 js_sdk/AC-Dictionary/script/Message.js create mode 100644 js_sdk/dc-deviceinfo/deviceinfo.js create mode 100644 js_sdk/util/dictTools.js create mode 100644 js_sdk/util/jsonData.js create mode 100644 js_sdk/validator/ngTools_Dict.js create mode 100644 js_sdk/validator/ngTools_DictItem.js create mode 100644 js_sdk/validator/ngTools_MeterList.js create mode 100644 js_sdk/validator/ngTools_MeterPar.js create mode 100644 js_sdk/validator/ngTools_NGComponents.js create mode 100644 js_sdk/validator/ngTools_NGPar.js create mode 100644 js_sdk/validator/ngTools_SamplingLocation.js create mode 100644 js_sdk/validator/ngTools_depart.js create mode 100644 js_sdk/validator/ngtools-categories.js create mode 100644 js_sdk/validator/ngtools-goods.js create mode 100644 js_sdk/validator/ngtools_information.js create mode 100644 js_sdk/validator/opendb-banner.js create mode 100644 js_sdk/validator/uni-id-users.js create mode 100644 lang/en.js create mode 100644 lang/i18n.js create mode 100644 lang/zh-Hans.js create mode 100644 main.js create mode 100644 manifest.json create mode 100644 package.json create mode 100644 pages.json create mode 100644 pages/grid/grid.vue create mode 100644 pages/list/detail.vue create mode 100644 pages/list/list.nvue create mode 100644 pages/ucenter.vue create mode 100644 pagesPackage/components/popup.vue create mode 100644 pagesPackage/ngTools_Dict/add.vue create mode 100644 pagesPackage/ngTools_Dict/detail.vue create mode 100644 pagesPackage/ngTools_Dict/edit.vue create mode 100644 pagesPackage/ngTools_Dict/list.vue create mode 100644 pagesPackage/ngTools_DictItem/add.vue create mode 100644 pagesPackage/ngTools_DictItem/detail.vue create mode 100644 pagesPackage/ngTools_DictItem/edit.vue create mode 100644 pagesPackage/ngTools_DictItem/list.vue create mode 100644 pagesPackage/ngTools_MeterList/add.vue create mode 100644 pagesPackage/ngTools_MeterList/detail.vue create mode 100644 pagesPackage/ngTools_MeterList/edit.vue create mode 100644 pagesPackage/ngTools_MeterList/list.vue create mode 100644 pagesPackage/ngTools_SamplingLocation/add.vue create mode 100644 pagesPackage/ngTools_SamplingLocation/detail.vue create mode 100644 pagesPackage/ngTools_SamplingLocation/edit.vue create mode 100644 pagesPackage/ngTools_SamplingLocation/list.vue create mode 100644 pagesPackage/ngTools_depart/add.vue create mode 100644 pagesPackage/ngTools_depart/departList/departList.vue create mode 100644 pagesPackage/ngTools_depart/departList/departTree.vue create mode 100644 pagesPackage/ngTools_depart/departList/style.css create mode 100644 pagesPackage/ngTools_depart/depart_select.vue create mode 100644 pagesPackage/ngTools_depart/detail.vue create mode 100644 pagesPackage/ngTools_depart/edit.vue create mode 100644 pagesPackage/ngTools_depart/list.vue create mode 100644 pagesPackage/ngTools_depart/user_select.vue create mode 100644 pagesPackage/ngtools-goods/add.vue create mode 100644 pagesPackage/ngtools-goods/detail.vue create mode 100644 pagesPackage/ngtools-goods/edit.vue create mode 100644 pagesPackage/ngtools-goods/list.vue create mode 100644 pagesPackage/ngtools_CNG/LNGQhJs.vue create mode 100644 pagesPackage/ngtools_CNG/srjBgJs.vue create mode 100644 pagesPackage/ngtools_CNG/srjJs.vue create mode 100644 pagesPackage/ngtools_CNG/zxcJs.vue create mode 100644 pagesPackage/ngtools_Flow/SqgyJs.vue create mode 100644 pagesPackage/ngtools_Flow/cysllJs.vue create mode 100644 pagesPackage/ngtools_Flow/ljlllJs.vue create mode 100644 pagesPackage/ngtools_Flow/sdsllJs.vue create mode 100644 pagesPackage/ngtools_Par/ZBgJs.vue create mode 100644 pagesPackage/ngtools_Par/mdRzJs.vue create mode 100644 pagesPackage/ngtools_Par/qtJs.vue create mode 100644 pagesPackage/ngtools_Par/zJs.vue create mode 100644 pagesPackage/ngtools_categories/add.vue create mode 100644 pagesPackage/ngtools_categories/detail.vue create mode 100644 pagesPackage/ngtools_categories/edit.vue create mode 100644 pagesPackage/ngtools_categories/list.vue create mode 100644 pagesPackage/ngtools_information/add.vue create mode 100644 pagesPackage/ngtools_information/detail.vue create mode 100644 pagesPackage/ngtools_information/edit.vue create mode 100644 pagesPackage/ngtools_information/list.vue create mode 100644 pagesPackage/opendb-banner/add.vue create mode 100644 pagesPackage/opendb-banner/detail.vue create mode 100644 pagesPackage/opendb-banner/edit.vue create mode 100644 pagesPackage/opendb-banner/list.vue create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/changelog.md create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/common/cache.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/common/queue.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/common/types/cache.d.ts create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/common/types/queue.d.ts create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/components/u-qrcode/u-qrcode.vue create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/components/uqrcode/uqrcode.vue create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/bridge/bridge-weex.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-2d/FillStyleLinearGradient.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-2d/FillStylePattern.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-2d/FillStyleRadialGradient.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-2d/RenderingContext.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/ActiveInfo.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Buffer.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Framebuffer.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/GLenum.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/GLmethod.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/GLtype.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Program.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Renderbuffer.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/RenderingContext.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Shader.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/ShaderPrecisionFormat.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Texture.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/UniformLocation.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/classUtils.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/env/canvas.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/env/image.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/env/tool.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/index.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/uqrcode/package.json create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/uqrcode/uqrcode.js create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/license.md create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/package.json create mode 100644 pagesPackage/ucenter/Sansnn-uQRCode/readme.md create mode 100644 pagesPackage/ucenter/about/about.vue create mode 100644 pagesPackage/ucenter/invite/invite.vue create mode 100644 pagesPackage/ucenter/pay/index.vue create mode 100644 pagesPackage/ucenter/read-news-log/read-news-log.vue create mode 100644 pagesPackage/ucenter/settings/dc-push/push.js create mode 100644 pagesPackage/ucenter/settings/settings.vue create mode 100644 pagesPackage/uni-agree/uni-agree.nvue create mode 100644 pagesPackage/uni-agree/utils/uni-agree.js create mode 100644 static/app-plus/sharemenu/copyurl.png create mode 100644 static/app-plus/sharemenu/more.png create mode 100644 static/app-plus/sharemenu/mp_weixin.png create mode 100644 static/app-plus/sharemenu/qq.png create mode 100644 static/app-plus/sharemenu/wechatfriend.png create mode 100644 static/app-plus/sharemenu/wechatmoments.png create mode 100644 static/app-plus/sharemenu/weibo.png create mode 100644 static/h5/download-app/android.png create mode 100644 static/h5/download-app/ios.png create mode 100644 static/h5/download-app/openImg.png create mode 100644 static/tabbar/grid.png create mode 100644 static/tabbar/grid_active.png create mode 100644 static/tabbar/list.png create mode 100644 static/tabbar/list_active.png create mode 100644 static/tabbar/me.png create mode 100644 static/tabbar/me_active.png create mode 100644 static/uni-center/headers.png create mode 100644 static/uni-load-state/disconnection.png create mode 100644 static/uni.ttf create mode 100644 uni-starter.config.js create mode 100644 uni.scss create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/package.json create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/shared/create-api.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/shared/error.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/shared/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/shared/utils.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/lib/date.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/lib/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/lib/uni-crypto.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/activeDevices.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/activeUsers.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/appCrashLogs.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/base.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/channel.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/device.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/errorLog.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/errorResult.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/event.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/eventLog.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/eventResult.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/loyalty.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/page.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/pageLog.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/pageResult.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/platform.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/runErrors.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/scenes.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/sessionLog.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/setting.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/shareLog.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/statResult.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/config.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniIdUsers.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniPayOrders.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniStatPayResult.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniStatSessionLogs.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniStatUserSessionLogs.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/payResult.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uniIDUsers.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/userSessionLog.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/version.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/receiver.js create mode 100644 uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/stat.js create mode 100644 uniCloud-aliyun/cloudfunctions/uni-analyse-searchhot/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/uni-analyse-searchhot/package.json create mode 100644 uniCloud-aliyun/cloudfunctions/uni-portal/createPublishHtml/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/uni-portal/createPublishHtml/lib/art-template.js create mode 100644 uniCloud-aliyun/cloudfunctions/uni-portal/createPublishHtml/template.html create mode 100644 uniCloud-aliyun/cloudfunctions/uni-portal/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/uni-portal/package.json create mode 100644 uniCloud-aliyun/cloudfunctions/uni-sms-co/build-template-data.js create mode 100644 uniCloud-aliyun/cloudfunctions/uni-sms-co/index.obj.js create mode 100644 uniCloud-aliyun/cloudfunctions/uni-sms-co/package.json create mode 100644 uniCloud-aliyun/cloudfunctions/uni-sms-co/schema-name-adapter.js create mode 100644 uniCloud-aliyun/cloudfunctions/uni-sms-co/utils.js create mode 100644 uniCloud-aliyun/cloudfunctions/uni-stat-cron/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/uni-stat-cron/package.json create mode 100644 uniCloud-aliyun/cloudfunctions/uni-stat-receiver/index.obj.js create mode 100644 uniCloud-aliyun/cloudfunctions/uni-stat-receiver/package.json create mode 100644 uniCloud-aliyun/cloudfunctions/uni-upgrade-center/checkVersion/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/uni-upgrade-center/index.js create mode 100644 uniCloud-aliyun/cloudfunctions/uni-upgrade-center/package.json create mode 100644 uniCloud-aliyun/cloudfunctions/uni-upgrade-center/uni-app-manager.param.json create mode 100644 uniCloud-aliyun/cloudfunctions/wxpay-virtual-co/index.obj.js create mode 100644 uniCloud-aliyun/cloudfunctions/wxpay-virtual-co/package.json create mode 100644 uniCloud-aliyun/cloudfunctions/wxpay-virtual-co/wxpay-virtual-co.param.js create mode 100644 uniCloud-aliyun/database/JQL查询.jql create mode 100644 uniCloud-aliyun/database/db_init.json create mode 100644 uniCloud-aliyun/database/dictItem.jql create mode 100644 uniCloud-aliyun/database/lab_custom.schema.json create mode 100644 uniCloud-aliyun/database/ngTools_Dict.schema.json create mode 100644 uniCloud-aliyun/database/ngTools_DictItem.schema.json create mode 100644 uniCloud-aliyun/database/ngTools_MeterList.schema.json create mode 100644 uniCloud-aliyun/database/ngTools_MeterPar.schema.json create mode 100644 uniCloud-aliyun/database/ngTools_NGComponents.schema.json create mode 100644 uniCloud-aliyun/database/ngTools_NGPar.schema.json create mode 100644 uniCloud-aliyun/database/ngTools_SamplingLocation.schema.json create mode 100644 uniCloud-aliyun/database/ngTools_depart.schema.json create mode 100644 uniCloud-aliyun/database/ngtools-categories.schema.json create mode 100644 uniCloud-aliyun/database/ngtools-goods.schema.json create mode 100644 uniCloud-aliyun/database/ngtools_MeterResult.schema.json create mode 100644 uniCloud-aliyun/database/ngtools_NGResult.schema.json create mode 100644 uniCloud-aliyun/database/ngtools_information.schema.json create mode 100644 uniCloud-aliyun/database/opendb-admin-menus.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-admin-menus.schema.json create mode 100644 uniCloud-aliyun/database/opendb-app-list.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-app-list.schema.json create mode 100644 uniCloud-aliyun/database/opendb-app-versions.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-app-versions.schema.json create mode 100644 uniCloud-aliyun/database/opendb-banner.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-banner.schema.json create mode 100644 uniCloud-aliyun/database/opendb-department.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-department.schema.json create mode 100644 uniCloud-aliyun/database/opendb-device.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-device.schema.json create mode 100644 uniCloud-aliyun/database/opendb-feedback.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-feedback.schema.json create mode 100644 uniCloud-aliyun/database/opendb-news-articles.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-news-articles.schema.json create mode 100644 uniCloud-aliyun/database/opendb-news-categories.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-news-categories.schema.json create mode 100644 uniCloud-aliyun/database/opendb-news-comments.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-news-comments.schema.json create mode 100644 uniCloud-aliyun/database/opendb-news-favorite.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-news-favorite.schema.json create mode 100644 uniCloud-aliyun/database/opendb-open-data.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-open-data.schema.json create mode 100644 uniCloud-aliyun/database/opendb-search-hot.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-search-hot.schema.json create mode 100644 uniCloud-aliyun/database/opendb-search-log.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-search-log.schema.json create mode 100644 uniCloud-aliyun/database/opendb-sign-in.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-sign-in.schema.json create mode 100644 uniCloud-aliyun/database/opendb-sms-log.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-sms-log.schema.json create mode 100644 uniCloud-aliyun/database/opendb-sms-task.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-sms-task.schema.json create mode 100644 uniCloud-aliyun/database/opendb-sms-template.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-sms-template.schema.json create mode 100644 uniCloud-aliyun/database/opendb-tempdata.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-tempdata.schema.json create mode 100644 uniCloud-aliyun/database/opendb-verify-codes.init_data.json create mode 100644 uniCloud-aliyun/database/opendb-verify-codes.schema.json create mode 100644 uniCloud-aliyun/database/read-news-log.init_data.json create mode 100644 uniCloud-aliyun/database/read-news-log.schema.json create mode 100644 uniCloud-aliyun/database/uni-id-device.init_data.json create mode 100644 uniCloud-aliyun/database/uni-id-device.schema.json create mode 100644 uniCloud-aliyun/database/uni-id-log.init_data.json create mode 100644 uniCloud-aliyun/database/uni-id-log.schema.json create mode 100644 uniCloud-aliyun/database/uni-id-permissions.init_data.json create mode 100644 uniCloud-aliyun/database/uni-id-permissions.schema.json create mode 100644 uniCloud-aliyun/database/uni-id-roles.init_data.json create mode 100644 uniCloud-aliyun/database/uni-id-roles.schema.json create mode 100644 uniCloud-aliyun/database/uni-id-scores.init_data.json create mode 100644 uniCloud-aliyun/database/uni-id-scores.schema.json create mode 100644 uniCloud-aliyun/database/uni-id-tag.init_data.json create mode 100644 uniCloud-aliyun/database/uni-id-tag.schema.json create mode 100644 uniCloud-aliyun/database/uni-id-users.init_data.json create mode 100644 uniCloud-aliyun/database/uni-id-users.schema.json create mode 100644 uniCloud-aliyun/database/uni-pay-orders.init_data.json create mode 100644 uniCloud-aliyun/database/uni-pay-orders.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-active-devices.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-active-devices.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-active-users.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-active-users.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-app-channels.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-app-channels.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-app-crash-logs.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-app-crash-logs.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-app-platforms.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-app-platforms.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-app-versions.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-app-versions.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-error-logs.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-error-logs.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-error-result.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-error-result.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-error-source-map.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-error-source-map.schema.ext.js create mode 100644 uniCloud-aliyun/database/uni-stat-error-source-map.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-event-logs.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-event-logs.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-event-result.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-event-result.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-events.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-events.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-loyalty-result.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-loyalty-result.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-mp-scenes.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-mp-scenes.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-page-detail-result.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-page-details.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-page-logs.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-page-logs.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-page-result.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-page-result.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-pages.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-pages.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-pay-result.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-pay-result.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-result.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-result.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-run-errors.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-run-errors.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-session-logs.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-session-logs.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-share-logs.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-share-logs.schema.json create mode 100644 uniCloud-aliyun/database/uni-stat-user-session-logs.init_data.json create mode 100644 uniCloud-aliyun/database/uni-stat-user-session-logs.schema.json create mode 100644 uni_modules/json-gps/changelog.md create mode 100644 uni_modules/json-gps/js_sdk/gps.js create mode 100644 uni_modules/json-gps/js_sdk/wa-permission/permission.js create mode 100644 uni_modules/json-gps/package.json create mode 100644 uni_modules/json-gps/readme.md create mode 100644 uni_modules/json-interceptor-chooseImage/changelog.md create mode 100644 uni_modules/json-interceptor-chooseImage/js_sdk/main.js create mode 100644 uni_modules/json-interceptor-chooseImage/package.json create mode 100644 uni_modules/json-interceptor-chooseImage/readme.md create mode 100644 uni_modules/kevy-collapse/changelog.md create mode 100644 uni_modules/kevy-collapse/components/kevy-collapse/kevy-collapse.vue create mode 100644 uni_modules/kevy-collapse/package.json create mode 100644 uni_modules/kevy-collapse/readme.md create mode 100644 uni_modules/kevy-collapse/static/icon/iconfont.css create mode 100644 uni_modules/kevy-collapse/static/icon/iconfont.ttf create mode 100644 uni_modules/kevy-collapse/static/icon/iconfont.woff create mode 100644 uni_modules/kevy-collapse/static/icon/iconfont.woff2 create mode 100644 uni_modules/next-search-more/changelog.md create mode 100644 uni_modules/next-search-more/components/next-search-more/next-search-more.vue create mode 100644 uni_modules/next-search-more/package.json create mode 100644 uni_modules/next-search-more/readme.md create mode 100644 uni_modules/next-tree/changelog.md create mode 100644 uni_modules/next-tree/components/next-tree/next-tree.vue create mode 100644 uni_modules/next-tree/components/next-tree/style.css create mode 100644 uni_modules/next-tree/package.json create mode 100644 uni_modules/next-tree/readme.md create mode 100644 uni_modules/sv-excel-json-each/changelog.md create mode 100644 uni_modules/sv-excel-json-each/js_sdk/parseExcel.js create mode 100644 uni_modules/sv-excel-json-each/js_sdk/plusFilePicker.js create mode 100644 uni_modules/sv-excel-json-each/package.json create mode 100644 uni_modules/sv-excel-json-each/readme.md create mode 100644 uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/index.js create mode 100644 uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/lib/cpexcel.js create mode 100644 uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/lib/xlsx.style.js create mode 100644 uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/package.json create mode 100644 uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/util/index.js create mode 100644 uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/sv-excel-json-each/index.obj.js create mode 100644 uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/sv-excel-json-each/package-lock.json create mode 100644 uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/sv-excel-json-each/package.json create mode 100644 uni_modules/uni-badge/changelog.md create mode 100644 uni_modules/uni-badge/components/uni-badge/uni-badge.vue create mode 100644 uni_modules/uni-badge/package.json create mode 100644 uni_modules/uni-badge/readme.md create mode 100644 uni_modules/uni-calendar/changelog.md create mode 100644 uni_modules/uni-calendar/components/uni-calendar/calendar.js create mode 100644 uni_modules/uni-calendar/components/uni-calendar/i18n/en.json create mode 100644 uni_modules/uni-calendar/components/uni-calendar/i18n/index.js create mode 100644 uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json create mode 100644 uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json create mode 100644 uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue create mode 100644 uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue create mode 100644 uni_modules/uni-calendar/components/uni-calendar/util.js create mode 100644 uni_modules/uni-calendar/package.json create mode 100644 uni_modules/uni-calendar/readme.md create mode 100644 uni_modules/uni-captcha/changelog.md create mode 100644 uni_modules/uni-captcha/components/uni-captcha/uni-captcha.uvue create mode 100644 uni_modules/uni-captcha/components/uni-captcha/uni-captcha.vue create mode 100644 uni_modules/uni-captcha/components/uni-popup-captcha/uni-popup-captcha.uvue create mode 100644 uni_modules/uni-captcha/components/uni-popup-captcha/uni-popup-captcha.vue create mode 100644 uni_modules/uni-captcha/package.json create mode 100644 uni_modules/uni-captcha/readme.md create mode 100644 uni_modules/uni-captcha/static/run.gif create mode 100644 uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/LICENSE.md create mode 100644 uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/fonts/font.ttf create mode 100644 uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/index.js create mode 100644 uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/package.json create mode 100644 uni_modules/uni-captcha/uniCloud/cloudfunctions/uni-captcha-co/config.js create mode 100644 uni_modules/uni-captcha/uniCloud/cloudfunctions/uni-captcha-co/index.obj.js create mode 100644 uni_modules/uni-captcha/uniCloud/cloudfunctions/uni-captcha-co/package.json create mode 100644 uni_modules/uni-card/changelog.md create mode 100644 uni_modules/uni-card/components/uni-card/uni-card.vue create mode 100644 uni_modules/uni-card/package.json create mode 100644 uni_modules/uni-card/readme.md create mode 100644 uni_modules/uni-cloud-s2s/changelog.md create mode 100644 uni_modules/uni-cloud-s2s/package.json create mode 100644 uni_modules/uni-cloud-s2s/readme.md create mode 100644 uni_modules/uni-cloud-s2s/uniCloud/cloudfunctions/common/uni-cloud-s2s/index.js create mode 100644 uni_modules/uni-cloud-s2s/uniCloud/cloudfunctions/common/uni-cloud-s2s/package.json create mode 100644 uni_modules/uni-collapse/changelog.md create mode 100644 uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue create mode 100644 uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue create mode 100644 uni_modules/uni-collapse/package.json create mode 100644 uni_modules/uni-collapse/readme.md create mode 100644 uni_modules/uni-combox/changelog.md create mode 100644 uni_modules/uni-combox/components/uni-combox/uni-combox.vue create mode 100644 uni_modules/uni-combox/package.json create mode 100644 uni_modules/uni-combox/readme.md 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-ad/config.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-open-bridge/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/config.js create mode 100644 uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-pay/wxpay/apiclient_cert.p12 create mode 100644 uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-pay/wxpay/apiclient_cert.pem create mode 100644 uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-pay/wxpay/apiclient_key.pem create mode 100644 uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-pay/【重要】请先看这里.md create mode 100644 uni_modules/uni-countdown/changelog.md create mode 100644 uni_modules/uni-countdown/components/uni-countdown/i18n/en.json create mode 100644 uni_modules/uni-countdown/components/uni-countdown/i18n/index.js create mode 100644 uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hans.json create mode 100644 uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hant.json create mode 100644 uni_modules/uni-countdown/components/uni-countdown/uni-countdown.vue create mode 100644 uni_modules/uni-countdown/package.json create mode 100644 uni_modules/uni-countdown/readme.md create mode 100644 uni_modules/uni-data-checkbox/changelog.md create mode 100644 uni_modules/uni-data-checkbox/components/uni-data-checkbox/clientdb.js create mode 100644 uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue create mode 100644 uni_modules/uni-data-checkbox/package.json create mode 100644 uni_modules/uni-data-checkbox/readme.md create mode 100644 uni_modules/uni-data-picker/changelog.md create mode 100644 uni_modules/uni-data-picker/components/uni-data-picker/config.json create mode 100644 uni_modules/uni-data-picker/components/uni-data-picker/keypress.js create mode 100644 uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.uvue create mode 100644 uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue create mode 100644 uni_modules/uni-data-picker/components/uni-data-pickerview/loading.uts create mode 100644 uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js create mode 100644 uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.uts create mode 100644 uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.css create mode 100644 uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.uvue create mode 100644 uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue create mode 100644 uni_modules/uni-data-picker/package.json create mode 100644 uni_modules/uni-data-picker/readme.md create mode 100644 uni_modules/uni-data-select/changelog.md create mode 100644 uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue create mode 100644 uni_modules/uni-data-select/package.json create mode 100644 uni_modules/uni-data-select/readme.md create mode 100644 uni_modules/uni-dateformat/changelog.md create mode 100644 uni_modules/uni-dateformat/components/uni-dateformat/date-format.js create mode 100644 uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue create mode 100644 uni_modules/uni-dateformat/package.json create mode 100644 uni_modules/uni-dateformat/readme.md create mode 100644 uni_modules/uni-datetime-picker/changelog.md create mode 100644 uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue create mode 100644 uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.js create mode 100644 uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue create mode 100644 uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json create mode 100644 uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js create mode 100644 uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json create mode 100644 uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json create mode 100644 uni_modules/uni-datetime-picker/components/uni-datetime-picker/keypress.js create mode 100644 uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue create mode 100644 uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue create mode 100644 uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js create mode 100644 uni_modules/uni-datetime-picker/package.json create mode 100644 uni_modules/uni-datetime-picker/readme.md create mode 100644 uni_modules/uni-drawer/changelog.md create mode 100644 uni_modules/uni-drawer/components/uni-drawer/keypress.js create mode 100644 uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue create mode 100644 uni_modules/uni-drawer/package.json create mode 100644 uni_modules/uni-drawer/readme.md create mode 100644 uni_modules/uni-easyinput/changelog.md create mode 100644 uni_modules/uni-easyinput/components/uni-easyinput/common.js create mode 100644 uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue create mode 100644 uni_modules/uni-easyinput/package.json create mode 100644 uni_modules/uni-easyinput/readme.md create mode 100644 uni_modules/uni-fab/changelog.md create mode 100644 uni_modules/uni-fab/components/uni-fab/uni-fab.vue create mode 100644 uni_modules/uni-fab/components/uni-fab/uni-fab.vue.bak create mode 100644 uni_modules/uni-fab/package.json create mode 100644 uni_modules/uni-fab/readme.md create mode 100644 uni_modules/uni-fav/changelog.md create mode 100644 uni_modules/uni-fav/components/uni-fav/i18n/en.json create mode 100644 uni_modules/uni-fav/components/uni-fav/i18n/index.js create mode 100644 uni_modules/uni-fav/components/uni-fav/i18n/zh-Hans.json create mode 100644 uni_modules/uni-fav/components/uni-fav/i18n/zh-Hant.json create mode 100644 uni_modules/uni-fav/components/uni-fav/uni-fav.vue create mode 100644 uni_modules/uni-fav/package.json create mode 100644 uni_modules/uni-fav/readme.md create mode 100644 uni_modules/uni-feedback/changelog.md create mode 100644 uni_modules/uni-feedback/js_sdk/validator/opendb-feedback.js create mode 100644 uni_modules/uni-feedback/package.json create mode 100644 uni_modules/uni-feedback/pages/opendb-feedback/detail.vue create mode 100644 uni_modules/uni-feedback/pages/opendb-feedback/edit.vue create mode 100644 uni_modules/uni-feedback/pages/opendb-feedback/list.vue create mode 100644 uni_modules/uni-feedback/pages/opendb-feedback/opendb-feedback.vue create mode 100644 uni_modules/uni-feedback/readme.md create mode 100644 uni_modules/uni-file-picker/changelog.md create mode 100644 uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js create mode 100644 uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue create mode 100644 uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue create mode 100644 uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue create mode 100644 uni_modules/uni-file-picker/components/uni-file-picker/utils.js create mode 100644 uni_modules/uni-file-picker/package.json create mode 100644 uni_modules/uni-file-picker/readme.md create mode 100644 uni_modules/uni-forms/changelog.md create mode 100644 uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue create mode 100644 uni_modules/uni-forms/components/uni-forms/uni-forms.vue create mode 100644 uni_modules/uni-forms/components/uni-forms/utils.js create mode 100644 uni_modules/uni-forms/components/uni-forms/validate.js create mode 100644 uni_modules/uni-forms/package.json create mode 100644 uni_modules/uni-forms/readme.md create mode 100644 uni_modules/uni-goods-nav/changelog.md create mode 100644 uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/en.json create mode 100644 uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/index.js create mode 100644 uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hans.json create mode 100644 uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hant.json create mode 100644 uni_modules/uni-goods-nav/components/uni-goods-nav/uni-goods-nav.vue create mode 100644 uni_modules/uni-goods-nav/package.json create mode 100644 uni_modules/uni-goods-nav/readme.md create mode 100644 uni_modules/uni-grid/changelog.md create mode 100644 uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue create mode 100644 uni_modules/uni-grid/components/uni-grid/uni-grid.vue create mode 100644 uni_modules/uni-grid/package.json create mode 100644 uni_modules/uni-grid/readme.md create mode 100644 uni_modules/uni-group/changelog.md create mode 100644 uni_modules/uni-group/components/uni-group/uni-group.vue create mode 100644 uni_modules/uni-group/package.json create mode 100644 uni_modules/uni-group/readme.md create mode 100644 uni_modules/uni-icons/changelog.md create mode 100644 uni_modules/uni-icons/components/uni-icons/icons.js create mode 100644 uni_modules/uni-icons/components/uni-icons/uni-icons.uvue create mode 100644 uni_modules/uni-icons/components/uni-icons/uni-icons.vue create mode 100644 uni_modules/uni-icons/components/uni-icons/uni.ttf create mode 100644 uni_modules/uni-icons/components/uni-icons/uniicons.css create mode 100644 uni_modules/uni-icons/components/uni-icons/uniicons.ttf create mode 100644 uni_modules/uni-icons/components/uni-icons/uniicons_file.ts create mode 100644 uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js create mode 100644 uni_modules/uni-icons/package.json create mode 100644 uni_modules/uni-icons/readme.md create mode 100644 uni_modules/uni-id-common/changelog.md create mode 100644 uni_modules/uni-id-common/package.json create mode 100644 uni_modules/uni-id-common/readme.md create mode 100644 uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/index.js create mode 100644 uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/package.json create mode 100644 uni_modules/uni-id-pages/changelog.md create mode 100644 uni_modules/uni-id-pages/common/check-id-card.js create mode 100644 uni_modules/uni-id-pages/common/login-page.mixin.js create mode 100644 uni_modules/uni-id-pages/common/login-page.scss create mode 100644 uni_modules/uni-id-pages/common/password.js create mode 100644 uni_modules/uni-id-pages/common/store.js create mode 100644 uni_modules/uni-id-pages/components/cloud-image/cloud-image.vue create mode 100644 uni_modules/uni-id-pages/components/uni-id-pages-agreements/uni-id-pages-agreements.vue create mode 100644 uni_modules/uni-id-pages/components/uni-id-pages-avatar/uni-id-pages-avatar.vue create mode 100644 uni_modules/uni-id-pages/components/uni-id-pages-bind-mobile/uni-id-pages-bind-mobile.vue create mode 100644 uni_modules/uni-id-pages/components/uni-id-pages-email-form/uni-id-pages-email-form.vue create mode 100644 uni_modules/uni-id-pages/components/uni-id-pages-fab-login/uni-id-pages-fab-login.vue create mode 100644 uni_modules/uni-id-pages/components/uni-id-pages-sms-form/uni-id-pages-sms-form.vue create mode 100644 uni_modules/uni-id-pages/components/uni-id-pages-user-profile/uni-id-pages-user-profile.vue create mode 100644 uni_modules/uni-id-pages/config.js create mode 100644 uni_modules/uni-id-pages/init.js create mode 100644 uni_modules/uni-id-pages/package.json create mode 100644 uni_modules/uni-id-pages/pages/common/webview/webview.vue create mode 100644 uni_modules/uni-id-pages/pages/login/login-smscode.vue create mode 100644 uni_modules/uni-id-pages/pages/login/login-withoutpwd.vue create mode 100644 uni_modules/uni-id-pages/pages/login/login-withpwd.vue create mode 100644 uni_modules/uni-id-pages/pages/register/register-admin.vue create mode 100644 uni_modules/uni-id-pages/pages/register/register-by-email.vue create mode 100644 uni_modules/uni-id-pages/pages/register/register.vue create mode 100644 uni_modules/uni-id-pages/pages/register/validator.js create mode 100644 uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email.vue create mode 100644 uni_modules/uni-id-pages/pages/retrieve/retrieve.vue create mode 100644 uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile.vue create mode 100644 uni_modules/uni-id-pages/pages/userinfo/change_pwd/change_pwd.vue create mode 100644 uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage.vue create mode 100644 uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/README.md create mode 100644 uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/photo.svg create mode 100644 uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/rotate.svg create mode 100644 uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/index.css create mode 100644 uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/limeClipper.vue create mode 100644 uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/utils.js create mode 100644 uni_modules/uni-id-pages/pages/userinfo/deactivate/deactivate.vue create mode 100644 uni_modules/uni-id-pages/pages/userinfo/realname-verify/face-verify-icon.svg create mode 100644 uni_modules/uni-id-pages/pages/userinfo/realname-verify/realname-verify.vue create mode 100644 uni_modules/uni-id-pages/pages/userinfo/set-pwd/set-pwd.vue create mode 100644 uni_modules/uni-id-pages/pages/userinfo/userinfo.vue create mode 100644 uni_modules/uni-id-pages/readme.md create mode 100644 uni_modules/uni-id-pages/static/app-plus/apple.png create mode 100644 uni_modules/uni-id-pages/static/app-plus/uni-fab-login/alipay.png create mode 100644 uni_modules/uni-id-pages/static/app-plus/uni-fab-login/apple.png create mode 100644 uni_modules/uni-id-pages/static/app-plus/uni-fab-login/douyin.png create mode 100644 uni_modules/uni-id-pages/static/app-plus/uni-fab-login/facebook.png create mode 100644 uni_modules/uni-id-pages/static/app-plus/uni-fab-login/google.png create mode 100644 uni_modules/uni-id-pages/static/app-plus/uni-fab-login/qq.png create mode 100644 uni_modules/uni-id-pages/static/app-plus/uni-fab-login/sinaweibo.png create mode 100644 uni_modules/uni-id-pages/static/app-plus/uni-fab-login/taobao.png create mode 100644 uni_modules/uni-id-pages/static/app-plus/uni-fab-login/univerify.png create mode 100644 uni_modules/uni-id-pages/static/limeClipper/photo.svg create mode 100644 uni_modules/uni-id-pages/static/limeClipper/rotate.svg create mode 100644 uni_modules/uni-id-pages/static/login/uni-fab-login/sms.png create mode 100644 uni_modules/uni-id-pages/static/login/uni-fab-login/user.png create mode 100644 uni_modules/uni-id-pages/static/login/uni-fab-login/weixin.png create mode 100644 uni_modules/uni-id-pages/static/login/weixin.png create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/constants.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/error.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/sensitive-aes-cipher.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/universal.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/utils.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/validator.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/config/permission.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/index.obj.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/en.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/zh-hans.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/README.md create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/protocols.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/alipayBase.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/account/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/rsa-public-key-pem.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/account/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/account/protocol.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/normalize.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/share/create-api.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/account/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/normalize.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/utils.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/account.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/captcha.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/config.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/fission.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/logout.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/qq.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/relate.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/sms.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/unified-login.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/univerify.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/update-user-info.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/utils.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/verify-code.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/weixin.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/access-control.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/auth.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/rbac.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/uni-id-log.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/validate.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/verify-request-sign.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/close-account.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/get-account-info.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/get-realname-info.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-email.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-sms.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/set-pwd.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/add-user.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/update-user.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/get-supported-login-type.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/login.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/register.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/update-user-info.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/facial-recognition-verify/get-auth-result.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/facial-recognition-verify/get-certify-id.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/facial-recognition-verify/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/accept-invite.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/get-invited-user.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-alipay.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-apple.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-baidu.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-dingtalk.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-douyin.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-code.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-link.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-facebook.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-google.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-qq.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-sms.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-taobao.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-toutiao.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-univerify.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weibo.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin-mobile.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/logout.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/authorize-app-login.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/remove-authorized-app.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/set-authorized-app.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/utils.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-admin.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user-by-email.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-alipay.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-apple.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-mp-weixin.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-sms.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-univerify.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-qq.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-weixin.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-alipay.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-apple.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-qq.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-weixin.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/refresh-token.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/secure-network-handshake-by-weixin.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/set-push-cid.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/create-captcha.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/index.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/refresh-captcha.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-code.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-link.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-sms-code.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package-lock.json create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package.json create mode 100644 uni_modules/uni-id-pages/uniCloud/database/opendb-frv-logs.schema.json create mode 100644 uni_modules/uni-image-menu/changelog.md create mode 100644 uni_modules/uni-image-menu/js_sdk/uni-image-menu.js create mode 100644 uni_modules/uni-image-menu/package.json create mode 100644 uni_modules/uni-image-menu/readme.md create mode 100644 uni_modules/uni-indexed-list/changelog.md create mode 100644 uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list-item.vue create mode 100644 uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list.vue create mode 100644 uni_modules/uni-indexed-list/package.json create mode 100644 uni_modules/uni-indexed-list/readme.md create mode 100644 uni_modules/uni-link/changelog.md create mode 100644 uni_modules/uni-link/components/uni-link/uni-link.vue create mode 100644 uni_modules/uni-link/package.json create mode 100644 uni_modules/uni-link/readme.md create mode 100644 uni_modules/uni-list/changelog.md create mode 100644 uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue create mode 100644 uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss create mode 100644 uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue create mode 100644 uni_modules/uni-list/components/uni-list-item/uni-list-item.vue create mode 100644 uni_modules/uni-list/components/uni-list/uni-list - 副本.vue create mode 100644 uni_modules/uni-list/components/uni-list/uni-list.vue create mode 100644 uni_modules/uni-list/components/uni-list/uni-refresh.vue create mode 100644 uni_modules/uni-list/components/uni-list/uni-refresh.wxs create mode 100644 uni_modules/uni-list/package.json create mode 100644 uni_modules/uni-list/readme.md create mode 100644 uni_modules/uni-load-more/changelog.md create mode 100644 uni_modules/uni-load-more/components/uni-load-more/i18n/en.json create mode 100644 uni_modules/uni-load-more/components/uni-load-more/i18n/index.js create mode 100644 uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json create mode 100644 uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json create mode 100644 uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue create mode 100644 uni_modules/uni-load-more/package.json create mode 100644 uni_modules/uni-load-more/readme.md create mode 100644 uni_modules/uni-nav-bar/changelog.md create mode 100644 uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue create mode 100644 uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue create mode 100644 uni_modules/uni-nav-bar/package.json create mode 100644 uni_modules/uni-nav-bar/readme.md create mode 100644 uni_modules/uni-notice-bar/changelog.md create mode 100644 uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue create mode 100644 uni_modules/uni-notice-bar/package.json create mode 100644 uni_modules/uni-notice-bar/readme.md create mode 100644 uni_modules/uni-number-box/changelog.md create mode 100644 uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue create mode 100644 uni_modules/uni-number-box/package.json create mode 100644 uni_modules/uni-number-box/readme.md create mode 100644 uni_modules/uni-open-bridge-common/changelog.md create mode 100644 uni_modules/uni-open-bridge-common/package.json create mode 100644 uni_modules/uni-open-bridge-common/readme.md create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/bridge-error.js create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/config.js create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/consts.js create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/index.js create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/package.json create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/storage.js create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/uni-cloud-cache.js create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/validator.js create mode 100644 uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/weixin-server.js create mode 100644 uni_modules/uni-open-bridge/changelog.md create mode 100644 uni_modules/uni-open-bridge/package.json create mode 100644 uni_modules/uni-open-bridge/readme.md create mode 100644 uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/basic.js create mode 100644 uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/config.js create mode 100644 uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/consts.js create mode 100644 uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/index.mp-weixin.js create mode 100644 uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/index.obj.js create mode 100644 uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/index.task.js create mode 100644 uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/package.json create mode 100644 uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/task-h5-weixin.js create mode 100644 uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/task-mp-weixin.js create mode 100644 uni_modules/uni-pagination/changelog.md create mode 100644 uni_modules/uni-pagination/components/uni-pagination/i18n/en.json create mode 100644 uni_modules/uni-pagination/components/uni-pagination/i18n/es.json create mode 100644 uni_modules/uni-pagination/components/uni-pagination/i18n/fr.json create mode 100644 uni_modules/uni-pagination/components/uni-pagination/i18n/index.js create mode 100644 uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hans.json create mode 100644 uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hant.json create mode 100644 uni_modules/uni-pagination/components/uni-pagination/uni-pagination.vue create mode 100644 uni_modules/uni-pagination/package.json create mode 100644 uni_modules/uni-pagination/readme.md create mode 100644 uni_modules/uni-pay/changelog.md create mode 100644 uni_modules/uni-pay/components/uni-pay/uni-pay.vue create mode 100644 uni_modules/uni-pay/js_sdk/appleiap.js create mode 100644 uni_modules/uni-pay/js_sdk/js_sdk.js create mode 100644 uni_modules/uni-pay/package.json create mode 100644 uni_modules/uni-pay/pages/ad-interactive-webview/ad-interactive-webview.vue create mode 100644 uni_modules/uni-pay/pages/pay-desk/pay-desk.vue create mode 100644 uni_modules/uni-pay/pages/success/success.vue create mode 100644 uni_modules/uni-pay/readme.md create mode 100644 uni_modules/uni-pay/static/alipay.png create mode 100644 uni_modules/uni-pay/static/wxpay.png create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/common/uni-pay/LICENSE.md create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/common/uni-pay/index.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/common/uni-pay/package.json create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/common/error.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/config/permission.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/dao/index.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/dao/opendbOpenData.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/dao/readme.md create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/dao/uniIdUsers.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/dao/uniPayOrders.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/index.obj.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/lang/en.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/lang/index.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/lang/zh-hans.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/libs/alipay.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/libs/certutil.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/libs/common.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/libs/crypto.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/libs/index.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/libs/qrcode.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/libs/wxpay.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/middleware/access-control.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/middleware/auth.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/middleware/index.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/notify/appleiap.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/notify/test.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/notify/【重要】请先看这里.md create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/package.json create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/service/index.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/service/pay.js create mode 100644 uni_modules/uni-pay/uniCloud/cloudfunctions/uni-pay-co/uni-pay-co.param.js create mode 100644 uni_modules/uni-pay/uniCloud/database/opendb-open-data.index.json create mode 100644 uni_modules/uni-pay/uniCloud/database/uni-pay-orders.index.json create mode 100644 uni_modules/uni-popup/changelog.md create mode 100644 uni_modules/uni-popup/components/uni-popup-dialog/keypress.js create mode 100644 uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue create mode 100644 uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue create mode 100644 uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue create mode 100644 uni_modules/uni-popup/components/uni-popup/i18n/en.json create mode 100644 uni_modules/uni-popup/components/uni-popup/i18n/index.js create mode 100644 uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json create mode 100644 uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json create mode 100644 uni_modules/uni-popup/components/uni-popup/keypress.js create mode 100644 uni_modules/uni-popup/components/uni-popup/message.js create mode 100644 uni_modules/uni-popup/components/uni-popup/popup.js create mode 100644 uni_modules/uni-popup/components/uni-popup/share.js create mode 100644 uni_modules/uni-popup/components/uni-popup/uni-popup.uvue create mode 100644 uni_modules/uni-popup/components/uni-popup/uni-popup.vue create mode 100644 uni_modules/uni-popup/package.json create mode 100644 uni_modules/uni-popup/readme.md create mode 100644 uni_modules/uni-rate/changelog.md create mode 100644 uni_modules/uni-rate/components/uni-rate/uni-rate.vue create mode 100644 uni_modules/uni-rate/package.json create mode 100644 uni_modules/uni-rate/readme.md create mode 100644 uni_modules/uni-row/changelog.md create mode 100644 uni_modules/uni-row/components/uni-col/uni-col.vue create mode 100644 uni_modules/uni-row/components/uni-row/uni-row.vue create mode 100644 uni_modules/uni-row/package.json create mode 100644 uni_modules/uni-row/readme.md create mode 100644 uni_modules/uni-scss/changelog.md create mode 100644 uni_modules/uni-scss/index.scss create mode 100644 uni_modules/uni-scss/package.json create mode 100644 uni_modules/uni-scss/readme.md create mode 100644 uni_modules/uni-scss/styles/index.scss create mode 100644 uni_modules/uni-scss/styles/setting/_border.scss create mode 100644 uni_modules/uni-scss/styles/setting/_color.scss create mode 100644 uni_modules/uni-scss/styles/setting/_radius.scss create mode 100644 uni_modules/uni-scss/styles/setting/_space.scss create mode 100644 uni_modules/uni-scss/styles/setting/_styles.scss create mode 100644 uni_modules/uni-scss/styles/setting/_text.scss create mode 100644 uni_modules/uni-scss/styles/setting/_variables.scss create mode 100644 uni_modules/uni-scss/styles/tools/functions.scss create mode 100644 uni_modules/uni-scss/theme.scss create mode 100644 uni_modules/uni-scss/variables.scss create mode 100644 uni_modules/uni-search-bar/changelog.md create mode 100644 uni_modules/uni-search-bar/components/uni-search-bar/i18n/en.json create mode 100644 uni_modules/uni-search-bar/components/uni-search-bar/i18n/index.js create mode 100644 uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hans.json create mode 100644 uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hant.json create mode 100644 uni_modules/uni-search-bar/components/uni-search-bar/uni-search-bar.vue create mode 100644 uni_modules/uni-search-bar/package.json create mode 100644 uni_modules/uni-search-bar/readme.md create mode 100644 uni_modules/uni-section/changelog.md create mode 100644 uni_modules/uni-section/components/uni-section/uni-section.vue create mode 100644 uni_modules/uni-section/package.json create mode 100644 uni_modules/uni-section/readme.md create mode 100644 uni_modules/uni-segmented-control/changelog.md create mode 100644 uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue create mode 100644 uni_modules/uni-segmented-control/package.json create mode 100644 uni_modules/uni-segmented-control/readme.md create mode 100644 uni_modules/uni-share/changelog.md create mode 100644 uni_modules/uni-share/js_sdk/uni-image-menu.js create mode 100644 uni_modules/uni-share/js_sdk/uni-share.js create mode 100644 uni_modules/uni-share/package.json create mode 100644 uni_modules/uni-share/readme.md create mode 100644 uni_modules/uni-sign-in/changelog.md create mode 100644 uni_modules/uni-sign-in/components/uni-sign-in/uni-sign-in.vue create mode 100644 uni_modules/uni-sign-in/package.json create mode 100644 uni_modules/uni-sign-in/pages/demo/demo.vue create mode 100644 uni_modules/uni-sign-in/readme.md create mode 100644 uni_modules/uni-sign-in/static/background.png create mode 100644 uni_modules/uni-sign-in/uniCloud/cloudfunctions/common/sign-in/index.js create mode 100644 uni_modules/uni-sign-in/uniCloud/cloudfunctions/common/sign-in/package.json create mode 100644 uni_modules/uni-sign-in/uniCloud/cloudfunctions/rewarded-video-ad-notify-url/index.js create mode 100644 uni_modules/uni-sign-in/uniCloud/cloudfunctions/rewarded-video-ad-notify-url/package.json create mode 100644 uni_modules/uni-sign-in/uniCloud/cloudfunctions/uni-clientDB-actions/signIn.js create mode 100644 uni_modules/uni-sign-in/utils/ad.js create mode 100644 uni_modules/uni-steps/changelog.md create mode 100644 uni_modules/uni-steps/components/uni-steps/uni-steps.vue create mode 100644 uni_modules/uni-steps/package.json create mode 100644 uni_modules/uni-steps/readme.md create mode 100644 uni_modules/uni-swipe-action/changelog.md create mode 100644 uni_modules/uni-swipe-action/components/uni-swipe-action-item/bindingx.js create mode 100644 uni_modules/uni-swipe-action/components/uni-swipe-action-item/index.wxs create mode 100644 uni_modules/uni-swipe-action/components/uni-swipe-action-item/isPC.js create mode 100644 uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js create mode 100644 uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js create mode 100644 uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js create mode 100644 uni_modules/uni-swipe-action/components/uni-swipe-action-item/render.js create mode 100644 uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue create mode 100644 uni_modules/uni-swipe-action/components/uni-swipe-action-item/wx.wxs create mode 100644 uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue create mode 100644 uni_modules/uni-swipe-action/package.json create mode 100644 uni_modules/uni-swipe-action/readme.md create mode 100644 uni_modules/uni-swiper-dot/changelog.md create mode 100644 uni_modules/uni-swiper-dot/components/uni-swiper-dot/uni-swiper-dot.vue create mode 100644 uni_modules/uni-swiper-dot/package.json create mode 100644 uni_modules/uni-swiper-dot/readme.md create mode 100644 uni_modules/uni-table/changelog.md create mode 100644 uni_modules/uni-table/components/uni-table/uni-table.vue create mode 100644 uni_modules/uni-table/components/uni-tbody/uni-tbody.vue create mode 100644 uni_modules/uni-table/components/uni-td/uni-td.vue create mode 100644 uni_modules/uni-table/components/uni-th/filter-dropdown.vue create mode 100644 uni_modules/uni-table/components/uni-th/uni-th.vue create mode 100644 uni_modules/uni-table/components/uni-thead/uni-thead.vue create mode 100644 uni_modules/uni-table/components/uni-tr/table-checkbox.vue create mode 100644 uni_modules/uni-table/components/uni-tr/uni-tr.vue create mode 100644 uni_modules/uni-table/i18n/en.json create mode 100644 uni_modules/uni-table/i18n/es.json create mode 100644 uni_modules/uni-table/i18n/fr.json create mode 100644 uni_modules/uni-table/i18n/index.js create mode 100644 uni_modules/uni-table/i18n/zh-Hans.json create mode 100644 uni_modules/uni-table/i18n/zh-Hant.json create mode 100644 uni_modules/uni-table/package.json create mode 100644 uni_modules/uni-table/readme.md create mode 100644 uni_modules/uni-tag/changelog.md create mode 100644 uni_modules/uni-tag/components/uni-tag/uni-tag.vue create mode 100644 uni_modules/uni-tag/package.json create mode 100644 uni_modules/uni-tag/readme.md create mode 100644 uni_modules/uni-title/changelog.md create mode 100644 uni_modules/uni-title/components/uni-title/uni-title.vue create mode 100644 uni_modules/uni-title/package.json create mode 100644 uni_modules/uni-title/readme.md create mode 100644 uni_modules/uni-tooltip/changelog.md create mode 100644 uni_modules/uni-tooltip/components/uni-tooltip/uni-tooltip.vue create mode 100644 uni_modules/uni-tooltip/package.json create mode 100644 uni_modules/uni-tooltip/readme.md create mode 100644 uni_modules/uni-transition/changelog.md create mode 100644 uni_modules/uni-transition/components/uni-transition/createAnimation.js create mode 100644 uni_modules/uni-transition/components/uni-transition/uni-transition.vue create mode 100644 uni_modules/uni-transition/package.json create mode 100644 uni_modules/uni-transition/readme.md create mode 100644 uni_modules/uni-ui/changelog.md create mode 100644 uni_modules/uni-ui/components/uni-ui/uni-ui.vue create mode 100644 uni_modules/uni-ui/package.json create mode 100644 uni_modules/uni-ui/readme.md create mode 100644 uni_modules/uni-upgrade-center-app/changelog.md create mode 100644 uni_modules/uni-upgrade-center-app/images/app_update_close.png create mode 100644 uni_modules/uni-upgrade-center-app/images/bg_top.png create mode 100644 uni_modules/uni-upgrade-center-app/package.json create mode 100644 uni_modules/uni-upgrade-center-app/pages/upgrade-popup.vue create mode 100644 uni_modules/uni-upgrade-center-app/readme.md create mode 100644 uni_modules/uni-upgrade-center-app/uniCloud/database/db_init.json create mode 100644 uni_modules/uni-upgrade-center-app/utils/call-check-version.js create mode 100644 uni_modules/uni-upgrade-center-app/utils/check-update.js create mode 100644 uni_modules/uni-upgrade-center/changelog.md create mode 100644 uni_modules/uni-upgrade-center/js_sdk/validator/opendb-app-list.js create mode 100644 uni_modules/uni-upgrade-center/js_sdk/validator/opendb-app-versions.js create mode 100644 uni_modules/uni-upgrade-center/menu.json create mode 100644 uni_modules/uni-upgrade-center/package.json create mode 100644 uni_modules/uni-upgrade-center/pages/components/show-info.vue create mode 100644 uni_modules/uni-upgrade-center/pages/mixin/version_add_detail_mixin.js create mode 100644 uni_modules/uni-upgrade-center/pages/utils.js create mode 100644 uni_modules/uni-upgrade-center/pages/version/add.vue create mode 100644 uni_modules/uni-upgrade-center/pages/version/detail.vue create mode 100644 uni_modules/uni-upgrade-center/pages/version/list.vue create mode 100644 uni_modules/uni-upgrade-center/readme.md create mode 100644 uni_modules/uni-upgrade-center/uniCloud/database/db_init.json create mode 100644 uni_modules/yjly-dictItemSelect/changelog.md create mode 100644 uni_modules/yjly-dictItemSelect/components/yjly-dictItemSelect/yjly-dictItemSelect.vue create mode 100644 uni_modules/yjly-dictItemSelect/package.json create mode 100644 uni_modules/yjly-dictItemSelect/readme.md create mode 100644 uni_modules/yjly-ngtools-NGComponents/changelog.md create mode 100644 uni_modules/yjly-ngtools-NGComponents/components/yjly-ngtools-NGComponents/yjly-ngtools-NGComponents.vue create mode 100644 uni_modules/yjly-ngtools-NGComponents/package.json create mode 100644 uni_modules/yjly-ngtools-NGComponents/readme.md create mode 100644 uni_modules/yjly-ngtools-ParResult/changelog.md create mode 100644 uni_modules/yjly-ngtools-ParResult/components/yjly-ngtools-ParResult/yjly-ngtools-ParResult.vue create mode 100644 uni_modules/yjly-ngtools-ParResult/package.json create mode 100644 uni_modules/yjly-ngtools-ParResult/readme.md create mode 100644 uni_modules/yjly-ngtools-meterPar/changelog.md create mode 100644 uni_modules/yjly-ngtools-meterPar/components/yjly-ngtools-meterPar/yjly-ngtools-meterPar.vue create mode 100644 uni_modules/yjly-ngtools-meterPar/package.json create mode 100644 uni_modules/yjly-ngtools-meterPar/readme.md create mode 100644 uni_modules/yjly-ngtools-meterResult/changelog.md create mode 100644 uni_modules/yjly-ngtools-meterResult/components/yjly-ngtools-meterResult/yjly-ngtools-meterResult.vue create mode 100644 uni_modules/yjly-ngtools-meterResult/package.json create mode 100644 uni_modules/yjly-ngtools-meterResult/readme.md create mode 100644 格式化.xlsx diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c0b65b5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +unpackage/ \ No newline at end of file diff --git a/.hbuilderx/launch.json b/.hbuilderx/launch.json new file mode 100644 index 0000000..be18780 --- /dev/null +++ b/.hbuilderx/launch.json @@ -0,0 +1,31 @@ +{ + // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/ + // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数 + "version" : "0.0", + "configurations" : [ + { + "app-plus" : + { + "launchtype" : "remote" + }, + "default" : + { + "launchtype" : "local" + }, + "h5" : + { + "launchtype" : "remote" + }, + "mp-weixin" : + { + "launchtype" : "local" + }, + "provider" : "aliyun", + "type" : "uniCloud" + }, + { + "playground" : "standard", + "type" : "uni-app:app-android" + } + ] +} diff --git a/App.vue b/App.vue new file mode 100644 index 0000000..081a31b --- /dev/null +++ b/App.vue @@ -0,0 +1,56 @@ + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -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/README.md b/README.md new file mode 100644 index 0000000..faccd69 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +

+文档已移至 uni-starter文档 +

\ No newline at end of file diff --git a/androidPrivacy.json b/androidPrivacy.json new file mode 100644 index 0000000..0d726ca --- /dev/null +++ b/androidPrivacy.json @@ -0,0 +1,3 @@ +{ + "prompt" : "template" +} diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..e95d399 --- /dev/null +++ b/changelog.md @@ -0,0 +1,268 @@ +## 2.1.8(2023-12-15) +更新 升级依赖的uni-icons版本为2.0.8 +## 2.1.7(2023-12-15) +修复 因网络错误引起的 manifest.json 文件错误引起的 web 端字体大小等样式问题 +## 2.1.6(2023-12-14) +- 更新 依赖的uni-id-pages的版本为1.1.17 +## 2.1.5(2023-10-20) +- 更新 依赖的uni-id-pages的版本为1.1.16 +## 2.1.4(2023-07-11) +- 纠正`opendb-news-articles.schema.json`错误的权限表达式`doc.uid`为`doc.user_id` +## 2.1.3(2023-05-10) +- 更新 依赖的uni-id-pages的版本为1.1.13 修复 启用摇树优化后切换登陆方式报错的问题 +## 2.1.2(2023-02-10) +- 新增 微信小程序端 首页需强制登录时,隐藏返回首页按钮 +## 2.1.1(2023-02-02) +- 重要 分包加载uni-id-pages 优化后 运行时主包大小为:637KB 分包为:78KB,发布后主包大小为:585KB 分包为:75KB +- 新增 微信小程序端 支持选择使用微信资料的“头像”和“昵称” 设置用户资料 [详情参考](https://wdoc-76491.picgzc.qpic.cn/MTY4ODg1MDUyNzQyMDUxNw_21263_rTNhg68FTngQGdvQ_1647431233?w=1280&h=695.7176470588236) +## 2.1.0(2023-01-17) +- 重要 新增uni-admin需要的相关依赖和初始化数据(方便uni-admin关联uni-starter后可直接运行) +- 升级依赖的 [uni-id-pages](https://ext.dcloud.net.cn/plugin?name=uni-id-pages) 修复如下问题: + 1. 优化 压缩依赖的文件资源大小 + 2. 更新依赖的 验证码插件`uni-captcha`版本的版本为 0.6.4 修复 部分情况下APP端无法获取验证码的问题 [详情参考](https://ext.dcloud.net.cn/plugin?id=4048) + 3. 修复 客户端token过期后,点击退出登录按钮报错的问题 + 4. uni-id-co 修复 updateUser 接口`手机号`和`邮箱`参数值为空字符串时,修改无效的问题 +## 2.0.6(2022-10-19) +- 更新 文件路径:`/uni_modules/uni-id-pages/init.js`内uni-push客户端推送标识获取失败的提示 +## 2.0.5(2022-10-19) +- 更新依赖的`uni-id-pages`的版本为1.0.26 +## 2.0.4(2022-09-21) +- 新增 使用uni-id-pages的账号信息的状态管理功能 +## 2.0.3(2022-09-20) +- 更新 依赖的`uni-ui`组件为最新版本(注意:该版本的`uni-form`相关组件将自定义节点设置成[虚拟节点](https://uniapp.dcloud.net.cn/tutorial/vue-api.html#%E5%85%B6%E4%BB%96%E9%85%8D%E7%BD%AE))) +- 更新 依赖的`uni_module`-> `uni-id-pages`为 v1.0.19版 修复 小程序端,使用将自定义节点设置成虚拟节点的uni-ui组件,导致的样式错乱问题 +## 2.0.2(2022-09-19) +- 更新表结构,解决部分clientDB操作没有权限的问题 +## 2.0.1(2022-09-16) +- 更改默认值 +## 2.0.0(2022-09-16) +- 【重要】 v2版正式发布 应用`uni-id-pages`、`uniIdRouter`;(注意:此版本更新内容较多,升级请注意备份) +- 考虑到部分旧项目不想升级,保留`uni-starter v1`版源码,托管在仓库的[v1分支](https://gitcode.net/dcloud/uni-starter/-/blob/v1/README.md);继续使用v1版,遇到问题可以提交[Issue](https://gitcode.net/dcloud/uni-starter/-/issues/new?issue%5Bassignee_id%5D=&issue%5Bmilestone_id%5D=)有bug仍然会修复,但v1版本不再新增功能。 +## 1.2.7(2022-08-10) +- 修复微信小程序绑定手机号失败的问题 +## 1.2.6(2022-06-29) +- 支持 ios 安全区 +## 1.2.5(2022-05-29) +升级预置的`uni_modules`->`uni-captcha`版本为:0.6.0。[详情](https://ext.dcloud.net.cn/plugin?name=uni-captcha) +## 1.2.4(2022-05-20) +- 修改`uni-starter.config.js`->`debug`的默认值为`false` +## 1.2.3(2022-05-20) +- 默认关闭`manifest.json`中的扩展配置 +- `uni-starter.config.js` 新增debug,用于配置是否开启调试模式 +## 1.2.2(2022-05-19) +- 优化登陆体验,账号密码登陆错误超过2次,再显示图形验证码进行人机校验。 +## 1.2.1(2022-05-18) +- 修复在某些情况下,微信小程序端验证码显示错误的问题 +## 1.2.0(2022-05-16) +- 短信验证码登陆、绑定手机号码新增防刷逻辑。当短信验证码输入错误2次以上,弹出图形验证码进行人机校验。 +- uni-id-cf,新增防刷机制。更改loginLog为uniIdLog 记录各类uni-id操作,并新增action字段记录操作的行为名称 +- 注册账号新增需要输入图形验证码 +## 1.1.34(2022-05-12) +修复绑定手机号码,未验证空验证码的问题。注意:请确保项目依赖的uni-id版本为3.3.18+ +## 1.1.33(2022-02-24) +修复微信小程序端,个人资料-绑定手机号码,一键获取微信资料中手机号码绑定授权,点击“拒绝”时toast:encryptedData 不可为空的问题 +## 1.1.32(2022-02-24) +- 删除多余文件:`uniCloud/database/opendb-news-articles-detail.schema.json` +- 修复当用户选择验证码登陆方式,在输入验证码页面,点击微信登陆时报“你未同意隐私政策协议”的问题 +## 1.1.31(2022-02-16) +修复微信小程序端,修改绑定的手机号码时表单验证不正常的问题 +## 1.1.30(2022-01-26) +- 新增逻辑:调用uni-id-cf的logout接口后刷新设备信息中token的有效期 +- 修复某些情况下前端执行logout没调用uniID.logout的问题 +- 修复某些情况下报push_clientid未定义的问题 +## 1.1.29(2022-01-25) +- 保存`uni_id_token`到`storage`改用异步方法,方便通过拦截器执行`token`更新后的操作 +- 新增通过拦截器监听`uni_id_token`更新,调用云函数刷新刷新设备信息token有效期的API `renewDeviceTokenExpired` +- 删除留言板示例 +- 修复图片验证码样式问题 +## 1.1.28(2022-01-12) +删除list页第37行多了个`?`引起的报错 +## 1.1.27(2022-01-11) +更新uni-id-cf为:1.0.10版,修复 限制只有 admin 用户可管理用户标签(不支持非 admin 用户操作managerMultiTag 接口) +## 1.1.26(2021-12-29) +- 性能优化,list页面使用`getTemp`,[详情](https://uniapp.dcloud.io/uniCloud/unicloud-db?id=collection) +- 拉齐uni-starter和uni-admin的schema新增:uni-id-tag.schema.json,更新:opendb-verify-codes.schema.json +- 修复首次登陆,用户id没存储到storage的问题 +- 新增:执行退出登陆后,通过云函数调用`uniID.logout` +## 1.1.25(2021-12-09) +修复H5端在about页面,返回触发`uniShare.hide()`引发报错 +## 1.1.24(2021-11-29) +- 新增注销用户账号的功能 +- 修复在某些情况下,签到不连续7天,也获得60积分的问题 +## 1.1.23(2021-11-20) +- 使用`uni.getUniverifyManager`优化一键登陆中,点击第三方登陆的逻辑:未勾选隐私政策时,toast提醒并阻止了一键登陆界面的close +- 新增支持看激励视频广告签到 +## 1.1.22(2021-11-10) +删除`common/openApp.js`中可选链操作符,解决vue3版本在hbuilderX内置浏览器不兼容的问题 +## 1.1.21(2021-11-10) +新增app端列表页面使用原生list下拉刷新 +## 1.1.20(2021-11-08) +修复vue3版某些情况下i18n报错的问题 +## 1.1.19(2021-11-08) +配置文件`uni-starter.config.js`默认关闭i18n多语言国际化 +## 1.1.18(2021-10-14) +使用2.0版`uni-share`。当显示分享窗口时,监听返回操作(如:物理返回,全面屏手机侧滑)关闭分享窗口,而不是关闭当前页面。 +## 1.1.17(2021-10-12) +- 更新文档 +- 修复list页面where条件中缺少&符,导致的错误 +## 1.1.16(2021-10-05) +在控制台提示:开启多语言国际化,将获取i18n中配置的tabbar的值覆盖pages.json中配置的tabbar的值 +## 1.1.15(2021-10-02) +新增,支持配置是否开启i18n多语言国际化。 +配置文件:`uni-starter.config.js` +` +"i18n":{ + "enable":true //默认启用,国际化。如果你不想使用国际化相关功能,请改为false +} +` +## 1.1.14(2021-09-30) +1. 通过微信小程序登录自动保存`sessionKey`到`uni-id-users`表 +2. 我的-设置-个人资料 点击绑定手机号码,完善账号信息支持以下三种策略: + - APP端,(如果支持)使用"通过运营商一键获取手机号码" + - 微信小程序端,支持"一键获取微信绑定的手机号" + - 其他端,通过手机验证码 +## 1.1.13(2021-09-29) +修复search页面因多语言国际化导致的白屏问题 +## 1.1.12(2021-09-28) +1. 改造微信登录逻辑,直接使用`uni.login`参数`"onlyAuthorize":true`实现 +2. 修复,一键登录弹出层,已勾选“同意隐私政策协议”点击自定义登录按钮,报“你未同意隐私政策协议”的bug +## 1.1.11(2021-09-24) +优化邀请下载app页(`pages/ucenter/invite`)下载按钮闪烁的问题 +## 1.1.10(2021-09-23) +修复获取验证码按钮的文字,在中文模式下显示为英文的问题 +## 1.1.9(2021-09-16) +修复由多语言切换功能引起的隐私政策协议标题链接被重写的问题 +## 1.1.8(2021-09-15) +更新数据表guestbook的schema中更新权限的配置 +## 1.1.7(2021-09-14) +更新数据表opendb-news-articles的schema中的权限配置 +## 1.1.6(2021-09-13) +纠正错误schema权限表达式`doc.uid`为`doc.user_id` +## 1.1.5(2021-09-01) +为了更直观理解路由拦截。移除路由拦截器中,默认过滤登录相关页面拦截的逻辑。确保所有白名单页面均在配置文件router.visitor中体现 +## 1.1.4(2021-08-31) +修改错误的文章表`SChema`的读权限表达式 +## 1.1.3(2021-08-31) +修复在微信小程序端默认语言为英文的问题 +## 1.1.2(2021-08-30) +修复在微信小程序下切换语言报`locale`不存在的问题 +## 1.1.1(2021-08-30) +- 解决3.2.6以下版本hbuilderx,编译的项目报`uni.setLocale`不存在的问题 +## 1.1.0(2021-08-27) +- APP端支持vue3 (hbuilderx 3.2.5+) +- 支持国际化 中英文切换 +- 新增留言板示例 +- 修复签到的时区问题 +## 1.0.48(2021-08-10) +- 修复登录成功后响应体包含`userInfo.password`的问题 +- 修改了`uni-id-users`表的schema中字段username的编辑权限,防止用户通过clientDB绕过用户名不能重复的规则更新用户名的问题 +## 1.0.47(2021-08-09) +- 更新文档快速体验部署流程 +- 修复一键登录优先时报变量找不到的问题 +## 1.0.46(2021-08-05) +清理多余文件 +## 1.0.45(2021-08-05) +默认首页为nvue页面+fast +## 1.0.44(2021-08-05) +解决首页为非nvue页面时白屏的问题。 +- 注意:本次在`common/appInit.js`中修改了路由拦截的逻辑,是个兼容方案;当首页为非nvue页面,路由拦截器逻辑会在加载首页时执行。接下来新版本的hx编译的uni-app项目无论首页是否为nvue都不走拦截器,保持各端逻辑一致。 +## 1.0.43(2021-08-02) +1. 微信小程序端,新增:微信登录成功后,弹出是否"获取微信头像和昵称,完善个人资料"的弹框 +2. APP端,新增逻辑:微信登录成功后,自动获取用户的微信昵称和头像完善用户个人资料 +- 提示:因为微信的头像一旦更换,微信返回的头像url会失效。所以,以上两示例功能将url(客户端:下载到临时目录/服务端:转为Buffer)再上传到uniCloud云存储中再使用。 +## 1.0.42(2021-07-29) +新增绑定手机号码页面前端校验 +## 1.0.41(2021-07-27) +1. 支持vue3.0 +2. 去掉App.vue全局样式,避免与非flex布局的页面样式冲突 +## 1.0.40(2021-07-22) +1. 调整使用正则表达式配置强制登录功能的写法,解决在小程序端的兼容问题。 +2. 新增签到功能(培养用户习惯,提升用户粘性)。支持:每日签到奖励、周期性连续7日签到,奖励翻倍。 +## 1.0.39(2021-07-19) +1. 强制登录配置,新增白名单模式 +2. 强制登录配置,支持正则表达式 +## 1.0.38(2021-07-17) +删除多余文件 +## 1.0.37(2021-07-14) +去掉配置文件:`uni-starter.config.js`,`h5` —> `url`结尾的`/` +## 1.0.36(2021-07-14) +剪切板中的邀请码,添加标识性前缀 `uniInvitationCode:` +## 1.0.35(2021-07-12) +1. H5端默认不开启,隐私权限协议签署页面。因为网页端没有什么隐私权限能被获取,目前全球仅欧盟有要求;如有需要请手动开启 +2. 在列表页演示,如何在onShow生命周期获取设备位置,并在设备或者应用没有权限时自动引导。设置完毕自动重新获取。[更多点此查看插件介绍](https://ext.dcloud.net.cn/plugin?name=json-gps) +## 1.0.34(2021-07-08) +修复,打开登录页时携带参数,导致的快捷登录方式重复的问题 +## 1.0.33(2021-07-06) +修复,点击短信验证码登录打开的页面不正确的问题 +## 1.0.32(2021-07-06) +修复,仅配置一种快捷登录时的错误 +## 1.0.31(2021-07-02) +优化项目文档 +## 1.0.30(2021-07-01) +1. 简化宫格页面写法,方便理解如何控制不同状态角色的用户是否可见哪些元素。 +2. uni-id-cf发送短信验证码api,默认注释掉:虚拟发送短信验证码的代码块。 +3. uni-id-cf统一action名称为驼峰法 +## 1.0.29(2021-06-29) +1. 修复在安卓10以下设备,操作登录获取不到oaid会直接导致登录失败的bug +2. 修复uniCloud版本为阿里云版时删除头像设置失败,腾讯云版删除头像后二次上传失败的问题 +## 1.0.28(2021-06-28) +修复云函数uni-id-cf的resetPwdBySmsCode接口,未注册过的用户也能调用的问题 +## 1.0.27(2021-06-25) +修改文档,新增h5版演示示例 +## 1.0.26(2021-06-24) +升级用户头像上传的裁切功能,app端为原生裁剪其他端保持原来方式。数据表字段改用avatar_file存储file对象方便做图片的回显 +## 1.0.25(2021-06-23) +预置uniCloud admin依赖的uniCloud文件,方便uniCloud admin与uni-starter配套使用时免做文件迁移 +## 1.0.24(2021-06-23) +删除callFunction拦截器中多余的代码 +## 1.0.23(2021-06-22) +更正调试遗留的uni-config-center/uni-id/config.json的tokenExpiresIn=1配置问题,改为默认值7200 +## 1.0.22(2021-06-22) +1. 新增一键登录授权界面的其他快捷登录按钮 +2. 优化uni-quick-login组件代码 +3. 调整隐私政策协议框勾选逻辑:在登录页面已勾选,同步勾选。如果没勾选需要手动勾选(为符合应用市场上架要求) +4. 调整登录页隐私政策协议框位置。 +5. 增强路由拦截,新增判断token是否过期。 +## 1.0.21(2021-06-21) +优化:uni_modules模式使用uni-id-cf,方便uni-starter与uniCloud-admin的uni-id-cf同步更新。 +## 1.0.20(2021-06-18) +1.H5端新增,强制要求用户同意隐私协议 2.兼容ios端自动设置打开下载页用户的剪切板为邀请者的inviteCode 3.成功注册用户,且请求体含邀请码inviteCode自动关联裂变关系 +## 1.0.19(2021-06-17) +1.新增获取邀请码接口getUserInviteCode 2.在邀请用户下载应用页面,自动设置被邀请用户的剪切板为邀请者的code(仅支持安卓端) 3.在注册或登录并注册请求时自动添加剪切板中的请求参数 4.统一接口名称为驼峰法 +## 1.0.18(2021-06-15) +修复,APP端有安装微信客户端但未显示微信登录快捷键的问题 +## 1.0.17(2021-06-09) +修复,非APP端deviceInfo为空引起的登录失败问题 +## 1.0.16(2021-06-08) +新增,操作注册/登录操作自动获取客户端设备:push_clientid、imei、oaid、idfa新增/更新到数据表uni-id-device新增,操作注册/登录操作自动获取客户端设备:push_clientid、imei、oaid、idfa新增/更新到数据表uni-id-device +## 1.0.15(2021-06-07) +为迎合苹果App Store的规则,登录与分享功能项显示之前自动检测是否安装了对应客户端。比如:设备未安装微信则不显示微信快捷登录和微信分享选项。为迎合苹果App Store的规则,登录与分享功能项显示之前自动检测是否安装了对应客户端。比如:设备未安装微信则不显示微信快捷登录和微信分享选项。 +## 1.0.14(2021-06-07) +修改错误的表名称uni-verify为opendb-verify-codes +## 1.0.13(2021-06-04) +新增一键登录界面的第三方快捷登录按钮 +## 1.0.12(2021-05-28) +修复拦截器在ios app端会报错:Unhandled promise...的问题 +## 1.0.10(2021-05-27) +新增callfunction的拦截器废除this.request的写法。为callFunction添加:请求失败是否断网判断并提示、恢复网络自动重新执行、自动处理响应体:token过期自动跳转到登录页面、token自动续期 +## 1.0.9(2021-05-23) +修复变量被重复定义的问题 +## 1.0.8(2021-05-22) +宫格页(/pages/grid/grid),新增根据当前用户是否登录、是否为管理员的角色来决定是否显示的示范 +## 1.0.7(2021-05-22) +删除多余数据 +## 1.0.6(2021-05-22) +修复当username(用户名&密码)为第一优先级的登录方式时。无法切换到smsCode(短信验证码)登录方式 +## 1.0.5(2021-05-20) +改用uni_modules方式处理图片选择api时无权限,引导用户快捷打开系统设置 +## 1.0.4(2021-05-19) +为方便部署,添加空的manifest.json uni-config-center下的uni-id配置 +## 1.0.3(2021-05-18) +重大调整,原云函数名称:user-center改名叫uni-id-cf +修复,绑定手机号码场景。因手机未插SIM导致的一键登录失败后未直接跳到获取短信验证码方式绑定 +## 1.0.2(2021-05-17) +添加 uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json 文件 +## 1.0.1(2021-05-17) +manifest.json 在小程序平台增加了一个配置项 betterScopedSlots,启用新的作用域插槽编译,用于支持作用域插槽内使用复杂表达式。 +## 1.0.0(2021-05-17) +第一版 \ No newline at end of file diff --git a/common/appInit.js b/common/appInit.js new file mode 100644 index 0000000..b62d38c --- /dev/null +++ b/common/appInit.js @@ -0,0 +1,164 @@ +import uniStarterConfig from '@/uni-starter.config.js'; +//应用初始化页 +// #ifdef APP-PLUS +import checkUpdate from '@/uni_modules/uni-upgrade-center-app/utils/check-update'; +import callCheckVersion from '@/uni_modules/uni-upgrade-center-app/utils/call-check-version'; + +// 实现,路由拦截。当应用无访问摄像头/相册权限,引导跳到设置界面 https://ext.dcloud.net.cn/plugin?id=5095 +import interceptorChooseImage from '@/uni_modules/json-interceptor-chooseImage/js_sdk/main.js'; +interceptorChooseImage() + +// #endif +const db = uniCloud.database() +export default async function() { + const debug = uniStarterConfig.debug; + + // uniStarterConfig挂载到getApp().globalData.config + setTimeout(() => { + getApp({ + allowDefault: true + }).globalData.config = uniStarterConfig; + }, 1) + + + // 初始化appVersion(仅app生效) + initAppVersion(); + + //clientDB的错误提示 + function onDBError({ + code, // 错误码详见https://uniapp.dcloud.net.cn/uniCloud/clientdb?id=returnvalue + message + }) { + console.log('onDBError', { + code, + message + }); + // 处理错误 + console.error(code, message); + } + // 绑定clientDB错误事件 + db.on('error', onDBError) + + + //拦截云对象请求 + uniCloud.interceptObject({ + async invoke({ + objectName, // 云对象名称 + methodName, // 云对象的方法名称 + params // 参数列表 + }) { + // console.log('interceptObject',{ + // objectName, // 云对象名称 + // methodName, // 云对象的方法名称 + // params // 参数列表 + // }); + if(objectName == "uni-id-co" && (methodName.includes('loginBy') || ['login','registerUser'].includes(methodName) )){ + console.log('执行登录相关云对象'); + params[0].inviteCode = await new Promise((callBack) => { + uni.getClipboardData({ + success: function(res) { + console.log('剪切板内容:'+res.data); + if (res.data.slice(0, 18) == 'uniInvitationCode:') { + let uniInvitationCode = res.data.slice(18, 38) + console.log('当前用户是其他用户推荐下载的,推荐者的code是:' + uniInvitationCode); + // uni.showModal({ + // content: '当前用户是其他用户推荐下载的,推荐者的code是:'+uniInvitationCode, + // showCancel: false + // }); + callBack(uniInvitationCode) + //当前用户是其他用户推荐下载的。这里登记他的推荐者id 为当前用户的myInviteCode。判断如果是注册 + } else { + callBack() + } + }, + fail() { + console.log('error--'); + callBack() + }, + complete() { + // #ifdef MP-WEIXIN + uni.hideToast() + // #endif + } + }); + }) + // console.log(params); + } + // console.log(params); + }, + success(e) { + console.log(e); + }, + complete() { + + }, + fail(e){ + console.error(e); + // if (debug) { + // uni.showModal({ + // content: JSON.stringify(e), + // showCancel: false + // }); + // }else{ + // uni.showToast({ + // title: '系统错误请稍后再试', + // icon:'error' + // }); + // } + } + }) + + + // #ifdef APP-PLUS + // 监听并提示设备网络状态变化 + uni.onNetworkStatusChange(res => { + console.log(res.isConnected); + console.log(res.networkType); + if (res.networkType != 'none') { + uni.showToast({ + title: '当前网络类型:' + res.networkType, + icon: 'none', + duration: 3000 + }) + } else { + uni.showToast({ + title: '网络类型:' + res.networkType, + icon: 'none', + duration: 3000 + }) + } + }); + // #endif + +} +/** + * // 初始化appVersion + */ +function initAppVersion() { + // #ifdef APP-PLUS + let appid = plus.runtime.appid; + plus.runtime.getProperty(appid, (wgtInfo) => { + let appVersion = plus.runtime; + let currentVersion = appVersion.versionCode > wgtInfo.versionCode ? appVersion : wgtInfo; + getApp({ + allowDefault: true + }).appVersion = { + ...currentVersion, + appid, + hasNew: false + } + // 检查更新小红点 + callCheckVersion().then(res => { + // console.log('检查是否有可以更新的版本', res); + if (res.result.code > 0) { + // 有新版本 + getApp({ + allowDefault: true + }).appVersion.hasNew = true; + console.log(checkUpdate()); + } + }) + }); + // 检查更新 + // #endif +} \ No newline at end of file diff --git a/common/openApp.js b/common/openApp.js new file mode 100644 index 0000000..6fbbbb4 --- /dev/null +++ b/common/openApp.js @@ -0,0 +1,36 @@ +/* + 创建在h5端全局悬浮引导用户下载app的功能, + 如不需要本功能直接移除配置文件uni-starter.config.js下的h5/openApp即可 +*/ + +import CONFIG from '../uni-starter.config.js'; + +const CONFIG_OPEN = CONFIG.h5.openApp || {}; +// 仅H5端添加"打开APP" +export default function() { + // #ifdef H5 + if (!CONFIG_OPEN.openUrl) return; + + let openLogo = CONFIG_OPEN.logo ? + `` : ''; + let openApp = document.createElement("div"); + openApp.id = 'openApp'; + openApp.style = + 'position: fixed;background:#FFFFFF;box-shadow: #eeeeee 1px 1px 9px; ;top: 0;left: 0;right: 0;z-index: 999;width: 100%;height: 45px;display: flex;flex-direction: row;justify-content: space-between;align-items: center;box-sizing: border-box;padding: 0 0.5rem;' + openApp.innerHTML = ` +
+ ${openLogo} +
${CONFIG_OPEN.appname || ''}
+
+
下载app
+ `; + document.body.insertBefore(openApp, document.body.firstChild); + document.body.style = 'height:calc(100% - 45px); margin-top:45px;'; + openApp.addEventListener('click', e => { + var target = e.target || e.srcElement; + if (target.className.indexOf('openBtn') >= 0) { + window.location.href = CONFIG_OPEN.openUrl; + } + }) + //#endif +} diff --git a/components/refreshBox/refreshBox.vue b/components/refreshBox/refreshBox.vue new file mode 100644 index 0000000..1165d06 --- /dev/null +++ b/components/refreshBox/refreshBox.vue @@ -0,0 +1,95 @@ + + + + diff --git a/components/uni-load-state/i18n/en.json b/components/uni-load-state/i18n/en.json new file mode 100644 index 0000000..b600ad4 --- /dev/null +++ b/components/uni-load-state/i18n/en.json @@ -0,0 +1,6 @@ +{ + "noData": "No Data", + "noNetwork": "Network error", + "toSet": "Go to settings", + "error": "error" +} diff --git a/components/uni-load-state/i18n/index.js b/components/uni-load-state/i18n/index.js new file mode 100644 index 0000000..c70a386 --- /dev/null +++ b/components/uni-load-state/i18n/index.js @@ -0,0 +1,6 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +export default { + en, + 'zh-Hans': zhHans +} diff --git a/components/uni-load-state/i18n/zh-Hans.json b/components/uni-load-state/i18n/zh-Hans.json new file mode 100644 index 0000000..4fa8e1a --- /dev/null +++ b/components/uni-load-state/i18n/zh-Hans.json @@ -0,0 +1,6 @@ +{ + "noData": "暂无数据", + "noNetwork": "网络异常", + "toSet": "前往设置", + "error": "错误" +} diff --git a/components/uni-load-state/readme.md b/components/uni-load-state/readme.md new file mode 100644 index 0000000..07288d6 --- /dev/null +++ b/components/uni-load-state/readme.md @@ -0,0 +1,3 @@ +新增uni-load-state组件,这是一个封装数据请求状态的组件。根据uniCloud-db组件提供的参数直接响应对应的效果。 +包括加载中、当前页面为空、没有更多数据、上拉加载更多; +加载错误判断,如果是断网就引导打开系统网络设置页面。恢复联网后自动触发networkResume方法。 \ No newline at end of file diff --git a/components/uni-load-state/uni-load-state.vue b/components/uni-load-state/uni-load-state.vue new file mode 100644 index 0000000..bfc72c5 --- /dev/null +++ b/components/uni-load-state/uni-load-state.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..13b75dd --- /dev/null +++ b/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/js_sdk/AC-Dictionary/script/HttpDictionary.js b/js_sdk/AC-Dictionary/script/HttpDictionary.js new file mode 100644 index 0000000..ceef1d7 --- /dev/null +++ b/js_sdk/AC-Dictionary/script/HttpDictionary.js @@ -0,0 +1,104 @@ +/* + 字典模块 + 作者:AC + 时间:2019/12/24 14:00 + 说明:所有其中的数据都不会显示在Storage中 一定程度上防止了泄漏 + 主要方法说明: + AddKeyValue:添加键值对 + DeleteValueByKey:根据键删除值 + GetValueByKey:根据键获取值 + ClearDictionary:清空字典内容 + GetDictionary:获取字典 + GetValueByKeyAndFun:根据键获取值 并且运行一个指定的函数(要求此函数必须返回这个键对应的值) + 主要参数说明: + dictionary:字典 + httpDictionary: 字典操作 + code:状态值 + key:字典的键 + value:字典的值 + fun:外部函数(要求此函数必须返回这个键对应的值) + 操作日志: + 1.初步搭建 2019/12/14 14:00 AC +*/ + +/* + 以下发出的功能均经过项目中的实际使用 + 在uni-app 中的微信小程序项目下 可以使用 避免使用Storage的一系列坑 + 不过此数据字典 会在每次用户关闭小程序或者关闭页面的时候清空. + 仅仅可以用在小程序的优化访问中 一些静态数据的存储以及修改 以及一些临时数据的存储 + + 需要在初始化的时候进行创建 详见APP.VUE 示例 +*/ +var message=require("script/Message.js"); + +//初始化请求字典集合 +var dictionary={}; +//执行结果值 +var value=""; +var httpDictionary={ + //添加/修改字典值-如果有这个key 则会覆盖其中原先的值 + AddKeyValue:function(key,value){ + dictionary[key]=value; + }, + //删除key的值 + DeleteValueByKey:function(key){ + return DeleteValue(key); + }, + //根据key获取值 + GetValueByKey:function(key){ + return GetValues(key); + }, + //清空字典的所有值 恢复成默认值 + ClearDictionary:function(){ + dictionary={}; + }, + //获取整个字典 + GetDictionary:function(){ + return dictionary; + }, + //获取字典的值 并且执行fun函数 如果fun是一个函数 结果fun必须返回一个字符串 + GetValueByKeyAndFun:function(key,fun){ + return typeof fun == "function"? fun(this.GetValueByKey(key)):this.GetValueByKey(key); + } +} +//获取value值 +function GetValues(key){ + try{ + //键为空 增加提示信息 + if(key==""){ + return message.SetMessage("A002","在执行获取字典内容的时候,键为空","",1); + } + console.log("值:"+dictionary[key]); + return (typeof dictionary[key] == "undefined"?"":dictionary[key]); + }catch(e){ + return message.SetMessage("A001","在执行获取"+key+"的值的时候发生异常","",0); + } +} + +//尝试清除字典中的值 +function DeleteValue(key){ + try{ + //键为空 增加提示信息 + if(key==""){ + return message.SetMessage("A002","在执行清除字典内容的时候,键为空",false,1); + } + dictionary[key]=""; + return true; + }catch(e){ + return message.SetMessage("A001","在执行清除"+key+"的值的时候发生异常",false,0); + } +} + +//设置字典中的值 +function SetValue(key,value){ + try{ + if(key==""){ + return message.SetMessage("A002","在执行添加字典内容的时候,键为空",false,1); + } + dictionary[key]=value; + return true; + }catch(e){ + return message.SetMessage("A001","在执行添加"+key+"的值的时候发生异常",false,0); + } +} +module.exports=httpDictionary; \ No newline at end of file diff --git a/js_sdk/AC-Dictionary/script/Message.js b/js_sdk/AC-Dictionary/script/Message.js new file mode 100644 index 0000000..2dc4a9c --- /dev/null +++ b/js_sdk/AC-Dictionary/script/Message.js @@ -0,0 +1,59 @@ +/* + 消息模块 + 作者:AC + 时间:2019/12/26 + 说明:目前只是简单的消息模块 后期会增加日志等功能 + 参数说明: + exec: + type:0 必定运行异常 1 系统警告 2 系统提示 3 正常请求 4可能会出现异常 + code: + "A001":执行异常 + "A002":传入参数为空 + "A200":提示信息 + "A400":无权操作 + message:消息内容 可以是提示,异常,警告等消息头 只需对应的type即可 + switchType:消息类型字典 常量 + Message: + 函数说明: + SetMessage:设置消息 + result:需要返回的值(其他操作携带过来的 此处可以对其进行再次处理) + code:同exce.code + message:同exce.message + type:同exce.type + 操作日志: + 1.初步搭建:2019/12/26 15:00 AC 搭建完成 通过测试 + 2.增加type 3 4 +*/ +//消息模块 此处为简单版本 保存运行时的日志信息 +//完善版本正在项目中使用并且测试,可自己完善其中的部分,如果您有更好的建议 +//希望您能够 添加我的qq 2960861359 或者微信 K11150922 + +var exce={ + message:"", + code:"", + type:2, + typeInfo:"提示" +}; + +var switchType={ + "0":"异常", + "1":"警告", + "2":"提示", + "3":"请求", + "4":"可能出现异常"//当message为空 则表示可能出现异常 +} +var Message={ + //设置错误信息 + SetMessage:function(code,message,result,type){ + exce.message=message; + exce.code=code; + exce.type=type; + exce.typeInfo=switchType[type]==""?"未注册的状态":switchType[type]; + return result; + }, + GetMessage:function(){ + return exce; + } +} +//消息模块 +module.exports=Message; \ No newline at end of file diff --git a/js_sdk/dc-deviceinfo/deviceinfo.js b/js_sdk/dc-deviceinfo/deviceinfo.js new file mode 100644 index 0000000..a035990 --- /dev/null +++ b/js_sdk/dc-deviceinfo/deviceinfo.js @@ -0,0 +1,159 @@ + +var WIFI_SERVICE = 'wifi'; +var ACTIVITY_SERVICE = 'activity'; + +/** + * 获取wifi的mac地址 + */ +function getMac(){ +try{ + var os = plus.os.name; + if('Android' == os){ + var main = plus.android.runtimeMainActivity(); + var wifiService = main.getSystemService(WIFI_SERVICE); + var wifiInfo = plus.android.invoke(wifiService, 'getConnectionInfo'); + var mac = plus.android.invoke(wifiInfo, 'getMacAddress'); + return mac; + }else{ + //unsupport, nothing to do. + } +}catch(e){ + console.error('error @getMac!!'); +} +} + +/** + * 获取手机可用内存大小 + * 单位为字节 + */ +function getAvailMemory(){ +try{ + var os = plus.os.name; + if('Android' == os){ + var ActivityManager = plus.android.importClass('android.app.ActivityManager'); + var mi = new ActivityManager.MemoryInfo(); + var activityService = plus.android.runtimeMainActivity().getSystemService(ACTIVITY_SERVICE); + activityService.getMemoryInfo(mi); + var memoryInfo = mi.plusGetAttribute('availMem'); + return memoryInfo; + }else{ + //unsupport, nothing to do. + } +}catch(e){ + console.error('error @getAvailMemory!!'); +} +} + +/** + * 获取手机总内存大小 + * 单位为KB + */ +function getTotalMemory(){ +try{ + var os = plus.os.name; + if('Android' == os){ + var memInfo = '/proc/meminfo'; + var temp = '', + ramSize = '', + arrays, initMemory; + var fileReader = plus.android.importClass("java.io.FileReader"); + var bufferedReader = plus.android.importClass("java.io.BufferedReader"); + var FileReader = new fileReader(memInfo); + var BufferedReader = new bufferedReader(FileReader, 8192); + while ((temp = BufferedReader.readLine()) != null) { + if (-1 != temp.indexOf('MemTotal:')) { + var value = temp.replace(/[^0-9]/ig, ""); + ramSize = parseInt(value); + } + } + return ramSize; + }else{ + //unsupport, nothing to do. + } +}catch(e){ + console.error('error @getAvailMemory!!'); +} +} + +/** + * 获取内部存储空间大小 + * 单位为字节 + */ +function getInternalStorage(){ +try{ + var os = plus.os.name; + if('Android' == os){ + var environment = plus.android.importClass('android.os.Environment'); + var statFs = plus.android.importClass('android.os.StatFs'); + var files = plus.android.importClass('java.io.File'); + var Files = environment.getDataDirectory(); + var StatFs = new statFs(Files.getPath()); + var blockSize = parseFloat(StatFs.getBlockSize()); + var blockCount = parseFloat(StatFs.getBlockCount()); + var internalMemSize = blockSize*blockCount; + return internalMemSize; + }else{ + //unsupport, nothing to do. + } +}catch(e){ + console.error('error @getCpuInfo!!'); +} +} + +/** + * 获取CPU信息 + */ +function getCpuInfo(){ +try{ + var os = plus.os.name; + if('Android' == os){ + var cpuInfo = '/proc/cpuinfo'; + var temp = '', + cpuHardware; + var fileReader = plus.android.importClass('java.io.FileReader'); + var bufferedReader = plus.android.importClass('java.io.BufferedReader'); + var FileReader = new fileReader(cpuInfo); + var BufferedReader = new bufferedReader(FileReader, 8192); + while ((temp = BufferedReader.readLine()) != null) { + if (-1 != temp.indexOf('Hardware')) { + cpuHardware = temp.substr(parseInt(temp.indexOf(":")) + 1); + } + } + return cpuHardware; + }else{ + //unsupport, nothing to do. + } +}catch(e){ + console.error('error @getCpuInfo!!'); +} +} + +/** + * 获取CPU核数 + */ +function getCpuCount(){ +try{ + var os = plus.os.name; + if('Android' == os){ + var Runtime = plus.android.importClass("java.lang.Runtime"); + var cpuCount = Runtime.getRuntime().availableProcessors(); + return cpuCount; + }else{ + //unsupport, nothing to do. + } +}catch(e){ + console.error('error @getCpuInfo!!'); +} +} + + + +module.exports = { + mac: getMac, + availMem: getAvailMemory, + totalMem: getTotalMemory, + interStorage: getInternalStorage, + cpuInfo: getCpuInfo, + cpuCount: getCpuCount, + getCpuInfo +} diff --git a/js_sdk/util/dictTools.js b/js_sdk/util/dictTools.js new file mode 100644 index 0000000..275a432 --- /dev/null +++ b/js_sdk/util/dictTools.js @@ -0,0 +1,113 @@ +const db = uniCloud.database(); +import { + getJsonTree, + groupBy +} from "@/js_sdk/util/jsonData"; + +//一次性把字典数据查询并存储 + export function saveDictItemStore() { + db.collection('ngTools_DictItem').field( + "dictID,itemValue as value , itemText as text ,itemColor,description,sortOrder" + ).orderBy('dictID,sortOrder') + .get().then((res) => { + console.log(res) + + if (res.result.data) { + const selectData = groupBy(res.result.data, 'dictID'); + // #ifdef APP-PLUS + uni.setStorageSync("dictItem", selectData); + // #endif + // #ifdef H5 + localStorage.setItem("dictItem", JSON.stringify(selectData)); + // #endif + // #ifdef MP-WEIXIN + wx.setStorageSync("dictItem", selectData); + // #endif + console.log(res.result.data) + console.log(selectData) + + } + }).catch((err) => { + uni.showModal({ + content: err.message || '请求服务失败', + showCancel: false + }) + console.log(3333) + }).finally(() => { + console.log(4444) + uni.hideLoading() + }) +} + +//一次性把字典数据查询并存储 + + +export function saveDepartStore() { + db.collection('ngTools_depart').field( + "_id,parent_id,depart_name,level,sort,manager_uid,status" + ).orderBy('parent_id') + .get().then((res) => { + if (res.result.data) { + const departData = getJsonTree(res.result.data); + console.log(departData) + // #ifdef APP-PLUS + uni.setStorageSync("departData", departData); + // #endif + // #ifdef H5 + localStorage.setItem("departData", JSON.stringify(departData)); + // #endif + // #ifdef MP-WEIXIN + wx.setStorageSync("departData", departData); + // #endif + console.log(res.result.data) + console.log(departData) + + } + }).catch((err) => { + uni.showModal({ + content: err.message || '请求服务失败', + showCancel: false + }) + console.log(3333) + }).finally(() => { + console.log(4444) + uni.hideLoading() + }) +} + +export function getDictItemStore(dictID) { + let data = []; + // #ifdef MP-WEIXIN + data = (wx.getStorageSync("dictItem")); + // #endif + // #ifdef APP-PLUS + data = uni.getStorageSync("dictItem"); + // #endif + // #ifdef H5 + data = JSON.parse(localStorage.getItem("dictItem")); + // #endif + return data[dictID]; + // console.log(this.selectData); + // console.log(data); + // if (this.selectData.length > 0) { + + // } +} + +export function getDepartStore() { + let data = []; + // #ifdef MP-WEIXIN + data = (wx.getStorageSync("departData")); + // #endif + // #ifdef APP-PLUS + data = uni.getStorageSync("departData"); + // #endif + // #ifdef H5 + data = JSON.parse(localStorage.getItem("departData")); + // #endif + return data; + +} + + + \ No newline at end of file diff --git a/js_sdk/util/jsonData.js b/js_sdk/util/jsonData.js new file mode 100644 index 0000000..790551c --- /dev/null +++ b/js_sdk/util/jsonData.js @@ -0,0 +1,48 @@ + export function groupBy(array, key) { + return array.reduce((result, currentItem) => { + // 使用 key 的值作为分组的键 + const groupKey = currentItem[key]; + + // 如果 result 中不存在这个键,则创建一个数组 + if (!result[groupKey]) { + result[groupKey] = []; + } + + // 将当前项推入对应的分组数组中 + result[groupKey].push(currentItem); + + return result; + }, {}); +} + + +export function getJsonTree(items) { + const rootItems = []; + const lookup = {}; + + for (const item of items) { + const itemId = item._id; + const parentId = item.parent_id; + + if (!lookup[itemId]) lookup[itemId] = { + ['children']: [] + }; + lookup[itemId] = { + ...item, + children: lookup[itemId]['children'] + }; + + const parent = parentId ? lookup[parentId] : null; + if (parent) { + if (!parent.children) parent.children = []; + parent.children.push(lookup[itemId]); + } else { + rootItems.push(lookup[itemId]); + } + } + + return rootItems; +} + + + \ No newline at end of file diff --git a/js_sdk/validator/ngTools_Dict.js b/js_sdk/validator/ngTools_Dict.js new file mode 100644 index 0000000..3eae10a --- /dev/null +++ b/js_sdk/validator/ngTools_Dict.js @@ -0,0 +1,129 @@ +// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema + + +const validator = { + "dictName": { + "rules": [ + { + "format": "string", + 'require':true, + } + ], + "title": "字典名称", + "label": "字典名称" + }, + "dictCode": { + "rules": [ + { + "format": "string", + 'require':true, + } + ], + "title": "字典编码", + "label": "字典编码" + }, + "description": { + "rules": [ + { + "format": "string" + } + ], + "title": "描述", + "label": "描述" + }, + "delFlag": { + "rules": [ + { + "format": "int" + } + ], + "title": "删除状态", + "label": "删除状态" + }, + "createBy": { + "rules": [ + { + "format": "string" + } + ], + "title": "创建人", + "label": "创建人" + }, + "updateBy": { + "rules": [ + { + "format": "string" + } + ], + "title": "更新人", + "label": "更新人" + }, + "updateTime": { + "rules": [ + { + "format": "datetime" + } + ], + "title": "更新时间", + "label": "更新时间" + } + // , + // "createTime": { + // "rules": [ + // { + // "format": "datetime" + // } + // ], + // "title": "创建时间", + // "label": "创建时间" + // } +} + +const enumConverter = {} + +function filterToWhere(filter, command) { + let where = {} + for (let field in filter) { + let { type, value } = filter[field] + switch (type) { + case "search": + if (typeof value === 'string' && value.length) { + where[field] = new RegExp(value) + } + break; + case "select": + if (value.length) { + let selectValue = [] + for (let s of value) { + selectValue.push(command.eq(s)) + } + where[field] = command.or(selectValue) + } + break; + case "range": + if (value.length) { + let gt = value[0] + let lt = value[1] + where[field] = command.and([command.gte(gt), command.lte(lt)]) + } + break; + case "date": + if (value.length) { + let [s, e] = value + let startDate = new Date(s) + let endDate = new Date(e) + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + case "timestamp": + if (value.length) { + let [startDate, endDate] = value + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + } + } + return where +} + +export { validator, enumConverter, filterToWhere } diff --git a/js_sdk/validator/ngTools_DictItem.js b/js_sdk/validator/ngTools_DictItem.js new file mode 100644 index 0000000..f4698f2 --- /dev/null +++ b/js_sdk/validator/ngTools_DictItem.js @@ -0,0 +1,153 @@ +// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema + + +const validator = { + "dictID": { + "rules": [ + { + "format": "string" + } + ], + "title": "字典ID", + "label": "字典ID" + }, + "itemValue": { + "rules": [ + { + "format": "string" + } + ], + "title": "字典项值", + "label": "字典项值" + }, + "itemText": { + "rules": [ + { + "format": "string" + } + ], + "title": "字典项文本", + "label": "字典项文本" + }, + "itemColor": { + "rules": [ + { + "format": "string" + } + ], + "title": "字典项颜色", + "label": "字典项颜色" + }, + "description": { + "rules": [ + { + "format": "string" + } + ], + "title": "描述", + "label": "描述" + }, + "sortOrder": { + "rules": [ + { + "format": "string" + } + ], + "title": "排序", + "label": "排序" + }, + "status": { + "rules": [ + { + "format": "int" + } + ], + "title": "状态", + "label": "状态" + }, + "createBy": { + "rules": [ + { + "format": "string" + } + ], + "title": "创建人", + "label": "创建人" + }, + "updateBy": { + "rules": [ + { + "format": "string" + } + ], + "title": "更新人", + "label": "更新人" + }, + "createTime": { + "rules": [ + { + "format": "datetime" + } + ], + "title": "创建时间", + "label": "创建时间" + }, + "updateTime": { + "rules": [ + { + "format": "datetime" + } + ], + "title": "更新时间", + "label": "更新时间" + } +} + +const enumConverter = {} + +function filterToWhere(filter, command) { + let where = {} + for (let field in filter) { + let { type, value } = filter[field] + switch (type) { + case "search": + if (typeof value === 'string' && value.length) { + where[field] = new RegExp(value) + } + break; + case "select": + if (value.length) { + let selectValue = [] + for (let s of value) { + selectValue.push(command.eq(s)) + } + where[field] = command.or(selectValue) + } + break; + case "range": + if (value.length) { + let gt = value[0] + let lt = value[1] + where[field] = command.and([command.gte(gt), command.lte(lt)]) + } + break; + case "date": + if (value.length) { + let [s, e] = value + let startDate = new Date(s) + let endDate = new Date(e) + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + case "timestamp": + if (value.length) { + let [startDate, endDate] = value + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + } + } + return where +} + +export { validator, enumConverter, filterToWhere } diff --git a/js_sdk/validator/ngTools_MeterList.js b/js_sdk/validator/ngTools_MeterList.js new file mode 100644 index 0000000..0e0f51b --- /dev/null +++ b/js_sdk/validator/ngTools_MeterList.js @@ -0,0 +1,108 @@ +// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema + + +const validator = { + "dMeterType": { + "rules": [ + { + "format": "string" + } + ], + "title": "流量计类别", + "label": "流量计类别" + }, + "departID": { + "rules": [ + { + "format": "string" + } + ], + "title": "部门编号", + "label": "部门编号" + }, + "createBy": { + "rules": [ + { + "format": "string" + } + ], + "title": "创建人", + "label": "创建人" + }, + "updateBy": { + "rules": [ + { + "format": "string" + } + ], + "title": "更新人", + "label": "更新人" + }, + "createTime": { + "rules": [ + { + "format": "datetime" + } + ], + "title": "创建时间", + "label": "创建时间" + }, + "updateTime": { + "rules": [ + { + "format": "datetime" + } + ], + "title": "更新时间", + "label": "更新时间" + } +} + +const enumConverter = {} + +function filterToWhere(filter, command) { + let where = {} + for (let field in filter) { + let { type, value } = filter[field] + switch (type) { + case "search": + if (typeof value === 'string' && value.length) { + where[field] = new RegExp(value) + } + break; + case "select": + if (value.length) { + let selectValue = [] + for (let s of value) { + selectValue.push(command.eq(s)) + } + where[field] = command.or(selectValue) + } + break; + case "range": + if (value.length) { + let gt = value[0] + let lt = value[1] + where[field] = command.and([command.gte(gt), command.lte(lt)]) + } + break; + case "date": + if (value.length) { + let [s, e] = value + let startDate = new Date(s) + let endDate = new Date(e) + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + case "timestamp": + if (value.length) { + let [startDate, endDate] = value + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + } + } + return where +} + +export { validator, enumConverter, filterToWhere } diff --git a/js_sdk/validator/ngTools_MeterPar.js b/js_sdk/validator/ngTools_MeterPar.js new file mode 100644 index 0000000..e5de7ea --- /dev/null +++ b/js_sdk/validator/ngTools_MeterPar.js @@ -0,0 +1,457 @@ +// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema + + +const validator = { + "createBy": { + "rules": [{ + "format": "string" + }], + "title": "创建人", + "label": "创建人" + }, + "updateBy": { + "rules": [{ + "format": "string" + }], + "title": "更新人", + "label": "更新人" + }, + "meterID": { + "rules": [{ + "format": "string" + }], + "title": "计量点编号", + "label": "计量点编号" + }, + "dFlowCalbz": { + "rules": [{ + "format": "string" + }], + "title": "流量计算标准", + "label": "流量计算标准" + }, + "dZcalbz": { + "rules": [{ + "format": "string" + }], + "title": "压缩因子计算标准", + "label": "压缩因子计算标准" + }, + "dCbtj": { + "rules": [{ + "format": "string" + }], + "title": "计量参比条件压力", + "label": "计量参比条件压力" + }, + "dPb_M": { + "rules": [{ + "format": "string" + }], + "title": "计量参比条件压力", + "label": "计量参比条件压力" + }, + "dTb_M": { + "rules": [{ + "format": "string" + }], + "title": "计量参比条件温度", + "label": "计量参比条件温度" + }, + "dPb_E": { + "rules": [{ + "format": "string" + }], + "title": "燃烧参比条件压力", + "label": "燃烧参比条件压力" + }, + "dTb_E": { + "rules": [{ + "format": "string" + }], + "title": "燃烧参比条件温度", + "label": "燃烧参比条件温度" + }, + "dPatm": { + "rules": [{ + "format": "string", + "required": true, + "errorMessage": '大气压未输入' + }], + "title": "当地大气压", + "label": "当地大气压" + }, + "dPatmUnit": { + "rules": [{ + "format": "string" + }], + "title": "当地大气压单位", + "label": "当地大气压单位" + }, + "dNG_Compents": { + "rules": [{ + "format": "string" + }], + "title": "天然气组分", + "label": "天然气组分" + }, + "dMeterType": { + "rules": [{ + "format": "string" + }], + "title": "流量计类别", + "label": "流量计类别" + }, + "dCoreType": { + "rules": [{ + "format": "string" + }], + "title": "节流装置类型", + "label": "节流装置类型" + }, + "dPtmode": { + "rules": [{ + "format": "string" + }], + "title": "取压方式", + "label": "取压方式" + }, + "dPipeType": { + "rules": [{ + "format": "string" + }], + "title": "管道类型", + "label": "管道类型" + }, + "dPipeD": { + "rules": [{ + "format": "string", + "required": true, + "errorMessage": '管径未输入' + }], + "title": "管道内径", + "label": "管道内径" + }, + "dLenUnit": { + "rules": [{ + "format": "string" + }], + "title": "长度单位", + "label": "长度单位" + }, + "dPipeDtemp": { + "rules": [{ + "format": "string" + }], + "title": "管道内径参考温度", + "label": "管道内径参考温度" + }, + "dPileDtempU": { + "rules": [{ + "format": "string" + }], + "title": "温度单位", + "label": "温度单位" + }, + "dPipeMaterial": { + "rules": [{ + "format": "string" + }], + "title": "管道材料", + "label": "管道材料" + }, + "dOrificeD": { + "rules": [{ + "format": "string", + "required": true, + "errorMessage": '孔径未输入' + }], + "title": "孔板孔径", + "label": "孔板孔径" + }, + "dOrificeUnit": { + "rules": [{ + "format": "string" + }], + "title": "长度单位", + "label": "长度单位" + }, + "dOrificeDtemp": { + "rules": [{ + "format": "string" + }], + "title": "孔板内径参考温度", + "label": "孔板内径参考温度" + }, + "dOrificeDtempUnit": { + "rules": [{ + "format": "string" + }], + "title": "温度单位", + "label": "温度单位" + }, + "dOrificeMaterial": { + "rules": [{ + "format": "string" + }], + "title": "孔板材料", + "label": "孔板材料" + }, + "dOrificeSharpness": { + "rules": [{ + "format": "string" + }], + "title": "锐利度系数计算方法", + "label": "锐利度系数计算方法" + }, + "dOrificeRk": { + "rules": [{ + "format": "string" + }], + "title": "孔板入口圆弧半径", + "label": "孔板入口圆弧半径" + }, + "dOrificeRkLenU": { + "rules": [{ + "format": "string" + }], + "title": "长度单位", + "label": "长度单位" + }, + "dPf": { + "rules": [{ + "format": "string", + "required": true, + "errorMessage": '工况压力未输入' + }], + "title": "输入压力", + "label": "输入压力" + }, + "dPfUnit": { + "rules": [{ + "format": "string" + }], + "title": "压力单位", + "label": "压力单位" + }, + "dPfType": { + "rules": [{ + "format": "string" + }], + "title": "压力类型", + "label": "压力类型" + }, + "dTf": { + "rules": [{ + "format": "string", + "required": true, + "errorMessage": '工况温度未输入' + }], + "title": "输入温度", + "label": "输入温度" + }, + "dTfUnit": { + "rules": [{ + "format": "string" + }], + "title": "温度单位", + "label": "温度单位" + }, + "dDp": { + "rules": [{ + "format": "string", + "required": true, + "errorMessage": '差压未输入' + }], + "title": "输入差压", + "label": "输入差压" + }, + "dDpUnit": { + "rules": [{ + "format": "string" + }], + "title": "压力单位", + "label": "压力单位" + }, + "dVFlowUnit": { + "rules": [{ + "format": "string" + }], + "title": "体积流量单位", + "label": "体积流量单位" + }, + "dMFlowUnit": { + "rules": [{ + "format": "string" + }], + "title": "质量流量单位", + "label": "质量流量单位" + }, + "dEFlowUnit": { + "rules": [{ + "format": "string" + }], + "title": "能量流量单位", + "label": "能量流量单位" + }, + + "dCdCalMethod": { + "rules": [{ + "format": "string" + }], + "title": "流出系数计算方法", + "label": "流出系数计算方法" + }, + "dMeterFactor": { + "rules": [{ + "format": "string", + "required": true, + "errorMessage": '仪表系数未输入' + }], + "title": "仪表系数", + "label": "仪表系数" + }, + "dPulseNum": { + "rules": [{ + "format": "string", + "required": true, + "errorMessage": '脉冲数未输入' + }], + "title": "脉冲数", + "label": "脉冲数" + }, + "dVFlowMax": { + "rules": [{ + "format": "string" + }], + "title": "最大体积流量", + "label": "最大体积流量" + }, + "dVFlowMin": { + "rules": [{ + "format": "string" + }], + "title": "最小体积流量", + "label": "最小体积流量" + }, + "dVFlowCon": { + "rules": [{ + "format": "string" + }], + "title": "常用流量", + "label": "常用流量" + }, + "dPfRangeMin": { + "rules": [{ + "format": "string" + }], + "title": "压力量程", + "label": "压力量程" + }, + "dPfRangeMax": { + "rules": [{ + "format": "string" + }], + "title": "压力量程", + "label": "压力量程" + }, + "dDpRangeMin": { + "rules": [{ + "format": "string" + }], + "title": "差压量程", + "label": "差压量程" + }, + "dDpRangeMax": { + "rules": [{ + "format": "string" + }], + "title": "差压量程", + "label": "差压量程" + }, + "dTfRangeMin": { + "rules": [{ + "format": "string" + }], + "title": "温度计量程", + "label": "温度计量程" + }, + "dTfRangeMax": { + "rules": [{ + "format": "string" + }], + "title": "温度计量程", + "label": "温度计量程" + }, + + "updateTime": { + "rules": [{ + "format": "datetime" + }], + "title": "更新时间", + "label": "更新时间" + }, + "createTime": { + "rules": [{ + "format": "datetime" + }], + "title": "创建时间", + "label": "创建时间" + } +} + +const enumConverter = {} + +function filterToWhere(filter, command) { + let where = {} + for (let field in filter) { + let { + type, + value + } = filter[field] + switch (type) { + case "search": + if (typeof value === 'string' && value.length) { + where[field] = new RegExp(value) + } + break; + case "select": + if (value.length) { + let selectValue = [] + for (let s of value) { + selectValue.push(command.eq(s)) + } + where[field] = command.or(selectValue) + } + break; + case "range": + if (value.length) { + let gt = value[0] + let lt = value[1] + where[field] = command.and([command.gte(gt), command.lte(lt)]) + } + break; + case "date": + if (value.length) { + let [s, e] = value + let startDate = new Date(s) + let endDate = new Date(e) + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + case "timestamp": + if (value.length) { + let [startDate, endDate] = value + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + } + } + return where +} + +export { + validator, + enumConverter, + filterToWhere +} \ No newline at end of file diff --git a/js_sdk/validator/ngTools_NGComponents.js b/js_sdk/validator/ngTools_NGComponents.js new file mode 100644 index 0000000..f4b6d6c --- /dev/null +++ b/js_sdk/validator/ngTools_NGComponents.js @@ -0,0 +1,295 @@ +// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema + + +const validator = { + "samplingDate": { + "rules": [{ + "format": "date" + }], + "title": "取样日期", + "defaultValue": { + "$env": "now" + }, + "label": "取样日期" + }, + "assayDate": { + "rules": [{ + "format": "date" + }], + "title": "分析日期", + "defaultValue": { + "$env": "now" + }, + "label": "分析日期" + }, + "samplingLocation": { + "rules": [{ + "format": "array" + }, + { + "arrayType": "string" + } + ], + "title": "取样地点", + "label": "取样地点" + }, + "sampleNumber": { + "rules": [{ + "format": "string" + }], + "title": "样品编号", + "label": "样品编号" + }, + "NG_C1": { + "rules": [{ + "format": "float" + }], + "title": "甲烷C1", + "defaultValue": 0, + "label": "甲烷C1" + }, + "NG_N2": { + "rules": [{ + "format": "float" + }], + "title": "氮气N2", + "defaultValue": 0, + "label": "氮气N2" + }, + "NG_CO2": { + "rules": [{ + "format": "float" + }], + "title": "二氧化碳CO2", + "defaultValue": 0, + "label": "二氧化碳CO2" + }, + "NG_C2": { + "rules": [{ + "format": "float" + }], + "title": "乙烷C2", + "defaultValue": 0, + "label": "乙烷C2" + }, + "NG_C3": { + "rules": [{ + "format": "float" + }], + "title": "丙烷C3", + "defaultValue": 0, + "label": "丙烷C3" + }, + "NG_H2O": { + "rules": [{ + "format": "float" + }], + "title": "水H2O", + "defaultValue": 0, + "label": "水H2O" + }, + "NG_H2S": { + "rules": [{ + "format": "float" + }], + "title": "硫化氢H2S", + "defaultValue": 0, + "label": "硫化氢H2S" + }, + "NG_H2": { + "rules": [{ + "format": "float" + }], + "title": "氢气H2", + "defaultValue": 0, + "label": "氢气H2" + }, + "NG_CO": { + "rules": [{ + "format": "float" + }], + "title": "一氧化碳CO", + "defaultValue": 0, + "label": "一氧化碳CO" + }, + "NG_O2": { + "rules": [{ + "format": "float" + }], + "title": "氧气O2", + "defaultValue": 0, + "label": "氧气O2" + }, + "NG_iC4": { + "rules": [{ + "format": "float" + }], + "title": "异丁烷iC4", + "defaultValue": 0, + "label": "异丁烷iC4" + }, + "NG_nC4": { + "rules": [{ + "format": "float" + }], + "title": "正丁烷nC4", + "defaultValue": 0, + "label": "正丁烷nC4" + }, + "NG_iC5": { + "rules": [{ + "format": "float" + }], + "title": "异戊烷iC5", + "defaultValue": 0, + "label": "异戊烷iC5" + }, + "NG_nC5": { + "rules": [{ + "format": "float" + }], + "title": "正戊烷nC5", + "defaultValue": 0, + "label": "正戊烷nC5" + }, + "NG_C6": { + "rules": [{ + "format": "float" + }], + "title": "己烷C6", + "defaultValue": 0, + "label": "己烷C6" + }, + "NG_C7": { + "rules": [{ + "format": "float" + }], + "title": "庚烷C7", + "defaultValue": 0, + "label": "庚烷C7" + }, + "NG_C8": { + "rules": [{ + "format": "float" + }], + "title": "辛烷C8", + "defaultValue": 0, + "label": "辛烷C8" + }, + "NG_C9": { + "rules": [{ + "format": "float" + }], + "title": "壬烷C9", + "defaultValue": 0, + "label": "壬烷C9" + }, + "NG_C10": { + "rules": [{ + "format": "float" + }], + "title": "癸烷C10", + "defaultValue": 0, + "label": "癸烷C10" + }, + "NG_He": { + "rules": [{ + "format": "float" + }], + "title": "氦气He", + "defaultValue": 0, + "label": "氦气He" + }, + "NG_Ar": { + "rules": [{ + "format": "float" + }], + "title": "氩气Ar", + "defaultValue": 0, + "label": "氩气Ar" + }, + // "NG_SUM": { + // "rules": [{ + // "format": "float", + // "required": true, + // "errorMessage": '组分输入不全' + // }, + // { + // validateFunction: function(rule, value, data, callback) { + // console.log(value) + // console.log(data) + // if (Math.abs(parseFloat(value) - 100) > 0.0001) { + // callback('组分之和不等于100%') + // } + // return true + // } + // } + // ], + // "title": "合计", + // "defaultValue": 0, + // "label": "合计" + // }, + "createTime": { + "rules": [{ + "format": "datetime" + }], + "title": "创建时间", + "label": "创建时间" + } +} + +const enumConverter = {} + +function filterToWhere(filter, command) { + let where = {} + for (let field in filter) { + let { + type, + value + } = filter[field] + switch (type) { + case "search": + if (typeof value === 'string' && value.length) { + where[field] = new RegExp(value) + } + break; + case "select": + if (value.length) { + let selectValue = [] + for (let s of value) { + selectValue.push(command.eq(s)) + } + where[field] = command.or(selectValue) + } + break; + case "range": + if (value.length) { + let gt = value[0] + let lt = value[1] + where[field] = command.and([command.gte(gt), command.lte(lt)]) + } + break; + case "date": + if (value.length) { + let [s, e] = value + let startDate = new Date(s) + let endDate = new Date(e) + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + case "timestamp": + if (value.length) { + let [startDate, endDate] = value + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + } + } + return where +} + +export { + validator, + enumConverter, + filterToWhere +} \ No newline at end of file diff --git a/js_sdk/validator/ngTools_NGPar.js b/js_sdk/validator/ngTools_NGPar.js new file mode 100644 index 0000000..bb7fd2b --- /dev/null +++ b/js_sdk/validator/ngTools_NGPar.js @@ -0,0 +1,558 @@ +// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema + + +const validator = { + "adMixture": { + "rules": [ + { + "format": "string" + } + ], + "title": "摩尔组成", + "label": "摩尔组成" + }, + "adMixtureV": { + "rules": [ + { + "format": "string" + } + ], + "title": "体积组成", + "label": "体积组成" + }, + "adMixtureD": { + "rules": [ + { + "format": "string" + } + ], + "title": "质量组成", + "label": "质量组成" + }, + "dCbtj": { + "rules": [ + { + "format": "string" + } + ], + "title": "参比条件", + "label": "参比条件" + }, + "dPb": { + "rules": [ + { + "format": "string" + } + ], + "title": "参比压力", + "label": "参比压力" + }, + "dTb": { + "rules": [ + { + "format": "string" + } + ], + "title": "参比温度", + "label": "参比温度" + }, + "dPf": { + "rules": [ + { + "format": "string" + } + ], + "title": "绝对压力", + "label": "绝对压力" + }, + "dTf": { + "rules": [ + { + "format": "string" + } + ], + "title": "工况温度", + "label": "工况温度" + }, + "dMrx": { + "rules": [ + { + "format": "string" + } + ], + "title": "分子量", + "label": "分子量" + }, + "dZb": { + "rules": [ + { + "format": "string" + } + ], + "title": "标况压缩因子", + "label": "标况压缩因子" + }, + "dZf": { + "rules": [ + { + "format": "string" + } + ], + "title": "工况压缩因子", + "label": "工况压缩因子" + }, + "dFpv": { + "rules": [ + { + "format": "string" + } + ], + "title": "超压缩系数", + "label": "超压缩系数" + }, + "dDb": { + "rules": [ + { + "format": "string" + } + ], + "title": "标况摩尔密度", + "label": "标况摩尔密度" + }, + "dDf": { + "rules": [ + { + "format": "string" + } + ], + "title": "工况摩尔密度", + "label": "工况摩尔密度" + }, + "dRhob": { + "rules": [ + { + "format": "string" + } + ], + "title": "标况质量密度", + "label": "标况质量密度" + }, + "dRhof": { + "rules": [ + { + "format": "string" + } + ], + "title": "工况质量密度", + "label": "工况质量密度" + }, + "dRD_Ideal": { + "rules": [ + { + "format": "string" + } + ], + "title": "理想气体的相对密度", + "label": "理想气体的相对密度" + }, + "dRD_Real": { + "rules": [ + { + "format": "string" + } + ], + "title": "真实气体的相对密度", + "label": "真实气体的相对密度" + }, + "dHo": { + "rules": [ + { + "format": "string" + } + ], + "title": "理想气体的比焓", + "label": "理想气体的比焓" + }, + "dH": { + "rules": [ + { + "format": "string" + } + ], + "title": "真实气体的焓", + "label": "真实气体的焓" + }, + "dS": { + "rules": [ + { + "format": "string" + } + ], + "title": "真实气体的熵", + "label": "真实气体的熵" + }, + "dCpi": { + "rules": [ + { + "format": "string" + } + ], + "title": "理想气体定压热容", + "label": "理想气体定压热容" + }, + "dCp": { + "rules": [ + { + "format": "string" + } + ], + "title": "定压热容", + "label": "定压热容" + }, + "dCv": { + "rules": [ + { + "format": "string" + } + ], + "title": "定容积热容", + "label": "定容积热容" + }, + "dk": { + "rules": [ + { + "format": "string" + } + ], + "title": "比热比", + "label": "比热比" + }, + "dKappa": { + "rules": [ + { + "format": "string" + } + ], + "title": "等熵指数", + "label": "等熵指数" + }, + "dSOS": { + "rules": [ + { + "format": "string" + } + ], + "title": "声速", + "label": "声速" + }, + "dCstar": { + "rules": [ + { + "format": "string" + } + ], + "title": "临界流函数", + "label": "临界流函数" + }, + "dHhvMol": { + "rules": [ + { + "format": "string" + } + ], + "title": "摩尔高位发热量", + "label": "摩尔高位发热量" + }, + "dLhvMol": { + "rules": [ + { + "format": "string" + } + ], + "title": "摩尔低位发热量", + "label": "摩尔低位发热量" + }, + "dHhvv": { + "rules": [ + { + "format": "string" + } + ], + "title": "体积高位发热量", + "label": "体积高位发热量" + }, + "dLhvv": { + "rules": [ + { + "format": "string" + } + ], + "title": "体积低位发热量", + "label": "体积低位发热量" + }, + "dHhvm": { + "rules": [ + { + "format": "string" + } + ], + "title": "质量高位发热量", + "label": "质量高位发热量" + }, + "dLhvm": { + "rules": [ + { + "format": "string" + } + ], + "title": "质量地位发热量", + "label": "质量地位发热量" + }, + "dZb11062": { + "rules": [ + { + "format": "string" + } + ], + "title": "标况压缩因子", + "label": "标况压缩因子" + }, + "dRhob11062": { + "rules": [ + { + "format": "string" + } + ], + "title": "标况质量密度", + "label": "标况质量密度" + }, + "dRhof11062": { + "rules": [ + { + "format": "string" + } + ], + "title": "工况质量密度", + "label": "工况质量密度" + }, + "dRD_Ideal11062": { + "rules": [ + { + "format": "string" + } + ], + "title": "理想气体的相对密度", + "label": "理想气体的相对密度" + }, + "dRD_Real11062": { + "rules": [ + { + "format": "string" + } + ], + "title": "真实气体的相对密度", + "label": "真实气体的相对密度" + }, + "dWobbeIndex": { + "rules": [ + { + "format": "string" + } + ], + "title": "真实气体的沃泊指数", + "label": "真实气体的沃泊指数" + }, + "Pc": { + "rules": [ + { + "format": "string" + } + ], + "title": "临界压力", + "label": "临界压力" + }, + "TC": { + "rules": [ + { + "format": "string" + } + ], + "title": "临界温度", + "label": "临界温度" + }, + "Bzsx": { + "rules": [ + { + "format": "string" + } + ], + "title": "爆炸上限", + "label": "爆炸上限" + }, + "Bzxx": { + "rules": [ + { + "format": "string" + } + ], + "title": "爆炸下限", + "label": "爆炸下限" + }, + "TotalC": { + "rules": [ + { + "format": "string" + } + ], + "title": "总炭含量", + "label": "总炭含量" + }, + "C2": { + "rules": [ + { + "format": "string" + } + ], + "title": "C2组分含量", + "label": "C2组分含量" + }, + "C2j": { + "rules": [ + { + "format": "string" + } + ], + "title": "C2以上组分含量", + "label": "C2以上组分含量" + }, + "C3j": { + "rules": [ + { + "format": "string" + } + ], + "title": "C3以上组分含量", + "label": "C3以上组分含量" + }, + "C4j": { + "rules": [ + { + "format": "string" + } + ], + "title": "C4以上组分含量", + "label": "C4以上组分含量" + }, + "C5j": { + "rules": [ + { + "format": "string" + } + ], + "title": "C5以上组分含量", + "label": "C5以上组分含量" + }, + "C6j": { + "rules": [ + { + "format": "string" + } + ], + "title": "C6以上组分含量", + "label": "C6以上组分含量" + }, + "C3C4": { + "rules": [ + { + "format": "string" + } + ], + "title": "C3C4组分含量", + "label": "C3C4组分含量" + }, + "createBy": { + "rules": [ + { + "format": "string" + } + ], + "title": "创建人", + "label": "创建人" + }, + "updateBy": { + "rules": [ + { + "format": "string" + } + ], + "title": "更新人", + "label": "更新人" + }, + "createTime": { + "rules": [ + { + "format": "datetime" + } + ], + "title": "创建时间", + "label": "创建时间" + }, + "updateTime": { + "rules": [ + { + "format": "datetime" + } + ], + "title": "更新时间", + "label": "更新时间" + } +} + +const enumConverter = {} + +function filterToWhere(filter, command) { + let where = {} + for (let field in filter) { + let { type, value } = filter[field] + switch (type) { + case "search": + if (typeof value === 'string' && value.length) { + where[field] = new RegExp(value) + } + break; + case "select": + if (value.length) { + let selectValue = [] + for (let s of value) { + selectValue.push(command.eq(s)) + } + where[field] = command.or(selectValue) + } + break; + case "range": + if (value.length) { + let gt = value[0] + let lt = value[1] + where[field] = command.and([command.gte(gt), command.lte(lt)]) + } + break; + case "date": + if (value.length) { + let [s, e] = value + let startDate = new Date(s) + let endDate = new Date(e) + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + case "timestamp": + if (value.length) { + let [startDate, endDate] = value + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + } + } + return where +} + +export { validator, enumConverter, filterToWhere } diff --git a/js_sdk/validator/ngTools_SamplingLocation.js b/js_sdk/validator/ngTools_SamplingLocation.js new file mode 100644 index 0000000..801d6a7 --- /dev/null +++ b/js_sdk/validator/ngTools_SamplingLocation.js @@ -0,0 +1,72 @@ +// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema + + +const validator = { + "samplingLocation": { + "rules": [ + { + "format": "string" + } + ], + "title": "取样地点", + "label": "取样地点" + }, + "departName": { + "rules": [ + { + "format": "string" + } + ], + "title": "单位名称", + "label": "单位名称" + } +} + +const enumConverter = {} + +function filterToWhere(filter, command) { + let where = {} + for (let field in filter) { + let { type, value } = filter[field] + switch (type) { + case "search": + if (typeof value === 'string' && value.length) { + where[field] = new RegExp(value) + } + break; + case "select": + if (value.length) { + let selectValue = [] + for (let s of value) { + selectValue.push(command.eq(s)) + } + where[field] = command.or(selectValue) + } + break; + case "range": + if (value.length) { + let gt = value[0] + let lt = value[1] + where[field] = command.and([command.gte(gt), command.lte(lt)]) + } + break; + case "date": + if (value.length) { + let [s, e] = value + let startDate = new Date(s) + let endDate = new Date(e) + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + case "timestamp": + if (value.length) { + let [startDate, endDate] = value + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + } + } + return where +} + +export { validator, enumConverter, filterToWhere } diff --git a/js_sdk/validator/ngTools_depart.js b/js_sdk/validator/ngTools_depart.js new file mode 100644 index 0000000..2f62b72 --- /dev/null +++ b/js_sdk/validator/ngTools_depart.js @@ -0,0 +1,102 @@ +// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema + + +const validator = { + "parent_id": { + "rules": [ + { + "format": "string" + } + ] + }, + "depart_name": { + "rules": [ + { + "format": "string", + "required": true, + "errorMessage": '单位名称未输入' + } + ], + "title": "部门名称", + "label": "部门名称" + }, + "level": { + "rules": [ + { + "format": "int" + } + ] + }, + "sort": { + "rules": [ + { + "format": "int" + } + ], + "title": "显示顺序", + "label": "显示顺序" + }, + "manager_uid": { + "rules": [ + { + "format": "string" + } + ] + }, + "status": { + "rules": [ + { + "format": "int" + } + ] + } +} + +const enumConverter = {} + +function filterToWhere(filter, command) { + let where = {} + for (let field in filter) { + let { type, value } = filter[field] + switch (type) { + case "search": + if (typeof value === 'string' && value.length) { + where[field] = new RegExp(value) + } + break; + case "select": + if (value.length) { + let selectValue = [] + for (let s of value) { + selectValue.push(command.eq(s)) + } + where[field] = command.or(selectValue) + } + break; + case "range": + if (value.length) { + let gt = value[0] + let lt = value[1] + where[field] = command.and([command.gte(gt), command.lte(lt)]) + } + break; + case "date": + if (value.length) { + let [s, e] = value + let startDate = new Date(s) + let endDate = new Date(e) + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + case "timestamp": + if (value.length) { + let [startDate, endDate] = value + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + } + } + return where +} + +export { validator, enumConverter, filterToWhere } diff --git a/js_sdk/validator/ngtools-categories.js b/js_sdk/validator/ngtools-categories.js new file mode 100644 index 0000000..1ed2a8f --- /dev/null +++ b/js_sdk/validator/ngtools-categories.js @@ -0,0 +1,131 @@ +// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema + + +const validator = { + "parent_id": { + "rules": [ + { + "format": "string" + } + ] + }, + "name": { + "rules": [ + { + "required": true + }, + { + "format": "string" + } + ], + "title": "类别名称", + "label": "类别名称" + }, + "icon": { + "rules": [ + { + "format": "string" + }, + { + "pattern": "^(http://|https://|/|./|@/)\\S" + } + ], + "title": "图标地址", + "label": "图标地址" + }, + "sort": { + "rules": [ + { + "format": "int" + } + ], + "title": "排序", + "label": "排序" + }, + "description": { + "rules": [ + { + "format": "string" + } + ], + "title": "类别描述", + "label": "类别描述" + }, + "is_hot_show": { + "rules": [ + { + "format": "bool" + } + ], + "title": "加入热门显示", + "label": "加入热门显示" + }, + "is_index_show": { + "rules": [ + { + "format": "bool" + } + ], + "title": "首页显示", + "label": "首页显示" + }, + "create_date": { + "rules": [ + { + "format": "timestamp" + } + ], + "defaultValue": { + "$env": "now" + } + } +} + +const enumConverter = {} + +function filterToWhere(filter, command) { + let where = {} + for (let field in filter) { + let { type, value } = filter[field] + switch (type) { + case "search": + if (typeof value === 'string' && value.length) { + where[field] = new RegExp(value) + } + break; + case "select": + if (value.length) { + let selectValue = [] + for (let s of value) { + selectValue.push(command.eq(s)) + } + where[field] = command.or(selectValue) + } + break; + case "range": + if (value.length) { + let gt = value[0] + let lt = value[1] + where[field] = command.and([command.gte(gt), command.lte(lt)]) + } + break; + case "date": + if (value.length) { + let [s, e] = value + let startDate = new Date(s) + let endDate = new Date(e) + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + case "timestamp": + if (value.length) { + let [startDate, endDate] = value + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + } + } + return where +} + +export { validator, enumConverter, filterToWhere } diff --git a/js_sdk/validator/ngtools-goods.js b/js_sdk/validator/ngtools-goods.js new file mode 100644 index 0000000..09c8822 --- /dev/null +++ b/js_sdk/validator/ngtools-goods.js @@ -0,0 +1,257 @@ +// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema + + +const validator = { + "category_id": { + "rules": [ + { + "format": "string" + } + ] + }, + "goods_sn": { + "rules": [ + { + "required": true + }, + { + "format": "string" + } + ], + "title": "货号", + "label": "货号" + }, + "name": { + "rules": [ + { + "required": true + }, + { + "format": "string" + } + ], + "title": "名称", + "label": "名称" + }, + "keywords": { + "rules": [ + { + "format": "string" + } + ], + "title": "关键字", + "label": "关键字" + }, + "goods_desc": { + "rules": [ + { + "format": "string" + } + ], + "title": "详细描述", + "label": "详细描述" + }, + "goods_thumb": { + "rules": [ + { + "format": "string" + }, + { + "pattern": "^(http://|https://|/|./|@/)\\S" + } + ], + "title": "缩略图地址", + "label": "缩略图地址" + }, + "goods_banner_imgs": { + "rules": [ + { + "format": "array" + } + ] + }, + "remain_count": { + "rules": [ + { + "required": true + }, + { + "format": "int" + } + ], + "title": "库存数量", + "label": "库存数量" + }, + "month_sell_count": { + "rules": [ + { + "required": true + }, + { + "format": "int" + } + ] + }, + "total_sell_count": { + "rules": [ + { + "required": true + }, + { + "format": "int" + } + ] + }, + "comment_count": { + "rules": [ + { + "required": true + }, + { + "format": "int" + } + ] + }, + "is_real": { + "rules": [ + { + "required": true + }, + { + "format": "bool" + } + ], + "title": "是否为实物", + "label": "是否为实物" + }, + "is_on_sale": { + "rules": [ + { + "required": true + }, + { + "format": "bool" + } + ], + "title": "是否上架", + "label": "是否上架" + }, + "is_alone_sale": { + "rules": [ + { + "required": true + }, + { + "format": "bool" + } + ] + }, + "is_best": { + "rules": [ + { + "required": true + }, + { + "format": "bool" + } + ] + }, + "is_new": { + "rules": [ + { + "required": true + }, + { + "format": "bool" + } + ], + "title": "是否新品", + "label": "是否新品" + }, + "is_hot": { + "rules": [ + { + "required": true + }, + { + "format": "bool" + } + ] + }, + "add_date": { + "rules": [ + { + "format": "timestamp" + } + ], + "defaultValue": { + "$env": "now" + } + }, + "last_modify_date": { + "rules": [ + { + "format": "timestamp" + } + ], + "defaultValue": { + "$env": "now" + } + }, + "seller_note": { + "rules": [ + { + "format": "string" + } + ] + } +} + +const enumConverter = {} + +function filterToWhere(filter, command) { + let where = {} + for (let field in filter) { + let { type, value } = filter[field] + switch (type) { + case "search": + if (typeof value === 'string' && value.length) { + where[field] = new RegExp(value) + } + break; + case "select": + if (value.length) { + let selectValue = [] + for (let s of value) { + selectValue.push(command.eq(s)) + } + where[field] = command.or(selectValue) + } + break; + case "range": + if (value.length) { + let gt = value[0] + let lt = value[1] + where[field] = command.and([command.gte(gt), command.lte(lt)]) + } + break; + case "date": + if (value.length) { + let [s, e] = value + let startDate = new Date(s) + let endDate = new Date(e) + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + case "timestamp": + if (value.length) { + let [startDate, endDate] = value + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + } + } + return where +} + +export { validator, enumConverter, filterToWhere } diff --git a/js_sdk/validator/ngtools_information.js b/js_sdk/validator/ngtools_information.js new file mode 100644 index 0000000..a4f054e --- /dev/null +++ b/js_sdk/validator/ngtools_information.js @@ -0,0 +1,129 @@ +// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema + + +const validator = { + "infoName": { + "rules": [ + { + "required": true + }, + { + "format": "string" + } + ], + "title": "资料名称", + "label": "资料名称" + }, + "infomation": { + "rules": [ + { + "format": "string" + } + ], + "title": "资料内容", + "label": "资料内容" + }, + "infoSouce": { + "rules": [ + { + "format": "string" + } + ], + "title": "资料来源", + "label": "资料来源" + }, + "infoType": { + "rules": [ + { + "format": "string" + } + ], + "title": "资料类型", + "label": "资料类型" + }, + "createTime": { + "rules": [ + { + "format": "datetime" + } + ], + "title": "创建时间", + "label": "创建时间" + }, + "createBy": { + "rules": [ + { + "format": "string" + } + ], + "title": "创建人", + "label": "创建人" + }, + "updateTime": { + "rules": [ + { + "format": "datetime" + } + ], + "title": "更新时间", + "label": "更新时间" + }, + "updateBy": { + "rules": [ + { + "format": "string" + } + ], + "title": "更新人", + "label": "更新人" + } +} + +const enumConverter = {} + +function filterToWhere(filter, command) { + let where = {} + for (let field in filter) { + let { type, value } = filter[field] + switch (type) { + case "search": + if (typeof value === 'string' && value.length) { + where[field] = new RegExp(value) + } + break; + case "select": + if (value.length) { + let selectValue = [] + for (let s of value) { + selectValue.push(command.eq(s)) + } + where[field] = command.or(selectValue) + } + break; + case "range": + if (value.length) { + let gt = value[0] + let lt = value[1] + where[field] = command.and([command.gte(gt), command.lte(lt)]) + } + break; + case "date": + if (value.length) { + let [s, e] = value + let startDate = new Date(s) + let endDate = new Date(e) + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + case "timestamp": + if (value.length) { + let [startDate, endDate] = value + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + } + } + return where +} + +export { validator, enumConverter, filterToWhere } diff --git a/js_sdk/validator/opendb-banner.js b/js_sdk/validator/opendb-banner.js new file mode 100644 index 0000000..59aec5a --- /dev/null +++ b/js_sdk/validator/opendb-banner.js @@ -0,0 +1,130 @@ +// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema + + +const validator = { + "bannerfile": { + "rules": [ + { + "required": true + }, + { + "format": "file" + } + ], + "title": "图片文件", + "label": "图片文件" + }, + "open_url": { + "rules": [ + { + "format": "string" + }, + { + "format": "url" + }, + { + "pattern": "^(http://|https://|/|./|@/)\\S" + } + ], + "title": "点击目标地址", + "label": "点击目标地址" + }, + "title": { + "rules": [ + { + "format": "string" + }, + { + "maxLength": 20 + } + ], + "title": "标题", + "label": "标题" + }, + "sort": { + "rules": [ + { + "format": "int" + } + ], + "title": "排序", + "label": "排序" + }, + "category_id": { + "rules": [ + { + "format": "string" + } + ], + "title": "分类id", + "label": "分类id" + }, + "status": { + "rules": [ + { + "format": "bool" + } + ], + "title": "生效状态", + "defaultValue": true, + "label": "生效状态" + }, + "description": { + "rules": [ + { + "format": "string" + } + ], + "title": "备注", + "label": "备注" + } +} + +const enumConverter = {} + +function filterToWhere(filter, command) { + let where = {} + for (let field in filter) { + let { type, value } = filter[field] + switch (type) { + case "search": + if (typeof value === 'string' && value.length) { + where[field] = new RegExp(value) + } + break; + case "select": + if (value.length) { + let selectValue = [] + for (let s of value) { + selectValue.push(command.eq(s)) + } + where[field] = command.or(selectValue) + } + break; + case "range": + if (value.length) { + let gt = value[0] + let lt = value[1] + where[field] = command.and([command.gte(gt), command.lte(lt)]) + } + break; + case "date": + if (value.length) { + let [s, e] = value + let startDate = new Date(s) + let endDate = new Date(e) + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + case "timestamp": + if (value.length) { + let [startDate, endDate] = value + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + } + } + return where +} + +export { validator, enumConverter, filterToWhere } diff --git a/js_sdk/validator/uni-id-users.js b/js_sdk/validator/uni-id-users.js new file mode 100644 index 0000000..9d1d33e --- /dev/null +++ b/js_sdk/validator/uni-id-users.js @@ -0,0 +1,354 @@ +// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema + + +const validator = { + "username": { + "rules": [ + { + "format": "string" + } + ], + "title": "用户名", + "label": "用户名" + }, + "password_secret_version": { + "rules": [ + { + "format": "int" + } + ], + "title": "passwordSecret", + "label": "passwordSecret" + }, + "nickname": { + "rules": [ + { + "format": "string" + } + ], + "title": "昵称", + "label": "昵称" + }, + "gender": { + "rules": [ + { + "format": "int" + }, + { + "range": [ + { + "text": "未知", + "value": 0 + }, + { + "text": "男", + "value": 1 + }, + { + "text": "女", + "value": 2 + } + ] + } + ], + "title": "性别", + "defaultValue": 0, + "label": "性别" + }, + "status": { + "rules": [ + { + "format": "int" + }, + { + "range": [ + { + "text": "正常", + "value": 0 + }, + { + "text": "禁用", + "value": 1 + }, + { + "text": "审核中", + "value": 2 + }, + { + "text": "审核拒绝", + "value": 3 + } + ] + } + ], + "title": "用户状态", + "defaultValue": 0, + "label": "用户状态" + }, + "mobile": { + "rules": [ + { + "format": "string" + }, + { + "pattern": "^\\+?[0-9-]{3,20}$" + } + ], + "title": "手机号码", + "label": "手机号码" + }, + "mobile_confirmed": { + "rules": [ + { + "format": "int" + }, + { + "range": [ + { + "text": "未验证", + "value": 0 + }, + { + "text": "已验证", + "value": 1 + } + ] + } + ], + "title": "手机号验证状态", + "defaultValue": 0, + "label": "手机号验证状态" + }, + "email": { + "rules": [ + { + "format": "string" + }, + { + "format": "email" + } + ], + "title": "邮箱", + "label": "邮箱" + }, + "email_confirmed": { + "rules": [ + { + "format": "int" + }, + { + "range": [ + { + "text": "未验证", + "value": 0 + }, + { + "text": "已验证", + "value": 1 + } + ] + } + ], + "title": "邮箱验证状态", + "defaultValue": 0, + "label": "邮箱验证状态" + }, + "avatar": { + "rules": [ + { + "format": "string" + } + ], + "title": "头像地址", + "label": "头像地址" + }, + "avatar_file": { + "rules": [ + { + "format": "file" + } + ], + "title": "头像文件", + "label": "头像文件" + }, + "d_ids": { + "rules": [ + { + "format": "array" + } + ], + "title": "部门", + "label": "部门" + }, + "e_ids": { + "rules": [ + { + "format": "array" + } + ], + "title": "企业", + "label": "企业" + }, + "wx_unionid": { + "rules": [ + { + "format": "string" + } + ] + }, + "ali_openid": { + "rules": [ + { + "format": "string" + } + ] + }, + "apple_openid": { + "rules": [ + { + "format": "string" + } + ] + }, + "dcloud_appid": { + "rules": [ + { + "format": "array" + } + ] + }, + "comment": { + "rules": [ + { + "format": "string" + } + ], + "title": "备注", + "label": "备注" + }, + "score": { + "rules": [ + { + "format": "int" + } + ] + }, + "last_login_date": { + "rules": [ + { + "format": "timestamp" + } + ] + }, + "last_login_ip": { + "rules": [ + { + "format": "string" + } + ] + }, + "token": { + "rules": [ + { + "format": "array" + } + ] + }, + "inviter_uid": { + "rules": [ + { + "format": "array" + } + ] + }, + "invite_time": { + "rules": [ + { + "format": "timestamp" + } + ] + }, + "my_invite_code": { + "rules": [ + { + "format": "string" + } + ] + }, + "identities": { + "rules": [ + { + "format": "array" + } + ] + } +} + +const enumConverter = { + "gender_valuetotext": { + "0": "未知", + "1": "男", + "2": "女" + }, + "status_valuetotext": { + "0": "正常", + "1": "禁用", + "2": "审核中", + "3": "审核拒绝" + }, + "mobile_confirmed_valuetotext": { + "0": "未验证", + "1": "已验证" + }, + "email_confirmed_valuetotext": { + "0": "未验证", + "1": "已验证" + } +} + +function filterToWhere(filter, command) { + let where = {} + for (let field in filter) { + let { type, value } = filter[field] + switch (type) { + case "search": + if (typeof value === 'string' && value.length) { + where[field] = new RegExp(value) + } + break; + case "select": + if (value.length) { + let selectValue = [] + for (let s of value) { + selectValue.push(command.eq(s)) + } + where[field] = command.or(selectValue) + } + break; + case "range": + if (value.length) { + let gt = value[0] + let lt = value[1] + where[field] = command.and([command.gte(gt), command.lte(lt)]) + } + break; + case "date": + if (value.length) { + let [s, e] = value + let startDate = new Date(s) + let endDate = new Date(e) + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + case "timestamp": + if (value.length) { + let [startDate, endDate] = value + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + } + } + return where +} + +export { validator, enumConverter, filterToWhere } diff --git a/lang/en.js b/lang/en.js new file mode 100644 index 0000000..0deb975 --- /dev/null +++ b/lang/en.js @@ -0,0 +1,191 @@ +export default { + tabbar:'List,Grid,contacts,Mine', + agreementsTitle:'User service agreement,Privacy policy', + common: { + wechatFriends: "friends", + wechatBbs: "bbs", + weibo: "weibo", + more: "more", + agree:"agree", + copy: "copy", + wechatApplet: "applet", + cancelShare: "cancel sharing", + updateSucceeded: "update succeeded", + phonePlaceholder: "Please enter your mobile phone number", + verifyCodePlaceholder: "Please enter the verification code", + newPasswordPlaceholder: "Please enter a new password", + confirmNewPasswordPlaceholder: "Please confirm the new password", + confirmPassword: "Please confirm the password", + verifyCodeSend: "Verification code has been sent to via SMS", + passwordDigits: "The password is 6 - 20 digits", + getVerifyCode: "Get Code", + noAgree: "You have not agreed to the privacy policy agreement", + gotIt: "got it", + login: "sign in", + error: "error", + complete: "complete", + submit: "Submit", + formatErr: "Incorrect mobile phone number format", + sixDigitCode: "Please enter a 6-digit verification code", + resetNavTitle:"Reset password" + }, + list: { + inputPlaceholder: "Please enter the search content", + }, + search: { + cancelText: "cancel", + searchHistory: "search history", + searchDiscovery: "search discovery", + deleteAll: "delete all", + delete: "delete", + deleteTip: "Are you sure to clear the search history ?", + complete: "complete", + searchHiddenTip: "Current search found hidden", + }, + grid: { + grid: "Grid Assembly", + visibleToAll: "Visible to all", + invisibleToTourists: "Invisible to tourists", + adminVisible: "Admin visible", + clickTip: "Click the", + clickTipGrid: "grid", + }, + mine: { + showText: "Text", + signIn: "Check In Reward", + signInByAd:"Check In Reward By AD", + toEvaluate: "To Evaluate", + readArticles: "Read Articles", + myScore: "My Score", + invite: "Invite Friends", + feedback: "Problems And Feedback", + settings: "Settings", + about: "About", + checkUpdate: "Check for Updates", + clicked: "You Clicked", + checkScore: "Please check your points after logging in", + currentScore: "The current score is ", + noScore: "There are currently no points", + notLogged: "not logged in", + }, + userinfo: { + navigationBarTitle:"My Profile", + ProfilePhoto: "Profile Photo", + nickname: "Nickname", + notSet: "not set", + phoneNumber: "Phone Number", + notSpecified: "Not Specified", + setNickname: "Set Nickname ", + setNicknamePlaceholder: "Please enter a nickname to set", + bindPhoneNumber: "One click binding of local number", + bindOtherLogin: "Other number binding", + noChange: "No change", + uploading: "uploading", + requestFail: "Request for service failed", + setting: "setting", + deleteSucceeded: "Delete succeeded", + setSucceeded: "Set successfully", + }, + smsCode: { + resendVerifyCode: "resend", + phoneErrTip: "Mobile phone number format error", + sendSuccessTip: "SMS verification code sent successfully", + }, + loadMore: { + noData: "No Data", + noNetwork: "Network error", + toSet: "Go to settings", + error: "error", + }, + uniFeedback: { + navigationBarTitle: "Problems and feedback", + msgTitle: "Message content", + imgTitle: "Picture list", + contacts: "contacts", + phone: "contact number", + submit: "submit", + }, + settings: { + navigationBarTitle:"Settings", + userInfo: "Personal Data", + changePassword: "change password", + clearTmp: "clean cache", + pushServer: "push function", + fingerPrint: "fingerprint unlock", + facial: "face unlock", + deactivate: "Deactivate", + logOut: "Logout", + login: "Login", + changeLanguage: "Language", + please: "please", + successText: "success", + failTip: "Authentication failed. Please try again", + authFailed: "authentication failed", + deviceNoOpen: "The device is not turned on", + fail: "fail", + tips: "tips", + exitLogin: "Do you want to log out?", + cancelText: "cancel", + confirmText: "confirm", + clearing: "clearing", + clearedSuccessed: "Cleared successfully", + }, + deactivate: { + cancelText: "cancel", + nextStep: "next step", + navigationBarTitle:"Logout prompt" + }, + about: { + sacnQR: "Scan the QR Code and your friends can also download it", + client: "applCantion", + and: "And", + about: "About", + }, + invite: { + download: "Download", + }, + login: { + phoneLogin: "After logging in, you can show yourself", + phoneLoginTip: "Unregistered mobile phone numbers will be automatically registered after verification", + getVerifyCode: "Get Code", + }, + uniQuickLogin: { + accountLogin: "Account", + SMSLogin: "SMS", + wechatLogin: "wechat", + appleLogin: "Apple", + oneClickLogin: "One click login", + QQLogin: "QQ", + xiaomiLogin: "Xiaomi", + getProviderFail: "Failed to get service provider", + loginErr: "Login service initialization error", + chooseOtherLogin: "Click the third-party login", + }, + pwdLogin: { + pwdLogin: "User name password login", + placeholder: "Please enter mobile number / user name", + passwordPlaceholder: "Please input a password", + verifyCodePlaceholder: "Please enter the verification code", + login: "sign in", + forgetPassword: "Forget password", + register: "Registered account", + }, + register: { + navigationBarTitle:"register", + usernamePlaceholder: "Please enter user name", + nicknamePlaceholder: "Please enter user nickname", + passwordDigitsPlaceholder: "Please enter a 6-20 digit password", + passwordAgain: "Enter the password again", + registerAndLogin: "Register and log in", + }, + listDetail: { + follow: "Click follow", + newsErr: "Error, news ID is empty", + }, + newsLog:{ + navigationBarTitle:"Reading Log" + }, + bindMobile:{ + navigationBarTitle:"Bind Mobile" + } +} diff --git a/lang/i18n.js b/lang/i18n.js new file mode 100644 index 0000000..a88a754 --- /dev/null +++ b/lang/i18n.js @@ -0,0 +1,96 @@ +import langEn from './en' +import zhHans from './zh-Hans' +import uniStarterConfig from '../uni-starter.config.js' +const {i18n:{enable:i18nEnable} }= uniStarterConfig +const messages = { + 'en': langEn, + 'zh-Hans': zhHans +} +let currentLang +if(i18nEnable){ + currentLang = uni.getStorageSync('CURRENT_LANG') +}else{ + currentLang = "zh-Hans" +} +// console.log(uni.getStorageSync('CURRENT_LANG'),currentLang); +if (!currentLang) { + if (uni.getLocale) { + console.log('获取应用语言:', uni.getLocale()); + let language = 'en' + if (uni.getLocale() != 'en') { + language = 'zh-Hans' + } + uni.setStorageSync('CURRENT_LANG', language) + currentLang = language + } else { + uni.getSystemInfo({ + success: function(res) { + console.log('获取设备信息:', res); + let language = 'zh-Hans' + if (res.language == 'en') { + language = 'en' + } + uni.setStorageSync('CURRENT_LANG', language) + currentLang = language + }, + fail: (err) => { + console.error(err) + } + }) + } +} +let i18nConfig = { + locale: currentLang, // set locale + messages // set locale messages +} + +// #ifdef VUE2 +import Vue from 'vue' +import VueI18n from 'vue-i18n' +Vue.use(VueI18n) +const i18n = new VueI18n(i18nConfig) +// #endif + +// #ifdef VUE3 +import { + createI18n +} from 'vue-i18n' +const i18n = createI18n(i18nConfig) +// #endif + +export default i18n + + +if(i18nEnable){ +console.log(` + 你已开启多语言国际化,将自动根据语言获取【lang/en.js】或【lang/en.js】文件中配置的tabbar的值, + 覆盖你在pages.json中的tabbar的值 + 如果你不需要多语言国际化,请打开配置文件uni-starter.config.js找到 -> i18n -> enable把值设置为false +`); + let initLanguageAfter = () => { + function $i18n(e){ + // #ifdef VUE3 + return i18n.global.messages[i18n.global.locale][e] + // #endif + return i18n.messages[i18n.locale][e] + } + setTimeout(function(){ + //底部tabbar更新 + $i18n('tabbar').split(',').forEach((text, index) => { + // console.log(text); + uni.setTabBarItem({ + index, + text, + complete: e => { + // console.log("e: " + JSON.stringify(e)); + } + }) + }) + },1) + } + initLanguageAfter() + uni.$on('changeLanguage', e => { + console.log('changeLanguage', e); + initLanguageAfter(e) + }) +} \ No newline at end of file diff --git a/lang/zh-Hans.js b/lang/zh-Hans.js new file mode 100644 index 0000000..e1fd23c --- /dev/null +++ b/lang/zh-Hans.js @@ -0,0 +1,268 @@ +export default { + tabbar: '列表,宫格,通讯录,我的', + agreementsTitle: '用户服务协议,隐私政策', + common: { + wechatFriends: "微信好友", + wechatBbs: "微信朋友圈", + weibo: "微博", + more: "更多", + agree: "同意", + copy: "复制", + wechatApplet: "微信小程序", + cancelShare: "取消分享", + updateSucceeded: "更新成功", + phonePlaceholder: "请输入手机号", + verifyCodePlaceholder: "请输入验证码", + newPasswordPlaceholder: "请输入新密码", + confirmNewPasswordPlaceholder: "请确认新密码", + confirmPassword: "请确认密码", + verifyCodeSend: "验证码已通过短信发送至", + passwordDigits: "密码为6 - 20位", + getVerifyCode: "获取验证码", + noAgree: "你未同意隐私政策协议", + gotIt: "知道了", + login: "登录", + error: "错误", + complete: "完成", + submit: "提交", + formatErr: "手机号码格式不正确", + sixDigitCode: "请输入6位验证码", + resetNavTitle: "重置密码" + + }, + list: { + inputPlaceholder: "请输入搜索内容", + }, + search: { + cancelText: '取消', + searchHistory: "搜索历史", + searchDiscovery: "搜索发现", + deleteAll: "全部删除", + delete: "删除", + deleteTip: "确认清空搜索历史吗?", + complete: "完成", + searchHiddenTip: "当前搜索发现已隐藏", + }, + grid: { + grid: "宫格组件", + visibleToAll: "所有人可见", + invisibleToTourists: "游客不可见", + adminVisible: "管理员可见", + clickTip: "点击第", + clickTipGrid: "个宫格", + }, + llJs: { + grid: "流量计算", + cysllJs: { + title: "差压式流量计", + url: "/pagesPackage/ngtools_Flow/cysllJs", + icon:'kb.png' + }, + sdsllJs: { + title: "速度式流量计", + url: "/pagesPackage/ngtools_Flow/sdsllJs", + icon:'sd.png' + }, + ljlllJs: { + title: "临界流流量计", + url: "/pagesPackage/ngtools_Flow/ljlllJs", + icon:'pz.png' + } + }, + wxcsJs: { + grid: "参数计算", + ysyzJs: { + title: "压缩因子", + url: "/pagesPackage/ngtools_Par/zJs", + icon:'z.png' + }, + rzJs: { + title: "密度热值", + url: "/pagesPackage/ngtools_Par/mdRzJs", + icon:'md.png' + }, + qtJs: { + title: "其他参数", + url: "/pagesPackage/ngtools_Par/qtJs", + icon:'qt.png' + } + }, + CNGJs: { + grid: "CNG、LNG计算", + LNGQhJs: { + title: "LNG气化量", + url: "/pagesPackage/ngtools_CNG/LNGQhJs", + icon:'qh.png' + }, + srjJs: { + title: "管束车容积", + url: "/pagesPackage/ngtools_CNG/srjJs", + icon:'v.png' + }, + zxcJs: { + title: "CNG装卸量", + url: "/pagesPackage/ngtools_CNG/zxcJs", + icon:'zx.png' + }, + }, + QtJs: { + grid: "其他计算", + ZBGJs: { + title: "压缩因子表格", + url: "/pagesPackage/ngtools_Par/ZBgJs", + icon:'zt' + }, + srjBGJs: { + title: "水容积表格", + url: "/pagesPackage/ngtools_CNG/srjBgJs", + icon:'vt' + } + // , + // SqgyJs: { + // title: "输气工艺", + // url: "/pagesPackage/ngtools_Flow/SqgyJs", + // icon:'' + // } + }, + mine: { + showText: "文字", + dict:"数据字典", + depart:"组织机构", + myPay:"打赏/购买", + signIn: "普通签到", + signInByAd: "看广告签到", + toEvaluate: "去评分", + readArticles: "阅读过的文章", + myScore: "我的积分", + invite: "分销推荐", + feedback: "问题与反馈", + settings: "设置", + checkUpdate: "检查更新", + about: "关于", + clicked: "你点击了", + checkScore: "请登录后查看积分", + currentScore: "当前积分为", + noScore: "当前无积分", + notLogged: "未登录", + }, + userinfo: { + navigationBarTitle: "个人资料", + ProfilePhoto: "头像", + nickname: "昵称", + notSet: "未设置", + phoneNumber: "手机号", + notSpecified: "未绑定", + setNickname: "设置昵称", + setNicknamePlaceholder: "请输入要设置的昵称", + bindPhoneNumber: "本机号码一键绑定", + bindOtherLogin: "其他号码绑定", + noChange: "没有变化", + uploading: "正在上传", + requestFail: "请求服务失败", + setting: "设置中", + deleteSucceeded: "删除成功", + setSucceeded: "设置成功", + }, + smsCode: { + resendVerifyCode: "重新发送", + phoneErrTip: "手机号格式错误", + sendSuccessTip: "短信验证码发送成功", + }, + loadMore: { + noData: "暂无数据", + noNetwork: "网络异常", + toSet: "前往设置", + error: "错误", + }, + uniFeedback: { + navigationBarTitle: "问题与反馈", + msgTitle: "留言内容", + imgTitle: "图片列表", + contacts: "联系人", + phone: "联系电话", + submit: "提交", + }, + settings: { + navigationBarTitle: "设置", + userInfo: "账号资料", + changePassword: "修改密码", + clearTmp: "清理缓存", + pushServer: "推送功能", + fingerPrint: "指纹解锁", + facial: "人脸解锁", + deactivate: "注销账号", + logOut: "退出登录", + login: "登录", + failTip: "认证失败请重试", + authFailed: "认证失败", + changeLanguage: "切换语言", + please: "请用", + successText: "成功", + deviceNoOpen: "设备未开启", + fail: "失败", + tips: "提示", + exitLogin: "是否退出登录?", + clearing: "清除中", + clearedSuccessed: "清除成功", + confirmText: "确定", + cancelText: '取消', + }, + deactivate: { + cancelText: '取消', + nextStep: "下一步", + navigationBarTitle: "注销提示" + }, + about: { + sacnQR: "扫描二维码,您的朋友也可以下载", + client: "客户端", + and: "和", + about: "关于", + }, + invite: { + download: "下载", + }, + login: { + phoneLogin: "登录后即可展示自己", + phoneLoginTip: "未注册的手机号验证通过后将自动注册", + getVerifyCode: "获取验证码", + }, + uniQuickLogin: { + accountLogin: "账号登录", + SMSLogin: "短信验证码", + wechatLogin: "微信登录", + appleLogin: "苹果登录", + oneClickLogin: "一键登录", + QQLogin: "QQ登录", + xiaomiLogin: "小米登录", + getProviderFail: "获取服务供应商失败", + loginErr: "登录服务初始化错误", + chooseOtherLogin: "点击了第三方登录", + }, + pwdLogin: { + pwdLogin: "用户名密码登录", + placeholder: "请输入手机号/用户名", + passwordPlaceholder: "请输入密码", + verifyCodePlaceholder: "请输入验证码", + login: "登录", + forgetPassword: "忘记密码", + register: "注册账号", + }, + register: { + navigationBarTitle: "注册", + usernamePlaceholder: "请输入用户名", + nicknamePlaceholder: "请输入用户昵称", + registerAndLogin: "注册并登录", + passwordDigitsPlaceholder: "请输入6-20位密码", + passwordAgain: "再次输入密码", + }, + listDetail: { + follow: "点击关注", + newsErr: "出错了,新闻ID为空", + }, + newsLog: { + navigationBarTitle: "阅读记录" + }, + bindMobile: { + navigationBarTitle: "绑定手机号码" + } +} \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 0000000..220e826 --- /dev/null +++ b/main.js @@ -0,0 +1,32 @@ +import App from './App' +import i18n from './lang/i18n' +Vue.prototype.staticDir = 'https://ngtools.cn:3000/pic/static/'; +Vue.prototype.getStaticFilePath = function(url) { + return Vue.prototype.staticDir + url; +} + +// #ifndef VUE3 +import Vue from 'vue' +Vue.config.productionTip = false +App.mpType = 'app' +const app = new Vue({ + i18n, + ...App +}) +app.$mount() +// #endif + + +// #ifdef VUE3 +import { + createSSRApp +} from 'vue' + +export function createApp() { + const app = createSSRApp(App) + app.use(i18n) + return { + app + } +} +// #endif \ No newline at end of file diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..4233a15 --- /dev/null +++ b/manifest.json @@ -0,0 +1,180 @@ +{ + "name" : "NGTools", + "appid" : "__UNI__ED84AD5", + "description" : "天然气计算工具", + "versionName" : "1.0.0", + "versionCode" : "100", + "transformPx" : false, + "app-plus" : { + "usingComponents" : true, + "nvueStyleCompiler" : "uni-app", + "compilerVersion" : 3, + "splashscreen" : { + "alwaysShowBeforeRender" : true, + "waiting" : true, + "autoclose" : true, + "delay" : 0 + }, + "modules" : { + "OAuth" : {}, + "Push" : {}, + "Payment" : {} + }, + "distribute" : { + "android" : { + "permissions" : [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + "ios" : { + "dSYMs" : false + }, + "sdkConfigs" : { + "push" : { + "unipush" : { + "version" : "2", + "offline" : false + } + }, + "oauth" : { + "weixin" : { + "appid" : "wx9f9b7d747d261686", + "UniversalLinks" : "" + } + }, + "ad" : { + "hw" : {}, + "360" : {} + }, + "payment" : { + "alipay" : { + "__platform__" : [ "android" ] + }, + "weixin" : { + "__platform__" : [ "android" ], + "appid" : "wx9f9b7d747d261686", + "UniversalLinks" : "" + } + } + }, + "icons" : { + "android" : { + "hdpi" : "unpackage/res/icons/72x72.png", + "xhdpi" : "unpackage/res/icons/96x96.png", + "xxhdpi" : "unpackage/res/icons/144x144.png", + "xxxhdpi" : "unpackage/res/icons/192x192.png" + }, + "ios" : { + "appstore" : "unpackage/res/icons/1024x1024.png", + "ipad" : { + "app" : "unpackage/res/icons/76x76.png", + "app@2x" : "unpackage/res/icons/152x152.png", + "notification" : "unpackage/res/icons/20x20.png", + "notification@2x" : "unpackage/res/icons/40x40.png", + "proapp@2x" : "unpackage/res/icons/167x167.png", + "settings" : "unpackage/res/icons/29x29.png", + "settings@2x" : "unpackage/res/icons/58x58.png", + "spotlight" : "unpackage/res/icons/40x40.png", + "spotlight@2x" : "unpackage/res/icons/80x80.png" + }, + "iphone" : { + "app@2x" : "unpackage/res/icons/120x120.png", + "app@3x" : "unpackage/res/icons/180x180.png", + "notification@2x" : "unpackage/res/icons/40x40.png", + "notification@3x" : "unpackage/res/icons/60x60.png", + "settings@2x" : "unpackage/res/icons/58x58.png", + "settings@3x" : "unpackage/res/icons/87x87.png", + "spotlight@2x" : "unpackage/res/icons/80x80.png", + "spotlight@3x" : "unpackage/res/icons/120x120.png" + } + } + } + }, + "uniStatistics" : { + "enable" : true + }, + "optimization" : { + "subPackages" : true + } + }, + "quickapp" : {}, + "mp-weixin" : { + "appid" : "wx9f9b7d747d261686", + "lazyCodeLoading" : "requiredComponents", + "setting" : { + "urlCheck" : false, + "minified" : true + }, + "usingComponents" : true, + "optimization" : { + "subPackages" : true + }, + "permission" : {}, + "unipush" : { + "enable" : true + }, + "secureNetwork" : { + "enable" : true + }, + "uniStatistics" : { + "enable" : true + } + }, + "mp-alipay" : { + "usingComponents" : true + }, + "mp-baidu" : { + "usingComponents" : true + }, + "mp-toutiao" : { + "usingComponents" : true + }, + "uniStatistics" : { + "enable" : false, + "version" : "2" + }, + "vueVersion" : "2", + "locale" : "zh-Hans", + "h5" : { + "devServer" : { + "port" : 80, + "disableHostCheck" : true, + "proxy" : { + "/api" : { + "target" : "https://ngtools.cn:8443", + "changeOrigin" : true, + "secure" : true, + "pathRewrite" : { + "^/api" : "" + } + } + } + }, + "router" : { + "base" : "ngtools" + }, + "uniStatistics" : { + "enable" : true + } + } +} +//浏览器运行端口 +//设置跳过host检查 +//目标接口域名 +//是否跨域 +// 设置支持https协议的代理 + diff --git a/package.json b/package.json new file mode 100644 index 0000000..96a4b8b --- /dev/null +++ b/package.json @@ -0,0 +1,90 @@ +{ + "id": "NGTools", + "displayName": "NGTools", + "version": "2.1.8", + "description": "天然气计算工具", + "keywords": [ + "login", + "登录", + "搜索", + "uni-id实例", + "留言板" + ], + "type": "module", + "repository": "https://gitcode.net/dcloud/uni-starter", + "engines": { + "HBuilderX": "^3.2.6" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "", + "type": "unicloud-template-project" + }, + "uni_modules": { + "dependencies": [ + "uni-id-pages" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "y", + "IE": "n", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "y", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + }, + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001627", + "qrcodejs2": "^0.0.2" + } +} diff --git a/pages.json b/pages.json new file mode 100644 index 0000000..5e45365 --- /dev/null +++ b/pages.json @@ -0,0 +1,666 @@ +{ + "pages": [{ + "path": "pages/grid/grid", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/list/list", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/list/detail", + "style": { + "navigationStyle": "custom" + } + }, + + { + "path": "pages/ucenter", + "style": { + "navigationStyle": "custom" + } + } + + + // #ifdef APP-PLUS + , { + "path": "uni_modules/uni-upgrade-center-app/pages/upgrade-popup", + "style": { + "disableScroll": true, + "app-plus": { + "backgroundColorTop": "transparent", + "background": "transparent", + "titleNView": false, + "scrollIndicator": false, + "popGesture": "none", + "animationType": "fade-in", + "animationDuration": 200 + } + } + } + // #endif + ], + "subPackages": [{ + "root": "pagesPackage/components", + "pages": [{ + "path": "popup", + "style": { + "navigationBarTitleText": "", + "enablePullDownRefresh": false, + "navigationStyle": "custom", + "app-plus": { + "animationType": "fade-in", // 设置fade-in淡入动画,为最合理的动画类型 + "background": "transparent", // 背景透明 + "backgroundColor": "transparent", // 背景透明 + "webviewBGTransparent": true, + "mask": "none", + "popGesture": "none", // 关闭IOS屏幕左边滑动关闭当前页面的功能 + "bounce": "none" // 将回弹属性关掉 + } + } + }] + }, + { + "root": "pagesPackage/opendb-banner", + "pages": [{ + "path": "add", + "style": { + "navigationBarTitleText": "新增" + } + }, + { + "path": "edit", + "style": { + "navigationBarTitleText": "编辑" + } + }, + { + "path": "list", + "style": { + "navigationBarTitleText": "列表" + } + }, + { + "path": "detail", + "style": { + "navigationBarTitleText": "详情" + } + } + ] + }, + { + "root": "pagesPackage/uni-agree", + "pages": [{ + "path": "uni-agree", + "style": { + "navigationStyle": "custom", + "app-plus": { + "popGesture": "none" + } + } + }] + }, + { + "root": "pagesPackage/ucenter", + "pages": [{ + "path": "invite/invite", + "style": { + "navigationStyle": "custom", + "enablePullDownRefresh": false + } + }, + { + "path": "settings/settings", + "style": { + "navigationBarTitleText": "设置" + } + }, + { + "path": "read-news-log/read-news-log", + "style": { + "navigationBarTitleText": "阅读记录", + "enablePullDownRefresh": true + } + }, + { + "path": "pay/index", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "about/about", + "style": { + "navigationBarTitleText": "关于", + "app-plus": { + "titleNView": { + "buttons": [{ + "type": "share" + }] + } + } + } + } + ] + }, + { + "root": "uni_modules/uni-feedback", + "pages": [{ + "path": "pages/opendb-feedback/opendb-feedback", + "style": { + "navigationBarTitleText": "意见反馈", + "enablePullDownRefresh": false + } + }] + }, { + "root": "uni_modules/uni-id-pages/pages", + "pages": [{ + "path": "userinfo/userinfo", + "style": { + "navigationBarTitleText": "个人资料" + } + }, + { + "path": "userinfo/realname-verify/realname-verify", + "style": { + "enablePullDownRefresh": false, + "navigationBarTitleText": "实名认证" + } + }, + { + "path": "login/login-withoutpwd" + }, + { + "path": "login/login-withpwd" + }, + { + "path": "userinfo/deactivate/deactivate", + "style": { + "navigationBarTitleText": "注销账号" + } + }, + { + "path": "userinfo/bind-mobile/bind-mobile", + "style": { + "navigationBarTitleText": "绑定手机号码" + } + }, + { + "path": "login/login-smscode", + "style": { + "navigationBarTitleText": "手机验证码登录" + } + }, + { + "path": "register/register", + "style": { + "navigationBarTitleText": "注册" + } + }, + { + "path": "retrieve/retrieve", + "style": { + "navigationBarTitleText": "重置密码" + } + }, { + "path": "common/webview/webview", + "style": { + "enablePullDownRefresh": false, + "navigationBarTitleText": "" + } + }, { + "path": "userinfo/change_pwd/change_pwd", + "style": { + "enablePullDownRefresh": false, + "navigationBarTitleText": "修改密码" + } + }, { + "path": "register/register-by-email", + "style": { + "navigationBarTitleText": "邮箱验证码注册" + } + }, { + "path": "retrieve/retrieve-by-email", + "style": { + "navigationBarTitleText": "通过邮箱重置密码" + } + }, + { + "path": "userinfo/set-pwd/set-pwd", + "style": { + "enablePullDownRefresh": false, + "navigationBarTitleText": "设置密码" + } + } + // #ifdef H5 + , + { + "path": "userinfo/cropImage/cropImage" + }, + { + "path": "register/register-admin", + "style": { + "enablePullDownRefresh": false, + "navigationBarTitleText": "注册管理员账号" + } + } + // #endif + ] + }, { + "root": "pagesPackage/ngtools_Flow", + "pages": [{ + "path": "cysllJs", + "style": { + "navigationBarTitleText": "差压式流量计算", + "navigationStyle": "custom" + } + }, { + "path": "sdsllJs", + "style": { + "navigationBarTitleText": "速度式流量计算", + "navigationStyle": "custom" + } + }, + { + "path": "ljlllJs", + "style": { + "navigationBarTitleText": "临界流流量计算", + "navigationStyle": "custom" + + + } + }, + { + "path": "SqgyJs", + "style": { + "navigationBarTitleText": "输气工艺", + "navigationStyle": "custom" + } + } + + ] + }, { + "root": "pagesPackage/ngtools_Par", + "pages": [{ + "path": "zJs", + "style": { + "navigationBarTitleText": "压缩因子计算GB/T 17747", + "navigationStyle": "custom" + + + } + }, + { + "path": "mdRzJs", + "style": { + "navigationBarTitleText": "密度热值计算GB/T 11062", + "navigationStyle": "custom" + } + }, + { + "path": "qtJs", + "style": { + "navigationBarTitleText": "其他物性参数计算", + "navigationStyle": "custom" + } + }, + { + "path": "ZBgJs", + "style": { + "navigationBarTitleText": "压缩因子表格", + "navigationStyle": "custom" + } + } + ] + }, { + "root": "pagesPackage/ngtools_CNG", + "pages": [{ + "path": "LNGQhJs", + "style": { + "navigationBarTitleText": "LNG气化计算", + "navigationStyle": "custom" + + + } + }, + { + "path": "srjJs", + "style": { + "navigationBarTitleText": "罐车水容积计算", + "navigationStyle": "custom" + } + }, + { + "path": "zxcJs", + "style": { + "navigationBarTitleText": "装卸量计算", + "navigationStyle": "custom" + } + }, + + { + "path": "srjBgJs", + "style": { + "navigationBarTitleText": "水容积表格", + "navigationStyle": "custom" + } + } + ] + }, { + "root": "pagesPackage/ngTools_depart", + "pages": [{ + "path": "add", + "style": { + "navigationStyle": "custom" + } + }, { + "path": "edit", + "style": { + "navigationStyle": "custom" + } + }, { + "path": "list", + "style": { + "navigationStyle": "custom" + } + }, { + "path": "detail", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "departList/departList", + "style": { + "navigationBarTitleText": "" + } + } + ] + }, + { + "root": "pagesPackage/ngTools_Dict", + "pages": [{ + "path": "add", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "edit", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "list", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "detail", + "style": { + "navigationStyle": "custom" + } + } + ] + }, + + { + "root": "pagesPackage/ngTools_DictItem", + "pages": [{ + "path": "add", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "edit", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "list", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "detail", + "style": { + "navigationStyle": "custom" + } + } + ] + }, + + { + "root": "pagesPackage/ngtools_information", + "pages": [{ + "path": "add", + "style": { + "navigationBarTitleText": "新增" + } + }, + { + "path": "edit", + "style": { + "navigationBarTitleText": "编辑" + } + }, + { + "path": "list", + "style": { + "navigationBarTitleText": "列表" + } + }, + { + "path": "detail", + "style": { + "navigationBarTitleText": "详情" + } + } + ] + }, + { + "root": "pagesPackage/ngtools_categories", + "pages": [{ + "path": "add", + "style": { + "navigationBarTitleText": "新增" + } + }, + { + "path": "edit", + "style": { + "navigationBarTitleText": "编辑" + } + }, + { + "path": "list", + "style": { + "navigationBarTitleText": "列表" + } + }, + { + "path": "detail", + "style": { + "navigationBarTitleText": "详情" + } + } + ] + }, + { + "root": "pagesPackage/ngTools_SamplingLocation", + "pages": [{ + "path": "add", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "edit", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "list", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "detail", + "style": { + "navigationStyle": "custom" + } + } + ] + }, + { + "root": "pagesPackage/ngTools_MeterList", + "pages": [{ + "path": "add", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "edit", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "list", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "detail", + "style": { + "navigationStyle": "custom" + } + } + ] + }, + { + "root": "pagesPackage/ngtools-goods", + "pages": [{ + "path": "add", + "style": { + "navigationBarTitleText": "新增" + } + }, + { + "path": "edit", + "style": { + "navigationBarTitleText": "编辑" + } + }, + { + "path": "list", + "style": { + "navigationBarTitleText": "列表" + } + }, + { + "path": "detail", + "style": { + "navigationBarTitleText": "详情" + } + } + ] + }, + { + "root": "uni_modules/uni-pay", + "pages": [{ + "path": "pages/success/success", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/ad-interactive-webview/ad-interactive-webview", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/pay-desk/pay-desk", + "style": { + "navigationStyle": "custom" + } + } + ] + } + ], + "globalStyle": { + // #ifdef H5 + "h5": { + "titleNView": false + }, + // #endif + "navigationBarTextStyle": "black", + // "navigationBarTitleText": "uni-starter", + "navigationBarBackgroundColor": "#FFFFFF", + "backgroundColor": "#F8F8F8", + "enablePullDownRefresh": false, + // "maxWidth":375, + "rpxCalcMaxDeviceWidth": 375, + "rpxCalcBaseDeviceWidth": 375 + // "rpxCalcIncludeWidth":0 + }, + "condition": { + "list": [{ + "path": "pages/list/detail" + }, + // { + // "path": "pages/list/list" + // }, + + { + "path": "pages/ucenter/settings/settings" + } + ], + "current": 1 + }, + "tabBar": { + "color": "#7A7E83", + "selectedColor": "#007AFF", + "borderStyle": "black", + "backgroundColor": "#FFFFFF", + "list": [{ + "pagePath": "pages/grid/grid", + "iconPath": "static/tabbar/list.png", + "selectedIconPath": "static/tabbar/list_active.png", + "text": "首页" + } + // , { + // "pagePath": "pages/list/list", + // "iconPath": "static/tabbar/grid.png", + // "selectedIconPath": "static/tabbar/grid_active.png", + // "text": "常用资料" + // } + , { + "pagePath": "pages/ucenter", + "iconPath": "static/tabbar/me.png", + "selectedIconPath": "static/tabbar/me_active.png", + "text": "我的" + }] + }, + "uniIdRouter": { + "loginPage": "uni_modules/uni-id-pages/pages/login/login-withoutpwd", + "needLogin": [ + "/uni_modules/uni-id-pages/pages/userinfo/userinfo" + ], + "resToLogin": true + } +} \ No newline at end of file diff --git a/pages/grid/grid.vue b/pages/grid/grid.vue new file mode 100644 index 0000000..fe1eeb1 --- /dev/null +++ b/pages/grid/grid.vue @@ -0,0 +1,404 @@ + + + + + \ No newline at end of file diff --git a/pages/list/detail.vue b/pages/list/detail.vue new file mode 100644 index 0000000..5bbef34 --- /dev/null +++ b/pages/list/detail.vue @@ -0,0 +1,373 @@ + + + + + diff --git a/pages/list/list.nvue b/pages/list/list.nvue new file mode 100644 index 0000000..a4a0e46 --- /dev/null +++ b/pages/list/list.nvue @@ -0,0 +1,206 @@ + + + + + \ No newline at end of file diff --git a/pages/ucenter.vue b/pages/ucenter.vue new file mode 100644 index 0000000..70a1d03 --- /dev/null +++ b/pages/ucenter.vue @@ -0,0 +1,503 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/components/popup.vue b/pagesPackage/components/popup.vue new file mode 100644 index 0000000..1bb3bba --- /dev/null +++ b/pagesPackage/components/popup.vue @@ -0,0 +1,104 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngTools_Dict/add.vue b/pagesPackage/ngTools_Dict/add.vue new file mode 100644 index 0000000..ed7feb1 --- /dev/null +++ b/pagesPackage/ngTools_Dict/add.vue @@ -0,0 +1,183 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngTools_Dict/detail.vue b/pagesPackage/ngTools_Dict/detail.vue new file mode 100644 index 0000000..295fb3b --- /dev/null +++ b/pagesPackage/ngTools_Dict/detail.vue @@ -0,0 +1,162 @@ + + + + + + \ No newline at end of file diff --git a/pagesPackage/ngTools_Dict/edit.vue b/pagesPackage/ngTools_Dict/edit.vue new file mode 100644 index 0000000..cb362ea --- /dev/null +++ b/pagesPackage/ngTools_Dict/edit.vue @@ -0,0 +1,198 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngTools_Dict/list.vue b/pagesPackage/ngTools_Dict/list.vue new file mode 100644 index 0000000..8f4e4ca --- /dev/null +++ b/pagesPackage/ngTools_Dict/list.vue @@ -0,0 +1,151 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngTools_DictItem/add.vue b/pagesPackage/ngTools_DictItem/add.vue new file mode 100644 index 0000000..4c22ecb --- /dev/null +++ b/pagesPackage/ngTools_DictItem/add.vue @@ -0,0 +1,182 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngTools_DictItem/detail.vue b/pagesPackage/ngTools_DictItem/detail.vue new file mode 100644 index 0000000..fe4969f --- /dev/null +++ b/pagesPackage/ngTools_DictItem/detail.vue @@ -0,0 +1,159 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngTools_DictItem/edit.vue b/pagesPackage/ngTools_DictItem/edit.vue new file mode 100644 index 0000000..5160ee5 --- /dev/null +++ b/pagesPackage/ngTools_DictItem/edit.vue @@ -0,0 +1,208 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngTools_DictItem/list.vue b/pagesPackage/ngTools_DictItem/list.vue new file mode 100644 index 0000000..cdf4290 --- /dev/null +++ b/pagesPackage/ngTools_DictItem/list.vue @@ -0,0 +1,165 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngTools_MeterList/add.vue b/pagesPackage/ngTools_MeterList/add.vue new file mode 100644 index 0000000..2c410a5 --- /dev/null +++ b/pagesPackage/ngTools_MeterList/add.vue @@ -0,0 +1,145 @@ + + + + + diff --git a/pagesPackage/ngTools_MeterList/detail.vue b/pagesPackage/ngTools_MeterList/detail.vue new file mode 100644 index 0000000..effe85e --- /dev/null +++ b/pagesPackage/ngTools_MeterList/detail.vue @@ -0,0 +1,120 @@ + + + + + diff --git a/pagesPackage/ngTools_MeterList/edit.vue b/pagesPackage/ngTools_MeterList/edit.vue new file mode 100644 index 0000000..d757826 --- /dev/null +++ b/pagesPackage/ngTools_MeterList/edit.vue @@ -0,0 +1,176 @@ + + + + + diff --git a/pagesPackage/ngTools_MeterList/list.vue b/pagesPackage/ngTools_MeterList/list.vue new file mode 100644 index 0000000..5ce42ce --- /dev/null +++ b/pagesPackage/ngTools_MeterList/list.vue @@ -0,0 +1,72 @@ + + + + + diff --git a/pagesPackage/ngTools_SamplingLocation/add.vue b/pagesPackage/ngTools_SamplingLocation/add.vue new file mode 100644 index 0000000..de67461 --- /dev/null +++ b/pagesPackage/ngTools_SamplingLocation/add.vue @@ -0,0 +1,129 @@ + + + + + diff --git a/pagesPackage/ngTools_SamplingLocation/detail.vue b/pagesPackage/ngTools_SamplingLocation/detail.vue new file mode 100644 index 0000000..908b912 --- /dev/null +++ b/pagesPackage/ngTools_SamplingLocation/detail.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/pagesPackage/ngTools_SamplingLocation/edit.vue b/pagesPackage/ngTools_SamplingLocation/edit.vue new file mode 100644 index 0000000..e98cbde --- /dev/null +++ b/pagesPackage/ngTools_SamplingLocation/edit.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/pagesPackage/ngTools_SamplingLocation/list.vue b/pagesPackage/ngTools_SamplingLocation/list.vue new file mode 100644 index 0000000..681206e --- /dev/null +++ b/pagesPackage/ngTools_SamplingLocation/list.vue @@ -0,0 +1,72 @@ + + + + + diff --git a/pagesPackage/ngTools_depart/add.vue b/pagesPackage/ngTools_depart/add.vue new file mode 100644 index 0000000..b141726 --- /dev/null +++ b/pagesPackage/ngTools_depart/add.vue @@ -0,0 +1,198 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngTools_depart/departList/departList.vue b/pagesPackage/ngTools_depart/departList/departList.vue new file mode 100644 index 0000000..05cc452 --- /dev/null +++ b/pagesPackage/ngTools_depart/departList/departList.vue @@ -0,0 +1,246 @@ + + + + \ No newline at end of file diff --git a/pagesPackage/ngTools_depart/departList/departTree.vue b/pagesPackage/ngTools_depart/departList/departTree.vue new file mode 100644 index 0000000..25493b9 --- /dev/null +++ b/pagesPackage/ngTools_depart/departList/departTree.vue @@ -0,0 +1,42 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngTools_depart/departList/style.css b/pagesPackage/ngTools_depart/departList/style.css new file mode 100644 index 0000000..a203f16 --- /dev/null +++ b/pagesPackage/ngTools_depart/departList/style.css @@ -0,0 +1,161 @@ +.next-tree-mask { + position: fixed; + top: 0rpx; + right: 0rpx; + bottom: 0rpx; + left: 0rpx; + z-index: 9998; + background-color: rgba(0, 0, 0, 0.6); + opacity: 0; + transition: all 0.3s ease; + visibility: hidden; +} +.next-tree-mask.show { + visibility: visible; + opacity: 1; +} +.next-tree-cnt { + position: fixed; + top: 0rpx; + right: 0rpx; + bottom: 0rpx; + left: 0rpx; + z-index: 9999; + top: 160rpx; + transition: all 0.3s ease; + transform: translateY(100%); +} +.next-tree-cnt.show { + transform: translateY(0); +} +.next-tree-bar { + background-color: #fff; + height: 72rpx; + padding-left: 20rpx; + padding-right: 20rpx; + display: flex; + justify-content: space-between; + align-items: center; + box-sizing: border-box; + border-bottom-width: 1rpx !important; + border-bottom-style: solid; + border-bottom-color: #f5f5f5; + font-size: 32rpx; + color: #757575; + line-height: 1; +} +.next-tree-bar-confirm { + color: #f9ae3d; +} +.next-tree-view { + position: absolute; + top: 0rpx; + right: 0rpx; + bottom: 0rpx; + left: 0rpx; + top: 72rpx; + background-color: #fff; + padding-top: 20rpx; + padding-right: 20rpx; + padding-bottom: 20rpx; + padding-left: 20rpx; +} +.next-tree-view-sc { + height: 100%; + overflow: hidden; +} +.next-tree-item { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 26rpx; + color: #757575; + line-height: 1; + height: 0; + opacity: 0; + transition: 0.2s; + position: relative; + overflow: hidden; +} +.next-tree-item.show { + height: 80rpx; + opacity: 1; +} +.next-tree-item.showchild:before { + transform: rotate(90deg); +} +.next-tree-item.border { + border-bottom: 1rpx solid rgba(204,204,204,0.2); +} +.next-tree-item.last:before { + opacity: 0; +} +.next-tree-icon { + width: 26rpx; + height: 26rpx; + margin-right: 8rpx; +} +.next-tree-label { + flex: 1; + display: flex; + align-items: center; + height: 100%; + line-height: 1.2; +} +.next-tree-check { + width: 40px; + height: 40px; + display: flex; + justify-content: center; + align-items: center; +} +.next-tree-check-yes, +.next-tree-check-no { + width: 20px; + height: 20px; + border-top-left-radius: 20%; + border-top-right-radius: 20%; + border-bottom-right-radius: 20%; + border-bottom-left-radius: 20%; + border-top-width: 1rpx; + border-left-width: 1rpx; + border-bottom-width: 1rpx; + border-right-width: 1rpx; + border-style: solid; + border-color: #f9ae3d; + display: flex; + justify-content: center; + align-items: center; + box-sizing: border-box; +} +.next-tree-check-yes-b { + border-top-left-radius: 20%; + border-top-right-radius: 20%; + border-bottom-right-radius: 20%; + border-bottom-left-radius: 20%; + background-color: #f9ae3d; + color: #fff; +} +.next-tree-check-yes-b .icon-text { + font-size: 14px; + font-weight: normal; + font-family: uicon-iconfont; + display: flex; + flex-direction: row; + align-items: center; +} +.next-tree-check .radio { + border-top-left-radius: 50%; + border-top-right-radius: 50%; + border-bottom-right-radius: 50%; + border-bottom-left-radius: 50%; +} +.next-tree-check .radio .next-tree-check-yes-b { + border-top-left-radius: 50%; + border-top-right-radius: 50%; + border-bottom-right-radius: 50%; + border-bottom-left-radius: 50%; +} +.hover-c { + opacity: 0.6; +} \ No newline at end of file diff --git a/pagesPackage/ngTools_depart/depart_select.vue b/pagesPackage/ngTools_depart/depart_select.vue new file mode 100644 index 0000000..cd53806 --- /dev/null +++ b/pagesPackage/ngTools_depart/depart_select.vue @@ -0,0 +1,136 @@ + + \ No newline at end of file diff --git a/pagesPackage/ngTools_depart/detail.vue b/pagesPackage/ngTools_depart/detail.vue new file mode 100644 index 0000000..4cda876 --- /dev/null +++ b/pagesPackage/ngTools_depart/detail.vue @@ -0,0 +1,130 @@ + + + + + diff --git a/pagesPackage/ngTools_depart/edit.vue b/pagesPackage/ngTools_depart/edit.vue new file mode 100644 index 0000000..7fb64e2 --- /dev/null +++ b/pagesPackage/ngTools_depart/edit.vue @@ -0,0 +1,209 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngTools_depart/list.vue b/pagesPackage/ngTools_depart/list.vue new file mode 100644 index 0000000..916a612 --- /dev/null +++ b/pagesPackage/ngTools_depart/list.vue @@ -0,0 +1,119 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngTools_depart/user_select.vue b/pagesPackage/ngTools_depart/user_select.vue new file mode 100644 index 0000000..41b28cd --- /dev/null +++ b/pagesPackage/ngTools_depart/user_select.vue @@ -0,0 +1,102 @@ + + \ No newline at end of file diff --git a/pagesPackage/ngtools-goods/add.vue b/pagesPackage/ngtools-goods/add.vue new file mode 100644 index 0000000..2c9864a --- /dev/null +++ b/pagesPackage/ngtools-goods/add.vue @@ -0,0 +1,201 @@ + + + + + diff --git a/pagesPackage/ngtools-goods/detail.vue b/pagesPackage/ngtools-goods/detail.vue new file mode 100644 index 0000000..f6930d7 --- /dev/null +++ b/pagesPackage/ngtools-goods/detail.vue @@ -0,0 +1,176 @@ + + + + + diff --git a/pagesPackage/ngtools-goods/edit.vue b/pagesPackage/ngtools-goods/edit.vue new file mode 100644 index 0000000..2f40403 --- /dev/null +++ b/pagesPackage/ngtools-goods/edit.vue @@ -0,0 +1,232 @@ + + + + + diff --git a/pagesPackage/ngtools-goods/list.vue b/pagesPackage/ngtools-goods/list.vue new file mode 100644 index 0000000..a8a16c8 --- /dev/null +++ b/pagesPackage/ngtools-goods/list.vue @@ -0,0 +1,72 @@ + + + + + diff --git a/pagesPackage/ngtools_CNG/LNGQhJs.vue b/pagesPackage/ngtools_CNG/LNGQhJs.vue new file mode 100644 index 0000000..7b17f58 --- /dev/null +++ b/pagesPackage/ngtools_CNG/LNGQhJs.vue @@ -0,0 +1,325 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngtools_CNG/srjBgJs.vue b/pagesPackage/ngtools_CNG/srjBgJs.vue new file mode 100644 index 0000000..f5abde9 --- /dev/null +++ b/pagesPackage/ngtools_CNG/srjBgJs.vue @@ -0,0 +1,365 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngtools_CNG/srjJs.vue b/pagesPackage/ngtools_CNG/srjJs.vue new file mode 100644 index 0000000..62ebaf7 --- /dev/null +++ b/pagesPackage/ngtools_CNG/srjJs.vue @@ -0,0 +1,313 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngtools_CNG/zxcJs.vue b/pagesPackage/ngtools_CNG/zxcJs.vue new file mode 100644 index 0000000..4e9df97 --- /dev/null +++ b/pagesPackage/ngtools_CNG/zxcJs.vue @@ -0,0 +1,343 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngtools_Flow/SqgyJs.vue b/pagesPackage/ngtools_Flow/SqgyJs.vue new file mode 100644 index 0000000..83730de --- /dev/null +++ b/pagesPackage/ngtools_Flow/SqgyJs.vue @@ -0,0 +1,523 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngtools_Flow/cysllJs.vue b/pagesPackage/ngtools_Flow/cysllJs.vue new file mode 100644 index 0000000..7f1f093 --- /dev/null +++ b/pagesPackage/ngtools_Flow/cysllJs.vue @@ -0,0 +1,299 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngtools_Flow/ljlllJs.vue b/pagesPackage/ngtools_Flow/ljlllJs.vue new file mode 100644 index 0000000..96c72c0 --- /dev/null +++ b/pagesPackage/ngtools_Flow/ljlllJs.vue @@ -0,0 +1,295 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngtools_Flow/sdsllJs.vue b/pagesPackage/ngtools_Flow/sdsllJs.vue new file mode 100644 index 0000000..a492b2c --- /dev/null +++ b/pagesPackage/ngtools_Flow/sdsllJs.vue @@ -0,0 +1,293 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngtools_Par/ZBgJs.vue b/pagesPackage/ngtools_Par/ZBgJs.vue new file mode 100644 index 0000000..fb58e50 --- /dev/null +++ b/pagesPackage/ngtools_Par/ZBgJs.vue @@ -0,0 +1,367 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngtools_Par/mdRzJs.vue b/pagesPackage/ngtools_Par/mdRzJs.vue new file mode 100644 index 0000000..67100b0 --- /dev/null +++ b/pagesPackage/ngtools_Par/mdRzJs.vue @@ -0,0 +1,342 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngtools_Par/qtJs.vue b/pagesPackage/ngtools_Par/qtJs.vue new file mode 100644 index 0000000..15cb478 --- /dev/null +++ b/pagesPackage/ngtools_Par/qtJs.vue @@ -0,0 +1,335 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngtools_Par/zJs.vue b/pagesPackage/ngtools_Par/zJs.vue new file mode 100644 index 0000000..c0a5231 --- /dev/null +++ b/pagesPackage/ngtools_Par/zJs.vue @@ -0,0 +1,335 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngtools_categories/add.vue b/pagesPackage/ngtools_categories/add.vue new file mode 100644 index 0000000..9ef9c7e --- /dev/null +++ b/pagesPackage/ngtools_categories/add.vue @@ -0,0 +1,153 @@ + + + + + diff --git a/pagesPackage/ngtools_categories/detail.vue b/pagesPackage/ngtools_categories/detail.vue new file mode 100644 index 0000000..093dee4 --- /dev/null +++ b/pagesPackage/ngtools_categories/detail.vue @@ -0,0 +1,128 @@ + + + + + diff --git a/pagesPackage/ngtools_categories/edit.vue b/pagesPackage/ngtools_categories/edit.vue new file mode 100644 index 0000000..799a5e0 --- /dev/null +++ b/pagesPackage/ngtools_categories/edit.vue @@ -0,0 +1,184 @@ + + + + + diff --git a/pagesPackage/ngtools_categories/list.vue b/pagesPackage/ngtools_categories/list.vue new file mode 100644 index 0000000..6b7ccb3 --- /dev/null +++ b/pagesPackage/ngtools_categories/list.vue @@ -0,0 +1,72 @@ + + + + + diff --git a/pagesPackage/ngtools_information/add.vue b/pagesPackage/ngtools_information/add.vue new file mode 100644 index 0000000..c837811 --- /dev/null +++ b/pagesPackage/ngtools_information/add.vue @@ -0,0 +1,153 @@ + + + + + diff --git a/pagesPackage/ngtools_information/detail.vue b/pagesPackage/ngtools_information/detail.vue new file mode 100644 index 0000000..c723709 --- /dev/null +++ b/pagesPackage/ngtools_information/detail.vue @@ -0,0 +1,382 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/ngtools_information/edit.vue b/pagesPackage/ngtools_information/edit.vue new file mode 100644 index 0000000..3324694 --- /dev/null +++ b/pagesPackage/ngtools_information/edit.vue @@ -0,0 +1,184 @@ + + + + + diff --git a/pagesPackage/ngtools_information/list.vue b/pagesPackage/ngtools_information/list.vue new file mode 100644 index 0000000..ad8d525 --- /dev/null +++ b/pagesPackage/ngtools_information/list.vue @@ -0,0 +1,81 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/opendb-banner/add.vue b/pagesPackage/opendb-banner/add.vue new file mode 100644 index 0000000..390d85e --- /dev/null +++ b/pagesPackage/opendb-banner/add.vue @@ -0,0 +1,149 @@ + + + + + diff --git a/pagesPackage/opendb-banner/detail.vue b/pagesPackage/opendb-banner/detail.vue new file mode 100644 index 0000000..ad825d3 --- /dev/null +++ b/pagesPackage/opendb-banner/detail.vue @@ -0,0 +1,126 @@ + + + + + diff --git a/pagesPackage/opendb-banner/edit.vue b/pagesPackage/opendb-banner/edit.vue new file mode 100644 index 0000000..a1646d4 --- /dev/null +++ b/pagesPackage/opendb-banner/edit.vue @@ -0,0 +1,180 @@ + + + + + diff --git a/pagesPackage/opendb-banner/list.vue b/pagesPackage/opendb-banner/list.vue new file mode 100644 index 0000000..1321a2d --- /dev/null +++ b/pagesPackage/opendb-banner/list.vue @@ -0,0 +1,72 @@ + + + + + diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/changelog.md b/pagesPackage/ucenter/Sansnn-uQRCode/changelog.md new file mode 100644 index 0000000..74a6e4c --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/changelog.md @@ -0,0 +1,12 @@ +## 4.0.6(2022-12-12) +修复`getDrawModules`,第一次获取结果正常,后续获取`tile`模块不存在的问题; +修复安卓type:normal因Canvas API使用了小数或为0的参数导致生成异常的问题(注:安卓非2d Canvas部分API参数不支持携带小数,部分API参数必须大于0)。 +## 4.0.1(2022-11-28) +优化组件loading属性的表现; +新增组件type选项normal,以便于在某些条件编译初始为type=2d时还可以选择使用非2d组件类型; +修复组件条件编译在其他编辑器语法提示报错; +修复原生对es5的支持。 +## 4.0.0(2022-11-21) +v4版本源代码全面开放,开源地址:[https://github.com/Sansnn/uQRCode](https://github.com/Sansnn/uQRCode); + +升级说明:v4为大版本更新,虽然已尽可能兼容上一代版本,但不可避免的还是存在一些细节差异,若更新后出现问题,请参考对照[v3 文档](https://uqrcode.cn/doc/v3),[v4 文档](https://uqrcode.cn/doc)进行修改。 diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/common/cache.js b/pagesPackage/ucenter/Sansnn-uQRCode/common/cache.js new file mode 100644 index 0000000..d897d26 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/common/cache.js @@ -0,0 +1 @@ +export const cacheImageList = []; \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/common/queue.js b/pagesPackage/ucenter/Sansnn-uQRCode/common/queue.js new file mode 100644 index 0000000..be6b1d2 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/common/queue.js @@ -0,0 +1,41 @@ +function Queue() { + let waitingQueue = this.waitingQueue = []; + let isRunning = this.isRunning = false; // 记录是否有未完成的任务 + + function execute(task, resolve, reject) { + task() + .then((data) => { + resolve(data); + }) + .catch((e) => { + reject(e); + }) + .finally(() => { + // 等待任务队列中如果有任务,则触发它;否则设置isRunning = false,表示无任务状态 + if (waitingQueue.length) { + const next = waitingQueue.shift(); + execute(next.task, next.resolve, next.reject); + } else { + isRunning = false; + } + }); + } + this.exec = function(task) { + return new Promise((resolve, reject) => { + if (isRunning) { + waitingQueue.push({ + task, + resolve, + reject + }); + } else { + isRunning = true; + execute(task, resolve, reject); + } + }); + } +} + +/* 队列实例,某些平台一起使用多个组件时需要通过队列逐一绘制,否则部分绘制方法异常,nvue端的iOS gcanvas尤其明显,在不通过队列绘制时会出现图片丢失的情况 */ +export const queueDraw = new Queue(); +export const queueLoadImage = new Queue(); \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/common/types/cache.d.ts b/pagesPackage/ucenter/Sansnn-uQRCode/common/types/cache.d.ts new file mode 100644 index 0000000..9b6c3ce --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/common/types/cache.d.ts @@ -0,0 +1,3 @@ +declare module '*/common/cache' { + export const cacheImageList: Array; +} \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/common/types/queue.d.ts b/pagesPackage/ucenter/Sansnn-uQRCode/common/types/queue.d.ts new file mode 100644 index 0000000..f81ab97 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/common/types/queue.d.ts @@ -0,0 +1,4 @@ +declare module '*/common/queue' { + export const queueDraw: any; + export const queueLoadImage: any; +} \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/components/u-qrcode/u-qrcode.vue b/pagesPackage/ucenter/Sansnn-uQRCode/components/u-qrcode/u-qrcode.vue new file mode 100644 index 0000000..4fefaac --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/components/u-qrcode/u-qrcode.vue @@ -0,0 +1,1131 @@ + + + + + diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/components/uqrcode/uqrcode.vue b/pagesPackage/ucenter/Sansnn-uQRCode/components/uqrcode/uqrcode.vue new file mode 100644 index 0000000..4fefaac --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/components/uqrcode/uqrcode.vue @@ -0,0 +1,1131 @@ + + + + + diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/bridge/bridge-weex.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/bridge/bridge-weex.js new file mode 100644 index 0000000..27086ec --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/bridge/bridge-weex.js @@ -0,0 +1,241 @@ +const isWeex = typeof WXEnvironment !== 'undefined'; +const isWeexIOS = isWeex && /ios/i.test(WXEnvironment.platform); +const isWeexAndroid = isWeex && !isWeexIOS; + +import GLmethod from '../context-webgl/GLmethod'; + +const GCanvasModule = + (typeof weex !== 'undefined' && weex.requireModule) ? (weex.requireModule('gcanvas')) : + (typeof __weex_require__ !== 'undefined') ? (__weex_require__('@weex-module/gcanvas')) : {}; + +let isDebugging = false; + +let isComboDisabled = false; + +const logCommand = (function () { + const methodQuery = []; + Object.keys(GLmethod).forEach(key => { + methodQuery[GLmethod[key]] = key; + }) + const queryMethod = (id) => { + return methodQuery[parseInt(id)] || 'NotFoundMethod'; + } + const logCommand = (id, cmds) => { + const mId = cmds.split(',')[0]; + const mName = queryMethod(mId); + console.log(`=== callNative - componentId:${id}; method: ${mName}; cmds: ${cmds}`); + } + return logCommand; +})(); + +function joinArray(arr, sep) { + let res = ''; + for (let i = 0; i < arr.length; i++) { + if (i !== 0) { + res += sep; + } + res += arr[i]; + } + return res; +} + +const commandsCache = {} + +const GBridge = { + + callEnable: (ref, configArray) => { + + commandsCache[ref] = []; + + return GCanvasModule.enable({ + componentId: ref, + config: configArray + }); + }, + + callEnableDebug: () => { + isDebugging = true; + }, + + callEnableDisableCombo: () => { + isComboDisabled = true; + }, + + callSetContextType: function (componentId, context_type) { + GCanvasModule.setContextType(context_type, componentId); + }, + + callReset: function(id){ + GCanvasModule.resetComponent && canvasModule.resetComponent(componentId); + }, + + render: isWeexIOS ? function (componentId) { + return GCanvasModule.extendCallNative({ + contextId: componentId, + type: 0x60000001 + }); + } : function (componentId) { + return callGCanvasLinkNative(componentId, 0x60000001, 'render'); + }, + + render2d: isWeexIOS ? function (componentId, commands, callback) { + + if (isDebugging) { + console.log('>>> >>> render2d ==='); + console.log('>>> commands: ' + commands); + } + + GCanvasModule.render([commands, callback?true:false], componentId, callback); + + } : function (componentId, commands,callback) { + + if (isDebugging) { + console.log('>>> >>> render2d ==='); + console.log('>>> commands: ' + commands); + } + + callGCanvasLinkNative(componentId, 0x20000001, commands); + if(callback){ + callback(); + } + }, + + callExtendCallNative: isWeexIOS ? function (componentId, cmdArgs) { + + throw 'should not be here anymore ' + cmdArgs; + + } : function (componentId, cmdArgs) { + + throw 'should not be here anymore ' + cmdArgs; + + }, + + + flushNative: isWeexIOS ? function (componentId) { + + const cmdArgs = joinArray(commandsCache[componentId], ';'); + commandsCache[componentId] = []; + + if (isDebugging) { + console.log('>>> >>> flush native ==='); + console.log('>>> commands: ' + cmdArgs); + } + + const result = GCanvasModule.extendCallNative({ + "contextId": componentId, + "type": 0x60000000, + "args": cmdArgs + }); + + const res = result && result.result; + + if (isDebugging) { + console.log('>>> result: ' + res); + } + + return res; + + } : function (componentId) { + + const cmdArgs = joinArray(commandsCache[componentId], ';'); + commandsCache[componentId] = []; + + if (isDebugging) { + console.log('>>> >>> flush native ==='); + console.log('>>> commands: ' + cmdArgs); + } + + const result = callGCanvasLinkNative(componentId, 0x60000000, cmdArgs); + + if (isDebugging) { + console.log('>>> result: ' + result); + } + + return result; + }, + + callNative: function (componentId, cmdArgs, cache) { + + if (isDebugging) { + logCommand(componentId, cmdArgs); + } + + commandsCache[componentId].push(cmdArgs); + + if (!cache || isComboDisabled) { + return GBridge.flushNative(componentId); + } else { + return undefined; + } + }, + + texImage2D(componentId, ...args) { + if (isWeexIOS) { + if (args.length === 6) { + const [target, level, internalformat, format, type, image] = args; + GBridge.callNative( + componentId, + GLmethod.texImage2D + ',' + 6 + ',' + target + ',' + level + ',' + internalformat + ',' + format + ',' + type + ',' + image.src + ) + } else if (args.length === 9) { + const [target, level, internalformat, width, height, border, format, type, image] = args; + GBridge.callNative( + componentId, + GLmethod.texImage2D + ',' + 9 + ',' + target + ',' + level + ',' + internalformat + ',' + width + ',' + height + ',' + border + ',' + + + format + ',' + type + ',' + (image ? image.src : 0) + ) + } + } else if (isWeexAndroid) { + if (args.length === 6) { + const [target, level, internalformat, format, type, image] = args; + GCanvasModule.texImage2D(componentId, target, level, internalformat, format, type, image.src); + } else if (args.length === 9) { + const [target, level, internalformat, width, height, border, format, type, image] = args; + GCanvasModule.texImage2D(componentId, target, level, internalformat, width, height, border, format, type, (image ? image.src : 0)); + } + } + }, + + texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image) { + if (isWeexIOS) { + if (arguments.length === 8) { + GBridge.callNative( + componentId, + GLmethod.texSubImage2D + ',' + 6 + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset, + ',' + format + ',' + type + ',' + image.src + ) + } + } else if (isWeexAndroid) { + GCanvasModule.texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image.src); + } + }, + + bindImageTexture(componentId, src, imageId) { + GCanvasModule.bindImageTexture([src, imageId], componentId); + }, + + perloadImage([url, id], callback) { + GCanvasModule.preLoadImage([url, id], function (image) { + image.url = url; + image.id = id; + callback(image); + }); + }, + + measureText(text, fontStyle, componentId) { + return GCanvasModule.measureText([text, fontStyle], componentId); + }, + + getImageData (componentId, x, y, w, h, callback) { + GCanvasModule.getImageData([x, y,w,h],componentId,callback); + }, + + putImageData (componentId, data, x, y, w, h, callback) { + GCanvasModule.putImageData([x, y,w,h,data],componentId,callback); + }, + + toTempFilePath(componentId, x, y, width, height, destWidth, destHeight, fileType, quality, callback){ + GCanvasModule.toTempFilePath([x, y, width,height, destWidth, destHeight, fileType, quality], componentId, callback); + } +} + +export default GBridge; \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-2d/FillStyleLinearGradient.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-2d/FillStyleLinearGradient.js new file mode 100644 index 0000000..3e7f03a --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-2d/FillStyleLinearGradient.js @@ -0,0 +1,18 @@ +class FillStyleLinearGradient { + + constructor(x0, y0, x1, y1) { + this._start_pos = { _x: x0, _y: y0 }; + this._end_pos = { _x: x1, _y: y1 }; + this._stop_count = 0; + this._stops = [0, 0, 0, 0, 0]; + } + + addColorStop = function (pos, color) { + if (this._stop_count < 5 && 0.0 <= pos && pos <= 1.0) { + this._stops[this._stop_count] = { _pos: pos, _color: color }; + this._stop_count++; + } + } +} + +export default FillStyleLinearGradient; \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-2d/FillStylePattern.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-2d/FillStylePattern.js new file mode 100644 index 0000000..6e4f646 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-2d/FillStylePattern.js @@ -0,0 +1,8 @@ +class FillStylePattern { + constructor(img, pattern) { + this._style = pattern; + this._img = img; + } +} + +export default FillStylePattern; \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-2d/FillStyleRadialGradient.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-2d/FillStyleRadialGradient.js new file mode 100644 index 0000000..7790596 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-2d/FillStyleRadialGradient.js @@ -0,0 +1,17 @@ +class FillStyleRadialGradient { + constructor(x0, y0, r0, x1, y1, r1) { + this._start_pos = { _x: x0, _y: y0, _r: r0 }; + this._end_pos = { _x: x1, _y: y1, _r: r1 }; + this._stop_count = 0; + this._stops = [0, 0, 0, 0, 0]; + } + + addColorStop(pos, color) { + if (this._stop_count < 5 && 0.0 <= pos && pos <= 1.0) { + this._stops[this._stop_count] = { _pos: pos, _color: color }; + this._stop_count++; + } + } +} + +export default FillStyleRadialGradient; \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-2d/RenderingContext.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-2d/RenderingContext.js new file mode 100644 index 0000000..e6b8f48 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-2d/RenderingContext.js @@ -0,0 +1,666 @@ +import FillStylePattern from './FillStylePattern'; +import FillStyleLinearGradient from './FillStyleLinearGradient'; +import FillStyleRadialGradient from './FillStyleRadialGradient'; +import GImage from '../env/image.js'; +import { + ArrayBufferToBase64, + Base64ToUint8ClampedArray +} from '../env/tool.js'; + +export default class CanvasRenderingContext2D { + + _drawCommands = ''; + + _globalAlpha = 1.0; + + _fillStyle = 'rgb(0,0,0)'; + _strokeStyle = 'rgb(0,0,0)'; + + _lineWidth = 1; + _lineCap = 'butt'; + _lineJoin = 'miter'; + + _miterLimit = 10; + + _globalCompositeOperation = 'source-over'; + + _textAlign = 'start'; + _textBaseline = 'alphabetic'; + + _font = '10px sans-serif'; + + _savedGlobalAlpha = []; + + timer = null; + componentId = null; + + _notCommitDrawImageCache = []; + _needRedrawImageCache = []; + _redrawCommands = ''; + _autoSaveContext = true; + // _imageMap = new GHashMap(); + // _textureMap = new GHashMap(); + + constructor() { + this.className = 'CanvasRenderingContext2D'; + //this.save() + } + + setFillStyle(value) { + this.fillStyle = value; + } + + set fillStyle(value) { + this._fillStyle = value; + + if (typeof(value) == 'string') { + this._drawCommands = this._drawCommands.concat("F" + value + ";"); + } else if (value instanceof FillStylePattern) { + const image = value._img; + if (!image.complete) { + image.onload = () => { + var index = this._needRedrawImageCache.indexOf(image); + if (index > -1) { + this._needRedrawImageCache.splice(index, 1); + CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); + this._redrawflush(true); + } + } + this._notCommitDrawImageCache.push(image); + } else { + CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); + } + + //CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); + this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";"); + } else if (value instanceof FillStyleLinearGradient) { + var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + + value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," + + value._stop_count; + for (var i = 0; i < value._stop_count; ++i) { + command += ("," + value._stops[i]._pos + "," + value._stops[i]._color); + } + this._drawCommands = this._drawCommands.concat(command + ";"); + } else if (value instanceof FillStyleRadialGradient) { + var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r + .toFixed(2) + "," + + value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," + value._end_pos._r.toFixed(2) + "," + + value._stop_count; + for (var i = 0; i < value._stop_count; ++i) { + command += ("," + value._stops[i]._pos + "," + value._stops[i]._color); + } + this._drawCommands = this._drawCommands.concat(command + ";"); + } + } + + get fillStyle() { + return this._fillStyle; + } + + get globalAlpha() { + return this._globalAlpha; + } + + setGlobalAlpha(value) { + this.globalAlpha = value; + } + + set globalAlpha(value) { + this._globalAlpha = value; + this._drawCommands = this._drawCommands.concat("a" + value.toFixed(2) + ";"); + } + + + get strokeStyle() { + return this._strokeStyle; + } + + setStrokeStyle(value) { + this.strokeStyle = value; + } + + set strokeStyle(value) { + + this._strokeStyle = value; + + if (typeof(value) == 'string') { + this._drawCommands = this._drawCommands.concat("S" + value + ";"); + } else if (value instanceof FillStylePattern) { + CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); + this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";"); + } else if (value instanceof FillStyleLinearGradient) { + var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + + value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," + + value._stop_count; + + for (var i = 0; i < value._stop_count; ++i) { + command += ("," + value._stops[i]._pos + "," + value._stops[i]._color); + } + this._drawCommands = this._drawCommands.concat(command + ";"); + } else if (value instanceof FillStyleRadialGradient) { + var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r + .toFixed(2) + "," + + value._end_pos._x.toFixed(2) + "," + value._end_pos._y + ",".toFixed(2) + value._end_pos._r.toFixed(2) + "," + + value._stop_count; + + for (var i = 0; i < value._stop_count; ++i) { + command += ("," + value._stops[i]._pos + "," + value._stops[i]._color); + } + this._drawCommands = this._drawCommands.concat(command + ";"); + } + } + + get lineWidth() { + return this._lineWidth; + } + + setLineWidth(value) { + this.lineWidth = value; + } + + set lineWidth(value) { + this._lineWidth = value; + this._drawCommands = this._drawCommands.concat("W" + value + ";"); + } + + get lineCap() { + return this._lineCap; + } + + setLineCap(value) { + this.lineCap = value; + } + + set lineCap(value) { + this._lineCap = value; + this._drawCommands = this._drawCommands.concat("C" + value + ";"); + } + + get lineJoin() { + return this._lineJoin; + } + + setLineJoin(value) { + this.lineJoin = value + } + + set lineJoin(value) { + this._lineJoin = value; + this._drawCommands = this._drawCommands.concat("J" + value + ";"); + } + + get miterLimit() { + return this._miterLimit; + } + + setMiterLimit(value) { + this.miterLimit = value + } + + set miterLimit(value) { + this._miterLimit = value; + this._drawCommands = this._drawCommands.concat("M" + value + ";"); + } + + get globalCompositeOperation() { + return this._globalCompositeOperation; + } + + set globalCompositeOperation(value) { + + this._globalCompositeOperation = value; + let mode = 0; + switch (value) { + case "source-over": + mode = 0; + break; + case "source-atop": + mode = 5; + break; + case "source-in": + mode = 0; + break; + case "source-out": + mode = 2; + break; + case "destination-over": + mode = 4; + break; + case "destination-atop": + mode = 4; + break; + case "destination-in": + mode = 4; + break; + case "destination-out": + mode = 3; + break; + case "lighter": + mode = 1; + break; + case "copy": + mode = 2; + break; + case "xor": + mode = 6; + break; + default: + mode = 0; + } + + this._drawCommands = this._drawCommands.concat("B" + mode + ";"); + } + + get textAlign() { + return this._textAlign; + } + + setTextAlign(value) { + this.textAlign = value + } + + set textAlign(value) { + + this._textAlign = value; + let Align = 0; + switch (value) { + case "start": + Align = 0; + break; + case "end": + Align = 1; + break; + case "left": + Align = 2; + break; + case "center": + Align = 3; + break; + case "right": + Align = 4; + break; + default: + Align = 0; + } + + this._drawCommands = this._drawCommands.concat("A" + Align + ";"); + } + + get textBaseline() { + return this._textBaseline; + } + + setTextBaseline(value) { + this.textBaseline = value + } + + set textBaseline(value) { + this._textBaseline = value; + let baseline = 0; + switch (value) { + case "alphabetic": + baseline = 0; + break; + case "middle": + baseline = 1; + break; + case "top": + baseline = 2; + break; + case "hanging": + baseline = 3; + break; + case "bottom": + baseline = 4; + break; + case "ideographic": + baseline = 5; + break; + default: + baseline = 0; + break; + } + + this._drawCommands = this._drawCommands.concat("E" + baseline + ";"); + } + + get font() { + return this._font; + } + + setFontSize(size) { + var str = this._font; + var strs = str.trim().split(/\s+/); + for (var i = 0; i < strs.length; i++) { + var values = ["normal", "italic", "oblique", "normal", "small-caps", "normal", "bold", + "bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900", + "normal", "ultra-condensed", "extra-condensed", "condensed", "semi-condensed", + "semi-expanded", "expanded", "extra-expanded", "ultra-expanded" + ]; + + if (-1 == values.indexOf(strs[i].trim())) { + if (typeof size === 'string') { + strs[i] = size; + } else if (typeof size === 'number') { + strs[i] = String(size) + 'px'; + } + break; + } + } + this.font = strs.join(" "); + } + + set font(value) { + this._font = value; + this._drawCommands = this._drawCommands.concat("j" + value + ";"); + } + + setTransform(a, b, c, d, tx, ty) { + this._drawCommands = this._drawCommands.concat("t" + + (a === 1 ? "1" : a.toFixed(2)) + "," + + (b === 0 ? "0" : b.toFixed(2)) + "," + + (c === 0 ? "0" : c.toFixed(2)) + "," + + (d === 1 ? "1" : d.toFixed(2)) + "," + tx.toFixed(2) + "," + ty.toFixed(2) + ";"); + } + + transform(a, b, c, d, tx, ty) { + this._drawCommands = this._drawCommands.concat("f" + + (a === 1 ? "1" : a.toFixed(2)) + "," + + (b === 0 ? "0" : b.toFixed(2)) + "," + + (c === 0 ? "0" : c.toFixed(2)) + "," + + (d === 1 ? "1" : d.toFixed(2)) + "," + tx + "," + ty + ";"); + } + + resetTransform() { + this._drawCommands = this._drawCommands.concat("m;"); + } + + scale(a, d) { + this._drawCommands = this._drawCommands.concat("k" + a.toFixed(2) + "," + + d.toFixed(2) + ";"); + } + + rotate(angle) { + this._drawCommands = this._drawCommands + .concat("r" + angle.toFixed(6) + ";"); + } + + translate(tx, ty) { + this._drawCommands = this._drawCommands.concat("l" + tx.toFixed(2) + "," + ty.toFixed(2) + ";"); + } + + save() { + this._savedGlobalAlpha.push(this._globalAlpha); + this._drawCommands = this._drawCommands.concat("v;"); + } + + restore() { + this._drawCommands = this._drawCommands.concat("e;"); + this._globalAlpha = this._savedGlobalAlpha.pop(); + } + + createPattern(img, pattern) { + if (typeof img === 'string') { + var imgObj = new GImage(); + imgObj.src = img; + img = imgObj; + } + return new FillStylePattern(img, pattern); + } + + createLinearGradient(x0, y0, x1, y1) { + return new FillStyleLinearGradient(x0, y0, x1, y1); + } + + createRadialGradient = function(x0, y0, r0, x1, y1, r1) { + return new FillStyleRadialGradient(x0, y0, r0, x1, y1, r1); + }; + + createCircularGradient = function(x0, y0, r0) { + return new FillStyleRadialGradient(x0, y0, 0, x0, y0, r0); + }; + + strokeRect(x, y, w, h) { + this._drawCommands = this._drawCommands.concat("s" + x + "," + y + "," + w + "," + h + ";"); + } + + + clearRect(x, y, w, h) { + this._drawCommands = this._drawCommands.concat("c" + x + "," + y + "," + w + + "," + h + ";"); + } + + clip() { + this._drawCommands = this._drawCommands.concat("p;"); + } + + resetClip() { + this._drawCommands = this._drawCommands.concat("q;"); + } + + closePath() { + this._drawCommands = this._drawCommands.concat("o;"); + } + + moveTo(x, y) { + this._drawCommands = this._drawCommands.concat("g" + x.toFixed(2) + "," + y.toFixed(2) + ";"); + } + + lineTo(x, y) { + this._drawCommands = this._drawCommands.concat("i" + x.toFixed(2) + "," + y.toFixed(2) + ";"); + } + + quadraticCurveTo = function(cpx, cpy, x, y) { + this._drawCommands = this._drawCommands.concat("u" + cpx + "," + cpy + "," + x + "," + y + ";"); + } + + bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, ) { + this._drawCommands = this._drawCommands.concat( + "z" + cp1x.toFixed(2) + "," + cp1y.toFixed(2) + "," + cp2x.toFixed(2) + "," + cp2y.toFixed(2) + "," + + x.toFixed(2) + "," + y.toFixed(2) + ";"); + } + + arcTo(x1, y1, x2, y2, radius) { + this._drawCommands = this._drawCommands.concat("h" + x1 + "," + y1 + "," + x2 + "," + y2 + "," + radius + ";"); + } + + beginPath() { + this._drawCommands = this._drawCommands.concat("b;"); + } + + + fillRect(x, y, w, h) { + this._drawCommands = this._drawCommands.concat("n" + x + "," + y + "," + w + + "," + h + ";"); + } + + rect(x, y, w, h) { + this._drawCommands = this._drawCommands.concat("w" + x + "," + y + "," + w + "," + h + ";"); + } + + fill() { + this._drawCommands = this._drawCommands.concat("L;"); + } + + stroke(path) { + this._drawCommands = this._drawCommands.concat("x;"); + } + + arc(x, y, radius, startAngle, endAngle, anticlockwise) { + + let ianticlockwise = 0; + if (anticlockwise) { + ianticlockwise = 1; + } + + this._drawCommands = this._drawCommands.concat( + "y" + x.toFixed(2) + "," + y.toFixed(2) + "," + + radius.toFixed(2) + "," + startAngle + "," + endAngle + "," + ianticlockwise + + ";" + ); + } + + fillText(text, x, y) { + let tmptext = text.replace(/!/g, "!!"); + tmptext = tmptext.replace(/,/g, "!,"); + tmptext = tmptext.replace(/;/g, "!;"); + this._drawCommands = this._drawCommands.concat("T" + tmptext + "," + x + "," + y + ",0.0;"); + } + + strokeText = function(text, x, y) { + let tmptext = text.replace(/!/g, "!!"); + tmptext = tmptext.replace(/,/g, "!,"); + tmptext = tmptext.replace(/;/g, "!;"); + this._drawCommands = this._drawCommands.concat("U" + tmptext + "," + x + "," + y + ",0.0;"); + } + + measureText(text) { + return CanvasRenderingContext2D.GBridge.measureText(text, this.font, this.componentId); + } + + isPointInPath = function(x, y) { + throw new Error('GCanvas not supported yet'); + } + + drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) { + if (typeof image === 'string') { + var imgObj = new GImage(); + imgObj.src = image; + image = imgObj; + } + if (image instanceof GImage) { + if (!image.complete) { + imgObj.onload = () => { + var index = this._needRedrawImageCache.indexOf(image); + if (index > -1) { + this._needRedrawImageCache.splice(index, 1); + CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); + this._redrawflush(true); + } + } + this._notCommitDrawImageCache.push(image); + } else { + CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); + } + var srcArgs = [image, sx, sy, sw, sh, dx, dy, dw, dh]; + var args = []; + for (var arg in srcArgs) { + if (typeof(srcArgs[arg]) != 'undefined') { + args.push(srcArgs[arg]); + } + } + this.__drawImage.apply(this, args); + //this.__drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh); + } + } + + __drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) { + const numArgs = arguments.length; + + function drawImageCommands() { + + if (numArgs === 3) { + const x = parseFloat(sx) || 0.0; + const y = parseFloat(sy) || 0.0; + + return ("d" + image._id + ",0,0," + + image.width + "," + image.height + "," + + x + "," + y + "," + image.width + "," + image.height + ";"); + } else if (numArgs === 5) { + const x = parseFloat(sx) || 0.0; + const y = parseFloat(sy) || 0.0; + const width = parseInt(sw) || image.width; + const height = parseInt(sh) || image.height; + + return ("d" + image._id + ",0,0," + + image.width + "," + image.height + "," + + x + "," + y + "," + width + "," + height + ";"); + } else if (numArgs === 9) { + sx = parseFloat(sx) || 0.0; + sy = parseFloat(sy) || 0.0; + sw = parseInt(sw) || image.width; + sh = parseInt(sh) || image.height; + dx = parseFloat(dx) || 0.0; + dy = parseFloat(dy) || 0.0; + dw = parseInt(dw) || image.width; + dh = parseInt(dh) || image.height; + + return ("d" + image._id + "," + + sx + "," + sy + "," + sw + "," + sh + "," + + dx + "," + dy + "," + dw + "," + dh + ";"); + } + } + this._drawCommands += drawImageCommands(); + } + + _flush(reserve, callback) { + const commands = this._drawCommands; + this._drawCommands = ''; + CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback); + this._needRender = false; + } + + _redrawflush(reserve, callback) { + const commands = this._redrawCommands; + CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback); + if (this._needRedrawImageCache.length == 0) { + this._redrawCommands = ''; + } + } + + draw(reserve, callback) { + if (!reserve) { + this._globalAlpha = this._savedGlobalAlpha.pop(); + this._savedGlobalAlpha.push(this._globalAlpha); + this._redrawCommands = this._drawCommands; + this._needRedrawImageCache = this._notCommitDrawImageCache; + if (this._autoSaveContext) { + this._drawCommands = ("v;" + this._drawCommands); + this._autoSaveContext = false; + } else { + this._drawCommands = ("e;X;v;" + this._drawCommands); + } + } else { + this._needRedrawImageCache = this._needRedrawImageCache.concat(this._notCommitDrawImageCache); + this._redrawCommands += this._drawCommands; + if (this._autoSaveContext) { + this._drawCommands = ("v;" + this._drawCommands); + this._autoSaveContext = false; + } + } + this._notCommitDrawImageCache = []; + if (this._flush) { + this._flush(reserve, callback); + } + } + + getImageData(x, y, w, h, callback) { + CanvasRenderingContext2D.GBridge.getImageData(this.componentId, x, y, w, h, function(res) { + res.data = Base64ToUint8ClampedArray(res.data); + if (typeof(callback) == 'function') { + callback(res); + } + }); + } + + putImageData(data, x, y, w, h, callback) { + if (data instanceof Uint8ClampedArray) { + data = ArrayBufferToBase64(data); + CanvasRenderingContext2D.GBridge.putImageData(this.componentId, data, x, y, w, h, function(res) { + if (typeof(callback) == 'function') { + callback(res); + } + }); + } + } + + toTempFilePath(x, y, width, height, destWidth, destHeight, fileType, quality, callback) { + CanvasRenderingContext2D.GBridge.toTempFilePath(this.componentId, x, y, width, height, destWidth, destHeight, + fileType, quality, + function(res) { + if (typeof(callback) == 'function') { + callback(res); + } + }); + } +} diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/ActiveInfo.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/ActiveInfo.js new file mode 100644 index 0000000..b495129 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/ActiveInfo.js @@ -0,0 +1,11 @@ +export default class WebGLActiveInfo { + className = 'WebGLActiveInfo'; + + constructor({ + type, name, size + }) { + this.type = type; + this.name = name; + this.size = size; + } +} \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Buffer.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Buffer.js new file mode 100644 index 0000000..4800f67 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Buffer.js @@ -0,0 +1,21 @@ +import {getTransferedObjectUUID} from './classUtils'; + +const name = 'WebGLBuffer'; + +function uuid(id) { + return getTransferedObjectUUID(name, id); +} + +export default class WebGLBuffer { + className = name; + + constructor(id) { + this.id = id; + } + + static uuid = uuid; + + uuid() { + return uuid(this.id); + } +} \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Framebuffer.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Framebuffer.js new file mode 100644 index 0000000..28b46d3 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Framebuffer.js @@ -0,0 +1,21 @@ +import {getTransferedObjectUUID} from './classUtils'; + +const name = 'WebGLFrameBuffer'; + +function uuid(id) { + return getTransferedObjectUUID(name, id); +} + +export default class WebGLFramebuffer { + className = name; + + constructor(id) { + this.id = id; + } + + static uuid = uuid; + + uuid() { + return uuid(this.id); + } +} \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/GLenum.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/GLenum.js new file mode 100644 index 0000000..ac5544d --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/GLenum.js @@ -0,0 +1,298 @@ +export default { + "DEPTH_BUFFER_BIT": 256, + "STENCIL_BUFFER_BIT": 1024, + "COLOR_BUFFER_BIT": 16384, + "POINTS": 0, + "LINES": 1, + "LINE_LOOP": 2, + "LINE_STRIP": 3, + "TRIANGLES": 4, + "TRIANGLE_STRIP": 5, + "TRIANGLE_FAN": 6, + "ZERO": 0, + "ONE": 1, + "SRC_COLOR": 768, + "ONE_MINUS_SRC_COLOR": 769, + "SRC_ALPHA": 770, + "ONE_MINUS_SRC_ALPHA": 771, + "DST_ALPHA": 772, + "ONE_MINUS_DST_ALPHA": 773, + "DST_COLOR": 774, + "ONE_MINUS_DST_COLOR": 775, + "SRC_ALPHA_SATURATE": 776, + "FUNC_ADD": 32774, + "BLEND_EQUATION": 32777, + "BLEND_EQUATION_RGB": 32777, + "BLEND_EQUATION_ALPHA": 34877, + "FUNC_SUBTRACT": 32778, + "FUNC_REVERSE_SUBTRACT": 32779, + "BLEND_DST_RGB": 32968, + "BLEND_SRC_RGB": 32969, + "BLEND_DST_ALPHA": 32970, + "BLEND_SRC_ALPHA": 32971, + "CONSTANT_COLOR": 32769, + "ONE_MINUS_CONSTANT_COLOR": 32770, + "CONSTANT_ALPHA": 32771, + "ONE_MINUS_CONSTANT_ALPHA": 32772, + "BLEND_COLOR": 32773, + "ARRAY_BUFFER": 34962, + "ELEMENT_ARRAY_BUFFER": 34963, + "ARRAY_BUFFER_BINDING": 34964, + "ELEMENT_ARRAY_BUFFER_BINDING": 34965, + "STREAM_DRAW": 35040, + "STATIC_DRAW": 35044, + "DYNAMIC_DRAW": 35048, + "BUFFER_SIZE": 34660, + "BUFFER_USAGE": 34661, + "CURRENT_VERTEX_ATTRIB": 34342, + "FRONT": 1028, + "BACK": 1029, + "FRONT_AND_BACK": 1032, + "TEXTURE_2D": 3553, + "CULL_FACE": 2884, + "BLEND": 3042, + "DITHER": 3024, + "STENCIL_TEST": 2960, + "DEPTH_TEST": 2929, + "SCISSOR_TEST": 3089, + "POLYGON_OFFSET_FILL": 32823, + "SAMPLE_ALPHA_TO_COVERAGE": 32926, + "SAMPLE_COVERAGE": 32928, + "NO_ERROR": 0, + "INVALID_ENUM": 1280, + "INVALID_VALUE": 1281, + "INVALID_OPERATION": 1282, + "OUT_OF_MEMORY": 1285, + "CW": 2304, + "CCW": 2305, + "LINE_WIDTH": 2849, + "ALIASED_POINT_SIZE_RANGE": 33901, + "ALIASED_LINE_WIDTH_RANGE": 33902, + "CULL_FACE_MODE": 2885, + "FRONT_FACE": 2886, + "DEPTH_RANGE": 2928, + "DEPTH_WRITEMASK": 2930, + "DEPTH_CLEAR_VALUE": 2931, + "DEPTH_FUNC": 2932, + "STENCIL_CLEAR_VALUE": 2961, + "STENCIL_FUNC": 2962, + "STENCIL_FAIL": 2964, + "STENCIL_PASS_DEPTH_FAIL": 2965, + "STENCIL_PASS_DEPTH_PASS": 2966, + "STENCIL_REF": 2967, + "STENCIL_VALUE_MASK": 2963, + "STENCIL_WRITEMASK": 2968, + "STENCIL_BACK_FUNC": 34816, + "STENCIL_BACK_FAIL": 34817, + "STENCIL_BACK_PASS_DEPTH_FAIL": 34818, + "STENCIL_BACK_PASS_DEPTH_PASS": 34819, + "STENCIL_BACK_REF": 36003, + "STENCIL_BACK_VALUE_MASK": 36004, + "STENCIL_BACK_WRITEMASK": 36005, + "VIEWPORT": 2978, + "SCISSOR_BOX": 3088, + "COLOR_CLEAR_VALUE": 3106, + "COLOR_WRITEMASK": 3107, + "UNPACK_ALIGNMENT": 3317, + "PACK_ALIGNMENT": 3333, + "MAX_TEXTURE_SIZE": 3379, + "MAX_VIEWPORT_DIMS": 3386, + "SUBPIXEL_BITS": 3408, + "RED_BITS": 3410, + "GREEN_BITS": 3411, + "BLUE_BITS": 3412, + "ALPHA_BITS": 3413, + "DEPTH_BITS": 3414, + "STENCIL_BITS": 3415, + "POLYGON_OFFSET_UNITS": 10752, + "POLYGON_OFFSET_FACTOR": 32824, + "TEXTURE_BINDING_2D": 32873, + "SAMPLE_BUFFERS": 32936, + "SAMPLES": 32937, + "SAMPLE_COVERAGE_VALUE": 32938, + "SAMPLE_COVERAGE_INVERT": 32939, + "COMPRESSED_TEXTURE_FORMATS": 34467, + "DONT_CARE": 4352, + "FASTEST": 4353, + "NICEST": 4354, + "GENERATE_MIPMAP_HINT": 33170, + "BYTE": 5120, + "UNSIGNED_BYTE": 5121, + "SHORT": 5122, + "UNSIGNED_SHORT": 5123, + "INT": 5124, + "UNSIGNED_INT": 5125, + "FLOAT": 5126, + "DEPTH_COMPONENT": 6402, + "ALPHA": 6406, + "RGB": 6407, + "RGBA": 6408, + "LUMINANCE": 6409, + "LUMINANCE_ALPHA": 6410, + "UNSIGNED_SHORT_4_4_4_4": 32819, + "UNSIGNED_SHORT_5_5_5_1": 32820, + "UNSIGNED_SHORT_5_6_5": 33635, + "FRAGMENT_SHADER": 35632, + "VERTEX_SHADER": 35633, + "MAX_VERTEX_ATTRIBS": 34921, + "MAX_VERTEX_UNIFORM_VECTORS": 36347, + "MAX_VARYING_VECTORS": 36348, + "MAX_COMBINED_TEXTURE_IMAGE_UNITS": 35661, + "MAX_VERTEX_TEXTURE_IMAGE_UNITS": 35660, + "MAX_TEXTURE_IMAGE_UNITS": 34930, + "MAX_FRAGMENT_UNIFORM_VECTORS": 36349, + "SHADER_TYPE": 35663, + "DELETE_STATUS": 35712, + "LINK_STATUS": 35714, + "VALIDATE_STATUS": 35715, + "ATTACHED_SHADERS": 35717, + "ACTIVE_UNIFORMS": 35718, + "ACTIVE_ATTRIBUTES": 35721, + "SHADING_LANGUAGE_VERSION": 35724, + "CURRENT_PROGRAM": 35725, + "NEVER": 512, + "LESS": 513, + "EQUAL": 514, + "LEQUAL": 515, + "GREATER": 516, + "NOTEQUAL": 517, + "GEQUAL": 518, + "ALWAYS": 519, + "KEEP": 7680, + "REPLACE": 7681, + "INCR": 7682, + "DECR": 7683, + "INVERT": 5386, + "INCR_WRAP": 34055, + "DECR_WRAP": 34056, + "VENDOR": 7936, + "RENDERER": 7937, + "VERSION": 7938, + "NEAREST": 9728, + "LINEAR": 9729, + "NEAREST_MIPMAP_NEAREST": 9984, + "LINEAR_MIPMAP_NEAREST": 9985, + "NEAREST_MIPMAP_LINEAR": 9986, + "LINEAR_MIPMAP_LINEAR": 9987, + "TEXTURE_MAG_FILTER": 10240, + "TEXTURE_MIN_FILTER": 10241, + "TEXTURE_WRAP_S": 10242, + "TEXTURE_WRAP_T": 10243, + "TEXTURE": 5890, + "TEXTURE_CUBE_MAP": 34067, + "TEXTURE_BINDING_CUBE_MAP": 34068, + "TEXTURE_CUBE_MAP_POSITIVE_X": 34069, + "TEXTURE_CUBE_MAP_NEGATIVE_X": 34070, + "TEXTURE_CUBE_MAP_POSITIVE_Y": 34071, + "TEXTURE_CUBE_MAP_NEGATIVE_Y": 34072, + "TEXTURE_CUBE_MAP_POSITIVE_Z": 34073, + "TEXTURE_CUBE_MAP_NEGATIVE_Z": 34074, + "MAX_CUBE_MAP_TEXTURE_SIZE": 34076, + "TEXTURE0": 33984, + "TEXTURE1": 33985, + "TEXTURE2": 33986, + "TEXTURE3": 33987, + "TEXTURE4": 33988, + "TEXTURE5": 33989, + "TEXTURE6": 33990, + "TEXTURE7": 33991, + "TEXTURE8": 33992, + "TEXTURE9": 33993, + "TEXTURE10": 33994, + "TEXTURE11": 33995, + "TEXTURE12": 33996, + "TEXTURE13": 33997, + "TEXTURE14": 33998, + "TEXTURE15": 33999, + "TEXTURE16": 34000, + "TEXTURE17": 34001, + "TEXTURE18": 34002, + "TEXTURE19": 34003, + "TEXTURE20": 34004, + "TEXTURE21": 34005, + "TEXTURE22": 34006, + "TEXTURE23": 34007, + "TEXTURE24": 34008, + "TEXTURE25": 34009, + "TEXTURE26": 34010, + "TEXTURE27": 34011, + "TEXTURE28": 34012, + "TEXTURE29": 34013, + "TEXTURE30": 34014, + "TEXTURE31": 34015, + "ACTIVE_TEXTURE": 34016, + "REPEAT": 10497, + "CLAMP_TO_EDGE": 33071, + "MIRRORED_REPEAT": 33648, + "FLOAT_VEC2": 35664, + "FLOAT_VEC3": 35665, + "FLOAT_VEC4": 35666, + "INT_VEC2": 35667, + "INT_VEC3": 35668, + "INT_VEC4": 35669, + "BOOL": 35670, + "BOOL_VEC2": 35671, + "BOOL_VEC3": 35672, + "BOOL_VEC4": 35673, + "FLOAT_MAT2": 35674, + "FLOAT_MAT3": 35675, + "FLOAT_MAT4": 35676, + "SAMPLER_2D": 35678, + "SAMPLER_CUBE": 35680, + "VERTEX_ATTRIB_ARRAY_ENABLED": 34338, + "VERTEX_ATTRIB_ARRAY_SIZE": 34339, + "VERTEX_ATTRIB_ARRAY_STRIDE": 34340, + "VERTEX_ATTRIB_ARRAY_TYPE": 34341, + "VERTEX_ATTRIB_ARRAY_NORMALIZED": 34922, + "VERTEX_ATTRIB_ARRAY_POINTER": 34373, + "VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 34975, + "IMPLEMENTATION_COLOR_READ_TYPE": 35738, + "IMPLEMENTATION_COLOR_READ_FORMAT": 35739, + "COMPILE_STATUS": 35713, + "LOW_FLOAT": 36336, + "MEDIUM_FLOAT": 36337, + "HIGH_FLOAT": 36338, + "LOW_INT": 36339, + "MEDIUM_INT": 36340, + "HIGH_INT": 36341, + "FRAMEBUFFER": 36160, + "RENDERBUFFER": 36161, + "RGBA4": 32854, + "RGB5_A1": 32855, + "RGB565": 36194, + "DEPTH_COMPONENT16": 33189, + "STENCIL_INDEX8": 36168, + "DEPTH_STENCIL": 34041, + "RENDERBUFFER_WIDTH": 36162, + "RENDERBUFFER_HEIGHT": 36163, + "RENDERBUFFER_INTERNAL_FORMAT": 36164, + "RENDERBUFFER_RED_SIZE": 36176, + "RENDERBUFFER_GREEN_SIZE": 36177, + "RENDERBUFFER_BLUE_SIZE": 36178, + "RENDERBUFFER_ALPHA_SIZE": 36179, + "RENDERBUFFER_DEPTH_SIZE": 36180, + "RENDERBUFFER_STENCIL_SIZE": 36181, + "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE": 36048, + "FRAMEBUFFER_ATTACHMENT_OBJECT_NAME": 36049, + "FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL": 36050, + "FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE": 36051, + "COLOR_ATTACHMENT0": 36064, + "DEPTH_ATTACHMENT": 36096, + "STENCIL_ATTACHMENT": 36128, + "DEPTH_STENCIL_ATTACHMENT": 33306, + "NONE": 0, + "FRAMEBUFFER_COMPLETE": 36053, + "FRAMEBUFFER_INCOMPLETE_ATTACHMENT": 36054, + "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT": 36055, + "FRAMEBUFFER_INCOMPLETE_DIMENSIONS": 36057, + "FRAMEBUFFER_UNSUPPORTED": 36061, + "FRAMEBUFFER_BINDING": 36006, + "RENDERBUFFER_BINDING": 36007, + "MAX_RENDERBUFFER_SIZE": 34024, + "INVALID_FRAMEBUFFER_OPERATION": 1286, + "UNPACK_FLIP_Y_WEBGL": 37440, + "UNPACK_PREMULTIPLY_ALPHA_WEBGL": 37441, + "CONTEXT_LOST_WEBGL": 37442, + "UNPACK_COLORSPACE_CONVERSION_WEBGL": 37443, + "BROWSER_DEFAULT_WEBGL": 37444 +}; \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/GLmethod.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/GLmethod.js new file mode 100644 index 0000000..f2659be --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/GLmethod.js @@ -0,0 +1,142 @@ +let i = 1; + +const GLmethod = {}; + +GLmethod.activeTexture = i++; //1 +GLmethod.attachShader = i++; +GLmethod.bindAttribLocation = i++; +GLmethod.bindBuffer = i++; +GLmethod.bindFramebuffer = i++; +GLmethod.bindRenderbuffer = i++; +GLmethod.bindTexture = i++; +GLmethod.blendColor = i++; +GLmethod.blendEquation = i++; +GLmethod.blendEquationSeparate = i++; //10 +GLmethod.blendFunc = i++; +GLmethod.blendFuncSeparate = i++; +GLmethod.bufferData = i++; +GLmethod.bufferSubData = i++; +GLmethod.checkFramebufferStatus = i++; +GLmethod.clear = i++; +GLmethod.clearColor = i++; +GLmethod.clearDepth = i++; +GLmethod.clearStencil = i++; +GLmethod.colorMask = i++; //20 +GLmethod.compileShader = i++; +GLmethod.compressedTexImage2D = i++; +GLmethod.compressedTexSubImage2D = i++; +GLmethod.copyTexImage2D = i++; +GLmethod.copyTexSubImage2D = i++; +GLmethod.createBuffer = i++; +GLmethod.createFramebuffer = i++; +GLmethod.createProgram = i++; +GLmethod.createRenderbuffer = i++; +GLmethod.createShader = i++; //30 +GLmethod.createTexture = i++; +GLmethod.cullFace = i++; +GLmethod.deleteBuffer = i++; +GLmethod.deleteFramebuffer = i++; +GLmethod.deleteProgram = i++; +GLmethod.deleteRenderbuffer = i++; +GLmethod.deleteShader = i++; +GLmethod.deleteTexture = i++; +GLmethod.depthFunc = i++; +GLmethod.depthMask = i++; //40 +GLmethod.depthRange = i++; +GLmethod.detachShader = i++; +GLmethod.disable = i++; +GLmethod.disableVertexAttribArray = i++; +GLmethod.drawArrays = i++; +GLmethod.drawArraysInstancedANGLE = i++; +GLmethod.drawElements = i++; +GLmethod.drawElementsInstancedANGLE = i++; +GLmethod.enable = i++; +GLmethod.enableVertexAttribArray = i++; //50 +GLmethod.flush = i++; +GLmethod.framebufferRenderbuffer = i++; +GLmethod.framebufferTexture2D = i++; +GLmethod.frontFace = i++; +GLmethod.generateMipmap = i++; +GLmethod.getActiveAttrib = i++; +GLmethod.getActiveUniform = i++; +GLmethod.getAttachedShaders = i++; +GLmethod.getAttribLocation = i++; +GLmethod.getBufferParameter = i++; //60 +GLmethod.getContextAttributes = i++; +GLmethod.getError = i++; +GLmethod.getExtension = i++; +GLmethod.getFramebufferAttachmentParameter = i++; +GLmethod.getParameter = i++; +GLmethod.getProgramInfoLog = i++; +GLmethod.getProgramParameter = i++; +GLmethod.getRenderbufferParameter = i++; +GLmethod.getShaderInfoLog = i++; +GLmethod.getShaderParameter = i++; //70 +GLmethod.getShaderPrecisionFormat = i++; +GLmethod.getShaderSource = i++; +GLmethod.getSupportedExtensions = i++; +GLmethod.getTexParameter = i++; +GLmethod.getUniform = i++; +GLmethod.getUniformLocation = i++; +GLmethod.getVertexAttrib = i++; +GLmethod.getVertexAttribOffset = i++; +GLmethod.isBuffer = i++; +GLmethod.isContextLost = i++; //80 +GLmethod.isEnabled = i++; +GLmethod.isFramebuffer = i++; +GLmethod.isProgram = i++; +GLmethod.isRenderbuffer = i++; +GLmethod.isShader = i++; +GLmethod.isTexture = i++; +GLmethod.lineWidth = i++; +GLmethod.linkProgram = i++; +GLmethod.pixelStorei = i++; +GLmethod.polygonOffset = i++; //90 +GLmethod.readPixels = i++; +GLmethod.renderbufferStorage = i++; +GLmethod.sampleCoverage = i++; +GLmethod.scissor = i++; +GLmethod.shaderSource = i++; +GLmethod.stencilFunc = i++; +GLmethod.stencilFuncSeparate = i++; +GLmethod.stencilMask = i++; +GLmethod.stencilMaskSeparate = i++; +GLmethod.stencilOp = i++; //100 +GLmethod.stencilOpSeparate = i++; +GLmethod.texImage2D = i++; +GLmethod.texParameterf = i++; +GLmethod.texParameteri = i++; +GLmethod.texSubImage2D = i++; +GLmethod.uniform1f = i++; +GLmethod.uniform1fv = i++; +GLmethod.uniform1i = i++; +GLmethod.uniform1iv = i++; +GLmethod.uniform2f = i++; //110 +GLmethod.uniform2fv = i++; +GLmethod.uniform2i = i++; +GLmethod.uniform2iv = i++; +GLmethod.uniform3f = i++; +GLmethod.uniform3fv = i++; +GLmethod.uniform3i = i++; +GLmethod.uniform3iv = i++; +GLmethod.uniform4f = i++; +GLmethod.uniform4fv = i++; +GLmethod.uniform4i = i++; //120 +GLmethod.uniform4iv = i++; +GLmethod.uniformMatrix2fv = i++; +GLmethod.uniformMatrix3fv = i++; +GLmethod.uniformMatrix4fv = i++; +GLmethod.useProgram = i++; +GLmethod.validateProgram = i++; +GLmethod.vertexAttrib1f = i++; //new +GLmethod.vertexAttrib2f = i++; //new +GLmethod.vertexAttrib3f = i++; //new +GLmethod.vertexAttrib4f = i++; //new //130 +GLmethod.vertexAttrib1fv = i++; //new +GLmethod.vertexAttrib2fv = i++; //new +GLmethod.vertexAttrib3fv = i++; //new +GLmethod.vertexAttrib4fv = i++; //new +GLmethod.vertexAttribPointer = i++; +GLmethod.viewport = i++; + +export default GLmethod; \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/GLtype.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/GLtype.js new file mode 100644 index 0000000..695abcb --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/GLtype.js @@ -0,0 +1,23 @@ +const GLtype = {}; + +[ + "GLbitfield", + "GLboolean", + "GLbyte", + "GLclampf", + "GLenum", + "GLfloat", + "GLint", + "GLintptr", + "GLsizei", + "GLsizeiptr", + "GLshort", + "GLubyte", + "GLuint", + "GLushort" +].sort().map((typeName, i) => GLtype[typeName] = 1 >> (i + 1)); + +export default GLtype; + + + diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Program.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Program.js new file mode 100644 index 0000000..6f5691c --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Program.js @@ -0,0 +1,21 @@ +import {getTransferedObjectUUID} from './classUtils'; + +const name = 'WebGLProgram'; + +function uuid(id) { + return getTransferedObjectUUID(name, id); +} + +export default class WebGLProgram { + className = name; + + constructor(id) { + this.id = id; + } + + static uuid = uuid; + + uuid() { + return uuid(this.id); + } +} \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Renderbuffer.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Renderbuffer.js new file mode 100644 index 0000000..d3182ae --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Renderbuffer.js @@ -0,0 +1,21 @@ +import {getTransferedObjectUUID} from './classUtils'; + +const name = 'WebGLRenderBuffer'; + +function uuid(id) { + return getTransferedObjectUUID(name, id); +} + +export default class WebGLRenderbuffer { + className = name; + + constructor(id) { + this.id = id; + } + + static uuid = uuid; + + uuid() { + return uuid(this.id); + } +} \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/RenderingContext.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/RenderingContext.js new file mode 100644 index 0000000..5f9608f --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/RenderingContext.js @@ -0,0 +1,1191 @@ +import GLenum from './GLenum'; +import ActiveInfo from './ActiveInfo'; +import Buffer from './Buffer'; +import Framebuffer from './Framebuffer'; +import Renderbuffer from './Renderbuffer'; +import Texture from './Texture'; +import Program from './Program'; +import Shader from './Shader'; +import ShaderPrecisionFormat from './ShaderPrecisionFormat'; +import UniformLocation from './UniformLocation'; +import GLmethod from './GLmethod'; + +const processArray = (array, checkArrayType = false) => { + + function joinArray(arr, sep) { + let res = ''; + for (let i = 0; i < arr.length; i++) { + if (i !== 0) { + res += sep; + } + res += arr[i]; + } + return res; + } + + let type = 'Float32Array'; + if (checkArrayType) { + if (array instanceof Uint8Array) { + type = 'Uint8Array' + } else if (array instanceof Uint16Array) { + type = 'Uint16Array'; + } else if (array instanceof Uint32Array) { + type = 'Uint32Array'; + } else if (array instanceof Float32Array) { + type = 'Float32Array'; + } else { + throw new Error('Check array type failed. Array type is ' + typeof array); + } + } + + const ArrayTypes = { + Uint8Array: 1, + Uint16Array: 2, + Uint32Array: 4, + Float32Array: 14 + }; + return ArrayTypes[type] + ',' + btoa(joinArray(array, ',')) +} + +export default class WebGLRenderingContext { + + // static GBridge = null; + + className = 'WebGLRenderingContext'; + + constructor(canvas, type, attrs) { + this._canvas = canvas; + this._type = type; + this._version = 'WebGL 1.0'; + this._attrs = attrs; + this._map = new Map(); + + Object.keys(GLenum) + .forEach(name => Object.defineProperty(this, name, { + value: GLenum[name] + })); + } + + get canvas() { + return this._canvas; + } + + activeTexture = function (textureUnit) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.activeTexture + ',' + textureUnit, + true + ); + } + + attachShader = function (progarm, shader) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.attachShader + ',' + progarm.id + ',' + shader.id, + true + ); + } + + bindAttribLocation = function (program, index, name) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.bindAttribLocation + ',' + program.id + ',' + index + ',' + name, + true + ) + } + + bindBuffer = function (target, buffer) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.bindBuffer + ',' + target + ',' + (buffer ? buffer.id : 0), + true + ); + } + + bindFramebuffer = function (target, framebuffer) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.bindFramebuffer + ',' + target + ',' + (framebuffer ? framebuffer.id : 0), + true + ) + } + + bindRenderbuffer = function (target, renderBuffer) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.bindRenderbuffer + ',' + target + ',' + (renderBuffer ? renderBuffer.id : 0), + true + ) + } + + bindTexture = function (target, texture) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.bindTexture + ',' + target + ',' + (texture ? texture.id : 0), + true + ) + } + + blendColor = function (r, g, b, a) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.blendColor + ',' + target + ',' + r + ',' + g + ',' + b + ',' + a, + true + ) + } + + blendEquation = function (mode) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.blendEquation + ',' + mode, + true + ) + } + + blendEquationSeparate = function (modeRGB, modeAlpha) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.blendEquationSeparate + ',' + modeRGB + ',' + modeAlpha, + true + ) + } + + + blendFunc = function (sfactor, dfactor) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.blendFunc + ',' + sfactor + ',' + dfactor, + true + ); + } + + blendFuncSeparate = function (srcRGB, dstRGB, srcAlpha, dstAlpha) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.blendFuncSeparate + ',' + srcRGB + ',' + dstRGB + ',' + srcAlpha + ',' + dstAlpha, + true + ); + } + + bufferData = function (target, data, usage) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.bufferData + ',' + target + ',' + processArray(data, true) + ',' + usage, + true + ) + } + + bufferSubData = function (target, offset, data) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.bufferSubData + ',' + target + ',' + offset + ',' + processArray(data, true), + true + ) + } + + checkFramebufferStatus = function (target) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.checkFramebufferStatus + ',' + target + ); + return Number(result); + } + + clear = function (mask) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.clear + ',' + mask + ); + this._canvas._needRender = true; + } + + clearColor = function (r, g, b, a) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.clearColor + ',' + r + ',' + g + ',' + b, + true + ) + } + + clearDepth = function (depth) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.clearDepth + ',' + depth, + true + ) + } + + clearStencil = function (s) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.clearStencil + ',' + s + ); + } + + colorMask = function (r, g, b, a) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.colorMask + ',' + r + ',' + g + ',' + b + ',' + a + ) + } + + compileShader = function (shader) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.compileShader + ',' + shader.id, + true + ) + } + + compressedTexImage2D = function (target, level, internalformat, width, height, border, pixels) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.compressedTexImage2D + ',' + target + ',' + level + ',' + internalformat + ',' + + width + ',' + height + ',' + border + ',' + processArray(pixels), + true + ) + } + + compressedTexSubImage2D = function (target, level, xoffset, yoffset, width, height, format, pixels) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.compressedTexSubImage2D + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset + ',' + + width + ',' + height + ',' + format + ',' + processArray(pixels), + true + ) + } + + + copyTexImage2D = function (target, level, internalformat, x, y, width, height, border) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.copyTexImage2D + ',' + target + ',' + level + ',' + internalformat + ',' + x + ',' + y + ',' + + width + ',' + height + ',' + border, + true + ); + } + + copyTexSubImage2D = function (target, level, xoffset, yoffset, x, y, width, height) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.copyTexSubImage2D + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset + ',' + x + ',' + y + ',' + + width + ',' + height + ); + } + + createBuffer = function () { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.createBuffer + '' + ); + const buffer = new Buffer(result); + this._map.set(buffer.uuid(), buffer); + return buffer; + } + + createFramebuffer = function () { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.createFramebuffer + '' + ); + const framebuffer = new Framebuffer(result); + this._map.set(framebuffer.uuid(), framebuffer); + return framebuffer; + } + + + createProgram = function () { + const id = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.createProgram + '' + ); + const program = new Program(id); + this._map.set(program.uuid(), program); + return program; + } + + createRenderbuffer = function () { + const id = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.createRenderbuffer + '' + ) + const renderBuffer = new Renderbuffer(id); + this._map.set(renderBuffer.uuid(), renderBuffer); + return renderBuffer; + } + + createShader = function (type) { + const id = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.createShader + ',' + type + ) + const shader = new Shader(id, type); + this._map.set(shader.uuid(), shader); + return shader; + } + + createTexture = function () { + const id = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.createTexture + '' + ); + const texture = new Texture(id); + this._map.set(texture.uuid(), texture); + return texture; + } + + cullFace = function (mode) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.cullFace + ',' + mode, + true + ) + } + + + deleteBuffer = function (buffer) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.deleteBuffer + ',' + buffer.id, + true + ) + } + + deleteFramebuffer = function (framebuffer) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.deleteFramebuffer + ',' + framebuffer.id, + true + ) + } + + deleteProgram = function (program) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.deleteProgram + ',' + program.id, + true + ) + } + + deleteRenderbuffer = function (renderbuffer) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.deleteRenderbuffer + ',' + renderbuffer.id, + true + ) + } + + deleteShader = function (shader) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.deleteShader + ',' + shader.id, + true + ) + } + + deleteTexture = function (texture) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.deleteTexture + ',' + texture.id, + true + ) + } + + depthFunc = function (func) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.depthFunc + ',' + func + ) + } + + depthMask = function (flag) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.depthMask + ',' + Number(flag), + true + ) + } + + depthRange = function (zNear, zFar) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.depthRange + ',' + zNear + ',' + zFar, + true + ) + } + + detachShader = function (program, shader) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.detachShader + ',' + program.id + ',' + shader.id, + true + ) + } + + disable = function (cap) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.disable + ',' + cap, + true + ) + } + + disableVertexAttribArray = function (index) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.disableVertexAttribArray + ',' + index, + true + ); + } + + drawArrays = function (mode, first, count) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.drawArrays + ',' + mode + ',' + first + ',' + count + ) + this._canvas._needRender = true; + } + + drawElements = function (mode, count, type, offset) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.drawElements + ',' + mode + ',' + count + ',' + type + ',' + offset + ';' + ); + this._canvas._needRender = true; + } + + enable = function (cap) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.enable + ',' + cap, + true + ); + } + + enableVertexAttribArray = function (index) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.enableVertexAttribArray + ',' + index, + true + ) + } + + + flush = function () { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.flush + '' + ) + } + + framebufferRenderbuffer = function (target, attachment, textarget, texture, level) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.framebufferRenderbuffer + ',' + target + ',' + attachment + ',' + textarget + ',' + (texture ? texture.id : 0) + ',' + level, + true + ) + } + + framebufferTexture2D = function (target, attachment, textarget, texture, level) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.framebufferTexture2D + ',' + target + ',' + attachment + ',' + textarget + ',' + (texture ? texture.id : 0) + ',' + level, + true + ) + } + + frontFace = function (mode) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.frontFace + ',' + mode, + true + ) + } + + generateMipmap = function (target) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.generateMipmap + ',' + target, + true + ) + } + + getActiveAttrib = function (progarm, index) { + const resultString = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getActiveAttrib + ',' + progarm.id + ',' + index + ) + const [type, size, name] = resultString.split(','); + return new ActiveInfo({ + type: Number(type), + size: Number(size), + name + }); + } + + getActiveUniform = function (progarm, index) { + const resultString = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getActiveUniform + ',' + progarm.id + ',' + index + ); + const [type, size, name] = resultString.split(','); + return new ActiveInfo({ + type: Number(type), + size: Number(size), + name + }) + } + + getAttachedShaders = function (progarm) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getAttachedShaders + ',' + progarm.id + ); + const [type, ...ids] = result; + return ids.map(id => this._map.get(Shader.uuid(id))); + } + + getAttribLocation = function (progarm, name) { + return WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getAttribLocation + ',' + progarm.id + ',' + name + ) + } + + getBufferParameter = function (target, pname) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getBufferParameter + ',' + target + ',' + pname + ); + const [type, res] = getBufferParameter; + return res; + } + + getError = function () { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getError + '' + ) + return result; + } + + getExtension = function (name) { + return null; + } + + getFramebufferAttachmentParameter = function (target, attachment, pname) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getFramebufferAttachmentParameter + ',' + target + ',' + attachment + ',' + pname + ) + switch (pname) { + case GLenum.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + return this._map.get(Renderbuffer.uuid(result)) || this._map.get(Texture.uuid(result)) || null; + default: + return result; + } + } + + getParameter = function (pname) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getParameter + ',' + pname + ) + switch (pname) { + case GLenum.VERSION: + return this._version; + case GLenum.ARRAY_BUFFER_BINDING: // buffer + case GLenum.ELEMENT_ARRAY_BUFFER_BINDING: // buffer + return this._map.get(Buffer.uuid(result)) || null; + case GLenum.CURRENT_PROGRAM: // program + return this._map.get(Program.uuid(result)) || null; + case GLenum.FRAMEBUFFER_BINDING: // framebuffer + return this._map.get(Framebuffer.uuid(result)) || null; + case GLenum.RENDERBUFFER_BINDING: // renderbuffer + return this._map.get(Renderbuffer.uuid(result)) || null; + case GLenum.TEXTURE_BINDING_2D: // texture + case GLenum.TEXTURE_BINDING_CUBE_MAP: // texture + return this._map.get(Texture.uuid(result)) || null; + case GLenum.ALIASED_LINE_WIDTH_RANGE: // Float32Array + case GLenum.ALIASED_POINT_SIZE_RANGE: // Float32Array + case GLenum.BLEND_COLOR: // Float32Array + case GLenum.COLOR_CLEAR_VALUE: // Float32Array + case GLenum.DEPTH_RANGE: // Float32Array + case GLenum.MAX_VIEWPORT_DIMS: // Int32Array + case GLenum.SCISSOR_BOX: // Int32Array + case GLenum.VIEWPORT: // Int32Array + case GLenum.COMPRESSED_TEXTURE_FORMATS: // Uint32Array + default: + const [type, ...res] = result.split(','); + if (res.length === 1) { + return Number(res[0]); + } else { + return res.map(Number); + } + } + } + + getProgramInfoLog = function (progarm) { + return WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getProgramInfoLog + ',' + progarm.id + ) + } + + getProgramParameter = function (program, pname) { + const res = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getProgramParameter + ',' + program.id + ',' + pname + ); + + const [type, result] = res.split(',').map(i => parseInt(i)); + + if (type === 1) { + return Boolean(result); + } else if (type === 2) { + return result; + } else { + throw new Error('Unrecongized program paramater ' + res + ', type: ' + typeof res); + } + } + + + getRenderbufferParameter = function (target, pname) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getRenderbufferParameter + ',' + target + ',' + pname + ) + return result; + } + + + getShaderInfoLog = function (shader) { + return WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getShaderInfoLog + ',' + shader.id + ); + } + + getShaderParameter = function (shader, pname) { + return WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getShaderParameter + ',' + shader.id + ',' + pname + ) + } + + getShaderPrecisionFormat = function (shaderType, precisionType) { + const [rangeMin, rangeMax, precision] = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getShaderPrecisionFormat + ',' + shaderType + ',' + precisionType + ); + const shaderPrecisionFormat = new ShaderPrecisionFormat({ + rangeMin: Number(rangeMin), + rangeMax: Number(rangeMax), + precision: Number(precision) + }); + return shaderPrecisionFormat; + } + + getShaderSource = function (shader) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getShaderSource + ',' + shader.id + ); + return result; + } + + getSupportedExtensions = function () { + return Object.keys({}); + } + + getTexParameter = function (target, pname) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getTexParameter + ',' + target + ',' + pname + ) + return result; + } + + getUniformLocation = function (program, name) { + const id = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getUniformLocation + ',' + program.id + ',' + name + ); + if (id === -1) { + return null; + } else { + return new UniformLocation(Number(id)); + } + } + + getVertexAttrib = function (index, pname) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getVertexAttrib + ',' + index + ',' + pname + ); + switch (pname) { + case GLenum.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + return this._map.get(Buffer.uuid(result)) || null; + case GLenum.CURRENT_VERTEX_ATTRIB: // Float32Array + default: + return result; + } + } + + getVertexAttribOffset = function (index, pname) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.getVertexAttribOffset + ',' + index + ',' + pname + ) + return Number(result); + } + + isBuffer = function (buffer) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.isBuffer + ',' + buffer.id + ) + return Boolean(result); + } + + isContextLost = function () { + return false; + } + + isEnabled = function (cap) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.isEnabled + ',' + cap + ) + return Boolean(result); + } + + isFramebuffer = function (framebuffer) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.isFramebuffer + ',' + framebuffer.id + ) + return Boolean(result); + } + + isProgram = function (program) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.isProgram + ',' + program.id + ) + return Boolean(result); + } + + isRenderbuffer = function (renderBuffer) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.isRenderbuffer + ',' + renderbuffer.id + ) + return Boolean(result); + } + + isShader = function (shader) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.isShader + ',' + shader.id + ) + return Boolean(result); + } + + isTexture = function (texture) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.isTexture + ',' + texture.id + ); + return Boolean(result); + } + + lineWidth = function (width) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.lineWidth + ',' + width, + true + ) + } + + linkProgram = function (program) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.linkProgram + ',' + program.id, + true + ); + } + + + pixelStorei = function (pname, param) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.pixelStorei + ',' + pname + ',' + Number(param) + ) + } + + polygonOffset = function (factor, units) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.polygonOffset + ',' + factor + ',' + units + ) + } + + readPixels = function (x, y, width, height, format, type, pixels) { + const result = WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.readPixels + ',' + x + ',' + y + ',' + width + ',' + height + ',' + format + ',' + type + ) + return result; + } + + renderbufferStorage = function (target, internalFormat, width, height) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.renderbufferStorage + ',' + target + ',' + internalFormat + ',' + width + ',' + height, + true + ) + } + + sampleCoverage = function (value, invert) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.sampleCoverage + ',' + value + ',' + Number(invert), + true + ) + } + + scissor = function (x, y, width, height) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.scissor + ',' + x + ',' + y + ',' + width + ',' + height, + true + ) + } + + shaderSource = function (shader, source) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.shaderSource + ',' + shader.id + ',' + source + ) + } + + stencilFunc = function (func, ref, mask) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.stencilFunc + ',' + func + ',' + ref + ',' + mask, + true + ) + } + + stencilFuncSeparate = function (face, func, ref, mask) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.stencilFuncSeparate + ',' + face + ',' + func + ',' + ref + ',' + mask, + true + ) + } + + stencilMask = function (mask) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.stencilMask + ',' + mask, + true + ) + } + + stencilMaskSeparate = function (face, mask) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.stencilMaskSeparate + ',' + face + ',' + mask, + true + ) + } + + stencilOp = function (fail, zfail, zpass) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.stencilOp + ',' + fail + ',' + zfail + ',' + zpass + ) + } + + stencilOpSeparate = function (face, fail, zfail, zpass) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.stencilOp + ',' + face + ',' + fail + ',' + zfail + ',' + zpass, + true + ) + } + + texImage2D = function (...args) { + WebGLRenderingContext.GBridge.texImage2D(this._canvas.id, ...args); + } + + + texParameterf = function (target, pname, param) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.texParameterf + ',' + target + ',' + pname + ',' + param, + true + ) + } + + texParameteri = function (target, pname, param) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.texParameteri + ',' + target + ',' + pname + ',' + param + ) + } + + texSubImage2D = function (...args) { + WebGLRenderingContext.GBridge.texSubImage2D(this._canvas.id, ...args); + } + + uniform1f = function (location, v0) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniform1f + ',' + location.id + ',' + v0 + ) + } + + uniform1fv = function (location, value) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniform1fv + ',' + location.id + ',' + processArray(value), + true + ) + } + + uniform1i = function (location, v0) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniform1i + ',' + location.id + ',' + v0, + // true + ) + } + + uniform1iv = function (location, value) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniform1iv + ',' + location.id + ',' + processArray(value), + true + ) + } + + uniform2f = function (location, v0, v1) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniform2f + ',' + location.id + ',' + v0 + ',' + v1, + true + ) + } + + uniform2fv = function (location, value) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniform2fv + ',' + location.id + ',' + processArray(value), + true + ) + } + + uniform2i = function (location, v0, v1) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniform2i + ',' + location.id + ',' + v0 + ',' + v1, + true + ) + } + + uniform2iv = function (location, value) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniform2iv + ',' + location.id + ',' + processArray(value), + true + ) + } + + uniform3f = function (location, v0, v1, v2) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniform3f + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2, + true + ) + } + + uniform3fv = function (location, value) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniform3fv + ',' + location.id + ',' + processArray(value), + true + ) + } + + uniform3i = function (location, v0, v1, v2) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniform3i + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2, + true + ) + } + + uniform3iv = function (location, value) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniform3iv + ',' + location.id + ',' + processArray(value), + true + ) + } + + uniform4f = function (location, v0, v1, v2, v3) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniform4f + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2 + ',' + v3, + true + ) + } + + uniform4fv = function (location, value) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniform4fv + ',' + location.id + ',' + processArray(value), + true + ) + } + + uniform4i = function (location, v0, v1, v2, v3) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniform4i + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2 + ',' + v3, + true + ) + } + + uniform4iv = function (location, value) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniform4iv + ',' + location.id + ',' + processArray(value, true), + true + ) + } + + uniformMatrix2fv = function (location, transpose, value) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniformMatrix2fv + ',' + location.id + ',' + Number(transpose) + ',' + processArray(value), + true + ) + } + + uniformMatrix3fv = function (location, transpose, value) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniformMatrix3fv + ',' + location.id + ',' + Number(transpose) + ',' + processArray(value), + true + ) + } + + uniformMatrix4fv = function (location, transpose, value) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.uniformMatrix4fv + ',' + location.id + ',' + Number(transpose) + ',' + processArray(value), + true + ); + } + + useProgram = function (progarm) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.useProgram + ',' + progarm.id + '', + true + ) + } + + + validateProgram = function (program) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.validateProgram + ',' + program.id, + true + ) + } + + vertexAttrib1f = function (index, v0) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.vertexAttrib1f + ',' + index + ',' + v0, + true + ) + } + + vertexAttrib2f = function (index, v0, v1) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.vertexAttrib2f + ',' + index + ',' + v0 + ',' + v1, + true + ) + } + + vertexAttrib3f = function (index, v0, v1, v2) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.vertexAttrib3f + ',' + index + ',' + v0 + ',' + v1 + ',' + v2, + true + ) + } + + vertexAttrib4f = function (index, v0, v1, v2, v3) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.vertexAttrib4f + ',' + index + ',' + v0 + ',' + v1 + ',' + v2 + ',' + v3, + true + ) + } + + vertexAttrib1fv = function (index, value) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.vertexAttrib1fv + ',' + index + ',' + processArray(value), + true + ) + } + + vertexAttrib2fv = function (index, value) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.vertexAttrib2fv + ',' + index + ',' + processArray(value), + true + ) + } + + vertexAttrib3fv = function (index, value) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.vertexAttrib3fv + ',' + index + ',' + processArray(value), + true + ) + } + + vertexAttrib4fv = function (index, value) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.vertexAttrib4fv + ',' + index + ',' + processArray(value), + true + ) + } + + vertexAttribPointer = function (index, size, type, normalized, stride, offset) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.vertexAttribPointer + ',' + index + ',' + size + ',' + type + ',' + Number(normalized) + ',' + stride + ',' + offset, + true + ) + } + + viewport = function (x, y, width, height) { + WebGLRenderingContext.GBridge.callNative( + this._canvas.id, + GLmethod.viewport + ',' + x + ',' + y + ',' + width + ',' + height, + true + ) + } +} \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Shader.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Shader.js new file mode 100644 index 0000000..a763886 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Shader.js @@ -0,0 +1,22 @@ +import {getTransferedObjectUUID} from './classUtils'; + +const name = 'WebGLShader'; + +function uuid(id) { + return getTransferedObjectUUID(name, id); +} + +export default class WebGLShader { + className = name; + + constructor(id, type) { + this.id = id; + this.type = type; + } + + static uuid = uuid; + + uuid() { + return uuid(this.id); + } +} \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/ShaderPrecisionFormat.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/ShaderPrecisionFormat.js new file mode 100644 index 0000000..208d6c1 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/ShaderPrecisionFormat.js @@ -0,0 +1,11 @@ +export default class WebGLShaderPrecisionFormat { + className = 'WebGLShaderPrecisionFormat'; + + constructor({ + rangeMin, rangeMax, precision + }) { + this.rangeMin = rangeMin; + this.rangeMax = rangeMax; + this.precision = precision; + } +} \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Texture.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Texture.js new file mode 100644 index 0000000..de4d806 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/Texture.js @@ -0,0 +1,22 @@ +import {getTransferedObjectUUID} from './classUtils'; + +const name = 'WebGLTexture'; + +function uuid(id) { + return getTransferedObjectUUID(name, id); +} + +export default class WebGLTexture { + className = name; + + constructor(id, type) { + this.id = id; + this.type = type; + } + + static uuid = uuid; + + uuid() { + return uuid(this.id); + } +} \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/UniformLocation.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/UniformLocation.js new file mode 100644 index 0000000..f5e99dc --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/UniformLocation.js @@ -0,0 +1,22 @@ +import {getTransferedObjectUUID} from './classUtils'; + +const name = 'WebGLUniformLocation'; + +function uuid(id) { + return getTransferedObjectUUID(name, id); +} + +export default class WebGLUniformLocation { + className = name; + + constructor(id, type) { + this.id = id; + this.type = type; + } + + static uuid = uuid; + + uuid() { + return uuid(this.id); + } +} \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/classUtils.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/classUtils.js new file mode 100644 index 0000000..88716be --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/context-webgl/classUtils.js @@ -0,0 +1,3 @@ +export function getTransferedObjectUUID(name, id) { + return `${name.toLowerCase()}-${id}`; +} \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/env/canvas.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/env/canvas.js new file mode 100644 index 0000000..a8d9bb9 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/env/canvas.js @@ -0,0 +1,74 @@ +import GContext2D from '../context-2d/RenderingContext'; +import GContextWebGL from '../context-webgl/RenderingContext'; + +export default class GCanvas { + + // static GBridge = null; + + id = null; + + _needRender = true; + + constructor(id, { disableAutoSwap }) { + this.id = id; + + this._disableAutoSwap = disableAutoSwap; + if (disableAutoSwap) { + this._swapBuffers = () => { + GCanvas.GBridge.render(this.id); + } + } + } + + getContext(type) { + + let context = null; + + if (type.match(/webgl/i)) { + context = new GContextWebGL(this); + + context.componentId = this.id; + + if (!this._disableAutoSwap) { + const render = () => { + if (this._needRender) { + GCanvas.GBridge.render(this.id); + this._needRender = false; + } + } + setInterval(render, 16); + } + + GCanvas.GBridge.callSetContextType(this.id, 1); // 0 for 2d; 1 for webgl + } else if (type.match(/2d/i)) { + context = new GContext2D(this); + + context.componentId = this.id; + +// const render = ( callback ) => { +// +// const commands = context._drawCommands; +// context._drawCommands = ''; +// +// GCanvas.GBridge.render2d(this.id, commands, callback); +// this._needRender = false; +// } +// //draw方法触发 +// context._flush = render; +// //setInterval(render, 16); + + GCanvas.GBridge.callSetContextType(this.id, 0); + } else { + throw new Error('not supported context ' + type); + } + + return context; + + } + + reset() { + GCanvas.GBridge.callReset(this.id); + } + + +} \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/env/image.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/env/image.js new file mode 100644 index 0000000..9499a51 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/env/image.js @@ -0,0 +1,96 @@ +let incId = 1; + +const noop = function () { }; + +class GImage { + + static GBridge = null; + + constructor() { + this._id = incId++; + this._width = 0; + this._height = 0; + this._src = undefined; + this._onload = noop; + this._onerror = noop; + this.complete = false; + } + + get width() { + return this._width; + } + set width(v) { + this._width = v; + } + + get height() { + return this._height; + } + + set height(v) { + this._height = v; + } + + get src() { + return this._src; + } + + set src(v) { + + if (v.startsWith('//')) { + v = 'http:' + v; + } + + this._src = v; + + GImage.GBridge.perloadImage([this._src, this._id], (data) => { + if (typeof data === 'string') { + data = JSON.parse(data); + } + if (data.error) { + var evt = { type: 'error', target: this }; + this.onerror(evt); + } else { + this.complete = true; + this.width = typeof data.width === 'number' ? data.width : 0; + this.height = typeof data.height === 'number' ? data.height : 0; + var evt = { type: 'load', target: this }; + this.onload(evt); + } + }); + } + + addEventListener(name, listener) { + if (name === 'load') { + this.onload = listener; + } else if (name === 'error') { + this.onerror = listener; + } + } + + removeEventListener(name, listener) { + if (name === 'load') { + this.onload = noop; + } else if (name === 'error') { + this.onerror = noop; + } + } + + get onload() { + return this._onload; + } + + set onload(v) { + this._onload = v; + } + + get onerror() { + return this._onerror; + } + + set onerror(v) { + this._onerror = v; + } +} + +export default GImage; \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/env/tool.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/env/tool.js new file mode 100644 index 0000000..d3fb398 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/env/tool.js @@ -0,0 +1,24 @@ + +export function ArrayBufferToBase64 (buffer) { + var binary = ''; + var bytes = new Uint8ClampedArray(buffer); + for (var len = bytes.byteLength, i = 0; i < len; i++) { + binary += String.fromCharCode(bytes[i]); + } + return btoa(binary); +} + +export function Base64ToUint8ClampedArray(base64String) { + const padding = '='.repeat((4 - base64String.length % 4) % 4); + const base64 = (base64String + padding) + .replace(/\-/g, '+') + .replace(/_/g, '/'); + + const rawData = atob(base64); + const outputArray = new Uint8ClampedArray(rawData.length); + + for (let i = 0; i < rawData.length; ++i) { + outputArray[i] = rawData.charCodeAt(i); + } + return outputArray; +} \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/index.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/index.js new file mode 100644 index 0000000..a34ad58 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/gcanvas/index.js @@ -0,0 +1,39 @@ +import GCanvas from './env/canvas'; +import GImage from './env/image'; + +import GWebGLRenderingContext from './context-webgl/RenderingContext'; +import GContext2D from './context-2d/RenderingContext'; + +import GBridgeWeex from './bridge/bridge-weex'; + +export let Image = GImage; + +export let WeexBridge = GBridgeWeex; + +export function enable(el, { bridge, debug, disableAutoSwap, disableComboCommands } = {}) { + + const GBridge = GImage.GBridge = GCanvas.GBridge = GWebGLRenderingContext.GBridge = GContext2D.GBridge = bridge; + + GBridge.callEnable(el.ref, [ + 0, // renderMode: 0--RENDERMODE_WHEN_DIRTY, 1--RENDERMODE_CONTINUOUSLY + -1, // hybridLayerType: 0--LAYER_TYPE_NONE 1--LAYER_TYPE_SOFTWARE 2--LAYER_TYPE_HARDWARE + false, // supportScroll + false, // newCanvasMode + 1, // compatible + 'white',// clearColor + false // sameLevel: newCanvasMode = true && true => GCanvasView and Webview is same level + ]); + + if (debug === true) { + GBridge.callEnableDebug(); + } + if (disableComboCommands) { + GBridge.callEnableDisableCombo(); + } + + var canvas = new GCanvas(el.ref, { disableAutoSwap }); + canvas.width = el.style.width; + canvas.height = el.style.height; + + return canvas; +}; \ No newline at end of file diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/uqrcode/package.json b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/uqrcode/package.json new file mode 100644 index 0000000..0932bc4 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/uqrcode/package.json @@ -0,0 +1,12 @@ +{ + "name": "uqrcode", + "version": "3.5.1", + "description": "", + "main": "uqrcode.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/uqrcode/uqrcode.js b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/uqrcode/uqrcode.js new file mode 100644 index 0000000..dfb92d0 --- /dev/null +++ b/pagesPackage/ucenter/Sansnn-uQRCode/js_sdk/uqrcode/uqrcode.js @@ -0,0 +1,1606 @@ +//--------------------------------------------------------------------- +// uQRCode二维码生成插件 v4.0.6 +// +// uQRCode是一款基于Javascript环境开发的二维码生成插件,适用所有Javascript运行环境的前端应用和Node.js。 +// +// Copyright (c) Sansnn uQRCode All rights reserved. +// +// Licensed under the Apache License, Version 2.0. +// http://www.apache.org/licenses/LICENSE-2.0 +// +// github地址: +// https://github.com/Sansnn/uQRCode +// +// npm地址: +// https://www.npmjs.com/package/uqrcodejs +// +// uni-app插件市场地址: +// https://ext.dcloud.net.cn/plugin?id=1287 +// +// 复制使用请保留本段注释,感谢支持开源! +// +//--------------------------------------------------------------------- + +//--------------------------------------------------------------------- +// 当前文件格式为 es,将 bundle 保留为 ES 模块文件,适用于其他打包工具以及支持 + +``` + +### 简单用法 + +`uQRCode`基于`Canvas API`封装了一套方法,建议开发者使用`canvas`生成,一键调用,非常方便。以下是示例: + +- HTML示例 + - DOM部分 + ``` html + + ``` + + - JS部分 + ``` javascript + // 获取uQRCode实例 + var qr = new UQRCode(); + // 设置二维码内容 + qr.data = "https://uqrcode.cn/doc"; + // 设置二维码大小,必须与canvas设置的宽高一致 + qr.size = 200; + // 调用制作二维码方法 + qr.make(); + // 获取canvas元素 + var canvas = document.getElementById("qrcode"); + // 获取canvas上下文 + var canvasContext = canvas.getContext("2d"); + // 设置uQRCode实例的canvas上下文 + qr.canvasContext = canvasContext; + // 调用绘制方法将二维码图案绘制到canvas上 + qr.drawCanvas(); + ``` + +- uni-app示例 + - Template部分 + ``` html + + ``` + + - JS部分 + ``` javascript + onReady() { + // 获取uQRCode实例 + var qr = new UQRCode(); + // 设置二维码内容 + qr.data = "https://uqrcode.cn/doc"; + // 设置二维码大小,必须与canvas设置的宽高一致 + qr.size = 200; + // 调用制作二维码方法 + qr.make(); + // 获取canvas上下文 + var canvasContext = uni.createCanvasContext('qrcode', this); // 如果是组件,this必须传入 + // 设置uQRCode实例的canvas上下文 + qr.canvasContext = canvasContext; + // 调用绘制方法将二维码图案绘制到canvas上 + qr.drawCanvas(); + } + ``` + +- 微信小程序,推荐使用Canvas 2D,关于Canvas 2D的使用请参考微信开放文档。 + +### 高级用法 + +考虑到部分平台可能不支持`canvas`,所以`uQRCode`并没有强制要求和`canvas`一起使用,您还可以选择其他方式来生成二维码,例如使用`js`操作`dom`进行绘制或是使用`svg`绘制等。以下是示例: + +- uni-app v-for+view + +```html + + + +``` + +- js操作dom + +``` html + + + + + uQRCode二维码生成 + + +
+ + + + +``` + +- svg +``` html + + + + + uQRCode二维码生成 + + + + + + + +``` + +> 更多用法大家自行探索咯,期待分享哟~ + +### 导出临时文件路径 + +原生方式基于`Canvas`的,请自行参阅各平台`Canvas`的导出方式。以下是部分示例: + +- uni-app +```javascript +// 通过uni.createCanvasContext方式创建绘制上下文的,对应导出API为uni.canvasToTempFilePath +// 调用完ctx.draw()方法后不能第一时间导出,否则会异常,需要有一定的延时 +setTimeout(() => { + uni.canvasToTempFilePath( + { + canvasId: this.canvasId, + fileType: this.fileType, + width: this.canvasWidth, + height: this.canvasHeight, + success: res => { + console.log(res); + }, + fail: err => { + console.log(err); + } + }, + // this // 组件内使用必传当前实例 + ); +}, 300); +``` + +- Canvas2D +```javascript +// 得到base64 +console.log(canvas.toDataURL()); +// 得到buffer +console.log(canvas.toBuffer()); +``` + +### 保存二维码到本地相册 + +必须在导出临时文件路径成功后再执行保存。uni-app通用保存方式(H5除外): +```javascript +uni.saveImageToPhotosAlbum({ + filePath: tempFilePath, + success: res => { + console.log(res); + }, + fail: err => { + console.log(err); + } +}); +``` + +H5可以通过设置``标签`href`属性的方式进行保存: +```javascript +const aEle = document.createElement('a'); +aEle.download = 'uQRCode'; // 设置下载的文件名,默认是'下载' +aEle.href = tempFilePath; +document.body.appendChild(aEle); +aEle.click(); +aEle.remove(); // 下载之后把创建的元素删除 +``` +经过测试,PC端浏览器可以下载,部分安卓自带或第三方浏览器可以下载,安卓微信浏览器不适用,移动端iOS所有浏览器均不适用,差异较大,还是推荐各位导出文件给图片组件显示,然后提示用户通过长按图片进行保存这种方式。 + +## uni-app组件方式 + +### 安装 + +通过uni-app插件市场地址安装:[https://ext.dcloud.net.cn/plugin?id=1287](https://ext.dcloud.net.cn/plugin?id=1287)。详细配置请移步到:文档 > [uni-app组件](https://uqrcode.cn/doc/document/uni-app.html)。 + +### 引入 + +uni-app默认为easycom模式,可直接键入``标签。 + +### 简单用法 + +安装`uqrcode`组件后,在`template`中键入``。设置`ref`属性可使用组件内部方法,`canvas-id`属性为组件内部的canvas组件标识,`value`属性为二维码生成对应内容,`options`为配置选项,可配置二维码样式,绘制Logo等,详见:[options](https://uqrcode.cn/doc/document/uni-app.html#options) 。 + +``` html + +``` + +### 导出临时文件路径 + +为了保证方法调用成功,请在 [complete](https://uqrcode.cn/doc/document/uni-app.html#complete) 事件返回`success=true`后调用。 + +```javascript +// uqrcode为组件的ref名称 +this.$refs.uqrcode.toTempFilePath({ + success: res => { + console.log(res); + } +}); +``` + +### 保存二维码到本地相册 + +为了保证方法调用成功,请在 [complete](https://uqrcode.cn/doc/document/uni-app.html#complete) 事件返回`success=true`后调用。 + +```javascript +// uqrcode为组件的ref名称 +this.$refs.uqrcode.save({ + success: () => { + uni.showToast({ + icon: 'success', + title: '保存成功' + }); + } +}); +``` + +## 更多使用说明请前往官方文档查看:[https://uqrcode.cn/doc](https://uqrcode.cn/doc)。 \ No newline at end of file diff --git a/pagesPackage/ucenter/about/about.vue b/pagesPackage/ucenter/about/about.vue new file mode 100644 index 0000000..9619606 --- /dev/null +++ b/pagesPackage/ucenter/about/about.vue @@ -0,0 +1,235 @@ + + + diff --git a/pagesPackage/ucenter/invite/invite.vue b/pagesPackage/ucenter/invite/invite.vue new file mode 100644 index 0000000..5bb4df8 --- /dev/null +++ b/pagesPackage/ucenter/invite/invite.vue @@ -0,0 +1,179 @@ + + + diff --git a/pagesPackage/ucenter/pay/index.vue b/pagesPackage/ucenter/pay/index.vue new file mode 100644 index 0000000..8c14f3a --- /dev/null +++ b/pagesPackage/ucenter/pay/index.vue @@ -0,0 +1,503 @@ + + + + + diff --git a/pagesPackage/ucenter/read-news-log/read-news-log.vue b/pagesPackage/ucenter/read-news-log/read-news-log.vue new file mode 100644 index 0000000..ed7bfec --- /dev/null +++ b/pagesPackage/ucenter/read-news-log/read-news-log.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/pagesPackage/ucenter/settings/dc-push/push.js b/pagesPackage/ucenter/settings/dc-push/push.js new file mode 100644 index 0000000..9ad20d4 --- /dev/null +++ b/pagesPackage/ucenter/settings/dc-push/push.js @@ -0,0 +1,118 @@ +/** + * 判断Push是否开启 + */ +function isTurnedOnPush(){ + var isOn = undefined; + try{ + if('iOS' == plus.os.name){ + var types = 0; + var app = plus.ios.invoke('UIApplication', 'sharedApplication'); + var settings = plus.ios.invoke(app, 'currentUserNotificationSettings'); + if(settings){ + types = settings.plusGetAttribute('types'); + plus.ios.deleteObject(settings); + }else{ + types = plus.ios.invoke(app, 'enabledRemoteNotificationTypes'); + } + plus.ios.deleteObject(app); + isOn = (0!=types); + }else{ + var main = plus.android.runtimeMainActivity(); + var manager = plus.android.invoke('com.igexin.sdk.PushManager', 'getInstance'); + isOn = plus.android.invoke(manager, 'isPushTurnedOn', main); + } + }catch(e){ + console.error('exception in isTurnedOnPush@dc-push!!'); + } + return isOn; +} + +/** + * 打开Push + * Android平台 - 打开个推(UniPush)的推送通道 + * iOS平台 - 如果开启通知功能,则打开应用的设置页面引导用户开启通知 + */ +function turnOnPush(){ + try{ + if('iOS' == plus.os.name){ + // 如果设置中没有开启通知,则打开应用的设置界面 + if(!isTurnedOnPush()){ + settingInIos(); + } + }else{ + var main = plus.android.runtimeMainActivity(); + var manager = plus.android.invoke('com.igexin.sdk.PushManager', 'getInstance'); + plus.android.invoke(manager, 'turnOnPush', main); + } + }catch(e){ + console.error('exception in turnOnPush@dc-push!!'); + } +} + +/** + * 关闭Push + * Android平台 - 关闭个推(UniPush)的推送通道 + * iOS平台 - 不做任何操作 + */ +function trunOffPush(){ + try{ + if('iOS' == plus.os.name){ + // 这里不做任何操作(不引导用户关闭应用的推送能力),应该通知业务服务器不向此用户下发推送消息 + }else{ + var main = plus.android.runtimeMainActivity(); + var manager = plus.android.invoke('com.igexin.sdk.PushManager', 'getInstance'); + plus.android.invoke(manager, 'turnOffPush', main); + } + }catch(e){ + console.error('exception in trunOffPush@dc-push!!'); + } +} + +/** + * iOS平台打开应用设置界面 + */ +function settingInIos(){ + try{ + if('iOS' == plus.os.name){ + var app = plus.ios.invoke('UIApplication', 'sharedApplication'); + var setting = plus.ios.invoke('NSURL', 'URLWithString:', 'app-settings:'); + plus.ios.invoke(app, 'openURL:', setting); + plus.ios.deleteObject(setting); + plus.ios.deleteObject(app); + } + }catch(e){ + console.error('exception in settingInIos@dc-push!!'); + } +} +/** + * android打开应用设置页面 + */ +function settingInAndroid(){ + if (uni.getSystemInfoSync().platform == "android") { + var main = plus.android.runtimeMainActivity(); + var Intent = plus.android.importClass('android.content.Intent'); + var Settings = plus.android.importClass('android.provider.Settings'); + var intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + // 安卓跳转设置页面详细查看(https://ask.dcloud.net.cn/question/14732) + main.startActivity(intent); + } +} +/** + * 打开应用设置界面 + */ +function setting(){ + if (uni.getSystemInfoSync().platform == "ios") { + settingInIos(); + } + if (uni.getSystemInfoSync().platform == "android") { + settingInAndroid(); + } +} + +export default { + isOn: isTurnedOnPush, + iosSetting: settingInIos, + on: turnOnPush, + off: trunOffPush, + setting:setting +} diff --git a/pagesPackage/ucenter/settings/settings.vue b/pagesPackage/ucenter/settings/settings.vue new file mode 100644 index 0000000..897a373 --- /dev/null +++ b/pagesPackage/ucenter/settings/settings.vue @@ -0,0 +1,304 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/uni-agree/uni-agree.nvue b/pagesPackage/uni-agree/uni-agree.nvue new file mode 100644 index 0000000..5e43891 --- /dev/null +++ b/pagesPackage/uni-agree/uni-agree.nvue @@ -0,0 +1,139 @@ + + + + + \ No newline at end of file diff --git a/pagesPackage/uni-agree/utils/uni-agree.js b/pagesPackage/uni-agree/utils/uni-agree.js new file mode 100644 index 0000000..3d1340c --- /dev/null +++ b/pagesPackage/uni-agree/utils/uni-agree.js @@ -0,0 +1,11 @@ +export default function(){ + console.log(uni.getSystemInfoSync().platform) + let userprotocol = uni.getStorageSync('userprotocol'); + console.log('userprotocol',userprotocol); + if(!userprotocol){ + uni.navigateTo({ + url:'/pages/uni-agree/uni-agree', + animationType:"none" + }) + } +} \ No newline at end of file diff --git a/static/app-plus/sharemenu/copyurl.png b/static/app-plus/sharemenu/copyurl.png new file mode 100644 index 0000000000000000000000000000000000000000..270e6aee210a59d179d67ac3e44d169d030a8721 GIT binary patch literal 920 zcmeAS@N?(olHy`uVBq!ia0vp^c_7Te3?x6cUOUOaz^E4B6XNQ6=HkF2pnE8Bz@}Gk zp8xpy_Sf%|A3k0F{N?_)?+4#~2)S_e>gTVwzJ6Qr{MG)q?;m~t@#o*aWzS!B-+xqg z^X}CzU%k&=>U;3`_rHJTx9}APPW}?eP%ZVY_k7_$;nO?9fAqh7qqY5p*hk}xKrdkEKlF5Q49U3n_Eu!LW1z&b zkFlCsT1yx;4||p_^0D+XIlp*IW=j2k{fW<dy$>XaKkDs^#R=bv3@9`&Y}7 zY1gxM&RjELno;aoRvV|Jc?Zh#ygc$=X+QsR;+f4k|2!YTOTowPS?-Tz*!26p#p(u= zPp4W%c$T-s?MP%i_4UlnI~wP5R~N)Fo{oNa#zJr1CLfXGuFhu^8+eU)PiE@$K5@IL zGHG^-m`ZvglT@MXBQDjr+b7rR^j%+D!TYr0AJ?hEy5P2=KZ@*6e>}CF@_2T6K%ae_ zgXKK?_M$oSr!JJSKezRCuFSr&D_qCW z%YA)<@!!Ya@-fYR-xtJOzCO|7(LbB=%~wUVMPF!K=FDTL){AkKcRsj0?t`Lq)w1{L zYHv6gEjJn@v#ZqpsO)*=RJhL1XZC@^x>w&jXYBhPIZNuysp~p>=gtyY#6J0j<%(5) zr)75QDJfs$z)*F9c^srsB%zyho<2Mi2u_+fvA6fJK#2uN9rgyf48(D5? nF}(AP-$~3&&7^(hvxojwds$A2CHpo46Apu?tDnm{r-UW|->C5L literal 0 HcmV?d00001 diff --git a/static/app-plus/sharemenu/more.png b/static/app-plus/sharemenu/more.png new file mode 100644 index 0000000000000000000000000000000000000000..d9cf62b9ecd46237986434e0af4f3f9bc36dc081 GIT binary patch literal 1436 zcmd6n`#aMM0LB-I)xpRjBVw!UF+)g*;}#a0QEKHJms74ea!chJD+;+jsgcXD_9$8` z=6hIVm^j;7jAw3Z?VuS+vz%Iv{)_W@p7;Iy{{HY5VEw(+ckAy4fk5g$-X6GZ$N!9) z@^-HgCRiZQ4p*#ikf&FI@7DhkQhhy%M5?X%Nqv32LZPT366Fic*o{gD(gyb)Y-*mBD#_ z=TS{Jj}DvF<|kO1)a0a;;uUUXHM$p+*GipEzM9Zc z!uW7T&(Pd|VbE<}xPrZ&PAQwB+4S1$Tvq#Xs+=(TR#4X(xGD| zx-i&D_RURebMwQw0fig|Rs+wZ=@wKYz_|CuHi>n9clYFbK4uElQO{3a?dezd=scp~ zQkV|QrU7B3t{-3Zx}4D(&V}h{)s?&}Cf|}m&%)F70JV66pUJn}`DX90mK#UTX%Ia& zf^%NoN!uE*HC}oJe|O!J&)5}>!i;u|TpcvCI^NJ|Yi7km4(%roe8?}GXdLiuF^H_z zE;q&Cd0EV-<6Rt@w=GW+dI@nXBLh}WOcUemAelbEDvzTH`u5^uLse~aVqc(AhLsc{?7}H zztf-MR}m?EO{JAy)fgtn_L^l3RM}lI43jOrdqLfw5r!wC*t1S|9s`@BN85{{y8n%R zjd15ouwV|YkuO;WkgjM0Y*NN+la(}+LDjRDKkDqADJ{O008Zh}Cf?~t<(hjZA8}4| z<1KPJsE}g4ZZHM#^3dmUZH@I$K{#aDY)G-_esM*Wc8*}2Z4s*4kg_qu_#BLW6t7v3 ztHnAzof1rmby&)cyw&?6r5iK%X=HPSXcJ@iS5&vlE?0PM0=wy3JrH0&pIZ60<~>x_ zkgMD59=@v?2H{Pq*f^Z^MLS6P!yAIu$S@4F!BQy_M<@}xn&FsJYRTPwMWN-=#aGs_ z9Pa{z4^;~}W>`(EdcNB)l?ZUD0;fg);0nKr$-t(U_fI48rmy9@mhHO|OIn2_O$Qo= zSKfVRst@LV{PDp#yI1a@rCG;#kOm49n;Mb6N0|24w1$1LBOiD;3k|uQh_tG#0z$9CswL8sIz4Ml$`- z?P_7psuKqe>zF7X3kp9-&-O^Y{!7V)@5+Bv+MP&_wM9VVpOy5ZjOpg;!>DfMU)_8T z1~!;=hH8VT;=0pSpM9&X6YquWIG0t?M;Ru}SAJGX*vcuHLunC4yg6@qqi>$?DZMnA rrqXUAtHxud9bmLrJrac4vOFc?|KhfSrO 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 literal 0 HcmV?d00001 diff --git a/static/app-plus/sharemenu/qq.png b/static/app-plus/sharemenu/qq.png new file mode 100644 index 0000000000000000000000000000000000000000..28e745655ba66f66917144ff8ef4f4eb39395a15 GIT binary patch literal 1605 zcmdT@`8(7J93I4?R5DbwijvK`71?z(t{h<;C5#*y#}BfQO3F;Qtz3y=J!dDu=aUK#m0NJ&Ge@w&1jo=1=t^?@rOn4hY zd$~wC8y?v}9u7kYivCyy?80bh9|R)k`&oEu6H%iAbS|<3p&#d9#wKFc2nO~-tS!X7 z1JtPnR`*aCL96EB)G>&;g*1Id%$q=+I$&iN1z_~?D0I0F@aP0h8o_t7uuB^lKLq{y z1uA60DWg!u9J~jk18Ybw1OB>;)-J&5;}ClXsau3ICZKE0pk@u=(he$D14HY`zPZJ3 zh<`VDwFwNOLmE^dZU{=BfV64=m1^L6D>%BbZy)`<1mEd_)Tw}B1JJdKyq<=6AW9j5 z#&}4>BCK5t-0A=$1|WP3*tUX%_d^9tICBEx>>x3NkaaT{)(`D}3v~e|c7dPf;iqE| zp&d*dhH#(3?h>c_`+ZyqwYPBqPNm8S*_{s=KTgni2ok=7>_+MNZivS~S{5_&lY9Xub}C0TP`c(ytF zbPJZ;y!Y-wFx@sG=PFyLt(2^uyjy|>Gk>#^g6BR;8|0aR$(zl2$Nc6parM+QMIA{V zfg<9%f`+PHKb%|K3yvydJ=XP!^I&zJO!O{bc+p-dE~rKDIC_FTmj)RZ+n?Nt3H4os zT@&%Q$@z19x4CT|XDfQM!KoE$c96>e$8q$A=B!fJ^EV&ee4DqO29?wg7Gl9pK+3-H0SmgBa-uz6RsvX;243eWloPT)Wme=XK|wVY7Se7Wno)_)e3b( z#Z#9RSTRk(#llp1_40<42g`hHQIU&|c)r%*=cE!5N_UXlEYHl7I!aL%P-h6sISI88 zB|@e>sdAcS+tR|>la`n3(l7)>!zB05vs(;LlY;0W#?R*z$(aN+z?q=^{b)hLQO?$Z z2cO2Z^Boy{HF^Gqf}?TX?M5_W*Mh18NuO6k#xid05kv%i)BEH^=}`bz(|*yfAY#md zMtrm|ns+vzoocgzx22JdN~GAU-Yyf#L9;2@7Bu~UJtf&A&#i;rhv^4d6`_|tC=8^! z#;(Mq^6TkgGZ?WoBsD@-agqBPk8gUd*2bKi<;r6AI>?0B7y8_ zd=UxStoJ+`cw|XQo4(UR`qDpKp!!hmhcW#(L~IKo2bNJZsG2VGuSOJ|#=P%| z4j>)`!qxN6?+twp?au@PS z-(h*G*LdX#(obp1-Q|^$HzLXDrzEqcUZ^|M<8RdImU{N(inzDz8EqK`xC}knA(_>8+pY43$IL@vH$=8 literal 0 HcmV?d00001 diff --git a/static/app-plus/sharemenu/wechatfriend.png b/static/app-plus/sharemenu/wechatfriend.png new file mode 100644 index 0000000000000000000000000000000000000000..e6af3472fe40c35b6a31e2ceb4a0d64a4f1db3db GIT binary patch literal 2024 zcmdUv`#;l-0>>wpdb&8B6wwVuPpao+MQ%@zyNHDelWUs9Tr*_lp(8!Iq9(Z%$6Z2U z%Uq(1T(ZsWyV-_~hV46Jw%N?aAdp?o7wtVa zJNm!gro5Sg`#>KAvW4yL>g8~TX#W4AP4fRmU0hpy{4*zLJgkNP(SF4BPgaH{*{*p3 zzq&39qoZ*AR_Y3ER1BDsE+D8OzLcOT3G>O%+=98+mE79z%Y9u-pKXU-YQc9aiWQc0 z`ahh?uB9&@`E4^&w(A%?Y3eS9nSN{XcFY9&IXnO2sJlDh`*OC(b<9h)E?eJNM^J;y zIn~wNx;n72k=JZFWS`2+I7_nnWBB5Evb7o6#(LO!li6y>fgzbBi-x}nda`Do=CJdy zvjt0QOHzeYBp2~yy!Q*u@^yLJV&_}1{)?c8w!$C^$&Y?!17hm1XjG&S$4w+LrL3Q; z?EBM?(peAClbCrKhqtz{Bp0Ny?sqSJO`N(D!HDfx?24aEzD5i0TOJq`lE%c8A<@XR zbcVJTyK+{7 z>`Le3OzXgXV-~GY9cAVg?a4zjrJ4B4UrN>DN=LAQ&Vh+VneF3(Z{&Q0iF*r9(eoyjMU zSZJtOruZH2*LAoImhYF&-#m20PCKBx8eIlF@pHO|c4$h1HBj-_CJGeTla^DdWi{v| z{NbP$b?s9F#dc@Gz-UC1x<UimZ6F9cFA+sVoG)E<1NQP?jpS_z+G1m+RG z__W}|)l_4l-k1v(DP8FA#RMd-_f)lFd>|dk#|SG+=lkmhx+3YKD&(ze+#Cm;PnGW1 z4qX`FHoWY(o5o=+Nc!;gO86+a`aV9Y$MAjCOB6_pqv3c|#V)gQD9QiW2mx!R(O0DP zD0b}*d+T!Dr7k4%JA6VqjkdfEU@4*J`OF8u$`Qw2x9g`INE``7MrD5R{$_tDEel{b z1Ks%!*AbHIs-|>J?7IiX4N8$r&2XX_!h3~x&daK>ohv?S3f3OEq3>h=Qt!uBU2$aT zbX!m^CAlk)F=N{O>ScOFr|nt)RK$4A_I!J#+iqoAJB(5EAn&Z+KQ(@9`K%+H$U3{5 zW0LtJb85t39+)@@>M{JeNAU=Z<(|Rv$~OCEqJD2obAyw~39HB3KpCZb z<@|Czt*XOJcqR*y YoKL7YX6RVB`D74h2bg`mZScLn0aHIo8~^|S literal 0 HcmV?d00001 diff --git a/static/app-plus/sharemenu/wechatmoments.png b/static/app-plus/sharemenu/wechatmoments.png new file mode 100644 index 0000000000000000000000000000000000000000..6445df06def179c84852804a4701a5b29efd6e9b GIT binary patch literal 1758 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 D?n@74 literal 0 HcmV?d00001 diff --git a/static/h5/download-app/android.png b/static/h5/download-app/android.png new file mode 100644 index 0000000000000000000000000000000000000000..41e4a038932068d2362d16a07b23aa7cae1a000f GIT binary patch literal 1033 zcmeAS@N?(olHy`uVBq!ia0vp^ARNHK3?%njU0TGzz{nKf6XNP#;PZcEgFBkZD}aF# zS`y?J%<%ZCL4j7teuui%U#GskZL#$E`m=5+CudeDIGvtb78TJx|9F<4-fpkYB?&i+ z`i(rgU!G?(b6I?MXR}R)gqq6M-@RdZ*ONqK4lfs*9LFSdkw+u#=ft_eA_@Ew5fNogOkuC2aPGxhe8u>y<~X%MXst~>b771>z7W_xoM@VdAX!b z@@02;{?~ceUSCaQNUEMBnUNFPQp=`2r|kN(^ws&>vr9v*kJ;z^+Z#Fic%%HjZ9F?_ z^9y%8yk{p{ymz;KgMeK9E~&js4phE+7UkBnkKx0Pi>^+;%Rcbc?Ag-uy>a`(CDXn8 zU)zP8p7FF;(eB`#+ZzR93LZNJ1fIF-E`Iw-yS#|x%HQct4*jaEdyTgzbuH$S7MNJJ zKJxOBtg|w2_N{vKdf)Sq&MEWNJlVE$REdPl)qI-L!Yg{#jL}-;jlkvYPeryc9B5k9 z5in^PCo^+c)xTRa!Y>DF`Wf!|-1~8#-ltV>Oyf^FPVIVP{b_2<)QqXJ_aA+!%WpCJ zbLfiwCff_?b(1{BE)>lDd;VJc&6>Dfy$jru=gd7nNjz&y?yU9KI3CZmE#1{V=lNgP zF8!0UYC3cM6n=hgJiA3V^O| zo@BvnIDKPB*V88kAF{evvmec6PEX+4ZS~`OI={q*u6+j;+vP-99d{o5wnEMJag(ZJ zU7vi1smq&B+XVGEd$#i?wsESkZo4?A=}GzVXUaS8ODqmLShRW4iD!QCsk49YKbs?5 zl@@m4!uAWFx9$7t{rFbnl$hx54Mt_1y7n@x`)>U-^VdA-Hf54o7kB@pFUMt;Yd#CI zii>Sk{7#d%%jAvLRq4!(0NkLYb%5`4_+>7=s)l9@WeFGLS9hQEK_+o%3Zrd7D+=|9j`&)1sR$9j71f zpTYS3*qozua!x<_`wGu`NCC+CSKd|M{9 z;ZGiG#I-$LqVsmFYAh2wTY7f$l!Q3Oy=&$QuGe@_YrQA(sP%@!!tW$3Hf=j^!_oMA zzRptdgk8V4{tNJpKYm_jnal2_Ywg{Op5A-in~_}jW$#z*xEZ;pPw&oIvHH4)z|Y4L z$9_(oASUaR!uIIUg)049>o$4k9_>2!HulEso9E{AXBd4*e7ExPm#*#Vdmmnv`YAK3 z;(t-Y^XZoQPkql${@T}NI`4hczL{zFIlAU}`*2LKJznv-bitFE&OPd86#@&S7VdFA zyo=!=+hyqm2P(qNj!4DM51c0<*(~s!eU5tHgoxnF+K&t~XEYhacX|X&my%%FV!CqH zODTckGptIE7oP_-EOTSbXEZ$iCdlEiTSt+&=7PHEi)ZZE=)st*d0y%Dxh?)imD3+L z^-f<{v5I8*(Iu)>pB{e}-jSd-))cfQp!*I!%R%yfBr#|s{|THZ(T+*a&oGR{5V zP9IevxZ|2qFg z4E58vMfTj9Ty^pAJ1zx&&HcLbr+T%XJ^4s|{=4>L=bD`6iTH|CnDPCI$g5tf{r2np7``iKEi>!u4!rQLz9spC+b>3ZL#07PA29DQc)I$ztaD0e F0ss`r<0k+B literal 0 HcmV?d00001 diff --git a/static/h5/download-app/openImg.png b/static/h5/download-app/openImg.png new file mode 100644 index 0000000000000000000000000000000000000000..fe43afabcfa54c74df6efad8c8a1497a6168e0bb GIT binary patch literal 12894 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 KT`OrE@;?B>Ke1#0 literal 0 HcmV?d00001 diff --git a/static/tabbar/grid.png b/static/tabbar/grid.png new file mode 100644 index 0000000000000000000000000000000000000000..938b8212107cec8b8ac8b458f620afed4def22ee GIT binary patch literal 2695 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 K#QtG=HuAqSbgTpb literal 0 HcmV?d00001 diff --git a/static/tabbar/list.png b/static/tabbar/list.png new file mode 100644 index 0000000000000000000000000000000000000000..303bb4c3b8d31ce21c751b379c251e50b66f49e2 GIT binary patch literal 2897 zcmZWrc|4Te9v@50J5rV`AxoA@_7Fot!&t{!;zjoCN|rGOO*7NXV47@|7z{?q5~0YJ z_nkzcB9|-?*|IO$)qQ4q-TV36`}v&bJm)#*yZwIWpNC|Nfb&AcARrKk*W3(d54_u$ z510d(AKrE^1%cRRY^@wk;Mc5B@!0N9ktxDluuS*$Q7C|d1QKEZ zUlssJg~p=eS)cnZfEp_U%ZS-tW)pr7RwOJ6|2y07cCi}BlqJLiI{QrqM527&!U6P}+!?(3 z71M0kGyK$IHXYj7h@47E5>Ac*4SG_z@1 zYud8Bp?J0`wY+0tSn@kGbif(dOC(q>yZ;tNrkX@j~f+hx=P-@_I zEk$H!RG)5REpii%OP#C=`DqgCQSmRyq@5e*3OinSln?8? z6o-%R215K?ugy7)ZDMt%!ls@dUOlEdl(sgO{KH&$1Ag8wwibE6mVL^PG5jW`LreW~ zYN>5xkEMdQR)uJs9JTyB?mcG2I|FH_acc#L8Qh@p*Bm9Xm)Co zW6iFcm?nRuR&HJAnPS(b=UNK5DON}<`n=BUjM%xG2C1H|HfS<>Ct_lb@h9PBuPg#I zQ#sRygh4Os<_TTQa!GfFaD+);^&!`5%^GSRa~JVBdUs_NFB#bwRJrInhTiJpGr`6E zmCqO8R@^j$y|7UhE!&mxm#?w^5Z-d`@r$KHo1);IS0UViU&c>Lj*aftOPl&L+98Wv z;Z1hhmkuSYYgm+}^T^YFnQUhkf-dr{^B|up5}bxw2%|oi3PjXKhmPK*X^;6FfH$*~ zn(Cgl_@MQOOQ*g`o9BI~jh$aRT_{JD-PPIN9OCDDJ8BX<X*YX|@b)~-6UD0!;K(4|b z6a=|rhq~2bjt;UhcFk)$x`MOrV@HFp;szd9s9y|bw0~b1;6aqXZGAb8x5V30DD}s^ zBOkSxua}#tDn*vFos7YSbcQUr z)Sr=zQ8GF)EUDI4><}P5Jvfn==mp$RZ~Ls4Hip86zZPReA=*d_HT82$>il>jc5A~m z90t=RlIwqIzneiQv~c%*B&NN)t=`auC`%#DTjf#QGY#GPvHe@3LHGFTC;;2!X? zW4F=+RqjT%%9ve|y_0PvsZ%SK`cPDctIwF&aqK!Q-1otUTD{c=jBwsK&M*3DoTR+_ z{YGKuO^N&l)#BhKunc7hJhIWODbQpZB5)Y`MaXi%T4@X{?6Z=6c$W3 z1x}nW7A!7tO&e^J-TsArJ4gH&=o|N4JgHd9ZNxg>VLee_cXgid#uGWGSj+p*o$!fA8ie zy;Av`cg8fQ<1&)?Z@a-tK6@vu6jg{jYnzI$Ju1t^teo}i6cB5e@W%a^C<(${a@`Q_3}Om&qD*c_)|7jUo$!oYECH9J`_B>25WTSu_0+WwTFhINQ;MG_4&6x1cI+U_eG!qh84;8X(J;tA z2Y(_bsk}-@!-8QdXHQk{=^7t`tQ21~xs<{!CaV#vyc5eP1=G5%0y4Xgr;{KIW~z*r zGK>e^8g!GBf0}Mz=qU6J>J2zWMA-F-v+VSe?n`e+xU{1&H0V80Pb` z3TQk__f@5LoY~81<=Wj)(qI?9XN%V*#?_a~B?u$5^Nn*Tq>L14?$eh{Q|(IIszApd z5eb%CoL_fi^Eti4I7C02Iu_gZ`O8{dR{NSOV)?!07j{)JR^D9cRawFYJbqVKhBNg_ w(ZEhSWNxf`!pDoPe_3QNH@zo~#J`f@cF1a*;ru!l_+0{-n;>B2#vZr+4eD}p+yDRo literal 0 HcmV?d00001 diff --git a/static/tabbar/list_active.png b/static/tabbar/list_active.png new file mode 100644 index 0000000000000000000000000000000000000000..0ff8c49c39f8722d5a963d170edf127277c058f2 GIT binary patch literal 3024 zcmcguc{tQ-8y=FzHrd89nHZsA=2*&D2GJPX93dnogb|Ws8A4KaW(s4ME&H+WvW8?| ziz7v-j3p8uBU`C&%5_|Q=bZ1lzQ4ZfdVkOR-1qZ5_w&5(_5SfA8yV>%wVy3Lbf|FX z5Py(|@X$FZq(l0mcRz3r=Q-r*%wd#H9(1Q$dig;+y5sO?4xKp+(W~eed&nFrAE+JF zy8Jjb<}c96guQ9nDGN=13`p5xx;L?U(9oiUkdyo-JX zZzu-dLMJ205Th1j_>hx>D(0lOeymNbJW$&h#Dw(4=`u@8^PN$Elr`G06J__AUjs#? z9$^_7?OYX9*%=jd&yW$0lK=oPQV)CH)R*C-VoX3W*d_$yw?@bD`&7{-ud^k@(ZQKArS&U!l&4qI6lt}Fqcb~5Sfo0$wjIZ% z?wSXNA|@2aq0?v5vtM(G)Ohi&?l?iQax8SmOxaO38@5aHXUX z8}|YgzAfrCxCN*i?>76MD8xalVJ&SiF7xDxF4+HlIDBoFxwL+NKXOC+oqk&++2~=d z?W1@f`%4WRi+he2!dAV|;}ErnCK_N!TC7=T(`Qe_VQZ9lU{ttr;A14nzJ%z6bRJv z)YKs%gWa9R?x78Dp>ca=MFpoXHgGLx%U0SD?dE=P|I! zee}tfRMq=eisG6Ab3=B z$CP=%PJxlmka>V7;}&~ z+OjGq_ihC|mDQXhkBCNf3$NNM=B=bJQKU}cCr+miKalmRE&+ShO0&pEj5e?(DY+$5 zhl8S5|G34q7lNaf|C$-bx4UrkdDSfUFQGwr&>WHBl>U(>z6yhUavLjsEH%jdh-T$g z5xpoSbWO+?zKZk@+a4i;JAw_HuLW$`-(Sttyf?lZsdTcIA+DFzS`6C4e!}ONdVWMz z478BIgoruXDhC;5zY`4BJNhh`>9Mv@;+w9aiXbdXWvU%O=|9F=!`1W4?3SI;XeH@{ zC2t#ZZ~i*l=y7UHX^WGse&9xa$q0!c!ShXsN&MU-WVaf0#IEQCX`si#Y2}%LF3`sx z{M2MIA!jn>czpB>77_D|#E3`Di5R|x+S8^Cp@oz=f1%(@ zQl4Oi{HpeKV^Ze&YgDyHa;Hx^vBxUyePl~`P#t9f~=tnoHH#dj&-$1`ca)Ot_z44S=8s^uI_JrU8e5PI4S;u)`};tcdi$6 zF;>(NGTrSKv9@Z1^0P`^VpaDmX;qaGT>fk~_3c6hLs#Di#?7|Osea_NFXz&cmf%p0 zj%sc#>U^6~NJZG`ve+Q1JQPE=wqMc;JGK{;b%UBKLuM-PX?zh_2EHYR$HcHJ-%FhK z%X3N~F2>1ET}0x4RRDzbZhe}Fw^)>sd@IWqs}j&xtV%PTaF*Z=^VPC{7am=`Ygn#d z7{=>dC7Dc+j0n3z+I;-ksIf*o|I{2pv}N)+Zs6$%mmh4yZb4;AIW3|5oQL~%Dy-ft zXY^eot}Ztkx2+~@2E(026?DoK<`RB;6-IKboGfh?DX0i6B454toQ(@dU9Da&4x9?lPAysb8LJ2Wub4!YUe z-+?DzhBlMP4wTP*Cpuj1CxBefGs`)1+N;c3Munw?VL7P%Ze1@@aeBeA(KX6kc4R0? zvuJ~dO%&_)^m?LIpW|w7dT8F{(?PPE3Sv#qrmGc-Za^0esi3q9WiDYJnOBm*BdHny5KRm2TYEDQefG4D)c4)|SCKjY} z*zIOyy!z48Y$Gtko=_YqlOJJjO-EB&6b?d=FV#J=al`S{oU!BkPV})flC4=S)s=^hB%vBpT24|`mUA`72 fKg<=1{dUB{$cJ0Wm*aZI@FH{klD~T?9}q2h zPY<^%1psKcjSbASbdU!AL81S*Q0P$d@(;pL_g_;KCIXGdqAC6VTNp}*+9%`D7|Iky z*|F3`E&redh5n+WFjOLCgeB9F$XJRmnM>|quzy-p9m#5;{#fi!{r@UceE$UdV<~j1 zCJI9d;O&p`_V%XYe}|_;r8xewpuor?6c!~v8cPujq8d>Z$buLQ`6{S%GJwp*P@aD$ zq(&tpe|0D&)tVaPrx!ILRfK9yjrSW*)}iDi-xwu18Bfuns!^_j^6-;rW@bhiQ9@Dz z_>xch$JxovJ85Y@5AI8a`J=I9B1MoaPL=Yelw=m=yyRb#G9s7c=}(;?ERqT!Pu)Hg zagzTimENX?Hvn!)U1I|kZ3xVjt&+V9tgyojr1#&Noeq^U2GQrta)?3Ceb?uhQK3Ss zd1*Ev|ALniPWekS*jrh=*A^N-)jGqkwWaVz6vo z@(4u;k}(nnq&br=ksp3qn;x=aTa|vcWZ*)jmDzej;Phv^1T=?I<&A08x`e^tR3((B z@7}l6v_MZj=beGK>&<(Ce-kriilQaN4^o_k`Vcsb2(2Cij#cE;{_y~!@F2M2ti09f!xn)jqQ_}3L z@2fpcbsu7JmADt@<>MgW$ePr39hn_)F~4Bqad~?o{t(|O#NBn^@ibx=z5Rl-g2&Uh zk&PYxP11#DqD4`xWyHH@P?O=Wtis040i$6zsQ>dDJyqM0ia{nh(z$i)m31C1Sqo}q zBMgR9A4d!5ty1Dxcc%tFriV$~PnZ(5BTT_36o0sKyQA+FtS3m7!M9jG7JHn+74N+M zB0uU6j}B^F%^*C4YXq|#l9x1`zaM~(uwaBMO;pz}%alfWadfJml5M3+)ESSTA0+y5*V zq9K5rONPCXl?h{yIoS@=>ahyb&~2etDIa(wbup#iroQF-K3!tz#^Pd$&t>E*h3*g) z79lQH)^c$}XKQ)H;kQtnI+%I5p7~s+6Tyuk(SnFO+!FFP)O<3oT-M*Fcu`beN zcUNCmoBv{imGYe}{ob*EUKPhj1P1B+$OrS-NM8JQbU!|i(z~e*Mk;Z>Q1|Mi09LmU{QE|g^5v!Z-h-a8GBo1wMd>$1Ew+=$gOMhQY}9aa0X^A zxY#%kd8f;>$s2~0>se;q%)Z|K%Yr$tzBq^ zshOTQB6ZfcBrxv*L0=1K_UHY0wk8a_tT7;>$q6)R>M6W8-;xUk-`9u)RqWqNFO-cm*SWM`Z8`D zX_FEK`CKE2?&W>kwm?#)7qAK+QXimA^JVIhbGv}A)oj`12ETgDx{0?xMYy_fqYhUf zFkNUsLMbs;_LWo+cXuRB^`dVgr+hFsKLOS*%jZT-##AKm=CIs21t_{!4A?BSQcB>-d0YKxHb zm%})j52goIl}o<&4!XjkiHWJ8*gVG5_DBBfQFo3Clf?t;+Q;>9H#0tMbL$v7S=$R2?KK~p8OVA?h$5o$;-b#5 zIXI6sT)f07qb7rIYL9~0hIf=3S&6JYTm5`i5tZFU8YF*l2s}JQd4%V

((JRXd-_R$uwwDG=wi%XLy3Q9s)-2%^hr;Jzu@K4*QUI z_@q9F->Q4dC*|dF`s}Bw-CPJM+um}U{qDmS=e;N3+N%OfPkDUm96wE2duWUvET*}q z;I*2sn6`GSne?B4@{fpBwsu&Ua^+|@UJD1^C$asbHkb#%F`O?JVr^l8{y@v zT8j4aiIFZ+KL330Ex*~n&LcNmHkzn6!}Kz7a#Or81~YD}xZ*so72%@rLwNLjTz(2o zo+}{T@^KzQdqtmC?j9~ac#u|_$KsB&3kplBpBXlbF*vk~ognGcCsr45BxEGWAkiJ}0VR!u@u(H0v|I0Qc>$rhu%0iR-dh6T3aXh|kkMIsibQJwLu^hF462M$7+J zd+-C{;optnDf5iRyxyTk>>J}2nwhN(A9(8$`}|0JdLWyFr?z@hvQ0Tt#^E#3*XcXQ zmb`x~e--ev-yvbTKxZog+gjKB!Q=XeTZRpMMk%bP2Zz{$i7V$uo6i}Z+B>}Z!*p)H zEo;tl3YP?aQ5KC-$V16_`a-0~@1&parr{GkoG{QP%=)R?>lEdAOepT=5x+#?#A$;8s#6N7CE%N*g?1+;oE8ibBt z_uBh(*Wszb3KP9~>ur-(LEL`bbo&w0J$oO%E4p26B9o;OHMx-ap=nhAnkK*a=f2_8 zF@8=CLi3x{7nr$92~gTPTa{M~JQ5r1Q9YTv|okt6O9kE((FQ4RS z3>bxeto8kZFlghh>0yQ z;>47kMS%%_uw@&}qB*)Zwe8!kPN0^MSHqc;!Y literal 0 HcmV?d00001 diff --git a/static/tabbar/me_active.png b/static/tabbar/me_active.png new file mode 100644 index 0000000000000000000000000000000000000000..e7276141fa070cb457d37a15a5e4c3ba36d5cb10 GIT binary patch literal 3461 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 NmgctPOQvpz{sj}*(vScE literal 0 HcmV?d00001 diff --git a/static/uni.ttf b/static/uni.ttf new file mode 100644 index 0000000000000000000000000000000000000000..60a1968d08cc6056c70b5402b2effac43c6f96a3 GIT binary patch literal 26164 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 literal 0 HcmV?d00001 diff --git a/uni-starter.config.js b/uni-starter.config.js new file mode 100644 index 0000000..6f0ac31 --- /dev/null +++ b/uni-starter.config.js @@ -0,0 +1,49 @@ +//这是应用的配置页面,App.vue挂载到getApp().globalData.config +export default { + "h5": { + "url": "https://uni-starter.dcloud.net.cn", // 前端网页托管的域名 + // 在h5端全局悬浮引导用户下载app的功能 更多自定义要求在/common/openApp.js中修改 + "openApp": { //如不需要本功能直接移除本节点即可 + // //点击悬浮下载栏后打开的网页链接 + // "openUrl": '/#/pages/ucenter/invite/invite', + // //左侧显示的应用名称 + "appname": '天然气计算', + // //应用的图标 + "logo": "https://ngtools.cn/pic/static/logomain.png", + } + }, + "mp": { + "weixin": { + //微信小程序原始id,微信小程序分享时 + "id": "wx9f9b7d747d261686" + } + }, + //关于应用 + "about": { + //应用名称 + "appName": "天然气计算", + //应用logo + "logo": "https://ngtools.cn/pic/static/logomain.png", + //公司名称 + "company": "妍杰丽云工作室", + //口号 + "slogan": "天然气工业应用计算工具集", + //应用的链接,用于分享到第三方平台和生成关于我们页的二维码 + "download": "https://itunes.apple.com/cn/app/hello-uni-app/id1417078253?mt=8", + //version + "version":"1.0.0" //用于非app端显示,app端自动获取 + }, + "download":{ //用于生成二合一下载页面 + "ios":"https://itunes.apple.com/cn/app/hello-uni-app/id1417078253?mt=8", + "android":"https://vkceyugu.cdn.bspapp.com/VKCEYUGU-97fca9f2-41f6-449f-a35e-3f135d4c3875/6d754387-a6c3-48ed-8ad2-e8f39b40fc01.apk" + }, + //用于打开应用市场评分界面 + "marketId":{ + "ios":"", + "android":"" + }, + //配置多语言国际化。i18n为英文单词 internationalization的首末字符i和n,18为中间的字符数 是“国际化”的简称 + "i18n":{ + "enable":false //默认关闭,国际化。如果你想使用国际化相关功能,请改为true + } +} \ No newline at end of file diff --git a/uni.scss b/uni.scss new file mode 100644 index 0000000..45ae737 --- /dev/null +++ b/uni.scss @@ -0,0 +1,76 @@ +/** + * 这里是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:#c8c7cc; + +/* 尺寸变量 */ + +/* 文字尺寸 */ +$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: 8px; +$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; \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/index.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/index.js new file mode 100644 index 0000000..7b505d4 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/index.js @@ -0,0 +1,23 @@ +const { + createApi +} = require('./shared/index') + +let reportDataReceiver, dataStatCron +module.exports = { + //uni统计数据上报数据接收器初始化 + initReceiver: (options = {}) => { + if(!reportDataReceiver) { + reportDataReceiver = require('./stat/receiver') + } + options.clientType = options.clientType || __ctx__.PLATFORM + return createApi(reportDataReceiver, options) + }, + //uni统计数据统计模块初始化 + initStat: (options = {}) => { + if(!dataStatCron) { + dataStatCron = require('./stat/stat') + } + options.clientType = options.clientType || __ctx__.PLATFORM + return createApi(dataStatCron, options) + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/package.json b/uniCloud-aliyun/cloudfunctions/common/uni-stat/package.json new file mode 100644 index 0000000..c9df117 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/package.json @@ -0,0 +1,15 @@ +{ + "name": "uni-stat", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "uni-config-center": "file:../../../../uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/shared/create-api.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/shared/create-api.js new file mode 100644 index 0000000..ea438f6 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/shared/create-api.js @@ -0,0 +1,82 @@ +const { + isFn, + isPlainObject +} = require('./utils') + +/** + * 实例参数处理,注意:不进行递归处理 + * @param {Object} params 初始参数 + * @param {Object} rule 规则集 + * @returns {Object} 处理后的参数 + */ +function parseParams (params = {}, rule) { + if (!rule || !params) { + return params + } + const internalKeys = ['_pre', '_purify', '_post'] + // 转换之前的处理 + if (rule._pre) { + params = rule._pre(params) + } + // 净化参数 + let purify = { shouldDelete: new Set([]) } + if (rule._purify) { + const _purify = rule._purify + for (const purifyKey in _purify) { + _purify[purifyKey] = new Set(_purify[purifyKey]) + } + purify = Object.assign(purify, _purify) + } + if (isPlainObject(rule)) { + for (const key in rule) { + const parser = rule[key] + if (isFn(parser) && internalKeys.indexOf(key) === -1) { + params[key] = parser(params) + } else if (typeof parser === 'string' && internalKeys.indexOf(key) === -1) { + // 直接转换属性名称的删除旧属性名 + params[key] = params[parser] + purify.shouldDelete.add(parser) + } + } + } else if (isFn(rule)) { + params = rule(params) + } + + if (purify.shouldDelete) { + for (const item of purify.shouldDelete) { + delete params[item] + } + } + + // 转换之后的处理 + if (rule._post) { + params = rule._post(params) + } + + return params +} + +/** + * 返回一个提供应用上下文的应用实例。应用实例挂载的整个组件树共享同一个上下文 + * @param {class} ApiClass 实例类 + * @param {Object} options 参数 + * @returns {Object} 实例类对象 + */ +module.exports = function createApi (ApiClass, options) { + const apiInstance = new ApiClass(options) + return new Proxy(apiInstance, { + get: function (obj, prop) { + if (typeof obj[prop] === 'function' && prop.indexOf('_') !== 0 && obj._protocols && obj._protocols[prop]) { + const protocol = obj._protocols[prop] + return async function (params) { + params = parseParams(params, protocol.args) + let result = await obj[prop](params) + result = parseParams(result, protocol.returnValue) + return result + } + } else { + return obj[prop] + } + } + }) +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/shared/error.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/shared/error.js new file mode 100644 index 0000000..2955d22 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/shared/error.js @@ -0,0 +1,19 @@ +/** + * @class UniCloudError 错误处理模块 + */ +module.exports = class UniCloudError extends Error { + constructor (options) { + super(options.message) + this.errMsg = options.message || '' + Object.defineProperties(this, { + message: { + get () { + return `errCode: ${options.code || ''} | errMsg: ` + this.errMsg + }, + set (msg) { + this.errMsg = msg + } + } + }) + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/shared/index.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/shared/index.js new file mode 100644 index 0000000..12951c8 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/shared/index.js @@ -0,0 +1,6 @@ +module.exports = { + UniCloudError: require('./error'), + createApi: require('./create-api'), + ... require('./utils') +} + diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/shared/utils.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/shared/utils.js new file mode 100644 index 0000000..2852343 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/shared/utils.js @@ -0,0 +1,197 @@ +const _toString = Object.prototype.toString +const hasOwnProperty = Object.prototype.hasOwnProperty + +/** + * 检查对象是否包含某个属性 + * @param {Object} obj 对象 + * @param {String} key 属性键值 + */ +function hasOwn(obj, key) { + return hasOwnProperty.call(obj, key) +} + +/** + * 参数是否为JavaScript的简单对象 + * @param {Object} obj + * @returns {Boolean} true|false + */ +function isPlainObject(obj) { + return _toString.call(obj) === '[object Object]' +} + +/** + * 是否为函数 + * @param {String} fn 函数名 + */ +function isFn(fn) { + return typeof fn === 'function' +} + +/** + * 深度克隆对象 + * @param {Object} obj + */ +function deepClone(obj) { + return JSON.parse(JSON.stringify(obj)) +} + + +/** + * 解析客户端上报的参数 + * @param {String} primitiveParams 原始参数 + * @param {Object} context 附带的上下文 + */ +function parseUrlParams(primitiveParams, context) { + if (!primitiveParams) { + return primitiveParams + } + + let params = {} + if(typeof primitiveParams === 'string') { + params = primitiveParams.split('&').reduce((res, cur) => { + const arr = cur.split('=') + return Object.assign({ + [arr[0]]: arr[1] + }, res) + }, {}) + } else { + //转换参数类型--兼容性 + for(let key in primitiveParams) { + if(typeof primitiveParams[key] === 'number') { + params[key] = primitiveParams[key] + '' + } else { + params[key] = primitiveParams[key] + } + } + } + + //原以下数据要从客户端上报,现调整为如果以下参数客户端未上报,则通过请求附带的context参数中获取 + const convertParams = { + //appid + ak: 'appId', + //当前登录用户编号 + uid: 'uid', + //设备编号 + did: 'deviceId', + //uni-app 运行平台,与条件编译平台相同。 + up: 'uniPlatform', + //操作系统名称 + p: 'osName', + //因为p参数可能会被前端覆盖掉,所以这里单独拿出来一个osName + on: 'osName', + //客户端ip + ip: 'clientIP', + //客户端的UA + ua: 'userAgent', + //当前服务空间编号 + spid: 'spaceId', + //当前服务空间提供商 + sppd: 'provider', + //应用版本号 + v: 'appVersion', + //rom 名称 + rn: 'romName', + //rom 版本 + rv: 'romVersion', + //操作系统版本 + sv: 'osVersion', + //操作系统语言 + lang: 'osLanguage', + //操作系统主题 + ot: 'osTheme', + //设备类型 + dtp: 'deviceType', + //设备品牌 + brand: 'deviceBrand', + //设备型号 + md: 'deviceModel', + //设备像素比 + pr: 'devicePixelRatio', + //可使用窗口宽度 + ww: 'windowWidth', + //可使用窗口高度 + wh: 'windowHeight', + //屏幕宽度 + sw: 'screenWidth', + //屏幕高度 + sh: 'screenHeight', + } + context = context ? context : {} + for (let key in convertParams) { + if (!params[key] && context[convertParams[key]]) { + params[key] = context[convertParams[key]] + } + } + + return params +} + +/** + * 解析url + * @param {String} url + */ +function parseUrl(url) { + if (typeof url !== "string" || !url) { + return false + } + const urlInfo = url.split('?') + + baseurl = urlInfo[0] + if (baseurl !== '/' && baseurl.indexOf('/') === 0) { + baseurl = baseurl.substr(1) + } + + return { + path: baseurl, + query: urlInfo[1] ? decodeURI(urlInfo[1]) : '' + } +} + +//加载配置中心-uni-config-center +let createConfig +try { + createConfig = require('uni-config-center') +} catch (e) {} + +/** + * 获取配置文件信息 + * @param {String} file 配置文件名称 + * @param {String} key 配置参数键值 + */ +function getConfig(file, key) { + if (!file) { + return false + } + + const uniConfig = createConfig && createConfig({ + pluginId: 'uni-stat' + }) + + if (!uniConfig || !uniConfig.hasFile(file + '.json')) { + console.error('Not found the config file') + return false + } + + const config = uniConfig.requireFile(file) + + return key ? config[key] : config +} + +/** + * 休眠 + * @param {Object} ms 休眠时间(毫秒) + */ +function sleep(ms) { + return new Promise(resolve => setTimeout(() => resolve(), ms)) +} + +module.exports = { + hasOwn, + isPlainObject, + isFn, + deepClone, + parseUrlParams, + parseUrl, + getConfig, + sleep +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/lib/date.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/lib/date.js new file mode 100644 index 0000000..00417a1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/lib/date.js @@ -0,0 +1,371 @@ +/** + * @class DateTime + * @description 日期处理模块 + */ +module.exports = class DateTime { + constructor() { + //默认日期展示格式 + this.defaultDateFormat = 'Y-m-d H:i:s' + //默认时区 + this.defaultTimezone = 8 + this.setTimeZone(this.defaultTimezone) + } + + /** + * 设置时区 + * @param {Number} timezone 时区 + */ + setTimeZone(timezone) { + if (timezone) { + this.timezone = parseInt(timezone) + } + return this + } + + /** + * 获取 Date对象 + * @param {Date|Time} time + */ + getDateObj(time) { + return time ? new Date(time) : new Date() + } + + /** + * 获取毫秒/秒级时间戳 + * @param {DateTime} datetime 日期 例:'2022-04-21 00:00:00' + * @param {Boolean} showSenconds 是否显示为秒级时间戳 + */ + getTime(datetime, showSenconds) { + let time = this.getDateObj(datetime).getTime() + if (showSenconds) { + time = Math.trunc(time / 1000) + } + return time + } + + /** + * 获取日期 + * @param {String} dateFormat 日期格式 + * @param {Time} time 时间戳 + */ + getDate(dateFormat, time) { + return this.dateFormat(dateFormat, time) + } + + + /** + * 获取日期在不同时区下的时间戳 + * @param {Date|Time}} time 日期或时间戳 + * @param {Object} timezone 时区 + */ + getTimeByTimeZone(time, timezone) { + this.setTimeZone(timezone) + const thisDate = time ? new Date(time) : new Date() + const localTime = thisDate.getTime() + const offset = thisDate.getTimezoneOffset() + const utc = offset * 60000 + localTime + return utc + (3600000 * this.timezone) + } + + /** + * 获取时间信息 + * @param {Time} time 时间戳 + * @param {Boolean} full 是否完整展示, 为true时小于10的位会自动补0 + */ + getTimeInfo(time, full = true) { + time = this.getTimeByTimeZone(time) + const date = this.getDateObj(time) + const retData = { + nYear: date.getFullYear(), + nMonth: date.getMonth() + 1, + nWeek: date.getDay() || 7, + nDay: date.getDate(), + nHour: date.getHours(), + nMinutes: date.getMinutes(), + nSeconds: date.getSeconds() + } + + if (full) { + for (const k in retData) { + if (retData[k] < 10) { + retData[k] = '0' + retData[k] + } + } + } + return retData + } + + /** + * 时间格式转换 + * @param {String} format 展示格式如:Y-m-d H:i:s + * @param {Time} time 时间戳 + */ + dateFormat(format, time) { + const timeInfo = this.getTimeInfo(time) + format = format || this.defaultDateFormat + let date = format + if (format.indexOf('Y') > -1) { + date = date.replace(/Y/, timeInfo.nYear) + } + if (format.indexOf('m') > -1) { + date = date.replace(/m/, timeInfo.nMonth) + } + if (format.indexOf('d') > -1) { + date = date.replace(/d/, timeInfo.nDay) + } + if (format.indexOf('H') > -1) { + date = date.replace(/H/, timeInfo.nHour) + } + if (format.indexOf('i') > -1) { + date = date.replace(/i/, timeInfo.nMinutes) + } + if (format.indexOf('s') > -1) { + date = date.replace(/s/, timeInfo.nSeconds) + } + return date + } + + /** + * 获取utc格式时间 + * @param {Date|Time} datetime 日期或时间戳 + */ + getUTC(datetime) { + return this.getDateObj(datetime).toUTCString() + } + + /** + * 获取ISO 格式时间 + * @param {Date|Time} datetime 日期或时间戳 + */ + getISO(datetime) { + return this.getDateObj(datetime).toISOString() + } + + /** + * 获取两时间相差天数 + * @param {Time} time1 时间戳 + * @param {Time} time2 时间戳 + */ + getDiffDays(time1, time2) { + if (!time1) { + return false + } + time2 = time2 ? time2 : this.getTime() + + let diffTime = time2 - time1 + if (diffTime < 0) { + diffTime = Math.abs(diffTime) + } + + return Math.ceil(diffTime / 86400000) + } + + /** + * 字符串转时间戳 + * @param {Object} str 字符串类型的时间戳 + */ + strToTime(str) { + if (Array.from(str).length === 10) { + str += '000' + } + return this.getTime(parseInt(str)) + } + + /** + * 根据设置的天数获取指定日期N天后(前)的时间戳 + * @param {Number} days 天数 + * @param {Date|Time} time 指定的日期或时间戳 + * @param {Boolean} getAll 是否获取完整时间戳,为 false 时返回指定日期初始时间戳(当天00:00:00的时间戳) + */ + getTimeBySetDays(days, time, getAll = false) { + const date = this.getDateObj(time) + date.setDate(date.getDate() + days) + let startTime = date.getTime() + if (!getAll) { + const realdate = this.getDate('Y-m-d 00:00:00', startTime) + startTime = this.getTimeByDateAndTimezone(realdate) + } + return startTime + } + + /** + * 根据设置的小时数获取指定日期N小时后(前)的时间戳 + * @param {Number} hours 小时数 + * @param {Date|Time} time 指定的日期或时间戳 + * @param {Boolean} getAll 是否获取完整时间戳,为 false 时返回指定时间初始时间戳(该小时00:00的时间戳) + */ + getTimeBySetHours(hours, time, getAll = false) { + const date = this.getDateObj(time) + date.setHours(date.getHours() + hours) + let startTime = date.getTime() + if (!getAll) { + const realdate = this.getDate('Y-m-d H:00:00', startTime) + startTime = this.getTimeByDateAndTimezone(realdate) + } + return startTime + } + + /** + * 根据设置的周数获取指定日期N周后(前)的时间戳 + * @param {Number} weeks 周数 + * @param {Date|Time} time 指定的日期或时间戳 + * @param {Boolean} getAll 是否获取完整时间戳,为 false 时返回指定日期初始时间戳(当天00:00:00的时间戳) + */ + getTimeBySetWeek(weeks, time, getAll = false) { + const date = this.getDateObj(time) + const dateInfo = this.getTimeInfo(time) + const day = dateInfo.nWeek + const offsetDays = 1 - day + weeks = weeks * 7 + offsetDays + date.setDate(date.getDate() + weeks) + let startTime = date.getTime() + if (!getAll) { + const realdate = this.getDate('Y-m-d 00:00:00', startTime) + startTime = this.getTimeByDateAndTimezone(realdate) + } + return startTime + } + + /** + * 根据设置的月数获取指定日期N月后(前)的时间戳 + * @param {Number} monthes 月数 + * @param {Date|Time} time 指定的日期或时间戳 + * @param {Boolean} getAll 是否获取完整时间戳,为 false 时返回指定日期初始时间戳(当天00:00:00的时间戳) + */ + getTimeBySetMonth(monthes, time, getAll = false) { + const date = this.getDateObj(time) + date.setMonth(date.getMonth() + monthes) + let startTime = date.getTime() + if (!getAll) { + const realdate = this.getDate('Y-m-01 00:00:00', startTime) + startTime = this.getTimeByDateAndTimezone(realdate) + } + return startTime + } + + /** + * 根据设置的季度数获取指定日期N个季度后(前)的时间戳 + * @param {Number} quarter 季度 + * @param {Date|Time} time 指定的日期或时间戳 + * @param {Boolean} getAll 是否获取完整时间戳,为 false 时返回指定日期初始时间戳(当天00:00:00的时间戳) + */ + getTimeBySetQuarter(quarter, time, getAll = false) { + const date = this.getDateObj(time) + const dateInfo = this.getTimeInfo(time) + date.setMonth(date.getMonth() + quarter * 3) + const month = date.getMonth() + 1; + let quarterN; + let mm; + if ([1,2,3].indexOf(month) > -1) { + // 第1季度 + mm = "01"; + } else if ([4,5,6].indexOf(month) > -1) { + // 第2季度 + mm = "04"; + } else if ([7,8,9].indexOf(month) > -1) { + // 第3季度 + mm = "07"; + } else if ([10,11,12].indexOf(month) > -1) { + // 第4季度 + mm = "10"; + } + let yyyy = date.getFullYear(); + let startTime = date.getTime() + if (!getAll) { + const realdate = this.getDate(`${yyyy}-${mm}-01 00:00:00`, startTime) + startTime = this.getTimeByDateAndTimezone(realdate) + } + return startTime + } + + /** + * 根据设置的年数获取指定日期N年后(前)的时间戳 + * @param {Number} year 月数 + * @param {Date|Time} time 指定的日期或时间戳 + * @param {Boolean} getAll 是否获取完整时间戳,为 false 时返回指定日期初始时间戳(当天00:00:00的时间戳) + */ + getTimeBySetYear(year, time, getAll = false) { + const date = this.getDateObj(time) + date.setFullYear(date.getFullYear() + year) + let startTime = date.getTime() + if (!getAll) { + const realdate = this.getDate('Y-01-01 00:00:00', startTime) + startTime = this.getTimeByDateAndTimezone(realdate) + } + return startTime + } + + + /** + * 根据时区获取指定时间的偏移时间 + * @param {Date|Time} 指定的日期或时间戳 + * @param {Number} timezone 时区 + */ + getTimeByDateAndTimezone(date, timezone) { + if (!timezone) { + timezone = this.timezone + } + const thisDate = this.getDateObj(date) + const thisTime = thisDate.getTime() + const offset = thisDate.getTimezoneOffset() + const offsetTime = offset * 60000 + timezone * 3600000 + return thisTime - offsetTime + } + + /** + * 根据指定的时间类型获取时间范围 + * @param {String} type 时间类型 hour:小时 day:天 week:周 month:月 + * @param {Number} offset 时间的偏移量 + * @param {Date|Time} thistime 指定的日期或时间戳 + * @param {Boolean} getAll 是否获取完整时间戳,为 false 时返回指定日期初始时间戳(当天00:00:00的时间戳) + */ + getTimeDimensionByType(type, offset = 0, thistime, getAll = false) { + let startTime = 0 + let endTime = 0 + switch (type) { + case 'hour': { + startTime = this.getTimeBySetHours(offset, thistime, getAll) + endTime = getAll ? startTime : startTime + 3599999 + break + } + case 'day': { + startTime = this.getTimeBySetDays(offset, thistime, getAll) + endTime = getAll ? startTime : startTime + 86399999 + break + } + case 'week': { + startTime = this.getTimeBySetWeek(offset, thistime, getAll) + endTime = getAll ? startTime + 86400000 * 6 : startTime + 86400000 * 6 + 86399999 + break + } + case 'month': { + startTime = this.getTimeBySetMonth(offset, thistime, getAll) + const date = this.getDateObj(this.getDate('Y-m-d H:i:s', startTime)) + const nextMonthFirstDayTime = new Date(date.getFullYear(), date.getMonth() + 1, 1).getTime() + endTime = getAll ? nextMonthFirstDayTime - 86400000 : this.getTimeByDateAndTimezone( + nextMonthFirstDayTime) - 1 + break + } + case 'quarter': { + startTime = this.getTimeBySetQuarter(offset, thistime, getAll) + const date = this.getDateObj(this.getDate('Y-m-d H:i:s', startTime)) + const nextMonthFirstDayTime = new Date(date.getFullYear(), date.getMonth() + 3, 1).getTime() + endTime = getAll ? nextMonthFirstDayTime - 86400000 : this.getTimeByDateAndTimezone( + nextMonthFirstDayTime) - 1 + break + } + case 'year': { + startTime = this.getTimeBySetYear(offset, thistime, getAll) + const date = this.getDateObj(this.getDate('Y-m-d H:i:s', startTime)) + const nextFirstDayTime = new Date(date.getFullYear() + 1, 0, 1).getTime() + endTime = getAll ? nextFirstDayTime - 86400000 : this.getTimeByDateAndTimezone( + nextFirstDayTime) - 1 + break + } + } + return { + startTime, + endTime + } + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/lib/index.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/lib/index.js new file mode 100644 index 0000000..4ccab05 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/lib/index.js @@ -0,0 +1,4 @@ +module.exports = { + DateTime: require('./date'), + UniCrypto: require('./uni-crypto') +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/lib/uni-crypto.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/lib/uni-crypto.js new file mode 100644 index 0000000..d5cdc8d --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/lib/uni-crypto.js @@ -0,0 +1,98 @@ +/** + * @class UniCrypto 数据加密服务 + * @function init 初始化函数 + * @function showConfig 返回配置信息函数 + * @function getCrypto 返回原始crypto对象函数 + * @function aesEncode AES加密函数 + * @function aesDecode AES解密函数 + * @function md5 MD5加密函数 + */ +const crypto = require('crypto') +module.exports = class UniCrypto { + constructor(config) { + this.init(config) + } + + /** + * 配置初始化函数 + * @param {Object} config + */ + init(config) { + this.config = { + //AES加密默认参数 + AES: { + mod: 'aes-128-cbc', + pasword: 'UniStat!010', + iv: 'UniStativ', + charset: 'utf8', + encodeReturnType: 'base64' + }, + //MD5加密默认参数 + MD5: { + encodeReturnType: 'hex' + }, + ...config || {} + } + return this + } + + /** + * 返回配置信息函数 + */ + showConfig() { + return this.config + } + + /** + * 返回原始crypto对象函数 + */ + getCrypto() { + return crypto + } + + /** + * AES加密函数 + * @param {String} data 加密数据明文 + * @param {String} encodeReturnType 返回加密数据类型,如:base64 + * @param {String} key 密钥 + * @param {String} iv 偏移量 + * @param {String} mod 模式 + * @param {String} charset 编码 + */ + aesEncode(data, encodeReturnType, key, iv, mod, charset) { + const cipher = crypto.createCipheriv(mod || this.config.AES.mod, key || this.config.AES.pasword, iv || + this.config.AES.iv) + let crypted = cipher.update(data, charset || this.config.AES.charset, 'binary') + crypted += cipher.final('binary') + crypted = Buffer.from(crypted, 'binary').toString(encodeReturnType || this.config.AES.encodeReturnType) + return crypted + } + + /** + * AES解密函数 + * @param {Object} crypted 加密数据密文 + * @param {Object} encodeReturnType 返回加密数据类型,如:base64 + * @param {Object} key 密钥 + * @param {Object} iv 偏移量 + * @param {Object} mod 模式 + * @param {Object} charset 编码 + */ + aesDecode(crypted, encodeReturnType, key, iv, mod, charset) { + crypted = Buffer.from(crypted, encodeReturnType || this.config.AES.encodeReturnType).toString('binary') + const decipher = crypto.createDecipheriv(mod || this.config.AES.mod, key || this.config.AES.pasword, + iv || this.config.AES.iv) + let decoded = decipher.update(crypted, 'binary', charset || this.config.AES.charset) + decoded += decipher.final(charset || this.config.AES.charset) + return decoded + } + + /** + * @param {Object} str 加密字符串 + * @param {Object} encodeReturnType encodeReturnType 返回加密数据类型,如:hex(转为16进制) + */ + md5(str, encodeReturnType) { + const md5Mod = crypto.createHash('md5') + md5Mod.update(str) + return md5Mod.digest(encodeReturnType || this.config.MD5.encodeReturnType) + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/activeDevices.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/activeDevices.js new file mode 100644 index 0000000..dd61a45 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/activeDevices.js @@ -0,0 +1,528 @@ +/** + * @class ActiveDevices 活跃设备模型 - 每日跑批合并,仅添加本周/本月首次访问的设备。 + */ +const BaseMod = require('./base') +const Platform = require('./platform') +const Channel = require('./channel') +const Version = require('./version') +const SessionLog = require('./sessionLog') +const { + DateTime, + UniCrypto +} = require('../lib') +module.exports = class ActiveDevices extends BaseMod { + constructor() { + super() + this.tableName = 'active-devices' + this.platforms = [] + this.channels = [] + this.versions = [] + } + + /** + * @desc 活跃设备统计 - 为周统计/月统计提供周活/月活数据 + * @param {date|time} date + * @param {bool} reset + */ + async stat(date, reset) { + const dateTime = new DateTime() + const dateDimension = dateTime.getTimeDimensionByType('day', -1, date) + this.startTime = dateDimension.startTime + // 查看当前时间段数据是否已存在,防止重复生成 + if (!reset) { + const checkRes = await this.getCollection(this.tableName).where({ + create_time: { + $gte: dateDimension.startTime, + $lte: dateDimension.endTime + } + }).get() + if (checkRes.data.length > 0) { + console.log('data have exists') + return { + code: 1003, + msg: 'Devices data in this time have already existed' + } + } + } else { + const delRes = await this.delete(this.tableName, { + create_time: { + $gte: dateDimension.startTime, + $lte: dateDimension.endTime + } + }) + console.log('Delete old data result:', JSON.stringify(delRes)) + } + + const sessionLog = new SessionLog() + const statRes = await this.aggregate(sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + is_first_visit: 1, + create_time: 1, + device_id: 1 + }, + match: { + create_time: { + $gte: dateDimension.startTime, + $lte: dateDimension.endTime + } + }, + group: { + _id: { + appid: '$appid', + version: '$version', + platform: '$platform', + channel: '$channel', + device_id: '$device_id' + }, + is_new: { + $max: '$is_first_visit' + }, + create_time: { + $min: '$create_time' + } + }, + sort: { + create_time: 1 + }, + getAll: true + }) + + let res = { + code: 0, + msg: 'success' + } + // if (this.debug) { + // console.log('statRes', JSON.stringify(statRes)) + // } + if (statRes.data.length > 0) { + const uniCrypto = new UniCrypto() + // 同应用、平台、渠道、版本的数据合并 + const statData = []; + let statKey; + let data + + const statOldRes = await this.aggregate(sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + is_first_visit: 1, + create_time: 1, + old_device_id: 1 + }, + match: { + create_time: { + $gte: dateDimension.startTime, + $lte: dateDimension.endTime + }, + old_device_id: {$exists: true} + }, + group: { + _id: { + appid: '$appid', + version: '$version', + platform: '$platform', + channel: '$channel', + old_device_id: '$old_device_id' + }, + create_time: { + $min: '$create_time' + } + }, + sort: { + create_time: 1 + }, + getAll: true + }) + if (this.debug) { + console.log('statOldRes', JSON.stringify(statOldRes)) + } + for (const sti in statRes.data) { + data = statRes.data[sti] + statKey = uniCrypto.md5(data._id.appid + data._id.platform + data._id.version + data._id + .channel) + if (!statData[statKey]) { + statData[statKey] = { + appid: data._id.appid, + platform: data._id.platform, + version: data._id.version, + channel: data._id.channel, + device_ids: [], + old_device_ids: [], + info: [], + old_info: [] + } + statData[statKey].device_ids.push(data._id.device_id) + statData[statKey].info[data._id.device_id] = { + is_new: data.is_new, + create_time: data.create_time + } + } else { + statData[statKey].device_ids.push(data._id.device_id) + statData[statKey].info[data._id.device_id] = { + is_new: data.is_new, + create_time: data.create_time + } + } + } + if(statOldRes.data.length) { + const oldDeviceIds = [] + for(const osti in statOldRes.data) { + if(!statOldRes.data[osti]._id.old_device_id) { + continue + } + oldDeviceIds.push(statOldRes.data[osti]._id.old_device_id) + } + if(oldDeviceIds.length) { + const statOldDidRes = await this.aggregate(sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + is_first_visit: 1, + create_time: 1, + device_id: 1 + }, + match: { + create_time: { + $gte: dateDimension.startTime, + $lte: dateDimension.endTime + }, + device_id: {$in: oldDeviceIds} + }, + group: { + _id: { + appid: '$appid', + version: '$version', + platform: '$platform', + channel: '$channel', + old_device_id: '$device_id' + }, + create_time: { + $min: '$create_time' + } + }, + sort: { + create_time: 1 + }, + getAll: true + }) + + if(statOldDidRes.data.length){ + for(const osti in statOldDidRes.data) { + data = statOldDidRes.data[osti] + statKey = uniCrypto.md5(data._id.appid + data._id.platform + data._id.version + data._id + .channel) + if(!data._id.old_device_id) { + continue + } + + if (!statData[statKey]) { + statData[statKey] = { + appid: data._id.appid, + platform: data._id.platform, + version: data._id.version, + channel: data._id.channel, + device_ids: [], + old_device_ids: [], + old_info: [] + } + statData[statKey].old_device_ids.push(data._id.old_device_id) + } else { + statData[statKey].old_device_ids.push(data._id.old_device_id) + } + if(!statData[statKey].old_info[data._id.old_device_id]) { + statData[statKey].old_info[data._id.old_device_id] = { + create_time: data.create_time + } + } + } + } + } + } + this.fillData = [] + for (const sk in statData) { + await this.getFillData(statData[sk]) + } + + if (this.fillData.length > 0) { + res = await this.batchInsert(this.tableName, this.fillData) + } + } + return res + } + + /** + * 获取填充数据 + * @param {Object} data + */ + async getFillData(data) { + // 平台信息 + let platformInfo = null + if (this.platforms && this.platforms[data.platform]) { + platformInfo = this.platforms[data.platform] + } else { + const platform = new Platform() + platformInfo = await platform.getPlatformAndCreate(data.platform, null) + if (!platformInfo || platformInfo.length === 0) { + platformInfo._id = '' + } + this.platforms[data.platform] = platformInfo + if (this.debug) { + console.log('platformInfo', JSON.stringify(platformInfo)) + } + } + + // 渠道信息 + let channelInfo = null + const channelKey = data.appid + '_' + platformInfo._id + '_' + data.channel + if (this.channels && this.channels[channelKey]) { + channelInfo = this.channels[channelKey] + } else { + const channel = new Channel() + channelInfo = await channel.getChannelAndCreate(data.appid, platformInfo._id, data.channel) + if (!channelInfo || channelInfo.length === 0) { + channelInfo._id = '' + } + this.channels[channelKey] = channelInfo + if (this.debug) { + console.log('channelInfo', JSON.stringify(channelInfo)) + } + } + + // 版本信息 + let versionInfo = null + const versionKey = data.appid + '_' + data.platform + '_' + data.version + if (this.versions && this.versions[versionKey]) { + versionInfo = this.versions[versionKey] + } else { + const version = new Version() + versionInfo = await version.getVersionAndCreate(data.appid, data.platform, data.version) + if (!versionInfo || versionInfo.length === 0) { + versionInfo._id = '' + } + this.versions[versionKey] = versionInfo + if (this.debug) { + console.log('versionInfo', JSON.stringify(versionInfo)) + } + } + + const datetime = new DateTime() + const dateDimension = datetime.getTimeDimensionByType('week', 0, this.startTime) + const dateMonthDimension = datetime.getTimeDimensionByType('month', 0, this.startTime) + + if(data.device_ids) { + // 取出本周已经存储的device_id + const weekHaveDeviceList = [] + const haveWeekList = await this.selectAll(this.tableName, { + appid: data.appid, + version_id: versionInfo._id, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + device_id: { + $in: data.device_ids + }, + dimension: 'week', + create_time: { + $gte: dateDimension.startTime, + $lte: dateDimension.endTime + } + }, { + device_id: 1 + }) + if (haveWeekList.data.length > 0) { + for (const hui in haveWeekList.data) { + weekHaveDeviceList.push(haveWeekList.data[hui].device_id) + } + } + if (this.debug) { + console.log('weekHaveDeviceList', JSON.stringify(weekHaveDeviceList)) + } + + // 取出本月已经存储的device_id + const monthHaveDeviceList = [] + const haveMonthList = await this.selectAll(this.tableName, { + appid: data.appid, + version_id: versionInfo._id, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + device_id: { + $in: data.device_ids + }, + dimension: 'month', + create_time: { + $gte: dateMonthDimension.startTime, + $lte: dateMonthDimension.endTime + } + }, { + device_id: 1 + }) + if (haveMonthList.data.length > 0) { + for (const hui in haveMonthList.data) { + monthHaveDeviceList.push(haveMonthList.data[hui].device_id) + } + } + if (this.debug) { + console.log('monthHaveDeviceList', JSON.stringify(monthHaveDeviceList)) + } + //数据填充 + for (const ui in data.device_ids) { + //周活跃数据填充 + if (!weekHaveDeviceList.includes(data.device_ids[ui])) { + this.fillData.push({ + appid: data.appid, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + version_id: versionInfo._id, + is_new: data.info[data.device_ids[ui]].is_new, + device_id: data.device_ids[ui], + dimension: 'week', + create_time: data.info[data.device_ids[ui]].create_time + }) + } + //月活跃数据填充 + if (!monthHaveDeviceList.includes(data.device_ids[ui])) { + this.fillData.push({ + appid: data.appid, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + version_id: versionInfo._id, + is_new: data.info[data.device_ids[ui]].is_new, + device_id: data.device_ids[ui], + dimension: 'month', + create_time: data.info[data.device_ids[ui]].create_time + }) + } + } + } + + if(data.old_device_ids) { + // 取出本周已经存储的old_device_id + const weekHaveOldDeviceList = [] + const haveOldWeekList = await this.selectAll(this.tableName, { + appid: data.appid, + version_id: versionInfo._id, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + device_id: { + $in: data.old_device_ids + }, + dimension: 'week-old', + create_time: { + $gte: dateDimension.startTime, + $lte: dateDimension.endTime + } + }, { + device_id: 1 + }) + if (haveOldWeekList.data.length > 0) { + for (const hui in haveOldWeekList.data) { + weekHaveOldDeviceList.push(haveOldWeekList.data[hui].device_id) + } + } + if (this.debug) { + console.log('weekHaveOldDeviceList', JSON.stringify(weekHaveOldDeviceList)) + } + + // 取出本月已经存储的old_device_id + const monthHaveOldDeviceList = [] + const haveOldMonthList = await this.selectAll(this.tableName, { + appid: data.appid, + version_id: versionInfo._id, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + device_id: { + $in: data.old_device_ids + }, + dimension: 'month-old', + create_time: { + $gte: dateMonthDimension.startTime, + $lte: dateMonthDimension.endTime + } + }, { + device_id: 1 + }) + if (haveOldMonthList.data.length > 0) { + for (const hui in haveOldMonthList.data) { + monthHaveOldDeviceList.push(haveOldMonthList.data[hui].device_id) + } + } + if (this.debug) { + console.log('monthHaveOldDeviceList', JSON.stringify(monthHaveOldDeviceList)) + } + //数据填充 + for (const ui in data.old_device_ids) { + //周活跃数据填充 + if (!weekHaveOldDeviceList.includes(data.old_device_ids[ui])) { + this.fillData.push({ + appid: data.appid, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + version_id: versionInfo._id, + is_new: 0, + device_id: data.old_device_ids[ui], + dimension: 'week-old', + create_time: data.old_info[data.old_device_ids[ui]].create_time + }) + } + //月活跃数据填充 + if (!monthHaveOldDeviceList.includes(data.old_device_ids[ui])) { + this.fillData.push({ + appid: data.appid, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + version_id: versionInfo._id, + is_new: 0, + device_id: data.old_device_ids[ui], + dimension: 'month-old', + create_time: data.old_info[data.old_device_ids[ui]].create_time + }) + } + } + } + + return true + } + + /** + * 日志清理,此处日志为临时数据并不需要自定义清理,默认为固定值即可 + */ + async clean() { + // 清除周数据,周留存统计最高需要10周数据,多余的为无用数据 + const weeks = 10 + console.log('Clean device\'s weekly logs - week:', weeks) + + const dateTime = new DateTime() + + const res = await this.delete(this.tableName, { + dimension: 'week', + create_time: { + $lt: dateTime.getTimeBySetWeek(0 - weeks) + } + }) + + if (!res.code) { + console.log('Clean device\'s weekly logs - res:', res) + } + + // 清除月数据,月留存统计最高需要10个月数据,多余的为无用数据 + const monthes = 10 + console.log('Clean device\'s monthly logs - month:', monthes) + const monthRes = await this.delete(this.tableName, { + dimension: 'month', + create_time: { + $lt: dateTime.getTimeBySetMonth(0 - monthes) + } + }) + if (!monthRes.code) { + console.log('Clean device\'s monthly logs - res:', res) + } + return monthRes + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/activeUsers.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/activeUsers.js new file mode 100644 index 0000000..bd15f75 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/activeUsers.js @@ -0,0 +1,314 @@ +/** + * @class ActiveUsers 活跃用户模型 - 每日跑批合并,仅添加本周/本月首次访问的用户。 + */ +const BaseMod = require('./base') +const Platform = require('./platform') +const Channel = require('./channel') +const Version = require('./version') +const UserSessionLog = require('./userSessionLog') +const { + DateTime, + UniCrypto +} = require('../lib') +module.exports = class ActiveUsers extends BaseMod { + constructor() { + super() + this.tableName = 'active-users' + this.platforms = [] + this.channels = [] + this.versions = [] + } + + async stat(date, reset) { + const dateTime = new DateTime() + const dateDimension = dateTime.getTimeDimensionByType('day', -1, date) + this.startTime = dateDimension.startTime + // 查看当前时间段数据是否已存在,防止重复生成 + if (!reset) { + const checkRes = await this.getCollection(this.tableName).where({ + create_time: { + $gte: dateDimension.startTime, + $lte: dateDimension.endTime + } + }).get() + if (checkRes.data.length > 0) { + console.log('data have exists') + return { + code: 1003, + msg: 'Users data in this time have already existed' + } + } + } else { + const delRes = await this.delete(this.tableName, { + create_time: { + $gte: dateDimension.startTime, + $lte: dateDimension.endTime + } + }) + console.log('Delete old data result:', JSON.stringify(delRes)) + } + + const userSessionLog = new UserSessionLog() + const statRes = await this.aggregate(userSessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + create_time: 1, + uid: 1 + }, + match: { + create_time: { + $gte: dateDimension.startTime, + $lte: dateDimension.endTime + } + }, + group: { + _id: { + appid: '$appid', + version: '$version', + platform: '$platform', + channel: '$channel', + uid: '$uid' + }, + create_time: { + $min: '$create_time' + } + }, + sort: { + create_time: 1 + }, + getAll: true + }) + + let res = { + code: 0, + msg: 'success' + } + // if (this.debug) { + // console.log('statRes', JSON.stringify(statRes)) + // } + if (statRes.data.length > 0) { + const uniCrypto = new UniCrypto() + // 同应用、平台、渠道、版本的数据合并 + const statData = []; + let statKey; + let data + + for (const sti in statRes.data) { + data = statRes.data[sti] + statKey = uniCrypto.md5(data._id.appid + data._id.platform + data._id.version + data._id + .channel) + if (!statData[statKey]) { + statData[statKey] = { + appid: data._id.appid, + platform: data._id.platform, + version: data._id.version, + channel: data._id.channel, + uids: [], + info: [] + } + statData[statKey].uids.push(data._id.uid) + statData[statKey].info[data._id.uid] = { + create_time: data.create_time + } + } else { + statData[statKey].uids.push(data._id.uid) + statData[statKey].info[data._id.uid] = { + create_time: data.create_time + } + } + } + + this.fillData = [] + for (const sk in statData) { + await this.getFillData(statData[sk]) + } + + if (this.fillData.length > 0) { + res = await this.batchInsert(this.tableName, this.fillData) + } + } + return res + } + + async getFillData(data) { + // 平台信息 + let platformInfo = null + if (this.platforms && this.platforms[data.platform]) { + platformInfo = this.platforms[data.platform] + } else { + const platform = new Platform() + platformInfo = await platform.getPlatformAndCreate(data.platform, null) + if (!platformInfo || platformInfo.length === 0) { + platformInfo._id = '' + } + this.platforms[data.platform] = platformInfo + if (this.debug) { + console.log('platformInfo', JSON.stringify(platformInfo)) + } + } + + // 渠道信息 + let channelInfo = null + const channelKey = data.appid + '_' + platformInfo._id + '_' + data.channel + if (this.channels && this.channels[channelKey]) { + channelInfo = this.channels[channelKey] + } else { + const channel = new Channel() + channelInfo = await channel.getChannelAndCreate(data.appid, platformInfo._id, data.channel) + if (!channelInfo || channelInfo.length === 0) { + channelInfo._id = '' + } + this.channels[channelKey] = channelInfo + if (this.debug) { + console.log('channelInfo', JSON.stringify(channelInfo)) + } + } + + // 版本信息 + let versionInfo = null + const versionKey = data.appid + '_' + data.platform + '_' + data.version + if (this.versions && this.versions[versionKey]) { + versionInfo = this.versions[versionKey] + } else { + const version = new Version() + versionInfo = await version.getVersionAndCreate(data.appid, data.platform, data.version) + if (!versionInfo || versionInfo.length === 0) { + versionInfo._id = '' + } + this.versions[versionKey] = versionInfo + if (this.debug) { + console.log('versionInfo', JSON.stringify(versionInfo)) + } + } + + // 是否在本周内已存在 + const datetime = new DateTime() + const dateDimension = datetime.getTimeDimensionByType('week', 0, this.startTime) + + // 取出本周已经存储的uid + const weekHaveUserList = [] + const haveWeekList = await this.selectAll(this.tableName, { + appid: data.appid, + version_id: versionInfo._id, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + uid: { + $in: data.uids + }, + dimension: 'week', + create_time: { + $gte: dateDimension.startTime, + $lte: dateDimension.endTime + } + }, { + uid: 1 + }) + + if (this.debug) { + console.log('haveWeekList', JSON.stringify(haveWeekList)) + } + + if (haveWeekList.data.length > 0) { + for (const hui in haveWeekList.data) { + weekHaveUserList.push(haveWeekList.data[hui].uid) + } + } + + // 取出本月已经存储的uid + const dateMonthDimension = datetime.getTimeDimensionByType('month', 0, this.startTime) + const monthHaveUserList = [] + const haveMonthList = await this.selectAll(this.tableName, { + appid: data.appid, + version_id: versionInfo._id, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + uid: { + $in: data.uids + }, + dimension: 'month', + create_time: { + $gte: dateMonthDimension.startTime, + $lte: dateMonthDimension.endTime + } + }, { + uid: 1 + }) + + if (this.debug) { + console.log('haveMonthList', JSON.stringify(haveMonthList)) + } + + if (haveMonthList.data.length > 0) { + for (const hui in haveMonthList.data) { + monthHaveUserList.push(haveMonthList.data[hui].uid) + } + } + + for (const ui in data.uids) { + if (!weekHaveUserList.includes(data.uids[ui])) { + this.fillData.push({ + appid: data.appid, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + version_id: versionInfo._id, + uid: data.uids[ui], + dimension: 'week', + create_time: data.info[data.uids[ui]].create_time + }) + } + + if (!monthHaveUserList.includes(data.uids[ui])) { + this.fillData.push({ + appid: data.appid, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + version_id: versionInfo._id, + uid: data.uids[ui], + dimension: 'month', + create_time: data.info[data.uids[ui]].create_time + }) + } + } + + return true + } + + /** + * 日志清理,此处日志为临时数据并不需要自定义清理,默认为固定值即可 + */ + async clean() { + // 清除周数据,周留存统计最高需要10周数据,多余的为无用数据 + const weeks = 10 + console.log('Clean user\'s weekly logs - week:', weeks) + + const dateTime = new DateTime() + + const res = await this.delete(this.tableName, { + dimension: 'week', + create_time: { + $lt: dateTime.getTimeBySetWeek(0 - weeks) + } + }) + + if (!res.code) { + console.log('Clean user\'s weekly logs - res:', res) + } + + // 清除月数据,月留存统计最高需要10个月数据,多余的为无用数据 + const monthes = 10 + console.log('Clean user\'s monthly logs - month:', monthes) + const monthRes = await this.delete(this.tableName, { + dimension: 'month', + create_time: { + $lt: dateTime.getTimeBySetMonth(0 - monthes) + } + }) + if (!monthRes.code) { + console.log('Clean user\'s monthly logs - res:', res) + } + return monthRes + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/appCrashLogs.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/appCrashLogs.js new file mode 100644 index 0000000..fc64df5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/appCrashLogs.js @@ -0,0 +1,37 @@ +/** + * @class AppCrashLogs 原生应用崩溃日志模型 + * @function clean 原生应用崩溃日志清理函数 + */ +const BaseMod = require('./base') +const { + DateTime, + UniCrypto +} = require('../lib') +module.exports = class AppCrashLogs extends BaseMod { + constructor() { + super() + this.tableName = 'app-crash-logs' + } + + /** + * 原生应用崩溃日志清理函数 + * @param {Number} days 保留天数 + */ + async clean(days = 7) { + days = Math.max(parseInt(days), 1) + console.log('clean app crash logs - day:', days) + + const dateTime = new DateTime() + + const res = await this.delete(this.tableName, { + create_time: { + $lt: dateTime.getTimeBySetDays(0 - days) + } + }) + + if (!res.code) { + console.log('clean app crash log:', res) + } + return res + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/base.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/base.js new file mode 100644 index 0000000..2914df2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/base.js @@ -0,0 +1,485 @@ +/** + * @class BaseMod 数据模型基类,提供基础服务支持 + */ +const { + getConfig +} = require('../../shared') +//基类 +module.exports = class BaseMod { + constructor() { + //配置信息 + this.config = getConfig('config') + //开启/关闭debug + this.debug = this.config.debug + //主键 + this.primaryKey = '_id' + //单次查询最多返回 500 条数据(阿里云500,腾讯云1000,这里取最小值) + this.selectMaxLimit = 500 + //数据表前缀 + this.tablePrefix = 'uni-stat' + //数据表连接符 + this.tableConnectors = '-' + //数据表名 + this.tableName = '' + //参数 + this.params = {} + //数据库连接 + this._dbConnection() + //redis连接 + this._redisConnection() + } + + /** + * 建立uniCloud数据库连接 + */ + _dbConnection() { + if (!this.db) { + try { + this.db = uniCloud.database() + this.dbCmd = this.db.command + this.dbAggregate = this.dbCmd.aggregate + } catch (e) { + console.error('database connection failed: ' + e) + throw new Error('database connection failed: ' + e) + } + } + } + + /** + * 建立uniCloud redis连接 + */ + _redisConnection() { + if (this.config.redis && !this.redis) { + try { + this.redis = uniCloud.redis() + } catch (e) { + console.log('redis server connection failed: ' + e) + } + } + } + + /** + * 获取uni统计配置项 + * @param {String} key + */ + getConfig(key) { + return this.config[key] + } + + /** + * 获取带前缀的数据表名称 + * @param {String} tab 表名 + * @param {Boolean} useDBPre 是否使用数据表前缀 + */ + getTableName(tab, useDBPre = true) { + tab = tab || this.tableName + const table = (useDBPre && this.tablePrefix && tab.indexOf(this.tablePrefix) !== 0) ? this.tablePrefix + this + .tableConnectors + tab : tab + return table + } + + /** + * 获取数据集 + * @param {String} tab表名 + * @param {Boolean} useDBPre 是否使用数据表前缀 + */ + getCollection(tab, useDBPre = true) { + return this.db.collection(this.getTableName(tab, useDBPre)) + } + + /** + * 获取reids缓存 + * @param {String} key reids缓存键值 + */ + async getCache(key) { + if (!this.redis || !key) { + return false + } + let cacheResult = await this.redis.get(key) + + if (this.debug) { + console.log('get cache result by key:' + key, cacheResult) + } + + if (cacheResult) { + try { + cacheResult = JSON.parse(cacheResult) + } catch (e) { + if (this.debug) { + console.log('json parse error: ' + e) + } + } + } + return cacheResult + } + + /** + * 设置redis缓存 + * @param {String} key 键值 + * @param {String} val 值 + * @param {Number} expireTime 过期时间 + */ + async setCache(key, val, expireTime) { + if (!this.redis || !key) { + return false + } + + if (val instanceof Object) { + val = JSON.stringify(val) + } + + if (this.debug) { + console.log('set cache result by key:' + key, val) + } + + return await this.redis.set(key, val, 'EX', expireTime || this.config.cachetime) + } + + /** + * 清除redis缓存 + * @param {String} key 键值 + */ + async clearCache(key) { + if (!this.redis || !key) { + return false + } + + if (this.debug) { + console.log('delete cache by key:' + key) + } + + return await this.redis.del(key) + } + + /** + * 通过数据表主键(_id)获取数据 + * @param {String} tab 表名 + * @param {String} id 主键值 + * @param {Boolean} useDBPre 是否使用数据表前缀 + */ + async getById(tab, id, useDBPre = true) { + const condition = {} + condition[this.primaryKey] = id + const info = await this.getCollection(tab, useDBPre).where(condition).get() + return (info && info.data.length > 0) ? info.data[0] : [] + } + + /** + * 插入数据到数据表 + * @param {String} tab 表名 + * @param {Object} params 字段参数 + * @param {Boolean} useDBPre 是否使用数据表前缀 + */ + async insert(tab, params, useDBPre = true) { + params = params || this.params + return await this.getCollection(tab, useDBPre).add(params) + } + + /** + * 修改数据表数据 + * @param {String} tab 表名 + * @param {Object} params 字段参数 + * @param {Object} condition 条件 + * @param {Boolean} useDBPre 是否使用数据表前缀 + */ + async update(tab, params, condition, useDBPre = true) { + params = params || this.params + return await this.getCollection(tab).where(condition).update(params) + } + + /** + * 删除数据表数据 + * @param {String} tab 表名 + * @param {Object} condition 条件 + * @param {Boolean} useDBPre 是否使用数据表前缀 + */ + async delete(tab, condition, useDBPre = true) { + if (!condition) { + return false + } + return await this.getCollection(tab, useDBPre).where(condition).remove() + } + + /** + * 批量插入 - 云服务空间对单条mongo语句执行时间有限制,所以批量插入需限制每次执行条数 + * @param {String} tab 表名 + * @param {Object} data 数据集合 + * @param {Boolean} useDBPre 是否使用数据表前缀 + */ + async batchInsert(tab, data, useDBPre = true) { + let batchInsertNum = this.getConfig('batchInsertNum') || 3000 + batchInsertNum = Math.min(batchInsertNum, 5000) + const insertNum = Math.ceil(data.length / batchInsertNum) + let start; + let end; + let fillData; + let insertRes; + const res = { + code: 0, + msg: 'success', + data: { + inserted: 0 + } + } + for (let p = 0; p < insertNum; p++) { + start = p * batchInsertNum + end = Math.min(start + batchInsertNum, data.length) + fillData = [] + for (let i = start; i < end; i++) { + fillData.push(data[i]) + } + if (fillData.length > 0) { + insertRes = await this.insert(tab, fillData, useDBPre) + if (insertRes && insertRes.inserted) { + res.data.inserted += insertRes.inserted + } + } + } + return res + } + + /** + * 批量删除 - 云服务空间对单条mongo语句执行时间有限制,所以批量删除需限制每次执行条数 + * @param {String} tab 表名 + * @param {Object} condition 条件 + * @param {Boolean} useDBPre 是否使用数据表前缀 + */ + async batchDelete(tab, condition, useDBPre = true) { + const batchDeletetNum = 5000; + let deleteIds; + let delRes; + let thisCondition + const res = { + code: 0, + msg: 'success', + data: { + deleted: 0 + } + } + let run = true + while (run) { + const dataRes = await this.getCollection(tab).where(condition).limit(batchDeletetNum).get() + if (dataRes && dataRes.data.length > 0) { + deleteIds = [] + for (let i = 0; i < dataRes.data.length; i++) { + deleteIds.push(dataRes.data[i][this.primaryKey]) + } + if (deleteIds.length > 0) { + thisCondition = {} + thisCondition[this.primaryKey] = { + $in: deleteIds + } + delRes = await this.delete(tab, thisCondition, useDBPre) + if (delRes && delRes.deleted) { + res.data.deleted += delRes.deleted + } + } + } else { + run = false + } + } + return res + } + + /** + * 基础查询 + * @param {String} tab 表名 + * @param {Object} params 查询参数 where:where条件,field:返回字段,skip:跳过的文档数,limit:返回的记录数,orderBy:排序,count:返回查询结果的数量 + * @param {Boolean} useDBPre 是否使用数据表前缀 + */ + async select(tab, params, useDBPre = true) { + const { + where, + field, + skip, + limit, + orderBy, + count + } = params + + const query = this.getCollection(tab, useDBPre) + + //拼接where条件 + if (where) { + if (where.length > 0) { + where.forEach(key => { + query.where(where[key]) + }) + } else { + query.where(where) + } + } + + //排序 + if (orderBy) { + Object.keys(orderBy).forEach(key => { + query.orderBy(key, orderBy[key]) + }) + } + + //指定跳过的文档数 + if (skip) { + query.skip(skip) + } + + //指定返回的记录数 + if (limit) { + query.limit(limit) + } + + //指定返回字段 + if (field) { + query.field(field) + } + + //指定返回查询结果数量 + if (count) { + return await query.count() + } + + //返回查询结果数据 + return await query.get() + } + + /** + * 查询并返回全部数据 + * @param {String} tab 表名 + * @param {Object} condition 条件 + * @param {Object} field 指定查询返回字段 + * @param {Boolean} useDBPre 是否使用数据表前缀 + */ + async selectAll(tab, condition, field = {}, useDBPre = true) { + const countRes = await this.getCollection(tab, useDBPre).where(condition).count() + if (countRes && countRes.total > 0) { + const pageCount = Math.ceil(countRes.total / this.selectMaxLimit) + let res, returnData + for (let p = 0; p < pageCount; p++) { + res = await this.getCollection(tab, useDBPre).where(condition).orderBy(this.primaryKey, 'asc').skip(p * + this.selectMaxLimit).limit(this.selectMaxLimit).field(field).get() + if (!returnData) { + returnData = res + } else { + returnData.affectedDocs += res.affectedDocs + for (const i in res.data) { + returnData.data.push(res.data[i]) + } + } + } + return returnData + } + return { + affectedDocs: 0, + data: [] + } + } + + /** + * 聚合查询 + * @param {String} tab 表名 + * @param {Object} params 聚合参数 + */ + async aggregate(tab, params) { + let { + project, + match, + lookup, + group, + skip, + limit, + sort, + getAll, + useDBPre, + addFields + } = params + //useDBPre 是否使用数据表前缀 + useDBPre = (useDBPre !== null && useDBPre !== undefined) ? useDBPre : true + const query = this.getCollection(tab, useDBPre).aggregate() + + //设置返回字段 + if (project) { + query.project(project) + } + + //设置匹配条件 + if (match) { + query.match(match) + } + + //数据表关联 + if (lookup) { + query.lookup(lookup) + } + + //分组 + if (group) { + if (group.length > 0) { + for (const gi in group) { + query.group(group[gi]) + } + } else { + query.group(group) + } + } + + //添加字段 + if (addFields) { + query.addFields(addFields) + } + + //排序 + if (sort) { + query.sort(sort) + } + + //分页 + if (skip) { + query.skip(skip) + } + if (limit) { + query.limit(limit) + } else if (!getAll) { + query.limit(this.selectMaxLimit) + } + + //如果未指定全部返回则直接返回查询结果 + if (!getAll) { + return await query.end() + } + + //若指定了全部返回则分页查询全部结果后再返回 + const resCount = await query.group({ + _id: {}, + aggregate_count: { + $sum: 1 + } + }).end() + + if (resCount && resCount.data.length > 0 && resCount.data[0].aggregate_count > 0) { + //分页查询 + const total = resCount.data[0].aggregate_count + const pageCount = Math.ceil(total / this.selectMaxLimit) + let res, returnData + params.limit = this.selectMaxLimit + params.getAll = false + //结果合并 + for (let p = 0; p < pageCount; p++) { + params.skip = p * params.limit + res = await this.aggregate(tab, params) + if (!returnData) { + returnData = res + } else { + returnData.affectedDocs += res.affectedDocs + for (const i in res.data) { + returnData.data.push(res.data[i]) + } + } + } + return returnData + } else { + return { + affectedDocs: 0, + data: [] + } + } + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/channel.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/channel.js new file mode 100644 index 0000000..45c0ab0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/channel.js @@ -0,0 +1,107 @@ +/** + * @class Channel 渠道模型 + */ +const BaseMod = require('./base') +const Scenes = require('./scenes') +const { + DateTime +} = require('../lib') +module.exports = class Channel extends BaseMod { + constructor() { + super() + this.tableName = 'app-channels' + this.scenes = new Scenes() + } + + /** + * 获取渠道信息 + * @param {String} appid + * @param {String} platformId 平台编号 + * @param {String} channel 渠道代码 + */ + async getChannel(appid, platformId, channel) { + const cacheKey = 'uni-stat-channel-' + appid + '-' + platformId + '-' + channel + let channelData = await this.getCache(cacheKey) + if (!channelData) { + const channelInfo = await this.getCollection(this.tableName).where({ + appid: appid, + platform_id: platformId, + channel_code: channel + }).limit(1).get() + channelData = [] + if (channelInfo.data.length > 0) { + channelData = channelInfo.data[0] + if (channelData.channel_name === '') { + const scenesName = await this.scenes.getScenesNameByPlatformId(platformId, channel) + if (scenesName) { + await this.update(this.tableName, { + channel_name: scenesName, + update_time: new DateTime().getTime() + }, { + _id: channelData._id + }) + } + } + await this.setCache(cacheKey, channelData) + } + } + return channelData + } + + /** + * 获取渠道信息没有则进行创建 + * @param {String} appid + * @param {String} platformId + * @param {String} channel + */ + async getChannelAndCreate(appid, platformId, channel) { + if (!appid || !platformId) { + return [] + } + + const channelInfo = await this.getChannel(appid, platformId, channel) + if (channelInfo.length === 0) { + const thisTime = new DateTime().getTime() + const insertParam = { + appid: appid, + platform_id: platformId, + channel_code: channel, + channel_name: await this.scenes.getScenesNameByPlatformId(platformId, channel), + create_time: thisTime, + update_time: thisTime + } + const res = await this.insert(this.tableName, insertParam) + if (res && res.id) { + return Object.assign(insertParam, { + _id: res.id + }) + } + } + return channelInfo + } + + /** + * 获取渠道_id + * @param {String} appid + * @param {String} platformId + * @param {String} channel + */ + async getChannelId(appid, platformId, channel) { + const channelInfo = await this.getChannel(appid, platformId, channel) + return channelInfo.length > 0 ? channelInfo._id : '' + } + + /** + * 获取渠道码或者场景值 + * @param {Object} params 上报参数 + */ + getChannelCode(params) { + //小程序未上报渠道则使用场景值 + if (params.ch) { + return params.ch + } else if (params.sc && params.ut.indexOf('mp-') === 0) { + return params.sc + } + return this.scenes.defualtCode + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/device.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/device.js new file mode 100644 index 0000000..1784c00 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/device.js @@ -0,0 +1,184 @@ +/** + * @class Device 设备模型 + */ +const BaseMod = require('./base') +const Platform = require('./platform') +const { + DateTime +} = require('../lib') +module.exports = class Device extends BaseMod { + constructor() { + super() + this.tableName = 'opendb-device' + this.tablePrefix = false + this.cacheKeyPre = 'uni-stat-device-' + } + + /** + * 通过设备编号获取设备信息 + * @param {Object} deviceId 设备编号 + */ + async getDeviceById(deviceId) { + const cacheKey = this.cacheKeyPre + deviceId + let deviceData = await this.getCache(cacheKey) + if (!deviceData) { + const deviceRes = await this.getCollection().where({ + device_id: deviceId + }).get() + deviceData = [] + if (deviceRes.data.length > 0) { + deviceData = deviceRes.data[0] + await this.setCache(cacheKey, deviceData) + } + } + return deviceData + } + + /** + * 设置设备信息 + * @param {Object} params 上报参数 + */ + async setDevice(params) { + // 设备信息 + if (!params.did) { + return { + code: 200, + msg: 'Parameter "did" not found' + } + } + const deviceData = await this.getDeviceById(params.did) + //不存在则添加 + if(deviceData.length === 0) { + return await this.addDevice(params) + } else { + return await this.updateDevice(params, deviceData) + } + } + + /** + * 添加设备信息 + * @param {Object} params 上报参数 + */ + async addDevice(params) { + const dateTime = new DateTime() + const platform = new Platform() + const fillParams = { + device_id: params.did, + appid: params.ak, + vendor: params.brand ? params.brand : '', + push_clientid: params.cid ? params.cid : '', + imei: params.imei ? params.imei : '', + oaid: params.oaid ? params.oaid : '', + idfa: params.idfa ? params.idfa : '', + imsi: params.imsi ? params.imsi : '', + model: params.md ? params.md : '', + uni_platform: params.up ? params.up : '', + os_name: params.on ? params.on : platform.getOsName(params.p), + os_version: params.sv ? params.sv : '', + os_language: params.lang ? params.lang : '', + os_theme: params.ot ? params.ot : '', + pixel_ratio: params.pr ? params.pr : '', + network_model: params.net ? params.net : '', + window_width: params.ww ? params.ww : '', + window_height: params.wh ? params.wh : '', + screen_width: params.sw ? params.sw : '', + screen_height: params.sh ? params.sh : '', + rom_name: params.rn ? params.rn : '', + rom_version: params.rv ? params.rv : '', + location_ip: params.ip ? params.ip : '', + location_latitude: params.lat ? parseFloat(params.lat) : 0, + location_longitude: params.lng ? parseFloat(params.lng) : 0, + location_country: params.cn ? params.cn : '', + location_province: params.pn ? params.pn : '', + location_city: params.ct ? params.ct : '', + create_date: dateTime.getTime(), + last_update_date: dateTime.getTime() + } + const res = await this.insert(this.tableName, fillParams) + if (res && res.id) { + return { + code: 0, + msg: 'success', + } + } else { + return { + code: 500, + msg: 'Device data filled error' + } + } + } + + /** + * 修改设备信息 + * @param {Object} params + * @param {Object} deviceData + */ + async updateDevice(params, deviceData) { + //最新的参数 + const dateTime = new DateTime() + const platform = new Platform() + console.log('device params', params) + const newDeviceParams = { + appid: params.ak, + push_clientid: params.cid ? params.cid : '', + imei: params.imei ? params.imei : '', + oaid: params.oaid ? params.oaid : '', + idfa: params.idfa ? params.idfa : '', + imsi: params.imsi ? params.imsi : '', + uni_platform: params.up ? params.up : '', + os_name: params.on ? params.on : platform.getOsName(params.p), + os_version: params.sv ? params.sv : '', + os_language: params.lang ? params.lang : '', + pixel_ratio: params.pr ? params.pr : '', + network_model: params.net ? params.net : '', + window_width: params.ww ? params.ww : '', + window_height: params.wh ? params.wh : '', + screen_width: params.sw ? params.sw : '', + screen_height: params.sh ? params.sh : '', + rom_name: params.rn ? params.rn : '', + rom_version: params.rv ? params.rv : '', + location_ip: params.ip ? params.ip : '', + location_latitude: params.lat ? parseFloat(params.lat) : '', + location_longitude: params.lng ? parseFloat(params.lng) : '', + location_country: params.cn ? params.cn : '', + location_province: params.pn ? params.pn : '', + location_city: params.ct ? params.ct : '', + } + + //检查是否有需要更新的数据 + const updateData = {} + for(let key in newDeviceParams) { + if(newDeviceParams[key] && newDeviceParams[key] !== deviceData[key]) { + updateData[key] = newDeviceParams[key] + } + } + + if(Object.keys(updateData).length) { + if(this.debug) { + console.log('Device need to update', updateData) + } + //数据更新 + updateData.last_update_date = dateTime.getTime() + await this.update(this.tableName, updateData, {device_id: params.did}) + } else { + if(this.debug) { + console.log('Device not need update', newDeviceParams) + } + } + + return { + code: 0, + msg: 'success' + } + } + + async bindPush(params) { + if (!params.cid) { + return { + code: 200, + msg: 'Parameter "cid" not found' + } + } + return await this.setDevice(params) + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/errorLog.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/errorLog.js new file mode 100644 index 0000000..05e6c98 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/errorLog.js @@ -0,0 +1,141 @@ +/** + * @class ErrorLog 错误日志模型 + */ +const BaseMod = require('./base') +const Platform = require('./platform') +const Channel = require('./channel') +const { + DateTime, + UniCrypto +} = require('../lib') +module.exports = class ErrorLog extends BaseMod { + constructor() { + super() + this.tableName = 'error-logs' + } + + /** + * 错误日志数据填充 + * @param {Object} reportParams 上报参数 + */ + async fill(reportParams) { + let params, errorHash, errorCount, cacheKey; + const fillParams = [] + const platform = new Platform() + const dateTime = new DateTime() + const uniCrypto = new UniCrypto() + const channel = new Channel() + const { + needCheck, + checkTime + } = this.getConfig('errorCheck') + const errorCheckTime = Math.max(checkTime, 1) + let spaceId + let spaceProvider + for (const rk in reportParams) { + params = reportParams[rk] + errorHash = uniCrypto.md5(params.em) + cacheKey = 'error-count-' + errorHash + // 校验在指定时间段内是否已存在相同的错误项 + if (needCheck) { + errorCount = await this.getCache(cacheKey) + if (!errorCount) { + errorCount = await this.getCollection(this.tableName).where({ + error_hash: errorHash, + create_time: { + $gte: dateTime.getTime() - errorCheckTime * 60000 + } + }).count() + if (errorCount && errorCount.total > 0) { + await this.setCache(cacheKey, errorCount, errorCheckTime * 60) + } + } + + if (errorCount && errorCount.total > 0) { + if (this.debug) { + console.log('This error have already existsed: ' + params.em) + } + continue + } + } + + //获取云端信息 + spaceId = null + spaceProvider = null + if (params.spi) { + //云函数调用参数 + spaceId = params.spi.spaceId + spaceProvider = params.spi.provider + } else { + //云对象调用参数 + if (params.spid) { + spaceId = params.spid + } + if (params.sppd) { + spaceProvider = params.sppd + } + } + + // 填充数据 + fillParams.push({ + appid: params.ak, + version: params.v ? params.v : '', + platform: platform.getPlatformCode(params.ut, params.p), + channel: channel.getChannelCode(params), + device_id: params.did, + uid: params.uid ? params.uid : '', + os: params.on ? params.on : platform.getOsName(params.p), + ua: params.ua ? params.ua : '', + page_url: params.url ? params.url : '', + space_id: spaceId ? spaceId : '', + space_provider: spaceProvider ? spaceProvider : '', + platform_version: params.mpv ? params.mpv : '', + error_msg: params.em ? params.em : '', + error_hash: errorHash, + create_time: dateTime.getTime() + }) + } + + if (fillParams.length === 0) { + return { + code: 200, + msg: 'Invild param' + } + } + + const res = await this.insert(this.tableName, fillParams) + if (res && res.inserted) { + return { + code: 0, + msg: 'success' + } + } else { + return { + code: 500, + msg: 'Filled error' + } + } + } + + /** + * 错误日志清理 + * @param {Number} days 日志保留天数 + */ + async clean(days) { + days = Math.max(parseInt(days), 1) + console.log('clean error logs - day:', days) + + const dateTime = new DateTime() + + const res = await this.delete(this.tableName, { + create_time: { + $lt: dateTime.getTimeBySetDays(0 - days) + } + }) + + if (!res.code) { + console.log('clean error log:', res) + } + return res + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/errorResult.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/errorResult.js new file mode 100644 index 0000000..5cd1ff6 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/errorResult.js @@ -0,0 +1,459 @@ +/** + * @class ErrorResult 错误结果统计模型 + */ +const BaseMod = require('./base') +const Platform = require('./platform') +const Channel = require('./channel') +const Version = require('./version') +const ErrorLog = require('./errorLog') +const AppCrashLogs = require('./appCrashLogs') +const SessionLog = require('./sessionLog') +const { + DateTime +} = require('../lib') +module.exports = class ErrorResult extends BaseMod { + constructor() { + super() + this.tableName = 'error-result' + this.platforms = [] + this.channels = [] + this.versions = [] + this.errors = [] + } + + /** + * 错误结果统计 + * @param {String} type 统计类型 hour:实时统计 day:按天统计,week:按周统计 month:按月统计 + * @param {Date|Time} date 指定日期或时间戳 + * @param {Boolean} reset 是否重置,为ture时会重置该批次数据 + */ + async stat(type, date, reset) { + //前端js错误统计 + const resJs = await this.statJs(type, date, reset) + //原生应用崩溃错误统计 + const resCrash = await this.statCrash(type, date, reset) + + return { + code: 0, + msg: 'success', + data: { + resJs, + resCrash + } + } + } + + /** + * 前端js错误结果统计 + * @param {String} type 统计类型 hour:实时统计 day:按天统计,week:按周统计 month:按月统计 + * @param {Date|Time} date 指定日期或时间戳 + * @param {Boolean} reset 是否重置,为ture时会重置该批次数据 + */ + async statJs(type, date, reset) { + const allowedType = ['day'] + if (!allowedType.includes(type)) { + return { + code: 1002, + msg: 'This type is not allowed' + } + } + this.fillType = type + const dateTime = new DateTime() + const dateDimension = dateTime.getTimeDimensionByType(type, -1, date) + this.startTime = dateDimension.startTime + this.endTime = dateDimension.endTime + + if (this.debug) { + console.log('dimension time', this.startTime + '--' + this.endTime) + } + + // 查看当前时间段日志是否已存在,防止重复生成 + if (!reset) { + const checkRes = await this.getCollection(this.tableName).where({ + type: 'js', + start_time: this.startTime, + end_time: this.endTime + }).get() + if (checkRes.data.length > 0) { + console.log('error log have existed') + return { + code: 1003, + msg: 'This log have existed' + } + } + } else { + const delRes = await this.delete(this.tableName, { + type: 'js', + start_time: this.startTime, + end_time: this.endTime + }) + console.log('delete old data result:', JSON.stringify(delRes)) + } + + // 数据获取 + this.errorLog = new ErrorLog() + const statRes = await this.aggregate(this.errorLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + error_hash: 1, + create_time: 1 + }, + match: { + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }, + group: { + _id: { + appid: '$appid', + version: '$version', + platform: '$platform', + channel: '$channel', + error_hash: '$error_hash' + }, + error_count: { + $sum: 1 + } + }, + sort: { + error_count: 1 + }, + getAll: true + }) + + let res = { + code: 0, + msg: 'success' + } + if (this.debug) { + console.log('statRes', JSON.stringify(statRes)) + } + if (statRes.data.length > 0) { + this.fillData = [] + for (const i in statRes.data) { + await this.fillJs(statRes.data[i]) + } + + if (this.fillData.length > 0) { + res = await this.batchInsert(this.tableName, this.fillData) + } + } + return res + } + + /** + * 前端js错误统计结果数据填充 + * @param {Object} data 数据集合 + */ + async fillJs(data) { + // 平台信息 + let platformInfo = null + if (this.platforms && this.platforms[data._id.platform]) { + //暂存下数据,减少读库 + platformInfo = this.platforms[data._id.platform] + } else { + const platform = new Platform() + platformInfo = await platform.getPlatformAndCreate(data._id.platform, null) + if (!platformInfo || platformInfo.length === 0) { + platformInfo._id = '' + } + this.platforms[data._id.platform] = platformInfo + if (this.debug) { + console.log('platformInfo', JSON.stringify(platformInfo)) + } + } + + // 渠道信息 + let channelInfo = null + const channelKey = data._id.appid + '_' + platformInfo._id + '_' + data._id.channel + if (this.channels && this.channels[channelKey]) { + channelInfo = this.channels[channelKey] + } else { + const channel = new Channel() + channelInfo = await channel.getChannelAndCreate(data._id.appid, platformInfo._id, data._id.channel) + if (!channelInfo || channelInfo.length === 0) { + channelInfo._id = '' + } + this.channels[channelKey] = channelInfo + if (this.debug) { + console.log('channelInfo', JSON.stringify(channelInfo)) + } + } + + // 版本信息 + let versionInfo = null + const versionKey = data._id.appid + '_' + data._id.platform + '_' + data._id.version + if (this.versions && this.versions[versionKey]) { + versionInfo = this.versions[versionKey] + } else { + const version = new Version() + versionInfo = await version.getVersionAndCreate(data._id.appid, data._id.platform, data._id.version) + if (!versionInfo || versionInfo.length === 0) { + versionInfo._id = '' + } + this.versions[versionKey] = versionInfo + if (this.debug) { + console.log('versionInfo', JSON.stringify(versionInfo)) + } + } + + // 错误信息 + let errorInfo = null + if (this.errors && this.errors[data._id.error_hash]) { + errorInfo = this.errors[data._id.error_hash] + } else { + const cacheKey = 'uni-stat-errors-' + data._id.error_hash + errorInfo = await this.getCache(cacheKey) + if (!errorInfo) { + errorInfo = await this.getCollection(this.errorLog.tableName).where({ + error_hash: data._id.error_hash + }).limit(1).get() + if (!errorInfo || errorInfo.data.length === 0) { + errorInfo.error_msg = '' + } else { + errorInfo = errorInfo.data[0] + await this.setCache(cacheKey, errorInfo) + } + } + this.errors[data._id.error_hash] = errorInfo + } + + // 最近一次报错时间 + const matchCondition = data._id + Object.assign(matchCondition, { + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }) + const lastErrorLog = await this.getCollection(this.errorLog.tableName).where(matchCondition).orderBy( + 'create_time', 'desc').limit(1).get() + let lastErrorTime = '' + if (lastErrorLog && lastErrorLog.data.length > 0) { + lastErrorTime = lastErrorLog.data[0].create_time + } + + //数据填充 + const datetime = new DateTime() + const insertParams = { + appid: data._id.appid, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + version_id: versionInfo._id, + type: 'js', + hash: data._id.error_hash, + msg: errorInfo.error_msg, + count: data.error_count, + last_time: lastErrorTime, + dimension: this.fillType, + stat_date: datetime.getDate('Ymd', this.startTime), + start_time: this.startTime, + end_time: this.endTime + } + + this.fillData.push(insertParams) + + return insertParams + } + + + /** + * 原生应用错误结果统计 + * @param {String} type 统计类型 hour:实时统计 day:按天统计,week:按周统计 month:按月统计 + * @param {Date|Time} date 指定日期或时间戳 + * @param {Boolean} reset 是否重置,为ture时会重置该批次数据 + */ + async statCrash(type, date, reset) { + const allowedType = ['day'] + if (!allowedType.includes(type)) { + return { + code: 1002, + msg: 'This type is not allowed' + } + } + this.fillType = type + const dateTime = new DateTime() + const dateDimension = dateTime.getTimeDimensionByType(type, -1, date) + this.startTime = dateDimension.startTime + this.endTime = dateDimension.endTime + + if (this.debug) { + console.log('dimension time', this.startTime + '--' + this.endTime) + } + + // 查看当前时间段日志是否已存在,防止重复生成 + if (!reset) { + const checkRes = await this.getCollection(this.tableName).where({ + type: 'crash', + start_time: this.startTime, + end_time: this.endTime + }).get() + if (checkRes.data.length > 0) { + console.log('error log have existed') + return { + code: 1003, + msg: 'This log have existed' + } + } + } else { + const delRes = await this.delete(this.tableName, { + type: 'crash', + start_time: this.startTime, + end_time: this.endTime + }) + console.log('delete old data result:', JSON.stringify(delRes)) + } + + // 数据获取 + this.crashLogs = new AppCrashLogs() + const statRes = await this.aggregate(this.crashLogs.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + create_time: 1 + }, + match: { + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }, + group: { + _id: { + appid: '$appid', + version: '$version', + platform: '$platform', + channel: '$channel' + }, + error_count: { + $sum: 1 + } + }, + sort: { + error_count: 1 + }, + getAll: true + }) + + let res = { + code: 0, + msg: 'success' + } + if (this.debug) { + console.log('statRes', JSON.stringify(statRes)) + } + if (statRes.data.length > 0) { + this.fillData = [] + for (const i in statRes.data) { + await this.fillCrash(statRes.data[i]) + } + + if (this.fillData.length > 0) { + res = await this.batchInsert(this.tableName, this.fillData) + } + } + return res + } + + async fillCrash(data) { + // 平台信息 + let platformInfo = null + if (this.platforms && this.platforms[data._id.platform]) { + //暂存下数据,减少读库 + platformInfo = this.platforms[data._id.platform] + } else { + const platform = new Platform() + platformInfo = await platform.getPlatformAndCreate(data._id.platform, null) + if (!platformInfo || platformInfo.length === 0) { + platformInfo._id = '' + } + this.platforms[data._id.platform] = platformInfo + if (this.debug) { + console.log('platformInfo', JSON.stringify(platformInfo)) + } + } + + // 渠道信息 + let channelInfo = null + data._id.channel = data._id.channel ? data._id.channel : '1001' + const channelKey = data._id.appid + '_' + platformInfo._id + '_' + data._id.channel + if (this.channels && this.channels[channelKey]) { + channelInfo = this.channels[channelKey] + } else { + const channel = new Channel() + channelInfo = await channel.getChannelAndCreate(data._id.appid, platformInfo._id, data._id.channel) + if (!channelInfo || channelInfo.length === 0) { + channelInfo._id = '' + } + this.channels[channelKey] = channelInfo + if (this.debug) { + console.log('channelInfo', JSON.stringify(channelInfo)) + } + } + + // 版本信息 + let versionInfo = null + const versionKey = data._id.appid + '_' + data._id.platform + '_' + data._id.version + if (this.versions && this.versions[versionKey]) { + versionInfo = this.versions[versionKey] + } else { + const version = new Version() + versionInfo = await version.getVersionAndCreate(data._id.appid, data._id.platform, data._id.version) + if (!versionInfo || versionInfo.length === 0) { + versionInfo._id = '' + } + this.versions[versionKey] = versionInfo + if (this.debug) { + console.log('versionInfo', JSON.stringify(versionInfo)) + } + } + + //app启动次数 + const sessionLog = new SessionLog() + const sessionTimesRes = await this.getCollection(sessionLog.tableName).where({ + appid: data._id.appid, + version: data._id.version, + platform: data._id.platform, + channel: data._id.channel, + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }).count() + + let sessionTimes = 0 + if(sessionTimesRes && sessionTimesRes.total > 0) { + sessionTimes = sessionTimesRes.total + } else { + console.log('Not found session logs') + return false + } + + + //数据填充 + const datetime = new DateTime() + const insertParams = { + appid: data._id.appid, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + version_id: versionInfo._id, + type: 'crash', + count: data.error_count, + app_launch_count: sessionTimes, + dimension: this.fillType, + stat_date: datetime.getDate('Ymd', this.startTime), + start_time: this.startTime, + end_time: this.endTime + } + + this.fillData.push(insertParams) + + return insertParams + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/event.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/event.js new file mode 100644 index 0000000..82e104c --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/event.js @@ -0,0 +1,72 @@ +/** + * @class StatEvent 事件统计模型 + */ +const BaseMod = require('./base') +const { + DateTime +} = require('../lib') +module.exports = class StatEvent extends BaseMod { + constructor() { + super() + this.tableName = 'events' + this.defaultEvent = this.getConfig('event') || { + login: '登录', + register: '注册', + click: '点击', + share: '分享', + pay_success: '支付成功', + pay_fail: '支付失败' + } + } + + /** + * 获取事件信息 + * @param {String} appid: DCloud appid + * @param {String} eventKey 事件键值 + */ + async getEvent(appid, eventKey) { + const cacheKey = 'uni-stat-event-' + appid + '-' + eventKey + let eventData = await this.getCache(cacheKey) + if (!eventData) { + const eventInfo = await this.getCollection(this.tableName).where({ + appid: appid, + event_key: eventKey + }).get() + eventData = [] + if (eventInfo.data.length > 0) { + eventData = eventInfo.data[0] + await this.setCache(cacheKey, eventData) + } + } + return eventData + } + + + /** + * 获取事件信息不存在则创建 + * @param {String} appid: DCloud appid + * @param {String} eventKey 事件键值 + */ + async getEventAndCreate(appid, eventKey) { + const eventInfo = await this.getEvent(appid, eventKey) + if (eventInfo.length === 0) { + const thisTime = new DateTime().getTime() + const insertParam = { + appid: appid, + event_key: eventKey, + event_name: this.defaultEvent[eventKey] ? this.defaultEvent[eventKey] : '', + create_time: thisTime, + update_time: thisTime + } + const res = await this.insert(this.tableName, insertParam) + + if (res && res.id) { + return Object.assign(insertParam, { + _id: res.id + }) + } + } + + return eventInfo + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/eventLog.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/eventLog.js new file mode 100644 index 0000000..61172cb --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/eventLog.js @@ -0,0 +1,156 @@ +/** + * @class EventLog 事件日志模型 + */ +const BaseMod = require('./base') +const Platform = require('./platform') +const Channel = require('./channel') +const StatEvent = require('./event') +const SessionLog = require('./sessionLog') +const ShareLog = require('./shareLog') +const { + DateTime +} = require('../lib') +module.exports = class EventLog extends BaseMod { + constructor() { + super() + this.tableName = 'event-logs' + this.sessionLogInfo = [] + } + + /** + * 事件日志填充 + * @param {Object} reportParams 上报参数 + */ + async fill(reportParams) { + let params; + let sessionKey, sessionLogKey; + let sessionLogInfo; + const sessionData = [] + const fillParams = [] + const shareParams = [] + const sessionLog = new SessionLog() + const event = new StatEvent() + const platform = new Platform() + const dateTime = new DateTime() + const channel = new Channel() + for (const rk in reportParams) { + params = reportParams[rk] + + //暂存下会话数据,减少读库 + sessionKey = params.ak + params.did + params.p + if (!this.sessionLogInfo[sessionKey]) { + // 会话日志 + sessionLogInfo = await sessionLog.getSession(params) + if (sessionLogInfo.code) { + return sessionLogInfo + } + if (this.debug) { + console.log('sessionLogInfo', JSON.stringify(sessionLogInfo)) + } + this.sessionLogInfo[sessionKey] = sessionLogInfo + } else { + sessionLogInfo = this.sessionLogInfo[sessionKey] + } + + // 会话数据 + sessionLogKey = sessionLogInfo.data.sessionLogId.toString() + if (!sessionData[sessionLogKey]) { + sessionData[sessionLogKey] = { + eventCount: sessionLogInfo.data.eventCount + 1, + addEventCount: 1, + uid: sessionLogInfo.data.uid, + createTime: sessionLogInfo.data.createTime + } + } else { + sessionData[sessionLogKey].eventCount++ + sessionData[sessionLogKey].addEventCount++ + } + + // 事件 + const eventInfo = await event.getEventAndCreate(params.ak, params.e_n) + + // 填充数据 + fillParams.push({ + appid: params.ak, + version: params.v ? params.v : '', + platform: platform.getPlatformCode(params.ut, params.p), + channel: channel.getChannelCode(params), + device_id: params.did, + uid: params.uid ? params.uid : '', + session_id: sessionLogInfo.data.sessionLogId, + page_id: sessionLogInfo.data.pageId, + event_key: eventInfo.event_key, + param: params.e_v ? params.e_v : '', + // 版本 + sdk_version: params.mpsdk ? params.mpsdk : '', + platform_version: params.mpv ? params.mpv : '', + // 设备相关 + device_os_name: params.on ? params.on : platform.getOsName(params.p), + device_os_version: params.sv ? params.sv : '', + device_vendor: params.brand ? params.brand : '', + device_model: params.md ? params.md : '', + device_language: params.lang ? params.lang : '', + device_pixel_ratio: params.pr ? params.pr : '', + device_window_width: params.ww ? params.ww : '', + device_window_height: params.wh ? params.wh : '', + device_screen_width: params.sw ? params.sw : '', + device_screen_height: params.sh ? params.sh : '', + create_time: dateTime.getTime() + }) + // 分享数据 + if (eventInfo.event_key === 'share') { + shareParams.push(params) + } + } + + if (fillParams.length === 0) { + return { + code: 200, + msg: 'Invild param' + } + } + + if (shareParams.length > 0) { + const shareLog = new ShareLog() + await shareLog.fill(shareParams, this.sessionLogInfo) + } + + const res = await this.insert(this.tableName, fillParams) + if (res && res.inserted) { + for (const sid in sessionData) { + await sessionLog.updateSession(sid, sessionData[sid]) + } + return { + code: 0, + msg: 'success' + } + } else { + return { + code: 500, + msg: 'Filled error' + } + } + } + + /** + * 事件日志清理 + * @param {Number} days 保留天数 + */ + async clean(days) { + days = Math.max(parseInt(days), 1) + console.log('clean event logs - day:', days) + + const dateTime = new DateTime() + //删除过期数据 + const res = await this.delete(this.tableName, { + create_time: { + $lt: dateTime.getTimeBySetDays(0 - days) + } + }) + + if (!res.code) { + console.log('clean event log:', res) + } + return res + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/eventResult.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/eventResult.js new file mode 100644 index 0000000..89e69a9 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/eventResult.js @@ -0,0 +1,268 @@ +/** + * @class EventResult 事件结果统计 + */ +const BaseMod = require('./base') +const Platform = require('./platform') +const Channel = require('./channel') +const Version = require('./version') +const EventLog = require('./eventLog') +const { + DateTime +} = require('../lib') +module.exports = class EventResult extends BaseMod { + constructor() { + super() + this.tableName = 'event-result' + this.platforms = [] + this.channels = [] + this.versions = [] + } + + /** + * 事件数据统计 + * @param {String} type 统计类型 hour:实时统计 day:按天统计,week:按周统计 month:按月统计 + * @param {Date|Time} date 指定日期或时间戳 + * @param {Boolean} reset 是否重置,为ture时会重置该批次数据 + */ + async stat(type, date, reset) { + const allowedType = ['day'] + if (!allowedType.includes(type)) { + return { + code: 1002, + msg: 'This type is not allowed' + } + } + this.fillType = type + const dateTime = new DateTime() + const dateDimension = dateTime.getTimeDimensionByType(type, -1, date) + this.startTime = dateDimension.startTime + this.endTime = dateDimension.endTime + if (this.debug) { + console.log('dimension time', this.startTime + '--' + this.endTime) + } + + // 查看当前时间段日志是否已存在,防止重复生成 + if (!reset) { + const checkRes = await this.getCollection(this.tableName).where({ + start_time: this.startTime, + end_time: this.endTime + }).get() + if (checkRes.data.length > 0) { + console.log('event log have existed') + return { + code: 1003, + msg: 'This log have existed' + } + } + } else { + const delRes = await this.delete(this.tableName, { + start_time: this.startTime, + end_time: this.endTime + }) + console.log('delete old data result:', JSON.stringify(delRes)) + } + + // 数据获取 + this.eventLog = new EventLog() + const statRes = await this.aggregate(this.eventLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + event_key: 1, + device_id: 1, + create_time: 1 + }, + match: { + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }, + group: { + _id: { + appid: '$appid', + version: '$version', + platform: '$platform', + channel: '$channel', + event_key: '$event_key' + }, + event_count: { + $sum: 1 + } + }, + sort: { + event_count: 1 + }, + getAll: true + }) + + let res = { + code: 0, + msg: 'success' + } + if (this.debug) { + console.log('statRes', JSON.stringify(statRes)) + } + if (statRes.data.length > 0) { + this.fillData = [] + for (const i in statRes.data) { + await this.fill(statRes.data[i]) + } + if (this.fillData.length > 0) { + res = await this.batchInsert(this.tableName, this.fillData) + } + } + return res + } + + /** + * 事件统计数据填充 + * @param {Object} data 数据集合 + */ + async fill(data) { + // 平台信息 + let platformInfo = null + if (this.platforms && this.platforms[data._id.platform]) { + //暂存下数据,减少读库 + platformInfo = this.platforms[data._id.platform] + } else { + const platform = new Platform() + platformInfo = await platform.getPlatformAndCreate(data._id.platform, null) + if (!platformInfo || platformInfo.length === 0) { + platformInfo._id = '' + } + this.platforms[data._id.platform] = platformInfo + if (this.debug) { + console.log('platformInfo', JSON.stringify(platformInfo)) + } + } + + // 渠道信息 + let channelInfo = null + const channelKey = data._id.appid + '_' + platformInfo._id + '_' + data._id.channel + if (this.channels && this.channels[channelKey]) { + channelInfo = this.channels[channelKey] + } else { + const channel = new Channel() + channelInfo = await channel.getChannelAndCreate(data._id.appid, platformInfo._id, data._id.channel) + if (!channelInfo || channelInfo.length === 0) { + channelInfo._id = '' + } + this.channels[channelKey] = channelInfo + if (this.debug) { + console.log('channelInfo', JSON.stringify(channelInfo)) + } + } + + // 版本信息 + let versionInfo = null + const versionKey = data._id.appid + '_' + data._id.platform + '_' + data._id.version + if (this.versions && this.versions[versionKey]) { + versionInfo = this.versions[versionKey] + } else { + const version = new Version() + versionInfo = await version.getVersionAndCreate(data._id.appid, data._id.platform, data._id.version) + if (!versionInfo || versionInfo.length === 0) { + versionInfo._id = '' + } + this.versions[versionKey] = versionInfo + if (this.debug) { + console.log('versionInfo', JSON.stringify(versionInfo)) + } + } + + const matchCondition = data._id + Object.assign(matchCondition, { + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }) + if (this.debug) { + console.log('matchCondition', JSON.stringify(matchCondition)) + } + + // 触发事件设备数统计 + const statEventDeviceRes = await this.aggregate(this.eventLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + event_key: 1, + device_id: 1, + create_time: 1 + }, + match: matchCondition, + group: [{ + _id: { + device_id: '$device_id' + } + }, { + _id: {}, + total_devices: { + $sum: 1 + } + }] + }) + + let eventDeviceCount = 0 + if (statEventDeviceRes.data.length > 0) { + eventDeviceCount = statEventDeviceRes.data[0].total_devices + } + + // 触发事件用户数统计 + const statEventUserRes = await this.aggregate(this.eventLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + event_key: 1, + uid: 1, + create_time: 1 + }, + match: { + ...matchCondition, + uid: { + $ne: '' + } + }, + group: [{ + _id: { + uid: '$uid' + } + }, { + _id: {}, + total_users: { + $sum: 1 + } + }] + }) + + let eventUserCount = 0 + if (statEventUserRes.data.length > 0) { + eventUserCount = statEventUserRes.data[0].total_users + } + + const datetime = new DateTime() + const insertParams = { + appid: data._id.appid, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + version_id: versionInfo._id, + event_key: data._id.event_key, + event_count: data.event_count, + device_count: eventDeviceCount, + user_count: eventUserCount, + dimension: this.fillType, + stat_date: datetime.getDate('Ymd', this.startTime), + start_time: this.startTime, + end_time: this.endTime + } + this.fillData.push(insertParams) + return insertParams + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/index.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/index.js new file mode 100644 index 0000000..4980049 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/index.js @@ -0,0 +1,23 @@ +/** + * 基础对外模型 + */ +module.exports = { + BaseMod: require('./base'), + SessionLog: require('./sessionLog'), + UserSessionLog: require('./userSessionLog'), + PageLog: require('./pageLog'), + EventLog: require('./eventLog'), + ShareLog: require('./shareLog'), + ErrorLog: require('./errorLog'), + AppCrashLogs: require('./appCrashLogs'), + StatResult: require('./statResult'), + ActiveUsers: require('./activeUsers'), + ActiveDevices: require('./activeDevices'), + PageResult: require('./pageResult'), + EventResult: require('./eventResult'), + ErrorResult: require('./errorResult'), + Loyalty: require('./loyalty'), + RunErrors: require('./runErrors'), + uniPay: require('./uni-pay'), + Setting: require('./setting'), +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/loyalty.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/loyalty.js new file mode 100644 index 0000000..273c04b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/loyalty.js @@ -0,0 +1,491 @@ +/** + * 设备/用户忠诚度(粘性)统计模型 + */ +const BaseMod = require('./base') +const Platform = require('./platform') +const Channel = require('./channel') +const Version = require('./version') +const SessionLog = require('./sessionLog') +const UserSessionLog = require('./userSessionLog') +const { + DateTime +} = require('../lib') +module.exports = class Loyalty extends BaseMod { + constructor() { + super() + this.tableName = 'loyalty-result' + this.platforms = [] + this.channels = [] + this.versions = [] + } + + /** + * 设备/用户忠诚度(粘性)统计 + * @param {String} type 统计类型 hour:实时统计 day:按天统计,week:按周统计 month:按月统计 + * @param {Date|Time} date 指定日期或时间戳 + * @param {Boolean} reset 是否重置,为ture时会重置该批次数据 + */ + async stat(type, date, reset) { + const allowedType = ['day'] + if (!allowedType.includes(type)) { + return { + code: 1002, + msg: 'This type is not allowed' + } + } + + this.fillType = type + const dateTime = new DateTime() + const dateDimension = dateTime.getTimeDimensionByType(type, -1, date) + this.startTime = dateDimension.startTime + this.endTime = dateDimension.endTime + + if (this.debug) { + console.log('this time', dateTime.getTime()) + console.log('dimension time', this.startTime + '--' + this.endTime) + } + + // 查看当前时间段日志是否已存在,防止重复生成 + if (!reset) { + const checkRes = await this.getCollection(this.tableName).where({ + start_time: this.startTime, + end_time: this.endTime + }).get() + if (checkRes.data.length > 0) { + console.log('loyalty log have existed') + return { + code: 1003, + msg: 'This log have existed' + } + } + } else { + const delRes = await this.delete(this.tableName, { + start_time: this.startTime, + end_time: this.endTime + }) + console.log('delete old data result:', JSON.stringify(delRes)) + } + + // 数据获取 + this.sessionLog = new SessionLog() + const statRes = await this.aggregate(this.sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + page_count: 1, + duration: 1, + create_time: 1 + }, + match: { + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }, + group: { + _id: { + appid: '$appid', + version: '$version', + platform: '$platform', + channel: '$channel' + }, + page_count_sum: { + $sum: '$page_count' + }, + duration_sum: { + $sum: '$duration' + } + }, + sort: { + page_count_sum: 1, + duration_sum: 1 + }, + getAll: true + }) + + let res = { + code: 0, + msg: 'success' + } + if (this.debug) { + console.log('statRes', JSON.stringify(statRes)) + } + if (statRes.data.length > 0) { + this.fillData = [] + for (const i in statRes.data) { + await this.fill(statRes.data[i]) + } + + if (this.fillData.length > 0) { + res = await this.batchInsert(this.tableName, this.fillData) + } + } + return res + } + + /** + * 设备/用户忠诚度(粘性)数据填充 + * @param {Object} data 数据集合 + */ + async fill(data) { + // 平台信息 + let platformInfo = null + if (this.platforms && this.platforms[data._id.platform]) { + platformInfo = this.platforms[data._id.platform] + } else { + const platform = new Platform() + platformInfo = await platform.getPlatformAndCreate(data._id.platform, null) + if (!platformInfo || platformInfo.length === 0) { + platformInfo._id = '' + } + this.platforms[data._id.platform] = platformInfo + if (this.debug) { + console.log('platformInfo', JSON.stringify(platformInfo)) + } + } + + // 渠道信息 + let channelInfo = null + const channelKey = data._id.appid + '_' + platformInfo._id + '_' + data._id.channel + if (this.channels && this.channels[channelKey]) { + channelInfo = this.channels[channelKey] + } else { + const channel = new Channel() + channelInfo = await channel.getChannelAndCreate(data._id.appid, platformInfo._id, data._id.channel) + if (!channelInfo || channelInfo.length === 0) { + channelInfo._id = '' + } + this.channels[channelKey] = channelInfo + if (this.debug) { + console.log('channelInfo', JSON.stringify(channelInfo)) + } + } + + // 版本信息 + let versionInfo = null + const versionKey = data._id.appid + '_' + data._id.platform + '_' + data._id.version + if (this.versions && this.versions[versionKey]) { + versionInfo = this.versions[versionKey] + } else { + const version = new Version() + versionInfo = await version.getVersionAndCreate(data._id.appid, data._id.platform, data._id.version) + if (!versionInfo || versionInfo.length === 0) { + versionInfo._id = '' + } + this.versions[versionKey] = versionInfo + if (this.debug) { + console.log('versionInfo', JSON.stringify(versionInfo)) + } + } + + // 访问深度-用户数统计和访问次数 + const pageMark = [1, 2, 3, 4, [5, 10], [10]] + + const matchCondition = Object.assign(data._id, { + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }) + + const visitDepthData = { + visit_devices: {}, + visit_users: {}, + visit_times: {} + } + + const userSessionLog = new UserSessionLog() + //根据各访问页面数区间统计 + for (const pi in pageMark) { + let pageMarkCondition = { + page_count: pageMark[pi] + } + + if (Array.isArray(pageMark[pi])) { + if (pageMark[pi].length === 2) { + pageMarkCondition = { + page_count: { + $gte: pageMark[pi][0], + $lte: pageMark[pi][1] + } + } + } else { + pageMarkCondition = { + page_count: { + $gt: pageMark[pi][0] + } + } + } + } + + // 访问次数(会话次数)统计 + const searchCondition = { + ...matchCondition, + ...pageMarkCondition + } + const vistRes = await this.aggregate(this.sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + page_count: 1, + create_time: 1 + }, + match: searchCondition, + group: { + _id: {}, + total_visits: { + $sum: 1 + } + } + }) + + if (this.debug) { + console.log('vistResCondtion', JSON.stringify(searchCondition)) + console.log('vistRes', JSON.stringify(vistRes)) + } + let vistCount = 0 + if (vistRes.data.length > 0) { + vistCount = vistRes.data[0].total_visits + } + + // 设备数统计 + const deviceRes = await this.aggregate(this.sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + page_count: 1, + create_time: 1, + device_id: 1 + }, + match: searchCondition, + group: [{ + _id: { + device_id: '$device_id' + } + }, { + _id: {}, + total_devices: { + $sum: 1 + } + }] + }) + + if (this.debug) { + console.log('searchCondition', JSON.stringify(searchCondition)) + console.log('deviceRes', JSON.stringify(deviceRes)) + } + + let deviceCount = 0 + if (deviceRes.data.length > 0) { + deviceCount = deviceRes.data[0].total_devices + } + + // 用户数统计 + const userRes = await this.aggregate(userSessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + page_count: 1, + create_time: 1, + uid: 1 + }, + match: searchCondition, + group: [{ + _id: { + uid: '$uid' + } + }, { + _id: {}, + total_users: { + $sum: 1 + } + }] + }) + + if (this.debug) { + console.log('userResCondtion', JSON.stringify(searchCondition)) + console.log('userRes', JSON.stringify(userRes)) + } + + let userCount = 0 + if (userRes.data.length > 0) { + userCount = userRes.data[0].total_users + } + + const pageKey = 'p_' + (Array.isArray(pageMark[pi]) ? pageMark[pi][0] : pageMark[pi]) + visitDepthData.visit_devices[pageKey] = deviceCount + visitDepthData.visit_users[pageKey] = userCount + visitDepthData.visit_times[pageKey] = vistCount + } + + // 访问时长-用户数统计和访问次数 + const durationMark = [ + [0, 2], + [3, 5], + [6, 10], + [11, 20], + [21, 30], + [31, 50], + [51, 100], + [100] + ] + const durationData = { + visit_devices: {}, + visit_users: {}, + visit_times: {} + } + //根据各访问时长区间统计 + for (const di in durationMark) { + let durationMarkCondition = { + duration: durationMark[di] + } + + if (Array.isArray(durationMark[di])) { + if (durationMark[di].length === 2) { + durationMarkCondition = { + duration: { + $gte: durationMark[di][0], + $lte: durationMark[di][1] + } + } + } else { + durationMarkCondition = { + duration: { + $gt: durationMark[di][0] + } + } + } + } + + // 访问次数(会话次数)统计 + const searchCondition = { + ...matchCondition, + ...durationMarkCondition + } + if (this.debug) { + console.log('searchCondition', JSON.stringify(searchCondition)) + } + const vistRes = await this.aggregate(this.sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + duration: 1, + create_time: 1 + }, + match: searchCondition, + group: { + _id: {}, + total_visits: { + $sum: 1 + } + } + }) + + if (this.debug) { + console.log('vistRes', JSON.stringify(vistRes)) + } + let vistCount = 0 + if (vistRes.data.length > 0) { + vistCount = vistRes.data[0].total_visits + } + + // 设备数统计 + const deviceRes = await this.aggregate(this.sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + device_id: 1, + duration: 1, + create_time: 1 + }, + match: searchCondition, + group: [{ + _id: { + device_id: '$device_id' + } + }, { + _id: {}, + total_devices: { + $sum: 1 + } + }] + }) + + if (this.debug) { + console.log('userRes', JSON.stringify(deviceRes)) + } + + let deviceCount = 0 + if (deviceRes.data.length > 0) { + deviceCount = deviceRes.data[0].total_devices + } + + // 用户数统计 + const userRes = await this.aggregate(userSessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + uid: 1, + duration: 1, + create_time: 1 + }, + match: searchCondition, + group: [{ + _id: { + uid: '$uid' + } + }, { + _id: {}, + total_users: { + $sum: 1 + } + }] + }) + + if (this.debug) { + console.log('userRes', JSON.stringify(userRes)) + } + + let userCount = 0 + if (userRes.data.length > 0) { + userCount = userRes.data[0].total_users + } + + const pageKey = 's_' + (Array.isArray(durationMark[di]) ? durationMark[di][0] : durationMark[di]) + durationData.visit_devices[pageKey] = deviceCount + durationData.visit_users[pageKey] = userCount + durationData.visit_times[pageKey] = vistCount + } + + // 数据填充 + const datetime = new DateTime() + const insertParams = { + appid: data._id.appid, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + version_id: versionInfo._id, + visit_depth_data: visitDepthData, + duration_data: durationData, + stat_date: datetime.getDate('Ymd', this.startTime), + start_time: this.startTime, + end_time: this.endTime + } + + this.fillData.push(insertParams) + return insertParams + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/page.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/page.js new file mode 100644 index 0000000..260fdc1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/page.js @@ -0,0 +1,83 @@ +/** + * @class Page 页面模型 + */ +const BaseMod = require('./base') +const { + parseUrl +} = require('../../shared') +const { + DateTime +} = require('../lib') +module.exports = class Page extends BaseMod { + constructor() { + super() + this.tableName = 'pages' + } + + /** + * 获取页面信息 + * @param {String} appid + * @param {String} url 页面地址 + */ + async getPage(appid, url) { + const cacheKey = 'uni-stat-page-' + appid + '-' + url + let pageData = await this.getCache(cacheKey) + if (!pageData) { + const pageInfo = await this.getCollection(this.tableName).where({ + appid: appid, + path: url + }).limit(1).get() + pageData = [] + if (pageInfo.data.length > 0) { + pageData = pageInfo.data[0] + await this.setCache(cacheKey, pageData) + } + } + return pageData + } + + /** + * 获取页面信息不存在则创建 + * @param {String} appid + * @param {String} url 页面地址 + * @param {Object} title 页面标题 + */ + async getPageAndCreate(appid, url, title) { + //获取url信息 + const urlInfo = parseUrl(url) + if (!urlInfo) { + return false + } + const baseurl = urlInfo.path + const pageInfo = await this.getPage(appid, baseurl) + //页面不存在则创建 + if (pageInfo.length === 0) { + const thisTime = new DateTime().getTime() + const insertParam = { + appid: appid, + path: baseurl, + title: title, + page_params: [], + create_time: thisTime, + update_time: thisTime + } + const res = await this.insert(this.tableName, insertParam) + + if (res && res.id) { + return Object.assign(insertParam, { + _id: res.id + }) + } + } else if (!pageInfo.title && title) { + const cacheKey = 'uni-stat-page-' + appid + '-' + baseurl + await this.clearCache(cacheKey) + await this.update(this.tableName, { + title: title + }, { + _id: pageInfo._id + }) + } + + return pageInfo + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/pageLog.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/pageLog.js new file mode 100644 index 0000000..6cc03d6 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/pageLog.js @@ -0,0 +1,186 @@ +/** + * @class PageLog 页面日志模型 + */ +const BaseMod = require('./base') +const Page = require('./page') +const Platform = require('./platform') +const Channel = require('./channel') +const SessionLog = require('./sessionLog') +const { + DateTime +} = require('../lib') +const { + parseUrl +} = require('../../shared') +module.exports = class PageLog extends BaseMod { + constructor() { + super() + this.tableName = 'page-logs' + this.sessionLogInfo = [] + } + + /** + * 页面日志数据填充 + * @param {Object} reportParams 上报参数 + */ + async fill(reportParams) { + let params; + let sessionKey + let sessionLogKey + let sessionLogInfo + let pageKey + let pageInfo + let referPageInfo + const sessionData = [] + const pageData = [] + const fillParams = [] + const sessionLog = new SessionLog() + const page = new Page() + const platform = new Platform() + const dateTime = new DateTime() + const channel = new Channel() + for (const pk in reportParams) { + params = reportParams[pk] + if (['3', '4'].includes(params.lt) && !params.url && params.urlref) { + params.url = params.urlref + } + + // 页面信息 + pageKey = params.ak + params.url + if (pageData[pageKey]) { + pageInfo = pageData[pageKey] + } else { + pageInfo = await page.getPageAndCreate(params.ak, params.url, params.ttpj) + if (!pageInfo || pageInfo.length === 0) { + console.log('Not found this page by param:', JSON.stringify(params)) + continue + } + pageData[pageKey] = pageInfo + } + + // 会话日志,暂存下会话数据,减少读库 + sessionKey = params.ak + params.did + params.p + if (!this.sessionLogInfo[sessionKey]) { + sessionLogInfo = await sessionLog.getSession(params) + if (sessionLogInfo.code) { + return sessionLogInfo + } + if (this.debug) { + console.log('sessionLogInfo', JSON.stringify(sessionLogInfo)) + } + this.sessionLogInfo[sessionKey] = sessionLogInfo + } else { + sessionLogInfo = this.sessionLogInfo[sessionKey] + } + + // 会话数据 + sessionLogKey = sessionLogInfo.data.sessionLogId.toString() + if (!sessionData[sessionLogKey]) { + //临时存储减少查询次数 + sessionData[sessionLogKey] = { + pageCount: sessionLogInfo.data.pageCount + 1, + addPageCount: 1, + createTime: sessionLogInfo.data.createTime, + pageId: pageInfo._id, + uid: sessionLogInfo.data.uid + } + + if (this.debug) { + console.log('add sessionData - ' + sessionLogKey, sessionData) + } + + } else { + sessionData[sessionLogKey].pageCount += 1 + sessionData[sessionLogKey].addPageCount += 1 + sessionData[sessionLogKey].pageId = pageInfo._id + + if (this.debug) { + console.log('update sessionData - ' + sessionLogKey, sessionData) + } + } + + // 上级页面信息 + pageKey = params.ak + params.urlref + if (pageData[pageKey]) { + referPageInfo = pageData[pageKey] + } else { + referPageInfo = await page.getPageAndCreate(params.ak, params.urlref, params.ttpj) + if (!referPageInfo || referPageInfo.length === 0) { + referPageInfo = {_id:''} + } + pageData[pageKey] = referPageInfo + } + + //当前页面url信息 + const urlInfo = parseUrl(params.url) + + // 填充数据 + fillParams.push({ + appid: params.ak, + version: params.v ? params.v : '', + platform: platform.getPlatformCode(params.ut, params.p), + channel: channel.getChannelCode(params), + device_id: params.did, + uid: params.uid ? params.uid : '', + session_id: sessionLogInfo.data.sessionLogId, + page_id: pageInfo._id, + query_string: urlInfo.query, + //上级页面相关 + previous_page_id: referPageInfo._id, + previous_page_duration: params.urlref_ts ? parseInt(params.urlref_ts) : 0, + previous_page_is_entry: referPageInfo._id === sessionLogInfo.data.entryPageId ? 1 : 0, + create_time: dateTime.getTime() + }) + } + + if (fillParams.length === 0) { + console.log('No page params') + return { + code: 200, + msg: 'Invild param' + } + } + + //日志数据入库 + const res = await this.insert(this.tableName, fillParams) + if (res && res.inserted) { + // 更新会话数据 + const nowTime = dateTime.getTime() + for (const sid in sessionData) { + await sessionLog.updateSession(sid, sessionData[sid]) + } + + return { + code: 0, + msg: 'success' + } + } else { + return { + code: 500, + msg: 'Filled error' + } + } + } + + /** + * 页面日志清理 + * @param {Number} days 页面日志保留天数 + */ + async clean(days) { + days = Math.max(parseInt(days), 1) + console.log('clean page logs - day:', days) + + const dateTime = new DateTime() + + const res = await this.delete(this.tableName, { + create_time: { + $lt: dateTime.getTimeBySetDays(0 - days) + } + }) + + if (!res.code) { + console.log('clean page log:', res) + } + return res + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/pageResult.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/pageResult.js new file mode 100644 index 0000000..d002ed3 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/pageResult.js @@ -0,0 +1,522 @@ +/** + * @class PageResult 页面结果统计模型 + */ +const BaseMod = require('./base') +const Platform = require('./platform') +const Channel = require('./channel') +const Version = require('./version') +const SessionLog = require('./sessionLog') +const PageLog = require('./pageLog') +const ShareLog = require('./shareLog') +const { + DateTime +} = require('../lib') +module.exports = class PageResult extends BaseMod { + constructor() { + super() + this.tableName = 'page-result' + this.platforms = [] + this.channels = [] + this.versions = [] + } + + /** + * 数据统计 + * @param {String} type 统计类型 hour:实时统计 day:按天统计,week:按周统计 month:按月统计 + * @param {Date|Time} date 指定日期或时间戳 + * @param {Boolean} reset 是否重置,为ture时会重置该批次数据 + */ + async stat(type, date, reset) { + //允许的类型 + const allowedType = ['day'] + if (!allowedType.includes(type)) { + return { + code: 1002, + msg: 'This type is not allowed' + } + } + this.fillType = type + //获取当前统计的时间范围 + const dateTime = new DateTime() + const dateDimension = dateTime.getTimeDimensionByType(type, -1, date) + this.startTime = dateDimension.startTime + this.endTime = dateDimension.endTime + if (this.debug) { + console.log('dimension time', this.startTime + '--' + this.endTime) + } + + // 查看当前时间段日志是否已存在,防止重复执行 + if (!reset) { + const checkRes = await this.getCollection(this.tableName).where({ + start_time: this.startTime, + end_time: this.endTime + }).get() + if (checkRes.data.length > 0) { + console.error('This page stat log have exists') + return { + code: 1003, + msg: 'This page stat log have existed' + } + } + } else { + const delRes = await this.delete(this.tableName, { + start_time: this.startTime, + end_time: this.endTime + }) + console.log('Delete old data result:', JSON.stringify(delRes)) + } + + // 数据获取 + this.pageLog = new PageLog() + const statRes = await this.aggregate(this.pageLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + page_id: 1, + create_time: 1 + }, + match: { + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }, + group: { + _id: { + appid: '$appid', + version: '$version', + platform: '$platform', + channel: '$channel', + page_id: '$page_id' + }, + visit_times: { + $sum: 1 + } + }, + sort: { + visit_times: 1 + }, + getAll: true + }) + + let res = { + code: 0, + msg: 'success' + } + if (this.debug) { + console.log('Page statRes', JSON.stringify(statRes)) + } + if (statRes.data.length > 0) { + this.fillData = [] + //获取填充数据 + for (const i in statRes.data) { + await this.fill(statRes.data[i]) + } + + //数据批量入库 + if (this.fillData.length > 0) { + res = await this.batchInsert(this.tableName, this.fillData) + } + } + return res + } + + /** + * 页面统计数据填充 + * @param {Object} data 统计数据 + */ + async fill(data) { + // 平台信息 + let platformInfo = null + if (this.platforms && this.platforms[data._id.platform]) { + //暂存下数据,减少读库 + platformInfo = this.platforms[data._id.platform] + } else { + const platform = new Platform() + platformInfo = await platform.getPlatformAndCreate(data._id.platform, null) + if (!platformInfo || platformInfo.length === 0) { + platformInfo._id = '' + } + this.platforms[data._id.platform] = platformInfo + if (this.debug) { + console.log('platformInfo', JSON.stringify(platformInfo)) + } + } + + // 渠道信息 + let channelInfo = null + const channelKey = data._id.appid + '_' + platformInfo._id + '_' + data._id.channel + if (this.channels && this.channels[channelKey]) { + channelInfo = this.channels[channelKey] + } else { + const channel = new Channel() + channelInfo = await channel.getChannelAndCreate(data._id.appid, platformInfo._id, data._id.channel) + if (!channelInfo || channelInfo.length === 0) { + channelInfo._id = '' + } + this.channels[channelKey] = channelInfo + if (this.debug) { + console.log('channelInfo', JSON.stringify(channelInfo)) + } + } + + // 版本信息 + let versionInfo = null + const versionKey = data._id.appid + '_' + data._id.platform + '_' + data._id.version + if (this.versions && this.versions[versionKey]) { + versionInfo = this.versions[versionKey] + } else { + const version = new Version() + versionInfo = await version.getVersionAndCreate(data._id.appid, data._id.platform, data._id.version) + if (!versionInfo || versionInfo.length === 0) { + versionInfo._id = '' + } + this.versions[versionKey] = versionInfo + if (this.debug) { + console.log('versionInfo', JSON.stringify(versionInfo)) + } + } + + const matchCondition = data._id + Object.assign(matchCondition, { + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }) + if (this.debug) { + console.log('matchCondition', JSON.stringify(matchCondition)) + } + + // 当前页面访问设备数 + const statPageDeviceRes = await this.aggregate(this.pageLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + device_id: 1, + page_id: 1, + create_time: 1 + }, + match: matchCondition, + group: [{ + _id: { + device_id: '$device_id' + } + }, { + _id: {}, + total_devices: { + $sum: 1 + } + }] + }) + + let pageVisitDevices = 0 + if (statPageDeviceRes.data.length > 0) { + pageVisitDevices = statPageDeviceRes.data[0].total_devices + } + + // 当前页面访问人数 + const statPageUserRes = await this.aggregate(this.pageLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + uid: 1, + page_id: 1, + create_time: 1 + }, + match: { + ...matchCondition, + uid: { + $ne: '' + } + }, + group: [{ + _id: { + uid: '$uid' + } + }, { + _id: {}, + total_users: { + $sum: 1 + } + }] + }) + + let pageVisitUsers = 0 + if (statPageUserRes.data.length > 0) { + pageVisitUsers = statPageUserRes.data[0].total_users + } + + // 退出次数 + const sessionLog = new SessionLog() + let existTimes = 0 + const existRes = await this.getCollection(sessionLog.tableName).where({ + appid: data._id.appid, + version: data._id.version, + platform: data._id.platform, + channel: data._id.channel, + exit_page_id: data._id.page_id, + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }).count() + if (existRes && existRes.total > 0) { + existTimes = existRes.total + } + + // 访问时长 + const statPageDurationRes = await this.aggregate(this.pageLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + previous_page_id: 1, + previous_page_duration: 1, + create_time: 1 + }, + match: { + appid: data._id.appid, + version: data._id.version, + platform: data._id.platform, + channel: data._id.channel, + previous_page_id: data._id.page_id, + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }, + group: { + _id: {}, + total_duration: { + $sum: '$previous_page_duration' + } + } + }) + + let totalDuration = 0 + if (statPageDurationRes.data.length > 0) { + totalDuration = statPageDurationRes.data[0].total_duration + } + + // 分享次数 + const shareLog = new ShareLog() + const statShareRes = await this.aggregate(shareLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + page_id: 1, + create_time: 1 + }, + match: { + appid: data._id.appid, + version: data._id.version, + platform: data._id.platform, + channel: data._id.channel, + page_id: data._id.page_id, + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }, + group: { + _id: {}, + share_count: { + $sum: 1 + } + } + }) + + let shareCount = 0 + if (statShareRes.data.length > 0) { + shareCount = statShareRes.data[0].share_count + } + + // 作为入口页的总次数和总访问时长 + const statPageEntryCountRes = await this.aggregate(this.pageLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + previous_page_id: 1, + previous_page_duration: 1, + previous_page_is_entry: 1, + create_time: 1 + }, + match: { + appid: data._id.appid, + version: data._id.version, + platform: data._id.platform, + channel: data._id.channel, + previous_page_id: data._id.page_id, + previous_page_is_entry: 1, + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }, + group: { + _id: {}, + entry_count: { + $sum: 1 + }, + entry_duration: { + $sum: '$previous_page_duration' + } + } + }) + + let entryCount = 0 + let entryDuration = 0 + if (statPageEntryCountRes.data.length > 0) { + entryCount = statPageEntryCountRes.data[0].entry_count + entryDuration = statPageEntryCountRes.data[0].entry_duration + } + + // 作为入口页的总设备数 + const statPageEntryDevicesRes = await this.aggregate(this.pageLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + device_id: 1, + previous_page_id: 1, + previous_page_is_entry: 1, + create_time: 1 + }, + match: { + appid: data._id.appid, + version: data._id.version, + platform: data._id.platform, + channel: data._id.channel, + previous_page_id: data._id.page_id, + previous_page_is_entry: 1, + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }, + group: [{ + _id: { + device_id: '$device_id' + } + }, { + _id: {}, + entry_devices: { + $sum: 1 + } + }] + }) + + let entryDevices = 0 + if (statPageEntryDevicesRes.data.length > 0) { + entryDevices = statPageEntryDevicesRes.data[0].entry_devices + } + + // 作为入口页的总人数 + const statPageEntryUsersRes = await this.aggregate(this.pageLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + uid: 1, + previous_page_id: 1, + previous_page_is_entry: 1, + create_time: 1 + }, + match: { + appid: data._id.appid, + version: data._id.version, + platform: data._id.platform, + channel: data._id.channel, + previous_page_id: data._id.page_id, + previous_page_is_entry: 1, + uid: { + $ne: '' + }, + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }, + group: [{ + _id: { + uid: '$uid' + } + }, { + _id: {}, + entry_users: { + $sum: 1 + } + }] + }) + + let entryUsers = 0 + if (statPageEntryUsersRes.data.length > 0) { + entryUsers = statPageEntryUsersRes.data[0].entry_users + } + + // 跳出率 + let bounceTimes = 0 + const bounceRes = await this.getCollection(sessionLog.tableName).where({ + appid: data._id.appid, + version: data._id.version, + platform: data._id.platform, + channel: data._id.channel, + entry_page_id: data._id.page_id, + page_count: 1, + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }).count() + if (bounceRes && bounceRes.total > 0) { + bounceTimes = bounceRes.total + } + let bounceRate = 0 + if (bounceTimes > 0 && data.visit_times > 0) { + bounceRate = bounceTimes * 100 / data.visit_times + bounceRate = parseFloat(bounceRate.toFixed(2)) + } + + // 数据填充 + const datetime = new DateTime() + const insertParams = { + appid: data._id.appid, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + version_id: versionInfo._id, + page_id: data._id.page_id, + visit_times: data.visit_times, + visit_devices: pageVisitDevices, + visit_users: pageVisitUsers, + exit_times: existTimes, + duration: totalDuration > 0 ? totalDuration : 1, + share_count: shareCount, + entry_users: entryUsers, + entry_devices: entryDevices, + entry_count: entryCount, + entry_duration: entryDuration, + bounce_rate: bounceRate, + dimension: this.fillType, + stat_date: datetime.getDate('Ymd', this.startTime), + start_time: this.startTime, + end_time: this.endTime + } + + this.fillData.push(insertParams) + return insertParams + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/platform.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/platform.js new file mode 100644 index 0000000..5a5bcfd --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/platform.js @@ -0,0 +1,160 @@ +/** + * @class Platform 应用平台模型 + */ +const BaseMod = require('./base') +const { + DateTime +} = require('../lib') +module.exports = class Platform extends BaseMod { + constructor() { + super() + this.tableName = 'app-platforms' + } + + /** + * 获取平台信息 + * @param {String} platform 平台代码 + * @param {String} os 系统 + */ + async getPlatform(platform, os) { + const cacheKey = 'uni-stat-platform-' + platform + '-' + os + let platformData = await this.getCache(cacheKey) + if (!platformData) { + const platformCode = this.getPlatformCode(platform, os) + const platformInfo = await this.getCollection(this.tableName).where({ + code: platformCode + }).limit(1).get() + platformData = [] + if (platformInfo.data.length > 0) { + platformData = platformInfo.data[0] + await this.setCache(cacheKey, platformData) + } + } + return platformData + } + + /** + * 获取平台信息没有则创建 + * @param {String} platform 平台代码 + * @param {String} os 系统 + */ + async getPlatformAndCreate(platform, os) { + if (!platform) { + return false + } + const platformInfo = await this.getPlatform(platform, os) + + if (platformInfo.length === 0) { + const platformCode = this.getPlatformCode(platform, os) + const insertParam = { + code: platformCode, + name: platformCode, + create_time: new DateTime().getTime() + } + const res = await this.insert(this.tableName, insertParam) + if (res && res.id) { + return Object.assign(insertParam, { + _id: res.id + }) + } + } + return platformInfo + } + + /** + * 获取平台代码 + * @param {String} platform 平台代码 + * @param {String} os 系统 + */ + getPlatformCode(platform, os) { + let platformCode = platform + + //兼容客户端上报参数 + switch(platform) { + //h5|web + case 'h5': + platformCode = 'web' + break + //微信小程序 + case 'wx': + platformCode = 'mp-weixin' + break + //百度小程序 + case 'bd': + platformCode = 'mp-baidu' + break + //支付宝小程序 + case 'ali': + platformCode = 'mp-alipay' + break + //字节跳动小程序 + case 'tt': + platformCode = 'mp-toutiao' + break + //qq小程序 + case 'qq': + platformCode = 'mp-qq' + break + //快应用联盟 + case 'qn': + platformCode = 'quickapp-webview-union' + break + //快应用(webview) + case 'qw': + platformCode = 'quickapp-webview' + break + //快应用华为 + case 'qi': + platformCode = 'quickapp-webview-huawei' + break + //360小程序 + case '360': + platformCode = 'mp-360' + break + //京东小程序 + case 'jd': + platformCode = 'mp-jd' + break + //钉钉小程序 + case 'dt': + platformCode = 'mp-dingtalk' + break + //快手小程序 + case 'ks': + platformCode = 'mp-kuaishou' + break + //飞书小程序 + case 'lark': + platformCode = 'mp-lark' + break + //原生应用 + case 'n': + case 'app-plus': + case 'app': + os = this.getOsName(os) + if (os === 'ios') { + platformCode = 'ios' + } else { + platformCode = 'android' + } + break + } + return platformCode + } + + /** + * 获取系统名称 + * @param {Object} os系统标识 + */ + getOsName(os) { + if(!os) { + return '' + } + //兼容老版上报参数 + const osSetting = { + i: 'ios', + a: 'android' + } + return osSetting[os] ? osSetting[os] : os + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/runErrors.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/runErrors.js new file mode 100644 index 0000000..be09242 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/runErrors.js @@ -0,0 +1,20 @@ +/** + * @class RunErrors 运行错误日志 + */ +const BaseMod = require('./base') +module.exports = class RunErrors extends BaseMod { + constructor() { + super() + this.tableName = 'run-errors' + } + + /** + * 创建日志 + * @param {Object} params 参数 + */ + async create(params) { + if (!params) return + const res = await this.insert(this.tableName, params) + return res + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/scenes.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/scenes.js new file mode 100644 index 0000000..af04b3c --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/scenes.js @@ -0,0 +1,80 @@ +/** + * @class Scenes 场景值模型 + */ +const BaseMod = require('./base') +const Platform = require('./platform') +module.exports = class Scenes extends BaseMod { + constructor() { + super() + this.tableName = 'mp-scenes' + this.defualtCode = '1001' + } + + /** + * 获取场景值 + * @param {String} platform 平台代码 + * @param {String} code 场景值代码 + */ + async getScenes(platform, code) { + const cacheKey = 'uni-stat-scenes-' + platform + '-' + code + let scenesData = await this.getCache(cacheKey) + if (!scenesData) { + const scenesInfo = await this.getCollection(this.tableName).where({ + platform: platform, + scene_code: code + }).limit(1).get() + scenesData = [] + if (scenesInfo.data.length > 0) { + scenesData = scenesInfo.data[0] + await this.setCache(cacheKey, scenesData) + } + } + return scenesData + } + + /** + * 通过平台编号获取场景值 + * @param {String} platformId 平台编号 + * @param {String} code 场景值代码 + */ + async getScenesByPlatformId(platformId, code) { + const platform = new Platform() + let platformInfo = await this.getCollection(platform.tableName).where({ + _id: platformId + }).limit(1).get() + let scenesData + if (platformInfo.data.length > 0) { + platformInfo = platformInfo.data[0] + scenesData = await this.getScenes(platformInfo.code, code) + } else { + scenesData = [] + } + return scenesData + } + + /** + * 获取场景值名称 + * @param {String} platform 平台代码 + * @param {String} code 场景值代码 + */ + async getScenesName(platform, code) { + const scenesData = await this.getScenes(platform, code) + if (scenesData.length === 0) { + return '' + } + return scenesData.scene_name + } + + /** + * 通过平台编号获取场景值名称 + * @param {String} platformId 平台编号 + * @param {String} code 场景值代码 + */ + async getScenesNameByPlatformId(platformId, code) { + const scenesData = await this.getScenesByPlatformId(platformId, code) + if (scenesData.length === 0) { + return code === this.defualtCode ? '默认' : '' + } + return scenesData.scene_name + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/sessionLog.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/sessionLog.js new file mode 100644 index 0000000..34f3c85 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/sessionLog.js @@ -0,0 +1,343 @@ +/** + * @class SessionLog 基础会话日志模型 + */ +const BaseMod = require('./base') +const Page = require('./page') +const Platform = require('./platform') +const Channel = require('./channel') +const UserSessionLog = require('./userSessionLog') +const Device = require('./device') +const { + DateTime +} = require('../lib') +module.exports = class SessionLog extends BaseMod { + constructor() { + super() + this.tableName = 'session-logs' + } + + + /** + * 会话日志批量填充 + * @param {Object} reportParams 上报参数 + */ + async batchFill(reportParams) { + let params, pageInfo, nowTime, firstVistTime, lastVistTime; + const fillParams = [] + + const page = new Page() + const platform = new Platform() + const dateTime = new DateTime() + const channel = new Channel() + const device = new Device() + let res + for (const pk in reportParams) { + params = reportParams[pk] + res = await this.fill(params) + if (res.code) { + console.error(res.msg) + } else { + //添加设备信息 + await device.setDevice(params) + } + } + return res + } + + /** + * 会话日志填充 + * @param {Object} params 上报参数 + */ + async fill(params) { + // 应用信息 + if (!params.ak) { + return { + code: 200, + msg: 'Parameter "ak" not found' + } + } + + // 平台信息 + if (!params.ut) { + return { + code: 200, + msg: 'Parameter "ut" not found' + } + } + + // 设备信息 + if (!params.did) { + return { + code: 200, + msg: 'Parameter "did" not found' + } + } + + // 页面信息 + const page = new Page() + const pageInfo = await page.getPageAndCreate(params.ak, params.url, params.ttpj) + if (!pageInfo || pageInfo.length === 0) { + return { + code: 300, + msg: 'Not found this entry page' + } + } + if (this.debug) { + console.log('pageInfo', JSON.stringify(pageInfo)) + } + const platform = new Platform() + const dateTime = new DateTime() + const channel = new Channel() + const nowTime = dateTime.getTime() + const firstVistTime = params.fvts ? dateTime.strToTime(params.fvts) : nowTime + const lastVistTime = (params.lvts && params.lvts !== '0') ? dateTime.strToTime(params.lvts) : 0 + + const fillParams = { + appid: params.ak, + version: params.v ? params.v : '', + platform: platform.getPlatformCode(params.ut, params.p), + channel: channel.getChannelCode(params), + type: params.cst ? parseInt(params.cst) : 0, + // 访问设备 + device_id: params.did, + //是否为首次访问,判断标准:最后一次访问时间为0 + is_first_visit: (params.lt === '1' && !lastVistTime) ? 1 : 0, + first_visit_time: firstVistTime, + last_visit_time: nowTime, + visit_count: params.tvc ? parseInt(params.tvc) : 1, + // 用户相关 + last_visit_user_id: params.uid ? params.uid : '', + // 页面相关 + entry_page_id: pageInfo._id, + exit_page_id: pageInfo._id, + page_count: 0, + event_count: 0, + duration: 1, + // 版本 + sdk_version: params.mpsdk ? params.mpsdk : '', + platform_version: params.mpv ? params.mpv : '', + // 设备相关 + device_os_name: params.on ? params.on : platform.getOsName(params.p), + device_os_version: params.sv ? params.sv : '', + device_vendor: params.brand ? params.brand : '', + device_model: params.md ? params.md : '', + device_language: params.lang ? params.lang : '', + device_pixel_ratio: params.pr ? params.pr : '', + device_window_width: params.ww ? params.ww : '', + device_window_height: params.wh ? params.wh : '', + device_screen_width: params.sw ? params.sw : '', + device_screen_height: params.sh ? params.sh : '', + // 地区相关 + location_ip: params.ip ? params.ip : '', + location_latitude: params.lat ? parseFloat(params.lat) : -1, + location_longitude: params.lng ? parseFloat(params.lng) : -1, + location_country: params.cn ? params.cn : '', + location_province: params.pn ? params.pn : '', + location_city: params.ct ? params.ct : '', + is_finish: 0, + create_time: nowTime + } + + if(this.isHaveOldDeviceId(params)) { + fillParams.old_device_id = params.odid + } + + const res = await this.insert(this.tableName, fillParams) + + if (res && res.id) { + + //填充用户的会话日志 + if (params.uid) { + await new UserSessionLog().fill({ + ...params, + page_id: pageInfo._id, + sid: res.id + }) + } + + return { + code: 0, + msg: 'success', + data: { + pageId: pageInfo._id, + sessionLogId: res.id, + entryPageId: fillParams.entry_page_id, + eventCount: fillParams.event_count, + startTime: fillParams.first_visit_time, + createTime: fillParams.create_time, + pageCount: fillParams.page_count, + uid: fillParams.last_visit_user_id + } + } + } else { + return { + code: 500, + msg: 'Session log filled error' + } + } + } + + /** + * 判断是否包含老版本sdk生成的device_id, 此功能用于处理前端sdk升级后 device_id 发生变化导致日活、留存数据不准确的问题 + * @param {Object} params + */ + isHaveOldDeviceId(params) { + if(params.odid && params.odid !== params.did && params.odid !== 'YluY92BA6nJ6NfixI77sFQ%3D%3D&ie=1') { + console.log('params.odid', params.odid) + return true + } + return false + } + + + /** + * 获取会话 + * @param {Object} params 上报参数 + */ + async getSession(params) { + // 页面信息 + const page = new Page() + const pageInfo = await page.getPageAndCreate(params.ak, params.url, params.ttpj) + if (!pageInfo || pageInfo.length === 0) { + return { + code: 300, + msg: 'Not found this entry page' + } + } + + const platformObj = new Platform() + const platform = platformObj.getPlatformCode(params.ut, params.p) + // 查询日志 + const sessionLogInfo = await this.getCollection(this.tableName).where({ + appid: params.ak, + platform: platform, + device_id: params.did, + is_finish: 0 + }).orderBy('create_time', 'desc').limit(1).get() + + if (sessionLogInfo.data.length > 0) { + const userSessionLog = new UserSessionLog() + const sessionLogInfoData = sessionLogInfo.data[0] + // 最后一次访问时间距现在超过半小时算上次会话已结束并生成一次新的会话 + let sessionExpireTime = this.getConfig('sessionExpireTime') + sessionExpireTime = sessionExpireTime ? sessionExpireTime : 1800 + const sessionTime = new DateTime().getTime() - sessionLogInfoData.last_visit_time + if (sessionTime >= sessionExpireTime * 1000) { + if (this.debug) { + console.log('session log time expired', sessionTime) + } + await this.update(this.tableName, { + is_finish: 1 + }, { + appid: params.ak, + platform: platform, + device_id: params.did, + is_finish: 0 + }) + //关闭用户会话 + await userSessionLog.closeUserSession() + + return await this.fill(params) + } else { + //如果当前会话切换了用户则生成新的用户会话 + if (params.uid != sessionLogInfoData.last_visit_user_id) { + await userSessionLog.checkUserSession({ + ...params, + page_id: pageInfo._id, + sid: sessionLogInfoData._id, + last_visit_user_id: sessionLogInfoData.last_visit_user_id + }) + + await this.update(this.tableName, { + last_visit_user_id: params.uid ? params.uid : '' + }, { + _id: sessionLogInfoData._id + }) + } + + return { + code: 0, + msg: 'success', + data: { + pageId: pageInfo._id, + sessionLogId: sessionLogInfoData._id, + entryPageId: sessionLogInfoData.entry_page_id, + eventCount: sessionLogInfoData.event_count, + startTime: sessionLogInfoData.first_visit_time, + createTime: sessionLogInfoData.create_time, + pageCount: sessionLogInfoData.page_count, + uid: sessionLogInfoData.last_visit_user_id + } + } + } + } else { + return await this.fill(params) + } + } + + /** + * 更新会话信息 + * @param {String} sid 会话编号 + * @param {Object} data 更新数据 + */ + async updateSession(sid, data) { + const nowTime = new DateTime().getTime() + const accessTime = nowTime - data.createTime + const accessSenconds = accessTime > 1000 ? parseInt(accessTime / 1000) : 1 + + const updateData = { + last_visit_time: nowTime, + duration: accessSenconds, + } + //访问页面数量 + if (data.addPageCount) { + updateData.page_count = data.pageCount + } + //最终访问的页面编号 + if (data.pageId) { + updateData.exit_page_id = data.pageId + } + //产生事件次数 + if (data.eventCount) { + updateData.event_count = data.eventCount + } + + if (this.debug) { + console.log('update session log by sid-' + sid, updateData) + } + + //更新会话 + await this.update(this.tableName, updateData, { + _id: sid + }) + + //更新用户会话 + if (data.uid) { + data.nowTime = nowTime + await new UserSessionLog().updateUserSession(sid, data) + } + + return true + } + + /** + * 清理日志数据 + * @param {Number} days 保留天数, 留存统计需要计算30天后留存率,因此至少应保留31天的日志数据 + */ + async clean(days) { + days = Math.max(parseInt(days), 1) + console.log('clean session logs - day:', days) + + const dateTime = new DateTime() + const res = await this.delete(this.tableName, { + create_time: { + $lt: dateTime.getTimeBySetDays(0 - days) + } + }) + + if (!res.code) { + console.log('clean session log:', res) + } + return res + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/setting.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/setting.js new file mode 100644 index 0000000..c0ebc94 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/setting.js @@ -0,0 +1,44 @@ +/** + * @class Version 应用版本模型 + */ +const BaseMod = require('./base') +const { + DateTime +} = require('../lib') +module.exports = class Setting extends BaseMod { + constructor() { + super() + this.tableName = 'opendb-tempdata' + this.tablePrefix = false + this.settingKey = "uni-stat-setting" + } + + /** + * 获取统计云端配置 + */ + async getSetting() { + const res = await this.getCollection(this.tableName).doc(this.settingKey).get(); + if (res.data && res.data[0] && res.data[0].value) { + return res.data[0].value; + } else { + return { + mode: "open", + day: 7 + }; + } + } + /** + * 检测N天内是否有设备访问记录,如果有,则返回true,否则返回false + */ + async checkAutoRun(obj = {}) { + let { + day = 7 + } = obj; + const _ = this.dbCmd; + let nowTime = Date.now(); + const res = await this.getCollection("uni-stat-session-logs").where({ + create_time: _.gte(nowTime - 1000 * 3600 * 24 * day) + }).count(); + return res.total > 0 ? true : false; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/shareLog.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/shareLog.js new file mode 100644 index 0000000..5f42138 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/shareLog.js @@ -0,0 +1,104 @@ +/** + * @class ShareLog 分享日志模型 + */ +const BaseMod = require('./base') +const Platform = require('./platform') +const Channel = require('./channel') +const SessionLog = require('./sessionLog') +const { + DateTime +} = require('../lib') +module.exports = class ShareLog extends BaseMod { + constructor() { + super() + this.tableName = 'share-logs' + } + + /** + * 分析日志填充 + * @param {Object} reportParams 上报参数 + * @param {Object} sessionLogData 会话日志数据,此参数传递可减少数据库查询 + */ + async fill(reportParams, sessionLogData) { + let params, sessionLogInfo, sessionKey; + const fillParams = [] + const sessionLog = new SessionLog() + const platform = new Platform() + const dateTime = new DateTime() + const channel = new Channel() + for (const rk in reportParams) { + params = reportParams[rk] + + //暂存下会话数据,减少读库 + sessionKey = params.ak + params.did + params.p + if (!sessionLogData[sessionKey]) { + // 会话日志 + sessionLogInfo = await sessionLog.getSession(params) + if (sessionLogInfo.code) { + return sessionLogInfo + } + if (this.debug) { + console.log('sessionLogInfo', JSON.stringify(sessionLogInfo)) + } + sessionLogData[sessionKey] = sessionLogInfo + } else { + sessionLogInfo = sessionLogData[sessionKey] + } + + // 填充数据 + fillParams.push({ + appid: params.ak, + version: params.v ? params.v : '', + platform: platform.getPlatformCode(params.ut, params.p), + channel: channel.getChannelCode(params), + device_id: params.did, + uid: params.uid ? params.uid : '', + session_id: sessionLogInfo.data.sessionLogId, + page_id: sessionLogInfo.data.pageId, + create_time: dateTime.getTime() + }) + } + + if (fillParams.length === 0) { + return { + code: 200, + msg: 'Invild param' + } + } + + const res = await this.insert(this.tableName, fillParams) + if (res && res.inserted) { + return { + code: 0, + msg: 'success' + } + } else { + return { + code: 500, + msg: 'Filled error' + } + } + } + + /** + * 分享日志清理 + * @param {Number} days 保留天数 + */ + async clean(days) { + days = Math.max(parseInt(days), 1) + console.log('clean share logs - day:', days) + + const dateTime = new DateTime() + + const res = await this.delete(this.tableName, { + create_time: { + $lt: dateTime.getTimeBySetDays(0 - days) + } + }) + + if (!res.code) { + console.log('clean share log:', res) + } + return res + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/statResult.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/statResult.js new file mode 100644 index 0000000..aac8dbf --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/statResult.js @@ -0,0 +1,2151 @@ +/** + * @class StatResult 基础数据结果统计模型 + */ +const BaseMod = require('./base') +const Platform = require('./platform') +const Channel = require('./channel') +const Version = require('./version') +const SessionLog = require('./sessionLog') +const UserSessionLog = require('./userSessionLog') +const ErrorLog = require('./errorLog') +const ActiveDevices = require('./activeDevices') +const ActiveUsers = require('./activeUsers') +const UniIDUsers = require('./uniIDUsers') +const { + DateTime +} = require('../lib') +module.exports = class StatResult extends BaseMod { + constructor() { + super() + this.tableName = 'result' + this.platforms = [] + this.channels = [] + this.versions = [] + } + + /** + * 基础数据统计 + * @param {String} type 统计类型 hour:实时统计 day:按天统计,week:按周统计 month:按月统计 + * @param {Date|Time} date 指定日期或时间戳 + * @param {Boolean} reset 是否重置,为ture时会重置该批次数据 + */ + async stat(type, date, reset) { + const allowedType = ['hour', 'day', 'week', 'month'] + if (!allowedType.includes(type)) { + return { + code: 1002, + msg: 'This type is not allowed' + } + } + + if (this.debug) { + console.log('result --type:' + type + ', date:' + date + ', reset:' + reset) + } + + this.fillType = type + const dateTime = new DateTime() + const dateDimension = dateTime.getTimeDimensionByType(type, -1, date) + this.startTime = dateDimension.startTime + this.endTime = dateDimension.endTime + if (this.debug) { + console.log('dimension time', this.startTime + '--' + this.endTime) + } + + // 查看当前时间段日志是否已存在,防止重复生成 + if (!reset) { + const checkRes = await this.getCollection(this.tableName).where({ + dimension: this.fillType, + start_time: this.startTime, + end_time: this.endTime + }).get() + if (checkRes.data.length > 0) { + console.log('log have existed') + return { + code: 1003, + msg: 'This log have existed' + } + } + } else { + const delRes = await this.delete(this.tableName, { + start_time: this.startTime, + end_time: this.endTime + }) + console.log('delete old data result:', JSON.stringify(delRes)) + } + + // 周月数据单独统计 + if (['week', 'month'].includes(this.fillType)) { + return await this.statWeekOrMonth() + } + + // 数据获取 + this.sessionLog = new SessionLog() + const statRes = await this.aggregate(this.sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + is_first_visit: 1, + page_count: 1, + duration: 1, + create_time: 1 + }, + match: { + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }, + group: { + _id: { + appid: '$appid', + version: '$version', + platform: '$platform', + channel: '$channel' + }, + new_device_count: { + $sum: '$is_first_visit' + }, + page_view_count: { + $sum: '$page_count' + }, + total_duration: { + $sum: '$duration' + }, + session_times: { + $sum: 1 + } + }, + sort: { + new_device_count: 1, + page_view_count: 1, + session_times: 1 + }, + getAll: true + }) + + let res = { + code: 0, + msg: 'success' + } + if (this.debug) { + console.log('statRes', JSON.stringify(statRes)) + } + + this.fillData = [] + this.composes = [] + if (statRes.data.length > 0) { + for (const i in statRes.data) { + await this.fill(statRes.data[i]) + } + } + //补充数据 + await this.replenishStat() + if (this.fillData.length > 0) { + res = await this.batchInsert(this.tableName, this.fillData) + } + return res + } + + /** + * 按周/月统计 + */ + async statWeekOrMonth() { + const statRes = await this.aggregate(this.tableName, { + project: { + appid: 1, + version_id: 1, + platform_id: 1, + channel_id: 1, + new_device_count: 1, + new_user_count: 1, + page_visit_count: 1, + user_visit_times: 1, + app_launch_count: 1, + error_count: 1, + bounce_times: 1, + duration: 1, + user_duration: 1, + dimension: 1, + start_time: 1 + }, + match: { + dimension: 'day', + start_time: { + $gte: this.startTime, + $lte: this.endTime + } + }, + group: { + _id: { + appid: '$appid', + version_id: '$version_id', + platform_id: '$platform_id', + channel_id: '$channel_id' + }, + new_device_count: { + $sum: '$new_device_count' + }, + new_user_count: { + $sum: '$new_user_count' + }, + error_count: { + $sum: '$error_count' + }, + page_count: { + $sum: '$page_visit_count' + }, + total_duration: { + $sum: '$duration' + }, + total_user_duration: { + $sum: '$user_duration' + }, + total_user_session_times: { + $sum: '$user_session_times' + }, + session_times: { + $sum: '$app_launch_count' + }, + total_bounce_times: { + $sum: '$bounce_times' + } + }, + sort: { + new_device_count: 1, + error_count: 1, + page_count: 1 + }, + getAll: true + }) + + let res = { + code: 0, + msg: 'success' + } + if (this.debug) { + console.log('statRes', JSON.stringify(statRes)) + } + + this.activeDevices = new ActiveDevices() + this.activeUsers = new ActiveUsers() + this.fillData = [] + this.composes = [] + if (statRes.data.length > 0) { + for (const i in statRes.data) { + await this.getWeekOrMonthData(statRes.data[i]) + } + } + //补充数据 + await this.replenishStat() + if (this.fillData.length > 0) { + res = await this.batchInsert(this.tableName, this.fillData) + } + return res + } + + /** + * 获取周/月维度的填充数据 + * @param {Object} data 统计数据 + */ + async getWeekOrMonthData(data) { + + const matchCondition = { + ...data._id, + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + } + + // 查询活跃设备数 + const statVisitDeviceRes = await this.getCollection(this.activeDevices.tableName).where({ + ...matchCondition, + dimension: this.fillType + }).count() + + let activeDeviceCount = 0 + if (statVisitDeviceRes && statVisitDeviceRes.total > 0) { + activeDeviceCount = statVisitDeviceRes.total + } + + // 设备次均停留时长 + let avgSessionTime = 0 + if (data.total_duration > 0 && data.session_times > 0) { + avgSessionTime = Math.round(data.total_duration / data.session_times) + } + + // 设均停留时长 + let avgDeviceTime = 0 + if (data.total_duration > 0 && activeDeviceCount > 0) { + avgDeviceTime = Math.round(data.total_duration / activeDeviceCount) + } + + // 跳出率 + let bounceRate = 0 + if (data.total_bounce_times > 0 && data.session_times > 0) { + bounceRate = data.total_bounce_times * 100 / data.session_times + bounceRate = parseFloat(bounceRate.toFixed(2)) + } + + // 累计设备数 + let totalDevices = data.new_device_count + const totalDeviceRes = await this.getCollection(this.tableName).where({ + ...matchCondition, + dimension: this.fillType, + start_time: { + $lt: this.startTime + } + }).orderBy('start_time', 'desc').limit(1).get() + if (totalDeviceRes && totalDeviceRes.data.length > 0) { + totalDevices += totalDeviceRes.data[0].total_devices + } + + //活跃用户数 + const statVisitUserRes = await this.getCollection(this.activeUsers.tableName).where({ + ...matchCondition, + dimension: this.fillType + }).count() + let activeUserCount = 0 + if (statVisitUserRes && statVisitUserRes.total > 0) { + activeUserCount = statVisitUserRes.total + } + + // 平台信息 + let platformInfo = null + if (this.platforms && this.platforms[data._id.platform_id]) { + platformInfo = this.platforms[data._id.platform_id] + } else { + const platform = new Platform() + platformInfo = await this.getById(platform.tableName, data._id.platform_id) + if (!platformInfo || platformInfo.length === 0) { + platformInfo.code = '' + } + this.platforms[data._id.platform_id] = platformInfo + } + + // 渠道信息 + let channelInfo = null + if (this.channels && this.channels[data._id.channel_id]) { + channelInfo = this.channels[data._id.channel_id] + } else { + const channel = new Channel() + channelInfo = await this.getById(channel.tableName, data._id.channel_id) + if (!channelInfo || channelInfo.length === 0) { + channelInfo.channel_code = '' + } + this.channels[data._id.channel_id] = channelInfo + } + + // 版本信息 + let versionInfo = null + if (this.versions && this.versions[data._id.version_id]) { + versionInfo = this.versions[data._id.version_id] + } else { + const version = new Version() + versionInfo = await this.getById(version.tableName, data._id.version_id, false) + if (!versionInfo || versionInfo.length === 0) { + versionInfo.version = '' + } + this.versions[data._id.version_id] = versionInfo + } + + //总用户数 + const uniIDUsers = new UniIDUsers() + let totalUserCount = await uniIDUsers.getUserCount(data._id.appid, platformInfo.code, channelInfo.channel_code, versionInfo.version, { + $lte: this.endTime + }) + + //人均停留时长 + let avgUserTime = 0 + if (data.total_user_duration > 0 && activeUserCount > 0) { + avgUserTime = Math.round(data.total_user_duration / activeUserCount) + } + + //用户次均访问时长 + let avgUserSessionTime = 0 + if (data.total_user_duration > 0 && data.total_user_session_times > 0) { + avgUserSessionTime = Math.round(data.total_user_duration / data.total_user_session_times) + } + + //安卓平台活跃设备数需要减去sdk更新后device_id发生变更的设备数 + if(platformInfo.code === 'android') { + try{ + const statVisitOldDeviceRes = await this.getCollection(this.activeDevices.tableName).where({ + ...data._id, + create_time: { + $gte: this.startTime, + $lte: this.endTime + }, + dimension: this.fillType + '-old' + }).count() + if (statVisitOldDeviceRes && statVisitOldDeviceRes.total > 0) { + // 活跃设备留存数 + activeDeviceCount -= statVisitOldDeviceRes.total + //平均设备停留时长 + avgDeviceTime = Math.round(data.total_duration / activeDeviceCount) + } + } catch (e) { + console.log('server error: ' + e) + } + } + + const insertParam = { + appid: data._id.appid, + platform_id: data._id.platform_id, + channel_id: data._id.channel_id, + version_id: data._id.version_id, + //总设备数 + total_devices: totalDevices, + //本时间段新增设备数 + new_device_count: data.new_device_count, + //登录用户会话次数 + user_session_times: data.total_user_session_times, + //活跃设备数 + active_device_count: activeDeviceCount, + //总用户数 + total_users: totalUserCount, + //新增用户数 + new_user_count: data.new_user_count, + //活跃用户数 + active_user_count: activeUserCount, + //应用启动次数 = 设备会话次数 + app_launch_count: data.session_times, + //页面访问次数 + page_visit_count: data.page_view_count, + //错误次数 + error_count: data.error_count, + //会话总访问时长 + duration: data.total_duration, + //用户会话总访问时长 + user_duration: data.total_user_duration, + avg_device_session_time: avgSessionTime, + avg_user_session_time: avgUserSessionTime, + avg_device_time: avgDeviceTime, + avg_user_time: avgUserTime, + bounce_times: data.total_bounce_times, + bounce_rate: bounceRate, + retention: {}, + dimension: this.fillType, + stat_date: new DateTime().getDate('Ymd', this.startTime), + start_time: this.startTime, + end_time: this.endTime + } + + this.fillData.push(insertParam) + this.composes.push(data._id.appid + '_' + data._id.platform_id + '_' + data._id.channel_id + '_' + data + ._id.version_id) + + return insertParam + } + + /** + * 基础填充数据-目前只有小时和天维度的数据 + * @param {Object} data 统计数据 + */ + async fill(data) { + // 平台信息 + let platformInfo = null + if (this.platforms && this.platforms[data._id.platform]) { + //暂存下数据,减少读库 + platformInfo = this.platforms[data._id.platform] + } else { + const platform = new Platform() + platformInfo = await platform.getPlatformAndCreate(data._id.platform, null) + if (!platformInfo || platformInfo.length === 0) { + platformInfo._id = '' + } + this.platforms[data._id.platform] = platformInfo + if (this.debug) { + console.log('platformInfo', JSON.stringify(platformInfo)) + } + } + + // 渠道信息 + let channelInfo = null + const channelKey = data._id.appid + '_' + platformInfo._id + '_' + data._id.channel + if (this.channels && this.channels[channelKey]) { + channelInfo = this.channels[channelKey] + } else { + const channel = new Channel() + channelInfo = await channel.getChannelAndCreate(data._id.appid, platformInfo._id, data._id.channel) + if (!channelInfo || channelInfo.length === 0) { + channelInfo._id = '' + } + this.channels[channelKey] = channelInfo + if (this.debug) { + console.log('channelInfo', JSON.stringify(channelInfo)) + } + } + + // 版本信息 + let versionInfo = null + const versionKey = data._id.appid + '_' + data._id.platform + '_' + data._id.version + if (this.versions && this.versions[versionKey]) { + versionInfo = this.versions[versionKey] + } else { + const version = new Version() + versionInfo = await version.getVersionAndCreate(data._id.appid, data._id.platform, data._id.version) + if (!versionInfo || versionInfo.length === 0) { + versionInfo._id = '' + } + this.versions[versionKey] = versionInfo + if (this.debug) { + console.log('versionInfo', JSON.stringify(versionInfo)) + } + } + + // 访问设备数统计 + const matchCondition = data._id + Object.assign(matchCondition, { + create_time: { + $gte: this.startTime, + $lte: this.endTime + } + }) + const statVisitDeviceRes = await this.aggregate(this.sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + device_id: 1, + create_time: 1 + }, + match: matchCondition, + group: [{ + _id: { + device_id: '$device_id' + } + }, { + _id: {}, + total_devices: { + $sum: 1 + } + }] + }) + let activeDeviceCount = 0 + if (statVisitDeviceRes.data.length > 0) { + activeDeviceCount = statVisitDeviceRes.data[0].total_devices + } + + //安卓平台活跃设备数需要减去sdk更新后device_id发生变更的设备数 + if(platformInfo.code === 'android') { + const oldDeviceRes = await this.aggregate(this.sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + old_device_id: 1, + create_time: 1 + }, + match: matchCondition, + group: { + _id: { + device_id: '$old_device_id' + }, + create_time: { + $min: '$create_time' + }, + sessionCount: { + $sum: 1 + } + }, + sort: { + create_time: 1, + sessionCount: 1 + }, + getAll: true + }) + + if(oldDeviceRes.data.length) { + const thisOldDeviceIds = [] + for (const tau in oldDeviceRes.data) { + if(oldDeviceRes.data[tau]._id.device_id) { + thisOldDeviceIds.push(oldDeviceRes.data[tau]._id.device_id) + } + } + const statVisitOldDeviceRes = await this.aggregate(this.sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + device_id: 1, + create_time: 1 + }, + match: { + ...matchCondition, + device_id: { + $in: thisOldDeviceIds + } + }, + group: [{ + _id: { + device_id: '$device_id' + } + }, { + _id: {}, + total_devices: { + $sum: 1 + } + }] + }) + + if (this.debug) { + console.log('statVisitOldDeviceRes', JSON.stringify(statVisitOldDeviceRes)) + } + if (statVisitOldDeviceRes && statVisitOldDeviceRes.data.length > 0) { + // 活跃设备留存数 + activeDeviceCount -= statVisitOldDeviceRes.data[0].total_devices + } + } + } + + // 错误数量统计 + const errorLog = new ErrorLog() + const statErrorRes = await this.getCollection(errorLog.tableName).where(matchCondition).count() + let errorCount = 0 + if (statErrorRes && statErrorRes.total > 0) { + errorCount = statErrorRes.total + } + + // 设备的次均停留时长,设备访问总时长/设备会话次数 + let avgSessionTime = 0 + if (data.total_duration > 0 && data.session_times > 0) { + avgSessionTime = Math.round(data.total_duration / data.session_times) + } + + // 设均停留时长 + let avgDeviceTime = 0 + if (data.total_duration > 0 && activeDeviceCount > 0) { + avgDeviceTime = Math.round(data.total_duration / activeDeviceCount) + } + + // 跳出率 + let bounceTimes = 0 + const bounceRes = await this.getCollection(this.sessionLog.tableName).where({ + ...matchCondition, + page_count: 1 + }).count() + if (bounceRes && bounceRes.total > 0) { + bounceTimes = bounceRes.total + } + let bounceRate = 0 + if (bounceTimes > 0 && data.session_times > 0) { + bounceRate = bounceTimes * 100 / data.session_times + bounceRate = parseFloat(bounceRate.toFixed(2)) + } + + // 应用启动次数 = 会话次数 + const launchCount = data.session_times + + // 累计设备数 + let totalDevices = data.new_device_count + const totalDeviceRes = await this.getCollection(this.tableName).where({ + appid: data._id.appid, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + version_id: versionInfo._id, + dimension: this.fillType, + start_time: { + $lt: this.startTime + } + }).orderBy('start_time', 'desc').limit(1).get() + + if (totalDeviceRes && totalDeviceRes.data.length > 0) { + totalDevices += totalDeviceRes.data[0].total_devices + } + + //活跃用户数 + const userSessionLog = new UserSessionLog() + let activeUserCount = 0 + const activeUserCountRes = await this.aggregate(userSessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + uid: 1, + create_time: 1 + }, + match: matchCondition, + group: [{ + _id: { + uid: '$uid' + } + }, { + _id: {}, + total_users: { + $sum: 1 + } + }] + }) + + if (activeUserCountRes && activeUserCountRes.data.length > 0) { + activeUserCount = activeUserCountRes.data[0].total_users + } + + //新增用户数 + const uniIDUsers = new UniIDUsers() + let newUserCount = await uniIDUsers.getUserCount(matchCondition.appid, matchCondition.platform, + matchCondition.channel, matchCondition.version, { + $gte: this.startTime, + $lte: this.endTime + }) + + //总用户数 + let totalUserCount = await uniIDUsers.getUserCount(matchCondition.appid, matchCondition.platform, + matchCondition.channel, matchCondition.version, { + $lte: this.endTime + }) + + + //用户停留总时长及总会话次数 + let totalUserDuration = 0 + let totalUserSessionTimes = 0 + const totalUserDurationRes = await this.aggregate(userSessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + duration: 1, + create_time: 1 + }, + match: matchCondition, + group: [{ + _id: {}, + total_duration: { + $sum: "$duration" + }, + total_session_times: { + $sum: 1 + } + }] + }) + if (totalUserDurationRes && totalUserDurationRes.data.length > 0) { + totalUserDuration = totalUserDurationRes.data[0].total_duration + totalUserSessionTimes = totalUserDurationRes.data[0].total_session_times + } + + //人均停留时长 + let avgUserTime = 0 + //用户次均访问时长 + let avgUserSessionTime = 0 + if (totalUserDuration > 0 && activeUserCount > 0) { + avgUserTime = Math.round(totalUserDuration / activeUserCount) + avgUserSessionTime = Math.round(totalUserDuration / totalUserSessionTimes) + } + + //设置填充数据 + const datetime = new DateTime() + const insertParam = { + appid: data._id.appid, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + version_id: versionInfo._id, + total_devices: totalDevices, + new_device_count: data.new_device_count, + active_device_count: activeDeviceCount, + total_users: totalUserCount, + new_user_count: newUserCount, + active_user_count: activeUserCount, + user_session_times: totalUserSessionTimes, + app_launch_count: launchCount, + page_visit_count: data.page_view_count, + error_count: errorCount, + duration: data.total_duration, + user_duration: totalUserDuration, + avg_device_session_time: avgSessionTime, + avg_user_session_time: avgUserSessionTime, + avg_device_time: avgDeviceTime, + avg_user_time: avgUserTime, + bounce_times: bounceTimes, + bounce_rate: bounceRate, + retention: {}, + dimension: this.fillType, + stat_date: datetime.getDate('Ymd', this.startTime), + start_time: this.startTime, + end_time: this.endTime + } + + //数据填充 + this.fillData.push(insertParam) + this.composes.push(data._id.appid + '_' + platformInfo._id + '_' + channelInfo._id + '_' + versionInfo + ._id) + return insertParam + } + + /** + * 基础统计数据补充,防止累计数据丢失 + */ + async replenishStat() { + if (this.debug) { + console.log('composes data', this.composes) + } + + const datetime = new DateTime() + // const { + // startTime + // } = datetime.getTimeDimensionByType(this.fillType, -1, this.startTime) + + //上一次统计时间 + let preStatRes = await this.getCollection(this.tableName).where({ + start_time: {$lt: this.startTime}, + dimension: this.fillType + }).orderBy('start_time', 'desc').limit(1).get() + let preStartTime = 0 + if(preStatRes && preStatRes.data.length > 0) { + preStartTime = preStatRes.data[0].start_time + } + + if (this.debug) { + console.log('replenishStat-preStartTime', preStartTime) + } + + if(!preStartTime) { + return false + } + + // 上一阶段数据 + const preStatData = await this.selectAll(this.tableName, { + start_time: preStartTime, + dimension: this.fillType + }, { + appid: 1, + platform_id: 1, + channel_id: 1, + version_id: 1, + total_devices: 1, + total_users: 1 + }) + + if (!preStatData || preStatData.data.length === 0) { + return false + } + + if (this.debug) { + console.log('preStatData', JSON.stringify(preStatData)) + } + + let preKey + const preKeyArr = [] + for (const pi in preStatData.data) { + preKey = preStatData.data[pi].appid + '_' + preStatData.data[pi].platform_id + '_' + preStatData + .data[pi].channel_id + '_' + preStatData.data[pi].version_id + if (!this.composes.includes(preKey) && !preKeyArr.includes(preKey)) { + preKeyArr.push(preKey) + if (this.debug) { + console.log('preKey -add', preKey) + } + this.fillData.push({ + appid: preStatData.data[pi].appid, + platform_id: preStatData.data[pi].platform_id, + channel_id: preStatData.data[pi].channel_id, + version_id: preStatData.data[pi].version_id, + total_devices: preStatData.data[pi].total_devices, + new_device_count: 0, + active_device_count: 0, + total_users: preStatData.data[pi].total_users, + new_user_count: 0, + active_user_count: 0, + user_session_times: 0, + app_launch_count: 0, + page_visit_count: 0, + error_count: 0, + duration: 0, + user_duration: 0, + avg_device_session_time: 0, + avg_user_session_time: 0, + avg_device_time: 0, + avg_user_time: 0, + bounce_times: 0, + bounce_rate: 0, + retention: {}, + dimension: this.fillType, + stat_date: datetime.getDate('Ymd', this.startTime), + start_time: this.startTime, + end_time: this.endTime + }) + } else if (this.debug) { + console.log('preKey -have', preKey) + } + } + + return true + } + + /** + * 留存数据统计 + * @param {String} type 统计类型 hour:实时统计 day:按天统计,week:按周统计 month:按月统计 + * @param {Date|Time} date 指定日期或时间戳 + * @param {String} mod 统计模块 device:设备,user:用户 + */ + async retentionStat(type, date, mod = 'device') { + date = date ? date : new DateTime().getTimeBySetDays(-1, date) + const allowedType = ['day', 'week', 'month'] + if (!allowedType.includes(type)) { + return { + code: 1002, + msg: 'This type is not allowed' + } + } + let days = [] + switch (type) { + case 'week': + case 'month': + days = [1, 2, 3, 4, 5, 6, 7, 8, 9] + break + default: + days = [1, 2, 3, 4, 5, 6, 7, 14, 30] + break + } + + let res = { + code: 0, + msg: 'success' + } + + for (const day in days) { + //留存统计数据库查询较为复杂,因此这里拆分为多个维度 + if (mod && mod === 'user') { + //用户留存统计 + if (type === 'day') { + res = await this.userRetentionFillDayly(type, days[day], date) + } else { + res = await this.userRetentionFillWeekOrMonth(type, days[day], date) + } + } else { + //设备留存统计 + if (type === 'day') { + res = await this.deviceRetentionFillDayly(type, days[day], date) + } else { + res = await this.deviceRetentionFillWeekOrMonth(type, days[day], date) + } + } + } + return res + } + + /** + * 设备日留存统计数据填充 + * @param {String} type 统计类型 hour:实时统计 day:按天统计,week:按周统计 month:按月统计 + * @param {Date|Time} date 指定日期或时间戳 + * @param {Boolean} reset 是否重置,为ture时会重置该批次数据 + */ + async deviceRetentionFillDayly(type, day, date) { + if (type !== 'day') { + return { + code: 301, + msg: 'Type error:' + type + } + } + const dateTime = new DateTime() + const { + startTime, + endTime + } = dateTime.getTimeDimensionByType(type, 0 - day, date) + + if (!startTime || !endTime) { + return { + code: 1001, + msg: 'The statistic time get failed' + } + } + + // 截止时间范围 + const lastTimeInfo = dateTime.getTimeDimensionByType(type, 0, date) + + // 获取当时批次的统计日志 + const resultLogRes = await this.selectAll(this.tableName, { + dimension: type, + start_time: startTime, + end_time: endTime + }) + // const resultLogRes = await this.getCollection(this.tableName).where({ + // dimension: type, + // start_time: startTime, + // end_time: endTime + // }).get() + + if (this.debug) { + console.log('resultLogRes', JSON.stringify(resultLogRes)) + } + + if (!resultLogRes || resultLogRes.data.length === 0) { + if (this.debug) { + console.log('Not found this log --' + type + ':' + day + ', start:' + startTime + ',endTime:' + + endTime) + } + return { + code: 1000, + msg: 'Not found this log' + } + } + + const sessionLog = new SessionLog() + const platform = new Platform() + const channel = new Channel() + const version = new Version() + let res = null + for (const resultIndex in resultLogRes.data) { + const resultLog = resultLogRes.data[resultIndex] + // 平台信息 + let platformInfo = null + if (this.platforms && this.platforms[resultLog.platform_id]) { + platformInfo = this.platforms[resultLog.platform_id] + } else { + platformInfo = await this.getById(platform.tableName, resultLog.platform_id) + if (!platformInfo || platformInfo.length === 0) { + platformInfo.code = '' + } + this.platforms[resultLog.platform_id] = platformInfo + if (this.debug) { + console.log('platformInfo', JSON.stringify(platformInfo)) + } + } + // 渠道信息 + let channelInfo = null + if (this.channels && this.channels[resultLog.channel_id]) { + channelInfo = this.channels[resultLog.channel_id] + } else { + channelInfo = await this.getById(channel.tableName, resultLog.channel_id) + if (!channelInfo || channelInfo.length === 0) { + channelInfo.channel_code = '' + } + this.channels[resultLog.channel_id] = channelInfo + if (this.debug) { + console.log('channelInfo', JSON.stringify(channelInfo)) + } + } + // 版本信息 + let versionInfo = null + if (this.versions && this.versions[resultLog.version_id]) { + versionInfo = this.versions[resultLog.version_id] + } else { + versionInfo = await this.getById(version.tableName, resultLog.version_id, false) + if (!versionInfo || versionInfo.length === 0) { + versionInfo.version = '' + } + this.versions[resultLog.version_id] = versionInfo + if (this.debug) { + console.log('versionInfo', JSON.stringify(versionInfo)) + } + } + + // 获取该批次的活跃设备数 + const activeDeviceRes = await this.aggregate(sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + device_id: 1, + create_time: 1 + }, + match: { + appid: resultLog.appid, + version: versionInfo.version, + platform: platformInfo.code, + channel: channelInfo.channel_code, + create_time: { + $gte: startTime, + $lte: endTime + } + }, + group: { + _id: { + device_id: '$device_id' + }, + create_time: { + $min: '$create_time' + }, + sessionCount: { + $sum: 1 + } + }, + sort: { + create_time: 1, + sessionCount: 1 + }, + getAll: true + }) + + if (this.debug) { + console.log('activeDeviceRes', JSON.stringify(activeDeviceRes)) + } + let activeDeviceRate = 0 + let activeDevices = 0 + if (activeDeviceRes && activeDeviceRes.data.length > 0) { + const thisDayActiveDevices = activeDeviceRes.data.length + const thisDayActiveDeviceIds = [] + for (const tau in activeDeviceRes.data) { + thisDayActiveDeviceIds.push(activeDeviceRes.data[tau]._id.device_id) + } + if (this.debug) { + console.log('thisDayActiveDeviceIds', JSON.stringify(thisDayActiveDeviceIds)) + } + + // 留存活跃设备查询 + const retentionActiveDeviceRes = await this.aggregate(sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + device_id: 1, + create_time: 1 + }, + match: { + appid: resultLog.appid, + version: versionInfo.version, + platform: platformInfo.code, + channel: channelInfo.channel_code, + device_id: { + $in: thisDayActiveDeviceIds + }, + create_time: { + $gte: lastTimeInfo.startTime, + $lte: lastTimeInfo.endTime + } + }, + group: [{ + _id: { + device_id: '$device_id' + } + }, { + _id: {}, + total_devices: { + $sum: 1 + } + }] + }) + + if (this.debug) { + console.log('retentionActiveDeviceRes', JSON.stringify(retentionActiveDeviceRes)) + } + if (retentionActiveDeviceRes && retentionActiveDeviceRes.data.length > 0) { + // 活跃设备留存数 + activeDevices = retentionActiveDeviceRes.data[0].total_devices + // 活跃设备留存率 + activeDeviceRate = parseFloat((activeDevices * 100 / thisDayActiveDevices).toFixed(2)) + } + + //安卓平台留存需要增加sdk更新后device_id发生变更的设备数 + if(platformInfo.code === 'android') { + const retentionActiveOldDeviceRes = await this.aggregate(sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + old_device_id: 1, + create_time: 1 + }, + match: { + appid: resultLog.appid, + version: versionInfo.version, + platform: platformInfo.code, + channel: channelInfo.channel_code, + old_device_id: { + $in: thisDayActiveDeviceIds + }, + create_time: { + $gte: lastTimeInfo.startTime, + $lte: lastTimeInfo.endTime + } + }, + group: [{ + _id: { + device_id: '$old_device_id' + } + }, { + _id: {}, + total_devices: { + $sum: 1 + } + }] + }) + + if (this.debug) { + console.log('retentionActiveOldDeviceRes', JSON.stringify(retentionActiveOldDeviceRes)) + } + if (retentionActiveOldDeviceRes && retentionActiveOldDeviceRes.data.length > 0) { + // 活跃设备留存数 + activeDevices += retentionActiveOldDeviceRes.data[0].total_devices + // 活跃设备留存率 + activeDeviceRate = parseFloat((activeDevices * 100 / thisDayActiveDevices).toFixed(2)) + } + } + } + + // 获取该批次新增设备数 + const newDeviceRes = await this.aggregate(sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + is_first_visit: 1, + device_id: 1, + create_time: 1 + }, + match: { + appid: resultLog.appid, + version: versionInfo.version, + platform: platformInfo.code, + channel: channelInfo.channel_code, + is_first_visit: 1, + create_time: { + $gte: startTime, + $lte: endTime + } + }, + group: { + _id: { + device_id: '$device_id' + }, + create_time: { + $min: '$create_time' + }, + sessionCount: { + $sum: 1 + } + }, + sort: { + create_time: 1, + sessionCount: 1 + }, + getAll: true + }) + + let newDeviceRate = 0 + let newDevices = 0 + if (newDeviceRes && newDeviceRes.data.length > 0) { + const thisDayNewDevices = newDeviceRes.data.length + const thisDayNewDeviceIds = [] + for (const tau in newDeviceRes.data) { + thisDayNewDeviceIds.push(newDeviceRes.data[tau]._id.device_id) + } + + if (this.debug) { + console.log('thisDayNewDeviceIds', JSON.stringify(thisDayNewDeviceIds)) + } + + // 留存的设备查询 + const retentionNewDeviceRes = await this.aggregate(sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + device_id: 1, + create_time: 1 + }, + match: { + appid: resultLog.appid, + version: versionInfo.version, + platform: platformInfo.code, + channel: channelInfo.channel_code, + device_id: { + $in: thisDayNewDeviceIds + }, + create_time: { + $gte: lastTimeInfo.startTime, + $lte: lastTimeInfo.endTime + } + }, + group: [{ + _id: { + device_id: '$device_id' + } + }, { + _id: {}, + total_devices: { + $sum: 1 + } + }] + }) + + if (retentionNewDeviceRes && retentionNewDeviceRes.data.length > 0) { + // 新增设备留存数 + newDevices = retentionNewDeviceRes.data[0].total_devices + // 新增设备留存率 + newDeviceRate = parseFloat((newDevices * 100 / thisDayNewDevices).toFixed(2)) + } + + //安卓平台留存需要增加sdk更新后device_id发生变更的设备数 + if(platformInfo.code === 'android') { + const retentionNewOldDeviceRes = await this.aggregate(sessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + old_device_id: 1, + create_time: 1 + }, + match: { + appid: resultLog.appid, + version: versionInfo.version, + platform: platformInfo.code, + channel: channelInfo.channel_code, + old_device_id: { + $in: thisDayNewDeviceIds + }, + create_time: { + $gte: lastTimeInfo.startTime, + $lte: lastTimeInfo.endTime + } + }, + group: [{ + _id: { + device_id: '$old_device_id' + } + }, { + _id: {}, + total_devices: { + $sum: 1 + } + }] + }) + + if (this.debug) { + console.log('retentionNewOldDeviceRes', JSON.stringify(retentionNewOldDeviceRes)) + } + + if (retentionNewOldDeviceRes && retentionNewOldDeviceRes.data.length > 0) { + // 新增设备留存数 + newDevices += retentionNewOldDeviceRes.data[0].total_devices + // 新增设备留存率 + newDeviceRate = parseFloat((newDevices * 100 / thisDayNewDevices).toFixed(2)) + } + } + } + + // 数据更新 + const retentionData = resultLog.retention + const dataKey = type.substr(0, 1) + '_' + day + if (!retentionData.active_device) { + retentionData.active_device = {} + } + retentionData.active_device[dataKey] = { + device_count: activeDevices, + device_rate: activeDeviceRate + } + if (!retentionData.new_device) { + retentionData.new_device = {} + } + retentionData.new_device[dataKey] = { + device_count: newDevices, + device_rate: newDeviceRate + } + + if (this.debug) { + console.log('retentionData', JSON.stringify(retentionData)) + } + + res = await this.update(this.tableName, { + retention: retentionData + }, { + _id: resultLog._id + }) + } + + if (res && res.updated) { + return { + code: 0, + msg: 'success' + } + } else { + return { + code: 500, + msg: 'retention data update failed' + } + } + } + + /** + * 设备周/月留存数据填充 + * @param {String} type 统计类型 hour:实时统计 day:按天统计,week:按周统计 month:按月统计 + * @param {Date|Time} date 指定日期或时间戳 + * @param {Boolean} reset 是否重置,为ture时会重置该批次数据 + */ + async deviceRetentionFillWeekOrMonth(type, day, date) { + if (!['week', 'month'].includes(type)) { + return { + code: 301, + msg: 'Type error:' + type + } + } + const dateTime = new DateTime() + const { + startTime, + endTime + } = dateTime.getTimeDimensionByType(type, 0 - day, date) + + if (!startTime || !endTime) { + return { + code: 1001, + msg: 'The statistic time get failed' + } + } + + // 截止时间范围 + const lastTimeInfo = dateTime.getTimeDimensionByType(type, 0, date) + + // 获取当时批次的统计日志 + const resultLogRes = await this.selectAll(this.tableName, { + dimension: type, + start_time: startTime, + end_time: endTime + }) + + if (this.debug) { + console.log('resultLogRes', JSON.stringify(resultLogRes)) + } + + if (!resultLogRes || resultLogRes.data.length === 0) { + if (this.debug) { + console.log('Not found this session log --' + type + ':' + day + ', start:' + startTime + + ',endTime:' + endTime) + } + return { + code: 1000, + msg: 'Not found this session log' + } + } + + const activeDevicesObj = new ActiveDevices() + let res = null; + let activeDeviceRes; + let activeDeviceRate; + let activeDevices; + let newDeviceRate; + let newDevices + for (const resultIndex in resultLogRes.data) { + const resultLog = resultLogRes.data[resultIndex] + // 获取该批次的活跃设备数 + activeDeviceRes = await this.selectAll(activeDevicesObj.tableName, { + appid: resultLog.appid, + platform_id: resultLog.platform_id, + channel_id: resultLog.channel_id, + version_id: resultLog.version_id, + dimension: type, + create_time: { + $gte: startTime, + $lte: endTime + } + }, { + device_id: 1 + }) + + if (this.debug) { + console.log('activeDeviceRes', JSON.stringify(activeDeviceRes)) + } + + activeDeviceRate = 0 + activeDevices = 0 + if (activeDeviceRes && activeDeviceRes.data.length > 0) { + const thisDayActiveDevices = activeDeviceRes.data.length + const thisDayActiveDeviceIds = [] + for (const tau in activeDeviceRes.data) { + thisDayActiveDeviceIds.push(activeDeviceRes.data[tau].device_id) + } + if (this.debug) { + console.log('thisDayActiveDeviceIds', JSON.stringify(thisDayActiveDeviceIds)) + } + // 留存活跃设备数 + const retentionActiveDeviceRes = await this.getCollection(activeDevicesObj.tableName).where({ + appid: resultLog.appid, + platform_id: resultLog.platform_id, + channel_id: resultLog.channel_id, + version_id: resultLog.version_id, + device_id: { + $in: thisDayActiveDeviceIds + }, + dimension: type, + create_time: { + $gte: lastTimeInfo.startTime, + $lte: lastTimeInfo.endTime + } + }).count() + + if (this.debug) { + console.log('retentionActiveDeviceRes', JSON.stringify(retentionActiveDeviceRes)) + } + if (retentionActiveDeviceRes && retentionActiveDeviceRes.total > 0) { + // 活跃设备留存数 + activeDevices = retentionActiveDeviceRes.total + // 活跃设备留存率 + activeDeviceRate = parseFloat((activeDevices * 100 / thisDayActiveDevices).toFixed(2)) + } + } + + // 获取该批次的新增设备数 + const newDeviceRes = await this.selectAll(activeDevicesObj.tableName, { + appid: resultLog.appid, + platform_id: resultLog.platform_id, + channel_id: resultLog.channel_id, + version_id: resultLog.version_id, + is_new: 1, + dimension: type, + create_time: { + $gte: startTime, + $lte: endTime + } + }, { + device_id: 1 + }) + + newDeviceRate = 0 + newDevices = 0 + if (newDeviceRes && newDeviceRes.data.length > 0) { + const thisDayNewDevices = newDeviceRes.data.length + const thisDayNewDeviceIds = [] + for (const tau in newDeviceRes.data) { + thisDayNewDeviceIds.push(newDeviceRes.data[tau].device_id) + } + + // 新增设备留存数 + const retentionNewDeviceRes = await this.getCollection(activeDevicesObj.tableName).where({ + appid: resultLog.appid, + platform_id: resultLog.platform_id, + channel_id: resultLog.channel_id, + version_id: resultLog.version_id, + device_id: { + $in: thisDayNewDeviceIds + }, + dimension: type, + create_time: { + $gte: lastTimeInfo.startTime, + $lte: lastTimeInfo.endTime + } + }).count() + + if (retentionNewDeviceRes && retentionNewDeviceRes.total > 0) { + // 新增设备留存数 + newDevices = retentionNewDeviceRes.total + // 新增设备留存率 + newDeviceRate = parseFloat((newDevices * 100 / thisDayNewDevices).toFixed(2)) + } + } + + // 数据更新 + const retentionData = resultLog.retention + const dataKey = type.substr(0, 1) + '_' + day + if (!retentionData.active_device) { + retentionData.active_device = {} + } + retentionData.active_device[dataKey] = { + device_count: activeDevices, + device_rate: activeDeviceRate + } + if (!retentionData.new_device) { + retentionData.new_device = {} + } + retentionData.new_device[dataKey] = { + device_count: newDevices, + device_rate: newDeviceRate + } + + if (this.debug) { + console.log('retentionData', JSON.stringify(retentionData)) + } + + res = await this.update(this.tableName, { + retention: retentionData + }, { + _id: resultLog._id + }) + } + + if (res && res.updated) { + return { + code: 0, + msg: 'success' + } + } else { + return { + code: 500, + msg: 'retention data update failed' + } + } + } + + /** + * 用户日留存数据填充 + * @param {String} type 统计类型 hour:实时统计 day:按天统计,week:按周统计 month:按月统计 + * @param {Date|Time} date 指定日期或时间戳 + * @param {Boolean} reset 是否重置,为ture时会重置该批次数据 + */ + async userRetentionFillDayly(type, day, date) { + if (type !== 'day') { + return { + code: 301, + msg: 'Type error:' + type + } + } + const dateTime = new DateTime() + const { + startTime, + endTime + } = dateTime.getTimeDimensionByType(type, 0 - day, date) + + if (!startTime || !endTime) { + return { + code: 1001, + msg: 'The statistic time get failed' + } + } + + // 截止时间范围 + const lastTimeInfo = dateTime.getTimeDimensionByType(type, 0, date) + + // 获取当时批次的统计日志 + const resultLogRes = await this.selectAll(this.tableName, { + dimension: type, + start_time: startTime, + end_time: endTime + }) + + if (this.debug) { + console.log('resultLogRes', JSON.stringify(resultLogRes)) + } + + if (!resultLogRes || resultLogRes.data.length === 0) { + if (this.debug) { + console.log('Not found this log --' + type + ':' + day + ', start:' + startTime + ',endTime:' + + endTime) + } + return { + code: 1000, + msg: 'Not found this log' + } + } + + const userSessionLog = new UserSessionLog() + const uniIDUsers = new UniIDUsers() + const platform = new Platform() + const channel = new Channel() + const version = new Version() + let res = null + for (const resultIndex in resultLogRes.data) { + const resultLog = resultLogRes.data[resultIndex] + // 平台信息 + let platformInfo = null + if (this.platforms && this.platforms[resultLog.platform_id]) { + platformInfo = this.platforms[resultLog.platform_id] + } else { + platformInfo = await this.getById(platform.tableName, resultLog.platform_id) + if (!platformInfo || platformInfo.length === 0) { + platformInfo.code = '' + } + this.platforms[resultLog.platform_id] = platformInfo + if (this.debug) { + console.log('platformInfo', JSON.stringify(platformInfo)) + } + } + // 渠道信息 + let channelInfo = null + if (this.channels && this.channels[resultLog.channel_id]) { + channelInfo = this.channels[resultLog.channel_id] + } else { + channelInfo = await this.getById(channel.tableName, resultLog.channel_id) + if (!channelInfo || channelInfo.length === 0) { + channelInfo.channel_code = '' + } + this.channels[resultLog.channel_id] = channelInfo + if (this.debug) { + console.log('channelInfo', JSON.stringify(channelInfo)) + } + } + // 版本信息 + let versionInfo = null + if (this.versions && this.versions[resultLog.version_id]) { + versionInfo = this.versions[resultLog.version_id] + } else { + versionInfo = await this.getById(version.tableName, resultLog.version_id, false) + if (!versionInfo || versionInfo.length === 0) { + versionInfo.version = '' + } + this.versions[resultLog.version_id] = versionInfo + if (this.debug) { + console.log('versionInfo', JSON.stringify(versionInfo)) + } + } + + // 获取该时间段内的活跃用户 + const activeUserRes = await this.aggregate(userSessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + uid: 1, + create_time: 1 + }, + match: { + appid: resultLog.appid, + version: versionInfo.version, + platform: platformInfo.code, + channel: channelInfo.channel_code, + create_time: { + $gte: startTime, + $lte: endTime + } + }, + group: { + _id: { + uid: '$uid' + }, + create_time: { + $min: '$create_time' + }, + sessionCount: { + $sum: 1 + } + }, + sort: { + create_time: 1, + sessionCount: 1 + }, + getAll: true + }) + + if (this.debug) { + console.log('activeUserRes', JSON.stringify(activeUserRes)) + } + + //活跃用户留存率 + let activeUserRate = 0 + //活跃用户留存数 + let activeUsers = 0 + if (activeUserRes && activeUserRes.data.length > 0) { + const thisDayActiveUsers = activeUserRes.data.length + //获取该时间段内的活跃用户编号,这里没用lookup联查是因为数据量较大时lookup效率很低 + const thisDayActiveUids = [] + for (let tau in activeUserRes.data) { + thisDayActiveUids.push(activeUserRes.data[tau]._id.uid) + } + + if (this.debug) { + console.log('thisDayActiveUids', JSON.stringify(thisDayActiveUids)) + } + + // 留存活跃用户数 + const retentionActiveUserRes = await this.aggregate(userSessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + uid: 1, + create_time: 1 + }, + match: { + appid: resultLog.appid, + version: versionInfo.version, + platform: platformInfo.code, + channel: channelInfo.channel_code, + uid: { + $in: thisDayActiveUids + }, + create_time: { + $gte: lastTimeInfo.startTime, + $lte: lastTimeInfo.endTime + } + }, + group: [{ + _id: { + uid: '$uid' + } + }, { + _id: {}, + total_users: { + $sum: 1 + } + }] + }) + + if (this.debug) { + console.log('retentionActiveUserRes', JSON.stringify(retentionActiveUserRes)) + } + if (retentionActiveUserRes && retentionActiveUserRes.data.length > 0) { + // 活跃用户留存数 + activeUsers = retentionActiveUserRes.data[0].total_users + // 活跃用户留存率 + activeUserRate = parseFloat((activeUsers * 100 / thisDayActiveUsers).toFixed(2)) + } + } + + + + //新增用户编号 + const thisDayNewUids = await uniIDUsers.getUserIds(resultLog.appid, platformInfo.code, channelInfo.channel_code, versionInfo.version, { + $gte: startTime, + $lte: endTime + }) + //新增用户留存率 + let newUserRate = 0 + //新增用户留存数 + let newUsers = 0 + if (thisDayNewUids.length > 0) { + // 现在依然活跃的用户数 + const retentionNewUserRes = await this.aggregate(userSessionLog.tableName, { + project: { + appid: 1, + version: 1, + platform: 1, + channel: 1, + uid: 1, + create_time: 1 + }, + match: { + appid: resultLog.appid, + version: versionInfo.version, + platform: platformInfo.code, + channel: channelInfo.channel_code, + uid: { + $in: thisDayNewUids + }, + create_time: { + $gte: lastTimeInfo.startTime, + $lte: lastTimeInfo.endTime + } + }, + group: [{ + _id: { + uid: '$uid' + } + }, { + _id: {}, + total_users: { + $sum: 1 + } + }] + }) + + if (retentionNewUserRes && retentionNewUserRes.data.length > 0) { + // 新增用户留存数 + newUsers = retentionNewUserRes.data[0].total_users + // 新增用户留存率 + newUserRate = parseFloat((newUsers * 100 / thisDayNewUids.length).toFixed(2)) + } + } + + // 数据更新 + const retentionData = resultLog.retention + const dataKey = type.substr(0, 1) + '_' + day + if (!retentionData.active_user) { + retentionData.active_user = {} + } + retentionData.active_user[dataKey] = { + user_count: activeUsers, + user_rate: activeUserRate + } + if (!retentionData.new_user) { + retentionData.new_user = {} + } + retentionData.new_user[dataKey] = { + user_count: newUsers, + user_rate: newUserRate + } + + if (this.debug) { + console.log('retentionData', JSON.stringify(retentionData)) + } + + res = await this.update(this.tableName, { + retention: retentionData + }, { + _id: resultLog._id + }) + } + + if (res && res.updated) { + return { + code: 0, + msg: 'success' + } + } else { + return { + code: 500, + msg: 'retention data update failed' + } + } + } + + + /** + * 用户周/月留存数据填充 + * @param {String} type 统计类型 hour:实时统计 day:按天统计,week:按周统计 month:按月统计 + * @param {Date|Time} date 指定日期或时间戳 + * @param {Boolean} reset 是否重置,为ture时会重置该批次数据 + */ + async userRetentionFillWeekOrMonth(type, day, date) { + if (!['week', 'month'].includes(type)) { + return { + code: 301, + msg: 'Type error:' + type + } + } + const dateTime = new DateTime() + const { + startTime, + endTime + } = dateTime.getTimeDimensionByType(type, 0 - day, date) + + if (!startTime || !endTime) { + return { + code: 1001, + msg: 'The statistic time get failed' + } + } + + // 截止时间范围 + const lastTimeInfo = dateTime.getTimeDimensionByType(type, 0, date) + + // 获取当时批次的统计日志 + const resultLogRes = await this.selectAll(this.tableName, { + dimension: type, + start_time: startTime, + end_time: endTime + }) + + if (this.debug) { + console.log('resultLogRes', JSON.stringify(resultLogRes)) + } + + if (!resultLogRes || resultLogRes.data.length === 0) { + if (this.debug) { + console.log('Not found this session log --' + type + ':' + day + ', start:' + startTime + + ',endTime:' + endTime) + } + return { + code: 1000, + msg: 'Not found this session log' + } + } + + const activeUserObj = new ActiveUsers() + const uniIDUsers = new UniIDUsers() + const platform = new Platform() + const channel = new Channel() + const version = new Version() + let res = null + //活跃用户留存率 + let activeUserRate + //活跃用户留存数 + let activeUsers + //新增用户留存率 + let newUserRate + //新增用户留存数 + let newUsers + for (const resultIndex in resultLogRes.data) { + const resultLog = resultLogRes.data[resultIndex] + + // 平台信息 + let platformInfo = null + if (this.platforms && this.platforms[resultLog.platform_id]) { + platformInfo = this.platforms[resultLog.platform_id] + } else { + platformInfo = await this.getById(platform.tableName, resultLog.platform_id) + if (!platformInfo || platformInfo.length === 0) { + platformInfo.code = '' + } + this.platforms[resultLog.platform_id] = platformInfo + if (this.debug) { + console.log('platformInfo', JSON.stringify(platformInfo)) + } + } + // 渠道信息 + let channelInfo = null + if (this.channels && this.channels[resultLog.channel_id]) { + channelInfo = this.channels[resultLog.channel_id] + } else { + channelInfo = await this.getById(channel.tableName, resultLog.channel_id) + if (!channelInfo || channelInfo.length === 0) { + channelInfo.channel_code = '' + } + this.channels[resultLog.channel_id] = channelInfo + if (this.debug) { + console.log('channelInfo', JSON.stringify(channelInfo)) + } + } + // 版本信息 + let versionInfo = null + if (this.versions && this.versions[resultLog.version_id]) { + versionInfo = this.versions[resultLog.version_id] + } else { + versionInfo = await this.getById(version.tableName, resultLog.version_id, false) + if (!versionInfo || versionInfo.length === 0) { + versionInfo.version = '' + } + this.versions[resultLog.version_id] = versionInfo + if (this.debug) { + console.log('versionInfo', JSON.stringify(versionInfo)) + } + } + + // 获取该批次的活跃用户数 + const activeUserRes = await this.selectAll(activeUserObj.tableName, { + appid: resultLog.appid, + platform_id: resultLog.platform_id, + channel_id: resultLog.channel_id, + version_id: resultLog.version_id, + dimension: type, + create_time: { + $gte: startTime, + $lte: endTime + } + }, { + uid: 1 + }) + + if (this.debug) { + console.log('activeUserRes', JSON.stringify(activeUserRes)) + } + + activeUserRate = 0 + activeUsers = 0 + if (activeUserRes && activeUserRes.data.length > 0) { + const thisDayactiveUsers = activeUserRes.data.length + const thisDayActiveDeviceIds = [] + for (const tau in activeUserRes.data) { + thisDayActiveDeviceIds.push(activeUserRes.data[tau].uid) + } + if (this.debug) { + console.log('thisDayActiveDeviceIds', JSON.stringify(thisDayActiveDeviceIds)) + } + // 留存活跃用户数 + const retentionactiveUserRes = await this.getCollection(activeUserObj.tableName).where({ + appid: resultLog.appid, + platform_id: resultLog.platform_id, + channel_id: resultLog.channel_id, + version_id: resultLog.version_id, + uid: { + $in: thisDayActiveDeviceIds + }, + dimension: type, + create_time: { + $gte: lastTimeInfo.startTime, + $lte: lastTimeInfo.endTime + } + }).count() + + if (this.debug) { + console.log('retentionactiveUserRes', JSON.stringify(retentionactiveUserRes)) + } + if (retentionactiveUserRes && retentionactiveUserRes.total > 0) { + // 活跃用户留存数 + activeUsers = retentionactiveUserRes.total + // 活跃用户留存率 + activeUserRate = parseFloat((activeUsers * 100 / thisDayactiveUsers).toFixed(2)) + } + } + + + //新增用户编号 + const thisDayNewUids = await uniIDUsers.getUserIds(resultLog.appid, platformInfo.code, channelInfo.channel_code, versionInfo.version, { + $gte: startTime, + $lte: endTime + }) + + // 新增用户留存率 + newUserRate = 0 + // 新增用户留存数 + newUsers = 0 + if(thisDayNewUids && thisDayNewUids.length > 0) { + // 新增用户留存数 + const retentionnewUserRes = await this.getCollection(activeUserObj.tableName).where({ + appid: resultLog.appid, + platform_id: resultLog.platform_id, + channel_id: resultLog.channel_id, + version_id: resultLog.version_id, + uid: { + $in: thisDayNewUids + }, + dimension: type, + create_time: { + $gte: lastTimeInfo.startTime, + $lte: lastTimeInfo.endTime + } + }).count() + + if (retentionnewUserRes && retentionnewUserRes.total > 0) { + // 新增用户留存数 + newUsers = retentionnewUserRes.total + // 新增用户留存率 + newUserRate = parseFloat((newUsers * 100 / thisDayNewUids.length).toFixed(2)) + } + } + + // 数据更新 + const retentionData = resultLog.retention + const dataKey = type.substr(0, 1) + '_' + day + if (!retentionData.active_user) { + retentionData.active_user = {} + } + retentionData.active_user[dataKey] = { + user_count: activeUsers, + user_rate: activeUserRate + } + if (!retentionData.new_user) { + retentionData.new_user = {} + } + retentionData.new_user[dataKey] = { + user_count: newUsers, + user_rate: newUserRate + } + + if (this.debug) { + console.log('retentionData', JSON.stringify(retentionData)) + } + + res = await this.update(this.tableName, { + retention: retentionData + }, { + _id: resultLog._id + }) + } + + if (res && res.updated) { + return { + code: 0, + msg: 'success' + } + } else { + return { + code: 500, + msg: 'retention data update failed' + } + } + } + + + /** + * 清理实时统计的日志 + * @param {Number} days 实时统计日志保留天数 + */ + async cleanHourLog(days = 7) { + + console.log('clean hour logs - day:', days) + + const dateTime = new DateTime() + + const res = await this.delete(this.tableName, { + dimension: 'hour', + start_time: { + $lt: dateTime.getTimeBySetDays(0 - days) + } + }) + + if (!res.code) { + console.log('clean hour logs - res:', res) + } + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/config.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/config.js new file mode 100644 index 0000000..c285788 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/config.js @@ -0,0 +1,12 @@ +/** + * 表名 + */ +const dbName = { + uniIdUsers: 'uni-id-users', // 支付订单明细表 + uniPayOrders: 'uni-pay-orders', // 支付订单明细表 + uniStatPayResult: 'uni-stat-pay-result', // 统计结果存储表 + uniStatSessionLogs: 'uni-stat-session-logs', // 设备会话日志表(主要用于统计访问设备数) + uniStatUserSessionLogs: 'uni-stat-user-session-logs', // 用户会话日志表(主要用于统计访问人数) +}; + +module.exports = dbName; diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/index.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/index.js new file mode 100644 index 0000000..933a82b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/index.js @@ -0,0 +1,10 @@ +/** + * 数据库操作 + */ +module.exports = { + uniIdUsers: require('./uniIdUsers'), + uniPayOrders: require('./uniPayOrders'), + uniStatPayResult: require('./uniStatPayResult'), + uniStatSessionLogs: require('./uniStatSessionLogs'), + uniStatUserSessionLogs: require('./uniStatUserSessionLogs'), +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniIdUsers.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniIdUsers.js new file mode 100644 index 0000000..5560be2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniIdUsers.js @@ -0,0 +1,62 @@ +/** + * 数据库操作 + */ +const dbName = require("./config"); + +let db = uniCloud.database(); +let _ = db.command; +let $ = _.aggregate; + +class Dao { + async count(whereJson) { + let dbRes = await db.collection(dbName.uniIdUsers).where(whereJson).count() + return dbRes && dbRes.total ? dbRes.total : 0; + } + + async countNewUserOrder(obj) { + let { + whereJson, + status + } = obj; + let dbRes = await db.collection(dbName.uniIdUsers).aggregate() + .match(whereJson) + .lookup({ + from: dbName.uniPayOrders, + let: { + user_id: '$_id', + }, + pipeline: $.pipeline() + .match(_.expr($.and([ + $.eq(['$user_id', '$$user_id']), + $.in(['$status', status]) + ]))) + .limit(1) + .done(), + as: 'order', + }) + .unwind({ + path: '$order', + }) + .group({ + _id: null, + count: { + $addToSet: '$_id' + }, + }) + .addFields({ + count: { + $size: '$count' + } + }) + .end() + try { + return dbRes.data[0].count; + } catch (err) { + return 0; + } + + } +} + + +module.exports = new Dao(); diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniPayOrders.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniPayOrders.js new file mode 100644 index 0000000..40e3709 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniPayOrders.js @@ -0,0 +1,99 @@ +/** + * 数据库操作 + */ +const BaseMod = require('../../base'); +const dbName = require("./config"); + +class Dao extends BaseMod { + + constructor() { + super() + this.tablePrefix = false; // 不使用表前缀 + } + + async group(data) { + let { + start_time, + end_time, + status: status_str + } = data; + let status; + if (status_str === "已下单") { + + } else if (status_str === "已付款") { + status = { + $gt: 0 + } + } else if (status_str === "已退款") { + status = { + $in: [2, 3] + } + } + const dbRes = await this.aggregate(dbName.uniPayOrders, { + match: { + create_date: { + $gte: start_time, + $lte: end_time + }, + status + }, + group: { + _id: { + appid: '$appid', + version: '$stat_data.app_version', + platform: '$stat_data.platform', + channel: '$stat_data.channel', + }, + status: { + $first: '$status' + }, + // 支付金额 + total_fee: { + $sum: '$total_fee' + }, + // 退款金额 + refund_fee: { + $sum: '$refund_fee' + }, + // 支付笔数 + order_count: { + $sum: 1 + }, + // 支付人数(去重复) + user_count: { + $addToSet: '$user_id' + }, + // 支付设备数(去重复) + device_count: { + $addToSet: '$device_id' + }, + + create_date: { + $min: '$create_date' + } + }, + addFields: { + user_count: { + $size: '$user_count' + }, + device_count: { + $size: '$device_count' + } + }, + // 按创建时间排序 + sort: { + create_date: 1 + }, + getAll: true + }); + + let list = dbRes.data; + list.map((item) => { + item.status_str = status_str; + }); + return list; + } +} + + +module.exports = new Dao(); diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniStatPayResult.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniStatPayResult.js new file mode 100644 index 0000000..5fb8944 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniStatPayResult.js @@ -0,0 +1,36 @@ +/** + * 数据库操作 + */ +const BaseMod = require('../../base'); +const dbName = require("./config"); + +class Dao extends BaseMod { + + constructor() { + super() + this.tablePrefix = false; // 不使用表前缀 + } + + async list(data) { + let { + whereJson, + } = data; + const dbRes = await this.getCollection(dbName.uniStatPayResult).where(whereJson).get(); + return dbRes.data; + } + + async del(data) { + let { + whereJson + } = data; + const dbRes = await this.delete(dbName.uniStatPayResult, whereJson); + return dbRes.deleted; + } + + async adds(saveList) { + return await this.batchInsert(dbName.uniStatPayResult, saveList); + } +} + + +module.exports = new Dao(); diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniStatSessionLogs.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniStatSessionLogs.js new file mode 100644 index 0000000..17511c0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniStatSessionLogs.js @@ -0,0 +1,78 @@ +/** + * 数据库操作 + */ +const BaseMod = require('../../base'); +const dbName = require("./config"); + +class Dao extends BaseMod { + + constructor() { + super() + this.tablePrefix = false; // 不使用表前缀 + } + + async group(data) { + let { + whereJson, + } = data; + const dbRes = await this.aggregate(dbName.uniStatSessionLogs, { + match: whereJson, + group: { + _id: { + appid: '$appid', + version: '$version', + platform: '$platform', + channel: '$channel', + }, + // 设备数(去重复) + device_count: { + $addToSet: '$device_id' + }, + + create_time: { + $min: '$create_time' + } + }, + addFields: { + device_count: { + $size: '$device_count' + } + }, + // 按创建时间排序 + sort: { + create_time: 1 + }, + getAll: true + }); + + return dbRes.data; + } + + async groupCount(whereJson) { + const dbRes = await this.aggregate(dbName.uniStatSessionLogs, { + match: whereJson, + group: { + _id: null, + // 设备数(去重复) + count: { + $addToSet: '$device_id' + }, + }, + addFields: { + count: { + $size: '$count' + } + }, + getAll: true + }); + try { + return dbRes.data[0].count; + } catch (err) { + return 0; + } + } + +} + + +module.exports = new Dao(); diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniStatUserSessionLogs.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniStatUserSessionLogs.js new file mode 100644 index 0000000..d4792f8 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/dao/uniStatUserSessionLogs.js @@ -0,0 +1,78 @@ +/** + * 数据库操作 + */ +const BaseMod = require('../../base'); +const dbName = require("./config"); + +class Dao extends BaseMod { + + constructor() { + super() + this.tablePrefix = false; // 不使用表前缀 + } + + async group(data) { + let { + whereJson + } = data; + const dbRes = await this.aggregate(dbName.uniStatUserSessionLogs, { + match: whereJson, + group: { + _id: { + appid: '$appid', + version: '$version', + platform: '$platform', + channel: '$channel', + }, + // 用户数(去重复) + user_count: { + $addToSet: '$uid' + }, + + create_time: { + $min: '$create_time' + } + }, + addFields: { + user_count: { + $size: '$user_count' + } + }, + // 按创建时间排序 + sort: { + create_time: 1 + }, + getAll: true + }); + + let list = dbRes.data; + return list; + } + + async groupCount(whereJson) { + const dbRes = await this.aggregate(dbName.uniStatUserSessionLogs, { + match: whereJson, + group: { + _id: null, + // 设备数(去重复) + count: { + $addToSet: '$uid' + }, + }, + addFields: { + count: { + $size: '$count' + } + }, + getAll: true + }); + try { + return dbRes.data[0].count; + } catch (err) { + return 0; + } + } +} + + +module.exports = new Dao(); diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/index.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/index.js new file mode 100644 index 0000000..c22fea2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/index.js @@ -0,0 +1,6 @@ +/** + * 基础对外模型 + */ +module.exports = { + PayResult: require('./payResult'), +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/payResult.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/payResult.js new file mode 100644 index 0000000..ad864ed --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uni-pay/payResult.js @@ -0,0 +1,500 @@ +/** + * @class ActiveDevices 活跃设备模型 - 每日跑批合并,仅添加本周/本月首次访问的设备。 + */ +const BaseMod = require('../base') +const Platform = require('../platform') +const Channel = require('../channel') +const Version = require('../version') + +const { + DateTime, + UniCrypto +} = require('../../lib') + +const dao = require('./dao') + +let db = uniCloud.database(); +let _ = db.command; +let $ = _.aggregate; + +module.exports = class PayResult extends BaseMod { + constructor() { + super() + this.platforms = [] + this.channels = [] + this.versions = [] + } + + /** + 支付金额:统计时间内,成功支付的订单金额之和(不剔除退款订单)。 + 支付笔数:统计时间内,成功支付的订单数,一个订单对应唯一一个订单号。(不剔除退款订单。) + 支付人数:统计时间内,成功支付的人数(不剔除退款订单)。 + 支付设备数:统计时间内,成功支付的设备数(不剔除退款订单)。 + 下单金额:统计时间内,成功下单的订单金额(不剔除退款订单)。 + 下单笔数:统计时间内,成功下单的订单笔数(不剔除退款订单)。 + 下单人数:统计时间内,成功下单的客户数,一人多次下单记为一人(不剔除退款订单)。 + 下单设备数:统计时间内,成功下单的设备数,一台设备多次访问被计为一台(不剔除退款订单)。 + 访问人数:统计时间内,访问人数,一人多次访问被计为一人(只统计已登录的用户)。 + 访问设备数:统计时间内,访问设备数,一台设备多次访问被计为一台(包含未登录的用户)。 + * @desc 支付统计(按日统计) + * @param {string} type 统计范围 hour:按小时统计,day:按天统计,week:按周统计,month:按月统计 quarter:按季度统计 year:按年统计 + * @param {date|time} date + * @param {bool} reset + */ + async stat(type, date, reset, config = {}) { + if (!date) date = Date.now(); + + // 以下是测试代码----------------------------------------------------------- + //reset = true; + //date = 1667318400000; + // 以上是测试代码----------------------------------------------------------- + let res = await this.run(type, date, reset, config); // 每小时 + if (type === "hour" && config.timely) { + /** + * 如果是小时纬度统计,则还需要再统计(今日实时数据) + * 2022-11-01 01:00:00 统计的是 2022-11-01 的天维度数据(即该天0点-1点数据) + * 2022-11-01 02:00:00 统计的是 2022-11-01 的天维度数据(即该天0点-2点数据) + * 2022-11-01 23:00:00 统计的是 2022-11-01 的天维度数据(即该天0点-23点数据) + * 2022-11-02 00:00:00 统计的是 2022-11-01 的天维度数据(即该天最终数据) + * 2022-11-02 01:00:00 统计的是 2022-11-02 的天维度数据(即该天0点-1点数据) + */ + date -= 1000 * 3600; // 需要减去1小时 + let tasks = []; + tasks.push(this.run("day", date, true, 0)); // 今日 + // 以下数据每6小时刷新一次 + const dateTime = new DateTime(); + const timeInfo = dateTime.getTimeInfo(date); + if ((timeInfo.nHour + 1) % 6 === 0) { + tasks.push(this.run("week", date, true, 0)); // 本周 + tasks.push(this.run("month", date, true, 0)); // 本月 + tasks.push(this.run("quarter", date, true, 0)); // 本季度 + tasks.push(this.run("year", date, true, 0)); // 本年度 + } + await Promise.all(tasks); + } + return res; + } + /** + * @desc 支付统计 + * @param {string} type 统计范围 hour:按小时统计,day:按天统计,week:按周统计,month:按月统计 quarter:按季度统计 year:按年统计 + * @param {date|time} date 哪个时间节点计算(默认已当前时间计算) + * @param {bool} reset 如果统计数据已存在,是否需要重新统计 + */ + async run(type, date, reset, offset = -1) { + let dimension = type; + const dateTime = new DateTime(); + // 获取统计的起始时间和截止时间 + const dateDimension = dateTime.getTimeDimensionByType(dimension, offset, date); + let start_time = dateDimension.startTime; + let end_time = dateDimension.endTime; + + let runStartTime = Date.now(); + let debug = true; + if (debug) { + console.log(`-----------------支付统计开始(${dimension})-----------------`); + console.log('本次统计时间:', dateTime.getDate('Y-m-d H:i:s', start_time), "-", dateTime.getDate('Y-m-d H:i:s', end_time)) + console.log('本次统计参数:', 'type:' + type, 'date:' + date, 'reset:' + reset) + } + this.startTime = start_time; + let pubWhere = { + start_time, + end_time + }; + // 查看当前时间段数据是否已存在,防止重复生成 + + if (!reset) { + let list = await dao.uniStatPayResult.list({ + whereJson: { + ...pubWhere, + dimension + } + }); + if (list.length > 0) { + console.log('data have exists') + if (debug) { + let runEndTime = Date.now(); + console.log(`耗时:${((runEndTime - runStartTime ) / 1000).toFixed(3)} 秒`) + console.log(`-----------------支付统计结束(${dimension})-----------------`); + } + return { + code: 1003, + msg: 'Pay data in this time have already existed' + } + } + } else { + let delRes = await dao.uniStatPayResult.del({ + whereJson: { + ...pubWhere, + dimension + } + }); + console.log('Delete old data result:', JSON.stringify(delRes)) + } + // 支付订单分组(已下单) + let statPayOrdersList1 = await dao.uniPayOrders.group({ + ...pubWhere, + status: "已下单" + }); + // 支付订单分组(且已付款,含退款) + let statPayOrdersList2 = await dao.uniPayOrders.group({ + ...pubWhere, + status: "已付款" + }); + // 支付订单分组(已退款) + let statPayOrdersList3 = await dao.uniPayOrders.group({ + ...pubWhere, + status: "已退款" + }); + let statPayOrdersList = statPayOrdersList1.concat(statPayOrdersList2).concat(statPayOrdersList3) + let res = { + code: 0, + msg: 'success' + } + // 将支付订单分组查询结果组装 + let statDta = {}; + if (statPayOrdersList.length > 0) { + for (let i = 0; i < statPayOrdersList.length; i++) { + let item = statPayOrdersList[i]; + let { + appid, + version, + platform, + channel, + } = item._id; + let { + status_str + } = item; + let key = `${appid}-${version}-${platform}-${channel}`; + if (!statDta[key]) { + statDta[key] = { + appid, + version, + platform, + channel, + status: {} + }; + } + let newItem = JSON.parse(JSON.stringify(item)); + delete newItem._id; + statDta[key].status[status_str] = newItem; + } + } + if (this.debug) console.log('statDta: ', statDta) + + let saveList = []; + for (let key in statDta) { + let item = statDta[key]; + let { + appid, + version, + platform, + channel, + status: statusData, + } = item; + if (!channel) channel = item.scene; + + let fieldData = { + pay_total_amount: 0, + pay_order_count: 0, + pay_user_count: 0, + pay_device_count: 0, + create_total_amount: 0, + create_order_count: 0, + create_user_count: 0, + create_device_count: 0, + refund_total_amount: 0, + refund_order_count: 0, + refund_user_count: 0, + refund_device_count: 0, + }; + + + for (let status in statusData) { + let statusItem = statusData[status]; + if (status === "已下单") { + // 已下单 + fieldData.create_total_amount += statusItem.total_fee; + fieldData.create_order_count += statusItem.order_count; + fieldData.create_user_count += statusItem.user_count; + fieldData.create_device_count += statusItem.device_count; + } else if (status === "已付款") { + // 已付款 + fieldData.pay_total_amount += statusItem.total_fee; + fieldData.pay_order_count += statusItem.order_count; + fieldData.pay_user_count += statusItem.user_count; + fieldData.pay_device_count += statusItem.device_count; + } else if (status === "已退款") { + // 已退款 + fieldData.refund_total_amount += statusItem.total_fee; + fieldData.refund_order_count += statusItem.order_count; + fieldData.refund_user_count += statusItem.user_count; + fieldData.refund_device_count += statusItem.device_count; + } + } + // 平台信息 + let platformInfo = null; + if (this.platforms && this.platforms[platform]) { + // 从缓存中读取数据 + platformInfo = this.platforms[platform] + } else { + const platformObj = new Platform() + platformInfo = await platformObj.getPlatformAndCreate(platform, null) + if (!platformInfo || platformInfo.length === 0) { + platformInfo._id = '' + } + this.platforms[platform] = platformInfo; + } + // 渠道信息 + let channelInfo = null + const channelKey = appid + '_' + platformInfo._id + '_' + channel; + if (this.channels && this.channels[channelKey]) { + channelInfo = this.channels[channelKey]; + } else { + const channelObj = new Channel() + channelInfo = await channelObj.getChannelAndCreate(appid, platformInfo._id, channel) + if (!channelInfo || channelInfo.length === 0) { + channelInfo._id = '' + } + this.channels[channelKey] = channelInfo + } + // 版本信息 + let versionInfo = null + const versionKey = appid + '_' + platform + '_' + version + if (this.versions && this.versions[versionKey]) { + versionInfo = this.versions[versionKey] + } else { + const versionObj = new Version() + versionInfo = await versionObj.getVersionAndCreate(appid, platform, version) + if (!versionInfo || versionInfo.length === 0) { + versionInfo._id = '' + } + this.versions[versionKey] = versionInfo + } + let countWhereJson = { + create_time: _.gte(start_time).lte(end_time), + appid, + version, + platform: _.in(getUniPlatform(platform)), + channel, + }; + // 活跃设备数量 + let activity_device_count = await dao.uniStatSessionLogs.groupCount(countWhereJson); + // 活跃用户数量 + let activity_user_count = await dao.uniStatUserSessionLogs.groupCount(countWhereJson); + + /* + // TODO 此处有问题,暂不使用 + // 新设备数量 + let new_device_count = await dao.uniStatSessionLogs.groupCount({ + ...countWhereJson, + is_first_visit: 1, + }); + // 新注册用户数量 + let new_user_count = await dao.uniIdUsers.count({ + register_date: _.gte(start_time).lte(end_time), + register_env: { + appid, + app_version: version, + uni_platform: _.in(getUniPlatform(platform)), + channel, + } + }); + + + // 新注册用户中下单的人数 + let new_user_create_order_count = await dao.uniIdUsers.countNewUserOrder({ + whereJson: { + register_date: _.gte(start_time).lte(end_time), + register_env: { + appid, + app_version: version, + uni_platform: _.in(getUniPlatform(platform)), + channel, + } + }, + status: [-1, 0] + }); + // 新注册用户中支付成功的人数 + let new_user_pay_order_count = await dao.uniIdUsers.countNewUserOrder({ + whereJson: { + register_date: _.gte(start_time).lte(end_time), + register_env: { + appid, + app_version: version, + uni_platform: _.in(getUniPlatform(platform)), + channel, + } + }, + status: [1, 2, 3] + }); */ + + + saveList.push({ + appid, + platform_id: platformInfo._id, + channel_id: channelInfo._id, + version_id: versionInfo._id, + dimension, + create_date: Date.now(), // 记录下当前时间 + start_time, + end_time, + stat_date: getNowDate(start_time, 8, dimension), + ...fieldData, + activity_user_count, + activity_device_count, + // new_user_count, + // new_device_count, + // new_user_create_order_count, + // new_user_pay_order_count, + }); + } + if (this.debug) console.log('saveList: ', saveList) + //return; + if (saveList.length > 0) { + res = await dao.uniStatPayResult.adds(saveList); + } + if (debug) { + let runEndTime = Date.now(); + console.log(`耗时:${((runEndTime - runStartTime ) / 1000).toFixed(3)} 秒`) + console.log(`本次共添加:${saveList.length } 条记录`) + console.log(`-----------------支付统计结束(${dimension})-----------------`); + } + return res + } + +} + + +function getUniPlatform(platform) { + let list = []; + if (["h5", "web"].indexOf(platform) > -1) { + list = ["h5", "web"]; + } else if (["app-plus", "app"].indexOf(platform) > -1) { + list = ["app-plus", "app"]; + } else { + list = [platform]; + } + return list; +} + +function getNowDate(date = new Date(), targetTimezone = 8, dimension) { + if (typeof date === "string" && !isNaN(date)) date = Number(date); + if (typeof date == "number") { + if (date.toString().length == 10) date *= 1000; + date = new Date(date); + } + const { + year, + month, + day, + hour, + minute, + second + } = getFullTime(date); + // 现在的时间 + let date_str; + if (dimension === "month") { + date_str = timeFormat(date, "yyyy-MM", targetTimezone); + } else if (dimension === "quarter") { + date_str = timeFormat(date, "yyyy-MM", targetTimezone); + } else if (dimension === "year") { + date_str = timeFormat(date, "yyyy", targetTimezone); + } else { + date_str = timeFormat(date, "yyyy-MM-dd", targetTimezone); + } + return { + date_str, + year, + month, + day, + hour, + //minute, + //second, + }; +} + +function getFullTime(date = new Date(), targetTimezone = 8) { + if (!date) { + return ""; + } + if (typeof date === "string" && !isNaN(date)) date = Number(date); + if (typeof date == "number") { + if (date.toString().length == 10) date *= 1000; + date = new Date(date); + } + const dif = date.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + const east8time = date.getTime() + timeDif; + date = new Date(east8time); + + let YYYY = date.getFullYear() + ''; + let MM = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1); + let DD = (date.getDate() < 10 ? '0' + (date.getDate()) : date.getDate()); + let hh = (date.getHours() < 10 ? '0' + (date.getHours()) : date.getHours()); + let mm = (date.getMinutes() < 10 ? '0' + (date.getMinutes()) : date.getMinutes()); + let ss = (date.getSeconds() < 10 ? '0' + (date.getSeconds()) : date.getSeconds()); + 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), + }; +}; + + +/** + * 日期格式化 + */ +function timeFormat(time, fmt = 'yyyy-MM-dd hh:mm:ss', targetTimezone = 8) { + try { + if (!time) { + return ""; + } + if (typeof time === "string" && !isNaN(time)) time = Number(time); + // 其他更多是格式化有如下: + // yyyy-MM-dd hh:mm:ss|yyyy年MM月dd日 hh时MM分等,可自定义组合 + let date; + if (typeof time === "number") { + if (time.toString().length == 10) time *= 1000; + date = new Date(time); + } else { + date = time; + } + + const dif = date.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + const east8time = date.getTime() + timeDif; + + date = new Date(east8time); + let opt = { + "M+": date.getMonth() + 1, //月份 + "d+": date.getDate(), //日 + "h+": date.getHours(), //小时 + "m+": date.getMinutes(), //分 + "s+": date.getSeconds(), //秒 + "q+": Math.floor((date.getMonth() + 3) / 3), //季度 + "S": date.getMilliseconds() //毫秒 + }; + if (/(y+)/.test(fmt)) { + fmt = fmt.replace(RegExp.$1, (date.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; + } +}; diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uniIDUsers.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uniIDUsers.js new file mode 100644 index 0000000..6f40dde --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/uniIDUsers.js @@ -0,0 +1,97 @@ +/** + * @class UniIDUsers uni-id 用户模型 + */ +const BaseMod = require('./base') +module.exports = class UniIDUsers extends BaseMod { + + constructor() { + super() + this.tableName = 'uni-id-users' + this.tablePrefix = false + } + + /** + * 获取用户数 + * @param {String} appid DCloud-appid + * @param {String} platform 平台 + * @param {String} channel 渠道 + * @param {String} version 版本 + * @param {Object} registerTime 注册时间范围 例:{$gte:开始日期时间戳, $lte:结束日期时间戳} + * @return {Number} + */ + async getUserCount(appid, platform, channel, version, registerTime) { + if(!appid || !platform) { + return false + } + const condition = this.getCondition(appid, platform, channel, version, registerTime) + let userCount = 0 + const userCountRes = await this.getCollection(this.tableName).where(condition).count() + if(userCountRes && userCountRes.total > 0) { + userCount = userCountRes.total + } + return userCount + } + + /** + * 获取用户编号列表 + * @param {String} appid DCloud-appid + * @param {String} platform 平台 + * @param {String} channel 渠道 + * @param {String} version 版本 + * @param {Object} registerTime 注册时间范围 例:{$gte:开始日期时间戳, $lte:结束日期时间戳} + * @return {Array} + */ + async getUserIds(appid, platform, channel, version, registerTime) { + if(!appid || !platform) { + return false + } + const condition = this.getCondition(appid, platform, channel, version, registerTime) + let uids = [] + const uidsRes = await this.selectAll(this.tableName, condition, { + _id: 1 + }) + + for (const u in uidsRes.data) { + uids.push(uidsRes.data[u]._id) + } + + return uids + } + + /** + * 获取查询条件 + * @param {String} appid DCloud-appid + * @param {String} platform 平台 + * @param {String} channel 渠道 + * @param {String} version 版本 + * @param {Object} registerTime 注册时间范围 例:{$gte:开始日期时间戳, $lte:结束日期时间戳} + */ + getCondition(appid, platform, channel, version, registerTime) { + + let condition = { + 'register_env.appid': appid,//DCloud appid + 'register_env.uni_platform': platform,//平台 + 'register_env.channel': channel ? channel : '1001', //渠道或场景值 + 'register_env.app_version' : version //应用版本区分 + } + + //原生应用平台 + if(['android', 'ios'].includes(platform)) { + condition['register_env.uni_platform'] = 'app'//systemInfo中uniPlatform字段android和ios都用app表示,所以此处查询需要用osName区分一下 + condition['register_env.os_name'] = platform //系统 + } + + //兼容vue2 + if(channel === '1001') { + condition['register_env.channel'] = {$in:['', '1001']} + } + + //注册时间 + if(registerTime) { + condition.register_date = registerTime + } + + return condition + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/userSessionLog.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/userSessionLog.js new file mode 100644 index 0000000..2af4ebd --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/userSessionLog.js @@ -0,0 +1,229 @@ +/** + * @class UserSessionLog 用户会话日志模型 + */ +const BaseMod = require('./base') +const Platform = require('./platform') +const Channel = require('./channel') +const { + DateTime +} = require('../lib') +module.exports = class UserSessionLog extends BaseMod { + constructor() { + super() + this.tableName = 'user-session-logs' + } + + /** + * 用户会话日志数据填充 + * @param {Object} params 上报参数 + */ + async fill(params) { + + if (!params.sid) { + return { + code: 200, + msg: 'Not found session log' + } + } + + if (!params.uid) { + return { + code: 200, + msg: 'Parameter "uid" not found' + } + } + + const dateTime = new DateTime() + const platform = new Platform() + const channel = new Channel() + + //获取当前页面信息 + if (!params.page_id) { + const pageInfo = await page.getPageAndCreate(params.ak, params.url, params.ttpj) + if (!pageInfo || pageInfo.length === 0) { + return { + code: 300, + msg: 'Not found this entry page' + } + } + params.page_id = pageInfo._id + } + + const nowTime = dateTime.getTime() + + const fillParams = { + appid: params.ak, + version: params.v ? params.v : '', + platform: platform.getPlatformCode(params.ut, params.p), + channel: channel.getChannelCode(params), + session_id: params.sid, + uid: params.uid, + last_visit_time: nowTime, + entry_page_id: params.page_id, + exit_page_id: params.page_id, + page_count: 0, + event_count: 0, + duration: 1, + is_finish: 0, + create_time: nowTime, + } + + const res = await this.insert(this.tableName, fillParams) + + if (res && res.id) { + return { + code: 0, + msg: 'success' + } + } else { + return { + code: 500, + msg: 'User session log filled error' + } + } + } + + /** + * 检测用户会话是否有变化,并更新 + * @param {Object} params 校验参数 - sid:基础会话编号 uid:用户编号 last_visit_user_id:基础会话中最近一个访问用户的编号 + */ + async checkUserSession(params) { + if (!params.sid) { + return { + code: 200, + msg: 'Not found session log' + } + } + + if (!params.uid) { + //用户已退出会话 + if (params.last_visit_user_id) { + if (this.debug) { + console.log('user "' + params.last_visit_user_id + '" is exit session :', params.sid) + } + await this.closeUserSession(params.sid) + } + } else { + //添加用户日志 + if (!params.last_visit_user_id) { + await this.fill(params) + } + //用户已切换 + else if (params.uid != params.last_visit_user_id) { + if (this.debug) { + console.log('user "' + params.last_visit_user_id + '" change to "' + params.uid + + '" in the session :', params.sid) + } + //关闭原会话生成新用户对话 + await this.closeUserSession(params.sid) + await this.fill(params) + } + } + return { + code: 0, + msg: 'success' + } + } + + + + /** + * 关闭用户会话 + * @param {String} sid 基础会话编号 + */ + async closeUserSession(sid) { + if (this.debug) { + console.log('close user session log by sid:', sid) + } + return await this.update(this.tableName, { + is_finish: 1 + }, { + session_id: sid, + is_finish: 0 + }) + } + + + /** + * 更新会话信息 + * @param {String} sid 基础会话编号 + * @param {Object} data 更新数据 + */ + async updateUserSession(sid, data) { + + const userSession = await this.getCollection(this.tableName).where({ + session_id: sid, + uid: data.uid, + is_finish: 0 + }).orderBy('create_time', 'desc').limit(1).get() + + if (userSession.data.length === 0) { + console.log('Not found the user session', { + session_id: sid, + uid: data.uid, + is_finish: 0 + }) + return { + code: 300, + msg: 'Not found the user session' + } + } + + let nowTime = data.nowTime ? data.nowTime : new DateTime().getTime() + const accessTime = nowTime - userSession.data[0].createTime + const accessSenconds = accessTime > 1000 ? parseInt(accessTime / 1000) : 1 + + const updateData = { + last_visit_time: nowTime, + duration: accessSenconds, + } + + //访问页面数量 + if (data.addPageCount) { + updateData.page_count = userSession.data[0].page_count + data.addPageCount + } + //最终访问的页面编号 + if (data.pageId) { + updateData.exit_page_id = data.pageId + } + //产生事件次数 + if (data.eventCount) { + updateData.event_count = userSession.data[0].event_count + data.addEventCount + } + + if (this.debug) { + console.log('update user session log by sid-' + sid, updateData) + } + + await this.update(this.tableName, updateData, { + _id: userSession.data[0]._id + }) + + return { + code: 0, + msg: 'success' + } + } + + /** + * 清理用户会话日志数据 + * @param {Object} days 保留天数, 留存统计需要计算30天后留存率,因此至少应保留31天的日志数据 + */ + async clean(days = 31) { + days = Math.max(parseInt(days), 1) + console.log('clean user session logs - day:', days) + + const dateTime = new DateTime() + const res = await this.delete(this.tableName, { + create_time: { + $lt: dateTime.getTimeBySetDays(0 - days) + } + }) + + if (!res.code) { + console.log('clean user session log:', res) + } + return res + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/version.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/version.js new file mode 100644 index 0000000..b20236a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/version.js @@ -0,0 +1,73 @@ +/** + * @class Version 应用版本模型 + */ +const BaseMod = require('./base') +const { + DateTime +} = require('../lib') +module.exports = class Version extends BaseMod { + constructor() { + super() + this.tableName = 'opendb-app-versions' + this.tablePrefix = false + this.cacheKeyPre = 'uni-stat-app-version-' + } + + /** + * 获取版本信息 + * @param {String} appid DCloud-appid + * @param {String} platformId 平台编号 + * @param {String} appVersion 平台版本号 + */ + async getVersion(appid, platform, appVersion) { + const cacheKey = this.cacheKeyPre + appid + '-' + platform + '-' + appVersion + let versionData = await this.getCache(cacheKey) + if (!versionData) { + const versionInfo = await this.getCollection(this.tableName).where({ + appid: appid, + uni_platform: platform, + type: 'native_app', + version: appVersion + }).limit(1).get() + versionData = [] + if (versionInfo.data.length > 0) { + versionData = versionInfo.data[0] + await this.setCache(cacheKey, versionData) + } + } + return versionData + } + + + /** + * 获取版本信息没有则进行创建 + * @param {String} appid DCloud-appid + * @param {String} platform 平台代码 + * @param {String} appVersion 平台版本号 + */ + async getVersionAndCreate(appid, platform, appVersion) { + const versionInfo = await this.getVersion(appid, platform, appVersion) + if (versionInfo.length === 0) { + if (appVersion.length > 0 && !appVersion.includes('}')) { + const thisTime = new DateTime().getTime() + const insertParam = { + appid: appid, + platform: [], + uni_platform: platform, + type: 'native_app', + version: appVersion, + stable_publish: false, + create_env: 'uni-stat', + create_date: thisTime + } + const res = await this.insert(this.tableName, insertParam) + if (res && res.id) { + return Object.assign(insertParam, { + _id: res.id + }) + } + } + } + return versionInfo + } +} diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/receiver.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/receiver.js new file mode 100644 index 0000000..61306e2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/receiver.js @@ -0,0 +1,126 @@ +/** + * @class UniStatReportDataReceiver uni统计上报数据接收器 + * @function report 上报数据调度处理函数 + */ +const { + parseUrlParams +} = require('../shared') +const SessionLog = require('./mod/sessionLog') +const PageLog = require('./mod/pageLog') +const EventLog = require('./mod/eventLog') +const ErrorLog = require('./mod/errorLog') +const Device = require('./mod/device') +class UniStatReportDataReceiver { + /** + * @description 上报数据调度处理函数 + * @param {Object} params 基础上报参数 + * @param {Object} context 请求附带的上下文信息 + */ + async report(params, context) { + let res = { + code: 0, + msg: 'success' + } + + if (!params || !params.requests) { + return { + code: 200, + msg: 'Invild params' + } + } + + // JSON参数解析 + const requestParam = JSON.parse(params.requests) + if (!requestParam || requestParam.length === 0) { + return { + code: 200, + msg: 'Invild params' + } + } + + // 日志填充 + const sessionParams = [] + const pageParams = [] + const eventParams = [] + const errorParams = [] + const device = new Device() + for (const ri in requestParam) { + //参数解析 + const urlParams = parseUrlParams(requestParam[ri], context) + if (!urlParams.ak) { + return { + code: 201, + msg: 'Not found appid' + } + } + + if (!urlParams.lt) { + return { + code: 202, + msg: 'Not found this log type' + } + } + + switch (parseInt(urlParams.lt)) { + // 会话日志 + case 1: { + sessionParams.push(urlParams) + break + } + // 页面日志 + case 3: + case 11: { + pageParams.push(urlParams) + break + } + // 事件日志 + case 21: { + eventParams.push(urlParams) + break + } + // 错误日志 + case 31: { + errorParams.push(urlParams) + break + } + //unipush信息绑定 + case 101: { + res = await device.bindPush(urlParams) + break + } + default: { + console.log('Invalid type by param "lt:' + urlParams.lt + '"') + break + } + } + } + + //会话日志填充 + if (sessionParams.length > 0) { + const sessionLog = new SessionLog() + res = await sessionLog.batchFill(sessionParams) + } + + //页面日志填充 + if (pageParams.length > 0) { + const pageLog = new PageLog() + res = await pageLog.fill(pageParams) + } + + //事件日志填充 + if (eventParams.length > 0) { + const eventLog = new EventLog() + res = await eventLog.fill(eventParams) + } + + //错误日志填充 + if (errorParams.length > 0) { + const errorLog = new ErrorLog() + res = await errorLog.fill(errorParams) + } + + return res + } +} + +module.exports = UniStatReportDataReceiver diff --git a/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/stat.js b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/stat.js new file mode 100644 index 0000000..93fc433 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/stat.js @@ -0,0 +1,388 @@ +/** + * @class UniStatDataStat uni统计-数据统计调度处理模块 + * @function cron 数据统计定时任务处理函数 + * @function stat 数据统计调度处理函数 + * @function cleanLog 日志清理调度处理函数 + */ +const { + DateTime +} = require('./lib') + +const { + sleep +} = require('../shared') + +const { + BaseMod, + SessionLog, + PageLog, + EventLog, + ShareLog, + ErrorLog, + StatResult, + ActiveDevices, + ActiveUsers, + PageResult, + EventResult, + ErrorResult, + Loyalty, + RunErrors, + UserSessionLog, + uniPay, + Setting +} = require('./mod') +class UniStatDataStat { + /** + * 数据统计定时任务处理函数 + * @param {Object} context 服务器请求上下文参数 + */ + async cron(context) { + const baseMod = new BaseMod() + const dateTime = new DateTime() + console.log('Cron start time: ', dateTime.getDate('Y-m-d H:i:s')) + + // const setting = new Setting(); + // let settingValue = await setting.getSetting() + // if (settingValue.mode === "close") { + // // 如果关闭了统计任务,则任务直接结束 + // return { + // code: 0, + // msg: 'Task is close', + // } + // } else if (settingValue.mode === "auto") { + // // 如果开启了节能模式,则判断N天内是否有设备访问记录 + // let runKey = await setting.checkAutoRun(settingValue); + // if (!runKey) { + // return { + // code: 0, + // msg: 'Task is auto close', + // } + // } + // } + + //获取运行参数 + const timeInfo = dateTime.getTimeInfo(null, false) + const cronConfig = baseMod.getConfig('cron') + const cronMin = baseMod.getConfig('cronMin') + const realtimeStat = baseMod.getConfig('realtimeStat') + // 数据跑批 + let res = null + if (cronConfig && cronConfig.length > 0) { + for (var mi in cronConfig) { + const currCronConfig = cronConfig[mi] + const cronType = currCronConfig.type + const cronTime = currCronConfig.time.split(' ') + const cronDimension = currCronConfig.dimension + + //未开启分钟级定时任务,则设置为小时级定时任务 + if (cronTime.length === 4 && !cronMin) { + cronTime.splice(3, 1) + } + + if (baseMod.debug) { + console.log('cronTime', cronTime) + } + //精度为分钟级的定时任务 + if (cronTime.length === 4) { + if (cronTime[0] !== '*') { + //周统计任务 + if (timeInfo.nWeek == cronTime[0] && timeInfo.nHour == cronTime[2] && timeInfo.nMinutes == + cronTime[3]) { + let dimension = cronDimension || 'week'; + console.log(cronType + `--${dimension} run`) + res = await this.stat({ + type: cronType, + dimension: cronDimension, + config: currCronConfig + }) + } + } else if (cronTime[1] !== '*') { + //月统计任务(包含季度统计任务和年统计任务) + if (timeInfo.nDay == cronTime[1] && timeInfo.nHour == cronTime[2] && timeInfo.nMinutes == + cronTime[3]) { + let dimension = cronDimension || 'month'; + console.log(cronType + `--${dimension} run`) + res = await this.stat({ + type: cronType, + dimension: dimension, + config: currCronConfig + }) + } + } else if (cronTime[2] !== '*') { + //日统计任务 + if (timeInfo.nHour == cronTime[2] && timeInfo.nMinutes == cronTime[3]) { + let dimension = cronDimension || 'day'; + console.log(cronType + `--${dimension} run`) + res = await this.stat({ + type: cronType, + dimension: dimension, + config: currCronConfig + }) + } + } else if (cronTime[3] !== '*') { + //实时统计任务 + if (timeInfo.nMinutes == cronTime[3] && realtimeStat) { + let dimension = cronDimension || 'hour'; + console.log(cronType + `--${dimension} run`) + res = await this.stat({ + type: cronType, + dimension: dimension, + config: currCronConfig + }) + } + } + } + //精度为小时级的定时任务 + else if (cronTime.length === 3) { + if (cronTime[0] !== '*') { + //周统计任务 + if (timeInfo.nWeek == cronTime[0] && timeInfo.nHour == cronTime[2]) { + let dimension = cronDimension || 'week'; + console.log(cronType + `--${dimension} run`) + res = await this.stat({ + type: cronType, + dimension: dimension, + config: currCronConfig + }) + } + } else if (cronTime[1] !== '*') { + //月统计任务(包含季度统计任务和年统计任务) + if (timeInfo.nDay == cronTime[1] && timeInfo.nHour == cronTime[2]) { + let dimension = cronDimension || 'month'; + console.log(cronType + `--${dimension} run`) + res = await this.stat({ + type: cronType, + dimension: dimension, + config: currCronConfig + }) + } + } else if (cronTime[2] !== '*') { + //日统计任务 + if (timeInfo.nHour == cronTime[2]) { + let dimension = cronDimension || 'day'; + console.log(cronType + `--${dimension} run`) + res = await this.stat({ + type: cronType, + dimension: dimension, + config: currCronConfig + }) + } + } else { + //实时统计任务 + if (realtimeStat) { + let dimension = cronDimension || 'hour'; + console.log(cronType + `--${dimension} run`) + res = await this.stat({ + type: cronType, + dimension: dimension, + config: currCronConfig + }) + } + } + } else { + console.error('Cron configuration error') + } + } + } + console.log('Cron end time: ', dateTime.getDate('Y-m-d H:i:s')) + return { + code: 0, + msg: 'Task have done', + lastCronResult: res + } + } + + /** + * 数据统计调度处理函数 + * @param {Object} params 统计参数 + */ + async stat(params) { + const { + type, + dimension, + date, + reset, + config + } = params + let res = { + code: 0, + msg: 'success' + } + + try { + switch (type) { + // 基础统计 + case 'stat': { + const resultStat = new StatResult() + res = await resultStat.stat(dimension, date, reset) + break + } + // 活跃设备统计归集 + case 'active-device': { + const activeDevices = new ActiveDevices() + res = await activeDevices.stat(date, reset) + break + } + // 活跃用户统计归集 + case 'active-user': { + const activeUsers = new ActiveUsers() + res = await activeUsers.stat(date, reset) + break + } + // 设备留存统计 + case 'retention-device': { + const retentionStat = new StatResult() + res = await retentionStat.retentionStat(dimension, date) + break + } + // 用户留存统计 + case 'retention-user': { + const retentionStat = new StatResult() + res = await retentionStat.retentionStat(dimension, date, 'user') + break + } + // 页面统计 + case 'page': { + const pageStat = new PageResult() + res = await pageStat.stat(dimension, date, reset) + break + } + // 事件统计 + case 'event': { + const eventStat = new EventResult() + res = await eventStat.stat(dimension, date, reset) + break + } + // 错误统计 + case 'error': { + const errorStat = new ErrorResult() + res = await errorStat.stat(dimension, date, reset) + break + } + // 设备忠诚度统计 + case 'loyalty': { + const loyaltyStat = new Loyalty() + res = await loyaltyStat.stat(dimension, date, reset) + break + } + // 日志清理 + case 'clean': { + res = await this.cleanLog() + } + // 支付统计 + case 'pay-result': { + const paymentResult = new uniPay.PayResult() + res = await paymentResult.stat(dimension, date, reset, config) + break + } + } + } catch (e) { + const maxTryTimes = 2 + if (!this.tryTimes) { + this.tryTimes = 1 + } else { + this.tryTimes++ + } + + //报错则重新尝试2次, 解决部分云服务器偶现连接超时问题 + if (this.tryTimes <= maxTryTimes) { + //休眠1秒后重新调用 + await sleep(1000) + params.reset = true + res = await this.stat(params) + } else { + // 2次尝试失败后记录错误 + console.error('server error: ' + e) + const runError = new RunErrors() + runError.create({ + mod: 'stat', + params: params, + error: e, + create_time: new DateTime().getTime() + }) + + res = { + code: 500, + msg: 'server error' + e + } + } + } + return res + } + + /** + * 日志清理调度处理函数 + */ + async cleanLog() { + const baseMod = new BaseMod() + const cleanLog = baseMod.getConfig('cleanLog') + if (!cleanLog || !cleanLog.open) { + return { + code: 100, + msg: 'The log cleanup service has not been turned on' + } + } + + const res = { + code: 0, + msg: 'success', + data: {} + } + + // 会话日志 + if (cleanLog.reserveDays.sessionLog > 0) { + const sessionLog = new SessionLog() + res.data.sessionLog = await sessionLog.clean(cleanLog.reserveDays.sessionLog) + } + + // 用户会话日志 + if (cleanLog.reserveDays.userSessionLog > 0) { + const userSessionLog = new UserSessionLog() + res.data.userSessionLog = await userSessionLog.clean(cleanLog.reserveDays.userSessionLog) + } + + // 页面日志 + if (cleanLog.reserveDays.pageLog > 0) { + const pageLog = new PageLog() + res.data.pageLog = await pageLog.clean(cleanLog.reserveDays.pageLog) + } + + // 事件日志 + if (cleanLog.reserveDays.eventLog > 0) { + const eventLog = new EventLog() + res.data.eventLog = await eventLog.clean(cleanLog.reserveDays.eventLog) + } + + // 分享日志 + if (cleanLog.reserveDays.shareLog > 0) { + const shareLog = new ShareLog() + res.data.shareLog = await shareLog.clean(cleanLog.reserveDays.shareLog) + } + + // 错误日志 + if (cleanLog.reserveDays.errorLog > 0) { + const errorLog = new ErrorLog() + res.data.errorLog = await errorLog.clean(cleanLog.reserveDays.errorLog) + } + + // 活跃设备日志 + const activeDevicesLog = new ActiveDevices() + res.data.activeDevicesLog = await activeDevicesLog.clean() + + // 活跃用户日志 + const activeUsersLog = new ActiveUsers() + res.data.activeUsersLog = await activeUsersLog.clean() + + // 实时统计日志 + const resultHourLog = new StatResult() + res.data.resultHourLog = await resultHourLog.cleanHourLog() + + //原生应用崩溃日志 + const appCrashLogs = new AppCrashLogs() + res.data.appCrashLogs = await appCrashLogs.clean() + + return res + } +} + +module.exports = UniStatDataStat diff --git a/uniCloud-aliyun/cloudfunctions/uni-analyse-searchhot/index.js b/uniCloud-aliyun/cloudfunctions/uni-analyse-searchhot/index.js new file mode 100644 index 0000000..1f16dc2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-analyse-searchhot/index.js @@ -0,0 +1,49 @@ +'use strict'; +exports.main = async (event, context) => { + /** + * 根据搜索记录,设定时间间隔来归纳出热搜数据并存储在热搜表中 + */ + const SEARCHHOT = 'opendb-search-hot'; // 热搜数据库名称 + const SEARCHLOG = 'opendb-search-log'; // 搜索记录数据库名称 + const SEARCHLOG_timeZone = 604800000; // 归纳搜索记录时间间隔,毫秒数,默认为最近7天 + const SEARCHHOT_size = 10; // 热搜条数 + + const DB = uniCloud.database(); + const DBCmd = DB.command; + const $ = DB.command.aggregate; + const SEARCHHOT_db = DB.collection(SEARCHHOT); + const SEARCHLOG_db = DB.collection(SEARCHLOG); + const timeEnd = Date.now() - SEARCHLOG_timeZone; + + let { + data: searchHotData + } = await SEARCHLOG_db + .aggregate() + .match({ + create_date: DBCmd.gt(timeEnd) + }) + .group({ + _id: { + 'content': '$content', + }, + count: $.sum(1) + }) + .replaceRoot({ + newRoot: $.mergeObjects(['$_id', '$$ROOT']) + }) + .project({ + _id: false + }) + .sort({ + count: -1 + }) + .end(); + + let now = Date.now(); + searchHotData.map(item => { + item.create_date = now; + return item; + }).slice(0, SEARCHHOT_size); + // searchHotData = searchHotData.sort((a, b) => b.count - a.count).slice(0, SEARCHHOT_size); + return searchHotData.length ? await SEARCHHOT_db.add(searchHotData) : '' +}; diff --git a/uniCloud-aliyun/cloudfunctions/uni-analyse-searchhot/package.json b/uniCloud-aliyun/cloudfunctions/uni-analyse-searchhot/package.json new file mode 100644 index 0000000..6005add --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-analyse-searchhot/package.json @@ -0,0 +1,14 @@ +{ + "name": "uni-analyse-searchhot", + "version": "1.0.0", + "description": "定时归纳热搜", + "main": "index.js", + "dependencies": {}, + "cloudfunction-config": { + "triggers": [{ + "name": "analyse-searchHot", + "type": "timer", + "config": "0 0 */2 * * * *" + }] + } +} diff --git a/uniCloud-aliyun/cloudfunctions/uni-portal/createPublishHtml/index.js b/uniCloud-aliyun/cloudfunctions/uni-portal/createPublishHtml/index.js new file mode 100644 index 0000000..4a0c31c --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-portal/createPublishHtml/index.js @@ -0,0 +1,188 @@ +const fs = require('fs') +const path = require('path') +const TE = require('./lib/art-template.js'); + +// 标准语法的界定符规则 +TE.defaults.openTag = '{@' +TE.defaults.closeTag = '@}' + +const success = { + success: true +} +const fail = { + 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) +} + +module.exports = async function(id) { + if (!id) { + return { + ...fail, + code: -1, + errMsg: 'id required' + }; + } + + // 根据sitemap配置加载页面模板,例如列表页,详情页 + let templatePage = fs.readFileSync(path.resolve(__dirname, './template.html'), 'utf8'); + if (!templatePage) { + return { + ...fail, + code: -2, + errMsg: 'page template no found' + }; + } + + const db = uniCloud.database() + let dbPublishList + try { + dbPublishList = db.collection('opendb-app-list') + } catch (e) {} + + if (!dbPublishList) return fail; + + const record = await dbPublishList.where({ + _id: id + }).get({ + getOne: true + }) + + if (record && record.data && record.data.length) { + const appInfo = record.data[0] + + 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]) + }) + } + + 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/uni-portal/createPublishHtml/lib/art-template.js b/uniCloud-aliyun/cloudfunctions/uni-portal/createPublishHtml/lib/art-template.js new file mode 100644 index 0000000..b292990 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-portal/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/uni-portal/createPublishHtml/template.html b/uniCloud-aliyun/cloudfunctions/uni-portal/createPublishHtml/template.html new file mode 100644 index 0000000..22d699d --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-portal/createPublishHtml/template.html @@ -0,0 +1,238 @@ + + + + + + + + + {@name@} + + + +

+ + + + + \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/uni-portal/index.js b/uniCloud-aliyun/cloudfunctions/uni-portal/index.js new file mode 100644 index 0000000..f45fb9c --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-portal/index.js @@ -0,0 +1,25 @@ +'use strict'; +const success = { + success: true +} +const fail = { + success: false +} +const createPublishHtml = require('./createPublishHtml') + +exports.main = async (event, context) => { + //event为客户端上传的参数 + console.log('event : ', event) + + let res = {}; + let params = event.data || event.params; + + switch (event.action) { + case 'createPublishHtml': + res = createPublishHtml(params.id) + break; + } + + //返回数据给客户端 + return res +}; diff --git a/uniCloud-aliyun/cloudfunctions/uni-portal/package.json b/uniCloud-aliyun/cloudfunctions/uni-portal/package.json new file mode 100644 index 0000000..354f947 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-portal/package.json @@ -0,0 +1,7 @@ +{ + "name": "uni-portal", + "dependencies": {}, + "extensions": { + "uni-cloud-jql": {} + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/uni-sms-co/build-template-data.js b/uniCloud-aliyun/cloudfunctions/uni-sms-co/build-template-data.js new file mode 100644 index 0000000..0057d40 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-sms-co/build-template-data.js @@ -0,0 +1,26 @@ +module.exports = (templateData, user) => { + const data = {} + for (const template of templateData) { + const isDynamic = /\{.*?\}/.test(template.value) + + // 仅支持uni-id-users + if (isDynamic) { + const [collection, field] = template.value.replace(/\{|\}/g, '').split('.') + data[template.field] = collection === 'uni-id-users' ? user[field] || template.value: template.value + } else { + data[template.field] = template.value + } + // switch (template.type) { + // case 'static': + // data[template.field] = template.value + // break + // case 'dynamic': + // data[template.field] = user[template.value] || '' + // break + // default: + // throw new Error(`template type [${template.type}] not supported`) + // } + } + + return data +} diff --git a/uniCloud-aliyun/cloudfunctions/uni-sms-co/index.obj.js b/uniCloud-aliyun/cloudfunctions/uni-sms-co/index.obj.js new file mode 100644 index 0000000..ba57c66 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-sms-co/index.obj.js @@ -0,0 +1,374 @@ +// 云对象教程: https://uniapp.dcloud.net.cn/uniCloud/cloud-obj +// jsdoc语法提示教程:https://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/129 +const createConfig = require('uni-config-center') +const buildTemplateData = require('./build-template-data') +const { parserDynamicField, checkIsStaticTemplate } = require('./utils') +const schemaNameAdapter = require('./schema-name-adapter') + +const uniSmsCo = uniCloud.importObject('uni-sms-co') +const db = uniCloud.database() +const smsConfig = createConfig({ + pluginId: 'uni-sms-co' +}).config() + +function errCode(code) { + return 'uni-sms-co-' + code +} + +const tableNames = { + template: 'opendb-sms-template', + task: 'opendb-sms-task', + log: 'opendb-sms-log' +} + +module.exports = { + _before: async function () { // 通用预处理器 + if (!smsConfig.smsKey || smsConfig.smsKey.length <= 20 || !smsConfig.smsSecret || smsConfig.smsSecret.length <= 20) { + throw new Error('请先配置smsKey和smsSecret') + } + + this.tableNames = tableNames + + /** + * 优化 schema 的命名规范,需要兼容 uni-admin@2.1.6 以下版本 + * 如果是在uni-admin@2.1.6版本以上创建的项目可以将其注释 + * */ + await schemaNameAdapter.call(this) + }, + _after: function (error, result) { + if (error) { + if (error instanceof Error) { + return { + errCode: 'error', + errMsg: error.message + } + } + + if (error.errCode) { + return error + } + + throw error + } + + return result + }, + /** + * 创建短信任务 + * @param {Object} to + * @param {Boolean} to.all=false 全部用户发送 + * @param {String} to.type=user to.all=true时用来区分发送类型 + * @param {Array} to.receiver 用户ID's / 用户标签ID's + * @param {String} templateId 短信模板ID + * @param {Array} templateData 短信模板数据 + * @param {String} options.taskName 任务名称 + */ + async createSmsTask(to, templateId, templateData, options = {}) { + if (!templateId) { + return { + errCode: errCode('template-id-required'), + errMsg: '缺少templateId' + } + } + + if (!to.all && (!to.receiver || to.receiver.length <= 0)) { + return { + errCode: errCode('send-users-is-null'), + errMsg: '请选择要发送的用户' + } + } + + const clientInfo = this.getClientInfo() + + const {data: templates} = await db.collection(this.tableNames.template).where({_id: templateId}).get() + if (templates.length <= 0) { + return { + errCode: errCode('template-not-found'), + errMsg: '短信模板不存在' + } + } + const [template] = templates + + // 创建短信任务 + const task = await db.collection(this.tableNames.task).add({ + app_id: clientInfo.appId, + name: options.taskName, + template_id: templateId, + template_contnet: template.content, + vars: templateData, + to, + send_qty: 0, + success_qty: 0, + fail_qty: 0, + create_date: Date.now() + }) + + uniSmsCo.createUserSmsMessage(task.id) + + return new Promise(resolve => setTimeout(() => resolve({ + errCode: 0, + errMsg: '任务创建成功', + taskId: task.id + }), 300)) + }, + async createUserSmsMessage(taskId, execData = {}) { + const parallel = 100 + let beforeId + const { data: tasks } = await db.collection(this.tableNames.task).where({ _id: taskId }).get() + + if (tasks.length <= 0) { + return { + errCode: errCode('task-id-not-found'), + errMsg: '任务ID不存在' + } + } + + const [task] = tasks + const query = { + mobile: db.command.exists(true) + } + + // 指定用户发送 + if (!task.to.all && task.to.type === 'user') { + let index = 0 + if (execData.beforeId) { + const i = task.to.receiver.findIndex(id => id === execData.beforeId) + index = i !== -1 ? i + 1 : 0 + } + + const receiver = task.to.receiver.slice(index, index + parallel) + query._id = db.command.in(receiver) + beforeId = receiver[receiver.length - 1] + } + + // 指定用户标签 + if (task.to.type === 'userTags') { + query.tags = db.command.in(task.to.receiver) + } + + // 全部用户 + if (task.to.all && execData.beforeId) { + query._id = db.command.gt(execData.beforeId) + } + + // 动态数据仅支持uni-id-users表字段 + const dynamicField = parserDynamicField(task.vars) + const userFields = dynamicField['uni-id-users'] ? dynamicField['uni-id-users'].reduce((res, field) => { + res[field] = true + return res + }, {}): {} + const { data: users } = await db.collection('uni-id-users') + .where(query) + .field({ + mobile: true, + ...userFields + }) + .limit(parallel) + .orderBy('_id', 'asc') + .get() + + if (users.length <= 0) { + // 更新要发送的短信数量 + const count = await db.collection(this.tableNames.log).where({ task_id: taskId }).count() + await db.collection(this.tableNames.task).where({ _id: taskId }).update({ + send_qty: count.total + }) + + // 开始发送 + uniSmsCo.sendSms(taskId) + + return new Promise(resolve => setTimeout(() => resolve({ + errCode: 0, + errMsg: '创建完成' + }), 500)) + } + + if (!beforeId) { + beforeId = users[users.length - 1]._id + } + + let docs = [] + for (const user of users) { + const varData = await buildTemplateData(task.vars, user) + docs.push({ + uid: user._id, + task_id: taskId, + mobile: user.mobile, + var_data: varData, + status: 0, + create_date: Date.now() + }) + } + + await db.collection(this.tableNames.log).add(docs) + + uniSmsCo.createUserSmsMessage(taskId, { beforeId }) + + return new Promise(resolve => setTimeout(() => resolve(), 500)) + }, + async sendSms(taskId) { + const { data: tasks } = await db.collection(this.tableNames.task).where({ _id: taskId }).get() + if (tasks.length <= 0) { + console.warn(`task [${taskId}] not found`) + return + } + + const [task] = tasks + const isStaticTemplate = !task.vars.length + + let sendData = { + appId: task.app_id, + smsKey: smsConfig.smsKey, + smsSecret: smsConfig.smsSecret, + templateId: task.template_id, + data: {} + } + + const { data: records } = await db.collection(this.tableNames.log) + .where({ task_id: taskId, status: 0 }) + .limit(isStaticTemplate ? 50 : 1) + .field({ mobile: true, var_data: true }) + .get() + + if (records.length <= 0) { + return { + errCode: 0, + errMsg: '发送完成' + } + } + + if (isStaticTemplate) { + sendData.phoneList = records.reduce((res, user) => { + res.push(user.mobile) + return res + }, []) + } else { + const [record] = records + sendData.phone = record.mobile + sendData.data = record.var_data + } + + try { + // await sendSms(sendData) + await uniCloud.sendSms(sendData) + // 修改发送状态为已发送 + await db.collection(this.tableNames.log).where({ + _id: db.command.in(records.map(record => record._id)) + }).update({ + status: 1, + send_date: Date.now() + }) + // 更新任务的短信成功数 + await db.collection(this.tableNames.task).where({ _id: taskId }) + .update({ + success_qty: db.command.inc(records.length) + }) + } catch (e) { + console.error('[sendSms Fail]', e) + // 修改发送状态为发送失败 + await db.collection(this.tableNames.log).where({ + _id: db.command.in(records.map(record => record._id)) + }).update({ + status: 2, + reason: e.errMsg || '未知原因', + send_date: Date.now() + }) + // 更新任务的短信失败数 + await db.collection(this.tableNames.task).where({ _id: taskId }) + .update({ + fail_qty: db.command.inc(records.length) + }) + } + + uniSmsCo.sendSms(taskId) + + return new Promise(resolve => setTimeout(() => resolve(), 500)) + }, + async template() { + const {data: templates = []} = await db.collection(this.tableNames.template).get() + return templates + }, + async task (id) { + const {data: tasks} = await db.collection(this.tableNames.task).where({_id: id}).get() + if (tasks.length <= 0) { + return null + } + + return tasks[0] + }, + async updateTemplates (templates) { + if (templates.length <= 0) { + return { + errCode: errCode('template-is-null'), + errMsg: '缺少模板信息' + } + } + + let group = [] + for (const template of templates) { + group.push( + db.collection(this.tableNames.template).doc(String(template.templateId)).set({ + name: template.templateName, + content: template.templateContent, + type: template.templateType, + sign: template.templateSign + }) + ) + } + + await Promise.all(group) + + return { + errCode: 0, + errMsg: '更新成功' + } + }, + async preview (to, templateId, templateData) { + const count = 1 + let query = { + mobile: db.command.exists(true) + } + + // 指定用户发送 + if (!to.all && to.type === 'user') { + const receiver = to.receiver.slice(0, 10) + query._id = db.command.in(receiver) + } + + // 指定用户标签 + if (to.type === 'userTags') { + query.tags = db.command.in(to.receiver) + } + + const {data: users} = await db.collection('uni-id-users').where(query).limit(count).get() + console.log({users, query}) + if (users.length <= 0) { + return { + errCode: errCode('users-is-null'), + errMsg: '请添加要发送的用户' + } + } + + const {data: templates} = await db.collection(this.tableNames.template).where({_id: templateId}).get() + if (templates.length <= 0) { + return { + errCode: errCode('template-not-found'), + errMsg: '模板不存在' + } + } + const [template] = templates + + let docs = [] + for (const user of users) { + const varData = buildTemplateData(templateData, user) + const content = template.content.replace(/\$\{(.*?)\}/g, ($1, param) => varData[param] || $1) + docs.push(`【${template.sign}】${content}`) + } + + return { + errCode: 0, + errMsg: '', + list: docs + } + } +} diff --git a/uniCloud-aliyun/cloudfunctions/uni-sms-co/package.json b/uniCloud-aliyun/cloudfunctions/uni-sms-co/package.json new file mode 100644 index 0000000..f989531 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-sms-co/package.json @@ -0,0 +1,10 @@ +{ + "name": "uni-sms-co", + "dependencies": { + "uni-config-center": "file:../../../uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + }, + "extensions": { + "uni-cloud-sms": {}, + "uni-cloud-jql": {} + } +} diff --git a/uniCloud-aliyun/cloudfunctions/uni-sms-co/schema-name-adapter.js b/uniCloud-aliyun/cloudfunctions/uni-sms-co/schema-name-adapter.js new file mode 100644 index 0000000..cf00293 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-sms-co/schema-name-adapter.js @@ -0,0 +1,15 @@ +const db = uniCloud.database() + +module.exports = async function () { + try { + const count = await db.collection('batch-sms-template').count() + + if (count.total > 0) { + this.tableNames = { + template: 'batch-sms-template', + task: 'batch-sms-task', + log: 'batch-sms-result' + } + } + } catch (e) {} +} diff --git a/uniCloud-aliyun/cloudfunctions/uni-sms-co/utils.js b/uniCloud-aliyun/cloudfunctions/uni-sms-co/utils.js new file mode 100644 index 0000000..edf34b8 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-sms-co/utils.js @@ -0,0 +1,42 @@ +exports.chunk = function (arr, num) { + const list = [] + let current = [] + + for (const item of arr) { + current.push(item); + if (current.length === num) { + list.push(current) + current = [] + } + } + + if (current.length) list.push(current) + + return list +} + +exports.checkIsStaticTemplate = function (data = []) { + let isStatic = data.length <= 0 + + for (const template of data) { + if (template.type === 'static') { + isStatic = true + break + } + } + + return isStatic +} + +exports.parserDynamicField = function (templateData) { + return templateData.reduce((res, template) => { + if (/\{.*?\}/.test(template.value)) { + const [collection, field] = template.value.replace(/\{|\}/g, '').split('.') + if (!res[collection]) { + res[collection] = [] + } + res[collection].push(field) + } + return res + }, {}) +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/uni-stat-cron/index.js b/uniCloud-aliyun/cloudfunctions/uni-stat-cron/index.js new file mode 100644 index 0000000..685c330 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-stat-cron/index.js @@ -0,0 +1,6 @@ +'use strict'; +const uniStat = require('uni-stat') +exports.main = async (event, context) => { + //数据跑批处理函数 + return await uniStat.initStat().cron(context) +}; diff --git a/uniCloud-aliyun/cloudfunctions/uni-stat-cron/package.json b/uniCloud-aliyun/cloudfunctions/uni-stat-cron/package.json new file mode 100644 index 0000000..f8b0486 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-stat-cron/package.json @@ -0,0 +1,27 @@ +{ + "name": "uni-stat-cron", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "uni-stat": "file:../common/uni-stat" + }, + "cloudfunction-config": { + "concurrency": 1, + "memorySize": 512, + "timeout": 600, + "triggers": [ + { + "name": "uni-stat-cron", + "type": "timer", + "config": "0 0 * * * * *" + } + ] + }, + "extensions": {} +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/uni-stat-receiver/index.obj.js b/uniCloud-aliyun/cloudfunctions/uni-stat-receiver/index.obj.js new file mode 100644 index 0000000..dac8354 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-stat-receiver/index.obj.js @@ -0,0 +1,29 @@ +const uniStat = require('uni-stat') +const uniID = require('uni-id-common') +module.exports = { + report: async function (params = {}) { + //客户端信息 + const clientInfo = this.getClientInfo() + //云服务信息 + const cloudInfo = this.getCloudInfo() + //token信息 + const token = this.getUniIdToken() + //当前登录用户id + let uid + if(token) { + const tokenRes = await uniID.createInstance({ + clientInfo + }).checkToken(token) + + if(tokenRes.uid) { + uid = tokenRes.uid + } + } + //数据上报 + return await uniStat.initReceiver().report(params, { + ...clientInfo, + ...cloudInfo, + uid + }) + } +} diff --git a/uniCloud-aliyun/cloudfunctions/uni-stat-receiver/package.json b/uniCloud-aliyun/cloudfunctions/uni-stat-receiver/package.json new file mode 100644 index 0000000..2535f17 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-stat-receiver/package.json @@ -0,0 +1,16 @@ +{ + "name": "uni-stat-receiver", + "dependencies": { + "uni-stat": "file:../common/uni-stat", + "uni-id-common": "file:../../../uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common" + }, + "cloudfunction-config": { + "concurrency": 1, + "memorySize": 128, + "timeout": 60, + "triggers": [] + }, + "extensions": { + "uni-cloud-jql": {} + } +} diff --git a/uniCloud-aliyun/cloudfunctions/uni-upgrade-center/checkVersion/index.js b/uniCloud-aliyun/cloudfunctions/uni-upgrade-center/checkVersion/index.js new file mode 100644 index 0000000..e38892c --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-upgrade-center/checkVersion/index.js @@ -0,0 +1,167 @@ +'use strict'; +module.exports = async (event, context) => { + /** + * 检测升级 使用说明 + * 上传包: + * 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, + } = event; + + 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' + + let platform = platform_Android; + + // 云函数URL化请求 + if (event.headers) { + let body; + try { + if (event.httpMethod.toLocaleLowerCase() === 'get') { + body = event.queryStringParameters; + } else { + body = JSON.parse(event.body); + } + } catch (e) { + return { + code: 500, + msg: '请求错误' + }; + } + + appid = body.appid; + appVersion = body.appVersion; + wgtVersion = body.wgtVersion; + + platform = /iPhone|iPad/.test(event.headers) ? platform_iOS : platform_Android; + } else if (context.OS) { + platform = context.OS === 'android' ? + platform_Android : + context.OS === 'ios' ? + platform_iOS : + platform_Android; + } + + if (appid && appVersion && wgtVersion && platform) { + const collection = uniCloud.database().collection(app_version_db_name); + + const record = await collection.where({ + appid, + platform, + stable_publish: true + }) + .orderBy('create_date', 'desc') + .get(); + + if (record && record.data && record.data.length > 0) { + const appVersionInDb = record.data.find(item => item.type === package_app) || {}; + const wgtVersionInDb = record.data.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, + message: 'wgt更新', + ...stablePublishDb + }; + } else if (hasAppPackage && compare(appVersionInDb.version, appVersion) === 1) { + return { + code: 102, + message: '整包更新', + ...appVersionInDb + }; + } + } + + return { + code: 0, + message: '当前版本已经是最新的,不需要更新' + }; + } + + return { + code: -101, + message: '暂无更新或检查appid是否填写正确' + }; + } + + return { + code: -102, + message: '请检查传参是否填写正确' + }; +}; + +/** + * 对比版本号,如需要,请自行修改判断规则 + * 支持比对 ("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/uni-upgrade-center/index.js b/uniCloud-aliyun/cloudfunctions/uni-upgrade-center/index.js new file mode 100644 index 0000000..7fbaae8 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-upgrade-center/index.js @@ -0,0 +1,91 @@ +'use strict'; +const success = { + success: true +} +const fail = { + success: false +} +const checkVersion = require('./checkVersion') + +exports.main = async (event, context) => { + //event为客户端上传的参数 + + const db = uniCloud.database() + const appListDBName = 'opendb-app-list' + const appVersionDBName = 'opendb-app-versions' + let res = {}; + + if (event.headers) { + try { + if (event.httpMethod.toLocaleLowerCase() === 'get') { + event = event.queryStringParameters; + } else { + event = JSON.parse(event.body); + } + } catch (e) { + return { + code: 500, + msg: '请求错误' + }; + } + } + + let params = event.data || event.params; + switch (event.action) { + case 'checkVersion': + res = await checkVersion(event, context) + break; + case 'deleteFile': + res = await uniCloud.deleteFile({ + fileList: params.fileList + }) + break; + case 'setNewAppData': + params.value.create_date = Date.now() + res = await db.collection(appListDBName).doc(params.id).set(params.value) + break; + case 'getAppInfo': + let dbAppList + try { + dbAppList = db.collection(appListDBName) + } catch (e) {} + + if (!dbAppList) return fail; + + const dbAppListRecord = await dbAppList.where({ + appid: params.appid + }).get() + + if (dbAppListRecord && dbAppListRecord.data.length) + return Object.assign({}, success, dbAppListRecord.data[0]) + + //返回数据给客户端 + return fail + break; + case 'getAppVersionInfo': + let dbVersionList + try { + dbVersionList = db.collection(appVersionDBName) + } catch (e) {} + + if (!dbVersionList) return fail; + + const dbVersionListrecord = await dbVersionList.where({ + appid: params.appid, + platform: params.platform, + type: "native_app", + stable_publish: true + }) + .orderBy('create_date', 'desc') + .get(); + + if (dbVersionListrecord && dbVersionListrecord.data && dbVersionListrecord.data.length > 0) + return Object.assign({}, dbVersionListrecord.data[0], success) + + return fail + break; + } + + //返回数据给客户端 + return res +}; diff --git a/uniCloud-aliyun/cloudfunctions/uni-upgrade-center/package.json b/uniCloud-aliyun/cloudfunctions/uni-upgrade-center/package.json new file mode 100644 index 0000000..ae7bc6c --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-upgrade-center/package.json @@ -0,0 +1,7 @@ +{ + "name": "uni-app-manager", + "dependencies": {}, + "extensions": { + "uni-cloud-jql": {} + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/uni-upgrade-center/uni-app-manager.param.json b/uniCloud-aliyun/cloudfunctions/uni-upgrade-center/uni-app-manager.param.json new file mode 100644 index 0000000..5a6c42e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/uni-upgrade-center/uni-app-manager.param.json @@ -0,0 +1,10 @@ +// 本文件中的json内容将在云函数【运行】时作为参数传给云函数。 + +// 配置教程参考:https://uniapp.dcloud.net.cn/uniCloud/quickstart?id=runparam + +{ + "action": "checkVersion", + "appid": "__UNI__ED84AD5", + "appVersion": "1.0.0", + "wgtVersion": "1.0.0" +} diff --git a/uniCloud-aliyun/cloudfunctions/wxpay-virtual-co/index.obj.js b/uniCloud-aliyun/cloudfunctions/wxpay-virtual-co/index.obj.js new file mode 100644 index 0000000..1af2d7e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/wxpay-virtual-co/index.obj.js @@ -0,0 +1,122 @@ +/** + * 此云对象是演示如何调用微信虚拟支付其他API + * 通过 const uniPayCo = uniCloud.importObject("uni-pay-co"); 获取云对象 + * 再通过 uniPayCo.requestWxpayVirtualApi 调用微信虚拟支付API + */ + +module.exports = { + _before: function() { + + }, + /** + * 查询用户代币余额 + * @param {string} openid - 用户openid + */ + async queryUserBalance(data) { + let { + openid + } = data; + let userIp = this.getClientInfo().clientIP; + const uniPayCo = uniCloud.importObject("uni-pay-co"); + let res = await uniPayCo.requestWxpayVirtualApi({ + method: "queryUserBalance", + data: { + openid, // 用户openid + userIp, // 用户IP + } + }); + return res; + }, + /** + * 扣减用户代币 + * @param {string} openid - 用户openid + */ + async currencyPay(data) { + let { + openid + } = data; + let userIp = this.getClientInfo().clientIP; + let outTradeNo = "test-" + Date.now(); // 商户订单号 + let payitem = JSON.stringify([{ "productid": "test001", "unit_price": 1, "quantity": 1 }]); + let remark = "备注"; + let amount = 1; // 扣减的代币数量 + + const uniPayCo = uniCloud.importObject("uni-pay-co"); + let res = await uniPayCo.requestWxpayVirtualApi({ + method: "currencyPay", + data: { + openid, // 用户openid + userIp, // 用户IP + amount, // 扣减的代币数量 + outTradeNo, // 商户订单号 + payitem, + remark, + deviceType: 1, // 平台类型1-安卓 仅支持传1 + } + }); + res.amount = amount; + return res; + }, + // // 打开下方注释可体验 撤回的扣减用户代币、赠送用户代币 + + /** + * 撤回的扣减用户代币 + * @param {string} openid - 用户openid + */ + async cancelCurrencyPay(data) { + let { + openid, + outTradeNo + } = data; + + let userIp = this.getClientInfo().clientIP; + let amount = 1; // 撤回扣减的代币数量 + + let timestampStr = Date.now().toString(); + let lastFourDigits = timestampStr.substr(-4); + + const uniPayCo = uniCloud.importObject("uni-pay-co"); + let res = await uniPayCo.requestWxpayVirtualApi({ + method: "cancelCurrencyPay", + data: { + openid, // 用户openid + userIp, // 用户IP + amount, // 撤回扣减的代币数量 + outTradeNo, // 商户订单号 + outRefundNo: `${outTradeNo}-${lastFourDigits}`, + deviceType: 1, // 平台类型1-安卓 仅支持传1 + } + }); + + return res; + }, + /** + * 赠送用户代币 + * @param {string} openid - 用户openid + */ + async presentCurrency(data) { + let { + openid + } = data; + + let userIp = this.getClientInfo().clientIP; + let outTradeNo = "test-" + Date.now(); // 商户订单号 + let amount = 1; // 赠送用户代币数量 + + const uniPayCo = uniCloud.importObject("uni-pay-co"); + let res = await uniPayCo.requestWxpayVirtualApi({ + method: "presentCurrency", + data: { + openid, // 用户openid + userIp, // 用户IP + amount, // 赠送用户代币数量 + outTradeNo, // 商户订单号 + deviceType: 1, // 平台类型1-安卓 仅支持传1 + } + }); + + return res; + }, + + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/wxpay-virtual-co/package.json b/uniCloud-aliyun/cloudfunctions/wxpay-virtual-co/package.json new file mode 100644 index 0000000..67c1cd9 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/wxpay-virtual-co/package.json @@ -0,0 +1,5 @@ +{ + "name": "wxpay-virtual-co", + "dependencies": {}, + "extensions": {} +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/wxpay-virtual-co/wxpay-virtual-co.param.js b/uniCloud-aliyun/cloudfunctions/wxpay-virtual-co/wxpay-virtual-co.param.js new file mode 100644 index 0000000..8283271 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/wxpay-virtual-co/wxpay-virtual-co.param.js @@ -0,0 +1,16 @@ +queryUserBalance({ + openid: "oIn_o5cf25LZCFFuuDqTVnvE9NTE" +}); + +// currencyPay({ +// openid: "oIn_o5cf25LZCFFuuDqTVnvE9NTE" +// }) + +// cancelCurrencyPay({ +// openid: "oIn_o5cf25LZCFFuuDqTVnvE9NTE", +// outTradeNo: "test-1710126821756", +// }) + +// presentCurrency({ +// openid: "oIn_o5cf25LZCFFuuDqTVnvE9NTE", +// }) \ No newline at end of file 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..652864e --- /dev/null +++ b/uniCloud-aliyun/database/db_init.json @@ -0,0 +1,549 @@ +// 在本文件中可配置云数据库初始化,数据格式见:https://uniapp.dcloud.io/uniCloud/hellodb?id=db-init + +// 编写完毕后对本文件点右键,可按配置规则创建表和添加数据 + +{ + "uni-id-users": { + "data": [{ + "_id": "_uni_starter_test_user_id", + "username": "uni-starter预置用户名", + "nickname": "测试用户昵称", + "avatar": "https://unicloud.dcloud.net.cn/assets/logo.dca09351.png", + "mobile": "18888888888", + "mobile_confirmed": 1 + }] + }, + "uni-id-roles": { + "data": [{ + "role_id": "admin", + "role_name": "超级管理员", + "permission": [], + "comment": "超级管理员拥有所有权限", + "create_date": 0 + }] + }, + "opendb-banner": { + "data": [{ + "status": true, + "bannerfile": { + "name": "094a9dc0-50c0-11eb-b680-7980c8a877b8.jpg", + "extname": "jpg", + "fileType": "image", + "url": "https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg", + "size": 70880, + "image": { + "width": 500, + "height": 333 + }, + "path": "https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg" + }, + "open_url": "https://www.dcloud.io/", + "title": "测试", + "sort": 1, + "category_id": "", + "description": "" + }, + { + "status": true, + "bannerfile": { + "name": "094a9dc0-50c0-11eb-b680-7980c8a877b8.jpg", + "extname": "jpg", + "fileType": "image", + "url": "https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg", + "size": 70880, + "image": { + "width": 500, + "height": 333 + }, + "path": "https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg" + }, + "open_url": "https://www.dcloud.io/", + "title": "", + "category_id": "", + "description": "" + } + ] + }, + "opendb-news-articles": { + "data": [{ + "title": "阿里小程序IDE官方内嵌uni-app,为开发者提供多端开发服务", + "excerpt": "阿里小程序IDE官方内嵌uni-app,为开发者提供多端开发服务", + "content": "

随着微信、阿里、百度、头条、QQ纷纷推出小程序,开发者的开发维护成本持续上升,负担过重。这点已经成为共识,现在连小程序平台厂商也充分意识到了。

\n

阿里小程序团队,为了减轻开发者的负担,在官方的小程序开发者工具中整合了多端框架。

\n

经过阿里团队仔细评估,uni-app 在产品完成度、跨平台支持度、开发者社区、可持续发展等多方面优势明显,最终选定 uni-app内置于阿里小程序开发工具中,为开发者提供多端开发解决方案。

\n

经过之前1个月的公测,10月10日,阿里小程序正式发布0.70版开发者工具,通过 uni-app 实现多端开发,成为本次版本更新的亮点功能!

\n

如下图,在阿里小程序工具左侧主导航选择 uni-app,创建项目,即可开发。

\n
\n


阿里小程序开发工具更新说明详见:https://docs.alipay.com/mini/ide/0.70-stable

\n

 

\n

集成uni-app,这对于阿里团队而言,并不是一个容易做出的决定。毕竟 uni-app 是一个三方产品,要经过复杂的评审流程。

\n

这一方面突显出阿里团队以开发者需求为本的优秀价值观,另一方面也证明 uni-app的产品确实过硬。

\n

很多开发者都有多端需求,但又没有足够精力去了解、评估 uni-app,而处于观望态度。现在大家可以更放心的使用 uni-app 了,它没有让阿里失望,也不会让你失望。

\n

自从uni-app推出以来,DCloud也取得了高速的发展,目前拥有370万开发者,框架运行在4.6亿手机用户设备上,月活达到1.35亿(仅包括部分接入DCloud统计平台的数据)。并且数据仍在高速增长中,在市场占有率上处于遥遥领先的位置。

\n

本次阿里小程序工具集成 uni-app,会让 uni-app 继续快速爆发,取得更大的成功。

\n

后续DCloud还将深化与阿里的合作,在serverless等领域给开发者提供更多优质服务。

\n

使用多端框架开发各端应用,是多赢的模式。开发者减轻了负担,获得了更多新流量。而小程序平台厂商,也能保证自己平台上的各种应用可以被及时的更新。

\n

DCloud欢迎更多小程序平台厂商,与我们一起合作,为开发者、平台、用户的多赢而努力。

\n

进一步了解uni-app,详见:https://uniapp.dcloud.io

\n

欢迎扫码关注DCloud公众号,转发消息到朋友圈。

", + "avatar": "https://ask.dcloud.net.cn/uploads/article/20191014/56f7dc1bd5f265e824649f7cb4f78d5b.png", + "type": 0, + "user_id": "_uni_starter_test_user_id", + "comment_count": 0, + "like_count": 0, + "comment_status": 0, + "article_status": 1, + "publish_date": 1616092287006, + "last_modify_date": 1616092303031, + "create_date": 1616092287006 + }] + }, + "opendb-admin-menus": { + "data": [{ + "menu_id": "index", + "name": "首页", + "icon": "uni-icons-home", + "url": "/", + "sort": 100, + "parent_id": "", + "permission": [], + "enable": true, + "create_date": 1602662469396 + }, { + "menu_id": "system_management", + "name": "系统管理", + "icon": "admin-icons-fl-xitong", + "url": "", + "sort": 1000, + "parent_id": "", + "permission": [], + "enable": true, + "create_date": 1602662469396 + }, { + "menu_id": "system_user", + "name": "用户管理", + "icon": "admin-icons-manager-user", + "url": "/pages/system/user/list", + "sort": 1010, + "parent_id": "system_management", + "permission": [], + "enable": true, + "create_date": 1602662469398 + }, { + "menu_id": "system_role", + "name": "角色管理", + "icon": "admin-icons-manager-role", + "url": "/pages/system/role/list", + "sort": 1020, + "parent_id": "system_management", + "permission": [], + "enable": true, + "create_date": 1602662469397 + }, { + "menu_id": "system_permission", + "name": "权限管理", + "icon": "admin-icons-manager-permission", + "url": "/pages/system/permission/list", + "sort": 1030, + "parent_id": "system_management", + "permission": [], + "enable": true, + "create_date": 1602662469396 + }, { + "menu_id": "system_menu", + "name": "菜单管理", + "icon": "admin-icons-manager-menu", + "url": "/pages/system/menu/list", + "sort": 1040, + "parent_id": "system_management", + "permission": [], + "enable": true, + "create_date": 1602662469396 + }, { + "menu_id": "system_app", + "name": "应用管理", + "icon": "admin-icons-manager-app", + "url": "/pages/system/app/list", + "sort": 1035, + "parent_id": "system_management", + "permission": [], + "enable": true, + "create_date": 1602662469399 + }, { + "menu_id": "system_update", + "name": "App升级中心", + "icon": "uni-icons-cloud-upload", + "url": "/uni_modules/uni-upgrade-center/pages/version/list", + "sort": 1036, + "parent_id": "system_management", + "permission": [], + "enable": true, + "create_date": 1656491532434 + }, { + "menu_id": "system_tag", + "name": "标签管理", + "icon": "admin-icons-manager-tag", + "url": "/pages/system/tag/list", + "sort": 1037, + "parent_id": "system_management", + "permission": [], + "enable": true, + "create_date": 1602662479389 + }, { + "permission": [], + "enable": true, + "menu_id": "safety_statistics", + "name": "安全审计", + "icon": "admin-icons-safety", + "url": "", + "sort": 3100, + "parent_id": "", + "create_date": 1638356430871 + }, { + "permission": [], + "enable": true, + "menu_id": "safety_statistics_user_log", + "name": "用户日志", + "icon": "", + "url": "/pages/system/safety/list", + "sort": 3101, + "parent_id": "safety_statistics", + "create_date": 1638356430871 + }, { + "permission": [], + "enable": true, + "menu_id": "uni-stat", + "name": "uni 统计", + "icon": "admin-icons-tongji", + "url": "", + "sort": 2100, + "parent_id": "", + "create_date": 1638356430871 + }, { + "parent_id": "uni-stat", + "permission": [], + "enable": true, + "menu_id": "uni-stat-device", + "name": "设备统计", + "icon": "admin-icons-shebeitongji", + "url": "", + "sort": 2120, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-device", + "permission": [], + "enable": true, + "menu_id": "uni-stat-device-overview", + "name": "概况", + "icon": "", + "url": "/pages/uni-stat/device/overview/overview", + "sort": 2121, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-device", + "permission": [], + "enable": true, + "menu_id": "uni-stat-device-activity", + "name": "活跃度", + "icon": "", + "url": "/pages/uni-stat/device/activity/activity", + "sort": 2122, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-device", + "permission": [], + "enable": true, + "menu_id": "uni-stat-device-trend", + "name": "趋势分析", + "icon": "", + "url": "/pages/uni-stat/device/trend/trend", + "sort": 2123, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-device", + "permission": [], + "enable": true, + "menu_id": "uni-stat-device-retention", + "name": "留存", + "icon": "", + "url": "/pages/uni-stat/device/retention/retention", + "sort": 2124, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-device", + "permission": [], + "enable": true, + "menu_id": "uni-stat-device-comparison", + "name": "平台对比", + "icon": "", + "url": "/pages/uni-stat/device/comparison/comparison", + "sort": 2125, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-device", + "permission": [], + "enable": true, + "menu_id": "uni-stat-device-stickiness", + "name": "粘性", + "icon": "", + "url": "/pages/uni-stat/device/stickiness/stickiness", + "sort": 2126, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat", + "permission": [], + "enable": true, + "menu_id": "uni-stat-user", + "name": "注册用户统计", + "icon": "admin-icons-yonghutongji", + "url": "", + "sort": 2122, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-user", + "permission": [], + "enable": true, + "menu_id": "uni-stat-user-overview", + "name": "概况", + "icon": "", + "url": "/pages/uni-stat/user/overview/overview", + "sort": 2121, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-user", + "permission": [], + "enable": true, + "menu_id": "uni-stat-user-activity", + "name": "活跃度", + "icon": "", + "url": "/pages/uni-stat/user/activity/activity", + "sort": 2122, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-user", + "permission": [], + "enable": true, + "icon": "", + "menu_id": "uni-stat-user-trend", + "name": "趋势分析", + "url": "/pages/uni-stat/user/trend/trend", + "sort": 2123, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-user", + "permission": [], + "enable": true, + "menu_id": "uni-stat-user-retention", + "name": "留存", + "icon": "", + "url": "/pages/uni-stat/user/retention/retention", + "sort": 2124, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-user", + "permission": [], + "enable": true, + "menu_id": "uni-stat-user-comparison", + "name": "平台对比", + "icon": "", + "url": "/pages/uni-stat/user/comparison/comparison", + "sort": 2125, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-user", + "permission": [], + "enable": true, + "menu_id": "uni-stat-user-stickiness", + "name": "粘性", + "icon": "", + "url": "/pages/uni-stat/user/stickiness/stickiness", + "sort": 2126, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat", + "permission": [], + "enable": true, + "menu_id": "uni-stat-page-analysis", + "name": "页面统计", + "icon": "admin-icons-page-ent", + "url": "", + "sort": 2123, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-page-analysis", + "permission": [], + "enable": true, + "menu_id": "uni-stat-page-res", + "name": "受访页", + "icon": "", + "url": "/pages/uni-stat/page-res/page-res", + "sort": 2131, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-page-analysis", + "permission": [], + "enable": true, + "menu_id": "uni-stat-page-ent", + "name": "入口页", + "icon": "", + "url": "/pages/uni-stat/page-ent/page-ent", + "sort": 2132, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat", + "permission": [], + "enable": true, + "menu_id": "uni-stat-senceChannel", + "name": "渠道/场景值分析", + "icon": "admin-icons-qudaofenxi", + "url": "", + "sort": 2150, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-senceChannel", + "permission": [], + "enable": true, + "menu_id": "uni-stat-senceChannel-scene", + "name": "场景值(小程序)", + "icon": "", + "url": "/pages/uni-stat/scene/scene", + "sort": 2151, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-senceChannel", + "permission": [], + "enable": true, + "menu_id": "uni-stat-senceChannel-channel", + "name": "渠道(app)", + "icon": "", + "url": "/pages/uni-stat/channel/channel", + "sort": 2152, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat", + "permission": [], + "enable": true, + "menu_id": "uni-stat-event-event", + "name": "自定义事件", + "icon": "admin-icons-shijianfenxi", + "url": "/pages/uni-stat/event/event", + "sort": 2160, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat", + "permission": [], + "enable": true, + "menu_id": "uni-stat-error", + "name": "错误统计", + "icon": "admin-icons-cuowutongji", + "url": "", + "sort": 2170, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-error", + "permission": [], + "enable": true, + "menu_id": "uni-stat-error-js", + "name": "js报错", + "icon": "", + "url": "/pages/uni-stat/error/js/js", + "sort": 2171, + "create_date": 1638356902516 + }, { + "parent_id": "uni-stat-error", + "permission": [], + "enable": true, + "menu_id": "uni-stat-error-app", + "name": "app崩溃", + "icon": "", + "url": "/pages/uni-stat/error/app/app", + "sort": 2172, + "create_date": 1638356902516 + }, + { + "menu_id": "uni-stat-pay", + "name": "支付统计", + "icon": "uni-icons-circle", + "url": "", + "sort": 2122, + "parent_id": "uni-stat", + "permission": [], + "enable": true, + "create_date": 1667386977981 + }, { + "menu_id": "uni-stat-pay-overview", + "name": "概况", + "icon": "", + "url": "/pages/uni-stat/pay-order/overview/overview", + "sort": 21221, + "parent_id": "uni-stat-pay", + "permission": [], + "enable": true, + "create_date": 1667387038602 + }, + { + "menu_id": "uni-stat-pay-funnel", + "name": "转换漏斗分析", + "icon": "", + "url": "/pages/uni-stat/pay-order/funnel/funnel", + "sort": 21222, + "parent_id": "uni-stat-pay", + "permission": [], + "enable": true, + "create_date": 1668430092890 + }, + { + "menu_id": "uni-stat-pay-ranking", + "name": "价值用户排行", + "icon": "", + "url": "/pages/uni-stat/pay-order/ranking/ranking", + "sort": 21223, + "parent_id": "uni-stat-pay", + "permission": [], + "enable": true, + "create_date": 1668430128302 + }, + { + "menu_id": "uni-stat-pay-order-list", + "name": "订单明细", + "icon": "", + "url": "/pages/uni-stat/pay-order/list/list", + "sort": 21224, + "parent_id": "uni-stat-pay", + "permission": [], + "enable": true, + "create_date": 1667387078947 + } + ] + }, + "uni-id-permissions": {}, + "uni-id-log": {}, + "uni-id-tag": {}, + "uni-id-device": {}, + "uni-id-scores": {}, + "opendb-verify-codes": {}, + "opendb-app-list": {}, + "opendb-app-versions": {}, + "opendb-device": {}, + "opendb-department": {}, + "opendb-sms-task": {}, + "opendb-sms-log": {}, + "opendb-sms-template": {}, + "opendb-open-data": {}, + "uni-stat-app-versions": {}, + "uni-stat-active-devices": {}, + "uni-stat-active-users": {}, + "uni-stat-app-channels": {}, + "uni-stat-app-crash-logs": {}, + "uni-stat-app-platforms": {}, + "uni-stat-error-logs": {}, + "uni-stat-error-result": {}, + "uni-stat-error-source-map": {}, + "uni-stat-event-logs": {}, + "uni-stat-event-result": {}, + "uni-stat-events": {}, + "uni-stat-loyalty-result": {}, + "uni-stat-mp-scenes": {}, + "uni-stat-page-logs": {}, + "uni-stat-page-result": {}, + "uni-stat-pages": {}, + "uni-stat-result": {}, + "uni-stat-run-errors": {}, + "uni-stat-session-logs": {}, + "uni-stat-share-logs": {}, + "uni-stat-user-session-logs": {}, + "uni-stat-pay-result": {}, + "uni-pay-orders": {}, + "opendb-tempdata": {}, + "opendb-feedback": {}, + "opendb-news-categories": {}, + "opendb-news-comments": {}, + "opendb-news-favorite": {}, + "opendb-search-hot": {}, + "opendb-search-log": {}, + "opendb-sign-in": {}, + "read-news-log": {} +} diff --git a/uniCloud-aliyun/database/dictItem.jql b/uniCloud-aliyun/database/dictItem.jql new file mode 100644 index 0000000..a5680d3 --- /dev/null +++ b/uniCloud-aliyun/database/dictItem.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('ngTools_DictItem').where({"dictID":"jsclpzxs"}).remove(); \ No newline at end of file diff --git a/uniCloud-aliyun/database/lab_custom.schema.json b/uniCloud-aliyun/database/lab_custom.schema.json new file mode 100644 index 0000000..e1e3915 --- /dev/null +++ b/uniCloud-aliyun/database/lab_custom.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"}}} \ No newline at end of file diff --git a/uniCloud-aliyun/database/ngTools_Dict.schema.json b/uniCloud-aliyun/database/ngTools_Dict.schema.json new file mode 100644 index 0000000..db31dca --- /dev/null +++ b/uniCloud-aliyun/database/ngTools_Dict.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":[],"permission":{"read":true,"create":true,"update":true,"delete":true},"properties":{"_id":{"description":"ID,系统自动生成"},"dictName":{"description":"字典名称","bsonType":"string","title":"字典名称","trim":"both"},"dictCode":{"description":"字典编码","bsonType":"string","title":"字典编码","trim":"both"},"description":{"description":"描述","bsonType":"string","title":"描述","trim":"both"},"delFlag":{"description":"删除状态","bsonType":"int","title":"删除状态","trim":"both"},"createTime":{"description":"创建时间","bsonType":"string","title":"创建时间","trim":"both"},"createBy":{"description":"创建人","bsonType":"string","title":"创建人","trim":"both"},"updateTime":{"description":"更新时间","bsonType":"datetime","title":"更新时间","trim":"both"},"updateBy":{"description":"更新人","bsonType":"string","title":"更新人","trim":"both"}}} \ No newline at end of file diff --git a/uniCloud-aliyun/database/ngTools_DictItem.schema.json b/uniCloud-aliyun/database/ngTools_DictItem.schema.json new file mode 100644 index 0000000..b3e2069 --- /dev/null +++ b/uniCloud-aliyun/database/ngTools_DictItem.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":[],"permission":{"read":true,"create":true,"update":true,"delete":true},"properties":{"_id":{"description":"ID,系统自动生成"},"dictID":{"description":"字典ID","bsonType":"string","title":"字典ID","trim":"both"},"itemValue":{"description":"字典项值","bsonType":"string","title":"字典项值","trim":"both","length":"1024"},"itemText":{"description":"字典项文本","bsonType":"string","title":"字典项文本","trim":"both"},"itemColor":{"description":"字典项颜色","bsonType":"string","title":"字典项颜色","trim":"both"},"description":{"description":"描述","bsonType":"string","title":"描述","trim":"both"},"sortOrder":{"description":"排序","bsonType":"string","title":"排序","trim":"both"},"status":{"description":"状态","bsonType":"int","title":"状态","trim":"both"},"createTime":{"description":"创建时间","bsonType":"datetime","title":"创建时间","trim":"both"},"createBy":{"description":"创建人","bsonType":"string","title":"创建人","trim":"both"},"updateTime":{"description":"更新时间","bsonType":"datetime","title":"更新时间","trim":"both"},"updateBy":{"description":"更新人","bsonType":"string","title":"更新人","trim":"both"}}} \ No newline at end of file diff --git a/uniCloud-aliyun/database/ngTools_MeterList.schema.json b/uniCloud-aliyun/database/ngTools_MeterList.schema.json new file mode 100644 index 0000000..05b9561 --- /dev/null +++ b/uniCloud-aliyun/database/ngTools_MeterList.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"dMeterType":{"description":"流量计类别","bsonType":"string","title":"流量计类别","trim":"both"},"departID":{"description":"部门编号","bsonType":"string","title":"部门编号","trim":"both"},"createTime":{"description":"创建时间","bsonType":"datetime","title":"创建时间","trim":"both"},"createBy":{"description":"创建人","bsonType":"string","title":"创建人","trim":"both"},"updateTime":{"description":"更新时间","bsonType":"datetime","title":"更新时间","trim":"both"},"updateBy":{"description":"更新人","bsonType":"string","title":"更新人","trim":"both"}}} \ No newline at end of file diff --git a/uniCloud-aliyun/database/ngTools_MeterPar.schema.json b/uniCloud-aliyun/database/ngTools_MeterPar.schema.json new file mode 100644 index 0000000..faebca6 --- /dev/null +++ b/uniCloud-aliyun/database/ngTools_MeterPar.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"createTime":{"description":"创建时间","bsonType":"datetime","title":"创建时间","trim":"both"},"createBy":{"description":"创建人","bsonType":"string","title":"创建人","trim":"both"},"updateTime":{"description":"更新时间","bsonType":"datetime","title":"更新时间","trim":"both"},"updateBy":{"description":"更新人","bsonType":"string","title":"更新人","trim":"both"},"meterID":{"description":"计量点编号","bsonType":"string","title":"计量点编号","trim":"both"},"dFlowCalbz":{"description":"流量计算标准","bsonType":"string","title":"流量计算标准","trim":"both"},"dZcalbz":{"description":"压缩因子计算标准","bsonType":"string","title":"压缩因子计算标准","trim":"both"},"dCbtj":{"description":"计量参比条件","bsonType":"string","title":"计量参比条件","trim":"both"},"dRsCbtj":{"description":"燃烧参比条件","bsonType":"string","title":"燃烧参比条件","trim":"both"},"dPb_M":{"description":"计量参比条件压力","bsonType":"string","title":"计量参比条件压力","trim":"both"},"dTb_M":{"description":"计量参比条件温度","bsonType":"string","title":"计量参比条件温度","trim":"both"},"dPb_E":{"description":"燃烧参比条件压力","bsonType":"string","title":"燃烧参比条件压力","trim":"both"},"dTb_E":{"description":"燃烧参比条件温度","bsonType":"string","title":"燃烧参比条件温度","trim":"both"},"dPatm":{"description":"当地大气压","bsonType":"string","title":"当地大气压","trim":"both"},"dPatmUnit":{"description":"当地大气压单位","bsonType":"string","title":"当地大气压单位","trim":"both"},"dNG_Compents":{"description":"天然气组分","bsonType":"string","title":"天然气组分","trim":"both"},"dMeterType":{"description":"流量计类别","bsonType":"string","title":"流量计类别","trim":"both"},"dCoreType":{"description":"节流装置类型","bsonType":"string","title":"节流装置类型","trim":"both"},"dPtmode":{"description":"取压方式","bsonType":"string","title":"取压方式","trim":"both"},"dPipeType":{"description":"管道类型","bsonType":"string","title":"管道类型","trim":"both"},"dPipeD":{"description":"管道内径","bsonType":"string","title":"管道内径","trim":"both"},"dLenUnit":{"description":"长度单位","bsonType":"string","title":"长度单位","trim":"both"},"dPipeDtemp":{"description":"管道内径参考温度","bsonType":"string","title":"管道内径参考温度","trim":"both"},"dPileDtempU":{"description":"温度单位","bsonType":"string","title":"温度单位","trim":"both"},"dPipeMaterial":{"description":"管道材料","bsonType":"string","title":"管道材料","trim":"both"},"dOrificeD":{"description":"孔板孔径","bsonType":"string","title":"孔板孔径","trim":"both"},"dOrificeUnit":{"description":"长度单位","bsonType":"string","title":"长度单位","trim":"both"},"dOrificeDtemp":{"description":"孔板内径参考温度","bsonType":"string","title":"孔板内径参考温度","trim":"both"},"dOrificeDtempUnit":{"description":"温度单位","bsonType":"string","title":"温度单位","trim":"both"},"dOrificeMaterial":{"description":"孔板材料","bsonType":"string","title":"孔板材料","trim":"both"},"dOrificeSharpness":{"description":"锐利度系数计算方法","bsonType":"string","title":"锐利度系数计算方法","trim":"both"},"dOrificeRk":{"description":"孔板入口圆弧半径","bsonType":"string","title":"孔板入口圆弧半径","trim":"both"},"dOrificeRkLenU":{"description":"长度单位","bsonType":"string","title":"长度单位","trim":"both"},"dPf":{"description":"输入压力","bsonType":"string","title":"输入压力","trim":"both"},"dPfUnit":{"description":"压力单位","bsonType":"string","title":"压力单位","trim":"both"},"dPfType":{"description":"压力类型","bsonType":"string","title":"压力类型","trim":"both"},"dTf":{"description":"输入温度","bsonType":"string","title":"输入温度","trim":"both"},"dTfUnit":{"description":"温度单位","bsonType":"string","title":"温度单位","trim":"both"},"dDp":{"description":"输入差压","bsonType":"string","title":"输入差压","trim":"both"},"dDpUnit":{"description":"压力单位","bsonType":"string","title":"压力单位","trim":"both"},"dVFlowUnit":{"description":"体积流量单位","bsonType":"string","title":"体积流量单位","trim":"both"},"dMFlowUnit":{"description":"质量流量单位","bsonType":"string","title":"质量流量单位","trim":"both"},"dEFlowUnit":{"description":"能量流量单位","bsonType":"string","title":"能量流量单位","trim":"both"},"dCdCalMethod":{"description":"流出系数计算方法","bsonType":"string","title":"流出系数计算方法","trim":"both"},"dMeterFactor":{"description":"仪表系数","bsonType":"string","title":"仪表系数","trim":"both"},"dPulseNum":{"description":"脉冲数","bsonType":"string","title":"脉冲数","trim":"both"},"dVFlowMax":{"description":"最大体积流量","bsonType":"string","title":"最大体积流量","trim":"both"},"dVFlowMin":{"description":"最小体积流量","bsonType":"string","title":"最小体积流量","trim":"both"},"dVFlowCon":{"description":"常用流量","bsonType":"string","title":"常用流量","trim":"both"},"dPfRangeMin":{"description":"压力量程","bsonType":"string","title":"压力量程","trim":"both"},"dPfRangeMax":{"description":"压力量程","bsonType":"string","title":"压力量程","trim":"both"},"dDpRangeMin":{"description":"差压量程","bsonType":"string","title":"差压量程","trim":"both"},"dDpRangeMax":{"description":"差压量程","bsonType":"string","title":"差压量程","trim":"both"},"dTfRangeMin":{"description":"温度计量程","bsonType":"string","title":"温度计量程","trim":"both"},"dTfRangeMax":{"description":"温度计量程","bsonType":"string","title":"温度计量程","trim":"both"},"dVGsc":{"description":"管束车水容积","bsonType":"string","title":"管束车水容积","trim":"both"}}} \ No newline at end of file diff --git a/uniCloud-aliyun/database/ngTools_NGComponents.schema.json b/uniCloud-aliyun/database/ngTools_NGComponents.schema.json new file mode 100644 index 0000000..1488e6f --- /dev/null +++ b/uniCloud-aliyun/database/ngTools_NGComponents.schema.json @@ -0,0 +1,210 @@ +// 文档教程: https://uniapp.dcloud.net.cn/uniCloud/schema +{ + "bsonType": "object", + "required": [], + "permission": { + "read": true, + "create": true, + "update": true, + "delete": true + }, + "properties": { + "_id": { + "description": "ID,系统自动生成" + }, + "createTime": { + "description": "创建时间", + "bsonType": "datetime", + "title": "创建时间", + "trim": "both" + + }, + "samplingDate": { + "description": "取样日期", + "bsonType": "date", + "title": "取样日期", + "trim": "both" + + }, + "assayDate": { + "description": "分析日期", + "bsonType": "date", + "title": "分析日期", + "trim": "both" + + }, + + + "samplingLocation": { + "bsonType": "array", + "arrayType": "string", + "title": "取样地点", + "multiple": false // 允许选择多张图片,schema2code生效 + }, + + + "sampleNumber": { + "description": "样品编号", + "bsonType": "string", + "title": "样品编号", + "trim": "both" + }, + "NG_C1": { + "description": "甲烷C1", + "bsonType": "string", + "title": "甲烷C1", + "trim": "both", + "defaultValue": "0" + }, + "NG_N2": { + "description": "氮气N2", + "bsonType": "string", + "title": "氮气N2", + "trim": "both", + "defaultValue": "0" + + }, + "NG_CO2": { + "description": "二氧化碳CO2", + "bsonType": "string", + "title": "二氧化碳CO2", + "trim": "both", + "defaultValue": "0" + }, + "NG_C2": { + "description": "乙烷C2", + "bsonType": "string", + "title": "乙烷C2", + "trim": "both", + "defaultValue": "0" + }, + "NG_C3": { + "description": "丙烷C3", + "bsonType": "string", + "title": "丙烷C3", + "trim": "both", + "defaultValue": "0" + }, + "NG_H2O": { + "description": "水H2O", + "bsonType": "string", + "title": "水H2O", + "trim": "both", + "defaultValue": "0" + }, + "NG_H2S": { + "description": "硫化氢H2S", + "bsonType": "string", + "title": "硫化氢H2S", + "trim": "both", + "defaultValue": "0" + }, + "NG_H2": { + "description": "氢气H2", + "bsonType": "string", + "title": "氢气H2", + "trim": "both", + "defaultValue": "0" + }, + "NG_CO": { + "description": "一氧化碳CO", + "bsonType": "string", + "title": "一氧化碳CO", + "trim": "both", + "defaultValue": "0" + }, + "NG_O2": { + "description": "氧气O2", + "bsonType": "string", + "title": "氧气O2", + "trim": "both", + "defaultValue": "0" + }, + "NG_iC4": { + "description": "异丁烷iC4", + "bsonType": "string", + "title": "异丁烷iC4", + "trim": "both", + "defaultValue": "0" + }, + "NG_nC4": { + "description": "正丁烷nC4", + "bsonType": "string", + "title": "正丁烷nC4", + "trim": "both", + "defaultValue": "0" + }, + "NG_iC5": { + "description": "异戊烷iC5", + "bsonType": "string", + "title": "异戊烷iC5", + "trim": "both", + "defaultValue": "0" + }, + "NG_nC5": { + "description": "正戊烷nC5", + "bsonType": "string", + "title": "正戊烷nC5", + "trim": "both", + "defaultValue": "0" + }, + "NG_C6": { + "description": "己烷C6", + "bsonType": "string", + "title": "己烷C6", + "trim": "both", + "defaultValue": "0" + }, + "NG_C7": { + "description": "庚烷C7", + "bsonType": "string", + "title": "庚烷C7", + "trim": "both", + "defaultValue": "0" + }, + "NG_C8": { + "description": "辛烷C8", + "bsonType": "string", + "title": "辛烷C8", + "trim": "both", + "defaultValue": "0" + }, + "NG_C9": { + "description": "壬烷C9", + "bsonType": "string", + "title": "壬烷C9", + "trim": "both", + "defaultValue": "0" + }, + "NG_C10": { + "description": "癸烷C10", + "bsonType": "string", + "title": "癸烷C10", + "trim": "both", + "defaultValue": "0" + }, + "NG_He": { + "description": "氦气He", + "bsonType": "string", + "title": "氦气He", + "trim": "both", + "defaultValue": "0" + }, + "NG_Ar": { + "description": "氩气Ar", + "bsonType": "string", + "title": "氩气Ar", + "trim": "both", + "defaultValue": "0" + }, + "NG_SUM": { + "description": "合计", + "bsonType": "string", + "title": "合计", + "trim": "both", + "defaultValue": "0" + } + + + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/database/ngTools_NGPar.schema.json b/uniCloud-aliyun/database/ngTools_NGPar.schema.json new file mode 100644 index 0000000..5d843e2 --- /dev/null +++ b/uniCloud-aliyun/database/ngTools_NGPar.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"adMixture":{"description":"摩尔组成","bsonType":"string","title":"摩尔组成","trim":"both"},"adMixtureV":{"description":"体积组成","bsonType":"string","title":"体积组成","trim":"both"},"adMixtureD":{"description":"质量组成","bsonType":"string","title":"质量组成","trim":"both"},"dCbtj":{"description":"参比条件","bsonType":"string","title":"参比条件","trim":"both"},"dPb":{"description":"参比压力","bsonType":"string","title":"参比压力","trim":"both"},"dTb":{"description":"参比温度","bsonType":"string","title":"参比温度","trim":"both"},"dPf":{"description":"绝对压力","bsonType":"string","title":"绝对压力","trim":"both"},"dTf":{"description":"工况温度","bsonType":"string","title":"工况温度","trim":"both"},"dMrx":{"description":"分子量","bsonType":"string","title":"分子量","trim":"both"},"dZb":{"description":"标况压缩因子","bsonType":"string","title":"标况压缩因子","trim":"both"},"dZf":{"description":"工况压缩因子","bsonType":"string","title":"工况压缩因子","trim":"both"},"dFpv":{"description":"超压缩系数","bsonType":"string","title":"超压缩系数","trim":"both"},"dDb":{"description":"标况摩尔密度","bsonType":"string","title":"标况摩尔密度","trim":"both"},"dDf":{"description":"工况摩尔密度","bsonType":"string","title":"工况摩尔密度","trim":"both"},"dRhob":{"description":"标况质量密度","bsonType":"string","title":"标况质量密度","trim":"both"},"dRhof":{"description":"工况质量密度","bsonType":"string","title":"工况质量密度","trim":"both"},"dRD_Ideal":{"description":"理想气体的相对密度","bsonType":"string","title":"理想气体的相对密度","trim":"both"},"dRD_Real":{"description":"真实气体的相对密度","bsonType":"string","title":"真实气体的相对密度","trim":"both"},"dHo":{"description":"理想气体的比焓","bsonType":"string","title":"理想气体的比焓","trim":"both"},"dH":{"description":"真实气体的焓","bsonType":"string","title":"真实气体的焓","trim":"both"},"dS":{"description":"真实气体的熵","bsonType":"string","title":"真实气体的熵","trim":"both"},"dCpi":{"description":"理想气体定压热容","bsonType":"string","title":"理想气体定压热容","trim":"both"},"dCp":{"description":"定压热容","bsonType":"string","title":"定压热容","trim":"both"},"dCv":{"description":"定容积热容","bsonType":"string","title":"定容积热容","trim":"both"},"dk":{"description":"比热比","bsonType":"string","title":"比热比","trim":"both"},"dKappa":{"description":"等熵指数","bsonType":"string","title":"等熵指数","trim":"both"},"dSOS":{"description":"声速","bsonType":"string","title":"声速","trim":"both"},"dCstar":{"description":"临界流函数","bsonType":"string","title":"临界流函数","trim":"both"},"dHhvMol":{"description":"摩尔高位发热量","bsonType":"string","title":"摩尔高位发热量","trim":"both"},"dLhvMol":{"description":"摩尔低位发热量","bsonType":"string","title":"摩尔低位发热量","trim":"both"},"dHhvv":{"description":"体积高位发热量","bsonType":"string","title":"体积高位发热量","trim":"both"},"dLhvv":{"description":"体积低位发热量","bsonType":"string","title":"体积低位发热量","trim":"both"},"dHhvm":{"description":"质量高位发热量","bsonType":"string","title":"质量高位发热量","trim":"both"},"dLhvm":{"description":"质量地位发热量","bsonType":"string","title":"质量地位发热量","trim":"both"},"dZb11062":{"description":"标况压缩因子","bsonType":"string","title":"标况压缩因子","trim":"both"},"dRhob11062":{"description":"标况质量密度","bsonType":"string","title":"标况质量密度","trim":"both"},"dRhof11062":{"description":"工况质量密度","bsonType":"string","title":"工况质量密度","trim":"both"},"dRD_Ideal11062":{"description":"理想气体的相对密度","bsonType":"string","title":"理想气体的相对密度","trim":"both"},"dRD_Real11062":{"description":"真实气体的相对密度","bsonType":"string","title":"真实气体的相对密度","trim":"both"},"dWobbeIndex":{"description":"真实气体的沃泊指数","bsonType":"string","title":"真实气体的沃泊指数","trim":"both"},"Pc":{"description":"临界压力","bsonType":"string","title":"临界压力","trim":"both"},"TC":{"description":"临界温度","bsonType":"string","title":"临界温度","trim":"both"},"Bzsx":{"description":"爆炸上限","bsonType":"string","title":"爆炸上限","trim":"both"},"Bzxx":{"description":"爆炸下限","bsonType":"string","title":"爆炸下限","trim":"both"},"TotalC":{"description":"总炭含量","bsonType":"string","title":"总炭含量","trim":"both"},"C2":{"description":"C2组分含量","bsonType":"string","title":"C2组分含量","trim":"both"},"C2j":{"description":"C2以上组分含量","bsonType":"string","title":"C2以上组分含量","trim":"both"},"C3j":{"description":"C3以上组分含量","bsonType":"string","title":"C3以上组分含量","trim":"both"},"C4j":{"description":"C4以上组分含量","bsonType":"string","title":"C4以上组分含量","trim":"both"},"C5j":{"description":"C5以上组分含量","bsonType":"string","title":"C5以上组分含量","trim":"both"},"C6j":{"description":"C6以上组分含量","bsonType":"string","title":"C6以上组分含量","trim":"both"},"C3C4":{"description":"C3C4组分含量","bsonType":"string","title":"C3C4组分含量","trim":"both"},"createTime":{"description":"创建时间","bsonType":"datetime","title":"创建时间","trim":"both"},"createBy":{"description":"创建人","bsonType":"string","title":"创建人","trim":"both"},"updateTime":{"description":"更新时间","bsonType":"datetime","title":"更新时间","trim":"both"},"updateBy":{"description":"更新人","bsonType":"string","title":"更新人","trim":"both"}}} \ No newline at end of file diff --git a/uniCloud-aliyun/database/ngTools_SamplingLocation.schema.json b/uniCloud-aliyun/database/ngTools_SamplingLocation.schema.json new file mode 100644 index 0000000..a15e732 --- /dev/null +++ b/uniCloud-aliyun/database/ngTools_SamplingLocation.schema.json @@ -0,0 +1,34 @@ +// 文档教程: https://uniapp.dcloud.net.cn/uniCloud/schema +{ + "bsonType": "object", + "required": [], + "permission": { + "read": true, + "create": true, + "update": true, + "delete": true + }, + "properties": { + "_id": { + "description": "ID,系统自动生成" + }, + "samplingLocation": { + "description": "取样地点", + "bsonType": "string", + "title": "取样地点", + "trim": "both" + }, + "departName": { + "description": "单位名称", + "bsonType": "string", + "title": "单位名称", + "trim": "both" + }, + "stationName": { + "description": "站场名称", + "bsonType": "string", + "title": "站场名称", + "trim": "both" + } + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/database/ngTools_depart.schema.json b/uniCloud-aliyun/database/ngTools_depart.schema.json new file mode 100644 index 0000000..a20f101 --- /dev/null +++ b/uniCloud-aliyun/database/ngTools_depart.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["name"],"permission":{"read":true,"create":true,"update":true,"delete":true},"properties":{"_id":{"description":"ID,系统自动生成"},"parent_id":{"bsonType":"string","description":"父级部门ID","parentKey":"_id"},"depart_name":{"bsonType":"string","description":"部门名称","title":"部门名称","trim":"both"},"level":{"bsonType":"int","description":"部门层级,为提升检索效率而作的冗余设计"},"sort":{"bsonType":"int","description":"部门在当前层级下的顺序,由小到大","title":"显示顺序"},"manager_uid":{"bsonType":"string","description":"部门主管的userid, 参考`uni-id-users` 表","foreignKey":"uni-id-users._id"},"create_date":{"bsonType":"timestamp","description":"部门创建时间","forceDefaultValue":{"$env":"now"}},"status":{"bsonType":"int","description":"部门状态,0-正常、1-禁用"},"createTime":{"description":"创建时间","bsonType":"datetime","title":"创建时间","trim":"both"},"createBy":{"description":"创建人","bsonType":"string","title":"创建人","trim":"both"},"updateTime":{"description":"更新时间","bsonType":"datetime","title":"更新时间","trim":"both"},"updateBy":{"description":"更新人","bsonType":"string","title":"更新人","trim":"both"}},"version":"0.1.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/ngtools-categories.schema.json b/uniCloud-aliyun/database/ngtools-categories.schema.json new file mode 100644 index 0000000..7f91b5a --- /dev/null +++ b/uniCloud-aliyun/database/ngtools-categories.schema.json @@ -0,0 +1,61 @@ +{ + "bsonType": "object", + "required": ["name"], + "permission": { + "read": true, + "create": true, + "update": true, + "delete": true + }, + "properties": { + "_id": { + "description": "存储文档 ID(文章 ID),系统自动生成" + }, + "parent_id": { + "bsonType": "string", + "description": "父ID,用于多级分类" + }, + "name": { + "bsonType": "string", + "description": "类别名称", + "title": "类别名称", + "trim": "both" + }, + "icon": { + "bsonType": "string", + "description": "类别图标\/图片地址", + "title": "图标地址", + "pattern": "^(http:\/\/|https:\/\/|\/|.\/|@\/)\\S", + "trim": "both" + }, + "sort": { + "bsonType": "int", + "description": "类别排序,越大越靠后", + "title": "排序" + }, + "description": { + "bsonType": "string", + "description": "类别描述", + "title": "类别描述", + "trim": "both" + }, + "is_hot_show": { + "bsonType": "bool", + "title": "加入热门显示", + "description": "是否热门显示" + }, + "is_index_show": { + "bsonType": "bool", + "title": "首页显示", + "description": "是否首页显示" + }, + "create_date": { + "bsonType": "timestamp", + "description": "创建时间", + "defaultValue": { + "$env": "now" + } + } + }, + "version": "0.0.1" +} \ No newline at end of file diff --git a/uniCloud-aliyun/database/ngtools-goods.schema.json b/uniCloud-aliyun/database/ngtools-goods.schema.json new file mode 100644 index 0000000..345c1bb --- /dev/null +++ b/uniCloud-aliyun/database/ngtools-goods.schema.json @@ -0,0 +1,124 @@ +{ + "bsonType": "object", + "required": ["goods_sn", "name", "remain_count", "month_sell_count", "total_sell_count", "comment_count", "is_real", + "is_on_sale", "is_alone_sale", "is_best", "is_new", "is_hot" + ], + "permission": { + "read": "doc.is_on_sale == true", + "create": true, + "update": true, + "delete": true + }, + "properties": { + "_id": { + "description": "存储文档 ID(商品 ID),系统自动生成" + }, + "category_id": { + "bsonType": "string", + "description": "分类 id,参考`opendb-mall-categories`表", + "foreignKey": "opendb-mall-categories._id" + }, + "goods_sn": { + "bsonType": "string", + "description": "商品的唯一货号", + "title": "货号", + "trim": "both" + }, + "name": { + "bsonType": "string", + "description": "商品名称", + "title": "名称", + "trim": "both" + }, + "keywords": { + "bsonType": "string", + "description": "商品关键字,为搜索引擎收录使用", + "title": "关键字", + "trim": "both" + }, + "goods_desc": { + "bsonType": "string", + "description": "商品详细描述", + "title": "详细描述", + "trim": "both" + }, + "goods_thumb": { + "bsonType": "string", + "description": "商品缩略图,用于在列表或搜索结果中预览显示", + "title": "缩略图地址", + "pattern": "^(http:\/\/|https:\/\/|\/|.\/|@\/)\\S", + "trim": "both" + }, + "goods_banner_imgs": { + "bsonType": "array", + "description": "商品详情页的banner图地址" + }, + "remain_count": { + "bsonType": "int", + "description": "库存数量", + "title": "库存数量" + }, + "month_sell_count": { + "bsonType": "int", + "description": "月销量" + }, + "total_sell_count": { + "bsonType": "int", + "description": "总销量" + }, + "comment_count": { + "bsonType": "int", + "description": "累计评论数" + }, + "is_real": { + "bsonType": "bool", + "description": "是否实物", + "title": "是否为实物" + }, + "is_on_sale": { + "bsonType": "bool", + "description": "是否上架销售", + "title": "是否上架" + }, + "is_alone_sale": { + "bsonType": "bool", + "description": "是否能单独销售;如果不能单独销售,则只能作为某商品的配件或者赠品销售" + }, + "is_best": { + "bsonType": "bool", + "description": "是否精品" + }, + "is_new": { + "bsonType": "bool", + "description": "是否新品", + "title": "是否新品" + }, + "is_hot": { + "bsonType": "bool", + "description": "是否热销" + }, + "add_date": { + "bsonType": "timestamp", + "description": "上架时间", + "defaultValue": { + "$env": "now" + } + }, + "last_modify_date": { + "bsonType": "timestamp", + "description": "最后修改时间", + "defaultValue": { + "$env": "now" + } + }, + "seller_note": { + "bsonType": "string", + "description": "商家备注,仅商家可见", + "trim": "both", + "permission": { + "read": false + } + } + }, + "version": "0.0.1" +} \ No newline at end of file diff --git a/uniCloud-aliyun/database/ngtools_MeterResult.schema.json b/uniCloud-aliyun/database/ngtools_MeterResult.schema.json new file mode 100644 index 0000000..0c7baa2 --- /dev/null +++ b/uniCloud-aliyun/database/ngtools_MeterResult.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"createTime":{"description":"创建时间","bsonType":"datetime","title":"创建时间","trim":"both"},"createBy":{"description":"创建人","bsonType":"string","title":"创建人","trim":"both"},"updateTime":{"description":"更新时间","bsonType":"datetime","title":"更新时间","trim":"both"},"updateBy":{"description":"更新人","bsonType":"string","title":"更新人","trim":"both"},"meterID":{"description":"计量点编号","bsonType":"string","title":"计量点编号","trim":"both"},"dCd":{"description":"流出系数","bsonType":"string","title":"流出系数","trim":"both"},"dE":{"description":"渐近速度系数 E","bsonType":"string","title":"求渐近速度系数 E","trim":"both"},"dFG":{"description":"相对密度系数 FG","bsonType":"string","title":"求相对密度系数 FG","trim":"both"},"dFT":{"description":"流动温度系数 FT","bsonType":"string","title":"求流动温度系数 FT","trim":"both"},"dDViscosity":{"description":"动力粘度dlnd","bsonType":"string","title":"求动力粘度dlnd","trim":"both"},"dDExpCoefficient":{"description":"可膨胀系数","bsonType":"string","title":"求可膨胀系数","trim":"both"},"dRnPipe":{"description":"管道雷诺数","bsonType":"string","title":"管道雷诺数","trim":"both"},"dBk":{"description":"孔板锐利度系数Bk","bsonType":"string","title":"孔板锐利度系数Bk","trim":"both"},"dRoughNessPipe":{"description":"管道粗糙度系数Gme","bsonType":"string","title":"管道粗糙度系数Gme","trim":"both"},"dCdCorrect":{"description":"修正后的流出系数","bsonType":"string","title":"修正后的流出系数","trim":"both"},"dCdNozell":{"description":"喷嘴的流出系数","bsonType":"string","title":"喷嘴的流出系数","trim":"both"},"dVFlowb":{"description":"标况体积流量m³\/s","bsonType":"string","title":"标况体积流量m³\/s","trim":"both"},"dVFlowf":{"description":"工况体积流量","bsonType":"string","title":"工况体积流量","trim":"both"},"dMFlowb":{"description":"标况质量流量","bsonType":"string","title":"标况质量流量","trim":"both"},"dEFlowb":{"description":"标况能量流量","bsonType":"string","title":"标况能量流量","trim":"both"},"dVelocityFlow":{"description":"管道内天然气流速","bsonType":"string","title":"管道内天然气流速","trim":"both"},"dPressLost":{"description":"压力损失","bsonType":"string","title":"压力损失","trim":"both"},"dBeta":{"description":"直径比","bsonType":"string","title":"直径比","trim":"both"},"dKappa":{"description":"等熵指数","bsonType":"string","title":"等熵指数","trim":"both"}}} \ No newline at end of file diff --git a/uniCloud-aliyun/database/ngtools_NGResult.schema.json b/uniCloud-aliyun/database/ngtools_NGResult.schema.json new file mode 100644 index 0000000..5d843e2 --- /dev/null +++ b/uniCloud-aliyun/database/ngtools_NGResult.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"adMixture":{"description":"摩尔组成","bsonType":"string","title":"摩尔组成","trim":"both"},"adMixtureV":{"description":"体积组成","bsonType":"string","title":"体积组成","trim":"both"},"adMixtureD":{"description":"质量组成","bsonType":"string","title":"质量组成","trim":"both"},"dCbtj":{"description":"参比条件","bsonType":"string","title":"参比条件","trim":"both"},"dPb":{"description":"参比压力","bsonType":"string","title":"参比压力","trim":"both"},"dTb":{"description":"参比温度","bsonType":"string","title":"参比温度","trim":"both"},"dPf":{"description":"绝对压力","bsonType":"string","title":"绝对压力","trim":"both"},"dTf":{"description":"工况温度","bsonType":"string","title":"工况温度","trim":"both"},"dMrx":{"description":"分子量","bsonType":"string","title":"分子量","trim":"both"},"dZb":{"description":"标况压缩因子","bsonType":"string","title":"标况压缩因子","trim":"both"},"dZf":{"description":"工况压缩因子","bsonType":"string","title":"工况压缩因子","trim":"both"},"dFpv":{"description":"超压缩系数","bsonType":"string","title":"超压缩系数","trim":"both"},"dDb":{"description":"标况摩尔密度","bsonType":"string","title":"标况摩尔密度","trim":"both"},"dDf":{"description":"工况摩尔密度","bsonType":"string","title":"工况摩尔密度","trim":"both"},"dRhob":{"description":"标况质量密度","bsonType":"string","title":"标况质量密度","trim":"both"},"dRhof":{"description":"工况质量密度","bsonType":"string","title":"工况质量密度","trim":"both"},"dRD_Ideal":{"description":"理想气体的相对密度","bsonType":"string","title":"理想气体的相对密度","trim":"both"},"dRD_Real":{"description":"真实气体的相对密度","bsonType":"string","title":"真实气体的相对密度","trim":"both"},"dHo":{"description":"理想气体的比焓","bsonType":"string","title":"理想气体的比焓","trim":"both"},"dH":{"description":"真实气体的焓","bsonType":"string","title":"真实气体的焓","trim":"both"},"dS":{"description":"真实气体的熵","bsonType":"string","title":"真实气体的熵","trim":"both"},"dCpi":{"description":"理想气体定压热容","bsonType":"string","title":"理想气体定压热容","trim":"both"},"dCp":{"description":"定压热容","bsonType":"string","title":"定压热容","trim":"both"},"dCv":{"description":"定容积热容","bsonType":"string","title":"定容积热容","trim":"both"},"dk":{"description":"比热比","bsonType":"string","title":"比热比","trim":"both"},"dKappa":{"description":"等熵指数","bsonType":"string","title":"等熵指数","trim":"both"},"dSOS":{"description":"声速","bsonType":"string","title":"声速","trim":"both"},"dCstar":{"description":"临界流函数","bsonType":"string","title":"临界流函数","trim":"both"},"dHhvMol":{"description":"摩尔高位发热量","bsonType":"string","title":"摩尔高位发热量","trim":"both"},"dLhvMol":{"description":"摩尔低位发热量","bsonType":"string","title":"摩尔低位发热量","trim":"both"},"dHhvv":{"description":"体积高位发热量","bsonType":"string","title":"体积高位发热量","trim":"both"},"dLhvv":{"description":"体积低位发热量","bsonType":"string","title":"体积低位发热量","trim":"both"},"dHhvm":{"description":"质量高位发热量","bsonType":"string","title":"质量高位发热量","trim":"both"},"dLhvm":{"description":"质量地位发热量","bsonType":"string","title":"质量地位发热量","trim":"both"},"dZb11062":{"description":"标况压缩因子","bsonType":"string","title":"标况压缩因子","trim":"both"},"dRhob11062":{"description":"标况质量密度","bsonType":"string","title":"标况质量密度","trim":"both"},"dRhof11062":{"description":"工况质量密度","bsonType":"string","title":"工况质量密度","trim":"both"},"dRD_Ideal11062":{"description":"理想气体的相对密度","bsonType":"string","title":"理想气体的相对密度","trim":"both"},"dRD_Real11062":{"description":"真实气体的相对密度","bsonType":"string","title":"真实气体的相对密度","trim":"both"},"dWobbeIndex":{"description":"真实气体的沃泊指数","bsonType":"string","title":"真实气体的沃泊指数","trim":"both"},"Pc":{"description":"临界压力","bsonType":"string","title":"临界压力","trim":"both"},"TC":{"description":"临界温度","bsonType":"string","title":"临界温度","trim":"both"},"Bzsx":{"description":"爆炸上限","bsonType":"string","title":"爆炸上限","trim":"both"},"Bzxx":{"description":"爆炸下限","bsonType":"string","title":"爆炸下限","trim":"both"},"TotalC":{"description":"总炭含量","bsonType":"string","title":"总炭含量","trim":"both"},"C2":{"description":"C2组分含量","bsonType":"string","title":"C2组分含量","trim":"both"},"C2j":{"description":"C2以上组分含量","bsonType":"string","title":"C2以上组分含量","trim":"both"},"C3j":{"description":"C3以上组分含量","bsonType":"string","title":"C3以上组分含量","trim":"both"},"C4j":{"description":"C4以上组分含量","bsonType":"string","title":"C4以上组分含量","trim":"both"},"C5j":{"description":"C5以上组分含量","bsonType":"string","title":"C5以上组分含量","trim":"both"},"C6j":{"description":"C6以上组分含量","bsonType":"string","title":"C6以上组分含量","trim":"both"},"C3C4":{"description":"C3C4组分含量","bsonType":"string","title":"C3C4组分含量","trim":"both"},"createTime":{"description":"创建时间","bsonType":"datetime","title":"创建时间","trim":"both"},"createBy":{"description":"创建人","bsonType":"string","title":"创建人","trim":"both"},"updateTime":{"description":"更新时间","bsonType":"datetime","title":"更新时间","trim":"both"},"updateBy":{"description":"更新人","bsonType":"string","title":"更新人","trim":"both"}}} \ No newline at end of file diff --git a/uniCloud-aliyun/database/ngtools_information.schema.json b/uniCloud-aliyun/database/ngtools_information.schema.json new file mode 100644 index 0000000..0810463 --- /dev/null +++ b/uniCloud-aliyun/database/ngtools_information.schema.json @@ -0,0 +1,65 @@ +{ + "bsonType": "object", + "required": ["infoName"], + "permission": { + "read": true, + "create": true, + "update": true, + "delete": true + }, + "properties": { + "_id": { + "description": "ID,系统自动生成" + }, + "infoName": { + "bsonType": "string", + "description": "资料名称", + "title": "资料名称", + "parentKey": "_id" + }, + "infomation": { + "bsonType": "string", + "description": "资料内容", + "title": "资料内容", + "trim": "both", + "length": 10000 + }, + "infoSouce": { + "bsonType": "string", + "description": "资料来源", + "title": "资料来源", + "trim": "both" + }, + "infoType": { + "bsonType": "string", + "description": "资料类型", + "title": "资料类型", + "trim": "both" + }, + "createTime": { + "description": "创建时间", + "bsonType": "datetime", + "title": "创建时间", + "trim": "both" + }, + "createBy": { + "description": "创建人", + "bsonType": "string", + "title": "创建人", + "trim": "both" + }, + "updateTime": { + "description": "更新时间", + "bsonType": "datetime", + "title": "更新时间", + "trim": "both" + }, + "updateBy": { + "description": "更新人", + "bsonType": "string", + "title": "更新人", + "trim": "both" + } + }, + "version": "0.1.1" +} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-admin-menus.init_data.json b/uniCloud-aliyun/database/opendb-admin-menus.init_data.json new file mode 100644 index 0000000..43f3f3b --- /dev/null +++ b/uniCloud-aliyun/database/opendb-admin-menus.init_data.json @@ -0,0 +1,453 @@ +[ + { + "menu_id": "index", + "name": "首页", + "icon": "uni-icons-home", + "url": "/", + "sort": 100, + "parent_id": "", + "permission": [], + "enable": true, + "create_date": 1602662469396 + }, + { + "menu_id": "system_management", + "name": "系统管理", + "icon": "admin-icons-fl-xitong", + "url": "", + "sort": 1000, + "parent_id": "", + "permission": [], + "enable": true, + "create_date": 1602662469396 + }, + { + "menu_id": "system_user", + "name": "用户管理", + "icon": "admin-icons-manager-user", + "url": "/pages/system/user/list", + "sort": 1010, + "parent_id": "system_management", + "permission": [], + "enable": true, + "create_date": 1602662469398 + }, + { + "menu_id": "system_role", + "name": "角色管理", + "icon": "admin-icons-manager-role", + "url": "/pages/system/role/list", + "sort": 1020, + "parent_id": "system_management", + "permission": [], + "enable": true, + "create_date": 1602662469397 + }, + { + "menu_id": "system_permission", + "name": "权限管理", + "icon": "admin-icons-manager-permission", + "url": "/pages/system/permission/list", + "sort": 1030, + "parent_id": "system_management", + "permission": [], + "enable": true, + "create_date": 1602662469396 + }, + { + "menu_id": "system_menu", + "name": "菜单管理", + "icon": "admin-icons-manager-menu", + "url": "/pages/system/menu/list", + "sort": 1040, + "parent_id": "system_management", + "permission": [], + "enable": true, + "create_date": 1602662469396 + }, + { + "menu_id": "system_app", + "name": "应用管理", + "icon": "admin-icons-manager-app", + "url": "/pages/system/app/list", + "sort": 1035, + "parent_id": "system_management", + "permission": [], + "enable": true, + "create_date": 1602662469399 + }, + { + "menu_id": "system_update", + "name": "App升级中心", + "icon": "uni-icons-cloud-upload", + "url": "/uni_modules/uni-upgrade-center/pages/version/list", + "sort": 1036, + "parent_id": "system_management", + "permission": [], + "enable": true, + "create_date": 1656491532434 + }, + { + "menu_id": "system_tag", + "name": "标签管理", + "icon": "admin-icons-manager-tag", + "url": "/pages/system/tag/list", + "sort": 1037, + "parent_id": "system_management", + "permission": [], + "enable": true, + "create_date": 1602662479389 + }, + { + "permission": [], + "enable": true, + "menu_id": "safety_statistics", + "name": "安全审计", + "icon": "admin-icons-safety", + "url": "", + "sort": 3100, + "parent_id": "", + "create_date": 1638356430871 + }, + { + "permission": [], + "enable": true, + "menu_id": "safety_statistics_user_log", + "name": "用户日志", + "icon": "", + "url": "/pages/system/safety/list", + "sort": 3101, + "parent_id": "safety_statistics", + "create_date": 1638356430871 + }, + { + "permission": [], + "enable": true, + "menu_id": "uni-stat", + "name": "uni 统计", + "icon": "admin-icons-tongji", + "url": "", + "sort": 2100, + "parent_id": "", + "create_date": 1638356430871 + }, + { + "parent_id": "uni-stat", + "permission": [], + "enable": true, + "menu_id": "uni-stat-device", + "name": "设备统计", + "icon": "admin-icons-shebeitongji", + "url": "", + "sort": 2120, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-device", + "permission": [], + "enable": true, + "menu_id": "uni-stat-device-overview", + "name": "概况", + "icon": "", + "url": "/pages/uni-stat/device/overview/overview", + "sort": 2121, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-device", + "permission": [], + "enable": true, + "menu_id": "uni-stat-device-activity", + "name": "活跃度", + "icon": "", + "url": "/pages/uni-stat/device/activity/activity", + "sort": 2122, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-device", + "permission": [], + "enable": true, + "menu_id": "uni-stat-device-trend", + "name": "趋势分析", + "icon": "", + "url": "/pages/uni-stat/device/trend/trend", + "sort": 2123, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-device", + "permission": [], + "enable": true, + "menu_id": "uni-stat-device-retention", + "name": "留存", + "icon": "", + "url": "/pages/uni-stat/device/retention/retention", + "sort": 2124, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-device", + "permission": [], + "enable": true, + "menu_id": "uni-stat-device-comparison", + "name": "平台对比", + "icon": "", + "url": "/pages/uni-stat/device/comparison/comparison", + "sort": 2125, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-device", + "permission": [], + "enable": true, + "menu_id": "uni-stat-device-stickiness", + "name": "粘性", + "icon": "", + "url": "/pages/uni-stat/device/stickiness/stickiness", + "sort": 2126, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat", + "permission": [], + "enable": true, + "menu_id": "uni-stat-user", + "name": "注册用户统计", + "icon": "admin-icons-yonghutongji", + "url": "", + "sort": 2122, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-user", + "permission": [], + "enable": true, + "menu_id": "uni-stat-user-overview", + "name": "概况", + "icon": "", + "url": "/pages/uni-stat/user/overview/overview", + "sort": 2121, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-user", + "permission": [], + "enable": true, + "menu_id": "uni-stat-user-activity", + "name": "活跃度", + "icon": "", + "url": "/pages/uni-stat/user/activity/activity", + "sort": 2122, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-user", + "permission": [], + "enable": true, + "icon": "", + "menu_id": "uni-stat-user-trend", + "name": "趋势分析", + "url": "/pages/uni-stat/user/trend/trend", + "sort": 2123, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-user", + "permission": [], + "enable": true, + "menu_id": "uni-stat-user-retention", + "name": "留存", + "icon": "", + "url": "/pages/uni-stat/user/retention/retention", + "sort": 2124, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-user", + "permission": [], + "enable": true, + "menu_id": "uni-stat-user-comparison", + "name": "平台对比", + "icon": "", + "url": "/pages/uni-stat/user/comparison/comparison", + "sort": 2125, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-user", + "permission": [], + "enable": true, + "menu_id": "uni-stat-user-stickiness", + "name": "粘性", + "icon": "", + "url": "/pages/uni-stat/user/stickiness/stickiness", + "sort": 2126, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat", + "permission": [], + "enable": true, + "menu_id": "uni-stat-page-analysis", + "name": "页面统计", + "icon": "admin-icons-page-ent", + "url": "", + "sort": 2123, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-page-analysis", + "permission": [], + "enable": true, + "menu_id": "uni-stat-page-res", + "name": "受访页", + "icon": "", + "url": "/pages/uni-stat/page-res/page-res", + "sort": 2131, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-page-analysis", + "permission": [], + "enable": true, + "menu_id": "uni-stat-page-ent", + "name": "入口页", + "icon": "", + "url": "/pages/uni-stat/page-ent/page-ent", + "sort": 2132, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat", + "permission": [], + "enable": true, + "menu_id": "uni-stat-senceChannel", + "name": "渠道/场景值分析", + "icon": "admin-icons-qudaofenxi", + "url": "", + "sort": 2150, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-senceChannel", + "permission": [], + "enable": true, + "menu_id": "uni-stat-senceChannel-scene", + "name": "场景值(小程序)", + "icon": "", + "url": "/pages/uni-stat/scene/scene", + "sort": 2151, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-senceChannel", + "permission": [], + "enable": true, + "menu_id": "uni-stat-senceChannel-channel", + "name": "渠道(app)", + "icon": "", + "url": "/pages/uni-stat/channel/channel", + "sort": 2152, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat", + "permission": [], + "enable": true, + "menu_id": "uni-stat-event-event", + "name": "自定义事件", + "icon": "admin-icons-shijianfenxi", + "url": "/pages/uni-stat/event/event", + "sort": 2160, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat", + "permission": [], + "enable": true, + "menu_id": "uni-stat-error", + "name": "错误统计", + "icon": "admin-icons-cuowutongji", + "url": "", + "sort": 2170, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-error", + "permission": [], + "enable": true, + "menu_id": "uni-stat-error-js", + "name": "js报错", + "icon": "", + "url": "/pages/uni-stat/error/js/js", + "sort": 2171, + "create_date": 1638356902516 + }, + { + "parent_id": "uni-stat-error", + "permission": [], + "enable": true, + "menu_id": "uni-stat-error-app", + "name": "app崩溃", + "icon": "", + "url": "/pages/uni-stat/error/app/app", + "sort": 2172, + "create_date": 1638356902516 + }, + { + "menu_id": "uni-stat-pay", + "name": "支付统计", + "icon": "uni-icons-circle", + "url": "", + "sort": 2122, + "parent_id": "uni-stat", + "permission": [], + "enable": true, + "create_date": 1667386977981 + }, + { + "menu_id": "uni-stat-pay-overview", + "name": "概况", + "icon": "", + "url": "/pages/uni-stat/pay-order/overview/overview", + "sort": 21221, + "parent_id": "uni-stat-pay", + "permission": [], + "enable": true, + "create_date": 1667387038602 + }, + { + "menu_id": "uni-stat-pay-funnel", + "name": "转换漏斗分析", + "icon": "", + "url": "/pages/uni-stat/pay-order/funnel/funnel", + "sort": 21222, + "parent_id": "uni-stat-pay", + "permission": [], + "enable": true, + "create_date": 1668430092890 + }, + { + "menu_id": "uni-stat-pay-ranking", + "name": "价值用户排行", + "icon": "", + "url": "/pages/uni-stat/pay-order/ranking/ranking", + "sort": 21223, + "parent_id": "uni-stat-pay", + "permission": [], + "enable": true, + "create_date": 1668430128302 + }, + { + "menu_id": "uni-stat-pay-order-list", + "name": "订单明细", + "icon": "", + "url": "/pages/uni-stat/pay-order/list/list", + "sort": 21224, + "parent_id": "uni-stat-pay", + "permission": [], + "enable": true, + "create_date": 1667387078947 + } +] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-admin-menus.schema.json b/uniCloud-aliyun/database/opendb-admin-menus.schema.json new file mode 100644 index 0000000..647e1c8 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-admin-menus.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["name","menu_id"],"properties":{"_id":{"description":"存储文档 ID,系统自动生成"},"menu_id":{"bsonType":"string","description":"菜单项的ID,不可重复","trim":"both"},"name":{"bsonType":"string","description":"菜单名称","trim":"both"},"icon":{"bsonType":"string","description":"菜单图标","trim":"both"},"url":{"bsonType":"string","description":"菜单url","trim":"both"},"comment":{"bsonType":"string","description":"备注,菜单说明"},"sort":{"bsonType":"int","description":"菜单序号(越大越靠后)"},"parent_id":{"bsonType":"string","description":"父级菜单Id"},"permission":{"bsonType":"array","description":"菜单权限列表"},"enable":{"bsonType":"bool","description":"是否启用菜单,true启用、false禁用"},"create_date":{"bsonType":"timestamp","description":"菜单创建时间","forceDefaultValue":{"$env":"now"}}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-app-list.init_data.json b/uniCloud-aliyun/database/opendb-app-list.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-app-list.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-app-list.schema.json b/uniCloud-aliyun/database/opendb-app-list.schema.json new file mode 100644 index 0000000..2777188 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-app-list.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["appid","name"],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"应用的AppID","label":"AppID","componentForEdit":{"name":"uni-easyinput","props":{":disabled":true}}},"name":{"bsonType":"string","description":"应用名称","label":"应用名称","componentForEdit":{"name":"uni-easyinput","props":{":disabled":true}}},"description":{"bsonType":"string","description":"应用描述","label":"应用描述","componentForEdit":{"name":"textarea"},"componentForShow":{"name":"textarea","props":{":disabled":true}}},"creator_uid":{"description":"创建者的user_id,创建者必然是用户,不随应用转让而改变","bsonType":"string"},"owner_type":{"bsonType":"int","description":"应用当前归属者类型,1:个人,2:企业"},"owner_id":{"bsonType":"string","description":"应用当前归属者的id,user_id or enterprise_id"},"managers":{"bsonType":"array","description":"应用管理员ID列表"},"members":{"bsonType":"array","description":"团队成员ID列表"},"icon_url":{"bsonType":"string","trim":"both","description":"应用图标链接","label":"应用图标"},"introduction":{"bsonType":"string","trim":"both","description":"应用简介","label":"应用简介","componentForEdit":{"name":"uni-easyinput","props":{"disabled":true}}},"screenshot":{"bsonType":"array","description":"应用截图","label":"应用截图"},"app_android":{"bsonType":"object","description":"安卓 App 相关信息","properties":{"name":{"bsonType":"string","description":"快应用名称","label":"快应用名称"},"url":{"bsonType":"string","description":"安卓可下载安装包地址","label":"安卓下载地址"}}},"app_ios":{"bsonType":"object","description":"苹果 App 相关信息","properties":{"name":{"bsonType":"string","description":"快应用名称","label":"快应用名称"},"url":{"bsonType":"string","description":"AppStore 上架地址","label":"AppStore 地址"}}},"mp_weixin":{"bsonType":"object","description":"微信小程序相关信息","label":"微信小程序","properties":{"name":{"bsonType":"string","description":"小程序名字"},"qrcode_url":{"bsonType":"string","description":"二维码url"}}},"mp_alipay":{"bsonType":"object","description":"支付宝小程序相关信息","label":"支付宝小程序","properties":{"name":{"bsonType":"string","description":"小程序名字"},"qrcode_url":{"bsonType":"string","description":"二维码url"}}},"mp_baidu":{"bsonType":"object","description":"百度小程序相关信息","label":"百度小程序","properties":{"name":{"bsonType":"string","description":"小程序名字"},"qrcode_url":{"bsonType":"string","description":"二维码url"}}},"mp_toutiao":{"bsonType":"object","description":"头条小程序相关信息","label":"头条小程序","properties":{"name":{"bsonType":"string","description":"小程序名字"},"qrcode_url":{"bsonType":"string","description":"二维码url"}}},"mp_qq":{"bsonType":"object","description":"QQ小程序相关信息","label":"QQ小程序","properties":{"name":{"bsonType":"string","description":"小程序名字"},"qrcode_url":{"bsonType":"string","description":"二维码url"}}},"mp_kuaishou":{"bsonType":"object","description":"快手小程序相关信息","label":"快手小程序","properties":{"name":{"bsonType":"string","description":"小程序名字"},"qrcode_url":{"bsonType":"string","description":"二维码url"}}},"mp_lark":{"bsonType":"object","description":"飞书小程序相关信息","label":"飞书小程序","properties":{"name":{"bsonType":"string","description":"小程序名字"},"qrcode_url":{"bsonType":"string","description":"二维码url"}}},"mp_jd":{"bsonType":"object","description":"京东小程序相关信息","label":"京东小程序","properties":{"name":{"bsonType":"string","description":"小程序名字"},"qrcode_url":{"bsonType":"string","description":"二维码url"}}},"mp_dingtalk":{"bsonType":"object","description":"钉钉小程序相关信息","label":"钉钉小程序","properties":{"name":{"bsonType":"string","description":"小程序名字"},"qrcode_url":{"bsonType":"string","description":"二维码url"}}},"h5":{"bsonType":"object","properties":{"url":{"bsonType":"string","description":"H5 可访问链接"}}},"quickapp":{"bsonType":"object","properties":{"name":{"bsonType":"string","description":"快应用名称","label":"快应用名称"},"qrcode_url":{"bsonType":"string","description":"快应用二维码url"}}},"store_list":{"bsonType":"array","description":"发布的应用市场","label":"应用市场","properties":{"id":{"bsonType":"string","description":"应用id,自动生成","label":"id"},"name":{"bsonType":"string","description":"应用名称","label":"应用名称"},"scheme":{"bsonType":"string","description":"应用 scheme","label":"应用 scheme"},"enable":{"bsonType":"bool","description":"是否启用"},"priority":{"bsonType":"int","description":"按照从大到小排序","label":"优先级"}}},"create_date":{"bsonType":"timestamp","label":"创建时间","forceDefaultValue":{"$env":"now"},"componentForEdit":{"name":"uni-dateformat"}}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-app-versions.init_data.json b/uniCloud-aliyun/database/opendb-app-versions.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-app-versions.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-app-versions.schema.json b/uniCloud-aliyun/database/opendb-app-versions.schema.json new file mode 100644 index 0000000..13fb7f7 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-app-versions.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["appid","uni_platform","version","type","create_env"],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"记录id,自动生成"},"appid":{"bsonType":"string","trim":"both","description":"应用的AppID","label":"AppID","componentForEdit":{"name":"uni-easyinput","props":{"disabled":true}}},"name":{"bsonType":"string","trim":"both","description":"应用名称","label":"应用名称","componentForEdit":{"name":"uni-easyinput","props":{"disabled":true}}},"title":{"bsonType":"string","description":"更新标题","label":"更新标题"},"contents":{"bsonType":"string","description":"更新内容","label":"更新内容","componentForEdit":{"name":"textarea"},"componentForShow":{"name":"textarea","props":{"disabled":true}}},"platform":{"bsonType":"array","enum":[{"value":"Android","text":"安卓"},{"value":"iOS","text":"苹果"}],"description":"更新平台,Android || iOS || [Android, iOS]","label":"平台"},"type":{"bsonType":"string","enum":[{"value":"native_app","text":"原生App安装包"},{"value":"wgt","text":"Wgt资源包"}],"description":"安装包类型,native_app || wgt","label":"安装包类型"},"uni_platform":{"bsonType":"string","description":"uni平台信息,如:mp-weixin\/web\/ios\/android","label":"uni 平台"},"version":{"bsonType":"string","description":"当前包版本号,必须大于当前线上发行版本号","label":"版本号"},"min_uni_version":{"bsonType":"string","description":"原生App最低版本","label":"原生App最低版本"},"url":{"bsonType":"string","description":"可下载或跳转的链接","label":"链接"},"stable_publish":{"bsonType":"bool","description":"是否上线发行","label":"上线发行"},"is_silently":{"bsonType":"bool","description":"是否静默更新","label":"静默更新","defaultValue":false},"is_mandatory":{"bsonType":"bool","description":"是否强制更新","label":"强制更新","defaultValue":false},"create_date":{"bsonType":"timestamp","label":"上传时间","forceDefaultValue":{"$env":"now"},"componentForEdit":{"name":"uni-dateformat"}},"create_env":{"bsonType":"string","description":"创建来源,uni-stat:uni统计自动创建,upgrade-center:升级中心管理员创建"},"store_list":{"bsonType":"array","description":"发布的应用市场","label":"应用市场","properties":{"id":{"bsonType":"string","description":"应用id,自动生成","label":"id"},"name":{"bsonType":"string","description":"应用名称","label":"应用名称"},"scheme":{"bsonType":"string","description":"应用 scheme","label":"应用 scheme"},"enable":{"bsonType":"bool","description":"是否启用"},"priority":{"bsonType":"int","description":"按照从大到小排序","label":"优先级"}}}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-banner.init_data.json b/uniCloud-aliyun/database/opendb-banner.init_data.json new file mode 100644 index 0000000..19655d8 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-banner.init_data.json @@ -0,0 +1,41 @@ +[ + { + "status": true, + "bannerfile": { + "name": "094a9dc0-50c0-11eb-b680-7980c8a877b8.jpg", + "extname": "jpg", + "fileType": "image", + "url": "https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg", + "size": 70880, + "image": { + "width": 500, + "height": 333 + }, + "path": "https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg" + }, + "open_url": "https://www.dcloud.io/", + "title": "测试", + "sort": 1, + "category_id": "", + "description": "" + }, + { + "status": true, + "bannerfile": { + "name": "094a9dc0-50c0-11eb-b680-7980c8a877b8.jpg", + "extname": "jpg", + "fileType": "image", + "url": "https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg", + "size": 70880, + "image": { + "width": 500, + "height": 333 + }, + "path": "https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg" + }, + "open_url": "https://www.dcloud.io/", + "title": "", + "category_id": "", + "description": "" + } +] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-banner.schema.json b/uniCloud-aliyun/database/opendb-banner.schema.json new file mode 100644 index 0000000..cbaa578 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-banner.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["bannerfile"],"permission":{"read":true,"create":true,"update":true,"delete":true},"properties":{"_id":{"description":"ID,系统自动生成"},"bannerfile":{"bsonType":"file","fileMediaType":"image","title":"图片文件","description":"图片文件信息,包括文件名、url等"},"open_url":{"bsonType":"string","description":"点击跳转目标地址。如果是web地址则使用内置web-view打开;如果是本地页面则跳转本地页面;如果是schema地址则打开本地的app","title":"点击目标地址","format":"url","pattern":"^(http:\/\/|https:\/\/|\/|.\/|@\/)\\S","trim":"both"},"title":{"bsonType":"string","description":"注意标题文字颜色和背景图靠色导致看不清的问题","maxLength":20,"title":"标题","trim":"both"},"sort":{"bsonType":"int","description":"数字越小,排序越前","title":"排序"},"category_id":{"bsonType":"string","description":"多个栏目的banner都存在一个表里时可用这个字段区分","title":"分类id"},"status":{"bsonType":"bool","defaultValue":true,"title":"生效状态"},"description":{"bsonType":"string","description":"维护者自用描述","title":"备注","trim":"both"}}} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-department.init_data.json b/uniCloud-aliyun/database/opendb-department.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-department.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-department.schema.json b/uniCloud-aliyun/database/opendb-department.schema.json new file mode 100644 index 0000000..9cfc2e9 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-department.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["name"],"permission":{"read":true,"create":true,"update":true,"delete":true},"properties":{"_id":{"description":"ID,系统自动生成"},"parent_id":{"bsonType":"string","description":"父级部门ID","parentKey":"_id"},"name":{"bsonType":"string","description":"部门名称","title":"部门名称","trim":"both"},"level":{"bsonType":"int","description":"部门层级,为提升检索效率而作的冗余设计"},"sort":{"bsonType":"int","description":"部门在当前层级下的顺序,由小到大","title":"显示顺序"},"manager_uid":{"bsonType":"string","description":"部门主管的userid, 参考`uni-id-users` 表","foreignKey":"uni-id-users._id"},"create_date":{"bsonType":"timestamp","description":"部门创建时间","forceDefaultValue":{"$env":"now"}},"status":{"bsonType":"int","description":"部门状态,0-正常、1-禁用"}},"version":"0.1.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-device.init_data.json b/uniCloud-aliyun/database/opendb-device.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-device.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-device.schema.json b/uniCloud-aliyun/database/opendb-device.schema.json new file mode 100644 index 0000000..3143026 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-device.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"DCloud appid"},"device_id":{"bsonType":"string","description":"设备唯一标识"},"vendor":{"bsonType":"string","description":"设备厂商"},"push_clientid":{"bsonType":"string","description":"推送设备客户端标识"},"imei":{"bsonType":"string","description":"国际移动设备识别码IMEI(International Mobile Equipment Identity)"},"oaid":{"bsonType":"string","description":"移动智能设备标识公共服务平台提供的匿名设备标识符(OAID)"},"idfa":{"bsonType":"string","description":"iOS平台配置应用使用广告标识(IDFA)"},"imsi":{"bsonType":"string","description":"国际移动用户识别码(International Mobile Subscriber Identification Number)"},"model":{"bsonType":"string","description":"设备型号"},"platform":{"bsonType":"string","description":"平台类型"},"uni_platform":{"bsonType":"string","description":"uni-app 运行平台,与条件编译平台相同。"},"os_name":{"bsonType":"string","description":"ios|android|windows|mac|linux "},"os_version":{"bsonType":"string","description":"操作系统版本号 "},"os_language":{"bsonType":"string","description":"操作系统语言 "},"os_theme":{"bsonType":"string","description":"操作系统主题 light|dark"},"pixel_ratio":{"bsonType":"string","description":"设备像素比 "},"network_model":{"bsonType":"string","description":"设备网络型号wifi\/3G\/4G\/"},"window_width":{"bsonType":"string","description":"设备窗口宽度 "},"window_height":{"bsonType":"string","description":"设备窗口高度"},"screen_width":{"bsonType":"string","description":"设备屏幕宽度"},"screen_height":{"bsonType":"string","description":"设备屏幕高度"},"rom_name":{"bsonType":"string","description":"rom 名称"},"rom_version":{"bsonType":"string","description":"rom 版本"},"location_latitude":{"bsonType":"double","description":"纬度"},"location_longitude":{"bsonType":"double","description":"经度"},"location_country":{"bsonType":"string","description":"国家"},"location_province":{"bsonType":"string","description":"省份"},"location_city":{"bsonType":"string","description":"城市"},"create_date":{"bsonType":"timestamp","description":"创建时间","forceDefaultValue":{"$env":"now"}},"last_update_date":{"bsonType":"timestamp","description":"最后一次修改时间","forceDefaultValue":{"$env":"now"}}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-feedback.init_data.json b/uniCloud-aliyun/database/opendb-feedback.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-feedback.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-feedback.schema.json b/uniCloud-aliyun/database/opendb-feedback.schema.json new file mode 100644 index 0000000..2841180 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-feedback.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["user_id","content"],"properties":{"_id":{"description":"ID,系统自动生成"},"user_id":{"bsonType":"string","description":"留言反馈用户ID\/回复留言用户ID,参考uni-id-users表","foreignKey":"uni-id-users._id"},"create_date":{"bsonType":"timestamp","description":"留言时间\/回复留言时间"},"content":{"bsonType":"string","description":"留言内容\/回复内容","trim":"right"},"imgs":{"bsonType":"array","description":"图片列表"},"is_reply":{"bsonType":"bool","description":"是否是回复类型"},"feedback_id":{"bsonType":"string","description":"被回复留言ID"},"contact":{"bsonType":"string","description":"联系人","trim":"both"},"mobile":{"bsonType":"string","description":"联系电话","trim":"both"},"reply_count":{"bsonType":"int","description":"被回复条数"}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-news-articles.init_data.json b/uniCloud-aliyun/database/opendb-news-articles.init_data.json new file mode 100644 index 0000000..4102a4a --- /dev/null +++ b/uniCloud-aliyun/database/opendb-news-articles.init_data.json @@ -0,0 +1,17 @@ +[ + { + "title": "阿里小程序IDE官方内嵌uni-app,为开发者提供多端开发服务", + "excerpt": "阿里小程序IDE官方内嵌uni-app,为开发者提供多端开发服务", + "content": "

随着微信、阿里、百度、头条、QQ纷纷推出小程序,开发者的开发维护成本持续上升,负担过重。这点已经成为共识,现在连小程序平台厂商也充分意识到了。

\n

阿里小程序团队,为了减轻开发者的负担,在官方的小程序开发者工具中整合了多端框架。

\n

经过阿里团队仔细评估,uni-app 在产品完成度、跨平台支持度、开发者社区、可持续发展等多方面优势明显,最终选定 uni-app内置于阿里小程序开发工具中,为开发者提供多端开发解决方案。

\n

经过之前1个月的公测,10月10日,阿里小程序正式发布0.70版开发者工具,通过 uni-app 实现多端开发,成为本次版本更新的亮点功能!

\n

如下图,在阿里小程序工具左侧主导航选择 uni-app,创建项目,即可开发。

\n
\n


阿里小程序开发工具更新说明详见:https://docs.alipay.com/mini/ide/0.70-stable

\n

 

\n

集成uni-app,这对于阿里团队而言,并不是一个容易做出的决定。毕竟 uni-app 是一个三方产品,要经过复杂的评审流程。

\n

这一方面突显出阿里团队以开发者需求为本的优秀价值观,另一方面也证明 uni-app的产品确实过硬。

\n

很多开发者都有多端需求,但又没有足够精力去了解、评估 uni-app,而处于观望态度。现在大家可以更放心的使用 uni-app 了,它没有让阿里失望,也不会让你失望。

\n

自从uni-app推出以来,DCloud也取得了高速的发展,目前拥有370万开发者,框架运行在4.6亿手机用户设备上,月活达到1.35亿(仅包括部分接入DCloud统计平台的数据)。并且数据仍在高速增长中,在市场占有率上处于遥遥领先的位置。

\n

本次阿里小程序工具集成 uni-app,会让 uni-app 继续快速爆发,取得更大的成功。

\n

后续DCloud还将深化与阿里的合作,在serverless等领域给开发者提供更多优质服务。

\n

使用多端框架开发各端应用,是多赢的模式。开发者减轻了负担,获得了更多新流量。而小程序平台厂商,也能保证自己平台上的各种应用可以被及时的更新。

\n

DCloud欢迎更多小程序平台厂商,与我们一起合作,为开发者、平台、用户的多赢而努力。

\n

进一步了解uni-app,详见:https://uniapp.dcloud.io

\n

欢迎扫码关注DCloud公众号,转发消息到朋友圈。

", + "avatar": "https://ask.dcloud.net.cn/uploads/article/20191014/56f7dc1bd5f265e824649f7cb4f78d5b.png", + "type": 0, + "user_id": "_uni_starter_test_user_id", + "comment_count": 0, + "like_count": 0, + "comment_status": 0, + "article_status": 1, + "publish_date": 1616092287006, + "last_modify_date": 1616092303031, + "create_date": 1616092287006 + } +] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-news-articles.schema.json b/uniCloud-aliyun/database/opendb-news-articles.schema.json new file mode 100644 index 0000000..39b120e --- /dev/null +++ b/uniCloud-aliyun/database/opendb-news-articles.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["user_id","title","content"],"permission":{"read":"doc.user_id == auth.uid && doc.article_status == 0 || doc.article_status == 1","create":"auth.uid != null","update":"doc.user_id == auth.uid","delete":"doc.user_id == auth.uid"},"properties":{"_id":{"description":"存储文档 ID(用户 ID),系统自动生成"},"user_id":{"bsonType":"string","description":"文章作者ID, 参考`uni-id-users` 表","foreignKey":"uni-id-users._id","defaultValue":{"$env":"uid"}},"category_id":{"bsonType":"string","title":"分类","description":"分类 id,参考`uni-news-categories`表","foreignKey":"opendb-news-categories._id","enum":{"collection":"opendb-news-categories","field":"name as text, _id as value"}},"title":{"bsonType":"string","title":"标题","description":"标题","label":"标题","trim":"both"},"content":{"bsonType":"string","title":"文章内容","description":"文章内容","label":"文章内容","trim":"right"},"excerpt":{"bsonType":"string","title":"文章摘录","description":"文章摘录","label":"摘要","trim":"both"},"article_status":{"bsonType":"int","title":"文章状态","description":"文章状态:0 草稿箱 1 已发布","defaultValue":0,"enum":[{"value":0,"text":"草稿箱"},{"value":1,"text":"已发布"}]},"view_count":{"bsonType":"int","title":"阅读数量","description":"阅读数量","permission":{"write":false}},"like_count":{"bsonType":"int","description":"喜欢数、点赞数","permission":{"write":false}},"is_sticky":{"bsonType":"bool","title":"是否置顶","description":"是否置顶","permission":{"write":false}},"is_essence":{"bsonType":"bool","title":"阅读加精","description":"阅读加精","permission":{"write":false}},"comment_status":{"bsonType":"int","title":"开放评论","description":"评论状态:0 关闭 1 开放","enum":[{"value":0,"text":"关闭"},{"value":1,"text":"开放"}]},"comment_count":{"bsonType":"int","description":"评论数量","permission":{"write":false}},"last_comment_user_id":{"bsonType":"string","description":"最后回复用户 id,参考`uni-id-users` 表","foreignKey":"uni-id-users._id"},"avatar":{"bsonType":"string","title":"封面大图","description":"缩略图地址","label":"封面大图","trim":"both"},"publish_date":{"bsonType":"timestamp","title":"发表时间","description":"发表时间","defaultValue":{"$env":"now"}},"publish_ip":{"bsonType":"string","title":"发布文章时IP地址","description":"发表时 IP 地址","forceDefaultValue":{"$env":"clientIP"}},"last_modify_date":{"bsonType":"timestamp","title":"最后修改时间","description":"最后修改时间","defaultValue":{"$env":"now"}},"last_modify_ip":{"bsonType":"string","description":"最后修改时 IP 地址","forceDefaultValue":{"$env":"clientIP"}},"mode":{"bsonType":"number","title":"排版显示模式","description":"排版显示模式,如左图右文、上图下文等"}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-news-categories.init_data.json b/uniCloud-aliyun/database/opendb-news-categories.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-news-categories.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-news-categories.schema.json b/uniCloud-aliyun/database/opendb-news-categories.schema.json new file mode 100644 index 0000000..6d53846 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-news-categories.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["name"],"permission":{"read":true,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"存储文档 ID(文章 ID),系统自动生成"},"name":{"bsonType":"string","description":"类别名称","label":"名称","trim":"both"},"description":{"bsonType":"string","description":"类别描述","label":"描述","trim":"both"},"icon":{"bsonType":"string","description":"类别图标地址","label":"图标地址","pattern":"^(http:\/\/|https:\/\/|\/|.\/|@\/)\\S","trim":"both"},"sort":{"bsonType":"int","description":"类别显示顺序","label":"排序"},"article_count":{"bsonType":"int","description":"该类别下文章数量"},"create_date":{"bsonType":"timestamp","description":"创建时间","forceDefaultValue":{"$env":"now"}}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-news-comments.init_data.json b/uniCloud-aliyun/database/opendb-news-comments.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-news-comments.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-news-comments.schema.json b/uniCloud-aliyun/database/opendb-news-comments.schema.json new file mode 100644 index 0000000..0a8f73a --- /dev/null +++ b/uniCloud-aliyun/database/opendb-news-comments.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["article_id","user_id","comment_content","like_count","comment_type","reply_user_id","reply_comment_id"],"permission":{"read":true,"create":"auth.uid != null","update":"doc.user_id == auth.uid","delete":"doc.user_id == auth.uid"},"properties":{"_id":{"description":"存储文档 ID(文章 ID),系统自动生成"},"article_id":{"bsonType":"string","description":"文章ID,opendb-news-posts 表中的`_id`字段","foreignKey":"opendb-news-articles._id"},"user_id":{"bsonType":"string","description":"评论者ID,参考`uni-id-users` 表","forceDefaultValue":{"$env":"uid"},"foreignKey":"uni-id-users._id"},"comment_content":{"bsonType":"string","description":"评论内容","title":"评论内容","trim":"right"},"like_count":{"bsonType":"int","description":"评论喜欢数、点赞数"},"comment_type":{"bsonType":"int","description":"回复类型: 0 针对文章的回复 1 针对评论的回复"},"reply_user_id":{"bsonType":"string","description":"被回复的评论用户ID,comment_type为1时有效","foreignKey":"uni-id-users._id"},"reply_comment_id":{"bsonType":"string","description":"被回复的评论ID,comment_type为1时有效","foreignKey":"opendb-news-comments._id"},"comment_date":{"bsonType":"timestamp","description":"评论发表时间","forceDefaultValue":{"$env":"now"}},"comment_ip":{"bsonType":"string","description":"评论发表时 IP 地址","forceDefaultValue":{"$env":"clientIP"}}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-news-favorite.init_data.json b/uniCloud-aliyun/database/opendb-news-favorite.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-news-favorite.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-news-favorite.schema.json b/uniCloud-aliyun/database/opendb-news-favorite.schema.json new file mode 100644 index 0000000..3c642a6 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-news-favorite.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["user_id","article_id"],"permission":{"read":true,"create":"auth.uid != null","update":false,"delete":"doc.user_id == auth.uid"},"properties":{"_id":{"description":"ID,系统自动生成"},"article_id":{"bsonType":"string","description":"文章id,参考opendb-news-articles表","foreignKey":"opendb-news-articles._id"},"user_id":{"bsonType":"string","description":"收藏者id,参考uni-id-users表","forceDefaultValue":{"$env":"uid"},"foreignKey":"uni-id-users._id"},"create_date":{"bsonType":"timestamp","description":"收藏时间","forceDefaultValue":{"$env":"now"}}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-open-data.init_data.json b/uniCloud-aliyun/database/opendb-open-data.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-open-data.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-open-data.schema.json b/uniCloud-aliyun/database/opendb-open-data.schema.json new file mode 100644 index 0000000..8eb8109 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-open-data.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["_id","value"],"properties":{"_id":{"bsonType":"string","description":"key,格式:uni-id:[provider]:[appid]:[openid]:[access-token|user-access-token|session-key|encrypt-key-version|ticket]"},"value":{"bsonType":"object","description":"字段_id对应的值"},"expired":{"bsonType":"timestamp","description":"过期时间"}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-search-hot.init_data.json b/uniCloud-aliyun/database/opendb-search-hot.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-search-hot.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-search-hot.schema.json b/uniCloud-aliyun/database/opendb-search-hot.schema.json new file mode 100644 index 0000000..cc5ba75 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-search-hot.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["content","count"],"permission":{"read":true,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"content":{"bsonType":"string","description":"搜索内容"},"count":{"bsonType":"int","description":"搜索次数"},"create_date":{"bsonType":"timestamp","description":"统计时间"}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-search-log.init_data.json b/uniCloud-aliyun/database/opendb-search-log.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-search-log.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-search-log.schema.json b/uniCloud-aliyun/database/opendb-search-log.schema.json new file mode 100644 index 0000000..8e9ab52 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-search-log.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["content"],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"user_id":{"bsonType":"string","description":"搜索人id,参考uni-id-users表"},"device_uuid":{"bsonType":"string","description":"设备id"},"platform":{"bsonType":"string","description":"设备平台,如:mp-weixin、app-plus等"},"content":{"bsonType":"string","description":"搜索内容"},"ip":{"bsonType":"string","description":"客户端IP地址","forceDefaultValue":{"$env":"clientIP"}},"create_date":{"bsonType":"timestamp","description":"统计时间"}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-sign-in.init_data.json b/uniCloud-aliyun/database/opendb-sign-in.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-sign-in.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-sign-in.schema.json b/uniCloud-aliyun/database/opendb-sign-in.schema.json new file mode 100644 index 0000000..e3a3ade --- /dev/null +++ b/uniCloud-aliyun/database/opendb-sign-in.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":[],"permission":{"read":"auth.uid == doc.user_id","create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"user_id":{"forceDefaultValue":{"$env":"uid"}},"date":{"bsonType":"timestamp","description":"签到的日期时间戳","permission":{"write":false}},"create_date":{"bsonType":"timestamp","description":"签到的时间戳","forceDefaultValue":{"$env":"now"}},"ip":{"bsonType":"string","forceDefaultValue":{"$env":"clientIP"}}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-sms-log.init_data.json b/uniCloud-aliyun/database/opendb-sms-log.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-sms-log.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-sms-log.schema.json b/uniCloud-aliyun/database/opendb-sms-log.schema.json new file mode 100644 index 0000000..a060624 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-sms-log.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"task_id":{"bsonType":"string","description":"任务ID","foreignKey":"batch-sms-task._id"},"uid":{"bsonType":"string","description":"用户ID","foreignKey":"uni-id-users._id"},"mobile":{"bsonType":"int","description":"手机号"},"var_data":{"bsonType":"object","description":"变量数据"},"status":{"bsonType":"int","description":"发送状态","defaultValue":0,"enum":[{"text":"未发送","value":0},{"text":"已发送","value":1},{"text":"发送失败","value":2}]},"reason":{"bsonType":"string","description":"发送失败原因"},"send_date":{"bsonType":"timestamp","description":"发送时间"},"create_date":{"bsonType":"timestamp","description":"创建时间","forceDefaultValue":{"$env":"now"}}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-sms-task.init_data.json b/uniCloud-aliyun/database/opendb-sms-task.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-sms-task.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-sms-task.schema.json b/uniCloud-aliyun/database/opendb-sms-task.schema.json new file mode 100644 index 0000000..fa4cd05 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-sms-task.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"name":{"bsonType":"string","description":"任务名称","trim":"both"},"app_id":{"bsonType":"string","description":"App ID","trim":"both"},"template_id":{"bsonType":"string","description":"短信模板ID","trim":"both"},"template_content":{"bsonType":"string","description":"短信模板内容","trim":"both"},"vars":{"bsonType":"array","description":"短信变量"},"to":{"bsonType":"object","description":"短信接收者信息","properties":{"all":{"bsonType":"bool","description":"全部用户发送;字段废弃,由 condition 替代"},"type":{"bsonType":"string","description":"可选值 user | userTags"},"receiver":{"bsonType":"array","description":"用户ID's \/ 用户标签ID's;指定id发送"},"condition":{"bsonType":"object","description":"根据条件发送,例如给所有人发送"}}},"send_qty":{"bsonType":"int","description":"发送总数"},"success_qty":{"bsonType":"int","description":"成功总数"},"fail_qty":{"bsonType":"int","description":"失败总数"},"create_date":{"bsonType":"timestamp","description":"创建时间","forceDefaultValue":{"$env":"now"}}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-sms-template.init_data.json b/uniCloud-aliyun/database/opendb-sms-template.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-sms-template.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-sms-template.schema.json b/uniCloud-aliyun/database/opendb-sms-template.schema.json new file mode 100644 index 0000000..3fc5ed5 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-sms-template.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"模板ID"},"name":{"bsonType":"string","description":"模板名称"},"content":{"bsonType":"string","description":"模板内容"},"type":{"bsonType":"int","description":"模板类型"},"sign":{"bsonType":"string","description":"模板签名"}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-tempdata.init_data.json b/uniCloud-aliyun/database/opendb-tempdata.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-tempdata.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-tempdata.schema.json b/uniCloud-aliyun/database/opendb-tempdata.schema.json new file mode 100644 index 0000000..f7a9a3b --- /dev/null +++ b/uniCloud-aliyun/database/opendb-tempdata.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["value","expired"],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"value":{"description":"值"},"expired":{"description":"过期时间","bsonType":"timestamp"}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-verify-codes.init_data.json b/uniCloud-aliyun/database/opendb-verify-codes.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-verify-codes.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/opendb-verify-codes.schema.json b/uniCloud-aliyun/database/opendb-verify-codes.schema.json new file mode 100644 index 0000000..d376194 --- /dev/null +++ b/uniCloud-aliyun/database/opendb-verify-codes.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":[],"properties":{"_id":{"description":"ID,系统自动生成"},"mobile":{"bsonType":"string","description":"手机号码"},"email":{"bsonType":"string","description":"邮箱"},"device_uuid":{"bsonType":"string","description":"设备UUID,常用于图片验证码"},"code":{"bsonType":"string","description":"验证码"},"scene":{"bsonType":"string","description":"使用验证码的场景,如:login, bind, unbind, pay"},"state":{"bsonType":"int","description":"验证状态:0 未验证、1 已验证、2 已作废"},"ip":{"bsonType":"string","description":"请求时客户端IP地址"},"created_date":{"bsonType":"timestamp","description":"创建时间"},"expired_date":{"bsonType":"timestamp","description":"过期时间"}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/read-news-log.init_data.json b/uniCloud-aliyun/database/read-news-log.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/read-news-log.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/read-news-log.schema.json b/uniCloud-aliyun/database/read-news-log.schema.json new file mode 100644 index 0000000..1cbd342 --- /dev/null +++ b/uniCloud-aliyun/database/read-news-log.schema.json @@ -0,0 +1,35 @@ +{ + "bsonType": "object", + "required": ["user_id", "article_id"], + "permission": { + "read": "doc.user_id == auth.uid", + "create": "auth.uid != null", + "update": "doc.user_id == auth.uid" + //"delete": "doc.user_id == auth.uid" + }, + "properties": { + "_id": { + "description": "ID,系统自动生成" + }, + "article_id": { + "bsonType": "string", + "description": "文章id,参考opendb-news-articles表", + "foreignKey": "opendb-news-articles._id" + }, + "user_id": { + "bsonType": "string", + "description": "收藏者id,参考uni-id-users表", + "forceDefaultValue": { + "$env": "uid" + }, + "foreignKey": "uni-id-users._id" + }, + "last_time": { //设计策略是多次看同一个文章只做一次记录,重复看的文章时间更新为当前时间 + "bsonType": "timestamp", + "description": "最后一次看的时间", + "defaultValue": { + "$env": "now" + } + } + } +} diff --git a/uniCloud-aliyun/database/uni-id-device.init_data.json b/uniCloud-aliyun/database/uni-id-device.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-id-device.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-id-device.schema.json b/uniCloud-aliyun/database/uni-id-device.schema.json new file mode 100644 index 0000000..dd47958 --- /dev/null +++ b/uniCloud-aliyun/database/uni-id-device.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["user_id"],"properties":{"_id":{"description":"ID,系统自动生成"},"user_id":{"bsonType":"string","description":"用户id,参考uni-id-users表"},"ua":{"bsonType":"string","description":"userAgent"},"uuid":{"bsonType":"string","description":"设备唯一标识(需要加密存储)"},"os_name":{"bsonType":"string","description":"ios|android|windows|mac|linux "},"os_version":{"bsonType":"string","description":"操作系统版本号 "},"os_language":{"bsonType":"string","description":"操作系统语言 "},"os_theme":{"bsonType":"string","description":"操作系统主题 light|dark"},"vendor":{"bsonType":"string","description":"设备厂商"},"push_clientid":{"bsonType":"string","description":"推送设备客户端标识"},"device_id":{"bsonType":"string","description":"设备id"},"imei":{"bsonType":"string","description":"国际移动设备识别码IMEI(International Mobile Equipment Identity)"},"oaid":{"bsonType":"string","description":"移动智能设备标识公共服务平台提供的匿名设备标识符(OAID)"},"idfa":{"bsonType":"string","description":"iOS平台配置应用使用广告标识(IDFA)"},"model":{"bsonType":"string","description":"设备型号"},"platform":{"bsonType":"string","description":"平台类型"},"create_date":{"bsonType":"timestamp","description":"创建时间","forceDefaultValue":{"$env":"now"}},"last_active_date":{"bsonType":"timestamp","description":"最后登录时间"},"last_active_ip":{"bsonType":"string","description":"最后登录IP"}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-id-log.init_data.json b/uniCloud-aliyun/database/uni-id-log.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-id-log.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-id-log.schema.json b/uniCloud-aliyun/database/uni-id-log.schema.json new file mode 100644 index 0000000..8c6905a --- /dev/null +++ b/uniCloud-aliyun/database/uni-id-log.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","properties":{"_id":{"description":"ID,系统自动生成"},"create_date":{"bsonType":"timestamp","description":"创建时间","forceDefaultValue":{"$env":"now"}},"device_id":{"bsonType":"string","description":"设备唯一标识"},"ip":{"bsonType":"string","description":"ip地址"},"state":{"bsonType":"int","description":"结果:0 失败、1 成功"},"type":{"bsonType":"string","description":"操作类型","enum":["logout","login","register","reset-pwd","bind-mobile","bind-weixin","bind-qq","bind-apple","bind-alipay"]},"ua":{"bsonType":"string","description":"userAgent"},"user_id":{"bsonType":"string","foreignKey":"uni-id-users._id","description":"用户id,参考uni-id-users表"},"username":{"bsonType":"string","description":"用户名"},"email":{"bsonType":"string","description":"邮箱"},"mobile":{"bsonType":"string","description":"手机号"},"appid":{"bsonType":"string","description":"客户端DCloud AppId"}},"required":[],"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-id-permissions.init_data.json b/uniCloud-aliyun/database/uni-id-permissions.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-id-permissions.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-id-permissions.schema.json b/uniCloud-aliyun/database/uni-id-permissions.schema.json new file mode 100644 index 0000000..f9ea23f --- /dev/null +++ b/uniCloud-aliyun/database/uni-id-permissions.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["permission_id","permission_name"],"properties":{"_id":{"description":"存储文档 ID,系统自动生成"},"permission_id":{"bsonType":"string","description":"权限唯一标识,不可修改,不允许重复","label":"权限标识","trim":"both","title":"权限ID","component":{"name":"input"}},"permission_name":{"bsonType":"string","description":"权限名称","label":"权限名称","title":"权限名称","trim":"both","component":{"name":"input"}},"comment":{"bsonType":"string","description":"备注","label":"备注","title":"备注","trim":"both","component":{"name":"textarea"}},"create_date":{"bsonType":"timestamp","description":"创建时间","forceDefaultValue":{"$env":"now"}}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-id-roles.init_data.json b/uniCloud-aliyun/database/uni-id-roles.init_data.json new file mode 100644 index 0000000..e6c78a9 --- /dev/null +++ b/uniCloud-aliyun/database/uni-id-roles.init_data.json @@ -0,0 +1,9 @@ +[ + { + "role_id": "admin", + "role_name": "超级管理员", + "permission": [], + "comment": "超级管理员拥有所有权限", + "create_date": 0 + } +] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-id-roles.schema.json b/uniCloud-aliyun/database/uni-id-roles.schema.json new file mode 100644 index 0000000..7051169 --- /dev/null +++ b/uniCloud-aliyun/database/uni-id-roles.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["role_id"],"permission":{"read":true,"create":true,"update":true,"delete":true},"properties":{"_id":{"description":"存储文档 ID,系统自动生成"},"role_id":{"title":"唯一ID","bsonType":"string","description":"角色唯一标识,不可修改,不允许重复","trim":"both"},"role_name":{"title":"名称","bsonType":"string","description":"角色名称","trim":"both"},"permission":{"title":"权限","bsonType":"array","foreignKey":"uni-id-permissions.permission_id","description":"角色拥有的权限列表"},"comment":{"title":"备注","bsonType":"string","description":"备注","trim":"both"},"create_date":{"bsonType":"timestamp","description":"创建时间","forceDefaultValue":{"$env":"now"}}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-id-scores.init_data.json b/uniCloud-aliyun/database/uni-id-scores.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-id-scores.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-id-scores.schema.json b/uniCloud-aliyun/database/uni-id-scores.schema.json new file mode 100644 index 0000000..2699afd --- /dev/null +++ b/uniCloud-aliyun/database/uni-id-scores.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["user_id","score","balance"],"properties":{"_id":{"description":"ID,系统自动生成"},"user_id":{"bsonType":"string","description":"用户id,参考uni-id-users表"},"score":{"bsonType":"int","description":"本次变化的积分"},"type":{"bsonType":"int","enum":[1,2],"description":"积分类型 1:收入 2:支出"},"balance":{"bsonType":"int","description":"变化后的积分余额"},"comment":{"bsonType":"string","description":"备注,说明积分新增、消费的缘由","trim":"both"},"create_date":{"bsonType":"timestamp","description":"创建时间","forceDefaultValue":{"$env":"now"}}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-id-tag.init_data.json b/uniCloud-aliyun/database/uni-id-tag.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-id-tag.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-id-tag.schema.json b/uniCloud-aliyun/database/uni-id-tag.schema.json new file mode 100644 index 0000000..18e229b --- /dev/null +++ b/uniCloud-aliyun/database/uni-id-tag.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["tagid","name"],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"tagid":{"bsonType":"string","description":"标签tagid","label":"标签tagid","componentForEdit":{"name":"uni-easyinput"}},"name":{"bsonType":"string","description":"标签名称","label":"标签名称","componentForEdit":{"name":"uni-easyinput"}},"description":{"bsonType":"string","description":"标签描述","label":"标签描述","componentForEdit":{"name":"textarea"},"componentForShow":{"name":"textarea"}},"create_date":{"bsonType":"timestamp","label":"创建时间","forceDefaultValue":{"$env":"now"},"componentForEdit":{"name":"uni-dateformat"}}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-id-users.init_data.json b/uniCloud-aliyun/database/uni-id-users.init_data.json new file mode 100644 index 0000000..2aef649 --- /dev/null +++ b/uniCloud-aliyun/database/uni-id-users.init_data.json @@ -0,0 +1,10 @@ +[ + { + "_id": "_uni_starter_test_user_id", + "username": "uni-starter预置用户名", + "nickname": "测试用户昵称", + "avatar": "https://unicloud.dcloud.net.cn/assets/logo.dca09351.png", + "mobile": "18888888888", + "mobile_confirmed": 1 + } +] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-id-users.schema.json b/uniCloud-aliyun/database/uni-id-users.schema.json new file mode 100644 index 0000000..9c848e1 --- /dev/null +++ b/uniCloud-aliyun/database/uni-id-users.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":[],"permission":{"read":true,"create":true,"update":true,"delete":true},"properties":{"_id":{"description":"存储文档 ID(用户 ID),系统自动生成"},"username":{"bsonType":"string","title":"用户名","description":"用户名,不允许重复","trim":"both"},"password":{"bsonType":"password","title":"密码","description":"密码,加密存储","trim":"both"},"password_secret_version":{"bsonType":"int","title":"passwordSecret","description":"密码使用的passwordSecret版本"},"nickname":{"bsonType":"string","title":"昵称","description":"用户昵称","trim":"both"},"gender":{"bsonType":"int","title":"性别","description":"用户性别:0 未知 1 男性 2 女性","defaultValue":0,"enum":[{"text":"未知","value":0},{"text":"男","value":1},{"text":"女","value":2}]},"status":{"bsonType":"int","description":"用户状态:0 正常 1 禁用 2 审核中 3 审核拒绝","title":"用户状态","defaultValue":0,"enum":[{"text":"正常","value":0},{"text":"禁用","value":1},{"text":"审核中","value":2},{"text":"审核拒绝","value":3}]},"mobile":{"bsonType":"string","title":"手机号码","description":"手机号码","pattern":"^\\+?[0-9-]{3,20}$","trim":"both"},"mobile_confirmed":{"bsonType":"int","description":"手机号验证状态:0 未验证 1 已验证","title":"手机号验证状态","defaultValue":0,"enum":[{"text":"未验证","value":0},{"text":"已验证","value":1}]},"email":{"bsonType":"string","format":"email","title":"邮箱","description":"邮箱地址","trim":"both"},"email_confirmed":{"bsonType":"int","description":"邮箱验证状态:0 未验证 1 已验证","title":"邮箱验证状态","defaultValue":0,"enum":[{"text":"未验证","value":0},{"text":"已验证","value":1}]},"avatar":{"bsonType":"string","title":"头像地址","description":"头像地址","trim":"both"},"avatar_file":{"bsonType":"file","title":"头像文件","description":"用file类型方便使用uni-file-picker组件"},"d_ids":{"bsonType":"array","description":"部门ID","title":"部门","foreignKey":"opendb-department._id","enumType":"tree","enum":{"collection":"opendb-department","orderby":"name asc","field":"_id as value, name as text"}},"e_ids":{"bsonType":"array","description":"企业ID","title":"企业"},"role":{"bsonType":"array","title":"角色","description":"用户角色","enum":{"collection":"uni-id-roles","field":"role_id as value, role_name as text"},"foreignKey":"uni-id-roles.role_id","permission":{"write":false}},"wx_unionid":{"bsonType":"string","description":"微信unionid"},"wx_openid":{"bsonType":"object","description":"微信各个平台openid","properties":{"app":{"bsonType":"string","description":"app平台微信openid"},"mp":{"bsonType":"string","description":"微信小程序平台openid"},"h5":{"bsonType":"string","description":"微信公众号平台openid"},"web":{"bsonType":"string","description":"微信网页登录openid"}}},"ali_openid":{"bsonType":"string","description":"支付宝平台openid"},"apple_openid":{"bsonType":"string","description":"苹果登录openid"},"dcloud_appid":{"bsonType":"array","description":"允许登录的客户端的appid列表","foreignKey":"opendb-app-list.appid"},"comment":{"bsonType":"string","title":"备注","description":"备注","trim":"both"},"third_party":{"bsonType":"object","description":"缓存用户在三方平台的token等信息","properties":{"mp_weixin":{"bsonType":"object","description":"微信小程序相关信息","properties":{"session_key":{"bsonType":"string","description":"微信小程序session key"}}},"app_weixin":{"bsonType":"object","description":"app平台微信相关信息","properties":{"access_token":{"bsonType":"string","description":"app平台微信access token"},"access_token_expired":{"bsonType":"string","description":"app平台微信access token过期时间"},"refresh_token":{"bsonType":"string","description":"app平台微信refresh token"}}},"h5_weixin":{"bsonType":"object","description":"微信公众号平台微信相关信息","properties":{"access_token":{"bsonType":"string","description":"微信公众号平台access token"},"access_token_expired":{"bsonType":"string","description":"微信公众号平台access token过期时间"},"refresh_token":{"bsonType":"string","description":"微信公众号平台refresh token"}}},"web_weixin":{"bsonType":"object","description":"web平台微信相关信息","properties":{"access_token":{"bsonType":"string","description":"web平台微信access token"},"access_token_expired":{"bsonType":"string","description":"web平台微信access token过期时间"},"refresh_token":{"bsonType":"string","description":"web平台微信refresh token"}}},"mp_qq":{"bsonType":"object","description":"QQ小程序相关信息","properties":{"session_key":{"bsonType":"string","description":"QQ小程序session key"}}},"app_qq":{"bsonType":"object","description":"app平台QQ相关信息","properties":{"access_token":{"bsonType":"string","description":"app平台QQ access token"},"access_token_expired":{"bsonType":"string","description":"app平台QQ access token过期时间"}}}}},"register_env":{"bsonType":"object","description":"注册环境信息","properties":{"appid":{"bsonType":"string","description":"注册时的应用AppId"},"uni_platform":{"bsonType":"string","description":"注册时的应用平台,app、h5等"},"os_name":{"bsonType":"string","description":"注册时的客户端系统类型,ios、android、windows、mac、linux"},"app_name":{"bsonType":"string","description":"注册时的应用名称"},"app_version":{"bsonType":"string","description":"注册时的应用版本名称"},"app_version_code":{"bsonType":"string","description":"注册时的应用版本号码"},"channel":{"bsonType":"string","description":"注册时的应用渠道或小程序启动场景"},"client_ip":{"bsonType":"string","description":"注册时的客户端ip"}}},"realname_auth":{"bsonType":"object","description":"实名认证信息","required":["type","auth_status"],"properties":{"type":{"bsonType":"int","minimum":0,"maximum":1,"description":"用户类型:0 个人用户 1 企业用户"},"auth_status":{"bsonType":"int","minimum":0,"maximum":3,"description":"认证状态:0 未认证 1 等待认证 2 认证通过 3 认证失败"},"auth_date":{"bsonType":"timestamp","description":"认证通过时间"},"real_name":{"bsonType":"string","description":"真实姓名\/企业名称"},"identity":{"bsonType":"string","description":"身份证号码\/营业执照号码"},"id_card_front":{"bsonType":"string","description":"身份证正面照 URL"},"id_card_back":{"bsonType":"string","description":"身份证反面照 URL"},"in_hand":{"bsonType":"string","description":"手持身份证照片 URL"},"license":{"bsonType":"string","description":"营业执照 URL"},"contact_person":{"bsonType":"string","description":"联系人姓名"},"contact_mobile":{"bsonType":"string","description":"联系人手机号码"},"contact_email":{"bsonType":"string","description":"联系人邮箱"}}},"score":{"bsonType":"int","description":"用户积分,积分变更记录可参考:uni-id-scores表定义"},"register_date":{"bsonType":"timestamp","description":"注册时间","forceDefaultValue":{"$env":"now"}},"register_ip":{"bsonType":"string","description":"注册时 IP 地址","forceDefaultValue":{"$env":"clientIP"}},"last_login_date":{"bsonType":"timestamp","description":"最后登录时间"},"last_login_ip":{"bsonType":"string","description":"最后登录时 IP 地址"},"token":{"bsonType":"array","description":"用户token"},"inviter_uid":{"bsonType":"array","description":"用户全部上级邀请者","trim":"both"},"invite_time":{"bsonType":"timestamp","description":"受邀时间"},"my_invite_code":{"bsonType":"string","description":"用户自身邀请码"},"identities":{"bsonType":"array","description":"三方平台身份信息;一个对象代表一个身份,参数支持: provider 身份源, userInfo 三方用户信息, openid 三方openid, unionid 三方unionid, uid 三方uid","permission":{"read":"'READ_UNI_ID_USERS' in auth.permission","write":"'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission"}}},"version":"1.0.3"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-pay-orders.init_data.json b/uniCloud-aliyun/database/uni-pay-orders.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-pay-orders.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-pay-orders.schema.json b/uniCloud-aliyun/database/uni-pay-orders.schema.json new file mode 100644 index 0000000..84c6e6a --- /dev/null +++ b/uniCloud-aliyun/database/uni-pay-orders.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","required":["provider","status","type","order_no","total_fee"],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"provider":{"title":"支付供应商","bsonType":"string","enum":[{"text":"微信支付","value":"wxpay"},{"text":"支付宝","value":"alipay"},{"text":"苹果应用内支付","value":"appleiap"}],"description":"支付供应商 如 wxpay alipay 参考 https:\/\/uniapp.dcloud.net.cn\/api\/plugins\/provider.html#"},"provider_pay_type":{"title":"支付方式","bsonType":"string","description":"支付供应商的支付类型(插件内部标记支付类型的标识,不需要用户传)","trim":"both"},"uni_platform":{"title":"应用平台","bsonType":"string","description":"uni客户端平台,如:web、mp-weixin、mp-alipay、app等","trim":"both"},"status":{"title":"订单状态","bsonType":"int","enum":[{"text":"已关闭","value":-1},{"text":"未支付","value":0},{"text":"已支付","value":1},{"text":"已部分退款","value":2},{"text":"已全额退款","value":3}],"description":"订单状态 -1 已关闭 0:未支付 1:已支付 2:已部分退款 3:已全额退款","defaultValue":0},"type":{"title":"订单类型","bsonType":"string","description":"订单类型 goods:订单付款 recharge:余额充值付款 vip:vip充值付款 等等,可自定义,用于判断最终执行哪个异步回调逻辑。","trim":"both"},"order_no":{"title":"业务系统订单号","bsonType":"string","minLength":20,"maxLength":28,"description":"业务系统订单号,控制在20-28位(不可以是24位,24位在阿里云空间可能会有问题,可重复,代表1个业务订单会有多次付款的情况)","trim":"both"},"out_trade_no":{"title":"支付插件订单号","bsonType":"string","description":"支付插件订单号(需控制唯一,不传则由插件自动生成)","trim":"both"},"transaction_id":{"title":"交易单号","bsonType":"string","description":"交易单号(支付平台订单号,由支付平台控制唯一)","trim":"both"},"user_id":{"title":"用户ID","bsonType":"string","description":"用户id,参考uni-id-users表","foreignKey":"uni-id-users._id"},"device_id":{"bsonType":"string","description":"客户端设备ID"},"client_ip":{"title":"客户端IP","bsonType":"string","description":"创建支付的客户端ip","trim":"both"},"openid":{"title":"openid","bsonType":"string","description":"发起支付的用户openid","trim":"both"},"description":{"title":"支付描述","bsonType":"string","description":"支付描述,如:uniCloud个人版包月套餐","trim":"both"},"err_msg":{"title":"支付失败原因","bsonType":"string","description":"支付失败原因","trim":"both"},"total_fee":{"title":"订单总金额","bsonType":"int","description":"订单总金额,单位为分,100等于1元"},"refund_fee":{"title":"订单总退款金额","bsonType":"int","description":"订单总退款金额,单位为分,100等于1元"},"refund_count":{"title":"当前退款笔数","bsonType":"int","description":"当前退款笔数 (退款单号为 out_trade_no-refund_count)"},"refund_list":{"title":"退款详情","bsonType":"array","description":"退款详情"},"provider_appid":{"title":"开放平台appid","bsonType":"string","description":"公众号appid,小程序appid,app开放平台appid 等","trim":"both"},"appid":{"title":"DCloud AppId","bsonType":"string","description":"dcloud_appid","trim":"both"},"user_order_success":{"title":"回调状态","bsonType":"bool","description":"用户异步通知逻辑是否全部执行完成,且无异常(建议前端通过此参数是否为true来判断是否支付成功)"},"custom":{"title":"自定义数据","bsonType":"object","description":"自定义数据(用户自定义数据)"},"original_data":{"title":"异步通知原始数据","bsonType":"object","description":"异步回调通知返回的原始数据,微信是xml转json后的数据,支付宝是原始json"},"create_date":{"title":"创建时间","bsonType":"timestamp","description":"创建时间","forceDefaultValue":{"$env":"now"}},"pay_date":{"title":"支付时间","bsonType":"timestamp","description":"支付时间"},"notify_date":{"title":"异步通知时间","bsonType":"timestamp","description":"订单通知支付成功时间"},"cancel_date":{"title":"取消时间","bsonType":"timestamp","description":"订单取消时间"},"stat_data":{"title":"uni统计相关数据","bsonType":"object","description":"uni统计相关数据","properties":{"platform":{"bsonType":"string","description":"与uni_platform唯一区别是APP区分 android 和 ios"},"app_version":{"bsonType":"string","description":"客户端版本号 (字符串形式)如1.0.0"},"app_version_code":{"bsonType":"int","description":"客户端版本号(数字形式) 如100"},"app_wgt_version":{"bsonType":"string","description":"客户端热更新版本号"},"os":{"bsonType":"string","description":"设备的操作系统 如 android ios"},"ua":{"bsonType":"string","description":"客户端userAgent"},"channel":{"bsonType":"string","description":"客户端渠道"},"scene":{"bsonType":"string","description":"小程序场景值"}}}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-active-devices.init_data.json b/uniCloud-aliyun/database/uni-stat-active-devices.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-active-devices.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-active-devices.schema.json b/uniCloud-aliyun/database/uni-stat-active-devices.schema.json new file mode 100644 index 0000000..151228d --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-active-devices.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"给周月维度的设备基础统计和留存统计提供数据,每日跑批合并,仅添加本周\/本月首次访问的设备","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"应用ID"},"platform_id":{"bsonType":"string","description":"应用平台ID,对应uni-stat-app-platforms._id","foreignKey":"uni-stat-app-platforms._id"},"channel_id":{"bsonType":"string","description":"渠道\/场景值ID,对应uni-stat-app-channels._id","foreignKey":"uni-stat-app-channels._id"},"version_id":{"bsonType":"string","description":"应用版本ID,对应opendb-app-versions._id","foreignKey":"opendb-app-versions._id"},"device_id":{"bsonType":"string","description":"客户端携带的设备标识"},"is_new":{"bsonType":"int","description":"是否为新设备","defaultValue":0,"enum":[{"text":"否","value":0},{"text":"是","value":1}]},"dimension":{"bsonType":"string","description":"时间范围 week:周,month:月","enum":[{"text":"月","value":"month"},{"text":"周","value":"week"}]},"create_time":{"bsonType":"timestamp","description":"创建时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-active-users.init_data.json b/uniCloud-aliyun/database/uni-stat-active-users.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-active-users.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-active-users.schema.json b/uniCloud-aliyun/database/uni-stat-active-users.schema.json new file mode 100644 index 0000000..ce64c48 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-active-users.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"给周月维度的用户基础统计和留存统计提供数据,每日跑批合并,仅添加本周\/本月首次访问的用户。","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"应用ID"},"platform_id":{"bsonType":"string","description":"应用平台ID,对应uni-stat-app-platforms._id","foreignKey":"uni-stat-app-platforms._id"},"channel_id":{"bsonType":"string","description":"渠道\/场景值ID,对应uni-stat-app-channels._id","foreignKey":"uni-stat-app-channels._id"},"version_id":{"bsonType":"string","description":"应用版本ID,对应opendb-app-versions._id","foreignKey":"opendb-app-versions._id"},"uid":{"bsonType":"string","description":"用户编号, 对应uni-id-users._id"},"dimension":{"bsonType":"string","description":"时间范围 week:周,month:月","enum":[{"text":"月","value":"month"},{"text":"周","value":"week"}]},"create_time":{"bsonType":"timestamp","description":"创建时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-app-channels.init_data.json b/uniCloud-aliyun/database/uni-stat-app-channels.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-app-channels.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-app-channels.schema.json b/uniCloud-aliyun/database/uni-stat-app-channels.schema.json new file mode 100644 index 0000000..210ae9d --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-app-channels.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"提供渠道和场景值数据","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"统计应用ID,对应opendb-app-list.appid","foreignKey":"opendb-app-list.appid"},"platform_id":{"bsonType":"string","description":"应用平台,对应uni-stat-app-platforms._id","foreignKey":"uni-stat-app-platforms._id"},"channel_code":{"bsonType":"int","description":"客户端上报的渠道代码"},"channel_name":{"bsonType":"string","description":"渠道名称,用户可编辑"},"create_time":{"bsonType":"timestamp","description":"创建时间"},"last_modify_time":{"bsonType":"timestamp","description":"最后修改时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-app-crash-logs.init_data.json b/uniCloud-aliyun/database/uni-stat-app-crash-logs.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-app-crash-logs.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-app-crash-logs.schema.json b/uniCloud-aliyun/database/uni-stat-app-crash-logs.schema.json new file mode 100644 index 0000000..ad0f18a --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-app-crash-logs.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"记录原生应用的崩溃日志","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"用户端上报的应用ID"},"version":{"bsonType":"string","description":"用户端上报的应用版本号。manifest.json中的version->name的值"},"platform":{"bsonType":"string","description":"用户端上报的平台code"},"channel":{"bsonType":"string","description":"用户端上报的渠道code\/场景值"},"sdk_version":{"bsonType":"string","description":"基础库版本号"},"device_id":{"bsonType":"string","description":"客户端携带的设备标识"},"device_net":{"bsonType":"string","description":"设备网络型号wifi\/3G\/4G\/"},"device_os":{"bsonType":"string","description":"系统版本:iOS平台为系统版本号,如15.1;Android平台为API等级,如30"},"device_os_version":{"bsonType":"string","description":"系统版本名称:iOS平台与os字段一致;Android平台为版本名称,如5.1.1"},"device_vendor":{"bsonType":"string","description":"设备供应商 "},"device_model":{"bsonType":"string","description":"设备型号"},"device_is_root":{"bsonType":"int","description":"是否root:1表示root;0表示未root"},"device_os_name":{"bsonType":"string","description":"系统名称:用于区别Android和鸿蒙,仅Android支持"},"device_batt_level":{"bsonType":"int","description":"设备电池电量:取值范围0-100,仅Android支持"},"device_batt_temp":{"bsonType":"string","description":"电池温度,仅Android支持"},"device_memory_use_size":{"bsonType":"int","description":"系统已使用内存,单位为Byte,仅Android支持"},"device_memory_total_size":{"bsonType":"int","description":"系统总内存,单位为Byte,仅Android支持"},"device_disk_use_size":{"bsonType":"int","description":"系统磁盘已使用大小,单位为Byte,仅Android支持"},"device_disk_total_size":{"bsonType":"int","description":"系统磁盘总大小,单位为Byte,仅Android支持"},"device_abis":{"bsonType":"string","description":"设备支持的CPU架构:多个使用,分割,如arm64-v8a,armeabi-v7a,armeabi,仅Android支持"},"app_count":{"bsonType":"int","description":"运行的app个数:包括运行的uni小程序数目。独立App时值为1"},"app_use_memory_size":{"bsonType":"int","description":"APP使用的内存量,单位为Byte"},"app_webview_count":{"bsonType":"int","description":"打开Webview窗口的个数"},"app_use_duration":{"bsonType":"int","description":"APP使用时长:单位为s"},"app_run_fore":{"bsonType":"int","description":"是否前台运行:1表示前台运行,0表示后台运行"},"package_name":{"bsonType":"string","description":"原生应用包名"},"package_version":{"bsonType":"string","description":"Android的apk版本名称;iOS的ipa版本名称"},"page_url":{"bsonType":"string","description":"页面url"},"error_msg":{"bsonType":"string","description":"错误信息"},"create_time":{"bsonType":"timestamp","description":"客户端记录到的崩溃时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-app-platforms.init_data.json b/uniCloud-aliyun/database/uni-stat-app-platforms.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-app-platforms.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-app-platforms.schema.json b/uniCloud-aliyun/database/uni-stat-app-platforms.schema.json new file mode 100644 index 0000000..6c561d6 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-app-platforms.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"提供应用的平台字典","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"code":{"bsonType":"string","description":"平台代码,前端上报"},"name":{"bsonType":"string","description":"平台名称,管理端显示"},"order":{"bsonType":"int","description":"序号,前端页面排序使用","defaultValue":0},"enable":{"bsonType":"bool","description":"是否启动","defaultValue":true,"enum":[{"text":"否","value":false},{"text":"是","value":true}]},"create_time":{"bsonType":"timestamp","description":"创建时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-app-versions.init_data.json b/uniCloud-aliyun/database/uni-stat-app-versions.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-app-versions.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-app-versions.schema.json b/uniCloud-aliyun/database/uni-stat-app-versions.schema.json new file mode 100644 index 0000000..dd23c57 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-app-versions.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"提供应用的版本号字典;已废弃,推荐使用opendb-app-versions表","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"统计应用ID,对应opendb-app-list.appid","foreignKey":"opendb-app-list.appid"},"platform_id":{"bsonType":"string","description":"应用平台,对应uni-stat-app-platforms._id","foreignKey":"uni-stat-app-platforms._id"},"version":{"bsonType":"string","description":"应用版本"},"create_time":{"bsonType":"timestamp","description":"创建时间"},"last_modify_time":{"bsonType":"timestamp","description":"最后修改时间"}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-error-logs.init_data.json b/uniCloud-aliyun/database/uni-stat-error-logs.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-error-logs.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-error-logs.schema.json b/uniCloud-aliyun/database/uni-stat-error-logs.schema.json new file mode 100644 index 0000000..2a22612 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-error-logs.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"记录上报的应用运行错误日志","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"用户端上报的应用ID"},"version":{"bsonType":"string","description":"用户端上报的应用版本号"},"platform":{"bsonType":"string","description":"用户端上报的平台code"},"channel":{"bsonType":"string","description":"用户端上报的渠道code\/场景值"},"error_type":{"bsonType":"int","description":"错误类型","defaultValue":0,"enum":[{"text":"未知","value":0},{"text":"表示webview页面js异常(uni-app项目对应vue页面)","value":2},{"text":"表示uni框架js异常(仅uni-app项目)","value":4},{"text":"表示控制页js异常(仅uni-app项目)","value":5},{"text":"表示nvue页面js异常(仅uni-app项目)","value":6}]},"device_id":{"bsonType":"string","description":"客户端携带的设备标识"},"uid":{"bsonType":"string","description":"用户编号, 对应uni-id-users._id"},"os":{"bsonType":"string","description":"客户端操作系统"},"ua":{"bsonType":"string","description":"客户端user-agent信息"},"space_id":{"bsonType":"string","description":"服务空间编号"},"space_provider":{"bsonType":"string","description":"服务空间提供商"},"sdk_version":{"bsonType":"string","description":"小程序基础库版本号"},"platform_version":{"bsonType":"string","description":"微信、支付宝宿主App的版本号"},"error_msg":{"bsonType":"string","description":"错误信息"},"error_hash":{"bsonType":"string","description":"错误hash码"},"page_url":{"bsonType":"string","description":"页面url"},"create_time":{"bsonType":"timestamp","description":"创建时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-error-result.init_data.json b/uniCloud-aliyun/database/uni-stat-error-result.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-error-result.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-error-result.schema.json b/uniCloud-aliyun/database/uni-stat-error-result.schema.json new file mode 100644 index 0000000..d13451d --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-error-result.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"存储汇总的错误日志的数据","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"应用ID"},"platform_id":{"bsonType":"string","description":"应用平台ID,对应uni-stat-app-platforms._id","foreignKey":"uni-stat-app-platforms._id"},"channel_id":{"bsonType":"string","description":"渠道\/场景值ID,对应uni-stat-app-channels._id","foreignKey":"uni-stat-app-channels._id"},"version_id":{"bsonType":"string","description":"应用版本ID,对应opendb-app-versions._id","foreignKey":"opendb-app-versions._id"},"type":{"bsonType":"string","description":"错误类型","enum":[{"text":"前端js错误","value":"js"},{"text":"原生应用崩溃错误","value":"crash"}]},"hash":{"bsonType":"string","description":"错误hash码"},"msg":{"bsonType":"string","description":"错误信息"},"count":{"bsonType":"int","description":"报错次数"},"app_launch_count":{"bsonType":"int","description":"本时间段App启动或从后台切到前台的次数"},"last_time":{"bsonType":"timestamp","description":"最近一次报错事件"},"dimension":{"bsonType":"string","description":"统计范围 day:按天统计,hour:按小时统计","enum":[{"text":"月","value":"month"},{"text":"周","value":"week"},{"text":"天","value":"day"},{"text":"小时","value":"hour"}]},"stat_date":{"bsonType":"int","description":"统计日期,格式yyyymmdd,例:20211201"},"start_time":{"bsonType":"timestamp","description":"开始时间"},"end_time":{"bsonType":"timestamp","description":"结束时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-error-source-map.init_data.json b/uniCloud-aliyun/database/uni-stat-error-source-map.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-error-source-map.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-error-source-map.schema.ext.js b/uniCloud-aliyun/database/uni-stat-error-source-map.schema.ext.js new file mode 100644 index 0000000..556f31e --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-error-source-map.schema.ext.js @@ -0,0 +1,29 @@ +module.exports = { + trigger: { + // 监听 - 删除前 + beforeDelete: async function(obj = {}) { + let { + collection, + operation, + where, + field + } = obj; + // 删除表记录前先删除云存储内的文件 + const db = uniCloud.database(); + const _ = db.command; + let getRes = await db.collection("uni-stat-error-source-map").where(where).limit(1000).get(); + let list = getRes.data; + if (list && list.length > 0) { + let fileList = list.map((item, index) => { + return item.file_id; + }); + try { + let deleteFileRes = await uniCloud.deleteFile({ + fileList + }); + // console.log('deleteFileRes: ', deleteFileRes) + } catch (err) {} + } + } + } +} diff --git a/uniCloud-aliyun/database/uni-stat-error-source-map.schema.json b/uniCloud-aliyun/database/uni-stat-error-source-map.schema.json new file mode 100644 index 0000000..5161de0 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-error-source-map.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"存储sourceMap文件资源地址","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"应用ID"},"uni_platform":{"title":"应用平台","bsonType":"string","description":"uni客户端平台,如:web、mp-weixin、mp-alipay、app等","trim":"both"},"version":{"bsonType":"string","description":"客户端上报的应用版本号"},"file_id":{"bsonType":"string","description":"fileID"},"url":{"bsonType":"string","description":"文件外网url路径"},"name":{"bsonType":"string","description":"文件名"},"size":{"bsonType":"int","description":"文件大小"},"cloud_path":{"bsonType":"string","description":"云端路径,通过该值识别是否是同一个文件"},"base":{"bsonType":"string","description":"基础路径"},"create_time":{"bsonType":"timestamp","description":"上传时间","forceDefaultValue":{"$env":"now"}}},"version":"0.0.1"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-event-logs.init_data.json b/uniCloud-aliyun/database/uni-stat-event-logs.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-event-logs.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-event-logs.schema.json b/uniCloud-aliyun/database/uni-stat-event-logs.schema.json new file mode 100644 index 0000000..cd13805 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-event-logs.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"记录上报的事件日志","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"客户端上报的应用ID"},"version":{"bsonType":"string","description":"客户端上报的应用版本号"},"platform":{"bsonType":"string","foreignKey":"uni-stat-app-platforms.code","description":"客户端上报的平台code"},"channel":{"bsonType":"string","description":"客户端上报的渠道code\/场景值"},"device_id":{"bsonType":"string","description":"客户端携带的设备标识"},"uid":{"bsonType":"string","description":"用户编号, 对应uni-id-users._id"},"session_id":{"bsonType":"string","description":"访问会话日志ID,对应uni-stat-session-logs._id","foreignKey":"uni-stat-session-logs._id"},"page_id":{"bsonType":"string","description":"页面ID,对应uni-stat-pages._id","foreignKey":"uni-stat-pages._id"},"event_key":{"bsonType":"string","description":"客户端上报的key"},"param":{"bsonType":"string","description":"事件参数"},"sdk_version":{"bsonType":"string","description":"基础库版本号"},"platform_version":{"bsonType":"string","description":"平台版本,如微信、支付宝宿主App版本号"},"device_os":{"bsonType":"int","description":"设备系统编号,1:安卓,2:iOS,3:PC"},"device_os_version":{"bsonType":"string","description":"设备系统版本"},"device_net":{"bsonType":"string","description":"设备网络型号wifi\/3G\/4G\/"},"device_vendor":{"bsonType":"string","description":"设备供应商 "},"device_model":{"bsonType":"string","description":"设备型号"},"device_language":{"bsonType":"string","description":"设备语言包"},"device_pixel_ratio":{"bsonType":"string","description":"设备像素比 "},"device_window_width":{"bsonType":"string","description":"设备窗口宽度 "},"device_window_height":{"bsonType":"string","description":"设备窗口高度"},"device_screen_width":{"bsonType":"string","description":"设备屏幕宽度"},"device_screen_height":{"bsonType":"string","description":"设备屏幕高度"},"create_time":{"bsonType":"timestamp","description":"创建时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-event-result.init_data.json b/uniCloud-aliyun/database/uni-stat-event-result.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-event-result.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-event-result.schema.json b/uniCloud-aliyun/database/uni-stat-event-result.schema.json new file mode 100644 index 0000000..3c9b3c7 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-event-result.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"存储汇总的事件日志的数据","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"应用ID"},"platform_id":{"bsonType":"string","description":"应用平台ID,对应uni-stat-app-platforms._id","foreignKey":"uni-stat-app-platforms._id"},"channel_id":{"bsonType":"string","description":"渠道\/场景值ID,对应uni-stat-app-channels._id","foreignKey":"uni-stat-app-channels._id"},"version_id":{"bsonType":"string","description":"应用版本ID,对应opendb-app-versions._id","foreignKey":"opendb-app-versions._id"},"event_key":{"bsonType":"string","description":"事件key,对应uni-stat-events.event_key","foreignKey":"uni-stat-events.event_key"},"event_count":{"bsonType":"int","description":"触发次数"},"device_count":{"bsonType":"int","description":"触发该事件的设备数"},"user_count":{"bsonType":"int","description":"触发该事件的用户数"},"dimension":{"bsonType":"string","description":"统计范围 day:按天统计,hour:按小时统计","enum":[{"text":"月","value":"month"},{"text":"周","value":"week"},{"text":"天","value":"day"},{"text":"小时","value":"hour"}]},"stat_date":{"bsonType":"int","description":"统计日期,格式yyyymmdd,例:20211201"},"start_time":{"bsonType":"timestamp","description":"开始时间"},"end_time":{"bsonType":"timestamp","description":"结束时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-events.init_data.json b/uniCloud-aliyun/database/uni-stat-events.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-events.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-events.schema.json b/uniCloud-aliyun/database/uni-stat-events.schema.json new file mode 100644 index 0000000..7033abb --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-events.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"提供应用的事件字典","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"统计应用ID,对应opendb-app-list.appid","foreignKey":"opendb-app-list.appid"},"event_key":{"bsonType":"string","description":"事件键值"},"event_name":{"bsonType":"string","description":"事件名称"},"create_time":{"bsonType":"timestamp","description":"创建时间"},"update_time":{"bsonType":"timestamp","description":"last_modify_time"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-loyalty-result.init_data.json b/uniCloud-aliyun/database/uni-stat-loyalty-result.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-loyalty-result.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-loyalty-result.schema.json b/uniCloud-aliyun/database/uni-stat-loyalty-result.schema.json new file mode 100644 index 0000000..715da9d --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-loyalty-result.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"存储汇总的设备\/用户的粘性数据","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"应用ID"},"platform_id":{"bsonType":"string","description":"应用平台ID,对应uni-stat-app-platforms._id","foreignKey":"uni-stat-app-platforms._id"},"channel_id":{"bsonType":"string","description":"渠道\/场景值ID,对应uni-stat-app-channels._id","foreignKey":"uni-stat-app-channels._id"},"version_id":{"bsonType":"string","description":"应用版本ID,对应opendb-app-versions._id","foreignKey":"opendb-app-versions._id"},"visit_depth_data":{"bsonType":"object","description":"访问深度数据","properties":{"visit_users":{"bsonType":"object","description":"访问用户数"},"visit_devices":{"bsonType":"object","description":"访问设备数"},"visit_times":{"bsonType":"object","description":"访问次数"}}},"duration_data":{"bsonType":"object","description":"访问时长数据","properties":{"visit_users":{"bsonType":"object","description":"访问用户数"},"visit_devices":{"bsonType":"object","description":"访问设备数"},"visit_times":{"bsonType":"object","description":"访问次数"}}},"stat_date":{"bsonType":"int","description":"统计日期,格式yyyymmdd,例:20211201"},"start_time":{"bsonType":"timestamp","description":"开始时间"},"end_time":{"bsonType":"timestamp","description":"结束时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-mp-scenes.init_data.json b/uniCloud-aliyun/database/uni-stat-mp-scenes.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-mp-scenes.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-mp-scenes.schema.json b/uniCloud-aliyun/database/uni-stat-mp-scenes.schema.json new file mode 100644 index 0000000..a814ec0 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-mp-scenes.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"提供应用渠道和小程序场景值的数据字典","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"platform":{"bsonType":"string","description":"应用平台,对应uni-stat-app-platforms.code","foreignKey":"uni-stat-app-platforms.code"},"scene_code":{"bsonType":"string","description":"场景代码"},"scene_name":{"bsonType":"string","description":"场景名称"},"create_time":{"bsonType":"timestamp","description":"创建时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-page-detail-result.schema.json b/uniCloud-aliyun/database/uni-stat-page-detail-result.schema.json new file mode 100644 index 0000000..0f6d90b --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-page-detail-result.schema.json @@ -0,0 +1,95 @@ +// 页面内容统计结果表 +{ + "bsonType": "object", + "description": "存储汇总的页面内容访问数据", + "required": [], + "permission": { + "read": "'READ_UNI_STAT_PAGE_RESULT' in auth.permission", + "create": false, + "update": false, + "delete": false + }, + "properties": { + "_id": { + "description": "ID,系统自动生成" + }, + "appid": { + "bsonType": "string", + "description": "应用ID" + }, + "platform_id": { + "bsonType": "string", + "description": "应用平台ID,对应uni-stat-app-platforms._id", + "foreignKey": "uni-stat-app-platforms._id" + }, + "channel_id": { + "bsonType": "string", + "description": "渠道\/场景值ID,对应uni-stat-app-channels._id", + "foreignKey": "uni-stat-app-channels._id" + }, + "version_id": { + "bsonType": "string", + "description": "应用版本ID,对应opendb-app-versions._id", + "foreignKey": "opendb-app-versions._id" + }, + "page_id": { + "bsonType": "string", + "description": "页面表ID,对应uni-stat-pages._id", + "foreignKey": "uni-stat-pages._id" + }, + "page_detail_id": { + "bsonType": "string", + "description": "页面详情表ID,对应uni-stat-page-details._id", + "foreignKey": "uni-stat-page-details._id" + }, + "visit_times": { + "bsonType": "int", + "description": "访问次数" + }, + "visit_devices": { + "bsonType": "int", + "description": "访问设备数" + }, + "visit_users": { + "bsonType": "int", + "description": "访问用户数" + }, + "duration": { + "bsonType": "int", + "description": "访问总时长,单位秒" + }, + "share_count": { + "bsonType": "int", + "description": "分享次数" + }, + "dimension": { + "bsonType": "string", + "description": "统计范围 day:按天统计,hour:按小时统计", + "enum": [{ + "text": "月", + "value": "month" + }, { + "text": "周", + "value": "week" + }, { + "text": "天", + "value": "day" + }, { + "text": "小时", + "value": "hour" + }] + }, + "stat_date": { + "bsonType": "int", + "description": "统计日期,格式yyyymmdd,例:20211201" + }, + "start_time": { + "bsonType": "timestamp", + "description": "开始时间" + }, + "end_time": { + "bsonType": "timestamp", + "description": "结束时间" + } + } +} diff --git a/uniCloud-aliyun/database/uni-stat-page-details.schema.json b/uniCloud-aliyun/database/uni-stat-page-details.schema.json new file mode 100644 index 0000000..a0add8e --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-page-details.schema.json @@ -0,0 +1,42 @@ +// 应用页面详情表 +{ + "bsonType": "object", + "description": "记录上报的页面详情字典", + "required": [], + "permission": { + "read": "'READ_UNI_STAT_PAGE_LOGS' in auth.permission", + "create": false, + "update": false, + "delete": false + }, + "properties": { + "_id": { + "description": "ID,系统自动生成" + }, + "appid": { + "bsonType": "string", + "description": "应用ID" + }, + "page_id": { + "bsonType": "string", + "description": "当前页面ID,对应uni-stat-pages._id", + "foreignKey": "uni-stat-pages._id" + }, + "page_link": { + "bsonType": "string", + "description": "页面链接,匹配并去除链接中无用参数后的url" + }, + "page_title": { + "bsonType": "string", + "description": "页面标题" + }, + "create_time": { + "bsonType": "timestamp", + "description": "创建时间" + }, + "update_time": { + "bsonType": "timestamp", + "description": "修改时间" + } + } +} diff --git a/uniCloud-aliyun/database/uni-stat-page-logs.init_data.json b/uniCloud-aliyun/database/uni-stat-page-logs.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-page-logs.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-page-logs.schema.json b/uniCloud-aliyun/database/uni-stat-page-logs.schema.json new file mode 100644 index 0000000..2c3f003 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-page-logs.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"记录上报的页面访问日志","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"应用ID"},"version":{"bsonType":"string","description":"用户端上报的应用版本号"},"platform":{"bsonType":"string","description":"用户端上报的平台code"},"channel":{"bsonType":"string","description":"用户端上报的渠道code\/场景值"},"device_id":{"bsonType":"string","description":"客户端携带的设备标识"},"uid":{"bsonType":"string","description":"用户编号, 对应uni-id-users._id"},"session_id":{"bsonType":"string","description":"访问会话日志ID,对应uni-stat-session-logs._id","foreignKey":"uni-stat-session-logs._id"},"page_id":{"bsonType":"string","description":"当前页面ID,对应uni-stat-pages._id","foreignKey":"uni-stat-pages._id"},"page_detail_id":{"bsonType":"string","description":"页面详情表ID,对应uni-stat-page-details._id","foreignKey":"uni-stat-page-details._id"},"previous_page_id":{"bsonType":"string","description":"上级页面ID,为空表示第一个页面, 对应uni-stat-pages._id","foreignKey":"uni-stat-pages._id"},"previous_page_detail_id":{"bsonType":"string","description":"上级页面详情表ID,对应uni-stat-page-details._id","foreignKey":"uni-stat-page-details._id"},"previous_page_duration":{"bsonType":"int","description":"上级页面停留时间,单位秒,前端上报"},"previous_page_is_entry":{"bsonType":"int","defaultValue":0,"description":" 上级页面是否为入口页, 0否 1是","enum":[{"text":"否","value":0},{"text":"是","value":1}]},"query_string":{"bsonType":"string","description":"页面参数"},"create_time":{"bsonType":"timestamp","description":"创建时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-page-result.init_data.json b/uniCloud-aliyun/database/uni-stat-page-result.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-page-result.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-page-result.schema.json b/uniCloud-aliyun/database/uni-stat-page-result.schema.json new file mode 100644 index 0000000..8f33596 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-page-result.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"存储汇总的页面访问日志的数据","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"应用ID"},"platform_id":{"bsonType":"string","description":"应用平台ID,对应uni-stat-app-platforms._id","foreignKey":"uni-stat-app-platforms._id"},"channel_id":{"bsonType":"string","description":"渠道\/场景值ID,对应uni-stat-app-channels._id","foreignKey":"uni-stat-app-channels._id"},"version_id":{"bsonType":"string","description":"应用版本ID,对应opendb-app-versions._id","foreignKey":"opendb-app-versions._id"},"page_id":{"bsonType":"string","description":"页面表ID,对应页面表ID,对应uni-stat-pages._id","foreignKey":"uni-stat-pages._id"},"visit_times":{"bsonType":"int","description":"访问次数"},"visit_devices":{"bsonType":"int","description":"访问设备数"},"exit_times":{"bsonType":"int","description":"退出次数"},"duration":{"bsonType":"int","description":"访问总时长,单位秒"},"share_count":{"bsonType":"int","description":"分享次数"},"entry_devices":{"bsonType":"int","description":"当前页作为入口页的设备数"},"entry_users":{"bsonType":"int","description":"当前页作为入口页的用户数"},"entry_count":{"bsonType":"int","description":"当前页作为入口页的总次数"},"entry_duration":{"bsonType":"int","description":"当前页作为入口时,本页面的总访问时长,单位秒"},"bounce_times":{"bsonType":"int","description":"跳出次数"},"bounce_rate":{"bsonType":"double","description":"跳出率"},"dimension":{"bsonType":"string","description":"统计范围 day:按天统计,hour:按小时统计","enum":[{"text":"月","value":"month"},{"text":"周","value":"week"},{"text":"天","value":"day"},{"text":"小时","value":"hour"}]},"stat_date":{"bsonType":"int","description":"统计日期,格式yyyymmdd,例:20211201"},"start_time":{"bsonType":"timestamp","description":"开始时间"},"end_time":{"bsonType":"timestamp","description":"结束时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-pages.init_data.json b/uniCloud-aliyun/database/uni-stat-pages.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-pages.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-pages.schema.json b/uniCloud-aliyun/database/uni-stat-pages.schema.json new file mode 100644 index 0000000..9b57a68 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-pages.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"提供应用的页面字典","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"统计应用ID,对应opendb-app-list.appid","foreignKey":"opendb-app-list.appid"},"path":{"bsonType":"string","description":"页面路径,如`\/pages\/index\/index`"},"title":{"bsonType":"string","description":"页面标题"},"page_rules":{"bsonType":"array","description":"页面规则,每个页面最多设置5个,例:[['id','page'],['sid']]"},"create_time":{"bsonType":"timestamp","description":"创建时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-pay-result.init_data.json b/uniCloud-aliyun/database/uni-stat-pay-result.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-pay-result.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-pay-result.schema.json b/uniCloud-aliyun/database/uni-stat-pay-result.schema.json new file mode 100644 index 0000000..694fa0e --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-pay-result.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"存储统计汇总的支付数据","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"应用ID,对应opendb-app-list.appid","foreignKey":"opendb-app-list.appid"},"platform_id":{"bsonType":"string","description":"应用平台ID,对应uni-stat-app-platforms._id","foreignKey":"uni-stat-app-platforms._id"},"channel_id":{"bsonType":"string","description":"渠道\/场景值ID,对应uni-stat-app-channels._id","foreignKey":"uni-stat-app-channels._id"},"version_id":{"bsonType":"string","description":"应用版本ID,对应opendb-app-versions._id","foreignKey":"opendb-app-versions._id"},"pay_total_amount":{"bsonType":"int","description":"支付金额:统计时间内,成功支付的订单金额之和(不剔除退款订单)。单位分。"},"pay_order_count":{"bsonType":"int","description":"支付笔数:统计时间内,成功支付的订单数,一个订单对应唯一一个订单号。(不剔除退款订单。)"},"pay_user_count":{"bsonType":"int","description":"支付人数:统计时间内,成功支付的人数(不剔除退款订单)。"},"pay_device_count":{"bsonType":"int","description":"支付设备数:统计时间内,成功支付的设备数(不剔除退款订单)。"},"create_total_amount":{"bsonType":"int","description":"下单金额:统计时间内,成功下单的订单金额(不剔除退款订单)。单位分。"},"create_order_count":{"bsonType":"int","description":"下单笔数:统计时间内,成功下单的订单笔数(不剔除退款订单)。"},"create_user_count":{"bsonType":"int","description":"下单人数:统计时间内,成功下单的客户数,一人多次下单记为一人(不剔除退款订单)。"},"create_device_count":{"bsonType":"int","description":"下单设备数:统计时间内,成功下单的设备数,一台设备多次访问被计为一台(不剔除退款订单)。"},"refund_total_amount":{"bsonType":"int","description":"成功退款金额:统计时间内,成功退款的金额。以成功退款时间点为准。单位分。"},"refund_order_count":{"bsonType":"int","description":"成功退款订单数:统计时间内,成功退款的订单数。以成功退款时间点为准。"},"refund_user_count":{"bsonType":"int","description":"成功退款人数:统计时间内,成功退款的人数(不剔除退款订单)。"},"refund_device_count":{"bsonType":"int","description":"成功退款设备数:统计时间内,成功退款的设备数(不剔除退款订单)。"},"activity_user_count":{"bsonType":"int","description":"访问人数:统计时间内,访问人数,一人多次访问被计为一人(只统计已登录的用户)。"},"activity_device_count":{"bsonType":"int","description":"访问设备数:统计时间内,访问设备数,一台设备多次访问被计为一台(包含未登录的用户)。"},"new_user_count":{"bsonType":"int","description":"新增注册人数:统计时间内,注册人数。"},"new_device_count":{"bsonType":"int","description":"新增新设备数:统计时间内,新设备数。"},"new_user_create_order_count":{"bsonType":"int","description":"新用户下单人数:统计时间内,新增注册人数中下单的人数。"},"new_user_pay_order_count":{"bsonType":"int","description":"新用户支付人数:统计时间内,新增注册人数中下成功支付的人数。"},"dimension":{"bsonType":"string","description":"统计范围 hour:按小时统计,day:按天统计,week:按周统计,month:按月统计 quarter:按季度统计 year:按年统计","enum":[{"text":"年","value":"year"},{"text":"季度","value":"quarter"},{"text":"月","value":"month"},{"text":"周","value":"week"},{"text":"天","value":"day"},{"text":"小时","value":"hour"}]},"create_date":{"bsonType":"timestamp","description":"创建时间"},"start_time":{"bsonType":"timestamp","description":"统计开始时间"},"end_time":{"bsonType":"timestamp","description":"统计结束时间"},"stat_date":{"bsonType":"object","description":"统计日期参数","properties":{"date_str":{"bsonType":"string","description":"如:2021-07-27"},"year":{"bsonType":"int","description":"年"},"month":{"bsonType":"int","description":"月"},"day":{"bsonType":"int","description":"日"},"hour":{"bsonType":"int","description":"时"}}}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-result.init_data.json b/uniCloud-aliyun/database/uni-stat-result.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-result.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-result.schema.json b/uniCloud-aliyun/database/uni-stat-result.schema.json new file mode 100644 index 0000000..69cbc6b --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-result.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"存储统计汇总的会话数据包括不限于设备\/用户的数量、访问量、活跃度(日活、周活、月活)、留存率(日留存、周留存、月留存)、跳出率、访问时长等数据","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"应用ID,对应opendb-app-list.appid","foreignKey":"opendb-app-list.appid"},"platform_id":{"bsonType":"string","description":"应用平台ID,对应uni-stat-app-platforms._id","foreignKey":"uni-stat-app-platforms._id"},"channel_id":{"bsonType":"string","description":"渠道\/场景值ID,对应uni-stat-app-channels._id","foreignKey":"uni-stat-app-channels._id"},"version_id":{"bsonType":"string","description":"应用版本ID,对应opendb-app-versions._id","foreignKey":"opendb-app-versions._id"},"total_users":{"bsonType":"int","description":"历史累计总用户数"},"new_user_count":{"bsonType":"int","description":"本时间段新增用户数"},"active_user_count":{"bsonType":"int","description":"本时间段活跃用户数"},"total_devices":{"bsonType":"int","description":"历史累计总设备数"},"new_device_count":{"bsonType":"int","description":"本时间段新增设备数"},"user_session_times":{"bsonType":"int","description":"本时间段用户的会话次数"},"active_device_count":{"bsonType":"int","description":"本时间段活跃设备数"},"app_launch_count":{"bsonType":"int","description":"本时间段App启动或从后台切到前台的次数"},"error_count":{"bsonType":"int","description":"本时间段报错次数"},"duration":{"bsonType":"int","description":"时间段内,所有会话访问总时长,单位秒"},"user_duration":{"bsonType":"int","description":"本次登录用户的会话总时长,单位为秒"},"avg_device_session_time":{"bsonType":"int","description":"设备的次均停留时长,单位秒"},"avg_device_time":{"bsonType":"int","defaultValue":"设均停留时长(平均每台设备的停留时长),单位秒"},"avg_user_session_time":{"bsonType":"int","description":"用户的次均停留时长,单位秒"},"avg_user_time":{"bsonType":"int","defaultValue":"人均停留时长(平均每个登录用户的停留时长),单位秒"},"bounce_times":{"bsonType":"int","description":"跳出次数"},"bounce_rate":{"bsonType":"double","description":"跳出率"},"retention":{"bsonType":"object","description":"留存信息","properties":{"active_user":{"bsonType":"object","description":"活跃用户留存信息"},"new_user":{"bsonType":"object","description":"新增用户留存信息"},"active_device":{"bsonType":"object","description":"活跃设备留存信息"},"new_device":{"bsonType":"object","description":"新增设备留存信息"}}},"dimension":{"bsonType":"string","description":"统计范围 day:按天统计,hour:按小时统计","enum":[{"text":"月","value":"month"},{"text":"周","value":"week"},{"text":"天","value":"day"},{"text":"小时","value":"hour"}]},"stat_date":{"bsonType":"int","description":"统计日期,格式yyyymmdd,例:20211201"},"start_time":{"bsonType":"timestamp","description":"开始时间"},"end_time":{"bsonType":"timestamp","description":"结束时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-run-errors.init_data.json b/uniCloud-aliyun/database/uni-stat-run-errors.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-run-errors.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-run-errors.schema.json b/uniCloud-aliyun/database/uni-stat-run-errors.schema.json new file mode 100644 index 0000000..9a5fd86 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-run-errors.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"记录数据统计时运行出错的日志","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"mod":{"bsonType":"string","description":"运行模块"},"params":{"bsonType":"object","description":"运行参数"},"error":{"bsonType":"string","description":"错误信息"},"create_time":{"bsonType":"timestamp","description":"创建时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-session-logs.init_data.json b/uniCloud-aliyun/database/uni-stat-session-logs.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-session-logs.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-session-logs.schema.json b/uniCloud-aliyun/database/uni-stat-session-logs.schema.json new file mode 100644 index 0000000..bf02e3b --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-session-logs.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"记录设备访问时产生的会话日志","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"客户端上报的应用ID"},"version":{"bsonType":"string","description":"客户端上报的应用版本号"},"platform":{"bsonType":"string","description":"客户端上报的平台code"},"channel":{"bsonType":"string","description":"客户端上报的渠道code\/场景值"},"type":{"bsonType":"string","description":"会话类型","defaultValue":1,"enum":[{"text":"正常进入上报","value":1},{"text":"后台进前台超时上报","value":2},{"text":"页面停留超时上报","value":3}]},"device_id":{"bsonType":"string","description":"客户端携带的设备标识"},"last_visit_user_id":{"bsonType":"string","description":"本次会话最终访问用户的ID, uni-id-users._id,客户端上报"},"is_first_visit":{"bsonType":"int","description":"是否为首次访问","defaultValue":0,"enum":[{"text":"否","value":0},{"text":"是","value":1}]},"first_visit_time":{"bsonType":"timestamp","description":"用户首次访问时间"},"last_visit_time":{"bsonType":"timestamp","description":"用户最后一次访问时间"},"total_visit_count":{"bsonType":"int","description":"用户累计访问次数,客户端上报"},"entry_page_id":{"bsonType":"string","description":"本次会话入口页面ID, 同uni-stat-pagesd"},"exit_page_id":{"bsonType":"string","description":"本次会话退出页面ID, 同uni-stat-pagesd"},"page_count":{"bsonType":"int","description":"本次会话浏览的页面数"},"event_count":{"bsonType":"int","description":"本次会话产生的事件数"},"duration":{"bsonType":"int","description":"本次会话时长,单位为秒,服务端计算"},"sdk_version":{"bsonType":"string","description":"基础库版本号"},"platform_version":{"bsonType":"string","description":"平台版本,如微信、支付宝宿主App版本号"},"device_os":{"bsonType":"int","description":"设备系统编号,1:安卓,2:iOS,3:PC"},"device_os_version":{"bsonType":"string","description":"设备系统版本"},"device_net":{"bsonType":"string","description":"设备网络型号wifi\/3G\/4G\/"},"device_vendor":{"bsonType":"string","description":"设备供应商 "},"device_model":{"bsonType":"string","description":"设备型号"},"device_language":{"bsonType":"string","description":"设备语言包"},"device_pixel_ratio":{"bsonType":"string","description":"设备像素比 "},"device_window_width":{"bsonType":"string","description":"设备窗口宽度 "},"device_window_height":{"bsonType":"string","description":"设备窗口高度"},"device_screen_width":{"bsonType":"string","description":"设备屏幕宽度"},"device_screen_height":{"bsonType":"string","description":"设备屏幕高度"},"location_ip":{"bsonType":"string","description":"ip"},"location_latitude":{"bsonType":"double","description":"纬度"},"location_longitude":{"bsonType":"double","description":"经度"},"location_country":{"bsonType":"string","description":"国家"},"location_province":{"bsonType":"string","description":"省份"},"location_city":{"bsonType":"string","description":"城市"},"is_finish":{"bsonType":"int","defaultValue":0,"description":"本次会话是否结束,0:否,1是","enum":[{"text":"否","value":0},{"text":"是","value":1}]},"create_time":{"bsonType":"timestamp","description":"创建时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-share-logs.init_data.json b/uniCloud-aliyun/database/uni-stat-share-logs.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-share-logs.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-share-logs.schema.json b/uniCloud-aliyun/database/uni-stat-share-logs.schema.json new file mode 100644 index 0000000..6603536 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-share-logs.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"记录触发分享事件的日志","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"客户端上报的应用ID"},"version":{"bsonType":"string","description":"客户端上报的应用版本号"},"platform":{"bsonType":"string","description":"客户端上报的平台code"},"channel":{"bsonType":"string","description":"客户端上报的渠道code\/场景值"},"device_id":{"bsonType":"string","description":"客户端携带的设备标识"},"uid":{"bsonType":"string","description":"用户编号, 对应uni-id-users._id"},"session_id":{"bsonType":"string","description":"访问会话日志ID,对应uni-stat-session-logs._id","foreignKey":"uni-stat-session-logs._id"},"page_id":{"bsonType":"string","description":"当前页面ID,对应uni-stat-pagesd","foreignKey":"uni-stat-pagesd"},"page_detail_id":{"bsonType":"string","description":"页面详情表ID,对应uni-stat-page-details._id","foreignKey":"uni-stat-page-details._id"},"create_time":{"bsonType":"timestamp","description":"创建时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-user-session-logs.init_data.json b/uniCloud-aliyun/database/uni-stat-user-session-logs.init_data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-user-session-logs.init_data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uniCloud-aliyun/database/uni-stat-user-session-logs.schema.json b/uniCloud-aliyun/database/uni-stat-user-session-logs.schema.json new file mode 100644 index 0000000..41806b3 --- /dev/null +++ b/uniCloud-aliyun/database/uni-stat-user-session-logs.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","description":"记录登录用户的会话日志","required":[],"permission":{"read":false,"create":false,"update":false,"delete":false},"properties":{"_id":{"description":"ID,系统自动生成"},"appid":{"bsonType":"string","description":"客户端携带的应用ID"},"version":{"bsonType":"string","description":"客户端上报的应用版本号"},"platform":{"bsonType":"string","description":"客户端上报的平台code"},"channel":{"bsonType":"string","description":"客户端上报的渠道code\/场景值"},"session_id":{"bsonType":"string","description":"访问会话日志ID,对应uni-stat-session-logs._id","foreignKey":"uni-stat-session-logs._id"},"uid":{"bsonType":"string","description":"本次会话最终访问用户的ID, uni-id-users._id"},"last_visit_time":{"bsonType":"timestamp","description":"用户最后一次访问时间"},"entry_page_id":{"bsonType":"string","description":"本次会话入口页面ID, 同uni-stat-pagesd"},"exit_page_id":{"bsonType":"string","description":"本次会话退出页面ID, 同uni-stat-pagesd"},"page_count":{"bsonType":"int","description":"本次会话浏览的页面数"},"event_count":{"bsonType":"int","description":"本次会话产生的事件数"},"duration":{"bsonType":"int","description":"本次会话时长,单位为秒,服务端计算"},"is_finish":{"bsonType":"int","defaultValue":0,"description":"本次会话是否结束,0:否,1是","enum":[{"text":"否","value":0},{"text":"是","value":1}]},"create_time":{"bsonType":"timestamp","description":"创建时间"}},"version":"0.0.2"} \ No newline at end of file diff --git a/uni_modules/json-gps/changelog.md b/uni_modules/json-gps/changelog.md new file mode 100644 index 0000000..d9847e2 --- /dev/null +++ b/uni_modules/json-gps/changelog.md @@ -0,0 +1,2 @@ +## 1.0.0(2021-07-12) +第一版发布 diff --git a/uni_modules/json-gps/js_sdk/gps.js b/uni_modules/json-gps/js_sdk/gps.js new file mode 100644 index 0000000..f7b2f67 --- /dev/null +++ b/uni_modules/json-gps/js_sdk/gps.js @@ -0,0 +1,132 @@ +// #ifdef APP-PLUS +import permision from "./wa-permission/permission.js" +// #endif +class Gps { + constructor(arg) { + this.lock = false //锁防止重复请求 + } + async getLocation(param = { + type: 'wgs84' + }) { + return new Promise(async (callback) => { + if (this.lock) { + // console.log('已锁,已有另一个请求正在执行。无需重复请求'); + callback(false); + return false + } + this.lock = true //加锁防止重复的请求 + uni.getLocation({ + ...param, + success: res => { + this.lock = false //成功后解锁 + //console.log(res); + callback(res) + }, + fail: async (err) => { + uni.showToast({ + title: '定位获取失败', + icon: 'none' + }); + console.error(err) + callback(false) + + // #ifdef APP-PLUS + await this.checkGpsIsOpen() + // #endif + + // #ifdef MP-WEIXIN + if (err.errMsg == 'getLocation:fail auth deny') { + uni.showModal({ + content: '应用无定位权限', + confirmText: '前往设置', + complete: (e) => { + if (e.confirm) { + uni.openSetting({ + success(res) { + console.log(res.authSetting) + } + }); + } + this.lock = false //解锁让回到界面重新获取 + } + }); + } + if (err.errMsg == 'getLocation:fail:ERROR_NOCELL&WIFI_LOCATIONSWITCHOFF') { + uni.showModal({ + content: '未开启定位权限,请前往手机系统设置中开启', + showCancel: false, + confirmText:"知道了" + }); + } + // #endif + } + }); + }) + } + // #ifdef APP-PLUS + async checkGpsIsOpen() { + this.lock = true //加锁防止重复的请求 + // console.log('检查定位设置开启问题', permision.checkSystemEnableLocation()); + if (!permision.checkSystemEnableLocation()) { + plus.nativeUI.confirm("手机定位权限没有开启,是否去开启?", (e) => { + this.lock = false + if (e.index == 0) { + if (uni.getSystemInfoSync().platform == "ios") { + plus.runtime.openURL("app-settings://"); + } else { + var main = plus.android.runtimeMainActivity(); //获取activity + var Intent = plus.android.importClass('android.content.Intent'); + var Settings = plus.android.importClass('android.provider.Settings'); + var intent = new Intent(Settings + .ACTION_LOCATION_SOURCE_SETTINGS); //可设置表中所有Action字段 + main.startActivity(intent); + } + } else { + uni.showToast({ + title: '设备无定位权限', + icon: 'none' + }); + callback(false) + } + }, { + "buttons": ["去设置", "不开启"], + "verticalAlign": "center" + }); + return false + } + let checkAppGpsRes = await this.checkAppGps() + // console.log(checkAppGpsRes, 'checkAppGpsRes'); + if (!checkAppGpsRes) { + plus.nativeUI.confirm("应用定位权限没有开启,是否去开启?", (e) => { + this.lock = false + if (e.index == 0) { + permision.gotoAppPermissionSetting() + callback(false) + } else { + uni.showToast({ + title: '应用无定位权限', + icon: 'none' + }); + return false + } + }, { + "buttons": ["去设置", "不开启"], + "verticalAlign": "center" + }); + } else { + this.lock = false + } + } + async checkAppGps() { + if (uni.getSystemInfoSync().platform == "ios" && !permision.judgeIosPermission("location")) { + return false + } + if (uni.getSystemInfoSync().platform != "ios" && await permision.requestAndroidPermission( + "android.permission.ACCESS_FINE_LOCATION") != 1) { + return false + } + return true + } + // #endif +} +export default Gps diff --git a/uni_modules/json-gps/js_sdk/wa-permission/permission.js b/uni_modules/json-gps/js_sdk/wa-permission/permission.js new file mode 100644 index 0000000..98de006 --- /dev/null +++ b/uni_modules/json-gps/js_sdk/wa-permission/permission.js @@ -0,0 +1,272 @@ +/** + * 本模块封装了Android、iOS的应用权限判断、打开应用权限设置界面、以及位置系统服务是否开启 + */ + +var isIos +// #ifdef APP-PLUS +isIos = (plus.os.name == "iOS") +// #endif + +// 判断推送权限是否开启 +function judgeIosPermissionPush() { + var result = false; + var UIApplication = plus.ios.import("UIApplication"); + var app = UIApplication.sharedApplication(); + var enabledTypes = 0; + if (app.currentUserNotificationSettings) { + var settings = app.currentUserNotificationSettings(); + enabledTypes = settings.plusGetAttribute("types"); + console.log("enabledTypes1:" + enabledTypes); + if (enabledTypes == 0) { + console.log("推送权限没有开启"); + } else { + result = true; + console.log("已经开启推送功能!") + } + plus.ios.deleteObject(settings); + } else { + enabledTypes = app.enabledRemoteNotificationTypes(); + if (enabledTypes == 0) { + console.log("推送权限没有开启!"); + } else { + result = true; + console.log("已经开启推送功能!") + } + console.log("enabledTypes2:" + enabledTypes); + } + plus.ios.deleteObject(app); + plus.ios.deleteObject(UIApplication); + return result; +} + +// 判断定位权限是否开启 +function judgeIosPermissionLocation() { + var result = false; + var cllocationManger = plus.ios.import("CLLocationManager"); + var status = cllocationManger.authorizationStatus(); + result = (status != 2) + // console.log("定位权限开启:" + result); + // 以下代码判断了手机设备的定位是否关闭,推荐另行使用方法 checkSystemEnableLocation + /* var enable = cllocationManger.locationServicesEnabled(); + var status = cllocationManger.authorizationStatus(); + console.log("enable:" + enable); + console.log("status:" + status); + if (enable && status != 2) { + result = true; + console.log("手机定位服务已开启且已授予定位权限"); + } else { + console.log("手机系统的定位没有打开或未给予定位权限"); + } */ + plus.ios.deleteObject(cllocationManger); + return result; +} + +// 判断麦克风权限是否开启 +function judgeIosPermissionRecord() { + var result = false; + var avaudiosession = plus.ios.import("AVAudioSession"); + var avaudio = avaudiosession.sharedInstance(); + var permissionStatus = avaudio.recordPermission(); + console.log("permissionStatus:" + permissionStatus); + if (permissionStatus == 1684369017 || permissionStatus == 1970168948) { + console.log("麦克风权限没有开启"); + } else { + result = true; + console.log("麦克风权限已经开启"); + } + plus.ios.deleteObject(avaudiosession); + return result; +} + +// 判断相机权限是否开启 +function judgeIosPermissionCamera() { + var result = false; + var AVCaptureDevice = plus.ios.import("AVCaptureDevice"); + var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide'); + console.log("authStatus:" + authStatus); + if (authStatus == 3) { + result = true; + console.log("相机权限已经开启"); + } else { + console.log("相机权限没有开启"); + } + plus.ios.deleteObject(AVCaptureDevice); + return result; +} + +// 判断相册权限是否开启 +function judgeIosPermissionPhotoLibrary() { + var result = false; + var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary"); + var authStatus = PHPhotoLibrary.authorizationStatus(); + console.log("authStatus:" + authStatus); + if (authStatus == 3) { + result = true; + console.log("相册权限已经开启"); + } else { + console.log("相册权限没有开启"); + } + plus.ios.deleteObject(PHPhotoLibrary); + return result; +} + +// 判断通讯录权限是否开启 +function judgeIosPermissionContact() { + var result = false; + var CNContactStore = plus.ios.import("CNContactStore"); + var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0); + if (cnAuthStatus == 3) { + result = true; + console.log("通讯录权限已经开启"); + } else { + console.log("通讯录权限没有开启"); + } + plus.ios.deleteObject(CNContactStore); + return result; +} + +// 判断日历权限是否开启 +function judgeIosPermissionCalendar() { + var result = false; + var EKEventStore = plus.ios.import("EKEventStore"); + var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0); + if (ekAuthStatus == 3) { + result = true; + console.log("日历权限已经开启"); + } else { + console.log("日历权限没有开启"); + } + plus.ios.deleteObject(EKEventStore); + return result; +} + +// 判断备忘录权限是否开启 +function judgeIosPermissionMemo() { + var result = false; + var EKEventStore = plus.ios.import("EKEventStore"); + var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1); + if (ekAuthStatus == 3) { + result = true; + console.log("备忘录权限已经开启"); + } else { + console.log("备忘录权限没有开启"); + } + plus.ios.deleteObject(EKEventStore); + return result; +} + +// Android权限查询 +function requestAndroidPermission(permissionID) { + return new Promise((resolve, reject) => { + plus.android.requestPermissions( + [permissionID], // 理论上支持多个权限同时查询,但实际上本函数封装只处理了一个权限的情况。有需要的可自行扩展封装 + function(resultObj) { + var result = 0; + for (var i = 0; i < resultObj.granted.length; i++) { + var grantedPermission = resultObj.granted[i]; + console.log('已获取的权限:' + grantedPermission); + result = 1 + } + for (var i = 0; i < resultObj.deniedPresent.length; i++) { + var deniedPresentPermission = resultObj.deniedPresent[i]; + console.log('拒绝本次申请的权限:' + deniedPresentPermission); + result = 0 + } + for (var i = 0; i < resultObj.deniedAlways.length; i++) { + var deniedAlwaysPermission = resultObj.deniedAlways[i]; + console.log('永久拒绝申请的权限:' + deniedAlwaysPermission); + result = -1 + } + resolve(result); + // 若所需权限被拒绝,则打开APP设置界面,可以在APP设置界面打开相应权限 + // if (result != 1) { + // gotoAppPermissionSetting() + // } + }, + function(error) { + console.log('申请权限错误:' + error.code + " = " + error.message); + resolve({ + code: error.code, + message: error.message + }); + } + ); + }); +} + +// 使用一个方法,根据参数判断权限 +function judgeIosPermission(permissionID) { + if (permissionID == "location") { + return judgeIosPermissionLocation() + } else if (permissionID == "camera") { + return judgeIosPermissionCamera() + } else if (permissionID == "photoLibrary") { + return judgeIosPermissionPhotoLibrary() + } else if (permissionID == "record") { + return judgeIosPermissionRecord() + } else if (permissionID == "push") { + return judgeIosPermissionPush() + } else if (permissionID == "contact") { + return judgeIosPermissionContact() + } else if (permissionID == "calendar") { + return judgeIosPermissionCalendar() + } else if (permissionID == "memo") { + return judgeIosPermissionMemo() + } + return false; +} + +// 跳转到**应用**的权限页面 +function gotoAppPermissionSetting() { + if (isIos) { + var UIApplication = plus.ios.import("UIApplication"); + var application2 = UIApplication.sharedApplication(); + var NSURL2 = plus.ios.import("NSURL"); + // var setting2 = NSURL2.URLWithString("prefs:root=LOCATION_SERVICES"); + var setting2 = NSURL2.URLWithString("app-settings:"); + application2.openURL(setting2); + + plus.ios.deleteObject(setting2); + plus.ios.deleteObject(NSURL2); + plus.ios.deleteObject(application2); + } else { + // console.log(plus.device.vendor); + var Intent = plus.android.importClass("android.content.Intent"); + var Settings = plus.android.importClass("android.provider.Settings"); + var Uri = plus.android.importClass("android.net.Uri"); + var mainActivity = plus.android.runtimeMainActivity(); + var intent = new Intent(); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + var uri = Uri.fromParts("package", mainActivity.getPackageName(), null); + intent.setData(uri); + mainActivity.startActivity(intent); + } +} + +// 检查系统的设备服务是否开启 +// var checkSystemEnableLocation = async function () { +function checkSystemEnableLocation() { + if (isIos) { + var result = false; + var cllocationManger = plus.ios.import("CLLocationManager"); + var result = cllocationManger.locationServicesEnabled(); + // console.log("系统定位开启:" + result); + plus.ios.deleteObject(cllocationManger); + return result; + } else { + var context = plus.android.importClass("android.content.Context"); + var locationManager = plus.android.importClass("android.location.LocationManager"); + var main = plus.android.runtimeMainActivity(); + var mainSvr = main.getSystemService(context.LOCATION_SERVICE); + var result = mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER); + console.log("系统定位开启:" + result); + return result + } +} + +export default { + judgeIosPermission: judgeIosPermission, + requestAndroidPermission: requestAndroidPermission, + checkSystemEnableLocation: checkSystemEnableLocation, + gotoAppPermissionSetting: gotoAppPermissionSetting +} diff --git a/uni_modules/json-gps/package.json b/uni_modules/json-gps/package.json new file mode 100644 index 0000000..3689121 --- /dev/null +++ b/uni_modules/json-gps/package.json @@ -0,0 +1,76 @@ +{ + "id": "json-gps", + "displayName": "地理位置获取方法,支持在onShow生命周期使用集成权限判断和引导开启(包括设备权限和应用权限)", + "version": "1.0.0", + "description": "支持在onShow生命周期使用集成权限判断和引导开启(包括设备权限和应用权限)的地理位置获取方法", + "keywords": [ + "权限引导" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "category": [ + "JS SDK", + "通用 SDK" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "y", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/json-gps/readme.md b/uni_modules/json-gps/readme.md new file mode 100644 index 0000000..739335f --- /dev/null +++ b/uni_modules/json-gps/readme.md @@ -0,0 +1,30 @@ +### 插件简介: +支持在onShow生命周期,使用的集成权限判断和引导开启(包括设备权限和应用权限)的地理位置获取方法 + +### 插件背景: +实现获取用户地理位置,当手机未开启定位模块或应用无定位权限时,引导用户前往手机系统或应用权限设置页面。设置完回到应用界面自动重新获取。 +为了实现该效果,开发者把获取定位权限放在onShow生命周期,然而即使是原生开发,调用判断设备权限操作也会触发onShow生命周期,直接使用会导致死循环。因此本插件,二次封装用锁的方式控制该问题。 + +### 使用方式 +```js +import Gps from '@/uni_modules/json-gps/js_sdk/gps.js'; +const gps = new Gps() +export default { + async onShow() { + uni.showLoading({ + title:"获取定位中" + }); + let location = await gps.getLocation() + console.log(location); + if(location){ + uni.showToast({ + title: JSON.stringify(location), + icon: 'none' + }); + } + uni.hideLoading() + } +} +``` + +>本插件基于第三方插件:[App权限判断和提示](https://ext.dcloud.net.cn/plugin?id=594)二次封装而成 \ No newline at end of file diff --git a/uni_modules/json-interceptor-chooseImage/changelog.md b/uni_modules/json-interceptor-chooseImage/changelog.md new file mode 100644 index 0000000..512bce8 --- /dev/null +++ b/uni_modules/json-interceptor-chooseImage/changelog.md @@ -0,0 +1,6 @@ +## 1.0.2(2021-05-20) +修复IOS提示不准确,无摄像头权限提示了无法访问相册 +## 1.0.1(2021-05-20) +新增文档和示例代码 +## 1.0.0(2021-05-20) +第一版本发布 diff --git a/uni_modules/json-interceptor-chooseImage/js_sdk/main.js b/uni_modules/json-interceptor-chooseImage/js_sdk/main.js new file mode 100644 index 0000000..7cf7bc6 --- /dev/null +++ b/uni_modules/json-interceptor-chooseImage/js_sdk/main.js @@ -0,0 +1,70 @@ +export default function(){ + //当应用无访问摄像头/相册权限,引导跳到设置界面 + uni.addInterceptor('chooseImage', { + fail(e) { // 失败回调拦截 更多拦截器用法 [详情](https://uniapp.dcloud.io/api/interceptor?id=addinterceptor) + console.log(e); + if (uni.getSystemInfoSync().platform == "android" && e.errMsg == 'chooseImage:fail No Permission') { + if (e.code === 11) { + uni.showModal({ + title: "无法访问摄像头", + content: "当前无摄像头访问权限,建议前往设置", + confirmText: "前往设置", + success(e) { + if (e.confirm) { + gotoAppPermissionSetting() + } + } + }); + } else { + uni.showModal({ + title: "无法访问相册", + content: "当前无系统相册访问权限,建议前往设置", + confirmText: "前往设置", + success(e) { + if (e.confirm) { + gotoAppPermissionSetting() + } + } + }); + } + } else if (e.errCode === 2&&e.errMsg == "chooseImage:fail No filming permission") { + console.log('e.errMsg === 2 ios无法拍照权限 '); + // 注:e.errCode === 8 ios无从相册选择图片的权限 api已内置无需自己用拦截器实现 + uni.showModal({ + title: "无法访问摄像头", + content: "当前无摄像头访问权限,建议前往设置", + confirmText: "前往设置", + success(e) { + if (e.confirm) { + gotoAppPermissionSetting() + } + } + }); + } + } + }) + + //跳转到**应用**的权限页面 参考来源:https://ext.dcloud.net.cn/plugin?id=594 + function gotoAppPermissionSetting() { + if (uni.getSystemInfoSync().platform == "ios") { + var UIApplication = plus.ios.import("UIApplication"); + var application2 = UIApplication.sharedApplication(); + var NSURL2 = plus.ios.import("NSURL"); + var setting2 = NSURL2.URLWithString("app-settings:"); + application2.openURL(setting2); + plus.ios.deleteObject(setting2); + plus.ios.deleteObject(NSURL2); + plus.ios.deleteObject(application2); + } else { + var Intent = plus.android.importClass("android.content.Intent"); + var Settings = plus.android.importClass("android.provider.Settings"); + var Uri = plus.android.importClass("android.net.Uri"); + var mainActivity = plus.android.runtimeMainActivity(); + var intent = new Intent(); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + var uri = Uri.fromParts("package", mainActivity.getPackageName(), null); + intent.setData(uri); + mainActivity.startActivity(intent); + } + } +} \ No newline at end of file diff --git a/uni_modules/json-interceptor-chooseImage/package.json b/uni_modules/json-interceptor-chooseImage/package.json new file mode 100644 index 0000000..9b81e6a --- /dev/null +++ b/uni_modules/json-interceptor-chooseImage/package.json @@ -0,0 +1,76 @@ +{ + "id": "json-interceptor-chooseImage", + "displayName": "拦截器应用示例 — 图片选择", + "version": "1.0.2", + "description": "当选择图片遇到权限问题时引导用户快捷打开系统设置", + "keywords": [ + "interceptor,拦截器,相册权限" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "category": [ + "JS SDK", + "通用 SDK" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "H5-mobile": { + "Safari": "n", + "Android Browser": "n", + "微信浏览器(Android)": "n", + "QQ浏览器(Android)": "n" + }, + "H5-pc": { + "Chrome": "n", + "IE": "n", + "Edge": "n", + "Firefox": "n", + "Safari": "n" + }, + "小程序": { + "微信": "n", + "阿里": "n", + "百度": "n", + "字节跳动": "n", + "QQ": "n" + }, + "快应用": { + "华为": "n", + "联盟": "n" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/json-interceptor-chooseImage/readme.md b/uni_modules/json-interceptor-chooseImage/readme.md new file mode 100644 index 0000000..e9d98fb --- /dev/null +++ b/uni_modules/json-interceptor-chooseImage/readme.md @@ -0,0 +1,30 @@ +拦截器顾名思义,是在框架方法执行的各个环节(包含:拦截前触发、成功回调拦截、失败回调拦截、完成回调拦截) +插入逻辑,篡改参数或终止运行。 +#### 优势 +- 这种方式相当于改写了api的内部逻辑,相比语法糖他更加直观,不影响ide的代码提示。 +- 将常规固定的逻辑封装到框架的api内,且支持个性化设计。如你可以在本插件路径:`/uni_modules/json-interceptor-chooseImage/js_sdk/main.js`修改弹出框元素,绘制更漂亮的样式和文字说明。 + +#### 使用示例,App.vue页代码如下: +``` + +``` + +> 跳转到**应用**的权限页面 参考来源:[https://ext.dcloud.net.cn/plugin?id=594](https://ext.dcloud.net.cn/plugin?id=594) 感谢作者@DCloud_heavensoft diff --git a/uni_modules/kevy-collapse/changelog.md b/uni_modules/kevy-collapse/changelog.md new file mode 100644 index 0000000..dec50dd --- /dev/null +++ b/uni_modules/kevy-collapse/changelog.md @@ -0,0 +1,31 @@ +## 1.0.4(2023-05-23) +- 修改已知问题; + +- 代码优化; + +- **注意**插件符合uni_modules规范,使用时直接点击插件详情页导入hbuilderx,然后在要使用的页面直接通过标签(参考插件使用示例代码)引入即可。 +## 1.0.3(2023-05-05) +- 针对vue3部分编译器语法警告优化; +- readme示例代码提供请求后再更新数据逻辑示例; +- **注意**插件符合uni_modules规范,使用时直接点击插件详情页导入hbuilderx,然后在要使用的页面直接通过标签(参考插件使用示例代码)引入即可。 +## 1.0.2(2023-05-04) +- 针对用户反馈,代码细节进行了优化; +- **注意**插件符合uni_modules规范,使用时直接点击插件详情页导入hbuilderx,然后在要使用的页面直接通过标签(参考插件使用示例代码)引入即可。 +## 1.0.1(2023-04-25) +- 这是一个各端通用的折叠面板组件,可以折叠/展开的内容区域,支持复杂的表格形式展示,简单的设置即可实现,节省效率必备; +- 插件含全部源码,可以给您无限实现可能,随心所欲自定义你的功能; +- 符合uni_modules和easycom规范,直接导入即可通过标签引入使用。 + +## 1.0.2(2023-05-04) +- 针对用户反馈,代码细节进行了优化; +- **注意**插件符合uni_modules规范,使用时直接点击插件详情页导入hbuilderx,然后在要使用的页面直接通过标签(参考插件使用示例代码)引入即可。 + +## 1.0.3(2023-05-05) +- 针对vue3部分编译器语法警告优化; +- readme示例代码提供请求后再更新数据逻辑示例; +- **注意**插件符合uni_modules规范,使用时直接点击插件详情页导入hbuilderx,然后在要使用的页面直接通过标签(参考插件使用示例代码)引入即可。 +- +## 1.0.4(2023-05-23) +- 修改已知问题; +- 代码优化; +- **注意**插件符合uni_modules规范,使用时直接点击插件详情页导入hbuilderx,然后在要使用的页面直接通过标签(参考插件使用示例代码)引入即可。 \ No newline at end of file diff --git a/uni_modules/kevy-collapse/components/kevy-collapse/kevy-collapse.vue b/uni_modules/kevy-collapse/components/kevy-collapse/kevy-collapse.vue new file mode 100644 index 0000000..4356370 --- /dev/null +++ b/uni_modules/kevy-collapse/components/kevy-collapse/kevy-collapse.vue @@ -0,0 +1,312 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/kevy-collapse/package.json b/uni_modules/kevy-collapse/package.json new file mode 100644 index 0000000..b604074 --- /dev/null +++ b/uni_modules/kevy-collapse/package.json @@ -0,0 +1,85 @@ +{ + "id": "kevy-collapse", + "displayName": "kevy-collapse(折叠面板)全端通用含源码可随心定制,支持复杂表格", + "version": "1.0.4", + "description": "这是一个各端通用的折叠面板组件,可以折叠/展开的内容区域,支持复杂的表格形式展示,简单的设置即可实现,节省效率必备,插件含全部源码,给你无限可能自定义你的功能", + "keywords": [ + "折叠面板", + "折叠", + "collapse", + "面板", + "表格" +], + "repository": "", + "engines": { + "HBuilderX": "^3.6.10" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无 " + }, + "npmurl": "", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y", + "钉钉": "y", + "快手": "y", + "飞书": "y", + "京东": "y" + }, + "快应用": { + "华为": "y", + "联盟": "y" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/kevy-collapse/readme.md b/uni_modules/kevy-collapse/readme.md new file mode 100644 index 0000000..29dc94a --- /dev/null +++ b/uni_modules/kevy-collapse/readme.md @@ -0,0 +1,122 @@ +# kevy-collapse + +#### 介绍 +这是一个**全端通用的折叠面板组件**,可以折叠/展开的内容区域,支持**复杂的表格形式展示**,简单的设置即可实现,节省效率必备。 +- 插件含全部源码,可以给您无限实现可能,随心所欲自定义你的功能; +- 符合uni_modules和easycom规范,直接导入即可通过标签引入使用。 + +祝您使用愉快,本插件会长期维护更新,开源不易,如果本插件对您有帮助的话请及时点个好评吧或者赞赏一下,总之谢谢您的鼓励啦。 + + +#### 方法和属性 + +| 名称 | 类型 | 默认值 | 字段说明 | +| ------- | ------- |------ |------ +| accordion | Boolean | true | 是否开启手风琴效果 | +| fontSize | Number | 32 | 标题文字大小,单位rpx | +| color| String | #333333 | 标题文字颜色 | +| arrowColor| String | #333333 | 箭头颜色 | +| contentColor| String | #666 | 内容文字颜色 | +| contentFontSize| Number | 32 | 内容文字大小,单位rpx | +| collapseData | Array | [] | 折叠面板数据列表,内部数据为Object类型,**格式见下方collapseData字段说明** | + +#### collapseData字段说明(内部为Object对象) +| 名称 | 类型 | 说明 | +| :------------ | :------------ | :------------ | +| title | String | 标题 | +| table | Boolean | 是否内容为表格格式,默认false | +| open | Boolean | 是否展开,默认false | +| bold | Boolean | 标题是否加粗,默认false | +| disabled | Boolean | 是否禁用,默认false | +| hideArrow | Boolean | 是否隐藏箭头,默认false | +| content | String或Object | 内容,table=true时必须为Object,**对应的数据见tableData说明** | + +#### tableData说明 +| 名称 | 类型 | 说明 | +| :------------ | :------------ | :------------ | +| head | Array | 表格头部head,示例数据:['项目','单价','使用量','金额'] | +| data | Array | 表格body数据,示例数据:[["垃圾费","¥6.09",'1','¥6.09'],["物业费","¥6.09",'1','¥6.09']] | +| bordered | Boolean | 表格body每行tr是否有底部边框,默认false | + +#### 使用方式 +插件详情页点击导入hbuilder即可。插件符合uni_modules和easycom规范,导入后可直接在页面通过标签引用。 + +#### 代码使用示例 +```html + + + + + +``` \ No newline at end of file diff --git a/uni_modules/kevy-collapse/static/icon/iconfont.css b/uni_modules/kevy-collapse/static/icon/iconfont.css new file mode 100644 index 0000000..86e5a0c --- /dev/null +++ b/uni_modules/kevy-collapse/static/icon/iconfont.css @@ -0,0 +1,19 @@ +@font-face { + font-family: 'iconfont'; /* Project id 4035241 */ + src: url('/uni_modules/kevy-collapse/static/icon/iconfont.woff2') format('woff2'), + url('/uni_modules/kevy-collapse/static/icon/iconfont.woff') format('woff'), + url('/uni_modules/kevy-collapse/static/icon/iconfont.ttf') format('truetype'); +} + +.iconfont { + font-family: "iconfont" !important; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-arrow:before { + content: "\eb8a"; + transition: transform .2s linear; +} + diff --git a/uni_modules/kevy-collapse/static/icon/iconfont.ttf b/uni_modules/kevy-collapse/static/icon/iconfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c844ea637cfb224b4484559af24e3fa5025ba01b GIT binary patch literal 1596 zcmd^9Jx>%t7=C8=?m$kFKw|vLxj}?P$sJrFhMs1I zBoQ_2xn18TF_HNR402#yPF%yVza(lUk&O3{W}(E z_IEWjxu8mkYw*N@-jEVg%66Qr^y=lz-I9->Gq7Q5Kz((O`wvIT;SL~V{{MSB8WiBH zDnn2!St-ilDad;sAZ?j9jrA8zJp(-h+LO)1#zsQC+)S*mCj#$wY$+c=-qFxs-joi7 zH8kOj!aDg*g(Jil6^`<+PAeQEe^ucYT*8RLaYii56OSC>I^9@OSfCAW71q#-j|%JL zzbG6b{-$sgC-6hz82R4{w_uw8a~MC4Zjl-GEYr8L#%#?fW?U!dI(}oGu<}*g^crGg zp0>P7(RGaeWM6|CvmDE7gsIHu)4rcGa-LfAj#(I(MU7(-8Mtte3r7DRd4kq?RAJN8`$v1wdz#iBDzuX^4fG?)r{bX1 z7_FSZ@?bU<%yYFgbM%>!!R|3qiD*>iXE76-*x&(5-5ld&Xq`kM@G4^vDSnOpH0+bX nK1=d337dS=4r`jwgpN~lMbq)!>Wp2qW{ak~KrvsV?9%5C&REmE literal 0 HcmV?d00001 diff --git a/uni_modules/kevy-collapse/static/icon/iconfont.woff b/uni_modules/kevy-collapse/static/icon/iconfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..572dc6f05014bc631b3e2b6fa45d71f35dca1759 GIT binary patch literal 992 zcmXT-cXMN4WB>x@2MpXGn#~5n2eDCsdvK@|0|O%mP}CZTLlnAItNerYjeueGfzVWt=mW7cd+UUbiaE&%DG3P=k_-|y zBqtOVe&$SkaN1MnWb%Zhgv17h2{uNv4b_cpCpI!4V?MR9A(Kxbt+|7VLCu=gg8`&B zF)?Azfdi)w9Jq3_q^+@Wp}dpvzBGfRCk$Oi8;pz-SQ#_dY4WhgmG6C*l=tKQfddC> z+8I5J3>Il5F)=is=dA;ok&uuI#B52j3TcT62|S4jDGZGE3pA7?=FDv5);V`*0ZZ6n zCZYPfU;o?puzZRaz~_u!vn`}Qi&uHrm;6e)q>nDaQF}dlf$HmjG_jN4DK9E*(^YtKo|^waR61Dkd%%sYoB8+l&6GXK@NPqU`={N{^==+k-8@Nq$AQHK zQ-4j~;9n=UZei!Vg1Ns|7clEr2;wzOmxWtgU>p8%p$EZ@)e9g=2;gPr^dO*5ouUfq;u(QPOV*{`{e$ybA6?IsQ?LXi#FOcYCTc=^8C#0I(t9mkMB;fP1cY;Cd9a( zw5{|yZCjnD0{-_lvKCm7`qliwKQLSZiN#2eN|T_+liJ;?jZTUxJKX8-Saa98%AsD@ zh+v(e3|YMqs&F%?(PRa+>aC&Cti8icx;&Fb;TkaEP7vBXkhJ=Vtlfty+!r-^{ZOmj zAB`?X%Xv*EqTDd%f)x}i*pfQsnk3SCL_Ib+*JZBAgQY2m{IFa)V23=#hGEjNhyumb z!d^axO+(N#IV{CDB7G7Bs_89$Nv*fRP)?u + + + + + + + + + 搜索 + + + + + + + + + + + + + + + diff --git a/uni_modules/next-search-more/package.json b/uni_modules/next-search-more/package.json new file mode 100644 index 0000000..f0f64e2 --- /dev/null +++ b/uni_modules/next-search-more/package.json @@ -0,0 +1,79 @@ +{ + "id": "next-search-more", + "displayName": "next-search-more(vue2 vue3多端通用)搜索框组合、搜索下拉框组件全端可用", + "version": "1.0.9", + "description": "搜索下拉框,支持多种展示形式,可以结合第三方组件一起使用,可自定义", + "keywords": [ + "远程搜索", + "组合搜索", + "配置搜索", + "自定义搜索", + "搜索下拉框" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.1" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "无" + }, + "npmurl": "", + "type": "component-vue" + }, + "uni_modules": { + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "n", + "app-nvue": "n" + }, + "H5-mobile": { + "Safari": "n", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "n", + "Edge": "n", + "Firefox": "n", + "Safari": "n" + }, + "小程序": { + "微信": "y", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u" + }, + "快应用": { + "华为": "n", + "联盟": "n" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/next-search-more/readme.md b/uni_modules/next-search-more/readme.md new file mode 100644 index 0000000..b418bae --- /dev/null +++ b/uni_modules/next-search-more/readme.md @@ -0,0 +1,215 @@ + +## next-search-more --搜索更多,搜索下拉,search-more + +> 遇到问题或有建议可以加入QQ群(455948571)反馈 +> 如果觉得组件不错,给五星鼓励鼓励咯! + + +## 使用 + +>[从uniapp插件市场导入](https://ext.dcloud.net.cn/plugin?name=next-search-more) + +```html + +``` + +### vue3 + ts 使用 + +```js + + + + + +``` +### vue2 同样支持,在这里不再写demo + +### 组件按需加载 +如果不需要组件全局加载,而已把组件拷贝到项目的components目录下,单独引入进来使用即可达到按需加载的效果 +### 预览 + +*** + +| 功能预览 | | 项目中应用演示 | +| :--------------------------------------------------------------------------:| | :-----------------------------------------------------------------------------:| +| ![](https://lixueshiaa.github.io/webtest/www/static/next-search-more.gif) | | ![](https://lixueshiaa.github.io/webtest/www/static/next-search-more-demo.gif) | + + +## 参数 + + +### next-search-more Props + +可选参数属性列表 + +|参数名 |说明 |类型 |是否必填 |默认值 |可选值 | +|---- |---- |---- |---- |---- |---- | +|mode |模式mode,支持common模式 center模式 more模式 |String |否 |common |center,more| +|button |搜索按钮的模式,支持outside模式 inside模式 |String |否 |outside |inside | +|isFixedSearchBtn |是否固定搜索按钮 |Boolean |否 |true |false | +|radius |搜索控件的radius |String, Number |否 |60 |- | +|placeholder | placeholder |String |否 |请输入搜索内容 |- | +|backgroundColor |搜索控件的背景颜色 |String |否 |#fff |- | +|showMore | mode=more模式下,用于控制打开下拉弹层 |Boolean |否 |false |true | +|border| border |String |否 |1px #f5f5f5 solid |- | + + +# Event 事件 +|事件名 |说明 |类型 |回调参数 | +|---- |---- |---- |---- | +|input |搜索框输入事件 |emit |- | +|search|搜索触发的事件 |emit |- | +|moreClick|更多按钮点击触发事件 |emit |- | + +## Slot 插槽 + +|名称 |说明 |参数 | +|---- |---- |---- | +|more |more插槽,在mode=more模式下用于存放下拉框内容 |无 | diff --git a/uni_modules/next-tree/changelog.md b/uni_modules/next-tree/changelog.md new file mode 100644 index 0000000..efdddaf --- /dev/null +++ b/uni_modules/next-tree/changelog.md @@ -0,0 +1,169 @@ +## 1.8.7(2024-05-08) +fix bug +## 1.8.6(2024-04-07) +功能更新 +## 1.8.5(2024-04-07) +修复bug +## 1.8.3(2024-04-06) +update +## 1.8.2(2024-04-06) +update +## 1.8.1(2024-04-06) +fix bug +## 1.8.0(2024-04-03) +优化 +## 1.7.9(2024-04-03) +优化编辑tree功能 +## 1.7.8(2024-04-02) +超集功能上线 +## 1.7.7(2024-03-26) +增加expandedMode=singe +## 1.7.6(2024-02-27) +修复特殊字符的处理方法 +## 1.7.5(2024-02-26) +增加无子节点的父节点配置 +## 1.7.4(2024-02-05) +修复vue2,语法使用问题 +## 1.7.3(2024-02-05) +修复vue2,插槽不显示bug +## 1.7.2(2024-02-05) +优化大数据的性能 +## 1.7.1(2024-01-25) +优化功能说明 +## 1.7.0(2024-01-24) +增加expandedKeys默认展开项目,配置 +## 1.6.9(2024-01-23) +增加change事件 +## 1.6.8(2024-01-22) +搜索模式下,不再响应展开收起逻辑 +## 1.6.7(2024-01-04) +修复异步加载节点搜索展示bug +## 1.6.6(2023-12-29) +修复next-tree异步加载节点关闭bug +## 1.6.5(2023-12-21) +fix bug +## 1.6.4(2023-12-21) +fix bug +## 1.6.3(2023-12-21) +更新vue2版本说明文档 +## 1.6.2(2023-12-21) +修复说明文档 +## 1.6.1(2023-12-18) +增加empty插槽 +## 1.6.0(2023-12-18) +增加empty插槽 +## 1.5.9(2023-12-15) +修改说明文件 +## 1.5.8(2023-12-15) +修复changeVerify函数单选时,返回参数bug +## 1.5.7(2023-12-14) +修复checkStrictlyModel === 'strong'的bug +## 1.5.6(2023-12-13) +代码优化 +## 1.5.5(2023-12-13) +优化changeVerify的使用 +## 1.5.4(2023-12-12) +修复提示层级问题 +## 1.5.3(2023-12-12) +优化uiMode=page模式下的使用 +## 1.5.2(2023-12-11) +增加uiMode配置,实现页面模式展示 +## 1.5.1(2023-12-06) +更新说明 +## 1.5.0(2023-12-06) +更新插件使用注意事项 +## 1.4.9(2023-12-01) +增加topBar插槽 +## 1.4.8(2023-11-30) +增加changeVerify验证函数,实现change的各种控制 +## 1.4.7(2023-11-30) +增加弹层容器高度可配置 +## 1.4.6(2023-11-28) +修复bug +## 1.4.5(2023-11-28) +修复disabled是,需要显示灰色不可操作 +## 1.4.4(2023-11-28) +增加说明 +## 1.4.3(2023-11-28) +增加主题配置 +## 1.4.2(2023-11-28) +增加异步加载时,子节点说明 +## 1.4.1(2023-11-27) +修复说明bug +## 1.4.0(2023-11-27) +next-tree 全面说明文档 +## 1.3.6(2023-11-27) +增加远程加载loadData,全面实现全功能覆盖 +## 1.3.5(2023-11-27) +增加title的定义 +## 1.3.4(2023-11-27) +增加title支持自定义定制 +## 1.3.3(2023-11-21) +增加搜索模式searchModel=depHighlight模式,从属高亮显示模式 +## 1.3.2(2023-11-20) +修复valueKey设置bug +## 1.3.1(2023-11-17) +增加说明文件,和demo +## 1.3.0(2023-11-17) +修复clear时不支持关联模式的设置 +## 1.2.9(2023-11-17) +增加checkStrictlyModel模式设置,强关联,和弱关联 +## 1.2.8(2023-11-16) +增加next-tree的辅助线模式 +## 1.2.7(2023-11-16) +优化next-tree +## 1.2.6(2023-11-16) +修复搜索时,隐藏未打开的数据 +## 1.2.5(2023-11-16) +修复搜索无法点击,和级联半选不生效问题 +## 1.2.4(2023-11-16) +更新新功能插件使用说明 +## 1.2.3(2023-11-16) +增加插槽模式,只是高ui要求定制 +## 1.2.2(2023-11-15) +修复checkStrictly配置下,子关联父的选择状态 +## 1.2.1(2023-11-15) +增加半选提示功能配置showHalfCheckedTips +## 1.2.0(2023-11-14) +修复disabled配置状态下,父子级联,不需要改变disabled设置项的选择状态 +## 1.1.9(2023-11-13) +增强大数据量体验交互,增加筛选搜索模式 +## 1.1.8(2023-11-13) +增加清除clear和取消cancel事件 +## 1.1.7(2023-11-08) +更新next-tree插件功能清单说明 +## 1.1.6(2023-11-07) +update说明文档 +## 1.1.5(2023-11-07) +update +## 1.1.4(2023-11-07) +更新readme.md说明 +## 1.1.3(2023-11-07) +更新说明demo +## 1.1.2(2023-11-07) +增加子节点按需渲染演示demo +## 1.1.1(2023-11-07) +增加清空功能 +## 1.1.0(2023-11-07) +增加子孙节点按需渲染,扩展本插件支持大数据量渲染; +## 1.0.9(2023-10-26) +增加文件说明 +## 1.0.8(2023-09-14) +增加禁用节点属性配置disabledKey +## 1.0.7(2023-09-06) +增加checkStrictly,实现父子节点关联 +## 1.0.6(2023-09-06) +更新vue2使用过程视图不更新的技术说明 +## 1.0.5(2023-09-06) +修复说明文档 +## 1.0.4(2023-06-19) +修改demo +## 1.0.3(2023-06-19) +更新vue2的使用demo +## 1.0.2(2023-06-19) +修复说明文档 + +## 1.0.1(2023-05-10) +更新说明文件 +## 1.0.0(2023-05-09) +初始化项目 diff --git a/uni_modules/next-tree/components/next-tree/next-tree.vue b/uni_modules/next-tree/components/next-tree/next-tree.vue new file mode 100644 index 0000000..5e47118 --- /dev/null +++ b/uni_modules/next-tree/components/next-tree/next-tree.vue @@ -0,0 +1,1034 @@ + + + + + diff --git a/uni_modules/next-tree/components/next-tree/style.css b/uni_modules/next-tree/components/next-tree/style.css new file mode 100644 index 0000000..76c987f --- /dev/null +++ b/uni_modules/next-tree/components/next-tree/style.css @@ -0,0 +1,269 @@ +@font-face { + font-family: 'iconfont'; + src: url('//at.alicdn.com/t/c/font_4110624_qs48wckazsh.ttf?t=1712479573821') format('truetype'); +} +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.iconfont { + font-family: iconfont; + font-style: normal; +} +.iconfont-loading { + font-family: iconfont; + display: inline-block; + font-style: normal; + animation: spin 1s linear infinite; +} +.next-tree-mask { + position: fixed; + top: 0rpx; + right: 0rpx; + bottom: 0rpx; + left: 0rpx; + z-index: 997; + background-color: rgba(0, 0, 0, 0.6); + opacity: 0; + transition: all 0.3s ease; + visibility: hidden; +} +.next-tree-mask.show { + visibility: visible; + opacity: 1; +} +.next-tree-cnt { + position: fixed; + top: 0rpx; + right: 0rpx; + bottom: 0rpx; + left: 0rpx; + z-index: 997; + top: 360rpx; + transition: all 0.3s ease; + transform: translateY(100%); +} +.next-tree-cnt.next-tree-cnt-page { + transition: none; +} +.next-tree-cnt.show { + transform: translateY(0); +} +.next-tree-bar { + background-color: #fff; + height: 72rpx; + padding-left: 20rpx; + padding-right: 20rpx; + display: flex; + justify-content: space-between; + align-items: center; + box-sizing: border-box; + border-bottom-width: 1rpx !important; + border-bottom-style: solid; + border-bottom-color: #f5f5f5; + font-size: 32rpx; + color: #757575; + line-height: 1; +} +.next-tree-bar-btns { + display: inline-block; + display: flex; + flex-direction: row; +} +.btn-divid { + display: inline-block; + width: 1px; + margin: 0 10px; + background-color: #ccc; +} +.next-tree-bar-confirm { + color: #f9ae3d; +} +.next-tree-view { + position: absolute; + top: 0rpx; + right: 0rpx; + bottom: 0rpx; + left: 0rpx; + top: 72rpx; + background-color: #fff; + padding-top: 20rpx; + padding-right: 20rpx; + padding-bottom: 20rpx; + padding-left: 20rpx; +} +.next-tree-view-sc { + height: 100%; + overflow: hidden; +} +.next-tree-view-sc .empty { + text-align: center; + color: #757575; + padding: 30rpx; +} +.next-tree-item-block { + +} +.next-tree-item { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 26rpx; + color: #757575; + line-height: 1; + height: 0; + opacity: 0; + transition: 0.2s; + position: relative; + overflow: hidden; +} +.next-tree-item .icon-btn { + font-size: 30rpx; + margin-right: 20rpx; +} +.next-tree-item .left-line { + position: relative; + width: 1rpx; + height: 100%; + box-sizing: border-box; +} +.next-tree-item .left-line::before { + position: absolute; + content: ""; + width: 1rpx; + height: 100%; + background-color: rgba(204,204,204,0.9); + box-sizing: border-box; + + left: -18rpx; +} +.next-tree-item .parent-horizontal-line { + width: 1rpx; + height: 100%; + position: absolute; + top: 0; + left: 0rpx; + box-sizing: border-box; + background-color: rgba(204,204,204,0.9); +} +.next-tree-item .left-line .horizontal-line { + width: 20rpx; + height: 1rpx; + position: absolute; + top: 40rpx; + left: 0rpx; + background-color: rgba(204,204,204,0.9); + box-sizing: border-box; +} + +.next-tree-item.show { + height: 80rpx; + opacity: 1; +} +.next-tree-item.showchild:before { + transform: rotate(90deg); +} +.next-tree-item.border { + border-bottom: 1rpx solid rgba(204,204,204,0.2); +} +.next-tree-item.last:before { + opacity: 0; +} +.next-tree-item.disabled { + color: #ccc!important; +} + +.next-tree-icon { + width: 26rpx; + height: 26rpx; + margin-right: 8rpx; +} +.next-tree-label { + flex: 1; + display: flex; + align-items: center; + height: 100%; + line-height: 1.2; +} +.next-tree-label .label-input { + border: 1rpx solid #f0f0f0; + border-radius: 10rpx; + width: 100%; + padding: 12rpx 18rpx; + margin-right: 30rpx; +} +.next-tree-check { + width: 40px; + height: 40px; + display: flex; + justify-content: center; + align-items: center; +} +.next-tree-check-yes, +.next-tree-check-no { + width: 20px; + height: 20px; + border-top-left-radius: 20%; + border-top-right-radius: 20%; + border-bottom-right-radius: 20%; + border-bottom-left-radius: 20%; + border-top-width: 1rpx; + border-left-width: 1rpx; + border-bottom-width: 1rpx; + border-right-width: 1rpx; + border-style: solid; + border-color: #f9ae3d; + display: flex; + justify-content: center; + align-items: center; + box-sizing: border-box; +} +.next-tree-check-yes-b { + border-top-left-radius: 20%; + border-top-right-radius: 20%; + border-bottom-right-radius: 20%; + border-bottom-left-radius: 20%; + background-color: #f9ae3d; + color: #fff; +} +.next-tree-check-yes-b .icon-text { + font-size: 14px; + font-weight: normal; + font-family: uicon-iconfont; + display: flex; + flex-direction: row; + align-items: center; +} +.next-tree-check .radio { + border-top-left-radius: 50%; + border-top-right-radius: 50%; + border-bottom-right-radius: 50%; + border-bottom-left-radius: 50%; +} +.next-tree-check .radio .next-tree-check-yes-b { + border-top-left-radius: 50%; + border-top-right-radius: 50%; + border-bottom-right-radius: 50%; + border-bottom-left-radius: 50%; +} + +.next-tree-item.disabled .next-tree-check-no { + color: #ccc!important; +} +.next-tree-item.disabled .next-tree-check-yes-b { + background-color: #ccc!important; +} +.hover-c { + opacity: 0.6; +} + +.fixed-bottom-bar { + position: fixed; + bottom: 0rpx; + left: 0rpx; + right: 0rpx; + z-index: 998; +} + + diff --git a/uni_modules/next-tree/package.json b/uni_modules/next-tree/package.json new file mode 100644 index 0000000..6eb8ba2 --- /dev/null +++ b/uni_modules/next-tree/package.json @@ -0,0 +1,84 @@ +{ + "id": "next-tree", + "displayName": "next-tree(超强树选择器、树组件、树插件、无限级联树、单选树、多选树、自定义样式树、树形选择器)", + "version": "1.8.7", + "description": "next-tree 弹窗树形选择器,支持多选,支持大数据, 无限级联,单选,父子级级联,远程/ajax加载,子节点增量/异步渲染,自定义样式定制,具名插槽等;支持h5/小程序/APP,全端通用", + "keywords": [ + "树选择", + "tree", + "弹窗树选择器", + "多选树", + "单选树" +], +"engines": { + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "修改版本说明", + "permissions": "无" + }, + "npmurl": "", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["next-search-more"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "n", + "Edge": "y", + "Firefox": "y", + "Safari": "u" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "u", + "QQ": "y", + "钉钉": "y", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/next-tree/readme.md b/uni_modules/next-tree/readme.md new file mode 100644 index 0000000..bf496f9 --- /dev/null +++ b/uni_modules/next-tree/readme.md @@ -0,0 +1,843 @@ + +## next-tree --下拉树 + +> 遇到问题或有建议可以加入QQ群(455948571)反馈 +> 如果觉得组件不错,给五星鼓励鼓励咯! + +## 亮点功能说明(打造你不得不用的好插件) + +### 本插件自1.5.0版本后支持一下功能 + + > 1.大数据量渲染(本插件智能判断,如果子孙集数据量大于50时,会响应等待渲染视图;) + > 2.子节点按需渲染(自动启用,无需配置) + > 3.父子级联选择设置 + > 4.单选多选设置 + > 5.父节点是否可选设置 + > 6.回显默认选中值 + > 7.不可选项disabled设置 + > 8.增强大数据量体验交互,增加筛选搜索模式 + > 9.增强样式定制,提供自定义插槽,实现高要求样式定制 + > 10.增加辅助线模式,外观更加精美 + > 11.支持动态配置title + > 12.支持搜索模式searchModel=depHighlight模式,从属高亮显示模式 + > 13.支持异步加载子节点,ajax加载子节点 + > 14.增加可配置主题,自由定制插件主题颜色 + > 15.支持动态校验,可以进行提示控制校验 + > 16.支持页面模式/弹层模式,可以进行单页面展示或者弹层展示 + > 17.支持半选提示状态显示 + > 18.支持展开项expandedKeys配置 + > 19.全面支持vue2/vue3 + > 20.增加无子节点的父节点配置支持(当item[childrenKey]为null时,代表无子节点的父节点) + > 21.终极支持超数据量使用,增加展开模式配置单链路配置使用expandedMode=singe,使得ui组件使用进一步不在限制与数据量 + > 22.功能模式再次增强,支持单选tree,多选tree,编辑tree,展示tree; + +## 注意 + +### 作者不介意你对组件源码进行改造使用,为了开源更加高效,谢谢你的配合;为了节省不必要的沟通浪费,以下情况请不要再反馈给作者,请自行解决; +### 在这感各位的理解,我支持开源,但是作者时间有限;谢谢各位的配合;在这里期望我写的小小插件能为你提供便捷; + + > 1.如果你对源码进行了修改使用,请不需要对作者做任何的反馈,作者确实没有空陪你做技术分析解答; + > 2.如果你引入插件,连插件是否有正常被uniapp框架识别解析都不清楚,请你换个插件使用; + > 3.如果你引入插件,针对自己项目进行功能改造的,请自行仔细阅读源码并了解其原理,自行改造;这里作者不愿意浪费过多时间进行技术解答; + > 4.如果你不想进行全局加载next-tree,需要按需加载;next-tree中有相关依赖的组件,需要你自行在组件内部单独引入;依赖组件可以在package.json中找到; + > 5.理论上作者不再解决由于本地开发环境问题所导致的插件使用问题,请自行到uniapp官网学习解决; + +## 使用 +### 超集功能即将不对外开源; + +>[从uniapp插件市场导入](https://ext.dcloud.net.cn/plugin?name=next-tree) + +## 关注作者的动态 +[点击进入主页,关注作者](https://ask.dcloud.net.cn/people/ponder_7464) + +## 关注作者其他开源 + +npm开源包:[npm](https://www.npmjs.com/~lixueshiaa); +github开源项目:[github](https://github.com/lixueshiaa); + + +```html + +``` + +### vue3 + ts 使用 + +```ts + + + +``` + +### vue2 使用 +```html + +``` + +```js + + + +``` + +### 个性化自定义样式渲染 + +如果你的需求对样式需求比较高,请使用插槽模式渲染,本组件提供label插槽供你自定义定制; + +```js + +``` + +### 预览 +### +*** + +| 功能预览 | 父子级关联演示 | 全面支持大数据量,子孙节点ui按需渲染(按需渲染数据) | +| :------------------------------------------------------------------: | :------------------------------------------------------------------: | :------------------------------------------------------------------: | +| ![](https://lixueshiaa.github.io/webtest/www/static/next-tree.gif) | ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-b.gif) | ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-d.gif) | + + + +| 增强控件交互能力,增加筛选search模式,全面支持大数据量交互 | 超强的样式定制能力,满足你高精美组件的需求 | 打开精美的辅助线模式,让你的控件更加友好 | +| :------------------------------------------------------------------: | :------------------------------------------------------------------: | :------------------------------------------------------------------: | +| ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-e.gif) | ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-f.gif) | ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-u.gif) | + + +| 增加搜索模式searchModel=depHighlight模式,从属高亮显示模式 | 支持异步加载子节点,子树集,ajax远程加载数据等 | 支持不同主题的切换,ui定制更简单 | +| :------------------------------------------------------------------: | :------------------------------------------------------------------: | :------------------------------------------------------------------: | +| ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-p.gif) | ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-k.gif) | ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-n.gif) | + +| 增加验证函数和topBar插槽使得更加容易和组件进行交互 | 增加页面模式,支持整页ui展示模式 | 增加展开模式expandedMode配置,支持单链路展开,理论上支持几万数据量 | +| :------------------------------------------------------------------: | :------------------------------------------------------------------: | :------------------------------------------------------------------: | +| ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-cc.gif)| ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-uu.gif)| ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-aab.gif) | + + + +### 超集功能预览(增值功能) +### +| 实现tree的功能模式扩展,让你的tree组件实现可编辑态 | +| :--------------------------------------------------------------------: | +| ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-eeee.gif)| + +## 参数 +可选参数属性列表 + +|参数名 |说明 |类型 |是否必填 |默认值 |可选值 | +|---- |---- |---- |---- |---- |----------------------- | +|uiMode |ui表现方式;popup<弹窗>, page<页面>;默认是 popup |String |是 |popup |page | +|funcMode |功能模式配置;display<展示模式>, edit<编辑模式>,checkbox<多选模式>, radio<单选模式>;默认是 radio |String |是 |radio |dispaly,edit,checkbox | +|treeData |树源数据列表 |Array |是 |[] |- | +|valueKey |绑定value的键属性(项的唯一key标识) |String |否 |id |- | +|labelKey |用于显示的字段 |String |否 |label |- | +|disabledKey |禁用节点绑定属性 |String |否 |disabled |- | +|childrenKey |子节点绑定属性 (注意:当item[childrenKey]的值设为null时,代表是无下级数据的父节点,即非叶子节点) |String |否 |children |- | +|title | 弹出标题(如果是函数时会返回所选项的值作为回调参数如;title: (checked):String => {}) |String, Function |否 |'' |- | +|selectParent |作用于funcMode=display模式下;是否可以选父级 |Boolean |否 |false |true | +|foldAll| 折叠时关闭所有已经打开的子集,再次打开时需要一级一级打开 |Boolean |否 |false |true | +|themeColor |主题颜色 |String |否 |#f9ae3d |- | +|cancelColor |取消按钮颜色 |String |否 |#757575 |- | +|titleColor |标题颜色 |String |否 |#757575 |- | +|border |是否有分割线 |Boolean |否 |false |true | +|checkStrictly|作用于funcMode=checkbox模式下; 状态下节点选择完全受控(父子节点选中状态不再关联) |Boolean |否 |false |true | +|checkStrictlyModel|作用于funcMode=checkbox模式下;父子节点关联模式:strong:强关联(不再受限节点的disabled控制),weak:弱关联(节点关联受disabled控制) |String |是 |weak |strong | +|showHalfCheckedTips|作用于funcMode=checkbox模式下; checkStrictly为false的状态下生效;父子节点选中状态不再关联,是否展示半选提示; |Boolean |否 |false |true | +|ifSearch| 筛选search模式 |Boolean |否 |true |false | +|searchModel| 搜索模式配置 depHighlight: 从属高亮(显示层级并高亮显示);common: 一般 |String |否 |common |depHighlight | +|showAuxiliaryLine| 是否打开辅助线 |Boolean |否 |false |true | +|loadData| 异步加载函数 (node):Promise([childData]) => {} // demo有说明 |Function |否 |- |- | +|height| 只在uiMode=popup时生效;弹层容器的高度,默认是500 |Number |否 |500 |- | +|changeVerify|作用于funcMode=display模式下; 验证函数 (current as any, chooseList as any []):String => {} // 验证函数会把当前控件的选择值作为参数返给函数体,demo有说明 |Function |否 |- |- | +|expandedKeys| (Controlled) Specifies the keys of the expanded treeNodes 展开配置项,格式为[valueKey] |Array |否 |[] |- | +|expandedMode| 展开模式配置: common: 一般模式;singe: 单一模式; |String |否 |common |singe | + + +# Event 事件 +|事件名 |说明 |类型 |回调参数 | +|---- |---- |---- |---- | +|confirm|菜单收起时返回的筛选结果 |emit |array | +|clear|点击清除按钮时触发 |emit |- | +|cancel|关闭弹层和点击取消时触发 |emit |- | +|change|选项改变时触发 |emit |array | + +## Slot 插槽 + +|名称 |说明 |参数 | +|---- |---- |---- | +|label |label插槽 |data(当前项对于treeData里面的数据) | +|topBar |topBar插槽 |----滚动区域顶部topBar插槽 | +|bottomBar |bottomBar插槽 |----滚动区域底部bottomBar插槽 | +|fixedBottomBar |fixedBottomBar插槽 |----固定在页面的底部,使用fixed进行定位 | +|empty |empty插槽 |----数据为空的插槽 | + diff --git a/uni_modules/sv-excel-json-each/changelog.md b/uni_modules/sv-excel-json-each/changelog.md new file mode 100644 index 0000000..e20a334 --- /dev/null +++ b/uni_modules/sv-excel-json-each/changelog.md @@ -0,0 +1,12 @@ +## 1.0.4(2024-05-11) +1. 更新文档 +## 1.0.3(2024-04-03) +1. 修复微信小程序报错 +## 1.0.2(2024-02-18) +1. 更新示例工程 +2. 更新文档 +3. 原路径jssdk更名为js_sdk +## 1.0.1(2024-01-29) +1. 修改云函数名称 +## 1.0.0(2024-01-19) +1. 仅供本人自用 diff --git a/uni_modules/sv-excel-json-each/js_sdk/parseExcel.js b/uni_modules/sv-excel-json-each/js_sdk/parseExcel.js new file mode 100644 index 0000000..8e00b45 --- /dev/null +++ b/uni_modules/sv-excel-json-each/js_sdk/parseExcel.js @@ -0,0 +1,125 @@ +import pickFile from './plusFilePicker.js' + +async function urlToBase64(url) { + // #ifndef MP-WEIXIN + // 注意url必须为http或者https协议路径,本地file路径不行 + let res = await uni.request({ + url: url, + method: 'GET', + responseType: 'arraybuffer' + }); + // 容错处理 + if (Array.isArray(res)) { + res = res.find(item => item && item.data) + } + let base64 = uni.arrayBufferToBase64(res.data); //把arraybuffer转成base64 + // #endif + + // #ifdef MP-WEIXIN + const fs = wx.getFileSystemManager() + let base64 = fs.readFileSync(url, 'base64') + // #endif + return base64 +} + +/** + * 文件选择 表格文件导入 返回表格数据 + * @param callback 为了兼容安卓文件选择,此处使用callback回调来接受解析后的json参数,其他平台勿使用该回调 + */ +export async function importToJson(sheetList = [], callback) { + // #ifdef H5 + let fileRes = await uni.chooseFile({ + count: 1, + extension: ['.xls', '.xlsx'] + }); + // fileRes可能是单对象,也可能是数组且数组中存在某项为null的情况,需要容错处理以取出真实文件数据对象 + if (Array.isArray(fileRes)) { + fileRes = fileRes.find(item => item && item.tempFilePaths.length > 0) + } + const filePath = fileRes.tempFilePaths[0] + return await fileToJson(filePath, sheetList) + // #endif + + // #ifdef MP-WEIXIN + const fileRes = await wx.chooseMessageFile({ + count: 1, + type: 'file', + extension: ['.xls', '.xlsx'] + }) + const filePath = fileRes.tempFiles[0].path + return await fileToJson(filePath, sheetList) + // #endif + + // #ifdef APP + switch (plus.os.name) { + case "Android": + // Android平台: plus.android.* + // 安卓需要先使用Native.js进行文件选择,上传文件后再进行解析 + pickFile.PickFile(async (src) => { + let srcPath = 'file://' + src; + console.log('==== srcPath :', srcPath); + const upRes = await uniCloud.uploadFile({ + filePath: srcPath, + // 同名会导致报错 policy_does_not_allow_file_overwrite + // cloudPath可由 想要存储的文件夹/文件名 拼接,若不拼文件夹名则默认存储在cloudstorage文件夹中 + cloudPath: `cloudstorage/${Date.now()}`, + cloudPathAsRealPath: true + }) + console.log('==== upRes :', upRes); + const filePath = upRes.fileID + callback(await fileToJson(filePath, sheetList)) + }); + break; + case "iOS": + // iOS平台: plus.ios.* + break; + default: + // 其它平台 + break; + } + // #endif +} +/** + * 表格文件导入 返回表格数据 + */ +async function fileToJson(path, sheetList) { + const base = await urlToBase64(path); + const eachObj = uniCloud.importObject('sv-excel-json-each') + const dataRes = await eachObj.getExcelToJson({ + data: base, + sheetList + }) + return dataRes +} + +/** + * 数据导出 返回表格文件下载 + * @param {Object} options + * 注:file文件模式可自动下载并返回文件下载路径,base64模式不提供自动下载并直接返回base64字串 + */ +export async function exportToExcel(options) { + const eachObj = uniCloud.importObject('sv-excel-json-each') + const dataRes = await eachObj.getJsonToExcel(options.params) + if (dataRes.code == 0) { + if (options.autoDownload && options.params.type == 'file') { + /** + * 下载文件资源到本地,客户端直接发起一个 HTTP GET 请求,返回文件的本地临时路径 + * 注意:在HbuilderX内置浏览器中无法正常运行 + * @tutorial https://uniapp.dcloud.net.cn/api/request/network-file.html#downloadfile + */ + uni.downloadFile({ + url: dataRes.data, + success: (res) => { + uni.openDocument({ + filePath: res.tempFilePath, + showMenu: true, + }); + } + }) + } + } else { + console.error('==== dataRes :', dataRes); + } + + return dataRes.data +} \ No newline at end of file diff --git a/uni_modules/sv-excel-json-each/js_sdk/plusFilePicker.js b/uni_modules/sv-excel-json-each/js_sdk/plusFilePicker.js new file mode 100644 index 0000000..460d88b --- /dev/null +++ b/uni_modules/sv-excel-json-each/js_sdk/plusFilePicker.js @@ -0,0 +1,107 @@ +let pickFile = { + //调用原生文件系统管理器并选取文件获取文件地址 + //acceptType为你要查的文件类型"image/*","audio/*","video/*;image/*" // intent.setType("image/*");//intent.setType("audio/*"); //选择音频//intent.setType("video/*;image/*"); //选择视频 (mp4 3gp 是android支持的视频格式) + PickFile: function(callback, acceptType) { + let CODE_REQUEST = 1000; + let main = plus.android.runtimeMainActivity(); + if (plus.os.name == 'Android') { + let Intent = plus.android.importClass('android.content.Intent'); + let intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + if (acceptType) { + intent.setType(acceptType); + } else { + intent.setType("*/*"); + } + let _this = pickFile; + main.onActivityResult = function(requestCode, resultCode, data) { + if (requestCode == CODE_REQUEST) { + let uri = data.getData(); + plus.android.importClass(uri); + let Build = plus.android.importClass('android.os.Build'); + let isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; + let contentUri + let DocumentsContract = plus.android.importClass('android.provider.DocumentsContract'); + // DocumentProvider + if (isKitKat && DocumentsContract.isDocumentUri(main, uri)) { + // console.log("版本大于 4.4 "); + // ExternalStorageProvider + if ("com.android.externalstorage.documents" == uri.getAuthority()) { + let docId = DocumentsContract.getDocumentId(uri); + let split = docId.split(":"); + let type = split[0]; + + if ("primary" == type) { + let Environment = plus.android.importClass('android.os.Environment'); + callback(Environment.getExternalStorageDirectory() + "/" + split[1]); + } else { + let System = plus.android.importClass('java.lang.System'); + let sdPath = System.getenv("SECONDARY_STORAGE"); + if (sdPath) { + callback(sdPath + "/" + split[1]); + } + } + } + // DownloadsProvider + else if ("com.android.providers.downloads.documents" == uri.getAuthority()) { + let id = DocumentsContract.getDocumentId(uri); + let ContentUris = plus.android.importClass('android.content.ContentUris'); + contentUri = ContentUris.withAppendedId( + // Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); + Uri.parse("content://downloads/public_downloads"), id); + callback(_this.getDataColumn(main, contentUri, null, null)); + } + // MediaProvider + else if ("com.android.providers.media.documents" == uri.getAuthority()) { + let docId = DocumentsContract.getDocumentId(uri); + let split = docId.split(":"); + let type = split[0]; + + let MediaStore = plus.android.importClass('android.provider.MediaStore'); + if ("image" == type) { + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + } else if ("video" == type) { + contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + } else if ("audio" == type) { + contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; + } else { + contentUri = MediaStore.Files.getContentUri("external") + } + + let selection = "_id=?"; + let selectionArgs = new Array(); + selectionArgs[0] = split[1]; + + callback(_this.getDataColumn(main, contentUri, selection, selectionArgs)); + } + } + // MediaStore (and general) + else if ("content" == uri.getScheme()) { + callback(_this.getDataColumn(main, uri, null, null)); + } + // File + else if ("file" == uri.getScheme()) { + callback(uri.getPath()); + } + } + } + main.startActivityForResult(intent, CODE_REQUEST); + } + }, + + getDataColumn: function(main, uri, selection, selectionArgs) { + plus.android.importClass(main.getContentResolver()); + let cursor = main.getContentResolver().query(uri, ['_data'], selection, selectionArgs, + null); + plus.android.importClass(cursor); + if (cursor != null && cursor.moveToFirst()) { + let column_index = cursor.getColumnIndexOrThrow('_data'); + let result = cursor.getString(column_index) + cursor.close(); + return result; + } + return null; + } +} + +export default pickFile \ No newline at end of file diff --git a/uni_modules/sv-excel-json-each/package.json b/uni_modules/sv-excel-json-each/package.json new file mode 100644 index 0000000..289071e --- /dev/null +++ b/uni_modules/sv-excel-json-each/package.json @@ -0,0 +1,83 @@ +{ + "id": "sv-excel-json-each", + "displayName": "EXCEL与JSON互转", + "version": "1.0.4", + "description": "EXCEL与JSON互转,根据原墨联大佬的ml-excel-to-json插件修改,仅供本人自用", + "keywords": [ + "EXCEL", + "JSON" +], + "repository": "", +"engines": { + }, + "dcloudext": { + "type": "unicloud-template-function", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-vue": "u", + "app-nvue": "u", + "app-uvue": "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", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/sv-excel-json-each/readme.md b/uni_modules/sv-excel-json-each/readme.md new file mode 100644 index 0000000..62e869f --- /dev/null +++ b/uni_modules/sv-excel-json-each/readme.md @@ -0,0 +1,151 @@ +# EXCEL&JSON 互转 [`sv-excel-json-each`](https://ext.dcloud.net.cn/plugin?id=16401) + +EXCEL&JSON 互相转换,源于 [EXCEL 转 JSON 函数](https://ext.dcloud.net.cn/plugin?id=6626) 插件,使用文档请移步至原插件。 + +## 前言 + +本插件开发之初仅考虑自用,请尊重并支持原 [EXCEL 转 JSON 函数](https://ext.dcloud.net.cn/plugin?id=6626) 插件。 + +## 改动内容 + +> 强烈建议优先了解原 [EXCEL 转 JSON 函数](https://ext.dcloud.net.cn/plugin?id=6626) 插件。 + +1. 将原插件中的 getExcelToJson 与 getJsonToExcel 两个云函数改为 sv-excel-json-each 云对象,并放至插件内部,解决每次导入插件都需要从示例工程中复制云对象移至项目中的问题,现一键导入即可。 + +2. 修改 jssdk/parseExcel.js 文件中 downloadXLSX 方法代码,修复原插件可能会报错 Failed to execute 'atob' on 'Window'问题。 + +3. 原插件中 parseExcel.js 文件中 downloadXLSX 方法已被我移除,已用其他可兼容 H5、安卓 App、微信小程序三端的方式代替。 + +4. 较大规模改动 parseExcel.js 文件,重要改动如下: + + - 由于 uni.chooseFile 只支持 H5 端,现添加微信小程序的 wx.chooseMessageFile 和 App 端 Native.js(目前只支持安卓)调用文件选择面板,因此现已兼容 H5、安卓 App、微信小程序三端。 + + - 修改当 type 为 base64 模式时,不提供自动下载功能,仅当 type 为 file 模式时开启 autoDownload 才提供自动下载功能 + +## 安装 + +1. [插件市场](https://ext.dcloud.net.cn/plugin?id=16401) 中点击 `下载插件并导入HBuildeX`。 + +## 插件兼容性 + +> `✔️ 实测可行` `❌ 未兼容` `➖ 未实测` + +| 阿里云 | 腾讯云 | 支付宝云 | Vue2 | Vue3 | H5 | App | 微信小程序 | +| :----: | :----: | :------: | :--: | :--: | :-: | :-: | :--------: | +| ✔️ | ➖ | ❌ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | + +纯 js 插件 + +## 使用示例 + +```javascript +import { importToJson, exportToExcel } from "@/uni_modules/sv-excel-json-each/js_sdk/parseExcel.js"; +import { testList, testAddList } from "@/api/test"; // 测试用例列表查询与批量导入接口 + +const testMapping = { + test_id: "测试用例ID", + test_name: "测试用例名称", +}; + +/** + * 测试用例导出 + */ +async function testExport(params) { + // 调用接口获取列表数据 + const dataRes = await testList(params); + const handleData = dataRes.data?.map((item) => { + return { + test_id: { + v: item.test_id, + t: "s", + s: { + alignment: { + horizontal: "left", // 数字列会默认右对齐 + }, + }, + }, + test_name: { + v: item.test_name, + t: "s", + s: { + alignment: { + horizontal: "left", + }, + font: { + color: { + rgb: "FF0000", // 文字标红 + }, + }, + }, + }, + }; + }); + exportToExcel({ + params: { + data: handleData, + title: "logs", + mapping: testMapping, + type: "file", + // merges: [{ start: [0, 1], end: [0, 4] }] + }, + autoDownload: true, + }).then((res) => { + // console.log('onExport ===>', res) + }); +} + +/** + * 测试用例导入 + */ +async function testImport(cover, callback) { + let sheetList = [{ index: 0 }, { index: 1 }]; + const toJsonRes = await importToJson(sheetList); + const dataRes = toJsonRes.data.data || []; + // 转换为接口原数据格式 + const handleData = dataRes.map((item) => { + return { + test_id: item["测试用例ID"] + "", // 导入时转换为字符串类型 + test_name: item["测试用例名称"] + "", + }; + }); + console.table(toJsonRes.data); + console.table(handleData); + // 调用批量导入接口 + const importRes = await testAddList({ + data: handleData, + cover, + }); + if (callback) callback(importRes); +} + +/** + * 测试用例模板下载 + */ +function testTemplate() { + exportToExcel({ + params: { + data: [ + { + test_id: "测试id", + test_name: "测试名称", + }, + ], // 若空数据数组,需要有个空对象 + title: "test", + mapping: testMapping, + type: "file", + }, + autoDownload: true, + }).then((res) => { + // console.log('onExport ===>', res) + }); +} +``` + +## 注意事项 + +1. 对单元格操作时,写法格式按照上述示例中严格把控。 +2. 更多请参照原 [EXCEL 转 JSON 函数](https://ext.dcloud.net.cn/plugin?id=6626) 插件文档。 + +## 写在最后 + +本插件开发之初仅考虑自用,请尊重并支持原 [EXCEL 转 JSON 函数](https://ext.dcloud.net.cn/plugin?id=6626) 插件。 diff --git a/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/index.js b/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/index.js new file mode 100644 index 0000000..f052d1a --- /dev/null +++ b/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/index.js @@ -0,0 +1,143 @@ +const xlsx = require('./lib/xlsx.style.js'); +const { + convertDSTo26BS, + convert26BSToDS, + readXlsx, + formatExcelToJsonOptions +} = require('./util/index.js') +module.exports = { + excelToarray: async function(base64) { + return readXlsx(base64); + }, + excelTojson: async function() { + const args = arguments + let base64 = args[0],options = formatExcelToJsonOptions(args[1]); + const sheetList = readXlsx(base64, options); + let data = [], + allKeys = []; + options.forEach(sheetItem => { + let keys = []; + try { + if (sheetItem.keys && sheetItem.keys.length > 0) { + keys = sheetItem.keys; + allKeys = allKeys.concat(keys); + } else { + keys = sheetList[sheetItem.index].data.find((item, rowIndex) => { + return rowIndex === sheetItem.keysIndex; + }); + allKeys = keys; + } + sheetList[sheetItem.index].data.forEach((rowItem, rowIndex) => { + if (rowIndex < sheetItem.startIndex) return false; + if (rowIndex > sheetItem.endIndex && sheetItem.endIndex !== -1) + throw new Error('end forEach'); + let obj = {}; + rowItem.forEach((colItem, colIndex) => { + if (keys[colIndex]) { + obj[keys[colIndex]] = colItem; + } + }) + data.push(obj) + }) + } catch (e) { + //throw new Error(e); + } + }) + let set = new Set(allKeys); + allKeys = Array.from(set); + return { + keys: allKeys, + data, + sheetListName: sheetList.map(item => { + return item.name + }) + } + }, + jsonToexcel: async function() { + let data = [], + options = { + title: "未命名", + mapping: {}, + type: "base64", + merges: [], + appendHeaderData: [] + } + const args = arguments + if (args.length === 5) { + data = args[0] + options = { + ...options, + ...args[4] + } + options.title = args[1] + options.mapping = args[2] + options.type = args[3] + } else if (args.length === 2) { + data = args[0] + options = { + ...options, + ...args[1] + } + } else if (args.length === 1) { + data = args[0].data + options = { + ...options, + ...args[0] + } + } + let { + title, + mapping, + type, + merges, + appendHeaderData + } = options + if (data.length === 0) return { + code: 'no data' + }; + let header = []; + for (let key in data[0]) { + if (!mapping[key]) { + mapping[key] = key; + } + header.push(key); + } + + let newData = [mapping, ...data]; + if (appendHeaderData && appendHeaderData.length > 0) { + newData.unshift(...appendHeaderData) + } + const worksheet = xlsx.utils.json_to_sheet(newData, { + header: header, + skipHeader: true + }); + var workbook = xlsx.utils.book_new(); + worksheet['!merges'] = options.merges.map(item => { + return { + s: { + r: item.start[0], + c: item.start[1] + }, + e: { + r: item.end[0], + c: item.end[1] + } + } + }) + xlsx.utils.book_append_sheet(workbook, worksheet, "sheet1"); + let xlsxData = xlsx.write(workbook, { + type: "base64" + }); + if (type === 'file') { + xlsxData = await uniCloud.uploadFile({ + cloudPath: title + '.xlsx', + fileContent: new Buffer(xlsxData, 'base64') + }); + xlsxData = xlsxData.fileID; + } else if (type === 'base64') { + xlsxData = "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64," + + xlsxData; + } + return xlsxData + } +} \ No newline at end of file diff --git a/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/lib/cpexcel.js b/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/lib/cpexcel.js new file mode 100644 index 0000000..4f195eb --- /dev/null +++ b/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/lib/cpexcel.js @@ -0,0 +1,1506 @@ +/*! cpexcel.js (C) 2013-present SheetJS -- http://sheetjs.com */ +/*jshint -W100 */ +var cptable = {version:"1.15.0"}; +cptable[437] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[620] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÇüéâäàąçêëèïîćÄĄĘęłôöĆûùŚÖܢ٥śƒŹŻóÓńŃźż¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[737] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρσςτυφχψ░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀ωάέήϊίόύϋώΆΈΉΊΌΎΏ±≥≤ΪΫ÷≈°∙·√ⁿ²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[850] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø×ƒáíóúñѪº¿®¬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ðÐÊËÈıÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµþÞÚÛÙýݯ´­±‗¾¶§÷¸°¨·¹³²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[852] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÇüéâäůćçłëŐőîŹÄĆÉĹĺôöĽľŚśÖÜŤťŁ×čáíóúĄąŽžĘ꬟Ⱥ«»░▒▓│┤ÁÂĚŞ╣║╗╝Żż┐└┴┬├─┼Ăă╚╔╩╦╠═╬¤đĐĎËďŇÍÎě┘┌█▄ŢŮ▀ÓßÔŃńňŠšŔÚŕŰýÝţ´­˝˛ˇ˘§÷¸°¨˙űŘř■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[857] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÇüéâäàåçêëèïîıÄÅÉæÆôöòûùİÖÜø£ØŞşáíóúñÑĞ𿮬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ºªÊËÈ�ÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµ�×ÚÛÙìÿ¯´­±�¾¶§÷¸°¨·¹³²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[861] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÇüéâäàåçêëèÐðÞÄÅÉæÆôöþûÝýÖÜø£Ø₧ƒáíóúÁÍÓÚ¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[865] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø₧ƒáíóúñѪº¿⌐¬½¼¡«¤░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[866] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёЄєЇїЎў°∙·√№¤■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[874] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€����…�����������‘’“”•–—�������� กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[895] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ČüéďäĎŤčěĚĹÍľǪÄÁÉžŽôöÓůÚýÖÜŠĽÝŘťáíóúňŇŮÔšřŕŔ¼§«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[932] = (function(){ var d = [], e = {}, D = [], j; +D[0] = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~���������������������������������。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚��������������������������������".split(""); +for(j = 0; j != D[0].length; ++j) if(D[0][j].charCodeAt(0) !== 0xFFFD) { e[D[0][j]] = 0 + j; d[0 + j] = D[0][j];} +D[129] = "���������������������������������������������������������������� 、。,.・:;?!゛゜´`¨^ ̄_ヽヾゝゞ〃仝々〆〇ー―‐/\~∥|…‥‘’“”()〔〕[]{}〈〉《》「」『』【】+-±×�÷=≠<>≦≧∞∴♂♀°′″℃¥$¢£%#&*@§☆★○●◎◇◆□■△▲▽▼※〒→←↑↓〓�����������∈∋⊆⊇⊂⊃∪∩��������∧∨¬⇒⇔∀∃�����������∠⊥⌒∂∇≡≒≪≫√∽∝∵∫∬�������ʼn♯♭♪†‡¶����◯���".split(""); +for(j = 0; j != D[129].length; ++j) if(D[129][j].charCodeAt(0) !== 0xFFFD) { e[D[129][j]] = 33024 + j; d[33024 + j] = D[129][j];} +D[130] = "�������������������������������������������������������������������������������0123456789�������ABCDEFGHIJKLMNOPQRSTUVWXYZ�������abcdefghijklmnopqrstuvwxyz����ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをん��������������".split(""); +for(j = 0; j != D[130].length; ++j) if(D[130][j].charCodeAt(0) !== 0xFFFD) { e[D[130][j]] = 33280 + j; d[33280 + j] = D[130][j];} +D[131] = "����������������������������������������������������������������ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミ�ムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶ��������ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ��������αβγδεζηθικλμνξοπρστυφχψω�����������������������������������������".split(""); +for(j = 0; j != D[131].length; ++j) if(D[131][j].charCodeAt(0) !== 0xFFFD) { e[D[131][j]] = 33536 + j; d[33536 + j] = D[131][j];} +D[132] = "����������������������������������������������������������������АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ���������������абвгдеёжзийклмн�опрстуфхцчшщъыьэюя�������������─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂�����������������������������������������������������������������".split(""); +for(j = 0; j != D[132].length; ++j) if(D[132][j].charCodeAt(0) !== 0xFFFD) { e[D[132][j]] = 33792 + j; d[33792 + j] = D[132][j];} +D[135] = "����������������������������������������������������������������①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ�㍉㌔㌢㍍㌘㌧㌃㌶㍑㍗㌍㌦㌣㌫㍊㌻㎜㎝㎞㎎㎏㏄㎡��������㍻�〝〟№㏍℡㊤㊥㊦㊧㊨㈱㈲㈹㍾㍽㍼≒≡∫∮∑√⊥∠∟⊿∵∩∪���������������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[135].length; ++j) if(D[135][j].charCodeAt(0) !== 0xFFFD) { e[D[135][j]] = 34560 + j; d[34560 + j] = D[135][j];} +D[136] = "���������������������������������������������������������������������������������������������������������������������������������������������������������������亜唖娃阿哀愛挨姶逢葵茜穐悪握渥旭葦芦鯵梓圧斡扱宛姐虻飴絢綾鮎或粟袷安庵按暗案闇鞍杏以伊位依偉囲夷委威尉惟意慰易椅為畏異移維緯胃萎衣謂違遺医井亥域育郁磯一壱溢逸稲茨芋鰯允印咽員因姻引飲淫胤蔭���".split(""); +for(j = 0; j != D[136].length; ++j) if(D[136][j].charCodeAt(0) !== 0xFFFD) { e[D[136][j]] = 34816 + j; d[34816 + j] = D[136][j];} +D[137] = "����������������������������������������������������������������院陰隠韻吋右宇烏羽迂雨卯鵜窺丑碓臼渦嘘唄欝蔚鰻姥厩浦瓜閏噂云運雲荏餌叡営嬰影映曳栄永泳洩瑛盈穎頴英衛詠鋭液疫益駅悦謁越閲榎厭円�園堰奄宴延怨掩援沿演炎焔煙燕猿縁艶苑薗遠鉛鴛塩於汚甥凹央奥往応押旺横欧殴王翁襖鴬鴎黄岡沖荻億屋憶臆桶牡乙俺卸恩温穏音下化仮何伽価佳加可嘉夏嫁家寡科暇果架歌河火珂禍禾稼箇花苛茄荷華菓蝦課嘩貨迦過霞蚊俄峨我牙画臥芽蛾賀雅餓駕介会解回塊壊廻快怪悔恢懐戒拐改���".split(""); +for(j = 0; j != D[137].length; ++j) if(D[137][j].charCodeAt(0) !== 0xFFFD) { e[D[137][j]] = 35072 + j; d[35072 + j] = D[137][j];} +D[138] = "����������������������������������������������������������������魁晦械海灰界皆絵芥蟹開階貝凱劾外咳害崖慨概涯碍蓋街該鎧骸浬馨蛙垣柿蛎鈎劃嚇各廓拡撹格核殻獲確穫覚角赫較郭閣隔革学岳楽額顎掛笠樫�橿梶鰍潟割喝恰括活渇滑葛褐轄且鰹叶椛樺鞄株兜竃蒲釜鎌噛鴨栢茅萱粥刈苅瓦乾侃冠寒刊勘勧巻喚堪姦完官寛干幹患感慣憾換敢柑桓棺款歓汗漢澗潅環甘監看竿管簡緩缶翰肝艦莞観諌貫還鑑間閑関陥韓館舘丸含岸巌玩癌眼岩翫贋雁頑顔願企伎危喜器基奇嬉寄岐希幾忌揮机旗既期棋棄���".split(""); +for(j = 0; j != D[138].length; ++j) if(D[138][j].charCodeAt(0) !== 0xFFFD) { e[D[138][j]] = 35328 + j; d[35328 + j] = D[138][j];} +D[139] = "����������������������������������������������������������������機帰毅気汽畿祈季稀紀徽規記貴起軌輝飢騎鬼亀偽儀妓宜戯技擬欺犠疑祇義蟻誼議掬菊鞠吉吃喫桔橘詰砧杵黍却客脚虐逆丘久仇休及吸宮弓急救�朽求汲泣灸球究窮笈級糾給旧牛去居巨拒拠挙渠虚許距鋸漁禦魚亨享京供侠僑兇競共凶協匡卿叫喬境峡強彊怯恐恭挟教橋況狂狭矯胸脅興蕎郷鏡響饗驚仰凝尭暁業局曲極玉桐粁僅勤均巾錦斤欣欽琴禁禽筋緊芹菌衿襟謹近金吟銀九倶句区狗玖矩苦躯駆駈駒具愚虞喰空偶寓遇隅串櫛釧屑屈���".split(""); +for(j = 0; j != D[139].length; ++j) if(D[139][j].charCodeAt(0) !== 0xFFFD) { e[D[139][j]] = 35584 + j; d[35584 + j] = D[139][j];} +D[140] = "����������������������������������������������������������������掘窟沓靴轡窪熊隈粂栗繰桑鍬勲君薫訓群軍郡卦袈祁係傾刑兄啓圭珪型契形径恵慶慧憩掲携敬景桂渓畦稽系経継繋罫茎荊蛍計詣警軽頚鶏芸迎鯨�劇戟撃激隙桁傑欠決潔穴結血訣月件倹倦健兼券剣喧圏堅嫌建憲懸拳捲検権牽犬献研硯絹県肩見謙賢軒遣鍵険顕験鹸元原厳幻弦減源玄現絃舷言諺限乎個古呼固姑孤己庫弧戸故枯湖狐糊袴股胡菰虎誇跨鈷雇顧鼓五互伍午呉吾娯後御悟梧檎瑚碁語誤護醐乞鯉交佼侯候倖光公功効勾厚口向���".split(""); +for(j = 0; j != D[140].length; ++j) if(D[140][j].charCodeAt(0) !== 0xFFFD) { e[D[140][j]] = 35840 + j; d[35840 + j] = D[140][j];} +D[141] = "����������������������������������������������������������������后喉坑垢好孔孝宏工巧巷幸広庚康弘恒慌抗拘控攻昂晃更杭校梗構江洪浩港溝甲皇硬稿糠紅紘絞綱耕考肯肱腔膏航荒行衡講貢購郊酵鉱砿鋼閤降�項香高鴻剛劫号合壕拷濠豪轟麹克刻告国穀酷鵠黒獄漉腰甑忽惚骨狛込此頃今困坤墾婚恨懇昏昆根梱混痕紺艮魂些佐叉唆嵯左差査沙瑳砂詐鎖裟坐座挫債催再最哉塞妻宰彩才採栽歳済災采犀砕砦祭斎細菜裁載際剤在材罪財冴坂阪堺榊肴咲崎埼碕鷺作削咋搾昨朔柵窄策索錯桜鮭笹匙冊刷���".split(""); +for(j = 0; j != D[141].length; ++j) if(D[141][j].charCodeAt(0) !== 0xFFFD) { e[D[141][j]] = 36096 + j; d[36096 + j] = D[141][j];} +D[142] = "����������������������������������������������������������������察拶撮擦札殺薩雑皐鯖捌錆鮫皿晒三傘参山惨撒散桟燦珊産算纂蚕讃賛酸餐斬暫残仕仔伺使刺司史嗣四士始姉姿子屍市師志思指支孜斯施旨枝止�死氏獅祉私糸紙紫肢脂至視詞詩試誌諮資賜雌飼歯事似侍児字寺慈持時次滋治爾璽痔磁示而耳自蒔辞汐鹿式識鴫竺軸宍雫七叱執失嫉室悉湿漆疾質実蔀篠偲柴芝屡蕊縞舎写射捨赦斜煮社紗者謝車遮蛇邪借勺尺杓灼爵酌釈錫若寂弱惹主取守手朱殊狩珠種腫趣酒首儒受呪寿授樹綬需囚収周���".split(""); +for(j = 0; j != D[142].length; ++j) if(D[142][j].charCodeAt(0) !== 0xFFFD) { e[D[142][j]] = 36352 + j; d[36352 + j] = D[142][j];} +D[143] = "����������������������������������������������������������������宗就州修愁拾洲秀秋終繍習臭舟蒐衆襲讐蹴輯週酋酬集醜什住充十従戎柔汁渋獣縦重銃叔夙宿淑祝縮粛塾熟出術述俊峻春瞬竣舜駿准循旬楯殉淳�準潤盾純巡遵醇順処初所暑曙渚庶緒署書薯藷諸助叙女序徐恕鋤除傷償勝匠升召哨商唱嘗奨妾娼宵将小少尚庄床廠彰承抄招掌捷昇昌昭晶松梢樟樵沼消渉湘焼焦照症省硝礁祥称章笑粧紹肖菖蒋蕉衝裳訟証詔詳象賞醤鉦鍾鐘障鞘上丈丞乗冗剰城場壌嬢常情擾条杖浄状畳穣蒸譲醸錠嘱埴飾���".split(""); +for(j = 0; j != D[143].length; ++j) if(D[143][j].charCodeAt(0) !== 0xFFFD) { e[D[143][j]] = 36608 + j; d[36608 + j] = D[143][j];} +D[144] = "����������������������������������������������������������������拭植殖燭織職色触食蝕辱尻伸信侵唇娠寝審心慎振新晋森榛浸深申疹真神秦紳臣芯薪親診身辛進針震人仁刃塵壬尋甚尽腎訊迅陣靭笥諏須酢図厨�逗吹垂帥推水炊睡粋翠衰遂酔錐錘随瑞髄崇嵩数枢趨雛据杉椙菅頗雀裾澄摺寸世瀬畝是凄制勢姓征性成政整星晴棲栖正清牲生盛精聖声製西誠誓請逝醒青静斉税脆隻席惜戚斥昔析石積籍績脊責赤跡蹟碩切拙接摂折設窃節説雪絶舌蝉仙先千占宣専尖川戦扇撰栓栴泉浅洗染潜煎煽旋穿箭線���".split(""); +for(j = 0; j != D[144].length; ++j) if(D[144][j].charCodeAt(0) !== 0xFFFD) { e[D[144][j]] = 36864 + j; d[36864 + j] = D[144][j];} +D[145] = "����������������������������������������������������������������繊羨腺舛船薦詮賎践選遷銭銑閃鮮前善漸然全禅繕膳糎噌塑岨措曾曽楚狙疏疎礎祖租粗素組蘇訴阻遡鼠僧創双叢倉喪壮奏爽宋層匝惣想捜掃挿掻�操早曹巣槍槽漕燥争痩相窓糟総綜聡草荘葬蒼藻装走送遭鎗霜騒像増憎臓蔵贈造促側則即息捉束測足速俗属賊族続卒袖其揃存孫尊損村遜他多太汰詑唾堕妥惰打柁舵楕陀駄騨体堆対耐岱帯待怠態戴替泰滞胎腿苔袋貸退逮隊黛鯛代台大第醍題鷹滝瀧卓啄宅托択拓沢濯琢託鐸濁諾茸凧蛸只���".split(""); +for(j = 0; j != D[145].length; ++j) if(D[145][j].charCodeAt(0) !== 0xFFFD) { e[D[145][j]] = 37120 + j; d[37120 + j] = D[145][j];} +D[146] = "����������������������������������������������������������������叩但達辰奪脱巽竪辿棚谷狸鱈樽誰丹単嘆坦担探旦歎淡湛炭短端箪綻耽胆蛋誕鍛団壇弾断暖檀段男談値知地弛恥智池痴稚置致蜘遅馳築畜竹筑蓄�逐秩窒茶嫡着中仲宙忠抽昼柱注虫衷註酎鋳駐樗瀦猪苧著貯丁兆凋喋寵帖帳庁弔張彫徴懲挑暢朝潮牒町眺聴脹腸蝶調諜超跳銚長頂鳥勅捗直朕沈珍賃鎮陳津墜椎槌追鎚痛通塚栂掴槻佃漬柘辻蔦綴鍔椿潰坪壷嬬紬爪吊釣鶴亭低停偵剃貞呈堤定帝底庭廷弟悌抵挺提梯汀碇禎程締艇訂諦蹄逓���".split(""); +for(j = 0; j != D[146].length; ++j) if(D[146][j].charCodeAt(0) !== 0xFFFD) { e[D[146][j]] = 37376 + j; d[37376 + j] = D[146][j];} +D[147] = "����������������������������������������������������������������邸鄭釘鼎泥摘擢敵滴的笛適鏑溺哲徹撤轍迭鉄典填天展店添纏甜貼転顛点伝殿澱田電兎吐堵塗妬屠徒斗杜渡登菟賭途都鍍砥砺努度土奴怒倒党冬�凍刀唐塔塘套宕島嶋悼投搭東桃梼棟盗淘湯涛灯燈当痘祷等答筒糖統到董蕩藤討謄豆踏逃透鐙陶頭騰闘働動同堂導憧撞洞瞳童胴萄道銅峠鴇匿得徳涜特督禿篤毒独読栃橡凸突椴届鳶苫寅酉瀞噸屯惇敦沌豚遁頓呑曇鈍奈那内乍凪薙謎灘捺鍋楢馴縄畷南楠軟難汝二尼弐迩匂賑肉虹廿日乳入���".split(""); +for(j = 0; j != D[147].length; ++j) if(D[147][j].charCodeAt(0) !== 0xFFFD) { e[D[147][j]] = 37632 + j; d[37632 + j] = D[147][j];} +D[148] = "����������������������������������������������������������������如尿韮任妊忍認濡禰祢寧葱猫熱年念捻撚燃粘乃廼之埜嚢悩濃納能脳膿農覗蚤巴把播覇杷波派琶破婆罵芭馬俳廃拝排敗杯盃牌背肺輩配倍培媒梅�楳煤狽買売賠陪這蝿秤矧萩伯剥博拍柏泊白箔粕舶薄迫曝漠爆縛莫駁麦函箱硲箸肇筈櫨幡肌畑畠八鉢溌発醗髪伐罰抜筏閥鳩噺塙蛤隼伴判半反叛帆搬斑板氾汎版犯班畔繁般藩販範釆煩頒飯挽晩番盤磐蕃蛮匪卑否妃庇彼悲扉批披斐比泌疲皮碑秘緋罷肥被誹費避非飛樋簸備尾微枇毘琵眉美���".split(""); +for(j = 0; j != D[148].length; ++j) if(D[148][j].charCodeAt(0) !== 0xFFFD) { e[D[148][j]] = 37888 + j; d[37888 + j] = D[148][j];} +D[149] = "����������������������������������������������������������������鼻柊稗匹疋髭彦膝菱肘弼必畢筆逼桧姫媛紐百謬俵彪標氷漂瓢票表評豹廟描病秒苗錨鋲蒜蛭鰭品彬斌浜瀕貧賓頻敏瓶不付埠夫婦富冨布府怖扶敷�斧普浮父符腐膚芙譜負賦赴阜附侮撫武舞葡蕪部封楓風葺蕗伏副復幅服福腹複覆淵弗払沸仏物鮒分吻噴墳憤扮焚奮粉糞紛雰文聞丙併兵塀幣平弊柄並蔽閉陛米頁僻壁癖碧別瞥蔑箆偏変片篇編辺返遍便勉娩弁鞭保舗鋪圃捕歩甫補輔穂募墓慕戊暮母簿菩倣俸包呆報奉宝峰峯崩庖抱捧放方朋���".split(""); +for(j = 0; j != D[149].length; ++j) if(D[149][j].charCodeAt(0) !== 0xFFFD) { e[D[149][j]] = 38144 + j; d[38144 + j] = D[149][j];} +D[150] = "����������������������������������������������������������������法泡烹砲縫胞芳萌蓬蜂褒訪豊邦鋒飽鳳鵬乏亡傍剖坊妨帽忘忙房暴望某棒冒紡肪膨謀貌貿鉾防吠頬北僕卜墨撲朴牧睦穆釦勃没殆堀幌奔本翻凡盆�摩磨魔麻埋妹昧枚毎哩槙幕膜枕鮪柾鱒桝亦俣又抹末沫迄侭繭麿万慢満漫蔓味未魅巳箕岬密蜜湊蓑稔脈妙粍民眠務夢無牟矛霧鵡椋婿娘冥名命明盟迷銘鳴姪牝滅免棉綿緬面麺摸模茂妄孟毛猛盲網耗蒙儲木黙目杢勿餅尤戻籾貰問悶紋門匁也冶夜爺耶野弥矢厄役約薬訳躍靖柳薮鑓愉愈油癒���".split(""); +for(j = 0; j != D[150].length; ++j) if(D[150][j].charCodeAt(0) !== 0xFFFD) { e[D[150][j]] = 38400 + j; d[38400 + j] = D[150][j];} +D[151] = "����������������������������������������������������������������諭輸唯佑優勇友宥幽悠憂揖有柚湧涌猶猷由祐裕誘遊邑郵雄融夕予余与誉輿預傭幼妖容庸揚揺擁曜楊様洋溶熔用窯羊耀葉蓉要謡踊遥陽養慾抑欲�沃浴翌翼淀羅螺裸来莱頼雷洛絡落酪乱卵嵐欄濫藍蘭覧利吏履李梨理璃痢裏裡里離陸律率立葎掠略劉流溜琉留硫粒隆竜龍侶慮旅虜了亮僚両凌寮料梁涼猟療瞭稜糧良諒遼量陵領力緑倫厘林淋燐琳臨輪隣鱗麟瑠塁涙累類令伶例冷励嶺怜玲礼苓鈴隷零霊麗齢暦歴列劣烈裂廉恋憐漣煉簾練聯���".split(""); +for(j = 0; j != D[151].length; ++j) if(D[151][j].charCodeAt(0) !== 0xFFFD) { e[D[151][j]] = 38656 + j; d[38656 + j] = D[151][j];} +D[152] = "����������������������������������������������������������������蓮連錬呂魯櫓炉賂路露労婁廊弄朗楼榔浪漏牢狼篭老聾蝋郎六麓禄肋録論倭和話歪賄脇惑枠鷲亙亘鰐詫藁蕨椀湾碗腕��������������������������������������������弌丐丕个丱丶丼丿乂乖乘亂亅豫亊舒弍于亞亟亠亢亰亳亶从仍仄仆仂仗仞仭仟价伉佚估佛佝佗佇佶侈侏侘佻佩佰侑佯來侖儘俔俟俎俘俛俑俚俐俤俥倚倨倔倪倥倅伜俶倡倩倬俾俯們倆偃假會偕偐偈做偖偬偸傀傚傅傴傲���".split(""); +for(j = 0; j != D[152].length; ++j) if(D[152][j].charCodeAt(0) !== 0xFFFD) { e[D[152][j]] = 38912 + j; d[38912 + j] = D[152][j];} +D[153] = "����������������������������������������������������������������僉僊傳僂僖僞僥僭僣僮價僵儉儁儂儖儕儔儚儡儺儷儼儻儿兀兒兌兔兢竸兩兪兮冀冂囘册冉冏冑冓冕冖冤冦冢冩冪冫决冱冲冰况冽凅凉凛几處凩凭�凰凵凾刄刋刔刎刧刪刮刳刹剏剄剋剌剞剔剪剴剩剳剿剽劍劔劒剱劈劑辨辧劬劭劼劵勁勍勗勞勣勦飭勠勳勵勸勹匆匈甸匍匐匏匕匚匣匯匱匳匸區卆卅丗卉卍凖卞卩卮夘卻卷厂厖厠厦厥厮厰厶參簒雙叟曼燮叮叨叭叺吁吽呀听吭吼吮吶吩吝呎咏呵咎呟呱呷呰咒呻咀呶咄咐咆哇咢咸咥咬哄哈咨���".split(""); +for(j = 0; j != D[153].length; ++j) if(D[153][j].charCodeAt(0) !== 0xFFFD) { e[D[153][j]] = 39168 + j; d[39168 + j] = D[153][j];} +D[154] = "����������������������������������������������������������������咫哂咤咾咼哘哥哦唏唔哽哮哭哺哢唹啀啣啌售啜啅啖啗唸唳啝喙喀咯喊喟啻啾喘喞單啼喃喩喇喨嗚嗅嗟嗄嗜嗤嗔嘔嗷嘖嗾嗽嘛嗹噎噐營嘴嘶嘲嘸�噫噤嘯噬噪嚆嚀嚊嚠嚔嚏嚥嚮嚶嚴囂嚼囁囃囀囈囎囑囓囗囮囹圀囿圄圉圈國圍圓團圖嗇圜圦圷圸坎圻址坏坩埀垈坡坿垉垓垠垳垤垪垰埃埆埔埒埓堊埖埣堋堙堝塲堡塢塋塰毀塒堽塹墅墹墟墫墺壞墻墸墮壅壓壑壗壙壘壥壜壤壟壯壺壹壻壼壽夂夊夐夛梦夥夬夭夲夸夾竒奕奐奎奚奘奢奠奧奬奩���".split(""); +for(j = 0; j != D[154].length; ++j) if(D[154][j].charCodeAt(0) !== 0xFFFD) { e[D[154][j]] = 39424 + j; d[39424 + j] = D[154][j];} +D[155] = "����������������������������������������������������������������奸妁妝佞侫妣妲姆姨姜妍姙姚娥娟娑娜娉娚婀婬婉娵娶婢婪媚媼媾嫋嫂媽嫣嫗嫦嫩嫖嫺嫻嬌嬋嬖嬲嫐嬪嬶嬾孃孅孀孑孕孚孛孥孩孰孳孵學斈孺宀�它宦宸寃寇寉寔寐寤實寢寞寥寫寰寶寳尅將專對尓尠尢尨尸尹屁屆屎屓屐屏孱屬屮乢屶屹岌岑岔妛岫岻岶岼岷峅岾峇峙峩峽峺峭嶌峪崋崕崗嵜崟崛崑崔崢崚崙崘嵌嵒嵎嵋嵬嵳嵶嶇嶄嶂嶢嶝嶬嶮嶽嶐嶷嶼巉巍巓巒巖巛巫已巵帋帚帙帑帛帶帷幄幃幀幎幗幔幟幢幤幇幵并幺麼广庠廁廂廈廐廏���".split(""); +for(j = 0; j != D[155].length; ++j) if(D[155][j].charCodeAt(0) !== 0xFFFD) { e[D[155][j]] = 39680 + j; d[39680 + j] = D[155][j];} +D[156] = "����������������������������������������������������������������廖廣廝廚廛廢廡廨廩廬廱廳廰廴廸廾弃弉彝彜弋弑弖弩弭弸彁彈彌彎弯彑彖彗彙彡彭彳彷徃徂彿徊很徑徇從徙徘徠徨徭徼忖忻忤忸忱忝悳忿怡恠�怙怐怩怎怱怛怕怫怦怏怺恚恁恪恷恟恊恆恍恣恃恤恂恬恫恙悁悍惧悃悚悄悛悖悗悒悧悋惡悸惠惓悴忰悽惆悵惘慍愕愆惶惷愀惴惺愃愡惻惱愍愎慇愾愨愧慊愿愼愬愴愽慂慄慳慷慘慙慚慫慴慯慥慱慟慝慓慵憙憖憇憬憔憚憊憑憫憮懌懊應懷懈懃懆憺懋罹懍懦懣懶懺懴懿懽懼懾戀戈戉戍戌戔戛���".split(""); +for(j = 0; j != D[156].length; ++j) if(D[156][j].charCodeAt(0) !== 0xFFFD) { e[D[156][j]] = 39936 + j; d[39936 + j] = D[156][j];} +D[157] = "����������������������������������������������������������������戞戡截戮戰戲戳扁扎扞扣扛扠扨扼抂抉找抒抓抖拔抃抔拗拑抻拏拿拆擔拈拜拌拊拂拇抛拉挌拮拱挧挂挈拯拵捐挾捍搜捏掖掎掀掫捶掣掏掉掟掵捫�捩掾揩揀揆揣揉插揶揄搖搴搆搓搦搶攝搗搨搏摧摯摶摎攪撕撓撥撩撈撼據擒擅擇撻擘擂擱擧舉擠擡抬擣擯攬擶擴擲擺攀擽攘攜攅攤攣攫攴攵攷收攸畋效敖敕敍敘敞敝敲數斂斃變斛斟斫斷旃旆旁旄旌旒旛旙无旡旱杲昊昃旻杳昵昶昴昜晏晄晉晁晞晝晤晧晨晟晢晰暃暈暎暉暄暘暝曁暹曉暾暼���".split(""); +for(j = 0; j != D[157].length; ++j) if(D[157][j].charCodeAt(0) !== 0xFFFD) { e[D[157][j]] = 40192 + j; d[40192 + j] = D[157][j];} +D[158] = "����������������������������������������������������������������曄暸曖曚曠昿曦曩曰曵曷朏朖朞朦朧霸朮朿朶杁朸朷杆杞杠杙杣杤枉杰枩杼杪枌枋枦枡枅枷柯枴柬枳柩枸柤柞柝柢柮枹柎柆柧檜栞框栩桀桍栲桎�梳栫桙档桷桿梟梏梭梔條梛梃檮梹桴梵梠梺椏梍桾椁棊椈棘椢椦棡椌棍棔棧棕椶椒椄棗棣椥棹棠棯椨椪椚椣椡棆楹楷楜楸楫楔楾楮椹楴椽楙椰楡楞楝榁楪榲榮槐榿槁槓榾槎寨槊槝榻槃榧樮榑榠榜榕榴槞槨樂樛槿權槹槲槧樅榱樞槭樔槫樊樒櫁樣樓橄樌橲樶橸橇橢橙橦橈樸樢檐檍檠檄檢檣���".split(""); +for(j = 0; j != D[158].length; ++j) if(D[158][j].charCodeAt(0) !== 0xFFFD) { e[D[158][j]] = 40448 + j; d[40448 + j] = D[158][j];} +D[159] = "����������������������������������������������������������������檗蘗檻櫃櫂檸檳檬櫞櫑櫟檪櫚櫪櫻欅蘖櫺欒欖鬱欟欸欷盜欹飮歇歃歉歐歙歔歛歟歡歸歹歿殀殄殃殍殘殕殞殤殪殫殯殲殱殳殷殼毆毋毓毟毬毫毳毯�麾氈氓气氛氤氣汞汕汢汪沂沍沚沁沛汾汨汳沒沐泄泱泓沽泗泅泝沮沱沾沺泛泯泙泪洟衍洶洫洽洸洙洵洳洒洌浣涓浤浚浹浙涎涕濤涅淹渕渊涵淇淦涸淆淬淞淌淨淒淅淺淙淤淕淪淮渭湮渮渙湲湟渾渣湫渫湶湍渟湃渺湎渤滿渝游溂溪溘滉溷滓溽溯滄溲滔滕溏溥滂溟潁漑灌滬滸滾漿滲漱滯漲滌���".split(""); +for(j = 0; j != D[159].length; ++j) if(D[159][j].charCodeAt(0) !== 0xFFFD) { e[D[159][j]] = 40704 + j; d[40704 + j] = D[159][j];} +D[224] = "����������������������������������������������������������������漾漓滷澆潺潸澁澀潯潛濳潭澂潼潘澎澑濂潦澳澣澡澤澹濆澪濟濕濬濔濘濱濮濛瀉瀋濺瀑瀁瀏濾瀛瀚潴瀝瀘瀟瀰瀾瀲灑灣炙炒炯烱炬炸炳炮烟烋烝�烙焉烽焜焙煥煕熈煦煢煌煖煬熏燻熄熕熨熬燗熹熾燒燉燔燎燠燬燧燵燼燹燿爍爐爛爨爭爬爰爲爻爼爿牀牆牋牘牴牾犂犁犇犒犖犢犧犹犲狃狆狄狎狒狢狠狡狹狷倏猗猊猜猖猝猴猯猩猥猾獎獏默獗獪獨獰獸獵獻獺珈玳珎玻珀珥珮珞璢琅瑯琥珸琲琺瑕琿瑟瑙瑁瑜瑩瑰瑣瑪瑶瑾璋璞璧瓊瓏瓔珱���".split(""); +for(j = 0; j != D[224].length; ++j) if(D[224][j].charCodeAt(0) !== 0xFFFD) { e[D[224][j]] = 57344 + j; d[57344 + j] = D[224][j];} +D[225] = "����������������������������������������������������������������瓠瓣瓧瓩瓮瓲瓰瓱瓸瓷甄甃甅甌甎甍甕甓甞甦甬甼畄畍畊畉畛畆畚畩畤畧畫畭畸當疆疇畴疊疉疂疔疚疝疥疣痂疳痃疵疽疸疼疱痍痊痒痙痣痞痾痿�痼瘁痰痺痲痳瘋瘍瘉瘟瘧瘠瘡瘢瘤瘴瘰瘻癇癈癆癜癘癡癢癨癩癪癧癬癰癲癶癸發皀皃皈皋皎皖皓皙皚皰皴皸皹皺盂盍盖盒盞盡盥盧盪蘯盻眈眇眄眩眤眞眥眦眛眷眸睇睚睨睫睛睥睿睾睹瞎瞋瞑瞠瞞瞰瞶瞹瞿瞼瞽瞻矇矍矗矚矜矣矮矼砌砒礦砠礪硅碎硴碆硼碚碌碣碵碪碯磑磆磋磔碾碼磅磊磬���".split(""); +for(j = 0; j != D[225].length; ++j) if(D[225][j].charCodeAt(0) !== 0xFFFD) { e[D[225][j]] = 57600 + j; d[57600 + j] = D[225][j];} +D[226] = "����������������������������������������������������������������磧磚磽磴礇礒礑礙礬礫祀祠祗祟祚祕祓祺祿禊禝禧齋禪禮禳禹禺秉秕秧秬秡秣稈稍稘稙稠稟禀稱稻稾稷穃穗穉穡穢穩龝穰穹穽窈窗窕窘窖窩竈窰�窶竅竄窿邃竇竊竍竏竕竓站竚竝竡竢竦竭竰笂笏笊笆笳笘笙笞笵笨笶筐筺笄筍笋筌筅筵筥筴筧筰筱筬筮箝箘箟箍箜箚箋箒箏筝箙篋篁篌篏箴篆篝篩簑簔篦篥籠簀簇簓篳篷簗簍篶簣簧簪簟簷簫簽籌籃籔籏籀籐籘籟籤籖籥籬籵粃粐粤粭粢粫粡粨粳粲粱粮粹粽糀糅糂糘糒糜糢鬻糯糲糴糶糺紆���".split(""); +for(j = 0; j != D[226].length; ++j) if(D[226][j].charCodeAt(0) !== 0xFFFD) { e[D[226][j]] = 57856 + j; d[57856 + j] = D[226][j];} +D[227] = "����������������������������������������������������������������紂紜紕紊絅絋紮紲紿紵絆絳絖絎絲絨絮絏絣經綉絛綏絽綛綺綮綣綵緇綽綫總綢綯緜綸綟綰緘緝緤緞緻緲緡縅縊縣縡縒縱縟縉縋縢繆繦縻縵縹繃縷�縲縺繧繝繖繞繙繚繹繪繩繼繻纃緕繽辮繿纈纉續纒纐纓纔纖纎纛纜缸缺罅罌罍罎罐网罕罔罘罟罠罨罩罧罸羂羆羃羈羇羌羔羞羝羚羣羯羲羹羮羶羸譱翅翆翊翕翔翡翦翩翳翹飜耆耄耋耒耘耙耜耡耨耿耻聊聆聒聘聚聟聢聨聳聲聰聶聹聽聿肄肆肅肛肓肚肭冐肬胛胥胙胝胄胚胖脉胯胱脛脩脣脯腋���".split(""); +for(j = 0; j != D[227].length; ++j) if(D[227][j].charCodeAt(0) !== 0xFFFD) { e[D[227][j]] = 58112 + j; d[58112 + j] = D[227][j];} +D[228] = "����������������������������������������������������������������隋腆脾腓腑胼腱腮腥腦腴膃膈膊膀膂膠膕膤膣腟膓膩膰膵膾膸膽臀臂膺臉臍臑臙臘臈臚臟臠臧臺臻臾舁舂舅與舊舍舐舖舩舫舸舳艀艙艘艝艚艟艤�艢艨艪艫舮艱艷艸艾芍芒芫芟芻芬苡苣苟苒苴苳苺莓范苻苹苞茆苜茉苙茵茴茖茲茱荀茹荐荅茯茫茗茘莅莚莪莟莢莖茣莎莇莊荼莵荳荵莠莉莨菴萓菫菎菽萃菘萋菁菷萇菠菲萍萢萠莽萸蔆菻葭萪萼蕚蒄葷葫蒭葮蒂葩葆萬葯葹萵蓊葢蒹蒿蒟蓙蓍蒻蓚蓐蓁蓆蓖蒡蔡蓿蓴蔗蔘蔬蔟蔕蔔蓼蕀蕣蕘蕈���".split(""); +for(j = 0; j != D[228].length; ++j) if(D[228][j].charCodeAt(0) !== 0xFFFD) { e[D[228][j]] = 58368 + j; d[58368 + j] = D[228][j];} +D[229] = "����������������������������������������������������������������蕁蘂蕋蕕薀薤薈薑薊薨蕭薔薛藪薇薜蕷蕾薐藉薺藏薹藐藕藝藥藜藹蘊蘓蘋藾藺蘆蘢蘚蘰蘿虍乕虔號虧虱蚓蚣蚩蚪蚋蚌蚶蚯蛄蛆蚰蛉蠣蚫蛔蛞蛩蛬�蛟蛛蛯蜒蜆蜈蜀蜃蛻蜑蜉蜍蛹蜊蜴蜿蜷蜻蜥蜩蜚蝠蝟蝸蝌蝎蝴蝗蝨蝮蝙蝓蝣蝪蠅螢螟螂螯蟋螽蟀蟐雖螫蟄螳蟇蟆螻蟯蟲蟠蠏蠍蟾蟶蟷蠎蟒蠑蠖蠕蠢蠡蠱蠶蠹蠧蠻衄衂衒衙衞衢衫袁衾袞衵衽袵衲袂袗袒袮袙袢袍袤袰袿袱裃裄裔裘裙裝裹褂裼裴裨裲褄褌褊褓襃褞褥褪褫襁襄褻褶褸襌褝襠襞���".split(""); +for(j = 0; j != D[229].length; ++j) if(D[229][j].charCodeAt(0) !== 0xFFFD) { e[D[229][j]] = 58624 + j; d[58624 + j] = D[229][j];} +D[230] = "����������������������������������������������������������������襦襤襭襪襯襴襷襾覃覈覊覓覘覡覩覦覬覯覲覺覽覿觀觚觜觝觧觴觸訃訖訐訌訛訝訥訶詁詛詒詆詈詼詭詬詢誅誂誄誨誡誑誥誦誚誣諄諍諂諚諫諳諧�諤諱謔諠諢諷諞諛謌謇謚諡謖謐謗謠謳鞫謦謫謾謨譁譌譏譎證譖譛譚譫譟譬譯譴譽讀讌讎讒讓讖讙讚谺豁谿豈豌豎豐豕豢豬豸豺貂貉貅貊貍貎貔豼貘戝貭貪貽貲貳貮貶賈賁賤賣賚賽賺賻贄贅贊贇贏贍贐齎贓賍贔贖赧赭赱赳趁趙跂趾趺跏跚跖跌跛跋跪跫跟跣跼踈踉跿踝踞踐踟蹂踵踰踴蹊���".split(""); +for(j = 0; j != D[230].length; ++j) if(D[230][j].charCodeAt(0) !== 0xFFFD) { e[D[230][j]] = 58880 + j; d[58880 + j] = D[230][j];} +D[231] = "����������������������������������������������������������������蹇蹉蹌蹐蹈蹙蹤蹠踪蹣蹕蹶蹲蹼躁躇躅躄躋躊躓躑躔躙躪躡躬躰軆躱躾軅軈軋軛軣軼軻軫軾輊輅輕輒輙輓輜輟輛輌輦輳輻輹轅轂輾轌轉轆轎轗轜�轢轣轤辜辟辣辭辯辷迚迥迢迪迯邇迴逅迹迺逑逕逡逍逞逖逋逧逶逵逹迸遏遐遑遒逎遉逾遖遘遞遨遯遶隨遲邂遽邁邀邊邉邏邨邯邱邵郢郤扈郛鄂鄒鄙鄲鄰酊酖酘酣酥酩酳酲醋醉醂醢醫醯醪醵醴醺釀釁釉釋釐釖釟釡釛釼釵釶鈞釿鈔鈬鈕鈑鉞鉗鉅鉉鉤鉈銕鈿鉋鉐銜銖銓銛鉚鋏銹銷鋩錏鋺鍄錮���".split(""); +for(j = 0; j != D[231].length; ++j) if(D[231][j].charCodeAt(0) !== 0xFFFD) { e[D[231][j]] = 59136 + j; d[59136 + j] = D[231][j];} +D[232] = "����������������������������������������������������������������錙錢錚錣錺錵錻鍜鍠鍼鍮鍖鎰鎬鎭鎔鎹鏖鏗鏨鏥鏘鏃鏝鏐鏈鏤鐚鐔鐓鐃鐇鐐鐶鐫鐵鐡鐺鑁鑒鑄鑛鑠鑢鑞鑪鈩鑰鑵鑷鑽鑚鑼鑾钁鑿閂閇閊閔閖閘閙�閠閨閧閭閼閻閹閾闊濶闃闍闌闕闔闖關闡闥闢阡阨阮阯陂陌陏陋陷陜陞陝陟陦陲陬隍隘隕隗險隧隱隲隰隴隶隸隹雎雋雉雍襍雜霍雕雹霄霆霈霓霎霑霏霖霙霤霪霰霹霽霾靄靆靈靂靉靜靠靤靦靨勒靫靱靹鞅靼鞁靺鞆鞋鞏鞐鞜鞨鞦鞣鞳鞴韃韆韈韋韜韭齏韲竟韶韵頏頌頸頤頡頷頽顆顏顋顫顯顰���".split(""); +for(j = 0; j != D[232].length; ++j) if(D[232][j].charCodeAt(0) !== 0xFFFD) { e[D[232][j]] = 59392 + j; d[59392 + j] = D[232][j];} +D[233] = "����������������������������������������������������������������顱顴顳颪颯颱颶飄飃飆飩飫餃餉餒餔餘餡餝餞餤餠餬餮餽餾饂饉饅饐饋饑饒饌饕馗馘馥馭馮馼駟駛駝駘駑駭駮駱駲駻駸騁騏騅駢騙騫騷驅驂驀驃�騾驕驍驛驗驟驢驥驤驩驫驪骭骰骼髀髏髑髓體髞髟髢髣髦髯髫髮髴髱髷髻鬆鬘鬚鬟鬢鬣鬥鬧鬨鬩鬪鬮鬯鬲魄魃魏魍魎魑魘魴鮓鮃鮑鮖鮗鮟鮠鮨鮴鯀鯊鮹鯆鯏鯑鯒鯣鯢鯤鯔鯡鰺鯲鯱鯰鰕鰔鰉鰓鰌鰆鰈鰒鰊鰄鰮鰛鰥鰤鰡鰰鱇鰲鱆鰾鱚鱠鱧鱶鱸鳧鳬鳰鴉鴈鳫鴃鴆鴪鴦鶯鴣鴟鵄鴕鴒鵁鴿鴾鵆鵈���".split(""); +for(j = 0; j != D[233].length; ++j) if(D[233][j].charCodeAt(0) !== 0xFFFD) { e[D[233][j]] = 59648 + j; d[59648 + j] = D[233][j];} +D[234] = "����������������������������������������������������������������鵝鵞鵤鵑鵐鵙鵲鶉鶇鶫鵯鵺鶚鶤鶩鶲鷄鷁鶻鶸鶺鷆鷏鷂鷙鷓鷸鷦鷭鷯鷽鸚鸛鸞鹵鹹鹽麁麈麋麌麒麕麑麝麥麩麸麪麭靡黌黎黏黐黔黜點黝黠黥黨黯�黴黶黷黹黻黼黽鼇鼈皷鼕鼡鼬鼾齊齒齔齣齟齠齡齦齧齬齪齷齲齶龕龜龠堯槇遙瑤凜熙�������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[234].length; ++j) if(D[234][j].charCodeAt(0) !== 0xFFFD) { e[D[234][j]] = 59904 + j; d[59904 + j] = D[234][j];} +D[237] = "����������������������������������������������������������������纊褜鍈銈蓜俉炻昱棈鋹曻彅丨仡仼伀伃伹佖侒侊侚侔俍偀倢俿倞偆偰偂傔僴僘兊兤冝冾凬刕劜劦勀勛匀匇匤卲厓厲叝﨎咜咊咩哿喆坙坥垬埈埇﨏�塚增墲夋奓奛奝奣妤妺孖寀甯寘寬尞岦岺峵崧嵓﨑嵂嵭嶸嶹巐弡弴彧德忞恝悅悊惞惕愠惲愑愷愰憘戓抦揵摠撝擎敎昀昕昻昉昮昞昤晥晗晙晴晳暙暠暲暿曺朎朗杦枻桒柀栁桄棏﨓楨﨔榘槢樰橫橆橳橾櫢櫤毖氿汜沆汯泚洄涇浯涖涬淏淸淲淼渹湜渧渼溿澈澵濵瀅瀇瀨炅炫焏焄煜煆煇凞燁燾犱���".split(""); +for(j = 0; j != D[237].length; ++j) if(D[237][j].charCodeAt(0) !== 0xFFFD) { e[D[237][j]] = 60672 + j; d[60672 + j] = D[237][j];} +D[238] = "����������������������������������������������������������������犾猤猪獷玽珉珖珣珒琇珵琦琪琩琮瑢璉璟甁畯皂皜皞皛皦益睆劯砡硎硤硺礰礼神祥禔福禛竑竧靖竫箞精絈絜綷綠緖繒罇羡羽茁荢荿菇菶葈蒴蕓蕙�蕫﨟薰蘒﨡蠇裵訒訷詹誧誾諟諸諶譓譿賰賴贒赶﨣軏﨤逸遧郞都鄕鄧釚釗釞釭釮釤釥鈆鈐鈊鈺鉀鈼鉎鉙鉑鈹鉧銧鉷鉸鋧鋗鋙鋐﨧鋕鋠鋓錥錡鋻﨨錞鋿錝錂鍰鍗鎤鏆鏞鏸鐱鑅鑈閒隆﨩隝隯霳霻靃靍靏靑靕顗顥飯飼餧館馞驎髙髜魵魲鮏鮱鮻鰀鵰鵫鶴鸙黑��ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹ¬¦'"���".split(""); +for(j = 0; j != D[238].length; ++j) if(D[238][j].charCodeAt(0) !== 0xFFFD) { e[D[238][j]] = 60928 + j; d[60928 + j] = D[238][j];} +D[250] = "����������������������������������������������������������������ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ¬¦'"㈱№℡∵纊褜鍈銈蓜俉炻昱棈鋹曻彅丨仡仼伀伃伹佖侒侊侚侔俍偀倢俿倞偆偰偂傔僴僘兊�兤冝冾凬刕劜劦勀勛匀匇匤卲厓厲叝﨎咜咊咩哿喆坙坥垬埈埇﨏塚增墲夋奓奛奝奣妤妺孖寀甯寘寬尞岦岺峵崧嵓﨑嵂嵭嶸嶹巐弡弴彧德忞恝悅悊惞惕愠惲愑愷愰憘戓抦揵摠撝擎敎昀昕昻昉昮昞昤晥晗晙晴晳暙暠暲暿曺朎朗杦枻桒柀栁桄棏﨓楨﨔榘槢樰橫橆橳橾櫢櫤毖氿汜沆汯泚洄涇浯���".split(""); +for(j = 0; j != D[250].length; ++j) if(D[250][j].charCodeAt(0) !== 0xFFFD) { e[D[250][j]] = 64000 + j; d[64000 + j] = D[250][j];} +D[251] = "����������������������������������������������������������������涖涬淏淸淲淼渹湜渧渼溿澈澵濵瀅瀇瀨炅炫焏焄煜煆煇凞燁燾犱犾猤猪獷玽珉珖珣珒琇珵琦琪琩琮瑢璉璟甁畯皂皜皞皛皦益睆劯砡硎硤硺礰礼神�祥禔福禛竑竧靖竫箞精絈絜綷綠緖繒罇羡羽茁荢荿菇菶葈蒴蕓蕙蕫﨟薰蘒﨡蠇裵訒訷詹誧誾諟諸諶譓譿賰賴贒赶﨣軏﨤逸遧郞都鄕鄧釚釗釞釭釮釤釥鈆鈐鈊鈺鉀鈼鉎鉙鉑鈹鉧銧鉷鉸鋧鋗鋙鋐﨧鋕鋠鋓錥錡鋻﨨錞鋿錝錂鍰鍗鎤鏆鏞鏸鐱鑅鑈閒隆﨩隝隯霳霻靃靍靏靑靕顗顥飯飼餧館馞驎髙���".split(""); +for(j = 0; j != D[251].length; ++j) if(D[251][j].charCodeAt(0) !== 0xFFFD) { e[D[251][j]] = 64256 + j; d[64256 + j] = D[251][j];} +D[252] = "����������������������������������������������������������������髜魵魲鮏鮱鮻鰀鵰鵫鶴鸙黑������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[252].length; ++j) if(D[252][j].charCodeAt(0) !== 0xFFFD) { e[D[252][j]] = 64512 + j; d[64512 + j] = D[252][j];} +return {"enc": e, "dec": d }; })(); +cptable[936] = (function(){ var d = [], e = {}, D = [], j; +D[0] = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€�������������������������������������������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[0].length; ++j) if(D[0][j].charCodeAt(0) !== 0xFFFD) { e[D[0][j]] = 0 + j; d[0 + j] = D[0][j];} +D[129] = "����������������������������������������������������������������丂丄丅丆丏丒丗丟丠両丣並丩丮丯丱丳丵丷丼乀乁乂乄乆乊乑乕乗乚乛乢乣乤乥乧乨乪乫乬乭乮乯乲乴乵乶乷乸乹乺乻乼乽乿亀亁亂亃亄亅亇亊�亐亖亗亙亜亝亞亣亪亯亰亱亴亶亷亸亹亼亽亾仈仌仏仐仒仚仛仜仠仢仦仧仩仭仮仯仱仴仸仹仺仼仾伀伂伃伄伅伆伇伈伋伌伒伓伔伕伖伜伝伡伣伨伩伬伭伮伱伳伵伷伹伻伾伿佀佁佂佄佅佇佈佉佊佋佌佒佔佖佡佢佦佨佪佫佭佮佱佲併佷佸佹佺佽侀侁侂侅來侇侊侌侎侐侒侓侕侖侘侙侚侜侞侟価侢�".split(""); +for(j = 0; j != D[129].length; ++j) if(D[129][j].charCodeAt(0) !== 0xFFFD) { e[D[129][j]] = 33024 + j; d[33024 + j] = D[129][j];} +D[130] = "����������������������������������������������������������������侤侫侭侰侱侲侳侴侶侷侸侹侺侻侼侽侾俀俁係俆俇俈俉俋俌俍俒俓俔俕俖俙俛俠俢俤俥俧俫俬俰俲俴俵俶俷俹俻俼俽俿倀倁倂倃倄倅倆倇倈倉倊�個倎倐們倓倕倖倗倛倝倞倠倢倣値倧倫倯倰倱倲倳倴倵倶倷倸倹倻倽倿偀偁偂偄偅偆偉偊偋偍偐偑偒偓偔偖偗偘偙偛偝偞偟偠偡偢偣偤偦偧偨偩偪偫偭偮偯偰偱偲偳側偵偸偹偺偼偽傁傂傃傄傆傇傉傊傋傌傎傏傐傑傒傓傔傕傖傗傘備傚傛傜傝傞傟傠傡傢傤傦傪傫傭傮傯傰傱傳傴債傶傷傸傹傼�".split(""); +for(j = 0; j != D[130].length; ++j) if(D[130][j].charCodeAt(0) !== 0xFFFD) { e[D[130][j]] = 33280 + j; d[33280 + j] = D[130][j];} +D[131] = "����������������������������������������������������������������傽傾傿僀僁僂僃僄僅僆僇僈僉僊僋僌働僎僐僑僒僓僔僕僗僘僙僛僜僝僞僟僠僡僢僣僤僥僨僩僪僫僯僰僱僲僴僶僷僸價僺僼僽僾僿儀儁儂儃億儅儈�儉儊儌儍儎儏儐儑儓儔儕儖儗儘儙儚儛儜儝儞償儠儢儣儤儥儦儧儨儩優儫儬儭儮儯儰儱儲儳儴儵儶儷儸儹儺儻儼儽儾兂兇兊兌兎兏児兒兓兗兘兙兛兝兞兟兠兡兣兤兦內兩兪兯兲兺兾兿冃冄円冇冊冋冎冏冐冑冓冔冘冚冝冞冟冡冣冦冧冨冩冪冭冮冴冸冹冺冾冿凁凂凃凅凈凊凍凎凐凒凓凔凕凖凗�".split(""); +for(j = 0; j != D[131].length; ++j) if(D[131][j].charCodeAt(0) !== 0xFFFD) { e[D[131][j]] = 33536 + j; d[33536 + j] = D[131][j];} +D[132] = "����������������������������������������������������������������凘凙凚凜凞凟凢凣凥処凧凨凩凪凬凮凱凲凴凷凾刄刅刉刋刌刏刐刓刔刕刜刞刟刡刢刣別刦刧刪刬刯刱刲刴刵刼刾剄剅剆則剈剉剋剎剏剒剓剕剗剘�剙剚剛剝剟剠剢剣剤剦剨剫剬剭剮剰剱剳剴創剶剷剸剹剺剻剼剾劀劃劄劅劆劇劉劊劋劌劍劎劏劑劒劔劕劖劗劘劙劚劜劤劥劦劧劮劯劰労劵劶劷劸効劺劻劼劽勀勁勂勄勅勆勈勊勌勍勎勏勑勓勔動勗務勚勛勜勝勞勠勡勢勣勥勦勧勨勩勪勫勬勭勮勯勱勲勳勴勵勶勷勸勻勼勽匁匂匃匄匇匉匊匋匌匎�".split(""); +for(j = 0; j != D[132].length; ++j) if(D[132][j].charCodeAt(0) !== 0xFFFD) { e[D[132][j]] = 33792 + j; d[33792 + j] = D[132][j];} +D[133] = "����������������������������������������������������������������匑匒匓匔匘匛匜匞匟匢匤匥匧匨匩匫匬匭匯匰匱匲匳匴匵匶匷匸匼匽區卂卄卆卋卌卍卐協単卙卛卝卥卨卪卬卭卲卶卹卻卼卽卾厀厁厃厇厈厊厎厏�厐厑厒厓厔厖厗厙厛厜厞厠厡厤厧厪厫厬厭厯厰厱厲厳厴厵厷厸厹厺厼厽厾叀參叄叅叆叇収叏叐叒叓叕叚叜叝叞叡叢叧叴叺叾叿吀吂吅吇吋吔吘吙吚吜吢吤吥吪吰吳吶吷吺吽吿呁呂呄呅呇呉呌呍呎呏呑呚呝呞呟呠呡呣呥呧呩呪呫呬呭呮呯呰呴呹呺呾呿咁咃咅咇咈咉咊咍咑咓咗咘咜咞咟咠咡�".split(""); +for(j = 0; j != D[133].length; ++j) if(D[133][j].charCodeAt(0) !== 0xFFFD) { e[D[133][j]] = 34048 + j; d[34048 + j] = D[133][j];} +D[134] = "����������������������������������������������������������������咢咥咮咰咲咵咶咷咹咺咼咾哃哅哊哋哖哘哛哠員哢哣哤哫哬哯哰哱哴哵哶哷哸哹哻哾唀唂唃唄唅唈唊唋唌唍唎唒唓唕唖唗唘唙唚唜唝唞唟唡唥唦�唨唩唫唭唲唴唵唶唸唹唺唻唽啀啂啅啇啈啋啌啍啎問啑啒啓啔啗啘啙啚啛啝啞啟啠啢啣啨啩啫啯啰啱啲啳啴啹啺啽啿喅喆喌喍喎喐喒喓喕喖喗喚喛喞喠喡喢喣喤喥喦喨喩喪喫喬喭單喯喰喲喴営喸喺喼喿嗀嗁嗂嗃嗆嗇嗈嗊嗋嗎嗏嗐嗕嗗嗘嗙嗚嗛嗞嗠嗢嗧嗩嗭嗮嗰嗱嗴嗶嗸嗹嗺嗻嗼嗿嘂嘃嘄嘅�".split(""); +for(j = 0; j != D[134].length; ++j) if(D[134][j].charCodeAt(0) !== 0xFFFD) { e[D[134][j]] = 34304 + j; d[34304 + j] = D[134][j];} +D[135] = "����������������������������������������������������������������嘆嘇嘊嘋嘍嘐嘑嘒嘓嘔嘕嘖嘗嘙嘚嘜嘝嘠嘡嘢嘥嘦嘨嘩嘪嘫嘮嘯嘰嘳嘵嘷嘸嘺嘼嘽嘾噀噁噂噃噄噅噆噇噈噉噊噋噏噐噑噒噓噕噖噚噛噝噞噟噠噡�噣噥噦噧噭噮噯噰噲噳噴噵噷噸噹噺噽噾噿嚀嚁嚂嚃嚄嚇嚈嚉嚊嚋嚌嚍嚐嚑嚒嚔嚕嚖嚗嚘嚙嚚嚛嚜嚝嚞嚟嚠嚡嚢嚤嚥嚦嚧嚨嚩嚪嚫嚬嚭嚮嚰嚱嚲嚳嚴嚵嚶嚸嚹嚺嚻嚽嚾嚿囀囁囂囃囄囅囆囇囈囉囋囌囍囎囏囐囑囒囓囕囖囘囙囜団囥囦囧囨囩囪囬囮囯囲図囶囷囸囻囼圀圁圂圅圇國圌圍圎圏圐圑�".split(""); +for(j = 0; j != D[135].length; ++j) if(D[135][j].charCodeAt(0) !== 0xFFFD) { e[D[135][j]] = 34560 + j; d[34560 + j] = D[135][j];} +D[136] = "����������������������������������������������������������������園圓圔圕圖圗團圙圚圛圝圞圠圡圢圤圥圦圧圫圱圲圴圵圶圷圸圼圽圿坁坃坄坅坆坈坉坋坒坓坔坕坖坘坙坢坣坥坧坬坮坰坱坲坴坵坸坹坺坽坾坿垀�垁垇垈垉垊垍垎垏垐垑垔垕垖垗垘垙垚垜垝垞垟垥垨垪垬垯垰垱垳垵垶垷垹垺垻垼垽垾垿埀埁埄埅埆埇埈埉埊埌埍埐埑埓埖埗埛埜埞埡埢埣埥埦埧埨埩埪埫埬埮埰埱埲埳埵埶執埻埼埾埿堁堃堄堅堈堉堊堌堎堏堐堒堓堔堖堗堘堚堛堜堝堟堢堣堥堦堧堨堩堫堬堭堮堯報堲堳場堶堷堸堹堺堻堼堽�".split(""); +for(j = 0; j != D[136].length; ++j) if(D[136][j].charCodeAt(0) !== 0xFFFD) { e[D[136][j]] = 34816 + j; d[34816 + j] = D[136][j];} +D[137] = "����������������������������������������������������������������堾堿塀塁塂塃塅塆塇塈塉塊塋塎塏塐塒塓塕塖塗塙塚塛塜塝塟塠塡塢塣塤塦塧塨塩塪塭塮塯塰塱塲塳塴塵塶塷塸塹塺塻塼塽塿墂墄墆墇墈墊墋墌�墍墎墏墐墑墔墕墖増墘墛墜墝墠墡墢墣墤墥墦墧墪墫墬墭墮墯墰墱墲墳墴墵墶墷墸墹墺墻墽墾墿壀壂壃壄壆壇壈壉壊壋壌壍壎壏壐壒壓壔壖壗壘壙壚壛壜壝壞壟壠壡壢壣壥壦壧壨壩壪壭壯壱売壴壵壷壸壺壻壼壽壾壿夀夁夃夅夆夈変夊夋夌夎夐夑夒夓夗夘夛夝夞夠夡夢夣夦夨夬夰夲夳夵夶夻�".split(""); +for(j = 0; j != D[137].length; ++j) if(D[137][j].charCodeAt(0) !== 0xFFFD) { e[D[137][j]] = 35072 + j; d[35072 + j] = D[137][j];} +D[138] = "����������������������������������������������������������������夽夾夿奀奃奅奆奊奌奍奐奒奓奙奛奜奝奞奟奡奣奤奦奧奨奩奪奫奬奭奮奯奰奱奲奵奷奺奻奼奾奿妀妅妉妋妌妎妏妐妑妔妕妘妚妛妜妝妟妠妡妢妦�妧妬妭妰妱妳妴妵妶妷妸妺妼妽妿姀姁姂姃姄姅姇姈姉姌姍姎姏姕姖姙姛姞姟姠姡姢姤姦姧姩姪姫姭姮姯姰姱姲姳姴姵姶姷姸姺姼姽姾娀娂娊娋娍娎娏娐娒娔娕娖娗娙娚娛娝娞娡娢娤娦娧娨娪娫娬娭娮娯娰娳娵娷娸娹娺娻娽娾娿婁婂婃婄婅婇婈婋婌婍婎婏婐婑婒婓婔婖婗婘婙婛婜婝婞婟婠�".split(""); +for(j = 0; j != D[138].length; ++j) if(D[138][j].charCodeAt(0) !== 0xFFFD) { e[D[138][j]] = 35328 + j; d[35328 + j] = D[138][j];} +D[139] = "����������������������������������������������������������������婡婣婤婥婦婨婩婫婬婭婮婯婰婱婲婳婸婹婻婼婽婾媀媁媂媃媄媅媆媇媈媉媊媋媌媍媎媏媐媑媓媔媕媖媗媘媙媜媝媞媟媠媡媢媣媤媥媦媧媨媩媫媬�媭媮媯媰媱媴媶媷媹媺媻媼媽媿嫀嫃嫄嫅嫆嫇嫈嫊嫋嫍嫎嫏嫐嫑嫓嫕嫗嫙嫚嫛嫝嫞嫟嫢嫤嫥嫧嫨嫪嫬嫭嫮嫯嫰嫲嫳嫴嫵嫶嫷嫸嫹嫺嫻嫼嫽嫾嫿嬀嬁嬂嬃嬄嬅嬆嬇嬈嬊嬋嬌嬍嬎嬏嬐嬑嬒嬓嬔嬕嬘嬙嬚嬛嬜嬝嬞嬟嬠嬡嬢嬣嬤嬥嬦嬧嬨嬩嬪嬫嬬嬭嬮嬯嬰嬱嬳嬵嬶嬸嬹嬺嬻嬼嬽嬾嬿孁孂孃孄孅孆孇�".split(""); +for(j = 0; j != D[139].length; ++j) if(D[139][j].charCodeAt(0) !== 0xFFFD) { e[D[139][j]] = 35584 + j; d[35584 + j] = D[139][j];} +D[140] = "����������������������������������������������������������������孈孉孊孋孌孍孎孏孒孖孞孠孡孧孨孫孭孮孯孲孴孶孷學孹孻孼孾孿宂宆宊宍宎宐宑宒宔宖実宧宨宩宬宭宮宯宱宲宷宺宻宼寀寁寃寈寉寊寋寍寎寏�寑寔寕寖寗寘寙寚寛寜寠寢寣實寧審寪寫寬寭寯寱寲寳寴寵寶寷寽対尀専尃尅將專尋尌對導尐尒尓尗尙尛尞尟尠尡尣尦尨尩尪尫尭尮尯尰尲尳尵尶尷屃屄屆屇屌屍屒屓屔屖屗屘屚屛屜屝屟屢層屧屨屩屪屫屬屭屰屲屳屴屵屶屷屸屻屼屽屾岀岃岄岅岆岇岉岊岋岎岏岒岓岕岝岞岟岠岡岤岥岦岧岨�".split(""); +for(j = 0; j != D[140].length; ++j) if(D[140][j].charCodeAt(0) !== 0xFFFD) { e[D[140][j]] = 35840 + j; d[35840 + j] = D[140][j];} +D[141] = "����������������������������������������������������������������岪岮岯岰岲岴岶岹岺岻岼岾峀峂峃峅峆峇峈峉峊峌峍峎峏峐峑峓峔峕峖峗峘峚峛峜峝峞峟峠峢峣峧峩峫峬峮峯峱峲峳峴峵島峷峸峹峺峼峽峾峿崀�崁崄崅崈崉崊崋崌崍崏崐崑崒崓崕崗崘崙崚崜崝崟崠崡崢崣崥崨崪崫崬崯崰崱崲崳崵崶崷崸崹崺崻崼崿嵀嵁嵂嵃嵄嵅嵆嵈嵉嵍嵎嵏嵐嵑嵒嵓嵔嵕嵖嵗嵙嵚嵜嵞嵟嵠嵡嵢嵣嵤嵥嵦嵧嵨嵪嵭嵮嵰嵱嵲嵳嵵嵶嵷嵸嵹嵺嵻嵼嵽嵾嵿嶀嶁嶃嶄嶅嶆嶇嶈嶉嶊嶋嶌嶍嶎嶏嶐嶑嶒嶓嶔嶕嶖嶗嶘嶚嶛嶜嶞嶟嶠�".split(""); +for(j = 0; j != D[141].length; ++j) if(D[141][j].charCodeAt(0) !== 0xFFFD) { e[D[141][j]] = 36096 + j; d[36096 + j] = D[141][j];} +D[142] = "����������������������������������������������������������������嶡嶢嶣嶤嶥嶦嶧嶨嶩嶪嶫嶬嶭嶮嶯嶰嶱嶲嶳嶴嶵嶶嶸嶹嶺嶻嶼嶽嶾嶿巀巁巂巃巄巆巇巈巉巊巋巌巎巏巐巑巒巓巔巕巖巗巘巙巚巜巟巠巣巤巪巬巭�巰巵巶巸巹巺巻巼巿帀帄帇帉帊帋帍帎帒帓帗帞帟帠帡帢帣帤帥帨帩帪師帬帯帰帲帳帴帵帶帹帺帾帿幀幁幃幆幇幈幉幊幋幍幎幏幐幑幒幓幖幗幘幙幚幜幝幟幠幣幤幥幦幧幨幩幪幫幬幭幮幯幰幱幵幷幹幾庁庂広庅庈庉庌庍庎庒庘庛庝庡庢庣庤庨庩庪庫庬庮庯庰庱庲庴庺庻庼庽庿廀廁廂廃廄廅�".split(""); +for(j = 0; j != D[142].length; ++j) if(D[142][j].charCodeAt(0) !== 0xFFFD) { e[D[142][j]] = 36352 + j; d[36352 + j] = D[142][j];} +D[143] = "����������������������������������������������������������������廆廇廈廋廌廍廎廏廐廔廕廗廘廙廚廜廝廞廟廠廡廢廣廤廥廦廧廩廫廬廭廮廯廰廱廲廳廵廸廹廻廼廽弅弆弇弉弌弍弎弐弒弔弖弙弚弜弝弞弡弢弣弤�弨弫弬弮弰弲弳弴張弶強弸弻弽弾弿彁彂彃彄彅彆彇彈彉彊彋彌彍彎彏彑彔彙彚彛彜彞彟彠彣彥彧彨彫彮彯彲彴彵彶彸彺彽彾彿徃徆徍徎徏徑従徔徖徚徛徝從徟徠徢徣徤徥徦徧復徫徬徯徰徱徲徳徴徶徸徹徺徻徾徿忀忁忂忇忈忊忋忎忓忔忕忚忛応忞忟忢忣忥忦忨忩忬忯忰忲忳忴忶忷忹忺忼怇�".split(""); +for(j = 0; j != D[143].length; ++j) if(D[143][j].charCodeAt(0) !== 0xFFFD) { e[D[143][j]] = 36608 + j; d[36608 + j] = D[143][j];} +D[144] = "����������������������������������������������������������������怈怉怋怌怐怑怓怗怘怚怞怟怢怣怤怬怭怮怰怱怲怳怴怶怷怸怹怺怽怾恀恄恅恆恇恈恉恊恌恎恏恑恓恔恖恗恘恛恜恞恟恠恡恥恦恮恱恲恴恵恷恾悀�悁悂悅悆悇悈悊悋悎悏悐悑悓悕悗悘悙悜悞悡悢悤悥悧悩悪悮悰悳悵悶悷悹悺悽悾悿惀惁惂惃惄惇惈惉惌惍惎惏惐惒惓惔惖惗惙惛惞惡惢惣惤惥惪惱惲惵惷惸惻惼惽惾惿愂愃愄愅愇愊愋愌愐愑愒愓愔愖愗愘愙愛愜愝愞愡愢愥愨愩愪愬愭愮愯愰愱愲愳愴愵愶愷愸愹愺愻愼愽愾慀慁慂慃慄慅慆�".split(""); +for(j = 0; j != D[144].length; ++j) if(D[144][j].charCodeAt(0) !== 0xFFFD) { e[D[144][j]] = 36864 + j; d[36864 + j] = D[144][j];} +D[145] = "����������������������������������������������������������������慇慉態慍慏慐慒慓慔慖慗慘慙慚慛慜慞慟慠慡慣慤慥慦慩慪慫慬慭慮慯慱慲慳慴慶慸慹慺慻慼慽慾慿憀憁憂憃憄憅憆憇憈憉憊憌憍憏憐憑憒憓憕�憖憗憘憙憚憛憜憞憟憠憡憢憣憤憥憦憪憫憭憮憯憰憱憲憳憴憵憶憸憹憺憻憼憽憿懀懁懃懄懅懆懇應懌懍懎懏懐懓懕懖懗懘懙懚懛懜懝懞懟懠懡懢懣懤懥懧懨懩懪懫懬懭懮懯懰懱懲懳懴懶懷懸懹懺懻懼懽懾戀戁戂戃戄戅戇戉戓戔戙戜戝戞戠戣戦戧戨戩戫戭戯戰戱戲戵戶戸戹戺戻戼扂扄扅扆扊�".split(""); +for(j = 0; j != D[145].length; ++j) if(D[145][j].charCodeAt(0) !== 0xFFFD) { e[D[145][j]] = 37120 + j; d[37120 + j] = D[145][j];} +D[146] = "����������������������������������������������������������������扏扐払扖扗扙扚扜扝扞扟扠扡扢扤扥扨扱扲扴扵扷扸扺扻扽抁抂抃抅抆抇抈抋抌抍抎抏抐抔抙抜抝択抣抦抧抩抪抭抮抯抰抲抳抴抶抷抸抺抾拀拁�拃拋拏拑拕拝拞拠拡拤拪拫拰拲拵拸拹拺拻挀挃挄挅挆挊挋挌挍挏挐挒挓挔挕挗挘挙挜挦挧挩挬挭挮挰挱挳挴挵挶挷挸挻挼挾挿捀捁捄捇捈捊捑捒捓捔捖捗捘捙捚捛捜捝捠捤捥捦捨捪捫捬捯捰捲捳捴捵捸捹捼捽捾捿掁掃掄掅掆掋掍掑掓掔掕掗掙掚掛掜掝掞掟採掤掦掫掯掱掲掵掶掹掻掽掿揀�".split(""); +for(j = 0; j != D[146].length; ++j) if(D[146][j].charCodeAt(0) !== 0xFFFD) { e[D[146][j]] = 37376 + j; d[37376 + j] = D[146][j];} +D[147] = "����������������������������������������������������������������揁揂揃揅揇揈揊揋揌揑揓揔揕揗揘揙揚換揜揝揟揢揤揥揦揧揨揫揬揮揯揰揱揳揵揷揹揺揻揼揾搃搄搆搇搈搉搊損搎搑搒搕搖搗搘搙搚搝搟搢搣搤�搥搧搨搩搫搮搯搰搱搲搳搵搶搷搸搹搻搼搾摀摂摃摉摋摌摍摎摏摐摑摓摕摖摗摙摚摛摜摝摟摠摡摢摣摤摥摦摨摪摫摬摮摯摰摱摲摳摴摵摶摷摻摼摽摾摿撀撁撃撆撈撉撊撋撌撍撎撏撐撓撔撗撘撚撛撜撝撟撠撡撢撣撥撦撧撨撪撫撯撱撲撳撴撶撹撻撽撾撿擁擃擄擆擇擈擉擊擋擌擏擑擓擔擕擖擙據�".split(""); +for(j = 0; j != D[147].length; ++j) if(D[147][j].charCodeAt(0) !== 0xFFFD) { e[D[147][j]] = 37632 + j; d[37632 + j] = D[147][j];} +D[148] = "����������������������������������������������������������������擛擜擝擟擠擡擣擥擧擨擩擪擫擬擭擮擯擰擱擲擳擴擵擶擷擸擹擺擻擼擽擾擿攁攂攃攄攅攆攇攈攊攋攌攍攎攏攐攑攓攔攕攖攗攙攚攛攜攝攞攟攠攡�攢攣攤攦攧攨攩攪攬攭攰攱攲攳攷攺攼攽敀敁敂敃敄敆敇敊敋敍敎敐敒敓敔敗敘敚敜敟敠敡敤敥敧敨敩敪敭敮敯敱敳敵敶數敹敺敻敼敽敾敿斀斁斂斃斄斅斆斈斉斊斍斎斏斒斔斕斖斘斚斝斞斠斢斣斦斨斪斬斮斱斲斳斴斵斶斷斸斺斻斾斿旀旂旇旈旉旊旍旐旑旓旔旕旘旙旚旛旜旝旞旟旡旣旤旪旫�".split(""); +for(j = 0; j != D[148].length; ++j) if(D[148][j].charCodeAt(0) !== 0xFFFD) { e[D[148][j]] = 37888 + j; d[37888 + j] = D[148][j];} +D[149] = "����������������������������������������������������������������旲旳旴旵旸旹旻旼旽旾旿昁昄昅昇昈昉昋昍昐昑昒昖昗昘昚昛昜昞昡昢昣昤昦昩昪昫昬昮昰昲昳昷昸昹昺昻昽昿晀時晄晅晆晇晈晉晊晍晎晐晑晘�晙晛晜晝晞晠晢晣晥晧晩晪晫晬晭晱晲晳晵晸晹晻晼晽晿暀暁暃暅暆暈暉暊暋暍暎暏暐暒暓暔暕暘暙暚暛暜暞暟暠暡暢暣暤暥暦暩暪暫暬暭暯暰暱暲暳暵暶暷暸暺暻暼暽暿曀曁曂曃曄曅曆曇曈曉曊曋曌曍曎曏曐曑曒曓曔曕曖曗曘曚曞曟曠曡曢曣曤曥曧曨曪曫曬曭曮曯曱曵曶書曺曻曽朁朂會�".split(""); +for(j = 0; j != D[149].length; ++j) if(D[149][j].charCodeAt(0) !== 0xFFFD) { e[D[149][j]] = 38144 + j; d[38144 + j] = D[149][j];} +D[150] = "����������������������������������������������������������������朄朅朆朇朌朎朏朑朒朓朖朘朙朚朜朞朠朡朢朣朤朥朧朩朮朰朲朳朶朷朸朹朻朼朾朿杁杄杅杇杊杋杍杒杔杕杗杘杙杚杛杝杢杣杤杦杧杫杬杮東杴杶�杸杹杺杻杽枀枂枃枅枆枈枊枌枍枎枏枑枒枓枔枖枙枛枟枠枡枤枦枩枬枮枱枲枴枹枺枻枼枽枾枿柀柂柅柆柇柈柉柊柋柌柍柎柕柖柗柛柟柡柣柤柦柧柨柪柫柭柮柲柵柶柷柸柹柺査柼柾栁栂栃栄栆栍栐栒栔栕栘栙栚栛栜栞栟栠栢栣栤栥栦栧栨栫栬栭栮栯栰栱栴栵栶栺栻栿桇桋桍桏桒桖桗桘桙桚桛�".split(""); +for(j = 0; j != D[150].length; ++j) if(D[150][j].charCodeAt(0) !== 0xFFFD) { e[D[150][j]] = 38400 + j; d[38400 + j] = D[150][j];} +D[151] = "����������������������������������������������������������������桜桝桞桟桪桬桭桮桯桰桱桲桳桵桸桹桺桻桼桽桾桿梀梂梄梇梈梉梊梋梌梍梎梐梑梒梔梕梖梘梙梚梛梜條梞梟梠梡梣梤梥梩梪梫梬梮梱梲梴梶梷梸�梹梺梻梼梽梾梿棁棃棄棅棆棇棈棊棌棎棏棐棑棓棔棖棗棙棛棜棝棞棟棡棢棤棥棦棧棨棩棪棫棬棭棯棲棳棴棶棷棸棻棽棾棿椀椂椃椄椆椇椈椉椊椌椏椑椓椔椕椖椗椘椙椚椛検椝椞椡椢椣椥椦椧椨椩椪椫椬椮椯椱椲椳椵椶椷椸椺椻椼椾楀楁楃楄楅楆楇楈楉楊楋楌楍楎楏楐楑楒楓楕楖楘楙楛楜楟�".split(""); +for(j = 0; j != D[151].length; ++j) if(D[151][j].charCodeAt(0) !== 0xFFFD) { e[D[151][j]] = 38656 + j; d[38656 + j] = D[151][j];} +D[152] = "����������������������������������������������������������������楡楢楤楥楧楨楩楪楬業楯楰楲楳楴極楶楺楻楽楾楿榁榃榅榊榋榌榎榏榐榑榒榓榖榗榙榚榝榞榟榠榡榢榣榤榥榦榩榪榬榮榯榰榲榳榵榶榸榹榺榼榽�榾榿槀槂槃槄槅槆槇槈槉構槍槏槑槒槓槕槖槗様槙槚槜槝槞槡槢槣槤槥槦槧槨槩槪槫槬槮槯槰槱槳槴槵槶槷槸槹槺槻槼槾樀樁樂樃樄樅樆樇樈樉樋樌樍樎樏樐樑樒樓樔樕樖標樚樛樜樝樞樠樢樣樤樥樦樧権樫樬樭樮樰樲樳樴樶樷樸樹樺樻樼樿橀橁橂橃橅橆橈橉橊橋橌橍橎橏橑橒橓橔橕橖橗橚�".split(""); +for(j = 0; j != D[152].length; ++j) if(D[152][j].charCodeAt(0) !== 0xFFFD) { e[D[152][j]] = 38912 + j; d[38912 + j] = D[152][j];} +D[153] = "����������������������������������������������������������������橜橝橞機橠橢橣橤橦橧橨橩橪橫橬橭橮橯橰橲橳橴橵橶橷橸橺橻橽橾橿檁檂檃檅檆檇檈檉檊檋檌檍檏檒檓檔檕檖檘檙檚檛檜檝檞檟檡檢檣檤檥檦�檧檨檪檭檮檯檰檱檲檳檴檵檶檷檸檹檺檻檼檽檾檿櫀櫁櫂櫃櫄櫅櫆櫇櫈櫉櫊櫋櫌櫍櫎櫏櫐櫑櫒櫓櫔櫕櫖櫗櫘櫙櫚櫛櫜櫝櫞櫟櫠櫡櫢櫣櫤櫥櫦櫧櫨櫩櫪櫫櫬櫭櫮櫯櫰櫱櫲櫳櫴櫵櫶櫷櫸櫹櫺櫻櫼櫽櫾櫿欀欁欂欃欄欅欆欇欈欉權欋欌欍欎欏欐欑欒欓欔欕欖欗欘欙欚欛欜欝欞欟欥欦欨欩欪欫欬欭欮�".split(""); +for(j = 0; j != D[153].length; ++j) if(D[153][j].charCodeAt(0) !== 0xFFFD) { e[D[153][j]] = 39168 + j; d[39168 + j] = D[153][j];} +D[154] = "����������������������������������������������������������������欯欰欱欳欴欵欶欸欻欼欽欿歀歁歂歄歅歈歊歋歍歎歏歐歑歒歓歔歕歖歗歘歚歛歜歝歞歟歠歡歨歩歫歬歭歮歯歰歱歲歳歴歵歶歷歸歺歽歾歿殀殅殈�殌殎殏殐殑殔殕殗殘殙殜殝殞殟殠殢殣殤殥殦殧殨殩殫殬殭殮殯殰殱殲殶殸殹殺殻殼殽殾毀毃毄毆毇毈毉毊毌毎毐毑毘毚毜毝毞毟毠毢毣毤毥毦毧毨毩毬毭毮毰毱毲毴毶毷毸毺毻毼毾毿氀氁氂氃氄氈氉氊氋氌氎氒気氜氝氞氠氣氥氫氬氭氱氳氶氷氹氺氻氼氾氿汃汄汅汈汋汌汍汎汏汑汒汓汖汘�".split(""); +for(j = 0; j != D[154].length; ++j) if(D[154][j].charCodeAt(0) !== 0xFFFD) { e[D[154][j]] = 39424 + j; d[39424 + j] = D[154][j];} +D[155] = "����������������������������������������������������������������汙汚汢汣汥汦汧汫汬汭汮汯汱汳汵汷汸決汻汼汿沀沄沇沊沋沍沎沑沒沕沖沗沘沚沜沝沞沠沢沨沬沯沰沴沵沶沷沺泀況泂泃泆泇泈泋泍泎泏泑泒泘�泙泚泜泝泟泤泦泧泩泬泭泲泴泹泿洀洂洃洅洆洈洉洊洍洏洐洑洓洔洕洖洘洜洝洟洠洡洢洣洤洦洨洩洬洭洯洰洴洶洷洸洺洿浀浂浄浉浌浐浕浖浗浘浛浝浟浡浢浤浥浧浨浫浬浭浰浱浲浳浵浶浹浺浻浽浾浿涀涁涃涄涆涇涊涋涍涏涐涒涖涗涘涙涚涜涢涥涬涭涰涱涳涴涶涷涹涺涻涼涽涾淁淂淃淈淉淊�".split(""); +for(j = 0; j != D[155].length; ++j) if(D[155][j].charCodeAt(0) !== 0xFFFD) { e[D[155][j]] = 39680 + j; d[39680 + j] = D[155][j];} +D[156] = "����������������������������������������������������������������淍淎淏淐淒淓淔淕淗淚淛淜淟淢淣淥淧淨淩淪淭淯淰淲淴淵淶淸淺淽淾淿渀渁渂渃渄渆渇済渉渋渏渒渓渕渘渙減渜渞渟渢渦渧渨渪測渮渰渱渳渵�渶渷渹渻渼渽渾渿湀湁湂湅湆湇湈湉湊湋湌湏湐湑湒湕湗湙湚湜湝湞湠湡湢湣湤湥湦湧湨湩湪湬湭湯湰湱湲湳湴湵湶湷湸湹湺湻湼湽満溁溂溄溇溈溊溋溌溍溎溑溒溓溔溕準溗溙溚溛溝溞溠溡溣溤溦溨溩溫溬溭溮溰溳溵溸溹溼溾溿滀滃滄滅滆滈滉滊滌滍滎滐滒滖滘滙滛滜滝滣滧滪滫滬滭滮滯�".split(""); +for(j = 0; j != D[156].length; ++j) if(D[156][j].charCodeAt(0) !== 0xFFFD) { e[D[156][j]] = 39936 + j; d[39936 + j] = D[156][j];} +D[157] = "����������������������������������������������������������������滰滱滲滳滵滶滷滸滺滻滼滽滾滿漀漁漃漄漅漇漈漊漋漌漍漎漐漑漒漖漗漘漙漚漛漜漝漞漟漡漢漣漥漦漧漨漬漮漰漲漴漵漷漸漹漺漻漼漽漿潀潁潂�潃潄潅潈潉潊潌潎潏潐潑潒潓潔潕潖潗潙潚潛潝潟潠潡潣潤潥潧潨潩潪潫潬潯潰潱潳潵潶潷潹潻潽潾潿澀澁澂澃澅澆澇澊澋澏澐澑澒澓澔澕澖澗澘澙澚澛澝澞澟澠澢澣澤澥澦澨澩澪澫澬澭澮澯澰澱澲澴澵澷澸澺澻澼澽澾澿濁濃濄濅濆濇濈濊濋濌濍濎濏濐濓濔濕濖濗濘濙濚濛濜濝濟濢濣濤濥�".split(""); +for(j = 0; j != D[157].length; ++j) if(D[157][j].charCodeAt(0) !== 0xFFFD) { e[D[157][j]] = 40192 + j; d[40192 + j] = D[157][j];} +D[158] = "����������������������������������������������������������������濦濧濨濩濪濫濬濭濰濱濲濳濴濵濶濷濸濹濺濻濼濽濾濿瀀瀁瀂瀃瀄瀅瀆瀇瀈瀉瀊瀋瀌瀍瀎瀏瀐瀒瀓瀔瀕瀖瀗瀘瀙瀜瀝瀞瀟瀠瀡瀢瀤瀥瀦瀧瀨瀩瀪�瀫瀬瀭瀮瀯瀰瀱瀲瀳瀴瀶瀷瀸瀺瀻瀼瀽瀾瀿灀灁灂灃灄灅灆灇灈灉灊灋灍灎灐灑灒灓灔灕灖灗灘灙灚灛灜灝灟灠灡灢灣灤灥灦灧灨灩灪灮灱灲灳灴灷灹灺灻災炁炂炃炄炆炇炈炋炌炍炏炐炑炓炗炘炚炛炞炟炠炡炢炣炤炥炦炧炨炩炪炰炲炴炵炶為炾炿烄烅烆烇烉烋烌烍烎烏烐烑烒烓烔烕烖烗烚�".split(""); +for(j = 0; j != D[158].length; ++j) if(D[158][j].charCodeAt(0) !== 0xFFFD) { e[D[158][j]] = 40448 + j; d[40448 + j] = D[158][j];} +D[159] = "����������������������������������������������������������������烜烝烞烠烡烢烣烥烪烮烰烱烲烳烴烵烶烸烺烻烼烾烿焀焁焂焃焄焅焆焇焈焋焌焍焎焏焑焒焔焗焛焜焝焞焟焠無焢焣焤焥焧焨焩焪焫焬焭焮焲焳焴�焵焷焸焹焺焻焼焽焾焿煀煁煂煃煄煆煇煈煉煋煍煏煐煑煒煓煔煕煖煗煘煙煚煛煝煟煠煡煢煣煥煩煪煫煬煭煯煰煱煴煵煶煷煹煻煼煾煿熀熁熂熃熅熆熇熈熉熋熌熍熎熐熑熒熓熕熖熗熚熛熜熝熞熡熢熣熤熥熦熧熩熪熫熭熮熯熰熱熲熴熶熷熸熺熻熼熽熾熿燀燁燂燄燅燆燇燈燉燊燋燌燍燏燐燑燒燓�".split(""); +for(j = 0; j != D[159].length; ++j) if(D[159][j].charCodeAt(0) !== 0xFFFD) { e[D[159][j]] = 40704 + j; d[40704 + j] = D[159][j];} +D[160] = "����������������������������������������������������������������燖燗燘燙燚燛燜燝燞營燡燢燣燤燦燨燩燪燫燬燭燯燰燱燲燳燴燵燶燷燸燺燻燼燽燾燿爀爁爂爃爄爅爇爈爉爊爋爌爍爎爏爐爑爒爓爔爕爖爗爘爙爚�爛爜爞爟爠爡爢爣爤爥爦爧爩爫爭爮爯爲爳爴爺爼爾牀牁牂牃牄牅牆牉牊牋牎牏牐牑牓牔牕牗牘牚牜牞牠牣牤牥牨牪牫牬牭牰牱牳牴牶牷牸牻牼牽犂犃犅犆犇犈犉犌犎犐犑犓犔犕犖犗犘犙犚犛犜犝犞犠犡犢犣犤犥犦犧犨犩犪犫犮犱犲犳犵犺犻犼犽犾犿狀狅狆狇狉狊狋狌狏狑狓狔狕狖狘狚狛�".split(""); +for(j = 0; j != D[160].length; ++j) if(D[160][j].charCodeAt(0) !== 0xFFFD) { e[D[160][j]] = 40960 + j; d[40960 + j] = D[160][j];} +D[161] = "����������������������������������������������������������������������������������������������������������������������������������������������������������������� 、。·ˉˇ¨〃々—~‖…‘’“”〔〕〈〉《》「」『』〖〗【】±×÷∶∧∨∑∏∪∩∈∷√⊥∥∠⌒⊙∫∮≡≌≈∽∝≠≮≯≤≥∞∵∴♂♀°′″℃$¤¢£‰§№☆★○●◎◇◆□■△▲※→←↑↓〓�".split(""); +for(j = 0; j != D[161].length; ++j) if(D[161][j].charCodeAt(0) !== 0xFFFD) { e[D[161][j]] = 41216 + j; d[41216 + j] = D[161][j];} +D[162] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹ������⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇①②③④⑤⑥⑦⑧⑨⑩��㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩��ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ���".split(""); +for(j = 0; j != D[162].length; ++j) if(D[162][j].charCodeAt(0) !== 0xFFFD) { e[D[162][j]] = 41472 + j; d[41472 + j] = D[162][j];} +D[163] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������!"#¥%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|} ̄�".split(""); +for(j = 0; j != D[163].length; ++j) if(D[163][j].charCodeAt(0) !== 0xFFFD) { e[D[163][j]] = 41728 + j; d[41728 + j] = D[163][j];} +D[164] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをん������������".split(""); +for(j = 0; j != D[164].length; ++j) if(D[164][j].charCodeAt(0) !== 0xFFFD) { e[D[164][j]] = 41984 + j; d[41984 + j] = D[164][j];} +D[165] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶ���������".split(""); +for(j = 0; j != D[165].length; ++j) if(D[165][j].charCodeAt(0) !== 0xFFFD) { e[D[165][j]] = 42240 + j; d[42240 + j] = D[165][j];} +D[166] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ��������αβγδεζηθικλμνξοπρστυφχψω�������︵︶︹︺︿﹀︽︾﹁﹂﹃﹄��︻︼︷︸︱�︳︴����������".split(""); +for(j = 0; j != D[166].length; ++j) if(D[166][j].charCodeAt(0) !== 0xFFFD) { e[D[166][j]] = 42496 + j; d[42496 + j] = D[166][j];} +D[167] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ���������������абвгдеёжзийклмнопрстуфхцчшщъыьэюя��������������".split(""); +for(j = 0; j != D[167].length; ++j) if(D[167][j].charCodeAt(0) !== 0xFFFD) { e[D[167][j]] = 42752 + j; d[42752 + j] = D[167][j];} +D[168] = "����������������������������������������������������������������ˊˋ˙–―‥‵℅℉↖↗↘↙∕∟∣≒≦≧⊿═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫╬╭╮╯╰╱╲╳▁▂▃▄▅▆▇�█▉▊▋▌▍▎▏▓▔▕▼▽◢◣◤◥☉⊕〒〝〞�����������āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜüêɑ�ńň�ɡ����ㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩ����������������������".split(""); +for(j = 0; j != D[168].length; ++j) if(D[168][j].charCodeAt(0) !== 0xFFFD) { e[D[168][j]] = 43008 + j; d[43008 + j] = D[168][j];} +D[169] = "����������������������������������������������������������������〡〢〣〤〥〦〧〨〩㊣㎎㎏㎜㎝㎞㎡㏄㏎㏑㏒㏕︰¬¦�℡㈱�‐���ー゛゜ヽヾ〆ゝゞ﹉﹊﹋﹌﹍﹎﹏﹐﹑﹒﹔﹕﹖﹗﹙﹚﹛﹜﹝﹞﹟﹠﹡�﹢﹣﹤﹥﹦﹨﹩﹪﹫�������������〇�������������─━│┃┄┅┆┇┈┉┊┋┌┍┎┏┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋����������������".split(""); +for(j = 0; j != D[169].length; ++j) if(D[169][j].charCodeAt(0) !== 0xFFFD) { e[D[169][j]] = 43264 + j; d[43264 + j] = D[169][j];} +D[170] = "����������������������������������������������������������������狜狝狟狢狣狤狥狦狧狪狫狵狶狹狽狾狿猀猂猄猅猆猇猈猉猋猌猍猏猐猑猒猔猘猙猚猟猠猣猤猦猧猨猭猯猰猲猳猵猶猺猻猼猽獀獁獂獃獄獅獆獇獈�獉獊獋獌獎獏獑獓獔獕獖獘獙獚獛獜獝獞獟獡獢獣獤獥獦獧獨獩獪獫獮獰獱�����������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[170].length; ++j) if(D[170][j].charCodeAt(0) !== 0xFFFD) { e[D[170][j]] = 43520 + j; d[43520 + j] = D[170][j];} +D[171] = "����������������������������������������������������������������獲獳獴獵獶獷獸獹獺獻獼獽獿玀玁玂玃玅玆玈玊玌玍玏玐玒玓玔玕玗玘玙玚玜玝玞玠玡玣玤玥玦玧玨玪玬玭玱玴玵玶玸玹玼玽玾玿珁珃珄珅珆珇�珋珌珎珒珓珔珕珖珗珘珚珛珜珝珟珡珢珣珤珦珨珪珫珬珮珯珰珱珳珴珵珶珷�����������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[171].length; ++j) if(D[171][j].charCodeAt(0) !== 0xFFFD) { e[D[171][j]] = 43776 + j; d[43776 + j] = D[171][j];} +D[172] = "����������������������������������������������������������������珸珹珺珻珼珽現珿琀琁琂琄琇琈琋琌琍琎琑琒琓琔琕琖琗琘琙琜琝琞琟琠琡琣琤琧琩琫琭琯琱琲琷琸琹琺琻琽琾琿瑀瑂瑃瑄瑅瑆瑇瑈瑉瑊瑋瑌瑍�瑎瑏瑐瑑瑒瑓瑔瑖瑘瑝瑠瑡瑢瑣瑤瑥瑦瑧瑨瑩瑪瑫瑬瑮瑯瑱瑲瑳瑴瑵瑸瑹瑺�����������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[172].length; ++j) if(D[172][j].charCodeAt(0) !== 0xFFFD) { e[D[172][j]] = 44032 + j; d[44032 + j] = D[172][j];} +D[173] = "����������������������������������������������������������������瑻瑼瑽瑿璂璄璅璆璈璉璊璌璍璏璑璒璓璔璕璖璗璘璙璚璛璝璟璠璡璢璣璤璥璦璪璫璬璭璮璯環璱璲璳璴璵璶璷璸璹璻璼璽璾璿瓀瓁瓂瓃瓄瓅瓆瓇�瓈瓉瓊瓋瓌瓍瓎瓏瓐瓑瓓瓔瓕瓖瓗瓘瓙瓚瓛瓝瓟瓡瓥瓧瓨瓩瓪瓫瓬瓭瓰瓱瓲�����������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[173].length; ++j) if(D[173][j].charCodeAt(0) !== 0xFFFD) { e[D[173][j]] = 44288 + j; d[44288 + j] = D[173][j];} +D[174] = "����������������������������������������������������������������瓳瓵瓸瓹瓺瓻瓼瓽瓾甀甁甂甃甅甆甇甈甉甊甋甌甎甐甒甔甕甖甗甛甝甞甠甡產産甤甦甧甪甮甴甶甹甼甽甿畁畂畃畄畆畇畉畊畍畐畑畒畓畕畖畗畘�畝畞畟畠畡畢畣畤畧畨畩畫畬畭畮畯異畱畳畵當畷畺畻畼畽畾疀疁疂疄疅疇�����������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[174].length; ++j) if(D[174][j].charCodeAt(0) !== 0xFFFD) { e[D[174][j]] = 44544 + j; d[44544 + j] = D[174][j];} +D[175] = "����������������������������������������������������������������疈疉疊疌疍疎疐疓疕疘疛疜疞疢疦疧疨疩疪疭疶疷疺疻疿痀痁痆痋痌痎痏痐痑痓痗痙痚痜痝痟痠痡痥痩痬痭痮痯痲痳痵痶痷痸痺痻痽痾瘂瘄瘆瘇�瘈瘉瘋瘍瘎瘏瘑瘒瘓瘔瘖瘚瘜瘝瘞瘡瘣瘧瘨瘬瘮瘯瘱瘲瘶瘷瘹瘺瘻瘽癁療癄�����������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[175].length; ++j) if(D[175][j].charCodeAt(0) !== 0xFFFD) { e[D[175][j]] = 44800 + j; d[44800 + j] = D[175][j];} +D[176] = "����������������������������������������������������������������癅癆癇癈癉癊癋癎癏癐癑癒癓癕癗癘癙癚癛癝癟癠癡癢癤癥癦癧癨癩癪癬癭癮癰癱癲癳癴癵癶癷癹発發癿皀皁皃皅皉皊皌皍皏皐皒皔皕皗皘皚皛�皜皝皞皟皠皡皢皣皥皦皧皨皩皪皫皬皭皯皰皳皵皶皷皸皹皺皻皼皽皾盀盁盃啊阿埃挨哎唉哀皑癌蔼矮艾碍爱隘鞍氨安俺按暗岸胺案肮昂盎凹敖熬翱袄傲奥懊澳芭捌扒叭吧笆八疤巴拔跋靶把耙坝霸罢爸白柏百摆佰败拜稗斑班搬扳般颁板版扮拌伴瓣半办绊邦帮梆榜膀绑棒磅蚌镑傍谤苞胞包褒剥�".split(""); +for(j = 0; j != D[176].length; ++j) if(D[176][j].charCodeAt(0) !== 0xFFFD) { e[D[176][j]] = 45056 + j; d[45056 + j] = D[176][j];} +D[177] = "����������������������������������������������������������������盄盇盉盋盌盓盕盙盚盜盝盞盠盡盢監盤盦盧盨盩盪盫盬盭盰盳盵盶盷盺盻盽盿眀眂眃眅眆眊県眎眏眐眑眒眓眔眕眖眗眘眛眜眝眞眡眣眤眥眧眪眫�眬眮眰眱眲眳眴眹眻眽眾眿睂睄睅睆睈睉睊睋睌睍睎睏睒睓睔睕睖睗睘睙睜薄雹保堡饱宝抱报暴豹鲍爆杯碑悲卑北辈背贝钡倍狈备惫焙被奔苯本笨崩绷甭泵蹦迸逼鼻比鄙笔彼碧蓖蔽毕毙毖币庇痹闭敝弊必辟壁臂避陛鞭边编贬扁便变卞辨辩辫遍标彪膘表鳖憋别瘪彬斌濒滨宾摈兵冰柄丙秉饼炳�".split(""); +for(j = 0; j != D[177].length; ++j) if(D[177][j].charCodeAt(0) !== 0xFFFD) { e[D[177][j]] = 45312 + j; d[45312 + j] = D[177][j];} +D[178] = "����������������������������������������������������������������睝睞睟睠睤睧睩睪睭睮睯睰睱睲睳睴睵睶睷睸睺睻睼瞁瞂瞃瞆瞇瞈瞉瞊瞋瞏瞐瞓瞔瞕瞖瞗瞘瞙瞚瞛瞜瞝瞞瞡瞣瞤瞦瞨瞫瞭瞮瞯瞱瞲瞴瞶瞷瞸瞹瞺�瞼瞾矀矁矂矃矄矅矆矇矈矉矊矋矌矎矏矐矑矒矓矔矕矖矘矙矚矝矞矟矠矡矤病并玻菠播拨钵波博勃搏铂箔伯帛舶脖膊渤泊驳捕卜哺补埠不布步簿部怖擦猜裁材才财睬踩采彩菜蔡餐参蚕残惭惨灿苍舱仓沧藏操糙槽曹草厕策侧册测层蹭插叉茬茶查碴搽察岔差诧拆柴豺搀掺蝉馋谗缠铲产阐颤昌猖�".split(""); +for(j = 0; j != D[178].length; ++j) if(D[178][j].charCodeAt(0) !== 0xFFFD) { e[D[178][j]] = 45568 + j; d[45568 + j] = D[178][j];} +D[179] = "����������������������������������������������������������������矦矨矪矯矰矱矲矴矵矷矹矺矻矼砃砄砅砆砇砈砊砋砎砏砐砓砕砙砛砞砠砡砢砤砨砪砫砮砯砱砲砳砵砶砽砿硁硂硃硄硆硈硉硊硋硍硏硑硓硔硘硙硚�硛硜硞硟硠硡硢硣硤硥硦硧硨硩硯硰硱硲硳硴硵硶硸硹硺硻硽硾硿碀碁碂碃场尝常长偿肠厂敞畅唱倡超抄钞朝嘲潮巢吵炒车扯撤掣彻澈郴臣辰尘晨忱沉陈趁衬撑称城橙成呈乘程惩澄诚承逞骋秤吃痴持匙池迟弛驰耻齿侈尺赤翅斥炽充冲虫崇宠抽酬畴踌稠愁筹仇绸瞅丑臭初出橱厨躇锄雏滁除楚�".split(""); +for(j = 0; j != D[179].length; ++j) if(D[179][j].charCodeAt(0) !== 0xFFFD) { e[D[179][j]] = 45824 + j; d[45824 + j] = D[179][j];} +D[180] = "����������������������������������������������������������������碄碅碆碈碊碋碏碐碒碔碕碖碙碝碞碠碢碤碦碨碩碪碫碬碭碮碯碵碶碷碸確碻碼碽碿磀磂磃磄磆磇磈磌磍磎磏磑磒磓磖磗磘磚磛磜磝磞磟磠磡磢磣�磤磥磦磧磩磪磫磭磮磯磰磱磳磵磶磸磹磻磼磽磾磿礀礂礃礄礆礇礈礉礊礋礌础储矗搐触处揣川穿椽传船喘串疮窗幢床闯创吹炊捶锤垂春椿醇唇淳纯蠢戳绰疵茨磁雌辞慈瓷词此刺赐次聪葱囱匆从丛凑粗醋簇促蹿篡窜摧崔催脆瘁粹淬翠村存寸磋撮搓措挫错搭达答瘩打大呆歹傣戴带殆代贷袋待逮�".split(""); +for(j = 0; j != D[180].length; ++j) if(D[180][j].charCodeAt(0) !== 0xFFFD) { e[D[180][j]] = 46080 + j; d[46080 + j] = D[180][j];} +D[181] = "����������������������������������������������������������������礍礎礏礐礑礒礔礕礖礗礘礙礚礛礜礝礟礠礡礢礣礥礦礧礨礩礪礫礬礭礮礯礰礱礲礳礵礶礷礸礹礽礿祂祃祄祅祇祊祋祌祍祎祏祐祑祒祔祕祘祙祡祣�祤祦祩祪祫祬祮祰祱祲祳祴祵祶祹祻祼祽祾祿禂禃禆禇禈禉禋禌禍禎禐禑禒怠耽担丹单郸掸胆旦氮但惮淡诞弹蛋当挡党荡档刀捣蹈倒岛祷导到稻悼道盗德得的蹬灯登等瞪凳邓堤低滴迪敌笛狄涤翟嫡抵底地蒂第帝弟递缔颠掂滇碘点典靛垫电佃甸店惦奠淀殿碉叼雕凋刁掉吊钓调跌爹碟蝶迭谍叠�".split(""); +for(j = 0; j != D[181].length; ++j) if(D[181][j].charCodeAt(0) !== 0xFFFD) { e[D[181][j]] = 46336 + j; d[46336 + j] = D[181][j];} +D[182] = "����������������������������������������������������������������禓禔禕禖禗禘禙禛禜禝禞禟禠禡禢禣禤禥禦禨禩禪禫禬禭禮禯禰禱禲禴禵禶禷禸禼禿秂秄秅秇秈秊秌秎秏秐秓秔秖秗秙秚秛秜秝秞秠秡秢秥秨秪�秬秮秱秲秳秴秵秶秷秹秺秼秾秿稁稄稅稇稈稉稊稌稏稐稑稒稓稕稖稘稙稛稜丁盯叮钉顶鼎锭定订丢东冬董懂动栋侗恫冻洞兜抖斗陡豆逗痘都督毒犊独读堵睹赌杜镀肚度渡妒端短锻段断缎堆兑队对墩吨蹲敦顿囤钝盾遁掇哆多夺垛躲朵跺舵剁惰堕蛾峨鹅俄额讹娥恶厄扼遏鄂饿恩而儿耳尔饵洱二�".split(""); +for(j = 0; j != D[182].length; ++j) if(D[182][j].charCodeAt(0) !== 0xFFFD) { e[D[182][j]] = 46592 + j; d[46592 + j] = D[182][j];} +D[183] = "����������������������������������������������������������������稝稟稡稢稤稥稦稧稨稩稪稫稬稭種稯稰稱稲稴稵稶稸稺稾穀穁穂穃穄穅穇穈穉穊穋穌積穎穏穐穒穓穔穕穖穘穙穚穛穜穝穞穟穠穡穢穣穤穥穦穧穨�穩穪穫穬穭穮穯穱穲穳穵穻穼穽穾窂窅窇窉窊窋窌窎窏窐窓窔窙窚窛窞窡窢贰发罚筏伐乏阀法珐藩帆番翻樊矾钒繁凡烦反返范贩犯饭泛坊芳方肪房防妨仿访纺放菲非啡飞肥匪诽吠肺废沸费芬酚吩氛分纷坟焚汾粉奋份忿愤粪丰封枫蜂峰锋风疯烽逢冯缝讽奉凤佛否夫敷肤孵扶拂辐幅氟符伏俘服�".split(""); +for(j = 0; j != D[183].length; ++j) if(D[183][j].charCodeAt(0) !== 0xFFFD) { e[D[183][j]] = 46848 + j; d[46848 + j] = D[183][j];} +D[184] = "����������������������������������������������������������������窣窤窧窩窪窫窮窯窰窱窲窴窵窶窷窸窹窺窻窼窽窾竀竁竂竃竄竅竆竇竈竉竊竌竍竎竏竐竑竒竓竔竕竗竘竚竛竜竝竡竢竤竧竨竩竪竫竬竮竰竱竲竳�竴竵競竷竸竻竼竾笀笁笂笅笇笉笌笍笎笐笒笓笖笗笘笚笜笝笟笡笢笣笧笩笭浮涪福袱弗甫抚辅俯釜斧脯腑府腐赴副覆赋复傅付阜父腹负富讣附妇缚咐噶嘎该改概钙盖溉干甘杆柑竿肝赶感秆敢赣冈刚钢缸肛纲岗港杠篙皋高膏羔糕搞镐稿告哥歌搁戈鸽胳疙割革葛格蛤阁隔铬个各给根跟耕更庚羹�".split(""); +for(j = 0; j != D[184].length; ++j) if(D[184][j].charCodeAt(0) !== 0xFFFD) { e[D[184][j]] = 47104 + j; d[47104 + j] = D[184][j];} +D[185] = "����������������������������������������������������������������笯笰笲笴笵笶笷笹笻笽笿筀筁筂筃筄筆筈筊筍筎筓筕筗筙筜筞筟筡筣筤筥筦筧筨筩筪筫筬筭筯筰筳筴筶筸筺筼筽筿箁箂箃箄箆箇箈箉箊箋箌箎箏�箑箒箓箖箘箙箚箛箞箟箠箣箤箥箮箯箰箲箳箵箶箷箹箺箻箼箽箾箿節篂篃範埂耿梗工攻功恭龚供躬公宫弓巩汞拱贡共钩勾沟苟狗垢构购够辜菇咕箍估沽孤姑鼓古蛊骨谷股故顾固雇刮瓜剐寡挂褂乖拐怪棺关官冠观管馆罐惯灌贯光广逛瑰规圭硅归龟闺轨鬼诡癸桂柜跪贵刽辊滚棍锅郭国果裹过哈�".split(""); +for(j = 0; j != D[185].length; ++j) if(D[185][j].charCodeAt(0) !== 0xFFFD) { e[D[185][j]] = 47360 + j; d[47360 + j] = D[185][j];} +D[186] = "����������������������������������������������������������������篅篈築篊篋篍篎篏篐篒篔篕篖篗篘篛篜篞篟篠篢篣篤篧篨篩篫篬篭篯篰篲篳篴篵篶篸篹篺篻篽篿簀簁簂簃簄簅簆簈簉簊簍簎簐簑簒簓簔簕簗簘簙�簚簛簜簝簞簠簡簢簣簤簥簨簩簫簬簭簮簯簰簱簲簳簴簵簶簷簹簺簻簼簽簾籂骸孩海氦亥害骇酣憨邯韩含涵寒函喊罕翰撼捍旱憾悍焊汗汉夯杭航壕嚎豪毫郝好耗号浩呵喝荷菏核禾和何合盒貉阂河涸赫褐鹤贺嘿黑痕很狠恨哼亨横衡恒轰哄烘虹鸿洪宏弘红喉侯猴吼厚候后呼乎忽瑚壶葫胡蝴狐糊湖�".split(""); +for(j = 0; j != D[186].length; ++j) if(D[186][j].charCodeAt(0) !== 0xFFFD) { e[D[186][j]] = 47616 + j; d[47616 + j] = D[186][j];} +D[187] = "����������������������������������������������������������������籃籄籅籆籇籈籉籊籋籌籎籏籐籑籒籓籔籕籖籗籘籙籚籛籜籝籞籟籠籡籢籣籤籥籦籧籨籩籪籫籬籭籮籯籰籱籲籵籶籷籸籹籺籾籿粀粁粂粃粄粅粆粇�粈粊粋粌粍粎粏粐粓粔粖粙粚粛粠粡粣粦粧粨粩粫粬粭粯粰粴粵粶粷粸粺粻弧虎唬护互沪户花哗华猾滑画划化话槐徊怀淮坏欢环桓还缓换患唤痪豢焕涣宦幻荒慌黄磺蝗簧皇凰惶煌晃幌恍谎灰挥辉徽恢蛔回毁悔慧卉惠晦贿秽会烩汇讳诲绘荤昏婚魂浑混豁活伙火获或惑霍货祸击圾基机畸稽积箕�".split(""); +for(j = 0; j != D[187].length; ++j) if(D[187][j].charCodeAt(0) !== 0xFFFD) { e[D[187][j]] = 47872 + j; d[47872 + j] = D[187][j];} +D[188] = "����������������������������������������������������������������粿糀糂糃糄糆糉糋糎糏糐糑糒糓糔糘糚糛糝糞糡糢糣糤糥糦糧糩糪糫糬糭糮糰糱糲糳糴糵糶糷糹糺糼糽糾糿紀紁紂紃約紅紆紇紈紉紋紌納紎紏紐�紑紒紓純紕紖紗紘紙級紛紜紝紞紟紡紣紤紥紦紨紩紪紬紭紮細紱紲紳紴紵紶肌饥迹激讥鸡姬绩缉吉极棘辑籍集及急疾汲即嫉级挤几脊己蓟技冀季伎祭剂悸济寄寂计记既忌际妓继纪嘉枷夹佳家加荚颊贾甲钾假稼价架驾嫁歼监坚尖笺间煎兼肩艰奸缄茧检柬碱硷拣捡简俭剪减荐槛鉴践贱见键箭件�".split(""); +for(j = 0; j != D[188].length; ++j) if(D[188][j].charCodeAt(0) !== 0xFFFD) { e[D[188][j]] = 48128 + j; d[48128 + j] = D[188][j];} +D[189] = "����������������������������������������������������������������紷紸紹紺紻紼紽紾紿絀絁終絃組絅絆絇絈絉絊絋経絍絎絏結絑絒絓絔絕絖絗絘絙絚絛絜絝絞絟絠絡絢絣絤絥給絧絨絩絪絫絬絭絯絰統絲絳絴絵絶�絸絹絺絻絼絽絾絿綀綁綂綃綄綅綆綇綈綉綊綋綌綍綎綏綐綑綒經綔綕綖綗綘健舰剑饯渐溅涧建僵姜将浆江疆蒋桨奖讲匠酱降蕉椒礁焦胶交郊浇骄娇嚼搅铰矫侥脚狡角饺缴绞剿教酵轿较叫窖揭接皆秸街阶截劫节桔杰捷睫竭洁结解姐戒藉芥界借介疥诫届巾筋斤金今津襟紧锦仅谨进靳晋禁近烬浸�".split(""); +for(j = 0; j != D[189].length; ++j) if(D[189][j].charCodeAt(0) !== 0xFFFD) { e[D[189][j]] = 48384 + j; d[48384 + j] = D[189][j];} +D[190] = "����������������������������������������������������������������継続綛綜綝綞綟綠綡綢綣綤綥綧綨綩綪綫綬維綯綰綱網綳綴綵綶綷綸綹綺綻綼綽綾綿緀緁緂緃緄緅緆緇緈緉緊緋緌緍緎総緐緑緒緓緔緕緖緗緘緙�線緛緜緝緞緟締緡緢緣緤緥緦緧編緩緪緫緬緭緮緯緰緱緲緳練緵緶緷緸緹緺尽劲荆兢茎睛晶鲸京惊精粳经井警景颈静境敬镜径痉靖竟竞净炯窘揪究纠玖韭久灸九酒厩救旧臼舅咎就疚鞠拘狙疽居驹菊局咀矩举沮聚拒据巨具距踞锯俱句惧炬剧捐鹃娟倦眷卷绢撅攫抉掘倔爵觉决诀绝均菌钧军君峻�".split(""); +for(j = 0; j != D[190].length; ++j) if(D[190][j].charCodeAt(0) !== 0xFFFD) { e[D[190][j]] = 48640 + j; d[48640 + j] = D[190][j];} +D[191] = "����������������������������������������������������������������緻緼緽緾緿縀縁縂縃縄縅縆縇縈縉縊縋縌縍縎縏縐縑縒縓縔縕縖縗縘縙縚縛縜縝縞縟縠縡縢縣縤縥縦縧縨縩縪縫縬縭縮縯縰縱縲縳縴縵縶縷縸縹�縺縼總績縿繀繂繃繄繅繆繈繉繊繋繌繍繎繏繐繑繒繓織繕繖繗繘繙繚繛繜繝俊竣浚郡骏喀咖卡咯开揩楷凯慨刊堪勘坎砍看康慷糠扛抗亢炕考拷烤靠坷苛柯棵磕颗科壳咳可渴克刻客课肯啃垦恳坑吭空恐孔控抠口扣寇枯哭窟苦酷库裤夸垮挎跨胯块筷侩快宽款匡筐狂框矿眶旷况亏盔岿窥葵奎魁傀�".split(""); +for(j = 0; j != D[191].length; ++j) if(D[191][j].charCodeAt(0) !== 0xFFFD) { e[D[191][j]] = 48896 + j; d[48896 + j] = D[191][j];} +D[192] = "����������������������������������������������������������������繞繟繠繡繢繣繤繥繦繧繨繩繪繫繬繭繮繯繰繱繲繳繴繵繶繷繸繹繺繻繼繽繾繿纀纁纃纄纅纆纇纈纉纊纋續纍纎纏纐纑纒纓纔纕纖纗纘纙纚纜纝纞�纮纴纻纼绖绤绬绹缊缐缞缷缹缻缼缽缾缿罀罁罃罆罇罈罉罊罋罌罍罎罏罒罓馈愧溃坤昆捆困括扩廓阔垃拉喇蜡腊辣啦莱来赖蓝婪栏拦篮阑兰澜谰揽览懒缆烂滥琅榔狼廊郎朗浪捞劳牢老佬姥酪烙涝勒乐雷镭蕾磊累儡垒擂肋类泪棱楞冷厘梨犁黎篱狸离漓理李里鲤礼莉荔吏栗丽厉励砾历利傈例俐�".split(""); +for(j = 0; j != D[192].length; ++j) if(D[192][j].charCodeAt(0) !== 0xFFFD) { e[D[192][j]] = 49152 + j; d[49152 + j] = D[192][j];} +D[193] = "����������������������������������������������������������������罖罙罛罜罝罞罠罣罤罥罦罧罫罬罭罯罰罳罵罶罷罸罺罻罼罽罿羀羂羃羄羅羆羇羈羉羋羍羏羐羑羒羓羕羖羗羘羙羛羜羠羢羣羥羦羨義羪羫羬羭羮羱�羳羴羵羶羷羺羻羾翀翂翃翄翆翇翈翉翋翍翏翐翑習翓翖翗翙翚翛翜翝翞翢翣痢立粒沥隶力璃哩俩联莲连镰廉怜涟帘敛脸链恋炼练粮凉梁粱良两辆量晾亮谅撩聊僚疗燎寥辽潦了撂镣廖料列裂烈劣猎琳林磷霖临邻鳞淋凛赁吝拎玲菱零龄铃伶羚凌灵陵岭领另令溜琉榴硫馏留刘瘤流柳六龙聋咙笼窿�".split(""); +for(j = 0; j != D[193].length; ++j) if(D[193][j].charCodeAt(0) !== 0xFFFD) { e[D[193][j]] = 49408 + j; d[49408 + j] = D[193][j];} +D[194] = "����������������������������������������������������������������翤翧翨翪翫翬翭翯翲翴翵翶翷翸翹翺翽翾翿耂耇耈耉耊耎耏耑耓耚耛耝耞耟耡耣耤耫耬耭耮耯耰耲耴耹耺耼耾聀聁聄聅聇聈聉聎聏聐聑聓聕聖聗�聙聛聜聝聞聟聠聡聢聣聤聥聦聧聨聫聬聭聮聯聰聲聳聴聵聶職聸聹聺聻聼聽隆垄拢陇楼娄搂篓漏陋芦卢颅庐炉掳卤虏鲁麓碌露路赂鹿潞禄录陆戮驴吕铝侣旅履屡缕虑氯律率滤绿峦挛孪滦卵乱掠略抡轮伦仑沦纶论萝螺罗逻锣箩骡裸落洛骆络妈麻玛码蚂马骂嘛吗埋买麦卖迈脉瞒馒蛮满蔓曼慢漫�".split(""); +for(j = 0; j != D[194].length; ++j) if(D[194][j].charCodeAt(0) !== 0xFFFD) { e[D[194][j]] = 49664 + j; d[49664 + j] = D[194][j];} +D[195] = "����������������������������������������������������������������聾肁肂肅肈肊肍肎肏肐肑肒肔肕肗肙肞肣肦肧肨肬肰肳肵肶肸肹肻胅胇胈胉胊胋胏胐胑胒胓胔胕胘胟胠胢胣胦胮胵胷胹胻胾胿脀脁脃脄脅脇脈脋�脌脕脗脙脛脜脝脟脠脡脢脣脤脥脦脧脨脩脪脫脭脮脰脳脴脵脷脹脺脻脼脽脿谩芒茫盲氓忙莽猫茅锚毛矛铆卯茂冒帽貌贸么玫枚梅酶霉煤没眉媒镁每美昧寐妹媚门闷们萌蒙檬盟锰猛梦孟眯醚靡糜迷谜弥米秘觅泌蜜密幂棉眠绵冕免勉娩缅面苗描瞄藐秒渺庙妙蔑灭民抿皿敏悯闽明螟鸣铭名命谬摸�".split(""); +for(j = 0; j != D[195].length; ++j) if(D[195][j].charCodeAt(0) !== 0xFFFD) { e[D[195][j]] = 49920 + j; d[49920 + j] = D[195][j];} +D[196] = "����������������������������������������������������������������腀腁腂腃腄腅腇腉腍腎腏腒腖腗腘腛腜腝腞腟腡腢腣腤腦腨腪腫腬腯腲腳腵腶腷腸膁膃膄膅膆膇膉膋膌膍膎膐膒膓膔膕膖膗膙膚膞膟膠膡膢膤膥�膧膩膫膬膭膮膯膰膱膲膴膵膶膷膸膹膼膽膾膿臄臅臇臈臉臋臍臎臏臐臑臒臓摹蘑模膜磨摩魔抹末莫墨默沫漠寞陌谋牟某拇牡亩姆母墓暮幕募慕木目睦牧穆拿哪呐钠那娜纳氖乃奶耐奈南男难囊挠脑恼闹淖呢馁内嫩能妮霓倪泥尼拟你匿腻逆溺蔫拈年碾撵捻念娘酿鸟尿捏聂孽啮镊镍涅您柠狞凝宁�".split(""); +for(j = 0; j != D[196].length; ++j) if(D[196][j].charCodeAt(0) !== 0xFFFD) { e[D[196][j]] = 50176 + j; d[50176 + j] = D[196][j];} +D[197] = "����������������������������������������������������������������臔臕臖臗臘臙臚臛臜臝臞臟臠臡臢臤臥臦臨臩臫臮臯臰臱臲臵臶臷臸臹臺臽臿舃與興舉舊舋舎舏舑舓舕舖舗舘舙舚舝舠舤舥舦舧舩舮舲舺舼舽舿�艀艁艂艃艅艆艈艊艌艍艎艐艑艒艓艔艕艖艗艙艛艜艝艞艠艡艢艣艤艥艦艧艩拧泞牛扭钮纽脓浓农弄奴努怒女暖虐疟挪懦糯诺哦欧鸥殴藕呕偶沤啪趴爬帕怕琶拍排牌徘湃派攀潘盘磐盼畔判叛乓庞旁耪胖抛咆刨炮袍跑泡呸胚培裴赔陪配佩沛喷盆砰抨烹澎彭蓬棚硼篷膨朋鹏捧碰坯砒霹批披劈琵毗�".split(""); +for(j = 0; j != D[197].length; ++j) if(D[197][j].charCodeAt(0) !== 0xFFFD) { e[D[197][j]] = 50432 + j; d[50432 + j] = D[197][j];} +D[198] = "����������������������������������������������������������������艪艫艬艭艱艵艶艷艸艻艼芀芁芃芅芆芇芉芌芐芓芔芕芖芚芛芞芠芢芣芧芲芵芶芺芻芼芿苀苂苃苅苆苉苐苖苙苚苝苢苧苨苩苪苬苭苮苰苲苳苵苶苸�苺苼苽苾苿茀茊茋茍茐茒茓茖茘茙茝茞茟茠茡茢茣茤茥茦茩茪茮茰茲茷茻茽啤脾疲皮匹痞僻屁譬篇偏片骗飘漂瓢票撇瞥拼频贫品聘乒坪苹萍平凭瓶评屏坡泼颇婆破魄迫粕剖扑铺仆莆葡菩蒲埔朴圃普浦谱曝瀑期欺栖戚妻七凄漆柒沏其棋奇歧畦崎脐齐旗祈祁骑起岂乞企启契砌器气迄弃汽泣讫掐�".split(""); +for(j = 0; j != D[198].length; ++j) if(D[198][j].charCodeAt(0) !== 0xFFFD) { e[D[198][j]] = 50688 + j; d[50688 + j] = D[198][j];} +D[199] = "����������������������������������������������������������������茾茿荁荂荄荅荈荊荋荌荍荎荓荕荖荗荘荙荝荢荰荱荲荳荴荵荶荹荺荾荿莀莁莂莃莄莇莈莊莋莌莍莏莐莑莔莕莖莗莙莚莝莟莡莢莣莤莥莦莧莬莭莮�莯莵莻莾莿菂菃菄菆菈菉菋菍菎菐菑菒菓菕菗菙菚菛菞菢菣菤菦菧菨菫菬菭恰洽牵扦钎铅千迁签仟谦乾黔钱钳前潜遣浅谴堑嵌欠歉枪呛腔羌墙蔷强抢橇锹敲悄桥瞧乔侨巧鞘撬翘峭俏窍切茄且怯窃钦侵亲秦琴勤芹擒禽寝沁青轻氢倾卿清擎晴氰情顷请庆琼穷秋丘邱球求囚酋泅趋区蛆曲躯屈驱渠�".split(""); +for(j = 0; j != D[199].length; ++j) if(D[199][j].charCodeAt(0) !== 0xFFFD) { e[D[199][j]] = 50944 + j; d[50944 + j] = D[199][j];} +D[200] = "����������������������������������������������������������������菮華菳菴菵菶菷菺菻菼菾菿萀萂萅萇萈萉萊萐萒萓萔萕萖萗萙萚萛萞萟萠萡萢萣萩萪萫萬萭萮萯萰萲萳萴萵萶萷萹萺萻萾萿葀葁葂葃葄葅葇葈葉�葊葋葌葍葎葏葐葒葓葔葕葖葘葝葞葟葠葢葤葥葦葧葨葪葮葯葰葲葴葷葹葻葼取娶龋趣去圈颧权醛泉全痊拳犬券劝缺炔瘸却鹊榷确雀裙群然燃冉染瓤壤攘嚷让饶扰绕惹热壬仁人忍韧任认刃妊纫扔仍日戎茸蓉荣融熔溶容绒冗揉柔肉茹蠕儒孺如辱乳汝入褥软阮蕊瑞锐闰润若弱撒洒萨腮鳃塞赛三叁�".split(""); +for(j = 0; j != D[200].length; ++j) if(D[200][j].charCodeAt(0) !== 0xFFFD) { e[D[200][j]] = 51200 + j; d[51200 + j] = D[200][j];} +D[201] = "����������������������������������������������������������������葽葾葿蒀蒁蒃蒄蒅蒆蒊蒍蒏蒐蒑蒒蒓蒔蒕蒖蒘蒚蒛蒝蒞蒟蒠蒢蒣蒤蒥蒦蒧蒨蒩蒪蒫蒬蒭蒮蒰蒱蒳蒵蒶蒷蒻蒼蒾蓀蓂蓃蓅蓆蓇蓈蓋蓌蓎蓏蓒蓔蓕蓗�蓘蓙蓚蓛蓜蓞蓡蓢蓤蓧蓨蓩蓪蓫蓭蓮蓯蓱蓲蓳蓴蓵蓶蓷蓸蓹蓺蓻蓽蓾蔀蔁蔂伞散桑嗓丧搔骚扫嫂瑟色涩森僧莎砂杀刹沙纱傻啥煞筛晒珊苫杉山删煽衫闪陕擅赡膳善汕扇缮墒伤商赏晌上尚裳梢捎稍烧芍勺韶少哨邵绍奢赊蛇舌舍赦摄射慑涉社设砷申呻伸身深娠绅神沈审婶甚肾慎渗声生甥牲升绳�".split(""); +for(j = 0; j != D[201].length; ++j) if(D[201][j].charCodeAt(0) !== 0xFFFD) { e[D[201][j]] = 51456 + j; d[51456 + j] = D[201][j];} +D[202] = "����������������������������������������������������������������蔃蔄蔅蔆蔇蔈蔉蔊蔋蔍蔎蔏蔐蔒蔔蔕蔖蔘蔙蔛蔜蔝蔞蔠蔢蔣蔤蔥蔦蔧蔨蔩蔪蔭蔮蔯蔰蔱蔲蔳蔴蔵蔶蔾蔿蕀蕁蕂蕄蕅蕆蕇蕋蕌蕍蕎蕏蕐蕑蕒蕓蕔蕕�蕗蕘蕚蕛蕜蕝蕟蕠蕡蕢蕣蕥蕦蕧蕩蕪蕫蕬蕭蕮蕯蕰蕱蕳蕵蕶蕷蕸蕼蕽蕿薀薁省盛剩胜圣师失狮施湿诗尸虱十石拾时什食蚀实识史矢使屎驶始式示士世柿事拭誓逝势是嗜噬适仕侍释饰氏市恃室视试收手首守寿授售受瘦兽蔬枢梳殊抒输叔舒淑疏书赎孰熟薯暑曙署蜀黍鼠属术述树束戍竖墅庶数漱�".split(""); +for(j = 0; j != D[202].length; ++j) if(D[202][j].charCodeAt(0) !== 0xFFFD) { e[D[202][j]] = 51712 + j; d[51712 + j] = D[202][j];} +D[203] = "����������������������������������������������������������������薂薃薆薈薉薊薋薌薍薎薐薑薒薓薔薕薖薗薘薙薚薝薞薟薠薡薢薣薥薦薧薩薫薬薭薱薲薳薴薵薶薸薺薻薼薽薾薿藀藂藃藄藅藆藇藈藊藋藌藍藎藑藒�藔藖藗藘藙藚藛藝藞藟藠藡藢藣藥藦藧藨藪藫藬藭藮藯藰藱藲藳藴藵藶藷藸恕刷耍摔衰甩帅栓拴霜双爽谁水睡税吮瞬顺舜说硕朔烁斯撕嘶思私司丝死肆寺嗣四伺似饲巳松耸怂颂送宋讼诵搜艘擞嗽苏酥俗素速粟僳塑溯宿诉肃酸蒜算虽隋随绥髓碎岁穗遂隧祟孙损笋蓑梭唆缩琐索锁所塌他它她塔�".split(""); +for(j = 0; j != D[203].length; ++j) if(D[203][j].charCodeAt(0) !== 0xFFFD) { e[D[203][j]] = 51968 + j; d[51968 + j] = D[203][j];} +D[204] = "����������������������������������������������������������������藹藺藼藽藾蘀蘁蘂蘃蘄蘆蘇蘈蘉蘊蘋蘌蘍蘎蘏蘐蘒蘓蘔蘕蘗蘘蘙蘚蘛蘜蘝蘞蘟蘠蘡蘢蘣蘤蘥蘦蘨蘪蘫蘬蘭蘮蘯蘰蘱蘲蘳蘴蘵蘶蘷蘹蘺蘻蘽蘾蘿虀�虁虂虃虄虅虆虇虈虉虊虋虌虒虓處虖虗虘虙虛虜虝號虠虡虣虤虥虦虧虨虩虪獭挞蹋踏胎苔抬台泰酞太态汰坍摊贪瘫滩坛檀痰潭谭谈坦毯袒碳探叹炭汤塘搪堂棠膛唐糖倘躺淌趟烫掏涛滔绦萄桃逃淘陶讨套特藤腾疼誊梯剔踢锑提题蹄啼体替嚏惕涕剃屉天添填田甜恬舔腆挑条迢眺跳贴铁帖厅听烃�".split(""); +for(j = 0; j != D[204].length; ++j) if(D[204][j].charCodeAt(0) !== 0xFFFD) { e[D[204][j]] = 52224 + j; d[52224 + j] = D[204][j];} +D[205] = "����������������������������������������������������������������虭虯虰虲虳虴虵虶虷虸蚃蚄蚅蚆蚇蚈蚉蚎蚏蚐蚑蚒蚔蚖蚗蚘蚙蚚蚛蚞蚟蚠蚡蚢蚥蚦蚫蚭蚮蚲蚳蚷蚸蚹蚻蚼蚽蚾蚿蛁蛂蛃蛅蛈蛌蛍蛒蛓蛕蛖蛗蛚蛜�蛝蛠蛡蛢蛣蛥蛦蛧蛨蛪蛫蛬蛯蛵蛶蛷蛺蛻蛼蛽蛿蜁蜄蜅蜆蜋蜌蜎蜏蜐蜑蜔蜖汀廷停亭庭挺艇通桐酮瞳同铜彤童桶捅筒统痛偷投头透凸秃突图徒途涂屠土吐兔湍团推颓腿蜕褪退吞屯臀拖托脱鸵陀驮驼椭妥拓唾挖哇蛙洼娃瓦袜歪外豌弯湾玩顽丸烷完碗挽晚皖惋宛婉万腕汪王亡枉网往旺望忘妄威�".split(""); +for(j = 0; j != D[205].length; ++j) if(D[205][j].charCodeAt(0) !== 0xFFFD) { e[D[205][j]] = 52480 + j; d[52480 + j] = D[205][j];} +D[206] = "����������������������������������������������������������������蜙蜛蜝蜟蜠蜤蜦蜧蜨蜪蜫蜬蜭蜯蜰蜲蜳蜵蜶蜸蜹蜺蜼蜽蝀蝁蝂蝃蝄蝅蝆蝊蝋蝍蝏蝐蝑蝒蝔蝕蝖蝘蝚蝛蝜蝝蝞蝟蝡蝢蝦蝧蝨蝩蝪蝫蝬蝭蝯蝱蝲蝳蝵�蝷蝸蝹蝺蝿螀螁螄螆螇螉螊螌螎螏螐螑螒螔螕螖螘螙螚螛螜螝螞螠螡螢螣螤巍微危韦违桅围唯惟为潍维苇萎委伟伪尾纬未蔚味畏胃喂魏位渭谓尉慰卫瘟温蚊文闻纹吻稳紊问嗡翁瓮挝蜗涡窝我斡卧握沃巫呜钨乌污诬屋无芜梧吾吴毋武五捂午舞伍侮坞戊雾晤物勿务悟误昔熙析西硒矽晰嘻吸锡牺�".split(""); +for(j = 0; j != D[206].length; ++j) if(D[206][j].charCodeAt(0) !== 0xFFFD) { e[D[206][j]] = 52736 + j; d[52736 + j] = D[206][j];} +D[207] = "����������������������������������������������������������������螥螦螧螩螪螮螰螱螲螴螶螷螸螹螻螼螾螿蟁蟂蟃蟄蟅蟇蟈蟉蟌蟍蟎蟏蟐蟔蟕蟖蟗蟘蟙蟚蟜蟝蟞蟟蟡蟢蟣蟤蟦蟧蟨蟩蟫蟬蟭蟯蟰蟱蟲蟳蟴蟵蟶蟷蟸�蟺蟻蟼蟽蟿蠀蠁蠂蠄蠅蠆蠇蠈蠉蠋蠌蠍蠎蠏蠐蠑蠒蠔蠗蠘蠙蠚蠜蠝蠞蠟蠠蠣稀息希悉膝夕惜熄烯溪汐犀檄袭席习媳喜铣洗系隙戏细瞎虾匣霞辖暇峡侠狭下厦夏吓掀锨先仙鲜纤咸贤衔舷闲涎弦嫌显险现献县腺馅羡宪陷限线相厢镶香箱襄湘乡翔祥详想响享项巷橡像向象萧硝霄削哮嚣销消宵淆晓�".split(""); +for(j = 0; j != D[207].length; ++j) if(D[207][j].charCodeAt(0) !== 0xFFFD) { e[D[207][j]] = 52992 + j; d[52992 + j] = D[207][j];} +D[208] = "����������������������������������������������������������������蠤蠥蠦蠧蠨蠩蠪蠫蠬蠭蠮蠯蠰蠱蠳蠴蠵蠶蠷蠸蠺蠻蠽蠾蠿衁衂衃衆衇衈衉衊衋衎衏衐衑衒術衕衖衘衚衛衜衝衞衟衠衦衧衪衭衯衱衳衴衵衶衸衹衺�衻衼袀袃袆袇袉袊袌袎袏袐袑袓袔袕袗袘袙袚袛袝袞袟袠袡袣袥袦袧袨袩袪小孝校肖啸笑效楔些歇蝎鞋协挟携邪斜胁谐写械卸蟹懈泄泻谢屑薪芯锌欣辛新忻心信衅星腥猩惺兴刑型形邢行醒幸杏性姓兄凶胸匈汹雄熊休修羞朽嗅锈秀袖绣墟戌需虚嘘须徐许蓄酗叙旭序畜恤絮婿绪续轩喧宣悬旋玄�".split(""); +for(j = 0; j != D[208].length; ++j) if(D[208][j].charCodeAt(0) !== 0xFFFD) { e[D[208][j]] = 53248 + j; d[53248 + j] = D[208][j];} +D[209] = "����������������������������������������������������������������袬袮袯袰袲袳袴袵袶袸袹袺袻袽袾袿裀裃裄裇裈裊裋裌裍裏裐裑裓裖裗裚裛補裝裞裠裡裦裧裩裪裫裬裭裮裯裲裵裶裷裺裻製裿褀褁褃褄褅褆複褈�褉褋褌褍褎褏褑褔褕褖褗褘褜褝褞褟褠褢褣褤褦褧褨褩褬褭褮褯褱褲褳褵褷选癣眩绚靴薛学穴雪血勋熏循旬询寻驯巡殉汛训讯逊迅压押鸦鸭呀丫芽牙蚜崖衙涯雅哑亚讶焉咽阉烟淹盐严研蜒岩延言颜阎炎沿奄掩眼衍演艳堰燕厌砚雁唁彦焰宴谚验殃央鸯秧杨扬佯疡羊洋阳氧仰痒养样漾邀腰妖瑶�".split(""); +for(j = 0; j != D[209].length; ++j) if(D[209][j].charCodeAt(0) !== 0xFFFD) { e[D[209][j]] = 53504 + j; d[53504 + j] = D[209][j];} +D[210] = "����������������������������������������������������������������褸褹褺褻褼褽褾褿襀襂襃襅襆襇襈襉襊襋襌襍襎襏襐襑襒襓襔襕襖襗襘襙襚襛襜襝襠襡襢襣襤襥襧襨襩襪襫襬襭襮襯襰襱襲襳襴襵襶襷襸襹襺襼�襽襾覀覂覄覅覇覈覉覊見覌覍覎規覐覑覒覓覔覕視覗覘覙覚覛覜覝覞覟覠覡摇尧遥窑谣姚咬舀药要耀椰噎耶爷野冶也页掖业叶曳腋夜液一壹医揖铱依伊衣颐夷遗移仪胰疑沂宜姨彝椅蚁倚已乙矣以艺抑易邑屹亿役臆逸肄疫亦裔意毅忆义益溢诣议谊译异翼翌绎茵荫因殷音阴姻吟银淫寅饮尹引隐�".split(""); +for(j = 0; j != D[210].length; ++j) if(D[210][j].charCodeAt(0) !== 0xFFFD) { e[D[210][j]] = 53760 + j; d[53760 + j] = D[210][j];} +D[211] = "����������������������������������������������������������������覢覣覤覥覦覧覨覩親覫覬覭覮覯覰覱覲観覴覵覶覷覸覹覺覻覼覽覾覿觀觃觍觓觔觕觗觘觙觛觝觟觠觡觢觤觧觨觩觪觬觭觮觰觱觲觴觵觶觷觸觹觺�觻觼觽觾觿訁訂訃訄訅訆計訉訊訋訌訍討訏訐訑訒訓訔訕訖託記訙訚訛訜訝印英樱婴鹰应缨莹萤营荧蝇迎赢盈影颖硬映哟拥佣臃痈庸雍踊蛹咏泳涌永恿勇用幽优悠忧尤由邮铀犹油游酉有友右佑釉诱又幼迂淤于盂榆虞愚舆余俞逾鱼愉渝渔隅予娱雨与屿禹宇语羽玉域芋郁吁遇喻峪御愈欲狱育誉�".split(""); +for(j = 0; j != D[211].length; ++j) if(D[211][j].charCodeAt(0) !== 0xFFFD) { e[D[211][j]] = 54016 + j; d[54016 + j] = D[211][j];} +D[212] = "����������������������������������������������������������������訞訟訠訡訢訣訤訥訦訧訨訩訪訫訬設訮訯訰許訲訳訴訵訶訷訸訹診註証訽訿詀詁詂詃詄詅詆詇詉詊詋詌詍詎詏詐詑詒詓詔評詖詗詘詙詚詛詜詝詞�詟詠詡詢詣詤詥試詧詨詩詪詫詬詭詮詯詰話該詳詴詵詶詷詸詺詻詼詽詾詿誀浴寓裕预豫驭鸳渊冤元垣袁原援辕园员圆猿源缘远苑愿怨院曰约越跃钥岳粤月悦阅耘云郧匀陨允运蕴酝晕韵孕匝砸杂栽哉灾宰载再在咱攒暂赞赃脏葬遭糟凿藻枣早澡蚤躁噪造皂灶燥责择则泽贼怎增憎曾赠扎喳渣札轧�".split(""); +for(j = 0; j != D[212].length; ++j) if(D[212][j].charCodeAt(0) !== 0xFFFD) { e[D[212][j]] = 54272 + j; d[54272 + j] = D[212][j];} +D[213] = "����������������������������������������������������������������誁誂誃誄誅誆誇誈誋誌認誎誏誐誑誒誔誕誖誗誘誙誚誛誜誝語誟誠誡誢誣誤誥誦誧誨誩說誫説読誮誯誰誱課誳誴誵誶誷誸誹誺誻誼誽誾調諀諁諂�諃諄諅諆談諈諉諊請諌諍諎諏諐諑諒諓諔諕論諗諘諙諚諛諜諝諞諟諠諡諢諣铡闸眨栅榨咋乍炸诈摘斋宅窄债寨瞻毡詹粘沾盏斩辗崭展蘸栈占战站湛绽樟章彰漳张掌涨杖丈帐账仗胀瘴障招昭找沼赵照罩兆肇召遮折哲蛰辙者锗蔗这浙珍斟真甄砧臻贞针侦枕疹诊震振镇阵蒸挣睁征狰争怔整拯正政�".split(""); +for(j = 0; j != D[213].length; ++j) if(D[213][j].charCodeAt(0) !== 0xFFFD) { e[D[213][j]] = 54528 + j; d[54528 + j] = D[213][j];} +D[214] = "����������������������������������������������������������������諤諥諦諧諨諩諪諫諬諭諮諯諰諱諲諳諴諵諶諷諸諹諺諻諼諽諾諿謀謁謂謃謄謅謆謈謉謊謋謌謍謎謏謐謑謒謓謔謕謖謗謘謙謚講謜謝謞謟謠謡謢謣�謤謥謧謨謩謪謫謬謭謮謯謰謱謲謳謴謵謶謷謸謹謺謻謼謽謾謿譀譁譂譃譄譅帧症郑证芝枝支吱蜘知肢脂汁之织职直植殖执值侄址指止趾只旨纸志挚掷至致置帜峙制智秩稚质炙痔滞治窒中盅忠钟衷终种肿重仲众舟周州洲诌粥轴肘帚咒皱宙昼骤珠株蛛朱猪诸诛逐竹烛煮拄瞩嘱主著柱助蛀贮铸筑�".split(""); +for(j = 0; j != D[214].length; ++j) if(D[214][j].charCodeAt(0) !== 0xFFFD) { e[D[214][j]] = 54784 + j; d[54784 + j] = D[214][j];} +D[215] = "����������������������������������������������������������������譆譇譈證譊譋譌譍譎譏譐譑譒譓譔譕譖譗識譙譚譛譜譝譞譟譠譡譢譣譤譥譧譨譩譪譫譭譮譯議譱譲譳譴譵譶護譸譹譺譻譼譽譾譿讀讁讂讃讄讅讆�讇讈讉變讋讌讍讎讏讐讑讒讓讔讕讖讗讘讙讚讛讜讝讞讟讬讱讻诇诐诪谉谞住注祝驻抓爪拽专砖转撰赚篆桩庄装妆撞壮状椎锥追赘坠缀谆准捉拙卓桌琢茁酌啄着灼浊兹咨资姿滋淄孜紫仔籽滓子自渍字鬃棕踪宗综总纵邹走奏揍租足卒族祖诅阻组钻纂嘴醉最罪尊遵昨左佐柞做作坐座������".split(""); +for(j = 0; j != D[215].length; ++j) if(D[215][j].charCodeAt(0) !== 0xFFFD) { e[D[215][j]] = 55040 + j; d[55040 + j] = D[215][j];} +D[216] = "����������������������������������������������������������������谸谹谺谻谼谽谾谿豀豂豃豄豅豈豊豋豍豎豏豐豑豒豓豔豖豗豘豙豛豜豝豞豟豠豣豤豥豦豧豨豩豬豭豮豯豰豱豲豴豵豶豷豻豼豽豾豿貀貁貃貄貆貇�貈貋貍貎貏貐貑貒貓貕貖貗貙貚貛貜貝貞貟負財貢貣貤貥貦貧貨販貪貫責貭亍丌兀丐廿卅丕亘丞鬲孬噩丨禺丿匕乇夭爻卮氐囟胤馗毓睾鼗丶亟鼐乜乩亓芈孛啬嘏仄厍厝厣厥厮靥赝匚叵匦匮匾赜卦卣刂刈刎刭刳刿剀剌剞剡剜蒯剽劂劁劐劓冂罔亻仃仉仂仨仡仫仞伛仳伢佤仵伥伧伉伫佞佧攸佚佝�".split(""); +for(j = 0; j != D[216].length; ++j) if(D[216][j].charCodeAt(0) !== 0xFFFD) { e[D[216][j]] = 55296 + j; d[55296 + j] = D[216][j];} +D[217] = "����������������������������������������������������������������貮貯貰貱貲貳貴貵貶買貸貹貺費貼貽貾貿賀賁賂賃賄賅賆資賈賉賊賋賌賍賎賏賐賑賒賓賔賕賖賗賘賙賚賛賜賝賞賟賠賡賢賣賤賥賦賧賨賩質賫賬�賭賮賯賰賱賲賳賴賵賶賷賸賹賺賻購賽賾賿贀贁贂贃贄贅贆贇贈贉贊贋贌贍佟佗伲伽佶佴侑侉侃侏佾佻侪佼侬侔俦俨俪俅俚俣俜俑俟俸倩偌俳倬倏倮倭俾倜倌倥倨偾偃偕偈偎偬偻傥傧傩傺僖儆僭僬僦僮儇儋仝氽佘佥俎龠汆籴兮巽黉馘冁夔勹匍訇匐凫夙兕亠兖亳衮袤亵脔裒禀嬴蠃羸冫冱冽冼�".split(""); +for(j = 0; j != D[217].length; ++j) if(D[217][j].charCodeAt(0) !== 0xFFFD) { e[D[217][j]] = 55552 + j; d[55552 + j] = D[217][j];} +D[218] = "����������������������������������������������������������������贎贏贐贑贒贓贔贕贖贗贘贙贚贛贜贠赑赒赗赟赥赨赩赪赬赮赯赱赲赸赹赺赻赼赽赾赿趀趂趃趆趇趈趉趌趍趎趏趐趒趓趕趖趗趘趙趚趛趜趝趞趠趡�趢趤趥趦趧趨趩趪趫趬趭趮趯趰趲趶趷趹趻趽跀跁跂跅跇跈跉跊跍跐跒跓跔凇冖冢冥讠讦讧讪讴讵讷诂诃诋诏诎诒诓诔诖诘诙诜诟诠诤诨诩诮诰诳诶诹诼诿谀谂谄谇谌谏谑谒谔谕谖谙谛谘谝谟谠谡谥谧谪谫谮谯谲谳谵谶卩卺阝阢阡阱阪阽阼陂陉陔陟陧陬陲陴隈隍隗隰邗邛邝邙邬邡邴邳邶邺�".split(""); +for(j = 0; j != D[218].length; ++j) if(D[218][j].charCodeAt(0) !== 0xFFFD) { e[D[218][j]] = 55808 + j; d[55808 + j] = D[218][j];} +D[219] = "����������������������������������������������������������������跕跘跙跜跠跡跢跥跦跧跩跭跮跰跱跲跴跶跼跾跿踀踁踂踃踄踆踇踈踋踍踎踐踑踒踓踕踖踗踘踙踚踛踜踠踡踤踥踦踧踨踫踭踰踲踳踴踶踷踸踻踼踾�踿蹃蹅蹆蹌蹍蹎蹏蹐蹓蹔蹕蹖蹗蹘蹚蹛蹜蹝蹞蹟蹠蹡蹢蹣蹤蹥蹧蹨蹪蹫蹮蹱邸邰郏郅邾郐郄郇郓郦郢郜郗郛郫郯郾鄄鄢鄞鄣鄱鄯鄹酃酆刍奂劢劬劭劾哿勐勖勰叟燮矍廴凵凼鬯厶弁畚巯坌垩垡塾墼壅壑圩圬圪圳圹圮圯坜圻坂坩垅坫垆坼坻坨坭坶坳垭垤垌垲埏垧垴垓垠埕埘埚埙埒垸埴埯埸埤埝�".split(""); +for(j = 0; j != D[219].length; ++j) if(D[219][j].charCodeAt(0) !== 0xFFFD) { e[D[219][j]] = 56064 + j; d[56064 + j] = D[219][j];} +D[220] = "����������������������������������������������������������������蹳蹵蹷蹸蹹蹺蹻蹽蹾躀躂躃躄躆躈躉躊躋躌躍躎躑躒躓躕躖躗躘躙躚躛躝躟躠躡躢躣躤躥躦躧躨躩躪躭躮躰躱躳躴躵躶躷躸躹躻躼躽躾躿軀軁軂�軃軄軅軆軇軈軉車軋軌軍軏軐軑軒軓軔軕軖軗軘軙軚軛軜軝軞軟軠軡転軣軤堋堍埽埭堀堞堙塄堠塥塬墁墉墚墀馨鼙懿艹艽艿芏芊芨芄芎芑芗芙芫芸芾芰苈苊苣芘芷芮苋苌苁芩芴芡芪芟苄苎芤苡茉苷苤茏茇苜苴苒苘茌苻苓茑茚茆茔茕苠苕茜荑荛荜茈莒茼茴茱莛荞茯荏荇荃荟荀茗荠茭茺茳荦荥�".split(""); +for(j = 0; j != D[220].length; ++j) if(D[220][j].charCodeAt(0) !== 0xFFFD) { e[D[220][j]] = 56320 + j; d[56320 + j] = D[220][j];} +D[221] = "����������������������������������������������������������������軥軦軧軨軩軪軫軬軭軮軯軰軱軲軳軴軵軶軷軸軹軺軻軼軽軾軿輀輁輂較輄輅輆輇輈載輊輋輌輍輎輏輐輑輒輓輔輕輖輗輘輙輚輛輜輝輞輟輠輡輢輣�輤輥輦輧輨輩輪輫輬輭輮輯輰輱輲輳輴輵輶輷輸輹輺輻輼輽輾輿轀轁轂轃轄荨茛荩荬荪荭荮莰荸莳莴莠莪莓莜莅荼莶莩荽莸荻莘莞莨莺莼菁萁菥菘堇萘萋菝菽菖萜萸萑萆菔菟萏萃菸菹菪菅菀萦菰菡葜葑葚葙葳蒇蒈葺蒉葸萼葆葩葶蒌蒎萱葭蓁蓍蓐蓦蒽蓓蓊蒿蒺蓠蒡蒹蒴蒗蓥蓣蔌甍蔸蓰蔹蔟蔺�".split(""); +for(j = 0; j != D[221].length; ++j) if(D[221][j].charCodeAt(0) !== 0xFFFD) { e[D[221][j]] = 56576 + j; d[56576 + j] = D[221][j];} +D[222] = "����������������������������������������������������������������轅轆轇轈轉轊轋轌轍轎轏轐轑轒轓轔轕轖轗轘轙轚轛轜轝轞轟轠轡轢轣轤轥轪辀辌辒辝辠辡辢辤辥辦辧辪辬辭辮辯農辳辴辵辷辸辺辻込辿迀迃迆�迉迊迋迌迍迏迒迖迗迚迠迡迣迧迬迯迱迲迴迵迶迺迻迼迾迿逇逈逌逎逓逕逘蕖蔻蓿蓼蕙蕈蕨蕤蕞蕺瞢蕃蕲蕻薤薨薇薏蕹薮薜薅薹薷薰藓藁藜藿蘧蘅蘩蘖蘼廾弈夼奁耷奕奚奘匏尢尥尬尴扌扪抟抻拊拚拗拮挢拶挹捋捃掭揶捱捺掎掴捭掬掊捩掮掼揲揸揠揿揄揞揎摒揆掾摅摁搋搛搠搌搦搡摞撄摭撖�".split(""); +for(j = 0; j != D[222].length; ++j) if(D[222][j].charCodeAt(0) !== 0xFFFD) { e[D[222][j]] = 56832 + j; d[56832 + j] = D[222][j];} +D[223] = "����������������������������������������������������������������這逜連逤逥逧逨逩逪逫逬逰週進逳逴逷逹逺逽逿遀遃遅遆遈遉遊運遌過達違遖遙遚遜遝遞遟遠遡遤遦遧適遪遫遬遯遰遱遲遳遶遷選遹遺遻遼遾邁�還邅邆邇邉邊邌邍邎邏邐邒邔邖邘邚邜邞邟邠邤邥邧邨邩邫邭邲邷邼邽邿郀摺撷撸撙撺擀擐擗擤擢攉攥攮弋忒甙弑卟叱叽叩叨叻吒吖吆呋呒呓呔呖呃吡呗呙吣吲咂咔呷呱呤咚咛咄呶呦咝哐咭哂咴哒咧咦哓哔呲咣哕咻咿哌哙哚哜咩咪咤哝哏哞唛哧唠哽唔哳唢唣唏唑唧唪啧喏喵啉啭啁啕唿啐唼�".split(""); +for(j = 0; j != D[223].length; ++j) if(D[223][j].charCodeAt(0) !== 0xFFFD) { e[D[223][j]] = 57088 + j; d[57088 + j] = D[223][j];} +D[224] = "����������������������������������������������������������������郂郃郆郈郉郋郌郍郒郔郕郖郘郙郚郞郟郠郣郤郥郩郪郬郮郰郱郲郳郵郶郷郹郺郻郼郿鄀鄁鄃鄅鄆鄇鄈鄉鄊鄋鄌鄍鄎鄏鄐鄑鄒鄓鄔鄕鄖鄗鄘鄚鄛鄜�鄝鄟鄠鄡鄤鄥鄦鄧鄨鄩鄪鄫鄬鄭鄮鄰鄲鄳鄴鄵鄶鄷鄸鄺鄻鄼鄽鄾鄿酀酁酂酄唷啖啵啶啷唳唰啜喋嗒喃喱喹喈喁喟啾嗖喑啻嗟喽喾喔喙嗪嗷嗉嘟嗑嗫嗬嗔嗦嗝嗄嗯嗥嗲嗳嗌嗍嗨嗵嗤辔嘞嘈嘌嘁嘤嘣嗾嘀嘧嘭噘嘹噗嘬噍噢噙噜噌噔嚆噤噱噫噻噼嚅嚓嚯囔囗囝囡囵囫囹囿圄圊圉圜帏帙帔帑帱帻帼�".split(""); +for(j = 0; j != D[224].length; ++j) if(D[224][j].charCodeAt(0) !== 0xFFFD) { e[D[224][j]] = 57344 + j; d[57344 + j] = D[224][j];} +D[225] = "����������������������������������������������������������������酅酇酈酑酓酔酕酖酘酙酛酜酟酠酦酧酨酫酭酳酺酻酼醀醁醂醃醄醆醈醊醎醏醓醔醕醖醗醘醙醜醝醞醟醠醡醤醥醦醧醨醩醫醬醰醱醲醳醶醷醸醹醻�醼醽醾醿釀釁釂釃釄釅釆釈釋釐釒釓釔釕釖釗釘釙釚釛針釞釟釠釡釢釣釤釥帷幄幔幛幞幡岌屺岍岐岖岈岘岙岑岚岜岵岢岽岬岫岱岣峁岷峄峒峤峋峥崂崃崧崦崮崤崞崆崛嵘崾崴崽嵬嵛嵯嵝嵫嵋嵊嵩嵴嶂嶙嶝豳嶷巅彳彷徂徇徉後徕徙徜徨徭徵徼衢彡犭犰犴犷犸狃狁狎狍狒狨狯狩狲狴狷猁狳猃狺�".split(""); +for(j = 0; j != D[225].length; ++j) if(D[225][j].charCodeAt(0) !== 0xFFFD) { e[D[225][j]] = 57600 + j; d[57600 + j] = D[225][j];} +D[226] = "����������������������������������������������������������������釦釧釨釩釪釫釬釭釮釯釰釱釲釳釴釵釶釷釸釹釺釻釼釽釾釿鈀鈁鈂鈃鈄鈅鈆鈇鈈鈉鈊鈋鈌鈍鈎鈏鈐鈑鈒鈓鈔鈕鈖鈗鈘鈙鈚鈛鈜鈝鈞鈟鈠鈡鈢鈣鈤�鈥鈦鈧鈨鈩鈪鈫鈬鈭鈮鈯鈰鈱鈲鈳鈴鈵鈶鈷鈸鈹鈺鈻鈼鈽鈾鈿鉀鉁鉂鉃鉄鉅狻猗猓猡猊猞猝猕猢猹猥猬猸猱獐獍獗獠獬獯獾舛夥飧夤夂饣饧饨饩饪饫饬饴饷饽馀馄馇馊馍馐馑馓馔馕庀庑庋庖庥庠庹庵庾庳赓廒廑廛廨廪膺忄忉忖忏怃忮怄忡忤忾怅怆忪忭忸怙怵怦怛怏怍怩怫怊怿怡恸恹恻恺恂�".split(""); +for(j = 0; j != D[226].length; ++j) if(D[226][j].charCodeAt(0) !== 0xFFFD) { e[D[226][j]] = 57856 + j; d[57856 + j] = D[226][j];} +D[227] = "����������������������������������������������������������������鉆鉇鉈鉉鉊鉋鉌鉍鉎鉏鉐鉑鉒鉓鉔鉕鉖鉗鉘鉙鉚鉛鉜鉝鉞鉟鉠鉡鉢鉣鉤鉥鉦鉧鉨鉩鉪鉫鉬鉭鉮鉯鉰鉱鉲鉳鉵鉶鉷鉸鉹鉺鉻鉼鉽鉾鉿銀銁銂銃銄銅�銆銇銈銉銊銋銌銍銏銐銑銒銓銔銕銖銗銘銙銚銛銜銝銞銟銠銡銢銣銤銥銦銧恪恽悖悚悭悝悃悒悌悛惬悻悱惝惘惆惚悴愠愦愕愣惴愀愎愫慊慵憬憔憧憷懔懵忝隳闩闫闱闳闵闶闼闾阃阄阆阈阊阋阌阍阏阒阕阖阗阙阚丬爿戕氵汔汜汊沣沅沐沔沌汨汩汴汶沆沩泐泔沭泷泸泱泗沲泠泖泺泫泮沱泓泯泾�".split(""); +for(j = 0; j != D[227].length; ++j) if(D[227][j].charCodeAt(0) !== 0xFFFD) { e[D[227][j]] = 58112 + j; d[58112 + j] = D[227][j];} +D[228] = "����������������������������������������������������������������銨銩銪銫銬銭銯銰銱銲銳銴銵銶銷銸銹銺銻銼銽銾銿鋀鋁鋂鋃鋄鋅鋆鋇鋉鋊鋋鋌鋍鋎鋏鋐鋑鋒鋓鋔鋕鋖鋗鋘鋙鋚鋛鋜鋝鋞鋟鋠鋡鋢鋣鋤鋥鋦鋧鋨�鋩鋪鋫鋬鋭鋮鋯鋰鋱鋲鋳鋴鋵鋶鋷鋸鋹鋺鋻鋼鋽鋾鋿錀錁錂錃錄錅錆錇錈錉洹洧洌浃浈洇洄洙洎洫浍洮洵洚浏浒浔洳涑浯涞涠浞涓涔浜浠浼浣渚淇淅淞渎涿淠渑淦淝淙渖涫渌涮渫湮湎湫溲湟溆湓湔渲渥湄滟溱溘滠漭滢溥溧溽溻溷滗溴滏溏滂溟潢潆潇漤漕滹漯漶潋潴漪漉漩澉澍澌潸潲潼潺濑�".split(""); +for(j = 0; j != D[228].length; ++j) if(D[228][j].charCodeAt(0) !== 0xFFFD) { e[D[228][j]] = 58368 + j; d[58368 + j] = D[228][j];} +D[229] = "����������������������������������������������������������������錊錋錌錍錎錏錐錑錒錓錔錕錖錗錘錙錚錛錜錝錞錟錠錡錢錣錤錥錦錧錨錩錪錫錬錭錮錯錰錱録錳錴錵錶錷錸錹錺錻錼錽錿鍀鍁鍂鍃鍄鍅鍆鍇鍈鍉�鍊鍋鍌鍍鍎鍏鍐鍑鍒鍓鍔鍕鍖鍗鍘鍙鍚鍛鍜鍝鍞鍟鍠鍡鍢鍣鍤鍥鍦鍧鍨鍩鍫濉澧澹澶濂濡濮濞濠濯瀚瀣瀛瀹瀵灏灞宀宄宕宓宥宸甯骞搴寤寮褰寰蹇謇辶迓迕迥迮迤迩迦迳迨逅逄逋逦逑逍逖逡逵逶逭逯遄遑遒遐遨遘遢遛暹遴遽邂邈邃邋彐彗彖彘尻咫屐屙孱屣屦羼弪弩弭艴弼鬻屮妁妃妍妩妪妣�".split(""); +for(j = 0; j != D[229].length; ++j) if(D[229][j].charCodeAt(0) !== 0xFFFD) { e[D[229][j]] = 58624 + j; d[58624 + j] = D[229][j];} +D[230] = "����������������������������������������������������������������鍬鍭鍮鍯鍰鍱鍲鍳鍴鍵鍶鍷鍸鍹鍺鍻鍼鍽鍾鍿鎀鎁鎂鎃鎄鎅鎆鎇鎈鎉鎊鎋鎌鎍鎎鎐鎑鎒鎓鎔鎕鎖鎗鎘鎙鎚鎛鎜鎝鎞鎟鎠鎡鎢鎣鎤鎥鎦鎧鎨鎩鎪鎫�鎬鎭鎮鎯鎰鎱鎲鎳鎴鎵鎶鎷鎸鎹鎺鎻鎼鎽鎾鎿鏀鏁鏂鏃鏄鏅鏆鏇鏈鏉鏋鏌鏍妗姊妫妞妤姒妲妯姗妾娅娆姝娈姣姘姹娌娉娲娴娑娣娓婀婧婊婕娼婢婵胬媪媛婷婺媾嫫媲嫒嫔媸嫠嫣嫱嫖嫦嫘嫜嬉嬗嬖嬲嬷孀尕尜孚孥孳孑孓孢驵驷驸驺驿驽骀骁骅骈骊骐骒骓骖骘骛骜骝骟骠骢骣骥骧纟纡纣纥纨纩�".split(""); +for(j = 0; j != D[230].length; ++j) if(D[230][j].charCodeAt(0) !== 0xFFFD) { e[D[230][j]] = 58880 + j; d[58880 + j] = D[230][j];} +D[231] = "����������������������������������������������������������������鏎鏏鏐鏑鏒鏓鏔鏕鏗鏘鏙鏚鏛鏜鏝鏞鏟鏠鏡鏢鏣鏤鏥鏦鏧鏨鏩鏪鏫鏬鏭鏮鏯鏰鏱鏲鏳鏴鏵鏶鏷鏸鏹鏺鏻鏼鏽鏾鏿鐀鐁鐂鐃鐄鐅鐆鐇鐈鐉鐊鐋鐌鐍�鐎鐏鐐鐑鐒鐓鐔鐕鐖鐗鐘鐙鐚鐛鐜鐝鐞鐟鐠鐡鐢鐣鐤鐥鐦鐧鐨鐩鐪鐫鐬鐭鐮纭纰纾绀绁绂绉绋绌绐绔绗绛绠绡绨绫绮绯绱绲缍绶绺绻绾缁缂缃缇缈缋缌缏缑缒缗缙缜缛缟缡缢缣缤缥缦缧缪缫缬缭缯缰缱缲缳缵幺畿巛甾邕玎玑玮玢玟珏珂珑玷玳珀珉珈珥珙顼琊珩珧珞玺珲琏琪瑛琦琥琨琰琮琬�".split(""); +for(j = 0; j != D[231].length; ++j) if(D[231][j].charCodeAt(0) !== 0xFFFD) { e[D[231][j]] = 59136 + j; d[59136 + j] = D[231][j];} +D[232] = "����������������������������������������������������������������鐯鐰鐱鐲鐳鐴鐵鐶鐷鐸鐹鐺鐻鐼鐽鐿鑀鑁鑂鑃鑄鑅鑆鑇鑈鑉鑊鑋鑌鑍鑎鑏鑐鑑鑒鑓鑔鑕鑖鑗鑘鑙鑚鑛鑜鑝鑞鑟鑠鑡鑢鑣鑤鑥鑦鑧鑨鑩鑪鑬鑭鑮鑯�鑰鑱鑲鑳鑴鑵鑶鑷鑸鑹鑺鑻鑼鑽鑾鑿钀钁钂钃钄钑钖钘铇铏铓铔铚铦铻锜锠琛琚瑁瑜瑗瑕瑙瑷瑭瑾璜璎璀璁璇璋璞璨璩璐璧瓒璺韪韫韬杌杓杞杈杩枥枇杪杳枘枧杵枨枞枭枋杷杼柰栉柘栊柩枰栌柙枵柚枳柝栀柃枸柢栎柁柽栲栳桠桡桎桢桄桤梃栝桕桦桁桧桀栾桊桉栩梵梏桴桷梓桫棂楮棼椟椠棹�".split(""); +for(j = 0; j != D[232].length; ++j) if(D[232][j].charCodeAt(0) !== 0xFFFD) { e[D[232][j]] = 59392 + j; d[59392 + j] = D[232][j];} +D[233] = "����������������������������������������������������������������锧锳锽镃镈镋镕镚镠镮镴镵長镸镹镺镻镼镽镾門閁閂閃閄閅閆閇閈閉閊開閌閍閎閏閐閑閒間閔閕閖閗閘閙閚閛閜閝閞閟閠閡関閣閤閥閦閧閨閩閪�閫閬閭閮閯閰閱閲閳閴閵閶閷閸閹閺閻閼閽閾閿闀闁闂闃闄闅闆闇闈闉闊闋椤棰椋椁楗棣椐楱椹楠楂楝榄楫榀榘楸椴槌榇榈槎榉楦楣楹榛榧榻榫榭槔榱槁槊槟榕槠榍槿樯槭樗樘橥槲橄樾檠橐橛樵檎橹樽樨橘橼檑檐檩檗檫猷獒殁殂殇殄殒殓殍殚殛殡殪轫轭轱轲轳轵轶轸轷轹轺轼轾辁辂辄辇辋�".split(""); +for(j = 0; j != D[233].length; ++j) if(D[233][j].charCodeAt(0) !== 0xFFFD) { e[D[233][j]] = 59648 + j; d[59648 + j] = D[233][j];} +D[234] = "����������������������������������������������������������������闌闍闎闏闐闑闒闓闔闕闖闗闘闙闚闛關闝闞闟闠闡闢闣闤闥闦闧闬闿阇阓阘阛阞阠阣阤阥阦阧阨阩阫阬阭阯阰阷阸阹阺阾陁陃陊陎陏陑陒陓陖陗�陘陙陚陜陝陞陠陣陥陦陫陭陮陯陰陱陳陸陹険陻陼陽陾陿隀隁隂隃隄隇隉隊辍辎辏辘辚軎戋戗戛戟戢戡戥戤戬臧瓯瓴瓿甏甑甓攴旮旯旰昊昙杲昃昕昀炅曷昝昴昱昶昵耆晟晔晁晏晖晡晗晷暄暌暧暝暾曛曜曦曩贲贳贶贻贽赀赅赆赈赉赇赍赕赙觇觊觋觌觎觏觐觑牮犟牝牦牯牾牿犄犋犍犏犒挈挲掰�".split(""); +for(j = 0; j != D[234].length; ++j) if(D[234][j].charCodeAt(0) !== 0xFFFD) { e[D[234][j]] = 59904 + j; d[59904 + j] = D[234][j];} +D[235] = "����������������������������������������������������������������隌階隑隒隓隕隖隚際隝隞隟隠隡隢隣隤隥隦隨隩險隫隬隭隮隯隱隲隴隵隷隸隺隻隿雂雃雈雊雋雐雑雓雔雖雗雘雙雚雛雜雝雞雟雡離難雤雥雦雧雫�雬雭雮雰雱雲雴雵雸雺電雼雽雿霂霃霅霊霋霌霐霑霒霔霕霗霘霙霚霛霝霟霠搿擘耄毪毳毽毵毹氅氇氆氍氕氘氙氚氡氩氤氪氲攵敕敫牍牒牖爰虢刖肟肜肓肼朊肽肱肫肭肴肷胧胨胩胪胛胂胄胙胍胗朐胝胫胱胴胭脍脎胲胼朕脒豚脶脞脬脘脲腈腌腓腴腙腚腱腠腩腼腽腭腧塍媵膈膂膑滕膣膪臌朦臊膻�".split(""); +for(j = 0; j != D[235].length; ++j) if(D[235][j].charCodeAt(0) !== 0xFFFD) { e[D[235][j]] = 60160 + j; d[60160 + j] = D[235][j];} +D[236] = "����������������������������������������������������������������霡霢霣霤霥霦霧霨霩霫霬霮霯霱霳霴霵霶霷霺霻霼霽霿靀靁靂靃靄靅靆靇靈靉靊靋靌靍靎靏靐靑靔靕靗靘靚靜靝靟靣靤靦靧靨靪靫靬靭靮靯靰靱�靲靵靷靸靹靺靻靽靾靿鞀鞁鞂鞃鞄鞆鞇鞈鞉鞊鞌鞎鞏鞐鞓鞕鞖鞗鞙鞚鞛鞜鞝臁膦欤欷欹歃歆歙飑飒飓飕飙飚殳彀毂觳斐齑斓於旆旄旃旌旎旒旖炀炜炖炝炻烀炷炫炱烨烊焐焓焖焯焱煳煜煨煅煲煊煸煺熘熳熵熨熠燠燔燧燹爝爨灬焘煦熹戾戽扃扈扉礻祀祆祉祛祜祓祚祢祗祠祯祧祺禅禊禚禧禳忑忐�".split(""); +for(j = 0; j != D[236].length; ++j) if(D[236][j].charCodeAt(0) !== 0xFFFD) { e[D[236][j]] = 60416 + j; d[60416 + j] = D[236][j];} +D[237] = "����������������������������������������������������������������鞞鞟鞡鞢鞤鞥鞦鞧鞨鞩鞪鞬鞮鞰鞱鞳鞵鞶鞷鞸鞹鞺鞻鞼鞽鞾鞿韀韁韂韃韄韅韆韇韈韉韊韋韌韍韎韏韐韑韒韓韔韕韖韗韘韙韚韛韜韝韞韟韠韡韢韣�韤韥韨韮韯韰韱韲韴韷韸韹韺韻韼韽韾響頀頁頂頃頄項順頇須頉頊頋頌頍頎怼恝恚恧恁恙恣悫愆愍慝憩憝懋懑戆肀聿沓泶淼矶矸砀砉砗砘砑斫砭砜砝砹砺砻砟砼砥砬砣砩硎硭硖硗砦硐硇硌硪碛碓碚碇碜碡碣碲碹碥磔磙磉磬磲礅磴礓礤礞礴龛黹黻黼盱眄眍盹眇眈眚眢眙眭眦眵眸睐睑睇睃睚睨�".split(""); +for(j = 0; j != D[237].length; ++j) if(D[237][j].charCodeAt(0) !== 0xFFFD) { e[D[237][j]] = 60672 + j; d[60672 + j] = D[237][j];} +D[238] = "����������������������������������������������������������������頏預頑頒頓頔頕頖頗領頙頚頛頜頝頞頟頠頡頢頣頤頥頦頧頨頩頪頫頬頭頮頯頰頱頲頳頴頵頶頷頸頹頺頻頼頽頾頿顀顁顂顃顄顅顆顇顈顉顊顋題額�顎顏顐顑顒顓顔顕顖顗願顙顚顛顜顝類顟顠顡顢顣顤顥顦顧顨顩顪顫顬顭顮睢睥睿瞍睽瞀瞌瞑瞟瞠瞰瞵瞽町畀畎畋畈畛畲畹疃罘罡罟詈罨罴罱罹羁罾盍盥蠲钅钆钇钋钊钌钍钏钐钔钗钕钚钛钜钣钤钫钪钭钬钯钰钲钴钶钷钸钹钺钼钽钿铄铈铉铊铋铌铍铎铐铑铒铕铖铗铙铘铛铞铟铠铢铤铥铧铨铪�".split(""); +for(j = 0; j != D[238].length; ++j) if(D[238][j].charCodeAt(0) !== 0xFFFD) { e[D[238][j]] = 60928 + j; d[60928 + j] = D[238][j];} +D[239] = "����������������������������������������������������������������顯顰顱顲顳顴颋颎颒颕颙颣風颩颪颫颬颭颮颯颰颱颲颳颴颵颶颷颸颹颺颻颼颽颾颿飀飁飂飃飄飅飆飇飈飉飊飋飌飍飏飐飔飖飗飛飜飝飠飡飢飣飤�飥飦飩飪飫飬飭飮飯飰飱飲飳飴飵飶飷飸飹飺飻飼飽飾飿餀餁餂餃餄餅餆餇铩铫铮铯铳铴铵铷铹铼铽铿锃锂锆锇锉锊锍锎锏锒锓锔锕锖锘锛锝锞锟锢锪锫锩锬锱锲锴锶锷锸锼锾锿镂锵镄镅镆镉镌镎镏镒镓镔镖镗镘镙镛镞镟镝镡镢镤镥镦镧镨镩镪镫镬镯镱镲镳锺矧矬雉秕秭秣秫稆嵇稃稂稞稔�".split(""); +for(j = 0; j != D[239].length; ++j) if(D[239][j].charCodeAt(0) !== 0xFFFD) { e[D[239][j]] = 61184 + j; d[61184 + j] = D[239][j];} +D[240] = "����������������������������������������������������������������餈餉養餋餌餎餏餑餒餓餔餕餖餗餘餙餚餛餜餝餞餟餠餡餢餣餤餥餦餧館餩餪餫餬餭餯餰餱餲餳餴餵餶餷餸餹餺餻餼餽餾餿饀饁饂饃饄饅饆饇饈饉�饊饋饌饍饎饏饐饑饒饓饖饗饘饙饚饛饜饝饞饟饠饡饢饤饦饳饸饹饻饾馂馃馉稹稷穑黏馥穰皈皎皓皙皤瓞瓠甬鸠鸢鸨鸩鸪鸫鸬鸲鸱鸶鸸鸷鸹鸺鸾鹁鹂鹄鹆鹇鹈鹉鹋鹌鹎鹑鹕鹗鹚鹛鹜鹞鹣鹦鹧鹨鹩鹪鹫鹬鹱鹭鹳疒疔疖疠疝疬疣疳疴疸痄疱疰痃痂痖痍痣痨痦痤痫痧瘃痱痼痿瘐瘀瘅瘌瘗瘊瘥瘘瘕瘙�".split(""); +for(j = 0; j != D[240].length; ++j) if(D[240][j].charCodeAt(0) !== 0xFFFD) { e[D[240][j]] = 61440 + j; d[61440 + j] = D[240][j];} +D[241] = "����������������������������������������������������������������馌馎馚馛馜馝馞馟馠馡馢馣馤馦馧馩馪馫馬馭馮馯馰馱馲馳馴馵馶馷馸馹馺馻馼馽馾馿駀駁駂駃駄駅駆駇駈駉駊駋駌駍駎駏駐駑駒駓駔駕駖駗駘�駙駚駛駜駝駞駟駠駡駢駣駤駥駦駧駨駩駪駫駬駭駮駯駰駱駲駳駴駵駶駷駸駹瘛瘼瘢瘠癀瘭瘰瘿瘵癃瘾瘳癍癞癔癜癖癫癯翊竦穸穹窀窆窈窕窦窠窬窨窭窳衤衩衲衽衿袂袢裆袷袼裉裢裎裣裥裱褚裼裨裾裰褡褙褓褛褊褴褫褶襁襦襻疋胥皲皴矜耒耔耖耜耠耢耥耦耧耩耨耱耋耵聃聆聍聒聩聱覃顸颀颃�".split(""); +for(j = 0; j != D[241].length; ++j) if(D[241][j].charCodeAt(0) !== 0xFFFD) { e[D[241][j]] = 61696 + j; d[61696 + j] = D[241][j];} +D[242] = "����������������������������������������������������������������駺駻駼駽駾駿騀騁騂騃騄騅騆騇騈騉騊騋騌騍騎騏騐騑騒験騔騕騖騗騘騙騚騛騜騝騞騟騠騡騢騣騤騥騦騧騨騩騪騫騬騭騮騯騰騱騲騳騴騵騶騷騸�騹騺騻騼騽騾騿驀驁驂驃驄驅驆驇驈驉驊驋驌驍驎驏驐驑驒驓驔驕驖驗驘驙颉颌颍颏颔颚颛颞颟颡颢颥颦虍虔虬虮虿虺虼虻蚨蚍蚋蚬蚝蚧蚣蚪蚓蚩蚶蛄蚵蛎蚰蚺蚱蚯蛉蛏蚴蛩蛱蛲蛭蛳蛐蜓蛞蛴蛟蛘蛑蜃蜇蛸蜈蜊蜍蜉蜣蜻蜞蜥蜮蜚蜾蝈蜴蜱蜩蜷蜿螂蜢蝽蝾蝻蝠蝰蝌蝮螋蝓蝣蝼蝤蝙蝥螓螯螨蟒�".split(""); +for(j = 0; j != D[242].length; ++j) if(D[242][j].charCodeAt(0) !== 0xFFFD) { e[D[242][j]] = 61952 + j; d[61952 + j] = D[242][j];} +D[243] = "����������������������������������������������������������������驚驛驜驝驞驟驠驡驢驣驤驥驦驧驨驩驪驫驲骃骉骍骎骔骕骙骦骩骪骫骬骭骮骯骲骳骴骵骹骻骽骾骿髃髄髆髇髈髉髊髍髎髏髐髒體髕髖髗髙髚髛髜�髝髞髠髢髣髤髥髧髨髩髪髬髮髰髱髲髳髴髵髶髷髸髺髼髽髾髿鬀鬁鬂鬄鬅鬆蟆螈螅螭螗螃螫蟥螬螵螳蟋蟓螽蟑蟀蟊蟛蟪蟠蟮蠖蠓蟾蠊蠛蠡蠹蠼缶罂罄罅舐竺竽笈笃笄笕笊笫笏筇笸笪笙笮笱笠笥笤笳笾笞筘筚筅筵筌筝筠筮筻筢筲筱箐箦箧箸箬箝箨箅箪箜箢箫箴篑篁篌篝篚篥篦篪簌篾篼簏簖簋�".split(""); +for(j = 0; j != D[243].length; ++j) if(D[243][j].charCodeAt(0) !== 0xFFFD) { e[D[243][j]] = 62208 + j; d[62208 + j] = D[243][j];} +D[244] = "����������������������������������������������������������������鬇鬉鬊鬋鬌鬍鬎鬐鬑鬒鬔鬕鬖鬗鬘鬙鬚鬛鬜鬝鬞鬠鬡鬢鬤鬥鬦鬧鬨鬩鬪鬫鬬鬭鬮鬰鬱鬳鬴鬵鬶鬷鬸鬹鬺鬽鬾鬿魀魆魊魋魌魎魐魒魓魕魖魗魘魙魚�魛魜魝魞魟魠魡魢魣魤魥魦魧魨魩魪魫魬魭魮魯魰魱魲魳魴魵魶魷魸魹魺魻簟簪簦簸籁籀臾舁舂舄臬衄舡舢舣舭舯舨舫舸舻舳舴舾艄艉艋艏艚艟艨衾袅袈裘裟襞羝羟羧羯羰羲籼敉粑粝粜粞粢粲粼粽糁糇糌糍糈糅糗糨艮暨羿翎翕翥翡翦翩翮翳糸絷綦綮繇纛麸麴赳趄趔趑趱赧赭豇豉酊酐酎酏酤�".split(""); +for(j = 0; j != D[244].length; ++j) if(D[244][j].charCodeAt(0) !== 0xFFFD) { e[D[244][j]] = 62464 + j; d[62464 + j] = D[244][j];} +D[245] = "����������������������������������������������������������������魼魽魾魿鮀鮁鮂鮃鮄鮅鮆鮇鮈鮉鮊鮋鮌鮍鮎鮏鮐鮑鮒鮓鮔鮕鮖鮗鮘鮙鮚鮛鮜鮝鮞鮟鮠鮡鮢鮣鮤鮥鮦鮧鮨鮩鮪鮫鮬鮭鮮鮯鮰鮱鮲鮳鮴鮵鮶鮷鮸鮹鮺�鮻鮼鮽鮾鮿鯀鯁鯂鯃鯄鯅鯆鯇鯈鯉鯊鯋鯌鯍鯎鯏鯐鯑鯒鯓鯔鯕鯖鯗鯘鯙鯚鯛酢酡酰酩酯酽酾酲酴酹醌醅醐醍醑醢醣醪醭醮醯醵醴醺豕鹾趸跫踅蹙蹩趵趿趼趺跄跖跗跚跞跎跏跛跆跬跷跸跣跹跻跤踉跽踔踝踟踬踮踣踯踺蹀踹踵踽踱蹉蹁蹂蹑蹒蹊蹰蹶蹼蹯蹴躅躏躔躐躜躞豸貂貊貅貘貔斛觖觞觚觜�".split(""); +for(j = 0; j != D[245].length; ++j) if(D[245][j].charCodeAt(0) !== 0xFFFD) { e[D[245][j]] = 62720 + j; d[62720 + j] = D[245][j];} +D[246] = "����������������������������������������������������������������鯜鯝鯞鯟鯠鯡鯢鯣鯤鯥鯦鯧鯨鯩鯪鯫鯬鯭鯮鯯鯰鯱鯲鯳鯴鯵鯶鯷鯸鯹鯺鯻鯼鯽鯾鯿鰀鰁鰂鰃鰄鰅鰆鰇鰈鰉鰊鰋鰌鰍鰎鰏鰐鰑鰒鰓鰔鰕鰖鰗鰘鰙鰚�鰛鰜鰝鰞鰟鰠鰡鰢鰣鰤鰥鰦鰧鰨鰩鰪鰫鰬鰭鰮鰯鰰鰱鰲鰳鰴鰵鰶鰷鰸鰹鰺鰻觥觫觯訾謦靓雩雳雯霆霁霈霏霎霪霭霰霾龀龃龅龆龇龈龉龊龌黾鼋鼍隹隼隽雎雒瞿雠銎銮鋈錾鍪鏊鎏鐾鑫鱿鲂鲅鲆鲇鲈稣鲋鲎鲐鲑鲒鲔鲕鲚鲛鲞鲟鲠鲡鲢鲣鲥鲦鲧鲨鲩鲫鲭鲮鲰鲱鲲鲳鲴鲵鲶鲷鲺鲻鲼鲽鳄鳅鳆鳇鳊鳋�".split(""); +for(j = 0; j != D[246].length; ++j) if(D[246][j].charCodeAt(0) !== 0xFFFD) { e[D[246][j]] = 62976 + j; d[62976 + j] = D[246][j];} +D[247] = "����������������������������������������������������������������鰼鰽鰾鰿鱀鱁鱂鱃鱄鱅鱆鱇鱈鱉鱊鱋鱌鱍鱎鱏鱐鱑鱒鱓鱔鱕鱖鱗鱘鱙鱚鱛鱜鱝鱞鱟鱠鱡鱢鱣鱤鱥鱦鱧鱨鱩鱪鱫鱬鱭鱮鱯鱰鱱鱲鱳鱴鱵鱶鱷鱸鱹鱺�鱻鱽鱾鲀鲃鲄鲉鲊鲌鲏鲓鲖鲗鲘鲙鲝鲪鲬鲯鲹鲾鲿鳀鳁鳂鳈鳉鳑鳒鳚鳛鳠鳡鳌鳍鳎鳏鳐鳓鳔鳕鳗鳘鳙鳜鳝鳟鳢靼鞅鞑鞒鞔鞯鞫鞣鞲鞴骱骰骷鹘骶骺骼髁髀髅髂髋髌髑魅魃魇魉魈魍魑飨餍餮饕饔髟髡髦髯髫髻髭髹鬈鬏鬓鬟鬣麽麾縻麂麇麈麋麒鏖麝麟黛黜黝黠黟黢黩黧黥黪黯鼢鼬鼯鼹鼷鼽鼾齄�".split(""); +for(j = 0; j != D[247].length; ++j) if(D[247][j].charCodeAt(0) !== 0xFFFD) { e[D[247][j]] = 63232 + j; d[63232 + j] = D[247][j];} +D[248] = "����������������������������������������������������������������鳣鳤鳥鳦鳧鳨鳩鳪鳫鳬鳭鳮鳯鳰鳱鳲鳳鳴鳵鳶鳷鳸鳹鳺鳻鳼鳽鳾鳿鴀鴁鴂鴃鴄鴅鴆鴇鴈鴉鴊鴋鴌鴍鴎鴏鴐鴑鴒鴓鴔鴕鴖鴗鴘鴙鴚鴛鴜鴝鴞鴟鴠鴡�鴢鴣鴤鴥鴦鴧鴨鴩鴪鴫鴬鴭鴮鴯鴰鴱鴲鴳鴴鴵鴶鴷鴸鴹鴺鴻鴼鴽鴾鴿鵀鵁鵂�����������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[248].length; ++j) if(D[248][j].charCodeAt(0) !== 0xFFFD) { e[D[248][j]] = 63488 + j; d[63488 + j] = D[248][j];} +D[249] = "����������������������������������������������������������������鵃鵄鵅鵆鵇鵈鵉鵊鵋鵌鵍鵎鵏鵐鵑鵒鵓鵔鵕鵖鵗鵘鵙鵚鵛鵜鵝鵞鵟鵠鵡鵢鵣鵤鵥鵦鵧鵨鵩鵪鵫鵬鵭鵮鵯鵰鵱鵲鵳鵴鵵鵶鵷鵸鵹鵺鵻鵼鵽鵾鵿鶀鶁�鶂鶃鶄鶅鶆鶇鶈鶉鶊鶋鶌鶍鶎鶏鶐鶑鶒鶓鶔鶕鶖鶗鶘鶙鶚鶛鶜鶝鶞鶟鶠鶡鶢�����������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[249].length; ++j) if(D[249][j].charCodeAt(0) !== 0xFFFD) { e[D[249][j]] = 63744 + j; d[63744 + j] = D[249][j];} +D[250] = "����������������������������������������������������������������鶣鶤鶥鶦鶧鶨鶩鶪鶫鶬鶭鶮鶯鶰鶱鶲鶳鶴鶵鶶鶷鶸鶹鶺鶻鶼鶽鶾鶿鷀鷁鷂鷃鷄鷅鷆鷇鷈鷉鷊鷋鷌鷍鷎鷏鷐鷑鷒鷓鷔鷕鷖鷗鷘鷙鷚鷛鷜鷝鷞鷟鷠鷡�鷢鷣鷤鷥鷦鷧鷨鷩鷪鷫鷬鷭鷮鷯鷰鷱鷲鷳鷴鷵鷶鷷鷸鷹鷺鷻鷼鷽鷾鷿鸀鸁鸂�����������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[250].length; ++j) if(D[250][j].charCodeAt(0) !== 0xFFFD) { e[D[250][j]] = 64000 + j; d[64000 + j] = D[250][j];} +D[251] = "����������������������������������������������������������������鸃鸄鸅鸆鸇鸈鸉鸊鸋鸌鸍鸎鸏鸐鸑鸒鸓鸔鸕鸖鸗鸘鸙鸚鸛鸜鸝鸞鸤鸧鸮鸰鸴鸻鸼鹀鹍鹐鹒鹓鹔鹖鹙鹝鹟鹠鹡鹢鹥鹮鹯鹲鹴鹵鹶鹷鹸鹹鹺鹻鹼鹽麀�麁麃麄麅麆麉麊麌麍麎麏麐麑麔麕麖麗麘麙麚麛麜麞麠麡麢麣麤麥麧麨麩麪�����������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[251].length; ++j) if(D[251][j].charCodeAt(0) !== 0xFFFD) { e[D[251][j]] = 64256 + j; d[64256 + j] = D[251][j];} +D[252] = "����������������������������������������������������������������麫麬麭麮麯麰麱麲麳麵麶麷麹麺麼麿黀黁黂黃黅黆黇黈黊黋黌黐黒黓黕黖黗黙黚點黡黣黤黦黨黫黬黭黮黰黱黲黳黴黵黶黷黸黺黽黿鼀鼁鼂鼃鼄鼅�鼆鼇鼈鼉鼊鼌鼏鼑鼒鼔鼕鼖鼘鼚鼛鼜鼝鼞鼟鼡鼣鼤鼥鼦鼧鼨鼩鼪鼫鼭鼮鼰鼱�����������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[252].length; ++j) if(D[252][j].charCodeAt(0) !== 0xFFFD) { e[D[252][j]] = 64512 + j; d[64512 + j] = D[252][j];} +D[253] = "����������������������������������������������������������������鼲鼳鼴鼵鼶鼸鼺鼼鼿齀齁齂齃齅齆齇齈齉齊齋齌齍齎齏齒齓齔齕齖齗齘齙齚齛齜齝齞齟齠齡齢齣齤齥齦齧齨齩齪齫齬齭齮齯齰齱齲齳齴齵齶齷齸�齹齺齻齼齽齾龁龂龍龎龏龐龑龒龓龔龕龖龗龘龜龝龞龡龢龣龤龥郎凉秊裏隣�����������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[253].length; ++j) if(D[253][j].charCodeAt(0) !== 0xFFFD) { e[D[253][j]] = 64768 + j; d[64768 + j] = D[253][j];} +D[254] = "����������������������������������������������������������������兀嗀﨎﨏﨑﨓﨔礼﨟蘒﨡﨣﨤﨧﨨﨩��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[254].length; ++j) if(D[254][j].charCodeAt(0) !== 0xFFFD) { e[D[254][j]] = 65024 + j; d[65024 + j] = D[254][j];} +return {"enc": e, "dec": d }; })(); +cptable[949] = (function(){ var d = [], e = {}, D = [], j; +D[0] = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~��������������������������������������������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[0].length; ++j) if(D[0][j].charCodeAt(0) !== 0xFFFD) { e[D[0][j]] = 0 + j; d[0 + j] = D[0][j];} +D[129] = "�����������������������������������������������������������������갂갃갅갆갋갌갍갎갏갘갞갟갡갢갣갥갦갧갨갩갪갫갮갲갳갴������갵갶갷갺갻갽갾갿걁걂걃걄걅걆걇걈걉걊걌걎걏걐걑걒걓걕������걖걗걙걚걛걝걞걟걠걡걢걣걤걥걦걧걨걩걪걫걬걭걮걯걲걳걵걶걹걻걼걽걾걿겂겇겈겍겎겏겑겒겓겕겖겗겘겙겚겛겞겢겣겤겥겦겧겫겭겮겱겲겳겴겵겶겷겺겾겿곀곂곃곅곆곇곉곊곋곍곎곏곐곑곒곓곔곖곘곙곚곛곜곝곞곟곢곣곥곦곩곫곭곮곲곴곷곸곹곺곻곾곿괁괂괃괅괇괈괉괊괋괎괐괒괓�".split(""); +for(j = 0; j != D[129].length; ++j) if(D[129][j].charCodeAt(0) !== 0xFFFD) { e[D[129][j]] = 33024 + j; d[33024 + j] = D[129][j];} +D[130] = "�����������������������������������������������������������������괔괕괖괗괙괚괛괝괞괟괡괢괣괤괥괦괧괨괪괫괮괯괰괱괲괳������괶괷괹괺괻괽괾괿굀굁굂굃굆굈굊굋굌굍굎굏굑굒굓굕굖굗������굙굚굛굜굝굞굟굠굢굤굥굦굧굨굩굪굫굮굯굱굲굷굸굹굺굾궀궃궄궅궆궇궊궋궍궎궏궑궒궓궔궕궖궗궘궙궚궛궞궟궠궡궢궣궥궦궧궨궩궪궫궬궭궮궯궰궱궲궳궴궵궶궸궹궺궻궼궽궾궿귂귃귅귆귇귉귊귋귌귍귎귏귒귔귕귖귗귘귙귚귛귝귞귟귡귢귣귥귦귧귨귩귪귫귬귭귮귯귰귱귲귳귴귵귶귷�".split(""); +for(j = 0; j != D[130].length; ++j) if(D[130][j].charCodeAt(0) !== 0xFFFD) { e[D[130][j]] = 33280 + j; d[33280 + j] = D[130][j];} +D[131] = "�����������������������������������������������������������������귺귻귽귾긂긃긄긅긆긇긊긌긎긏긐긑긒긓긕긖긗긘긙긚긛긜������긝긞긟긠긡긢긣긤긥긦긧긨긩긪긫긬긭긮긯긲긳긵긶긹긻긼������긽긾긿깂깄깇깈깉깋깏깑깒깓깕깗깘깙깚깛깞깢깣깤깦깧깪깫깭깮깯깱깲깳깴깵깶깷깺깾깿꺀꺁꺂꺃꺆꺇꺈꺉꺊꺋꺍꺎꺏꺐꺑꺒꺓꺔꺕꺖꺗꺘꺙꺚꺛꺜꺝꺞꺟꺠꺡꺢꺣꺤꺥꺦꺧꺨꺩꺪꺫꺬꺭꺮꺯꺰꺱꺲꺳꺴꺵꺶꺷꺸꺹꺺꺻꺿껁껂껃껅껆껇껈껉껊껋껎껒껓껔껕껖껗껚껛껝껞껟껠껡껢껣껤껥�".split(""); +for(j = 0; j != D[131].length; ++j) if(D[131][j].charCodeAt(0) !== 0xFFFD) { e[D[131][j]] = 33536 + j; d[33536 + j] = D[131][j];} +D[132] = "�����������������������������������������������������������������껦껧껩껪껬껮껯껰껱껲껳껵껶껷껹껺껻껽껾껿꼀꼁꼂꼃꼄꼅������꼆꼉꼊꼋꼌꼎꼏꼑꼒꼓꼔꼕꼖꼗꼘꼙꼚꼛꼜꼝꼞꼟꼠꼡꼢꼣������꼤꼥꼦꼧꼨꼩꼪꼫꼮꼯꼱꼳꼵꼶꼷꼸꼹꼺꼻꼾꽀꽄꽅꽆꽇꽊꽋꽌꽍꽎꽏꽑꽒꽓꽔꽕꽖꽗꽘꽙꽚꽛꽞꽟꽠꽡꽢꽣꽦꽧꽨꽩꽪꽫꽬꽭꽮꽯꽰꽱꽲꽳꽴꽵꽶꽷꽸꽺꽻꽼꽽꽾꽿꾁꾂꾃꾅꾆꾇꾉꾊꾋꾌꾍꾎꾏꾒꾓꾔꾖꾗꾘꾙꾚꾛꾝꾞꾟꾠꾡꾢꾣꾤꾥꾦꾧꾨꾩꾪꾫꾬꾭꾮꾯꾰꾱꾲꾳꾴꾵꾶꾷꾺꾻꾽꾾�".split(""); +for(j = 0; j != D[132].length; ++j) if(D[132][j].charCodeAt(0) !== 0xFFFD) { e[D[132][j]] = 33792 + j; d[33792 + j] = D[132][j];} +D[133] = "�����������������������������������������������������������������꾿꿁꿂꿃꿄꿅꿆꿊꿌꿏꿐꿑꿒꿓꿕꿖꿗꿘꿙꿚꿛꿝꿞꿟꿠꿡������꿢꿣꿤꿥꿦꿧꿪꿫꿬꿭꿮꿯꿲꿳꿵꿶꿷꿹꿺꿻꿼꿽꿾꿿뀂뀃������뀅뀆뀇뀈뀉뀊뀋뀍뀎뀏뀑뀒뀓뀕뀖뀗뀘뀙뀚뀛뀞뀟뀠뀡뀢뀣뀤뀥뀦뀧뀩뀪뀫뀬뀭뀮뀯뀰뀱뀲뀳뀴뀵뀶뀷뀸뀹뀺뀻뀼뀽뀾뀿끀끁끂끃끆끇끉끋끍끏끐끑끒끖끘끚끛끜끞끟끠끡끢끣끤끥끦끧끨끩끪끫끬끭끮끯끰끱끲끳끴끵끶끷끸끹끺끻끾끿낁낂낃낅낆낇낈낉낊낋낎낐낒낓낔낕낖낗낛낝낞낣낤�".split(""); +for(j = 0; j != D[133].length; ++j) if(D[133][j].charCodeAt(0) !== 0xFFFD) { e[D[133][j]] = 34048 + j; d[34048 + j] = D[133][j];} +D[134] = "�����������������������������������������������������������������낥낦낧낪낰낲낶낷낹낺낻낽낾낿냀냁냂냃냆냊냋냌냍냎냏냒������냓냕냖냗냙냚냛냜냝냞냟냡냢냣냤냦냧냨냩냪냫냬냭냮냯냰������냱냲냳냴냵냶냷냸냹냺냻냼냽냾냿넀넁넂넃넄넅넆넇넊넍넎넏넑넔넕넖넗넚넞넟넠넡넢넦넧넩넪넫넭넮넯넰넱넲넳넶넺넻넼넽넾넿녂녃녅녆녇녉녊녋녌녍녎녏녒녓녖녗녙녚녛녝녞녟녡녢녣녤녥녦녧녨녩녪녫녬녭녮녯녰녱녲녳녴녵녶녷녺녻녽녾녿놁놃놄놅놆놇놊놌놎놏놐놑놕놖놗놙놚놛놝�".split(""); +for(j = 0; j != D[134].length; ++j) if(D[134][j].charCodeAt(0) !== 0xFFFD) { e[D[134][j]] = 34304 + j; d[34304 + j] = D[134][j];} +D[135] = "�����������������������������������������������������������������놞놟놠놡놢놣놤놥놦놧놩놪놫놬놭놮놯놰놱놲놳놴놵놶놷놸������놹놺놻놼놽놾놿뇀뇁뇂뇃뇄뇅뇆뇇뇈뇉뇊뇋뇍뇎뇏뇑뇒뇓뇕������뇖뇗뇘뇙뇚뇛뇞뇠뇡뇢뇣뇤뇥뇦뇧뇪뇫뇭뇮뇯뇱뇲뇳뇴뇵뇶뇷뇸뇺뇼뇾뇿눀눁눂눃눆눇눉눊눍눎눏눐눑눒눓눖눘눚눛눜눝눞눟눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눵눶눷눸눹눺눻눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉙뉚뉛뉝뉞뉟뉡뉢뉣뉤뉥뉦뉧뉪뉫뉬뉭뉮�".split(""); +for(j = 0; j != D[135].length; ++j) if(D[135][j].charCodeAt(0) !== 0xFFFD) { e[D[135][j]] = 34560 + j; d[34560 + j] = D[135][j];} +D[136] = "�����������������������������������������������������������������뉯뉰뉱뉲뉳뉶뉷뉸뉹뉺뉻뉽뉾뉿늀늁늂늃늆늇늈늊늋늌늍늎������늏늒늓늕늖늗늛늜늝늞늟늢늤늧늨늩늫늭늮늯늱늲늳늵늶늷������늸늹늺늻늼늽늾늿닀닁닂닃닄닅닆닇닊닋닍닎닏닑닓닔닕닖닗닚닜닞닟닠닡닣닧닩닪닰닱닲닶닼닽닾댂댃댅댆댇댉댊댋댌댍댎댏댒댖댗댘댙댚댛댝댞댟댠댡댢댣댤댥댦댧댨댩댪댫댬댭댮댯댰댱댲댳댴댵댶댷댸댹댺댻댼댽댾댿덀덁덂덃덄덅덆덇덈덉덊덋덌덍덎덏덐덑덒덓덗덙덚덝덠덡덢덣�".split(""); +for(j = 0; j != D[136].length; ++j) if(D[136][j].charCodeAt(0) !== 0xFFFD) { e[D[136][j]] = 34816 + j; d[34816 + j] = D[136][j];} +D[137] = "�����������������������������������������������������������������덦덨덪덬덭덯덲덳덵덶덷덹덺덻덼덽덾덿뎂뎆뎇뎈뎉뎊뎋뎍������뎎뎏뎑뎒뎓뎕뎖뎗뎘뎙뎚뎛뎜뎝뎞뎟뎢뎣뎤뎥뎦뎧뎩뎪뎫뎭������뎮뎯뎰뎱뎲뎳뎴뎵뎶뎷뎸뎹뎺뎻뎼뎽뎾뎿돀돁돂돃돆돇돉돊돍돏돑돒돓돖돘돚돜돞돟돡돢돣돥돦돧돩돪돫돬돭돮돯돰돱돲돳돴돵돶돷돸돹돺돻돽돾돿됀됁됂됃됄됅됆됇됈됉됊됋됌됍됎됏됑됒됓됔됕됖됗됙됚됛됝됞됟됡됢됣됤됥됦됧됪됬됭됮됯됰됱됲됳됵됶됷됸됹됺됻됼됽됾됿둀둁둂둃둄�".split(""); +for(j = 0; j != D[137].length; ++j) if(D[137][j].charCodeAt(0) !== 0xFFFD) { e[D[137][j]] = 35072 + j; d[35072 + j] = D[137][j];} +D[138] = "�����������������������������������������������������������������둅둆둇둈둉둊둋둌둍둎둏둒둓둕둖둗둙둚둛둜둝둞둟둢둤둦������둧둨둩둪둫둭둮둯둰둱둲둳둴둵둶둷둸둹둺둻둼둽둾둿뒁뒂������뒃뒄뒅뒆뒇뒉뒊뒋뒌뒍뒎뒏뒐뒑뒒뒓뒔뒕뒖뒗뒘뒙뒚뒛뒜뒞뒟뒠뒡뒢뒣뒥뒦뒧뒩뒪뒫뒭뒮뒯뒰뒱뒲뒳뒴뒶뒸뒺뒻뒼뒽뒾뒿듁듂듃듅듆듇듉듊듋듌듍듎듏듑듒듓듔듖듗듘듙듚듛듞듟듡듢듥듧듨듩듪듫듮듰듲듳듴듵듶듷듹듺듻듼듽듾듿딀딁딂딃딄딅딆딇딈딉딊딋딌딍딎딏딐딑딒딓딖딗딙딚딝�".split(""); +for(j = 0; j != D[138].length; ++j) if(D[138][j].charCodeAt(0) !== 0xFFFD) { e[D[138][j]] = 35328 + j; d[35328 + j] = D[138][j];} +D[139] = "�����������������������������������������������������������������딞딟딠딡딢딣딦딫딬딭딮딯딲딳딵딶딷딹딺딻딼딽딾딿땂땆������땇땈땉땊땎땏땑땒땓땕땖땗땘땙땚땛땞땢땣땤땥땦땧땨땩땪������땫땬땭땮땯땰땱땲땳땴땵땶땷땸땹땺땻땼땽땾땿떀떁떂떃떄떅떆떇떈떉떊떋떌떍떎떏떐떑떒떓떔떕떖떗떘떙떚떛떜떝떞떟떢떣떥떦떧떩떬떭떮떯떲떶떷떸떹떺떾떿뗁뗂뗃뗅뗆뗇뗈뗉뗊뗋뗎뗒뗓뗔뗕뗖뗗뗙뗚뗛뗜뗝뗞뗟뗠뗡뗢뗣뗤뗥뗦뗧뗨뗩뗪뗫뗭뗮뗯뗰뗱뗲뗳뗴뗵뗶뗷뗸뗹뗺뗻뗼뗽뗾뗿�".split(""); +for(j = 0; j != D[139].length; ++j) if(D[139][j].charCodeAt(0) !== 0xFFFD) { e[D[139][j]] = 35584 + j; d[35584 + j] = D[139][j];} +D[140] = "�����������������������������������������������������������������똀똁똂똃똄똅똆똇똈똉똊똋똌똍똎똏똒똓똕똖똗똙똚똛똜똝������똞똟똠똡똢똣똤똦똧똨똩똪똫똭똮똯똰똱똲똳똵똶똷똸똹똺������똻똼똽똾똿뙀뙁뙂뙃뙄뙅뙆뙇뙉뙊뙋뙌뙍뙎뙏뙐뙑뙒뙓뙔뙕뙖뙗뙘뙙뙚뙛뙜뙝뙞뙟뙠뙡뙢뙣뙥뙦뙧뙩뙪뙫뙬뙭뙮뙯뙰뙱뙲뙳뙴뙵뙶뙷뙸뙹뙺뙻뙼뙽뙾뙿뚀뚁뚂뚃뚄뚅뚆뚇뚈뚉뚊뚋뚌뚍뚎뚏뚐뚑뚒뚓뚔뚕뚖뚗뚘뚙뚚뚛뚞뚟뚡뚢뚣뚥뚦뚧뚨뚩뚪뚭뚮뚯뚰뚲뚳뚴뚵뚶뚷뚸뚹뚺뚻뚼뚽뚾뚿뛀뛁뛂�".split(""); +for(j = 0; j != D[140].length; ++j) if(D[140][j].charCodeAt(0) !== 0xFFFD) { e[D[140][j]] = 35840 + j; d[35840 + j] = D[140][j];} +D[141] = "�����������������������������������������������������������������뛃뛄뛅뛆뛇뛈뛉뛊뛋뛌뛍뛎뛏뛐뛑뛒뛓뛕뛖뛗뛘뛙뛚뛛뛜뛝������뛞뛟뛠뛡뛢뛣뛤뛥뛦뛧뛨뛩뛪뛫뛬뛭뛮뛯뛱뛲뛳뛵뛶뛷뛹뛺������뛻뛼뛽뛾뛿뜂뜃뜄뜆뜇뜈뜉뜊뜋뜌뜍뜎뜏뜐뜑뜒뜓뜔뜕뜖뜗뜘뜙뜚뜛뜜뜝뜞뜟뜠뜡뜢뜣뜤뜥뜦뜧뜪뜫뜭뜮뜱뜲뜳뜴뜵뜶뜷뜺뜼뜽뜾뜿띀띁띂띃띅띆띇띉띊띋띍띎띏띐띑띒띓띖띗띘띙띚띛띜띝띞띟띡띢띣띥띦띧띩띪띫띬띭띮띯띲띴띶띷띸띹띺띻띾띿랁랂랃랅랆랇랈랉랊랋랎랓랔랕랚랛랝랞�".split(""); +for(j = 0; j != D[141].length; ++j) if(D[141][j].charCodeAt(0) !== 0xFFFD) { e[D[141][j]] = 36096 + j; d[36096 + j] = D[141][j];} +D[142] = "�����������������������������������������������������������������랟랡랢랣랤랥랦랧랪랮랯랰랱랲랳랶랷랹랺랻랼랽랾랿럀럁������럂럃럄럅럆럈럊럋럌럍럎럏럐럑럒럓럔럕럖럗럘럙럚럛럜럝������럞럟럠럡럢럣럤럥럦럧럨럩럪럫럮럯럱럲럳럵럶럷럸럹럺럻럾렂렃렄렅렆렊렋렍렎렏렑렒렓렔렕렖렗렚렜렞렟렠렡렢렣렦렧렩렪렫렭렮렯렰렱렲렳렶렺렻렼렽렾렿롁롂롃롅롆롇롈롉롊롋롌롍롎롏롐롒롔롕롖롗롘롙롚롛롞롟롡롢롣롥롦롧롨롩롪롫롮롰롲롳롴롵롶롷롹롺롻롽롾롿뢀뢁뢂뢃뢄�".split(""); +for(j = 0; j != D[142].length; ++j) if(D[142][j].charCodeAt(0) !== 0xFFFD) { e[D[142][j]] = 36352 + j; d[36352 + j] = D[142][j];} +D[143] = "�����������������������������������������������������������������뢅뢆뢇뢈뢉뢊뢋뢌뢎뢏뢐뢑뢒뢓뢔뢕뢖뢗뢘뢙뢚뢛뢜뢝뢞뢟������뢠뢡뢢뢣뢤뢥뢦뢧뢩뢪뢫뢬뢭뢮뢯뢱뢲뢳뢵뢶뢷뢹뢺뢻뢼뢽������뢾뢿룂룄룆룇룈룉룊룋룍룎룏룑룒룓룕룖룗룘룙룚룛룜룞룠룢룣룤룥룦룧룪룫룭룮룯룱룲룳룴룵룶룷룺룼룾룿뤀뤁뤂뤃뤅뤆뤇뤈뤉뤊뤋뤌뤍뤎뤏뤐뤑뤒뤓뤔뤕뤖뤗뤙뤚뤛뤜뤝뤞뤟뤡뤢뤣뤤뤥뤦뤧뤨뤩뤪뤫뤬뤭뤮뤯뤰뤱뤲뤳뤴뤵뤶뤷뤸뤹뤺뤻뤾뤿륁륂륃륅륆륇륈륉륊륋륍륎륐륒륓륔륕륖륗�".split(""); +for(j = 0; j != D[143].length; ++j) if(D[143][j].charCodeAt(0) !== 0xFFFD) { e[D[143][j]] = 36608 + j; d[36608 + j] = D[143][j];} +D[144] = "�����������������������������������������������������������������륚륛륝륞륟륡륢륣륤륥륦륧륪륬륮륯륰륱륲륳륶륷륹륺륻륽������륾륿릀릁릂릃릆릈릋릌릏릐릑릒릓릔릕릖릗릘릙릚릛릜릝릞������릟릠릡릢릣릤릥릦릧릨릩릪릫릮릯릱릲릳릵릶릷릸릹릺릻릾맀맂맃맄맅맆맇맊맋맍맓맔맕맖맗맚맜맟맠맢맦맧맩맪맫맭맮맯맰맱맲맳맶맻맼맽맾맿먂먃먄먅먆먇먉먊먋먌먍먎먏먐먑먒먓먔먖먗먘먙먚먛먜먝먞먟먠먡먢먣먤먥먦먧먨먩먪먫먬먭먮먯먰먱먲먳먴먵먶먷먺먻먽먾먿멁멃멄멅멆�".split(""); +for(j = 0; j != D[144].length; ++j) if(D[144][j].charCodeAt(0) !== 0xFFFD) { e[D[144][j]] = 36864 + j; d[36864 + j] = D[144][j];} +D[145] = "�����������������������������������������������������������������멇멊멌멏멐멑멒멖멗멙멚멛멝멞멟멠멡멢멣멦멪멫멬멭멮멯������멲멳멵멶멷멹멺멻멼멽멾멿몀몁몂몆몈몉몊몋몍몎몏몐몑몒������몓몔몕몖몗몘몙몚몛몜몝몞몟몠몡몢몣몤몥몦몧몪몭몮몯몱몳몴몵몶몷몺몼몾몿뫀뫁뫂뫃뫅뫆뫇뫉뫊뫋뫌뫍뫎뫏뫐뫑뫒뫓뫔뫕뫖뫗뫚뫛뫜뫝뫞뫟뫠뫡뫢뫣뫤뫥뫦뫧뫨뫩뫪뫫뫬뫭뫮뫯뫰뫱뫲뫳뫴뫵뫶뫷뫸뫹뫺뫻뫽뫾뫿묁묂묃묅묆묇묈묉묊묋묌묎묐묒묓묔묕묖묗묙묚묛묝묞묟묡묢묣묤묥묦묧�".split(""); +for(j = 0; j != D[145].length; ++j) if(D[145][j].charCodeAt(0) !== 0xFFFD) { e[D[145][j]] = 37120 + j; d[37120 + j] = D[145][j];} +D[146] = "�����������������������������������������������������������������묨묪묬묭묮묯묰묱묲묳묷묹묺묿뭀뭁뭂뭃뭆뭈뭊뭋뭌뭎뭑뭒������뭓뭕뭖뭗뭙뭚뭛뭜뭝뭞뭟뭠뭢뭤뭥뭦뭧뭨뭩뭪뭫뭭뭮뭯뭰뭱������뭲뭳뭴뭵뭶뭷뭸뭹뭺뭻뭼뭽뭾뭿뮀뮁뮂뮃뮄뮅뮆뮇뮉뮊뮋뮍뮎뮏뮑뮒뮓뮔뮕뮖뮗뮘뮙뮚뮛뮜뮝뮞뮟뮠뮡뮢뮣뮥뮦뮧뮩뮪뮫뮭뮮뮯뮰뮱뮲뮳뮵뮶뮸뮹뮺뮻뮼뮽뮾뮿믁믂믃믅믆믇믉믊믋믌믍믎믏믑믒믔믕믖믗믘믙믚믛믜믝믞믟믠믡믢믣믤믥믦믧믨믩믪믫믬믭믮믯믰믱믲믳믴믵믶믷믺믻믽믾밁�".split(""); +for(j = 0; j != D[146].length; ++j) if(D[146][j].charCodeAt(0) !== 0xFFFD) { e[D[146][j]] = 37376 + j; d[37376 + j] = D[146][j];} +D[147] = "�����������������������������������������������������������������밃밄밅밆밇밊밎밐밒밓밙밚밠밡밢밣밦밨밪밫밬밮밯밲밳밵������밶밷밹밺밻밼밽밾밿뱂뱆뱇뱈뱊뱋뱎뱏뱑뱒뱓뱔뱕뱖뱗뱘뱙������뱚뱛뱜뱞뱟뱠뱡뱢뱣뱤뱥뱦뱧뱨뱩뱪뱫뱬뱭뱮뱯뱰뱱뱲뱳뱴뱵뱶뱷뱸뱹뱺뱻뱼뱽뱾뱿벀벁벂벃벆벇벉벊벍벏벐벑벒벓벖벘벛벜벝벞벟벢벣벥벦벩벪벫벬벭벮벯벲벶벷벸벹벺벻벾벿볁볂볃볅볆볇볈볉볊볋볌볎볒볓볔볖볗볙볚볛볝볞볟볠볡볢볣볤볥볦볧볨볩볪볫볬볭볮볯볰볱볲볳볷볹볺볻볽�".split(""); +for(j = 0; j != D[147].length; ++j) if(D[147][j].charCodeAt(0) !== 0xFFFD) { e[D[147][j]] = 37632 + j; d[37632 + j] = D[147][j];} +D[148] = "�����������������������������������������������������������������볾볿봀봁봂봃봆봈봊봋봌봍봎봏봑봒봓봕봖봗봘봙봚봛봜봝������봞봟봠봡봢봣봥봦봧봨봩봪봫봭봮봯봰봱봲봳봴봵봶봷봸봹������봺봻봼봽봾봿뵁뵂뵃뵄뵅뵆뵇뵊뵋뵍뵎뵏뵑뵒뵓뵔뵕뵖뵗뵚뵛뵜뵝뵞뵟뵠뵡뵢뵣뵥뵦뵧뵩뵪뵫뵬뵭뵮뵯뵰뵱뵲뵳뵴뵵뵶뵷뵸뵹뵺뵻뵼뵽뵾뵿붂붃붅붆붋붌붍붎붏붒붔붖붗붘붛붝붞붟붠붡붢붣붥붦붧붨붩붪붫붬붭붮붯붱붲붳붴붵붶붷붹붺붻붼붽붾붿뷀뷁뷂뷃뷄뷅뷆뷇뷈뷉뷊뷋뷌뷍뷎뷏뷐뷑�".split(""); +for(j = 0; j != D[148].length; ++j) if(D[148][j].charCodeAt(0) !== 0xFFFD) { e[D[148][j]] = 37888 + j; d[37888 + j] = D[148][j];} +D[149] = "�����������������������������������������������������������������뷒뷓뷖뷗뷙뷚뷛뷝뷞뷟뷠뷡뷢뷣뷤뷥뷦뷧뷨뷪뷫뷬뷭뷮뷯뷱������뷲뷳뷵뷶뷷뷹뷺뷻뷼뷽뷾뷿븁븂븄븆븇븈븉븊븋븎븏븑븒븓������븕븖븗븘븙븚븛븞븠븡븢븣븤븥븦븧븨븩븪븫븬븭븮븯븰븱븲븳븴븵븶븷븸븹븺븻븼븽븾븿빀빁빂빃빆빇빉빊빋빍빏빐빑빒빓빖빘빜빝빞빟빢빣빥빦빧빩빫빬빭빮빯빲빶빷빸빹빺빾빿뺁뺂뺃뺅뺆뺇뺈뺉뺊뺋뺎뺒뺓뺔뺕뺖뺗뺚뺛뺜뺝뺞뺟뺠뺡뺢뺣뺤뺥뺦뺧뺩뺪뺫뺬뺭뺮뺯뺰뺱뺲뺳뺴뺵뺶뺷�".split(""); +for(j = 0; j != D[149].length; ++j) if(D[149][j].charCodeAt(0) !== 0xFFFD) { e[D[149][j]] = 38144 + j; d[38144 + j] = D[149][j];} +D[150] = "�����������������������������������������������������������������뺸뺹뺺뺻뺼뺽뺾뺿뻀뻁뻂뻃뻄뻅뻆뻇뻈뻉뻊뻋뻌뻍뻎뻏뻒뻓������뻕뻖뻙뻚뻛뻜뻝뻞뻟뻡뻢뻦뻧뻨뻩뻪뻫뻭뻮뻯뻰뻱뻲뻳뻴뻵������뻶뻷뻸뻹뻺뻻뻼뻽뻾뻿뼀뼂뼃뼄뼅뼆뼇뼊뼋뼌뼍뼎뼏뼐뼑뼒뼓뼔뼕뼖뼗뼚뼞뼟뼠뼡뼢뼣뼤뼥뼦뼧뼨뼩뼪뼫뼬뼭뼮뼯뼰뼱뼲뼳뼴뼵뼶뼷뼸뼹뼺뼻뼼뼽뼾뼿뽂뽃뽅뽆뽇뽉뽊뽋뽌뽍뽎뽏뽒뽓뽔뽖뽗뽘뽙뽚뽛뽜뽝뽞뽟뽠뽡뽢뽣뽤뽥뽦뽧뽨뽩뽪뽫뽬뽭뽮뽯뽰뽱뽲뽳뽴뽵뽶뽷뽸뽹뽺뽻뽼뽽뽾뽿뾀뾁뾂�".split(""); +for(j = 0; j != D[150].length; ++j) if(D[150][j].charCodeAt(0) !== 0xFFFD) { e[D[150][j]] = 38400 + j; d[38400 + j] = D[150][j];} +D[151] = "�����������������������������������������������������������������뾃뾄뾅뾆뾇뾈뾉뾊뾋뾌뾍뾎뾏뾐뾑뾒뾓뾕뾖뾗뾘뾙뾚뾛뾜뾝������뾞뾟뾠뾡뾢뾣뾤뾥뾦뾧뾨뾩뾪뾫뾬뾭뾮뾯뾱뾲뾳뾴뾵뾶뾷뾸������뾹뾺뾻뾼뾽뾾뾿뿀뿁뿂뿃뿄뿆뿇뿈뿉뿊뿋뿎뿏뿑뿒뿓뿕뿖뿗뿘뿙뿚뿛뿝뿞뿠뿢뿣뿤뿥뿦뿧뿨뿩뿪뿫뿬뿭뿮뿯뿰뿱뿲뿳뿴뿵뿶뿷뿸뿹뿺뿻뿼뿽뿾뿿쀀쀁쀂쀃쀄쀅쀆쀇쀈쀉쀊쀋쀌쀍쀎쀏쀐쀑쀒쀓쀔쀕쀖쀗쀘쀙쀚쀛쀜쀝쀞쀟쀠쀡쀢쀣쀤쀥쀦쀧쀨쀩쀪쀫쀬쀭쀮쀯쀰쀱쀲쀳쀴쀵쀶쀷쀸쀹쀺쀻쀽쀾쀿�".split(""); +for(j = 0; j != D[151].length; ++j) if(D[151][j].charCodeAt(0) !== 0xFFFD) { e[D[151][j]] = 38656 + j; d[38656 + j] = D[151][j];} +D[152] = "�����������������������������������������������������������������쁀쁁쁂쁃쁄쁅쁆쁇쁈쁉쁊쁋쁌쁍쁎쁏쁐쁒쁓쁔쁕쁖쁗쁙쁚쁛������쁝쁞쁟쁡쁢쁣쁤쁥쁦쁧쁪쁫쁬쁭쁮쁯쁰쁱쁲쁳쁴쁵쁶쁷쁸쁹������쁺쁻쁼쁽쁾쁿삀삁삂삃삄삅삆삇삈삉삊삋삌삍삎삏삒삓삕삖삗삙삚삛삜삝삞삟삢삤삦삧삨삩삪삫삮삱삲삷삸삹삺삻삾샂샃샄샆샇샊샋샍샎샏샑샒샓샔샕샖샗샚샞샟샠샡샢샣샦샧샩샪샫샭샮샯샰샱샲샳샶샸샺샻샼샽샾샿섁섂섃섅섆섇섉섊섋섌섍섎섏섑섒섓섔섖섗섘섙섚섛섡섢섥섨섩섪섫섮�".split(""); +for(j = 0; j != D[152].length; ++j) if(D[152][j].charCodeAt(0) !== 0xFFFD) { e[D[152][j]] = 38912 + j; d[38912 + j] = D[152][j];} +D[153] = "�����������������������������������������������������������������섲섳섴섵섷섺섻섽섾섿셁셂셃셄셅셆셇셊셎셏셐셑셒셓셖셗������셙셚셛셝셞셟셠셡셢셣셦셪셫셬셭셮셯셱셲셳셵셶셷셹셺셻������셼셽셾셿솀솁솂솃솄솆솇솈솉솊솋솏솑솒솓솕솗솘솙솚솛솞솠솢솣솤솦솧솪솫솭솮솯솱솲솳솴솵솶솷솸솹솺솻솼솾솿쇀쇁쇂쇃쇅쇆쇇쇉쇊쇋쇍쇎쇏쇐쇑쇒쇓쇕쇖쇙쇚쇛쇜쇝쇞쇟쇡쇢쇣쇥쇦쇧쇩쇪쇫쇬쇭쇮쇯쇲쇴쇵쇶쇷쇸쇹쇺쇻쇾쇿숁숂숃숅숆숇숈숉숊숋숎숐숒숓숔숕숖숗숚숛숝숞숡숢숣�".split(""); +for(j = 0; j != D[153].length; ++j) if(D[153][j].charCodeAt(0) !== 0xFFFD) { e[D[153][j]] = 39168 + j; d[39168 + j] = D[153][j];} +D[154] = "�����������������������������������������������������������������숤숥숦숧숪숬숮숰숳숵숶숷숸숹숺숻숼숽숾숿쉀쉁쉂쉃쉄쉅������쉆쉇쉉쉊쉋쉌쉍쉎쉏쉒쉓쉕쉖쉗쉙쉚쉛쉜쉝쉞쉟쉡쉢쉣쉤쉦������쉧쉨쉩쉪쉫쉮쉯쉱쉲쉳쉵쉶쉷쉸쉹쉺쉻쉾슀슂슃슄슅슆슇슊슋슌슍슎슏슑슒슓슔슕슖슗슙슚슜슞슟슠슡슢슣슦슧슩슪슫슮슯슰슱슲슳슶슸슺슻슼슽슾슿싀싁싂싃싄싅싆싇싈싉싊싋싌싍싎싏싐싑싒싓싔싕싖싗싘싙싚싛싞싟싡싢싥싦싧싨싩싪싮싰싲싳싴싵싷싺싽싾싿쌁쌂쌃쌄쌅쌆쌇쌊쌋쌎쌏�".split(""); +for(j = 0; j != D[154].length; ++j) if(D[154][j].charCodeAt(0) !== 0xFFFD) { e[D[154][j]] = 39424 + j; d[39424 + j] = D[154][j];} +D[155] = "�����������������������������������������������������������������쌐쌑쌒쌖쌗쌙쌚쌛쌝쌞쌟쌠쌡쌢쌣쌦쌧쌪쌫쌬쌭쌮쌯쌰쌱쌲������쌳쌴쌵쌶쌷쌸쌹쌺쌻쌼쌽쌾쌿썀썁썂썃썄썆썇썈썉썊썋썌썍������썎썏썐썑썒썓썔썕썖썗썘썙썚썛썜썝썞썟썠썡썢썣썤썥썦썧썪썫썭썮썯썱썳썴썵썶썷썺썻썾썿쎀쎁쎂쎃쎅쎆쎇쎉쎊쎋쎍쎎쎏쎐쎑쎒쎓쎔쎕쎖쎗쎘쎙쎚쎛쎜쎝쎞쎟쎠쎡쎢쎣쎤쎥쎦쎧쎨쎩쎪쎫쎬쎭쎮쎯쎰쎱쎲쎳쎴쎵쎶쎷쎸쎹쎺쎻쎼쎽쎾쎿쏁쏂쏃쏄쏅쏆쏇쏈쏉쏊쏋쏌쏍쏎쏏쏐쏑쏒쏓쏔쏕쏖쏗쏚�".split(""); +for(j = 0; j != D[155].length; ++j) if(D[155][j].charCodeAt(0) !== 0xFFFD) { e[D[155][j]] = 39680 + j; d[39680 + j] = D[155][j];} +D[156] = "�����������������������������������������������������������������쏛쏝쏞쏡쏣쏤쏥쏦쏧쏪쏫쏬쏮쏯쏰쏱쏲쏳쏶쏷쏹쏺쏻쏼쏽쏾������쏿쐀쐁쐂쐃쐄쐅쐆쐇쐉쐊쐋쐌쐍쐎쐏쐑쐒쐓쐔쐕쐖쐗쐘쐙쐚������쐛쐜쐝쐞쐟쐠쐡쐢쐣쐥쐦쐧쐨쐩쐪쐫쐭쐮쐯쐱쐲쐳쐵쐶쐷쐸쐹쐺쐻쐾쐿쑀쑁쑂쑃쑄쑅쑆쑇쑉쑊쑋쑌쑍쑎쑏쑐쑑쑒쑓쑔쑕쑖쑗쑘쑙쑚쑛쑜쑝쑞쑟쑠쑡쑢쑣쑦쑧쑩쑪쑫쑭쑮쑯쑰쑱쑲쑳쑶쑷쑸쑺쑻쑼쑽쑾쑿쒁쒂쒃쒄쒅쒆쒇쒈쒉쒊쒋쒌쒍쒎쒏쒐쒑쒒쒓쒕쒖쒗쒘쒙쒚쒛쒝쒞쒟쒠쒡쒢쒣쒤쒥쒦쒧쒨쒩�".split(""); +for(j = 0; j != D[156].length; ++j) if(D[156][j].charCodeAt(0) !== 0xFFFD) { e[D[156][j]] = 39936 + j; d[39936 + j] = D[156][j];} +D[157] = "�����������������������������������������������������������������쒪쒫쒬쒭쒮쒯쒰쒱쒲쒳쒴쒵쒶쒷쒹쒺쒻쒽쒾쒿쓀쓁쓂쓃쓄쓅������쓆쓇쓈쓉쓊쓋쓌쓍쓎쓏쓐쓑쓒쓓쓔쓕쓖쓗쓘쓙쓚쓛쓜쓝쓞쓟������쓠쓡쓢쓣쓤쓥쓦쓧쓨쓪쓫쓬쓭쓮쓯쓲쓳쓵쓶쓷쓹쓻쓼쓽쓾씂씃씄씅씆씇씈씉씊씋씍씎씏씑씒씓씕씖씗씘씙씚씛씝씞씟씠씡씢씣씤씥씦씧씪씫씭씮씯씱씲씳씴씵씶씷씺씼씾씿앀앁앂앃앆앇앋앏앐앑앒앖앚앛앜앟앢앣앥앦앧앩앪앫앬앭앮앯앲앶앷앸앹앺앻앾앿얁얂얃얅얆얈얉얊얋얎얐얒얓얔�".split(""); +for(j = 0; j != D[157].length; ++j) if(D[157][j].charCodeAt(0) !== 0xFFFD) { e[D[157][j]] = 40192 + j; d[40192 + j] = D[157][j];} +D[158] = "�����������������������������������������������������������������얖얙얚얛얝얞얟얡얢얣얤얥얦얧얨얪얫얬얭얮얯얰얱얲얳얶������얷얺얿엀엁엂엃엋엍엏엒엓엕엖엗엙엚엛엜엝엞엟엢엤엦엧������엨엩엪엫엯엱엲엳엵엸엹엺엻옂옃옄옉옊옋옍옎옏옑옒옓옔옕옖옗옚옝옞옟옠옡옢옣옦옧옩옪옫옯옱옲옶옸옺옼옽옾옿왂왃왅왆왇왉왊왋왌왍왎왏왒왖왗왘왙왚왛왞왟왡왢왣왤왥왦왧왨왩왪왫왭왮왰왲왳왴왵왶왷왺왻왽왾왿욁욂욃욄욅욆욇욊욌욎욏욐욑욒욓욖욗욙욚욛욝욞욟욠욡욢욣욦�".split(""); +for(j = 0; j != D[158].length; ++j) if(D[158][j].charCodeAt(0) !== 0xFFFD) { e[D[158][j]] = 40448 + j; d[40448 + j] = D[158][j];} +D[159] = "�����������������������������������������������������������������욨욪욫욬욭욮욯욲욳욵욶욷욻욼욽욾욿웂웄웆웇웈웉웊웋웎������웏웑웒웓웕웖웗웘웙웚웛웞웟웢웣웤웥웦웧웪웫웭웮웯웱웲������웳웴웵웶웷웺웻웼웾웿윀윁윂윃윆윇윉윊윋윍윎윏윐윑윒윓윖윘윚윛윜윝윞윟윢윣윥윦윧윩윪윫윬윭윮윯윲윴윶윸윹윺윻윾윿읁읂읃읅읆읇읈읉읋읎읐읙읚읛읝읞읟읡읢읣읤읥읦읧읩읪읬읭읮읯읰읱읲읳읶읷읹읺읻읿잀잁잂잆잋잌잍잏잒잓잕잙잛잜잝잞잟잢잧잨잩잪잫잮잯잱잲잳잵잶잷�".split(""); +for(j = 0; j != D[159].length; ++j) if(D[159][j].charCodeAt(0) !== 0xFFFD) { e[D[159][j]] = 40704 + j; d[40704 + j] = D[159][j];} +D[160] = "�����������������������������������������������������������������잸잹잺잻잾쟂쟃쟄쟅쟆쟇쟊쟋쟍쟏쟑쟒쟓쟔쟕쟖쟗쟙쟚쟛쟜������쟞쟟쟠쟡쟢쟣쟥쟦쟧쟩쟪쟫쟭쟮쟯쟰쟱쟲쟳쟴쟵쟶쟷쟸쟹쟺������쟻쟼쟽쟾쟿젂젃젅젆젇젉젋젌젍젎젏젒젔젗젘젙젚젛젞젟젡젢젣젥젦젧젨젩젪젫젮젰젲젳젴젵젶젷젹젺젻젽젾젿졁졂졃졄졅졆졇졊졋졎졏졐졑졒졓졕졖졗졘졙졚졛졜졝졞졟졠졡졢졣졤졥졦졧졨졩졪졫졬졭졮졯졲졳졵졶졷졹졻졼졽졾졿좂좄좈좉좊좎좏좐좑좒좓좕좖좗좘좙좚좛좜좞좠좢좣좤�".split(""); +for(j = 0; j != D[160].length; ++j) if(D[160][j].charCodeAt(0) !== 0xFFFD) { e[D[160][j]] = 40960 + j; d[40960 + j] = D[160][j];} +D[161] = "�����������������������������������������������������������������좥좦좧좩좪좫좬좭좮좯좰좱좲좳좴좵좶좷좸좹좺좻좾좿죀죁������죂죃죅죆죇죉죊죋죍죎죏죐죑죒죓죖죘죚죛죜죝죞죟죢죣죥������죦죧죨죩죪죫죬죭죮죯죰죱죲죳죴죶죷죸죹죺죻죾죿줁줂줃줇줈줉줊줋줎 、。·‥…¨〃­―∥\∼‘’“”〔〕〈〉《》「」『』【】±×÷≠≤≥∞∴°′″℃Å¢£¥♂♀∠⊥⌒∂∇≡≒§※☆★○●◎◇◆□■△▲▽▼→←↑↓↔〓≪≫√∽∝∵∫∬∈∋⊆⊇⊂⊃∪∩∧∨¬�".split(""); +for(j = 0; j != D[161].length; ++j) if(D[161][j].charCodeAt(0) !== 0xFFFD) { e[D[161][j]] = 41216 + j; d[41216 + j] = D[161][j];} +D[162] = "�����������������������������������������������������������������줐줒줓줔줕줖줗줙줚줛줜줝줞줟줠줡줢줣줤줥줦줧줨줩줪줫������줭줮줯줰줱줲줳줵줶줷줸줹줺줻줼줽줾줿쥀쥁쥂쥃쥄쥅쥆쥇������쥈쥉쥊쥋쥌쥍쥎쥏쥒쥓쥕쥖쥗쥙쥚쥛쥜쥝쥞쥟쥢쥤쥥쥦쥧쥨쥩쥪쥫쥭쥮쥯⇒⇔∀∃´~ˇ˘˝˚˙¸˛¡¿ː∮∑∏¤℉‰◁◀▷▶♤♠♡♥♧♣⊙◈▣◐◑▒▤▥▨▧▦▩♨☏☎☜☞¶†‡↕↗↙↖↘♭♩♪♬㉿㈜№㏇™㏂㏘℡€®������������������������".split(""); +for(j = 0; j != D[162].length; ++j) if(D[162][j].charCodeAt(0) !== 0xFFFD) { e[D[162][j]] = 41472 + j; d[41472 + j] = D[162][j];} +D[163] = "�����������������������������������������������������������������쥱쥲쥳쥵쥶쥷쥸쥹쥺쥻쥽쥾쥿즀즁즂즃즄즅즆즇즊즋즍즎즏������즑즒즓즔즕즖즗즚즜즞즟즠즡즢즣즤즥즦즧즨즩즪즫즬즭즮������즯즰즱즲즳즴즵즶즷즸즹즺즻즼즽즾즿짂짃짅짆짉짋짌짍짎짏짒짔짗짘짛!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[₩]^_`abcdefghijklmnopqrstuvwxyz{|} ̄�".split(""); +for(j = 0; j != D[163].length; ++j) if(D[163][j].charCodeAt(0) !== 0xFFFD) { e[D[163][j]] = 41728 + j; d[41728 + j] = D[163][j];} +D[164] = "�����������������������������������������������������������������짞짟짡짣짥짦짨짩짪짫짮짲짳짴짵짶짷짺짻짽짾짿쨁쨂쨃쨄������쨅쨆쨇쨊쨎쨏쨐쨑쨒쨓쨕쨖쨗쨙쨚쨛쨜쨝쨞쨟쨠쨡쨢쨣쨤쨥������쨦쨧쨨쨪쨫쨬쨭쨮쨯쨰쨱쨲쨳쨴쨵쨶쨷쨸쨹쨺쨻쨼쨽쨾쨿쩀쩁쩂쩃쩄쩅쩆ㄱㄲㄳㄴㄵㄶㄷㄸㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅃㅄㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣㅤㅥㅦㅧㅨㅩㅪㅫㅬㅭㅮㅯㅰㅱㅲㅳㅴㅵㅶㅷㅸㅹㅺㅻㅼㅽㅾㅿㆀㆁㆂㆃㆄㆅㆆㆇㆈㆉㆊㆋㆌㆍㆎ�".split(""); +for(j = 0; j != D[164].length; ++j) if(D[164][j].charCodeAt(0) !== 0xFFFD) { e[D[164][j]] = 41984 + j; d[41984 + j] = D[164][j];} +D[165] = "�����������������������������������������������������������������쩇쩈쩉쩊쩋쩎쩏쩑쩒쩓쩕쩖쩗쩘쩙쩚쩛쩞쩢쩣쩤쩥쩦쩧쩩쩪������쩫쩬쩭쩮쩯쩰쩱쩲쩳쩴쩵쩶쩷쩸쩹쩺쩻쩼쩾쩿쪀쪁쪂쪃쪅쪆������쪇쪈쪉쪊쪋쪌쪍쪎쪏쪐쪑쪒쪓쪔쪕쪖쪗쪙쪚쪛쪜쪝쪞쪟쪠쪡쪢쪣쪤쪥쪦쪧ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹ�����ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ�������ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ��������αβγδεζηθικλμνξοπρστυφχψω�������".split(""); +for(j = 0; j != D[165].length; ++j) if(D[165][j].charCodeAt(0) !== 0xFFFD) { e[D[165][j]] = 42240 + j; d[42240 + j] = D[165][j];} +D[166] = "�����������������������������������������������������������������쪨쪩쪪쪫쪬쪭쪮쪯쪰쪱쪲쪳쪴쪵쪶쪷쪸쪹쪺쪻쪾쪿쫁쫂쫃쫅������쫆쫇쫈쫉쫊쫋쫎쫐쫒쫔쫕쫖쫗쫚쫛쫜쫝쫞쫟쫡쫢쫣쫤쫥쫦쫧������쫨쫩쫪쫫쫭쫮쫯쫰쫱쫲쫳쫵쫶쫷쫸쫹쫺쫻쫼쫽쫾쫿쬀쬁쬂쬃쬄쬅쬆쬇쬉쬊─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂┒┑┚┙┖┕┎┍┞┟┡┢┦┧┩┪┭┮┱┲┵┶┹┺┽┾╀╁╃╄╅╆╇╈╉╊���������������������������".split(""); +for(j = 0; j != D[166].length; ++j) if(D[166][j].charCodeAt(0) !== 0xFFFD) { e[D[166][j]] = 42496 + j; d[42496 + j] = D[166][j];} +D[167] = "�����������������������������������������������������������������쬋쬌쬍쬎쬏쬑쬒쬓쬕쬖쬗쬙쬚쬛쬜쬝쬞쬟쬢쬣쬤쬥쬦쬧쬨쬩������쬪쬫쬬쬭쬮쬯쬰쬱쬲쬳쬴쬵쬶쬷쬸쬹쬺쬻쬼쬽쬾쬿쭀쭂쭃쭄������쭅쭆쭇쭊쭋쭍쭎쭏쭑쭒쭓쭔쭕쭖쭗쭚쭛쭜쭞쭟쭠쭡쭢쭣쭥쭦쭧쭨쭩쭪쭫쭬㎕㎖㎗ℓ㎘㏄㎣㎤㎥㎦㎙㎚㎛㎜㎝㎞㎟㎠㎡㎢㏊㎍㎎㎏㏏㎈㎉㏈㎧㎨㎰㎱㎲㎳㎴㎵㎶㎷㎸㎹㎀㎁㎂㎃㎄㎺㎻㎼㎽㎾㎿㎐㎑㎒㎓㎔Ω㏀㏁㎊㎋㎌㏖㏅㎭㎮㎯㏛㎩㎪㎫㎬㏝㏐㏓㏃㏉㏜㏆����������������".split(""); +for(j = 0; j != D[167].length; ++j) if(D[167][j].charCodeAt(0) !== 0xFFFD) { e[D[167][j]] = 42752 + j; d[42752 + j] = D[167][j];} +D[168] = "�����������������������������������������������������������������쭭쭮쭯쭰쭱쭲쭳쭴쭵쭶쭷쭺쭻쭼쭽쭾쭿쮀쮁쮂쮃쮄쮅쮆쮇쮈������쮉쮊쮋쮌쮍쮎쮏쮐쮑쮒쮓쮔쮕쮖쮗쮘쮙쮚쮛쮝쮞쮟쮠쮡쮢쮣������쮤쮥쮦쮧쮨쮩쮪쮫쮬쮭쮮쮯쮰쮱쮲쮳쮴쮵쮶쮷쮹쮺쮻쮼쮽쮾쮿쯀쯁쯂쯃쯄ÆÐªĦ�IJ�ĿŁØŒºÞŦŊ�㉠㉡㉢㉣㉤㉥㉦㉧㉨㉩㉪㉫㉬㉭㉮㉯㉰㉱㉲㉳㉴㉵㉶㉷㉸㉹㉺㉻ⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮½⅓⅔¼¾⅛⅜⅝⅞�".split(""); +for(j = 0; j != D[168].length; ++j) if(D[168][j].charCodeAt(0) !== 0xFFFD) { e[D[168][j]] = 43008 + j; d[43008 + j] = D[168][j];} +D[169] = "�����������������������������������������������������������������쯅쯆쯇쯈쯉쯊쯋쯌쯍쯎쯏쯐쯑쯒쯓쯕쯖쯗쯘쯙쯚쯛쯜쯝쯞쯟������쯠쯡쯢쯣쯥쯦쯨쯪쯫쯬쯭쯮쯯쯰쯱쯲쯳쯴쯵쯶쯷쯸쯹쯺쯻쯼������쯽쯾쯿찀찁찂찃찄찅찆찇찈찉찊찋찎찏찑찒찓찕찖찗찘찙찚찛찞찟찠찣찤æđðħıijĸŀłøœßþŧŋʼn㈀㈁㈂㈃㈄㈅㈆㈇㈈㈉㈊㈋㈌㈍㈎㈏㈐㈑㈒㈓㈔㈕㈖㈗㈘㈙㈚㈛⒜⒝⒞⒟⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯⒰⒱⒲⒳⒴⒵⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂¹²³⁴ⁿ₁₂₃₄�".split(""); +for(j = 0; j != D[169].length; ++j) if(D[169][j].charCodeAt(0) !== 0xFFFD) { e[D[169][j]] = 43264 + j; d[43264 + j] = D[169][j];} +D[170] = "�����������������������������������������������������������������찥찦찪찫찭찯찱찲찳찴찵찶찷찺찿챀챁챂챃챆챇챉챊챋챍챎������챏챐챑챒챓챖챚챛챜챝챞챟챡챢챣챥챧챩챪챫챬챭챮챯챱챲������챳챴챶챷챸챹챺챻챼챽챾챿첀첁첂첃첄첅첆첇첈첉첊첋첌첍첎첏첐첑첒첓ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをん������������".split(""); +for(j = 0; j != D[170].length; ++j) if(D[170][j].charCodeAt(0) !== 0xFFFD) { e[D[170][j]] = 43520 + j; d[43520 + j] = D[170][j];} +D[171] = "�����������������������������������������������������������������첔첕첖첗첚첛첝첞첟첡첢첣첤첥첦첧첪첮첯첰첱첲첳첶첷첹������첺첻첽첾첿쳀쳁쳂쳃쳆쳈쳊쳋쳌쳍쳎쳏쳑쳒쳓쳕쳖쳗쳘쳙쳚������쳛쳜쳝쳞쳟쳠쳡쳢쳣쳥쳦쳧쳨쳩쳪쳫쳭쳮쳯쳱쳲쳳쳴쳵쳶쳷쳸쳹쳺쳻쳼쳽ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶ���������".split(""); +for(j = 0; j != D[171].length; ++j) if(D[171][j].charCodeAt(0) !== 0xFFFD) { e[D[171][j]] = 43776 + j; d[43776 + j] = D[171][j];} +D[172] = "�����������������������������������������������������������������쳾쳿촀촂촃촄촅촆촇촊촋촍촎촏촑촒촓촔촕촖촗촚촜촞촟촠������촡촢촣촥촦촧촩촪촫촭촮촯촰촱촲촳촴촵촶촷촸촺촻촼촽촾������촿쵀쵁쵂쵃쵄쵅쵆쵇쵈쵉쵊쵋쵌쵍쵎쵏쵐쵑쵒쵓쵔쵕쵖쵗쵘쵙쵚쵛쵝쵞쵟АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ���������������абвгдеёжзийклмнопрстуфхцчшщъыьэюя��������������".split(""); +for(j = 0; j != D[172].length; ++j) if(D[172][j].charCodeAt(0) !== 0xFFFD) { e[D[172][j]] = 44032 + j; d[44032 + j] = D[172][j];} +D[173] = "�����������������������������������������������������������������쵡쵢쵣쵥쵦쵧쵨쵩쵪쵫쵮쵰쵲쵳쵴쵵쵶쵷쵹쵺쵻쵼쵽쵾쵿춀������춁춂춃춄춅춆춇춉춊춋춌춍춎춏춐춑춒춓춖춗춙춚춛춝춞춟������춠춡춢춣춦춨춪춫춬춭춮춯춱춲춳춴춵춶춷춸춹춺춻춼춽춾춿췀췁췂췃췅�����������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[173].length; ++j) if(D[173][j].charCodeAt(0) !== 0xFFFD) { e[D[173][j]] = 44288 + j; d[44288 + j] = D[173][j];} +D[174] = "�����������������������������������������������������������������췆췇췈췉췊췋췍췎췏췑췒췓췔췕췖췗췘췙췚췛췜췝췞췟췠췡������췢췣췤췥췦췧췩췪췫췭췮췯췱췲췳췴췵췶췷췺췼췾췿츀츁츂������츃츅츆츇츉츊츋츍츎츏츐츑츒츓츕츖츗츘츚츛츜츝츞츟츢츣츥츦츧츩츪츫�����������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[174].length; ++j) if(D[174][j].charCodeAt(0) !== 0xFFFD) { e[D[174][j]] = 44544 + j; d[44544 + j] = D[174][j];} +D[175] = "�����������������������������������������������������������������츬츭츮츯츲츴츶츷츸츹츺츻츼츽츾츿칀칁칂칃칄칅칆칇칈칉������칊칋칌칍칎칏칐칑칒칓칔칕칖칗칚칛칝칞칢칣칤칥칦칧칪칬������칮칯칰칱칲칳칶칷칹칺칻칽칾칿캀캁캂캃캆캈캊캋캌캍캎캏캒캓캕캖캗캙�����������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[175].length; ++j) if(D[175][j].charCodeAt(0) !== 0xFFFD) { e[D[175][j]] = 44800 + j; d[44800 + j] = D[175][j];} +D[176] = "�����������������������������������������������������������������캚캛캜캝캞캟캢캦캧캨캩캪캫캮캯캰캱캲캳캴캵캶캷캸캹캺������캻캼캽캾캿컀컂컃컄컅컆컇컈컉컊컋컌컍컎컏컐컑컒컓컔컕������컖컗컘컙컚컛컜컝컞컟컠컡컢컣컦컧컩컪컭컮컯컰컱컲컳컶컺컻컼컽컾컿가각간갇갈갉갊감갑값갓갔강갖갗같갚갛개객갠갤갬갭갯갰갱갸갹갼걀걋걍걔걘걜거걱건걷걸걺검겁것겄겅겆겉겊겋게겐겔겜겝겟겠겡겨격겪견겯결겸겹겻겼경곁계곈곌곕곗고곡곤곧골곪곬곯곰곱곳공곶과곽관괄괆�".split(""); +for(j = 0; j != D[176].length; ++j) if(D[176][j].charCodeAt(0) !== 0xFFFD) { e[D[176][j]] = 45056 + j; d[45056 + j] = D[176][j];} +D[177] = "�����������������������������������������������������������������켂켃켅켆켇켉켊켋켌켍켎켏켒켔켖켗켘켙켚켛켝켞켟켡켢켣������켥켦켧켨켩켪켫켮켲켳켴켵켶켷켹켺켻켼켽켾켿콀콁콂콃콄������콅콆콇콈콉콊콋콌콍콎콏콐콑콒콓콖콗콙콚콛콝콞콟콠콡콢콣콦콨콪콫콬괌괍괏광괘괜괠괩괬괭괴괵괸괼굄굅굇굉교굔굘굡굣구국군굳굴굵굶굻굼굽굿궁궂궈궉권궐궜궝궤궷귀귁귄귈귐귑귓규균귤그극근귿글긁금급긋긍긔기긱긴긷길긺김깁깃깅깆깊까깍깎깐깔깖깜깝깟깠깡깥깨깩깬깰깸�".split(""); +for(j = 0; j != D[177].length; ++j) if(D[177][j].charCodeAt(0) !== 0xFFFD) { e[D[177][j]] = 45312 + j; d[45312 + j] = D[177][j];} +D[178] = "�����������������������������������������������������������������콭콮콯콲콳콵콶콷콹콺콻콼콽콾콿쾁쾂쾃쾄쾆쾇쾈쾉쾊쾋쾍������쾎쾏쾐쾑쾒쾓쾔쾕쾖쾗쾘쾙쾚쾛쾜쾝쾞쾟쾠쾢쾣쾤쾥쾦쾧쾩������쾪쾫쾬쾭쾮쾯쾱쾲쾳쾴쾵쾶쾷쾸쾹쾺쾻쾼쾽쾾쾿쿀쿁쿂쿃쿅쿆쿇쿈쿉쿊쿋깹깻깼깽꺄꺅꺌꺼꺽꺾껀껄껌껍껏껐껑께껙껜껨껫껭껴껸껼꼇꼈꼍꼐꼬꼭꼰꼲꼴꼼꼽꼿꽁꽂꽃꽈꽉꽐꽜꽝꽤꽥꽹꾀꾄꾈꾐꾑꾕꾜꾸꾹꾼꿀꿇꿈꿉꿋꿍꿎꿔꿜꿨꿩꿰꿱꿴꿸뀀뀁뀄뀌뀐뀔뀜뀝뀨끄끅끈끊끌끎끓끔끕끗끙�".split(""); +for(j = 0; j != D[178].length; ++j) if(D[178][j].charCodeAt(0) !== 0xFFFD) { e[D[178][j]] = 45568 + j; d[45568 + j] = D[178][j];} +D[179] = "�����������������������������������������������������������������쿌쿍쿎쿏쿐쿑쿒쿓쿔쿕쿖쿗쿘쿙쿚쿛쿜쿝쿞쿟쿢쿣쿥쿦쿧쿩������쿪쿫쿬쿭쿮쿯쿲쿴쿶쿷쿸쿹쿺쿻쿽쿾쿿퀁퀂퀃퀅퀆퀇퀈퀉퀊������퀋퀌퀍퀎퀏퀐퀒퀓퀔퀕퀖퀗퀙퀚퀛퀜퀝퀞퀟퀠퀡퀢퀣퀤퀥퀦퀧퀨퀩퀪퀫퀬끝끼끽낀낄낌낍낏낑나낙낚난낟날낡낢남납낫났낭낮낯낱낳내낵낸낼냄냅냇냈냉냐냑냔냘냠냥너넉넋넌널넒넓넘넙넛넜넝넣네넥넨넬넴넵넷넸넹녀녁년녈념녑녔녕녘녜녠노녹논놀놂놈놉놋농높놓놔놘놜놨뇌뇐뇔뇜뇝�".split(""); +for(j = 0; j != D[179].length; ++j) if(D[179][j].charCodeAt(0) !== 0xFFFD) { e[D[179][j]] = 45824 + j; d[45824 + j] = D[179][j];} +D[180] = "�����������������������������������������������������������������퀮퀯퀰퀱퀲퀳퀶퀷퀹퀺퀻퀽퀾퀿큀큁큂큃큆큈큊큋큌큍큎큏������큑큒큓큕큖큗큙큚큛큜큝큞큟큡큢큣큤큥큦큧큨큩큪큫큮큯������큱큲큳큵큶큷큸큹큺큻큾큿킀킂킃킄킅킆킇킈킉킊킋킌킍킎킏킐킑킒킓킔뇟뇨뇩뇬뇰뇹뇻뇽누눅눈눋눌눔눕눗눙눠눴눼뉘뉜뉠뉨뉩뉴뉵뉼늄늅늉느늑는늘늙늚늠늡늣능늦늪늬늰늴니닉닌닐닒님닙닛닝닢다닥닦단닫달닭닮닯닳담답닷닸당닺닻닿대댁댄댈댐댑댓댔댕댜더덕덖던덛덜덞덟덤덥�".split(""); +for(j = 0; j != D[180].length; ++j) if(D[180][j].charCodeAt(0) !== 0xFFFD) { e[D[180][j]] = 46080 + j; d[46080 + j] = D[180][j];} +D[181] = "�����������������������������������������������������������������킕킖킗킘킙킚킛킜킝킞킟킠킡킢킣킦킧킩킪킫킭킮킯킰킱킲������킳킶킸킺킻킼킽킾킿탂탃탅탆탇탊탋탌탍탎탏탒탖탗탘탙탚������탛탞탟탡탢탣탥탦탧탨탩탪탫탮탲탳탴탵탶탷탹탺탻탼탽탾탿턀턁턂턃턄덧덩덫덮데덱덴델뎀뎁뎃뎄뎅뎌뎐뎔뎠뎡뎨뎬도독돈돋돌돎돐돔돕돗동돛돝돠돤돨돼됐되된될됨됩됫됴두둑둔둘둠둡둣둥둬뒀뒈뒝뒤뒨뒬뒵뒷뒹듀듄듈듐듕드득든듣들듦듬듭듯등듸디딕딘딛딜딤딥딧딨딩딪따딱딴딸�".split(""); +for(j = 0; j != D[181].length; ++j) if(D[181][j].charCodeAt(0) !== 0xFFFD) { e[D[181][j]] = 46336 + j; d[46336 + j] = D[181][j];} +D[182] = "�����������������������������������������������������������������턅턆턇턈턉턊턋턌턎턏턐턑턒턓턔턕턖턗턘턙턚턛턜턝턞턟������턠턡턢턣턤턥턦턧턨턩턪턫턬턭턮턯턲턳턵턶턷턹턻턼턽턾������턿텂텆텇텈텉텊텋텎텏텑텒텓텕텖텗텘텙텚텛텞텠텢텣텤텥텦텧텩텪텫텭땀땁땃땄땅땋때땍땐땔땜땝땟땠땡떠떡떤떨떪떫떰떱떳떴떵떻떼떽뗀뗄뗌뗍뗏뗐뗑뗘뗬또똑똔똘똥똬똴뙈뙤뙨뚜뚝뚠뚤뚫뚬뚱뛔뛰뛴뛸뜀뜁뜅뜨뜩뜬뜯뜰뜸뜹뜻띄띈띌띔띕띠띤띨띰띱띳띵라락란랄람랍랏랐랑랒랖랗�".split(""); +for(j = 0; j != D[182].length; ++j) if(D[182][j].charCodeAt(0) !== 0xFFFD) { e[D[182][j]] = 46592 + j; d[46592 + j] = D[182][j];} +D[183] = "�����������������������������������������������������������������텮텯텰텱텲텳텴텵텶텷텸텹텺텻텽텾텿톀톁톂톃톅톆톇톉톊������톋톌톍톎톏톐톑톒톓톔톕톖톗톘톙톚톛톜톝톞톟톢톣톥톦톧������톩톪톫톬톭톮톯톲톴톶톷톸톹톻톽톾톿퇁퇂퇃퇄퇅퇆퇇퇈퇉퇊퇋퇌퇍퇎퇏래랙랜랠램랩랫랬랭랴략랸럇량러럭런럴럼럽럿렀렁렇레렉렌렐렘렙렛렝려력련렬렴렵렷렸령례롄롑롓로록론롤롬롭롯롱롸롼뢍뢨뢰뢴뢸룀룁룃룅료룐룔룝룟룡루룩룬룰룸룹룻룽뤄뤘뤠뤼뤽륀륄륌륏륑류륙륜률륨륩�".split(""); +for(j = 0; j != D[183].length; ++j) if(D[183][j].charCodeAt(0) !== 0xFFFD) { e[D[183][j]] = 46848 + j; d[46848 + j] = D[183][j];} +D[184] = "�����������������������������������������������������������������퇐퇑퇒퇓퇔퇕퇖퇗퇙퇚퇛퇜퇝퇞퇟퇠퇡퇢퇣퇤퇥퇦퇧퇨퇩퇪������퇫퇬퇭퇮퇯퇰퇱퇲퇳퇵퇶퇷퇹퇺퇻퇼퇽퇾퇿툀툁툂툃툄툅툆������툈툊툋툌툍툎툏툑툒툓툔툕툖툗툘툙툚툛툜툝툞툟툠툡툢툣툤툥툦툧툨툩륫륭르륵른를름릅릇릉릊릍릎리릭린릴림립릿링마막만많맏말맑맒맘맙맛망맞맡맣매맥맨맬맴맵맷맸맹맺먀먁먈먕머먹먼멀멂멈멉멋멍멎멓메멕멘멜멤멥멧멨멩며멱면멸몃몄명몇몌모목몫몬몰몲몸몹못몽뫄뫈뫘뫙뫼�".split(""); +for(j = 0; j != D[184].length; ++j) if(D[184][j].charCodeAt(0) !== 0xFFFD) { e[D[184][j]] = 47104 + j; d[47104 + j] = D[184][j];} +D[185] = "�����������������������������������������������������������������툪툫툮툯툱툲툳툵툶툷툸툹툺툻툾퉀퉂퉃퉄퉅퉆퉇퉉퉊퉋퉌������퉍퉎퉏퉐퉑퉒퉓퉔퉕퉖퉗퉘퉙퉚퉛퉝퉞퉟퉠퉡퉢퉣퉥퉦퉧퉨������퉩퉪퉫퉬퉭퉮퉯퉰퉱퉲퉳퉴퉵퉶퉷퉸퉹퉺퉻퉼퉽퉾퉿튂튃튅튆튇튉튊튋튌묀묄묍묏묑묘묜묠묩묫무묵묶문묻물묽묾뭄뭅뭇뭉뭍뭏뭐뭔뭘뭡뭣뭬뮈뮌뮐뮤뮨뮬뮴뮷므믄믈믐믓미믹민믿밀밂밈밉밋밌밍및밑바박밖밗반받발밝밞밟밤밥밧방밭배백밴밸뱀뱁뱃뱄뱅뱉뱌뱍뱐뱝버벅번벋벌벎범법벗�".split(""); +for(j = 0; j != D[185].length; ++j) if(D[185][j].charCodeAt(0) !== 0xFFFD) { e[D[185][j]] = 47360 + j; d[47360 + j] = D[185][j];} +D[186] = "�����������������������������������������������������������������튍튎튏튒튓튔튖튗튘튙튚튛튝튞튟튡튢튣튥튦튧튨튩튪튫튭������튮튯튰튲튳튴튵튶튷튺튻튽튾틁틃틄틅틆틇틊틌틍틎틏틐틑������틒틓틕틖틗틙틚틛틝틞틟틠틡틢틣틦틧틨틩틪틫틬틭틮틯틲틳틵틶틷틹틺벙벚베벡벤벧벨벰벱벳벴벵벼벽변별볍볏볐병볕볘볜보복볶본볼봄봅봇봉봐봔봤봬뵀뵈뵉뵌뵐뵘뵙뵤뵨부북분붇불붉붊붐붑붓붕붙붚붜붤붰붸뷔뷕뷘뷜뷩뷰뷴뷸븀븃븅브븍븐블븜븝븟비빅빈빌빎빔빕빗빙빚빛빠빡빤�".split(""); +for(j = 0; j != D[186].length; ++j) if(D[186][j].charCodeAt(0) !== 0xFFFD) { e[D[186][j]] = 47616 + j; d[47616 + j] = D[186][j];} +D[187] = "�����������������������������������������������������������������틻틼틽틾틿팂팄팆팇팈팉팊팋팏팑팒팓팕팗팘팙팚팛팞팢팣������팤팦팧팪팫팭팮팯팱팲팳팴팵팶팷팺팾팿퍀퍁퍂퍃퍆퍇퍈퍉������퍊퍋퍌퍍퍎퍏퍐퍑퍒퍓퍔퍕퍖퍗퍘퍙퍚퍛퍜퍝퍞퍟퍠퍡퍢퍣퍤퍥퍦퍧퍨퍩빨빪빰빱빳빴빵빻빼빽뺀뺄뺌뺍뺏뺐뺑뺘뺙뺨뻐뻑뻔뻗뻘뻠뻣뻤뻥뻬뼁뼈뼉뼘뼙뼛뼜뼝뽀뽁뽄뽈뽐뽑뽕뾔뾰뿅뿌뿍뿐뿔뿜뿟뿡쀼쁑쁘쁜쁠쁨쁩삐삑삔삘삠삡삣삥사삭삯산삳살삵삶삼삽삿샀상샅새색샌샐샘샙샛샜생샤�".split(""); +for(j = 0; j != D[187].length; ++j) if(D[187][j].charCodeAt(0) !== 0xFFFD) { e[D[187][j]] = 47872 + j; d[47872 + j] = D[187][j];} +D[188] = "�����������������������������������������������������������������퍪퍫퍬퍭퍮퍯퍰퍱퍲퍳퍴퍵퍶퍷퍸퍹퍺퍻퍾퍿펁펂펃펅펆펇������펈펉펊펋펎펒펓펔펕펖펗펚펛펝펞펟펡펢펣펤펥펦펧펪펬펮������펯펰펱펲펳펵펶펷펹펺펻펽펾펿폀폁폂폃폆폇폊폋폌폍폎폏폑폒폓폔폕폖샥샨샬샴샵샷샹섀섄섈섐섕서석섞섟선섣설섦섧섬섭섯섰성섶세섹센셀셈셉셋셌셍셔셕션셜셤셥셧셨셩셰셴셸솅소속솎손솔솖솜솝솟송솥솨솩솬솰솽쇄쇈쇌쇔쇗쇘쇠쇤쇨쇰쇱쇳쇼쇽숀숄숌숍숏숑수숙순숟술숨숩숫숭�".split(""); +for(j = 0; j != D[188].length; ++j) if(D[188][j].charCodeAt(0) !== 0xFFFD) { e[D[188][j]] = 48128 + j; d[48128 + j] = D[188][j];} +D[189] = "�����������������������������������������������������������������폗폙폚폛폜폝폞폟폠폢폤폥폦폧폨폩폪폫폮폯폱폲폳폵폶폷������폸폹폺폻폾퐀퐂퐃퐄퐅퐆퐇퐉퐊퐋퐌퐍퐎퐏퐐퐑퐒퐓퐔퐕퐖������퐗퐘퐙퐚퐛퐜퐞퐟퐠퐡퐢퐣퐤퐥퐦퐧퐨퐩퐪퐫퐬퐭퐮퐯퐰퐱퐲퐳퐴퐵퐶퐷숯숱숲숴쉈쉐쉑쉔쉘쉠쉥쉬쉭쉰쉴쉼쉽쉿슁슈슉슐슘슛슝스슥슨슬슭슴습슷승시식신싣실싫심십싯싱싶싸싹싻싼쌀쌈쌉쌌쌍쌓쌔쌕쌘쌜쌤쌥쌨쌩썅써썩썬썰썲썸썹썼썽쎄쎈쎌쏀쏘쏙쏜쏟쏠쏢쏨쏩쏭쏴쏵쏸쐈쐐쐤쐬쐰�".split(""); +for(j = 0; j != D[189].length; ++j) if(D[189][j].charCodeAt(0) !== 0xFFFD) { e[D[189][j]] = 48384 + j; d[48384 + j] = D[189][j];} +D[190] = "�����������������������������������������������������������������퐸퐹퐺퐻퐼퐽퐾퐿푁푂푃푅푆푇푈푉푊푋푌푍푎푏푐푑푒푓������푔푕푖푗푘푙푚푛푝푞푟푡푢푣푥푦푧푨푩푪푫푬푮푰푱푲������푳푴푵푶푷푺푻푽푾풁풃풄풅풆풇풊풌풎풏풐풑풒풓풕풖풗풘풙풚풛풜풝쐴쐼쐽쑈쑤쑥쑨쑬쑴쑵쑹쒀쒔쒜쒸쒼쓩쓰쓱쓴쓸쓺쓿씀씁씌씐씔씜씨씩씬씰씸씹씻씽아악안앉않알앍앎앓암압앗았앙앝앞애액앤앨앰앱앳앴앵야약얀얄얇얌얍얏양얕얗얘얜얠얩어억언얹얻얼얽얾엄업없엇었엉엊엌엎�".split(""); +for(j = 0; j != D[190].length; ++j) if(D[190][j].charCodeAt(0) !== 0xFFFD) { e[D[190][j]] = 48640 + j; d[48640 + j] = D[190][j];} +D[191] = "�����������������������������������������������������������������풞풟풠풡풢풣풤풥풦풧풨풪풫풬풭풮풯풰풱풲풳풴풵풶풷풸������풹풺풻풼풽풾풿퓀퓁퓂퓃퓄퓅퓆퓇퓈퓉퓊퓋퓍퓎퓏퓑퓒퓓퓕������퓖퓗퓘퓙퓚퓛퓝퓞퓠퓡퓢퓣퓤퓥퓦퓧퓩퓪퓫퓭퓮퓯퓱퓲퓳퓴퓵퓶퓷퓹퓺퓼에엑엔엘엠엡엣엥여역엮연열엶엷염엽엾엿였영옅옆옇예옌옐옘옙옛옜오옥온올옭옮옰옳옴옵옷옹옻와왁완왈왐왑왓왔왕왜왝왠왬왯왱외왹왼욀욈욉욋욍요욕욘욜욤욥욧용우욱운울욹욺움웁웃웅워웍원월웜웝웠웡웨�".split(""); +for(j = 0; j != D[191].length; ++j) if(D[191][j].charCodeAt(0) !== 0xFFFD) { e[D[191][j]] = 48896 + j; d[48896 + j] = D[191][j];} +D[192] = "�����������������������������������������������������������������퓾퓿픀픁픂픃픅픆픇픉픊픋픍픎픏픐픑픒픓픖픘픙픚픛픜픝������픞픟픠픡픢픣픤픥픦픧픨픩픪픫픬픭픮픯픰픱픲픳픴픵픶픷������픸픹픺픻픾픿핁핂핃핅핆핇핈핉핊핋핎핐핒핓핔핕핖핗핚핛핝핞핟핡핢핣웩웬웰웸웹웽위윅윈윌윔윕윗윙유육윤율윰윱윳융윷으윽은을읊음읍읏응읒읓읔읕읖읗의읜읠읨읫이익인일읽읾잃임입잇있잉잊잎자작잔잖잗잘잚잠잡잣잤장잦재잭잰잴잼잽잿쟀쟁쟈쟉쟌쟎쟐쟘쟝쟤쟨쟬저적전절젊�".split(""); +for(j = 0; j != D[192].length; ++j) if(D[192][j].charCodeAt(0) !== 0xFFFD) { e[D[192][j]] = 49152 + j; d[49152 + j] = D[192][j];} +D[193] = "�����������������������������������������������������������������핤핦핧핪핬핮핯핰핱핲핳핶핷핹핺핻핽핾핿햀햁햂햃햆햊햋������햌햍햎햏햑햒햓햔햕햖햗햘햙햚햛햜햝햞햟햠햡햢햣햤햦햧������햨햩햪햫햬햭햮햯햰햱햲햳햴햵햶햷햸햹햺햻햼햽햾햿헀헁헂헃헄헅헆헇점접젓정젖제젝젠젤젬젭젯젱져젼졀졈졉졌졍졔조족존졸졺좀좁좃종좆좇좋좌좍좔좝좟좡좨좼좽죄죈죌죔죕죗죙죠죡죤죵주죽준줄줅줆줌줍줏중줘줬줴쥐쥑쥔쥘쥠쥡쥣쥬쥰쥴쥼즈즉즌즐즘즙즛증지직진짇질짊짐집짓�".split(""); +for(j = 0; j != D[193].length; ++j) if(D[193][j].charCodeAt(0) !== 0xFFFD) { e[D[193][j]] = 49408 + j; d[49408 + j] = D[193][j];} +D[194] = "�����������������������������������������������������������������헊헋헍헎헏헑헓헔헕헖헗헚헜헞헟헠헡헢헣헦헧헩헪헫헭헮������헯헰헱헲헳헶헸헺헻헼헽헾헿혂혃혅혆혇혉혊혋혌혍혎혏혒������혖혗혘혙혚혛혝혞혟혡혢혣혥혦혧혨혩혪혫혬혮혯혰혱혲혳혴혵혶혷혺혻징짖짙짚짜짝짠짢짤짧짬짭짯짰짱째짹짼쨀쨈쨉쨋쨌쨍쨔쨘쨩쩌쩍쩐쩔쩜쩝쩟쩠쩡쩨쩽쪄쪘쪼쪽쫀쫄쫌쫍쫏쫑쫓쫘쫙쫠쫬쫴쬈쬐쬔쬘쬠쬡쭁쭈쭉쭌쭐쭘쭙쭝쭤쭸쭹쮜쮸쯔쯤쯧쯩찌찍찐찔찜찝찡찢찧차착찬찮찰참찹찻�".split(""); +for(j = 0; j != D[194].length; ++j) if(D[194][j].charCodeAt(0) !== 0xFFFD) { e[D[194][j]] = 49664 + j; d[49664 + j] = D[194][j];} +D[195] = "�����������������������������������������������������������������혽혾혿홁홂홃홄홆홇홊홌홎홏홐홒홓홖홗홙홚홛홝홞홟홠홡������홢홣홤홥홦홨홪홫홬홭홮홯홲홳홵홶홷홸홹홺홻홼홽홾홿횀������횁횂횄횆횇횈횉횊횋횎횏횑횒횓횕횖횗횘횙횚횛횜횞횠횢횣횤횥횦횧횩횪찼창찾채책챈챌챔챕챗챘챙챠챤챦챨챰챵처척천철첨첩첫첬청체첵첸첼쳄쳅쳇쳉쳐쳔쳤쳬쳰촁초촉촌촐촘촙촛총촤촨촬촹최쵠쵤쵬쵭쵯쵱쵸춈추축춘출춤춥춧충춰췄췌췐취췬췰췸췹췻췽츄츈츌츔츙츠측츤츨츰츱츳층�".split(""); +for(j = 0; j != D[195].length; ++j) if(D[195][j].charCodeAt(0) !== 0xFFFD) { e[D[195][j]] = 49920 + j; d[49920 + j] = D[195][j];} +D[196] = "�����������������������������������������������������������������횫횭횮횯횱횲횳횴횵횶횷횸횺횼횽횾횿훀훁훂훃훆훇훉훊훋������훍훎훏훐훒훓훕훖훘훚훛훜훝훞훟훡훢훣훥훦훧훩훪훫훬훭������훮훯훱훲훳훴훶훷훸훹훺훻훾훿휁휂휃휅휆휇휈휉휊휋휌휍휎휏휐휒휓휔치칙친칟칠칡침칩칫칭카칵칸칼캄캅캇캉캐캑캔캘캠캡캣캤캥캬캭컁커컥컨컫컬컴컵컷컸컹케켁켄켈켐켑켓켕켜켠켤켬켭켯켰켱켸코콕콘콜콤콥콧콩콰콱콴콸쾀쾅쾌쾡쾨쾰쿄쿠쿡쿤쿨쿰쿱쿳쿵쿼퀀퀄퀑퀘퀭퀴퀵퀸퀼�".split(""); +for(j = 0; j != D[196].length; ++j) if(D[196][j].charCodeAt(0) !== 0xFFFD) { e[D[196][j]] = 50176 + j; d[50176 + j] = D[196][j];} +D[197] = "�����������������������������������������������������������������휕휖휗휚휛휝휞휟휡휢휣휤휥휦휧휪휬휮휯휰휱휲휳휶휷휹������휺휻휽휾휿흀흁흂흃흅흆흈흊흋흌흍흎흏흒흓흕흚흛흜흝흞������흟흢흤흦흧흨흪흫흭흮흯흱흲흳흵흶흷흸흹흺흻흾흿힀힂힃힄힅힆힇힊힋큄큅큇큉큐큔큘큠크큭큰클큼큽킁키킥킨킬킴킵킷킹타탁탄탈탉탐탑탓탔탕태택탠탤탬탭탯탰탱탸턍터턱턴털턺텀텁텃텄텅테텍텐텔템텝텟텡텨텬텼톄톈토톡톤톨톰톱톳통톺톼퇀퇘퇴퇸툇툉툐투툭툰툴툼툽툿퉁퉈퉜�".split(""); +for(j = 0; j != D[197].length; ++j) if(D[197][j].charCodeAt(0) !== 0xFFFD) { e[D[197][j]] = 50432 + j; d[50432 + j] = D[197][j];} +D[198] = "�����������������������������������������������������������������힍힎힏힑힒힓힔힕힖힗힚힜힞힟힠힡힢힣������������������������������������������������������������������������������퉤튀튁튄튈튐튑튕튜튠튤튬튱트특튼튿틀틂틈틉틋틔틘틜틤틥티틱틴틸팀팁팃팅파팍팎판팔팖팜팝팟팠팡팥패팩팬팰팸팹팻팼팽퍄퍅퍼퍽펀펄펌펍펏펐펑페펙펜펠펨펩펫펭펴편펼폄폅폈평폐폘폡폣포폭폰폴폼폽폿퐁�".split(""); +for(j = 0; j != D[198].length; ++j) if(D[198][j].charCodeAt(0) !== 0xFFFD) { e[D[198][j]] = 50688 + j; d[50688 + j] = D[198][j];} +D[199] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������퐈퐝푀푄표푠푤푭푯푸푹푼푿풀풂품풉풋풍풔풩퓌퓐퓔퓜퓟퓨퓬퓰퓸퓻퓽프픈플픔픕픗피픽핀필핌핍핏핑하학한할핥함합핫항해핵핸핼햄햅햇했행햐향허헉헌헐헒험헙헛헝헤헥헨헬헴헵헷헹혀혁현혈혐협혓혔형혜혠�".split(""); +for(j = 0; j != D[199].length; ++j) if(D[199][j].charCodeAt(0) !== 0xFFFD) { e[D[199][j]] = 50944 + j; d[50944 + j] = D[199][j];} +D[200] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������혤혭호혹혼홀홅홈홉홋홍홑화확환활홧황홰홱홴횃횅회획횐횔횝횟횡효횬횰횹횻후훅훈훌훑훔훗훙훠훤훨훰훵훼훽휀휄휑휘휙휜휠휨휩휫휭휴휵휸휼흄흇흉흐흑흔흖흗흘흙흠흡흣흥흩희흰흴흼흽힁히힉힌힐힘힙힛힝�".split(""); +for(j = 0; j != D[200].length; ++j) if(D[200][j].charCodeAt(0) !== 0xFFFD) { e[D[200][j]] = 51200 + j; d[51200 + j] = D[200][j];} +D[202] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������伽佳假價加可呵哥嘉嫁家暇架枷柯歌珂痂稼苛茄街袈訶賈跏軻迦駕刻却各恪慤殼珏脚覺角閣侃刊墾奸姦干幹懇揀杆柬桿澗癎看磵稈竿簡肝艮艱諫間乫喝曷渴碣竭葛褐蝎鞨勘坎堪嵌感憾戡敢柑橄減甘疳監瞰紺邯鑑鑒龕�".split(""); +for(j = 0; j != D[202].length; ++j) if(D[202][j].charCodeAt(0) !== 0xFFFD) { e[D[202][j]] = 51712 + j; d[51712 + j] = D[202][j];} +D[203] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������匣岬甲胛鉀閘剛堈姜岡崗康强彊慷江畺疆糠絳綱羌腔舡薑襁講鋼降鱇介价個凱塏愷愾慨改槪漑疥皆盖箇芥蓋豈鎧開喀客坑更粳羹醵倨去居巨拒据據擧渠炬祛距踞車遽鉅鋸乾件健巾建愆楗腱虔蹇鍵騫乞傑杰桀儉劍劒檢�".split(""); +for(j = 0; j != D[203].length; ++j) if(D[203][j].charCodeAt(0) !== 0xFFFD) { e[D[203][j]] = 51968 + j; d[51968 + j] = D[203][j];} +D[204] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������瞼鈐黔劫怯迲偈憩揭擊格檄激膈覡隔堅牽犬甄絹繭肩見譴遣鵑抉決潔結缺訣兼慊箝謙鉗鎌京俓倞傾儆勁勍卿坰境庚徑慶憬擎敬景暻更梗涇炅烱璟璥瓊痙硬磬竟競絅經耕耿脛莖警輕逕鏡頃頸驚鯨係啓堺契季屆悸戒桂械�".split(""); +for(j = 0; j != D[204].length; ++j) if(D[204][j].charCodeAt(0) !== 0xFFFD) { e[D[204][j]] = 52224 + j; d[52224 + j] = D[204][j];} +D[205] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������棨溪界癸磎稽系繫繼計誡谿階鷄古叩告呱固姑孤尻庫拷攷故敲暠枯槁沽痼皐睾稿羔考股膏苦苽菰藁蠱袴誥賈辜錮雇顧高鼓哭斛曲梏穀谷鵠困坤崑昆梱棍滾琨袞鯤汨滑骨供公共功孔工恐恭拱控攻珙空蚣貢鞏串寡戈果瓜�".split(""); +for(j = 0; j != D[205].length; ++j) if(D[205][j].charCodeAt(0) !== 0xFFFD) { e[D[205][j]] = 52480 + j; d[52480 + j] = D[205][j];} +D[206] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������科菓誇課跨過鍋顆廓槨藿郭串冠官寬慣棺款灌琯瓘管罐菅觀貫關館刮恝括适侊光匡壙廣曠洸炚狂珖筐胱鑛卦掛罫乖傀塊壞怪愧拐槐魁宏紘肱轟交僑咬喬嬌嶠巧攪敎校橋狡皎矯絞翹膠蕎蛟較轎郊餃驕鮫丘久九仇俱具勾�".split(""); +for(j = 0; j != D[206].length; ++j) if(D[206][j].charCodeAt(0) !== 0xFFFD) { e[D[206][j]] = 52736 + j; d[52736 + j] = D[206][j];} +D[207] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������區口句咎嘔坵垢寇嶇廐懼拘救枸柩構歐毆毬求溝灸狗玖球瞿矩究絿耉臼舅舊苟衢謳購軀逑邱鉤銶駒驅鳩鷗龜國局菊鞠鞫麴君窘群裙軍郡堀屈掘窟宮弓穹窮芎躬倦券勸卷圈拳捲權淃眷厥獗蕨蹶闕机櫃潰詭軌饋句晷歸貴�".split(""); +for(j = 0; j != D[207].length; ++j) if(D[207][j].charCodeAt(0) !== 0xFFFD) { e[D[207][j]] = 52992 + j; d[52992 + j] = D[207][j];} +D[208] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������鬼龜叫圭奎揆槻珪硅窺竅糾葵規赳逵閨勻均畇筠菌鈞龜橘克剋劇戟棘極隙僅劤勤懃斤根槿瑾筋芹菫覲謹近饉契今妗擒昑檎琴禁禽芩衾衿襟金錦伋及急扱汲級給亘兢矜肯企伎其冀嗜器圻基埼夔奇妓寄岐崎己幾忌技旗旣�".split(""); +for(j = 0; j != D[208].length; ++j) if(D[208][j].charCodeAt(0) !== 0xFFFD) { e[D[208][j]] = 53248 + j; d[53248 + j] = D[208][j];} +D[209] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������朞期杞棋棄機欺氣汽沂淇玘琦琪璂璣畸畿碁磯祁祇祈祺箕紀綺羈耆耭肌記譏豈起錡錤飢饑騎騏驥麒緊佶吉拮桔金喫儺喇奈娜懦懶拏拿癩羅蘿螺裸邏那樂洛烙珞落諾酪駱亂卵暖欄煖爛蘭難鸞捏捺南嵐枏楠湳濫男藍襤拉�".split(""); +for(j = 0; j != D[209].length; ++j) if(D[209][j].charCodeAt(0) !== 0xFFFD) { e[D[209][j]] = 53504 + j; d[53504 + j] = D[209][j];} +D[210] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������納臘蠟衲囊娘廊朗浪狼郎乃來內奈柰耐冷女年撚秊念恬拈捻寧寗努勞奴弩怒擄櫓爐瑙盧老蘆虜路露駑魯鷺碌祿綠菉錄鹿論壟弄濃籠聾膿農惱牢磊腦賂雷尿壘屢樓淚漏累縷陋嫩訥杻紐勒肋凜凌稜綾能菱陵尼泥匿溺多茶�".split(""); +for(j = 0; j != D[210].length; ++j) if(D[210][j].charCodeAt(0) !== 0xFFFD) { e[D[210][j]] = 53760 + j; d[53760 + j] = D[210][j];} +D[211] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������丹亶但單團壇彖斷旦檀段湍短端簞緞蛋袒鄲鍛撻澾獺疸達啖坍憺擔曇淡湛潭澹痰聃膽蕁覃談譚錟沓畓答踏遝唐堂塘幢戇撞棠當糖螳黨代垈坮大對岱帶待戴擡玳臺袋貸隊黛宅德悳倒刀到圖堵塗導屠島嶋度徒悼挑掉搗桃�".split(""); +for(j = 0; j != D[211].length; ++j) if(D[211][j].charCodeAt(0) !== 0xFFFD) { e[D[211][j]] = 54016 + j; d[54016 + j] = D[211][j];} +D[212] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������棹櫂淘渡滔濤燾盜睹禱稻萄覩賭跳蹈逃途道都鍍陶韜毒瀆牘犢獨督禿篤纛讀墩惇敦旽暾沌焞燉豚頓乭突仝冬凍動同憧東桐棟洞潼疼瞳童胴董銅兜斗杜枓痘竇荳讀豆逗頭屯臀芚遁遯鈍得嶝橙燈登等藤謄鄧騰喇懶拏癩羅�".split(""); +for(j = 0; j != D[212].length; ++j) if(D[212][j].charCodeAt(0) !== 0xFFFD) { e[D[212][j]] = 54272 + j; d[54272 + j] = D[212][j];} +D[213] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������蘿螺裸邏樂洛烙珞絡落諾酪駱丹亂卵欄欒瀾爛蘭鸞剌辣嵐擥攬欖濫籃纜藍襤覽拉臘蠟廊朗浪狼琅瑯螂郞來崍徠萊冷掠略亮倆兩凉梁樑粮粱糧良諒輛量侶儷勵呂廬慮戾旅櫚濾礪藜蠣閭驢驪麗黎力曆歷瀝礫轢靂憐戀攣漣�".split(""); +for(j = 0; j != D[213].length; ++j) if(D[213][j].charCodeAt(0) !== 0xFFFD) { e[D[213][j]] = 54528 + j; d[54528 + j] = D[213][j];} +D[214] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������煉璉練聯蓮輦連鍊冽列劣洌烈裂廉斂殮濂簾獵令伶囹寧岺嶺怜玲笭羚翎聆逞鈴零靈領齡例澧禮醴隷勞怒撈擄櫓潞瀘爐盧老蘆虜路輅露魯鷺鹵碌祿綠菉錄鹿麓論壟弄朧瀧瓏籠聾儡瀨牢磊賂賚賴雷了僚寮廖料燎療瞭聊蓼�".split(""); +for(j = 0; j != D[214].length; ++j) if(D[214][j].charCodeAt(0) !== 0xFFFD) { e[D[214][j]] = 54784 + j; d[54784 + j] = D[214][j];} +D[215] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������遼鬧龍壘婁屢樓淚漏瘻累縷蔞褸鏤陋劉旒柳榴流溜瀏琉瑠留瘤硫謬類六戮陸侖倫崙淪綸輪律慄栗率隆勒肋凜凌楞稜綾菱陵俚利厘吏唎履悧李梨浬犁狸理璃異痢籬罹羸莉裏裡里釐離鯉吝潾燐璘藺躪隣鱗麟林淋琳臨霖砬�".split(""); +for(j = 0; j != D[215].length; ++j) if(D[215][j].charCodeAt(0) !== 0xFFFD) { e[D[215][j]] = 55040 + j; d[55040 + j] = D[215][j];} +D[216] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������立笠粒摩瑪痲碼磨馬魔麻寞幕漠膜莫邈万卍娩巒彎慢挽晩曼滿漫灣瞞萬蔓蠻輓饅鰻唜抹末沫茉襪靺亡妄忘忙望網罔芒茫莽輞邙埋妹媒寐昧枚梅每煤罵買賣邁魅脈貊陌驀麥孟氓猛盲盟萌冪覓免冕勉棉沔眄眠綿緬面麵滅�".split(""); +for(j = 0; j != D[216].length; ++j) if(D[216][j].charCodeAt(0) !== 0xFFFD) { e[D[216][j]] = 55296 + j; d[55296 + j] = D[216][j];} +D[217] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������蔑冥名命明暝椧溟皿瞑茗蓂螟酩銘鳴袂侮冒募姆帽慕摸摹暮某模母毛牟牡瑁眸矛耗芼茅謀謨貌木沐牧目睦穆鶩歿沒夢朦蒙卯墓妙廟描昴杳渺猫竗苗錨務巫憮懋戊拇撫无楙武毋無珷畝繆舞茂蕪誣貿霧鵡墨默們刎吻問文�".split(""); +for(j = 0; j != D[217].length; ++j) if(D[217][j].charCodeAt(0) !== 0xFFFD) { e[D[217][j]] = 55552 + j; d[55552 + j] = D[217][j];} +D[218] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������汶紊紋聞蚊門雯勿沕物味媚尾嵋彌微未梶楣渼湄眉米美薇謎迷靡黴岷悶愍憫敏旻旼民泯玟珉緡閔密蜜謐剝博拍搏撲朴樸泊珀璞箔粕縛膊舶薄迫雹駁伴半反叛拌搬攀斑槃泮潘班畔瘢盤盼磐磻礬絆般蟠返頒飯勃拔撥渤潑�".split(""); +for(j = 0; j != D[218].length; ++j) if(D[218][j].charCodeAt(0) !== 0xFFFD) { e[D[218][j]] = 55808 + j; d[55808 + j] = D[218][j];} +D[219] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������發跋醱鉢髮魃倣傍坊妨尨幇彷房放方旁昉枋榜滂磅紡肪膀舫芳蒡蚌訪謗邦防龐倍俳北培徘拜排杯湃焙盃背胚裴裵褙賠輩配陪伯佰帛柏栢白百魄幡樊煩燔番磻繁蕃藩飜伐筏罰閥凡帆梵氾汎泛犯範范法琺僻劈壁擘檗璧癖�".split(""); +for(j = 0; j != D[219].length; ++j) if(D[219][j].charCodeAt(0) !== 0xFFFD) { e[D[219][j]] = 56064 + j; d[56064 + j] = D[219][j];} +D[220] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������碧蘗闢霹便卞弁變辨辯邊別瞥鱉鼈丙倂兵屛幷昞昺柄棅炳甁病秉竝輧餠騈保堡報寶普步洑湺潽珤甫菩補褓譜輔伏僕匐卜宓復服福腹茯蔔複覆輹輻馥鰒本乶俸奉封峯峰捧棒烽熢琫縫蓬蜂逢鋒鳳不付俯傅剖副否咐埠夫婦�".split(""); +for(j = 0; j != D[220].length; ++j) if(D[220][j].charCodeAt(0) !== 0xFFFD) { e[D[220][j]] = 56320 + j; d[56320 + j] = D[220][j];} +D[221] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������孚孵富府復扶敷斧浮溥父符簿缶腐腑膚艀芙莩訃負賦賻赴趺部釜阜附駙鳧北分吩噴墳奔奮忿憤扮昐汾焚盆粉糞紛芬賁雰不佛弗彿拂崩朋棚硼繃鵬丕備匕匪卑妃婢庇悲憊扉批斐枇榧比毖毗毘沸泌琵痺砒碑秕秘粃緋翡肥�".split(""); +for(j = 0; j != D[221].length; ++j) if(D[221][j].charCodeAt(0) !== 0xFFFD) { e[D[221][j]] = 56576 + j; d[56576 + j] = D[221][j];} +D[222] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������脾臂菲蜚裨誹譬費鄙非飛鼻嚬嬪彬斌檳殯浜濱瀕牝玭貧賓頻憑氷聘騁乍事些仕伺似使俟僿史司唆嗣四士奢娑寫寺射巳師徙思捨斜斯柶査梭死沙泗渣瀉獅砂社祀祠私篩紗絲肆舍莎蓑蛇裟詐詞謝賜赦辭邪飼駟麝削數朔索�".split(""); +for(j = 0; j != D[222].length; ++j) if(D[222][j].charCodeAt(0) !== 0xFFFD) { e[D[222][j]] = 56832 + j; d[56832 + j] = D[222][j];} +D[223] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������傘刪山散汕珊産疝算蒜酸霰乷撒殺煞薩三參杉森渗芟蔘衫揷澁鈒颯上傷像償商喪嘗孀尙峠常床庠廂想桑橡湘爽牀狀相祥箱翔裳觴詳象賞霜塞璽賽嗇塞穡索色牲生甥省笙墅壻嶼序庶徐恕抒捿敍暑曙書栖棲犀瑞筮絮緖署�".split(""); +for(j = 0; j != D[223].length; ++j) if(D[223][j].charCodeAt(0) !== 0xFFFD) { e[D[223][j]] = 57088 + j; d[57088 + j] = D[223][j];} +D[224] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������胥舒薯西誓逝鋤黍鼠夕奭席惜昔晳析汐淅潟石碩蓆釋錫仙僊先善嬋宣扇敾旋渲煽琁瑄璇璿癬禪線繕羨腺膳船蘚蟬詵跣選銑鐥饍鮮卨屑楔泄洩渫舌薛褻設說雪齧剡暹殲纖蟾贍閃陝攝涉燮葉城姓宬性惺成星晟猩珹盛省筬�".split(""); +for(j = 0; j != D[224].length; ++j) if(D[224][j].charCodeAt(0) !== 0xFFFD) { e[D[224][j]] = 57344 + j; d[57344 + j] = D[224][j];} +D[225] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������聖聲腥誠醒世勢歲洗稅笹細說貰召嘯塑宵小少巢所掃搔昭梳沼消溯瀟炤燒甦疏疎瘙笑篠簫素紹蔬蕭蘇訴逍遡邵銷韶騷俗屬束涑粟續謖贖速孫巽損蓀遜飡率宋悚松淞訟誦送頌刷殺灑碎鎖衰釗修受嗽囚垂壽嫂守岫峀帥愁�".split(""); +for(j = 0; j != D[225].length; ++j) if(D[225][j].charCodeAt(0) !== 0xFFFD) { e[D[225][j]] = 57600 + j; d[57600 + j] = D[225][j];} +D[226] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������戍手授搜收數樹殊水洙漱燧狩獸琇璲瘦睡秀穗竪粹綏綬繡羞脩茱蒐蓚藪袖誰讐輸遂邃酬銖銹隋隧隨雖需須首髓鬚叔塾夙孰宿淑潚熟琡璹肅菽巡徇循恂旬栒楯橓殉洵淳珣盾瞬筍純脣舜荀蓴蕣詢諄醇錞順馴戌術述鉥崇崧�".split(""); +for(j = 0; j != D[226].length; ++j) if(D[226][j].charCodeAt(0) !== 0xFFFD) { e[D[226][j]] = 57856 + j; d[57856 + j] = D[226][j];} +D[227] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������嵩瑟膝蝨濕拾習褶襲丞乘僧勝升承昇繩蠅陞侍匙嘶始媤尸屎屍市弑恃施是時枾柴猜矢示翅蒔蓍視試詩諡豕豺埴寔式息拭植殖湜熄篒蝕識軾食飾伸侁信呻娠宸愼新晨燼申神紳腎臣莘薪藎蜃訊身辛辰迅失室實悉審尋心沁�".split(""); +for(j = 0; j != D[227].length; ++j) if(D[227][j].charCodeAt(0) !== 0xFFFD) { e[D[227][j]] = 58112 + j; d[58112 + j] = D[227][j];} +D[228] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������沈深瀋甚芯諶什十拾雙氏亞俄兒啞娥峨我牙芽莪蛾衙訝阿雅餓鴉鵝堊岳嶽幄惡愕握樂渥鄂鍔顎鰐齷安岸按晏案眼雁鞍顔鮟斡謁軋閼唵岩巖庵暗癌菴闇壓押狎鴨仰央怏昻殃秧鴦厓哀埃崖愛曖涯碍艾隘靄厄扼掖液縊腋額�".split(""); +for(j = 0; j != D[228].length; ++j) if(D[228][j].charCodeAt(0) !== 0xFFFD) { e[D[228][j]] = 58368 + j; d[58368 + j] = D[228][j];} +D[229] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������櫻罌鶯鸚也倻冶夜惹揶椰爺耶若野弱掠略約若葯蒻藥躍亮佯兩凉壤孃恙揚攘敭暘梁楊樣洋瀁煬痒瘍禳穰糧羊良襄諒讓釀陽量養圄御於漁瘀禦語馭魚齬億憶抑檍臆偃堰彦焉言諺孼蘖俺儼嚴奄掩淹嶪業円予余勵呂女如廬�".split(""); +for(j = 0; j != D[229].length; ++j) if(D[229][j].charCodeAt(0) !== 0xFFFD) { e[D[229][j]] = 58624 + j; d[58624 + j] = D[229][j];} +D[230] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������旅歟汝濾璵礖礪與艅茹輿轝閭餘驪麗黎亦力域役易曆歷疫繹譯轢逆驛嚥堧姸娟宴年延憐戀捐挻撚椽沇沿涎涓淵演漣烟然煙煉燃燕璉硏硯秊筵緣練縯聯衍軟輦蓮連鉛鍊鳶列劣咽悅涅烈熱裂說閱厭廉念捻染殮炎焰琰艶苒�".split(""); +for(j = 0; j != D[230].length; ++j) if(D[230][j].charCodeAt(0) !== 0xFFFD) { e[D[230][j]] = 58880 + j; d[58880 + j] = D[230][j];} +D[231] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������簾閻髥鹽曄獵燁葉令囹塋寧嶺嶸影怜映暎楹榮永泳渶潁濚瀛瀯煐營獰玲瑛瑩瓔盈穎纓羚聆英詠迎鈴鍈零霙靈領乂倪例刈叡曳汭濊猊睿穢芮藝蘂禮裔詣譽豫醴銳隸霓預五伍俉傲午吾吳嗚塢墺奧娛寤悟惡懊敖旿晤梧汚澳�".split(""); +for(j = 0; j != D[231].length; ++j) if(D[231][j].charCodeAt(0) !== 0xFFFD) { e[D[231][j]] = 59136 + j; d[59136 + j] = D[231][j];} +D[232] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������烏熬獒筽蜈誤鰲鼇屋沃獄玉鈺溫瑥瘟穩縕蘊兀壅擁瓮甕癰翁邕雍饔渦瓦窩窪臥蛙蝸訛婉完宛梡椀浣玩琓琬碗緩翫脘腕莞豌阮頑曰往旺枉汪王倭娃歪矮外嵬巍猥畏了僚僥凹堯夭妖姚寥寮尿嶢拗搖撓擾料曜樂橈燎燿瑤療�".split(""); +for(j = 0; j != D[232].length; ++j) if(D[232][j].charCodeAt(0) !== 0xFFFD) { e[D[232][j]] = 59392 + j; d[59392 + j] = D[232][j];} +D[233] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������窈窯繇繞耀腰蓼蟯要謠遙遼邀饒慾欲浴縟褥辱俑傭冗勇埇墉容庸慂榕涌湧溶熔瑢用甬聳茸蓉踊鎔鏞龍于佑偶優又友右宇寓尤愚憂旴牛玗瑀盂祐禑禹紆羽芋藕虞迂遇郵釪隅雨雩勖彧旭昱栯煜稶郁頊云暈橒殞澐熉耘芸蕓�".split(""); +for(j = 0; j != D[233].length; ++j) if(D[233][j].charCodeAt(0) !== 0xFFFD) { e[D[233][j]] = 59648 + j; d[59648 + j] = D[233][j];} +D[234] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������運隕雲韻蔚鬱亐熊雄元原員圓園垣媛嫄寃怨愿援沅洹湲源爰猿瑗苑袁轅遠阮院願鴛月越鉞位偉僞危圍委威尉慰暐渭爲瑋緯胃萎葦蔿蝟衛褘謂違韋魏乳侑儒兪劉唯喩孺宥幼幽庾悠惟愈愉揄攸有杻柔柚柳楡楢油洧流游溜�".split(""); +for(j = 0; j != D[234].length; ++j) if(D[234][j].charCodeAt(0) !== 0xFFFD) { e[D[234][j]] = 59904 + j; d[59904 + j] = D[234][j];} +D[235] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������濡猶猷琉瑜由留癒硫紐維臾萸裕誘諛諭踰蹂遊逾遺酉釉鍮類六堉戮毓肉育陸倫允奫尹崙淪潤玧胤贇輪鈗閏律慄栗率聿戎瀜絨融隆垠恩慇殷誾銀隱乙吟淫蔭陰音飮揖泣邑凝應膺鷹依倚儀宜意懿擬椅毅疑矣義艤薏蟻衣誼�".split(""); +for(j = 0; j != D[235].length; ++j) if(D[235][j].charCodeAt(0) !== 0xFFFD) { e[D[235][j]] = 60160 + j; d[60160 + j] = D[235][j];} +D[236] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������議醫二以伊利吏夷姨履已弛彛怡易李梨泥爾珥理異痍痢移罹而耳肄苡荑裏裡貽貳邇里離飴餌匿溺瀷益翊翌翼謚人仁刃印吝咽因姻寅引忍湮燐璘絪茵藺蚓認隣靭靷鱗麟一佚佾壹日溢逸鎰馹任壬妊姙恁林淋稔臨荏賃入卄�".split(""); +for(j = 0; j != D[236].length; ++j) if(D[236][j].charCodeAt(0) !== 0xFFFD) { e[D[236][j]] = 60416 + j; d[60416 + j] = D[236][j];} +D[237] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������立笠粒仍剩孕芿仔刺咨姉姿子字孜恣慈滋炙煮玆瓷疵磁紫者自茨蔗藉諮資雌作勺嚼斫昨灼炸爵綽芍酌雀鵲孱棧殘潺盞岑暫潛箴簪蠶雜丈仗匠場墻壯奬將帳庄張掌暲杖樟檣欌漿牆狀獐璋章粧腸臟臧莊葬蔣薔藏裝贓醬長�".split(""); +for(j = 0; j != D[237].length; ++j) if(D[237][j].charCodeAt(0) !== 0xFFFD) { e[D[237][j]] = 60672 + j; d[60672 + j] = D[237][j];} +D[238] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������障再哉在宰才材栽梓渽滓災縡裁財載齋齎爭箏諍錚佇低儲咀姐底抵杵楮樗沮渚狙猪疽箸紵苧菹著藷詛貯躇這邸雎齟勣吊嫡寂摘敵滴狄炙的積笛籍績翟荻謫賊赤跡蹟迪迹適鏑佃佺傳全典前剪塡塼奠專展廛悛戰栓殿氈澱�".split(""); +for(j = 0; j != D[238].length; ++j) if(D[238][j].charCodeAt(0) !== 0xFFFD) { e[D[238][j]] = 60928 + j; d[60928 + j] = D[238][j];} +D[239] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������煎琠田甸畑癲筌箋箭篆纏詮輾轉鈿銓錢鐫電顚顫餞切截折浙癤竊節絶占岾店漸点粘霑鮎點接摺蝶丁井亭停偵呈姃定幀庭廷征情挺政整旌晶晸柾楨檉正汀淀淨渟湞瀞炡玎珽町睛碇禎程穽精綎艇訂諪貞鄭酊釘鉦鋌錠霆靖�".split(""); +for(j = 0; j != D[239].length; ++j) if(D[239][j].charCodeAt(0) !== 0xFFFD) { e[D[239][j]] = 61184 + j; d[61184 + j] = D[239][j];} +D[240] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������靜頂鼎制劑啼堤帝弟悌提梯濟祭第臍薺製諸蹄醍除際霽題齊俎兆凋助嘲弔彫措操早晁曺曹朝條棗槽漕潮照燥爪璪眺祖祚租稠窕粗糟組繰肇藻蚤詔調趙躁造遭釣阻雕鳥族簇足鏃存尊卒拙猝倧宗從悰慫棕淙琮種終綜縱腫�".split(""); +for(j = 0; j != D[240].length; ++j) if(D[240][j].charCodeAt(0) !== 0xFFFD) { e[D[240][j]] = 61440 + j; d[61440 + j] = D[240][j];} +D[241] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������踪踵鍾鐘佐坐左座挫罪主住侏做姝胄呪周嗾奏宙州廚晝朱柱株注洲湊澍炷珠疇籌紂紬綢舟蛛註誅走躊輳週酎酒鑄駐竹粥俊儁准埈寯峻晙樽浚準濬焌畯竣蠢逡遵雋駿茁中仲衆重卽櫛楫汁葺增憎曾拯烝甑症繒蒸證贈之只�".split(""); +for(j = 0; j != D[241].length; ++j) if(D[241][j].charCodeAt(0) !== 0xFFFD) { e[D[241][j]] = 61696 + j; d[61696 + j] = D[241][j];} +D[242] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������咫地址志持指摯支旨智枝枳止池沚漬知砥祉祗紙肢脂至芝芷蜘誌識贄趾遲直稙稷織職唇嗔塵振搢晉晋桭榛殄津溱珍瑨璡畛疹盡眞瞋秦縉縝臻蔯袗診賑軫辰進鎭陣陳震侄叱姪嫉帙桎瓆疾秩窒膣蛭質跌迭斟朕什執潗緝輯�".split(""); +for(j = 0; j != D[242].length; ++j) if(D[242][j].charCodeAt(0) !== 0xFFFD) { e[D[242][j]] = 61952 + j; d[61952 + j] = D[242][j];} +D[243] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������鏶集徵懲澄且侘借叉嗟嵯差次此磋箚茶蹉車遮捉搾着窄錯鑿齪撰澯燦璨瓚竄簒纂粲纘讚贊鑽餐饌刹察擦札紮僭參塹慘慙懺斬站讒讖倉倡創唱娼廠彰愴敞昌昶暢槍滄漲猖瘡窓脹艙菖蒼債埰寀寨彩採砦綵菜蔡采釵冊柵策�".split(""); +for(j = 0; j != D[243].length; ++j) if(D[243][j].charCodeAt(0) !== 0xFFFD) { e[D[243][j]] = 62208 + j; d[62208 + j] = D[243][j];} +D[244] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������責凄妻悽處倜刺剔尺慽戚拓擲斥滌瘠脊蹠陟隻仟千喘天川擅泉淺玔穿舛薦賤踐遷釧闡阡韆凸哲喆徹撤澈綴輟轍鐵僉尖沾添甛瞻簽籤詹諂堞妾帖捷牒疊睫諜貼輒廳晴淸聽菁請靑鯖切剃替涕滯締諦逮遞體初剿哨憔抄招梢�".split(""); +for(j = 0; j != D[244].length; ++j) if(D[244][j].charCodeAt(0) !== 0xFFFD) { e[D[244][j]] = 62464 + j; d[62464 + j] = D[244][j];} +D[245] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������椒楚樵炒焦硝礁礎秒稍肖艸苕草蕉貂超酢醋醮促囑燭矗蜀觸寸忖村邨叢塚寵悤憁摠總聰蔥銃撮催崔最墜抽推椎楸樞湫皺秋芻萩諏趨追鄒酋醜錐錘鎚雛騶鰍丑畜祝竺筑築縮蓄蹙蹴軸逐春椿瑃出朮黜充忠沖蟲衝衷悴膵萃�".split(""); +for(j = 0; j != D[245].length; ++j) if(D[245][j].charCodeAt(0) !== 0xFFFD) { e[D[245][j]] = 62720 + j; d[62720 + j] = D[245][j];} +D[246] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������贅取吹嘴娶就炊翠聚脆臭趣醉驟鷲側仄厠惻測層侈値嗤峙幟恥梔治淄熾痔痴癡稚穉緇緻置致蚩輜雉馳齒則勅飭親七柒漆侵寢枕沈浸琛砧針鍼蟄秤稱快他咤唾墮妥惰打拖朶楕舵陀馱駝倬卓啄坼度托拓擢晫柝濁濯琢琸託�".split(""); +for(j = 0; j != D[246].length; ++j) if(D[246][j].charCodeAt(0) !== 0xFFFD) { e[D[246][j]] = 62976 + j; d[62976 + j] = D[246][j];} +D[247] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������鐸呑嘆坦彈憚歎灘炭綻誕奪脫探眈耽貪塔搭榻宕帑湯糖蕩兌台太怠態殆汰泰笞胎苔跆邰颱宅擇澤撑攄兎吐土討慟桶洞痛筒統通堆槌腿褪退頹偸套妬投透鬪慝特闖坡婆巴把播擺杷波派爬琶破罷芭跛頗判坂板版瓣販辦鈑�".split(""); +for(j = 0; j != D[247].length; ++j) if(D[247][j].charCodeAt(0) !== 0xFFFD) { e[D[247][j]] = 63232 + j; d[63232 + j] = D[247][j];} +D[248] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������阪八叭捌佩唄悖敗沛浿牌狽稗覇貝彭澎烹膨愎便偏扁片篇編翩遍鞭騙貶坪平枰萍評吠嬖幣廢弊斃肺蔽閉陛佈包匍匏咆哺圃布怖抛抱捕暴泡浦疱砲胞脯苞葡蒲袍褒逋鋪飽鮑幅暴曝瀑爆輻俵剽彪慓杓標漂瓢票表豹飇飄驃�".split(""); +for(j = 0; j != D[248].length; ++j) if(D[248][j].charCodeAt(0) !== 0xFFFD) { e[D[248][j]] = 63488 + j; d[63488 + j] = D[248][j];} +D[249] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������品稟楓諷豊風馮彼披疲皮被避陂匹弼必泌珌畢疋筆苾馝乏逼下何厦夏廈昰河瑕荷蝦賀遐霞鰕壑學虐謔鶴寒恨悍旱汗漢澣瀚罕翰閑閒限韓割轄函含咸啣喊檻涵緘艦銜陷鹹合哈盒蛤閤闔陜亢伉姮嫦巷恒抗杭桁沆港缸肛航�".split(""); +for(j = 0; j != D[249].length; ++j) if(D[249][j].charCodeAt(0) !== 0xFFFD) { e[D[249][j]] = 63744 + j; d[63744 + j] = D[249][j];} +D[250] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������行降項亥偕咳垓奚孩害懈楷海瀣蟹解該諧邂駭骸劾核倖幸杏荇行享向嚮珦鄕響餉饗香噓墟虛許憲櫶獻軒歇險驗奕爀赫革俔峴弦懸晛泫炫玄玹現眩睍絃絢縣舷衒見賢鉉顯孑穴血頁嫌俠協夾峽挾浹狹脅脇莢鋏頰亨兄刑型�".split(""); +for(j = 0; j != D[250].length; ++j) if(D[250][j].charCodeAt(0) !== 0xFFFD) { e[D[250][j]] = 64000 + j; d[64000 + j] = D[250][j];} +D[251] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������形泂滎瀅灐炯熒珩瑩荊螢衡逈邢鎣馨兮彗惠慧暳蕙蹊醯鞋乎互呼壕壺好岵弧戶扈昊晧毫浩淏湖滸澔濠濩灝狐琥瑚瓠皓祜糊縞胡芦葫蒿虎號蝴護豪鎬頀顥惑或酷婚昏混渾琿魂忽惚笏哄弘汞泓洪烘紅虹訌鴻化和嬅樺火畵�".split(""); +for(j = 0; j != D[251].length; ++j) if(D[251][j].charCodeAt(0) !== 0xFFFD) { e[D[251][j]] = 64256 + j; d[64256 + j] = D[251][j];} +D[252] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������禍禾花華話譁貨靴廓擴攫確碻穫丸喚奐宦幻患換歡晥桓渙煥環紈還驩鰥活滑猾豁闊凰幌徨恍惶愰慌晃晄榥況湟滉潢煌璜皇篁簧荒蝗遑隍黃匯回廻徊恢悔懷晦會檜淮澮灰獪繪膾茴蛔誨賄劃獲宖橫鐄哮嚆孝效斅曉梟涍淆�".split(""); +for(j = 0; j != D[252].length; ++j) if(D[252][j].charCodeAt(0) !== 0xFFFD) { e[D[252][j]] = 64512 + j; d[64512 + j] = D[252][j];} +D[253] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������爻肴酵驍侯候厚后吼喉嗅帿後朽煦珝逅勛勳塤壎焄熏燻薰訓暈薨喧暄煊萱卉喙毁彙徽揮暉煇諱輝麾休携烋畦虧恤譎鷸兇凶匈洶胸黑昕欣炘痕吃屹紇訖欠欽歆吸恰洽翕興僖凞喜噫囍姬嬉希憙憘戱晞曦熙熹熺犧禧稀羲詰�".split(""); +for(j = 0; j != D[253].length; ++j) if(D[253][j].charCodeAt(0) !== 0xFFFD) { e[D[253][j]] = 64768 + j; d[64768 + j] = D[253][j];} +return {"enc": e, "dec": d }; })(); +cptable[950] = (function(){ var d = [], e = {}, D = [], j; +D[0] = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~��������������������������������������������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[0].length; ++j) if(D[0][j].charCodeAt(0) !== 0xFFFD) { e[D[0][j]] = 0 + j; d[0 + j] = D[0][j];} +D[161] = "���������������������������������������������������������������� ,、。.‧;:?!︰…‥﹐﹑﹒·﹔﹕﹖﹗|–︱—︳╴︴﹏()︵︶{}︷︸〔〕︹︺【】︻︼《》︽︾〈〉︿﹀「」﹁﹂『』﹃﹄﹙﹚����������������������������������﹛﹜﹝﹞‘’“”〝〞‵′#&*※§〃○●△▲◎☆★◇◆□■▽▼㊣℅¯ ̄_ˍ﹉﹊﹍﹎﹋﹌﹟﹠﹡+-×÷±√<>=≦≧≠∞≒≡﹢﹣﹤﹥﹦~∩∪⊥∠∟⊿㏒㏑∫∮∵∴♀♂⊕⊙↑↓←→↖↗↙↘∥∣/�".split(""); +for(j = 0; j != D[161].length; ++j) if(D[161][j].charCodeAt(0) !== 0xFFFD) { e[D[161][j]] = 41216 + j; d[41216 + j] = D[161][j];} +D[162] = "����������������������������������������������������������������\∕﹨$¥〒¢£%@℃℉﹩﹪﹫㏕㎜㎝㎞㏎㎡㎎㎏㏄°兙兛兞兝兡兣嗧瓩糎▁▂▃▄▅▆▇█▏▎▍▌▋▊▉┼┴┬┤├▔─│▕┌┐└┘╭����������������������������������╮╰╯═╞╪╡◢◣◥◤╱╲╳0123456789ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ〡〢〣〤〥〦〧〨〩十卄卅ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv�".split(""); +for(j = 0; j != D[162].length; ++j) if(D[162][j].charCodeAt(0) !== 0xFFFD) { e[D[162][j]] = 41472 + j; d[41472 + j] = D[162][j];} +D[163] = "����������������������������������������������������������������wxyzΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψωㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏ����������������������������������ㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩ˙ˉˊˇˋ���������������������������������€������������������������������".split(""); +for(j = 0; j != D[163].length; ++j) if(D[163][j].charCodeAt(0) !== 0xFFFD) { e[D[163][j]] = 41728 + j; d[41728 + j] = D[163][j];} +D[164] = "����������������������������������������������������������������一乙丁七乃九了二人儿入八几刀刁力匕十卜又三下丈上丫丸凡久么也乞于亡兀刃勺千叉口土士夕大女子孑孓寸小尢尸山川工己已巳巾干廾弋弓才����������������������������������丑丐不中丰丹之尹予云井互五亢仁什仃仆仇仍今介仄元允內六兮公冗凶分切刈勻勾勿化匹午升卅卞厄友及反壬天夫太夭孔少尤尺屯巴幻廿弔引心戈戶手扎支文斗斤方日曰月木欠止歹毋比毛氏水火爪父爻片牙牛犬王丙�".split(""); +for(j = 0; j != D[164].length; ++j) if(D[164][j].charCodeAt(0) !== 0xFFFD) { e[D[164][j]] = 41984 + j; d[41984 + j] = D[164][j];} +D[165] = "����������������������������������������������������������������世丕且丘主乍乏乎以付仔仕他仗代令仙仞充兄冉冊冬凹出凸刊加功包匆北匝仟半卉卡占卯卮去可古右召叮叩叨叼司叵叫另只史叱台句叭叻四囚外����������������������������������央失奴奶孕它尼巨巧左市布平幼弁弘弗必戊打扔扒扑斥旦朮本未末札正母民氐永汁汀氾犯玄玉瓜瓦甘生用甩田由甲申疋白皮皿目矛矢石示禾穴立丞丟乒乓乩亙交亦亥仿伉伙伊伕伍伐休伏仲件任仰仳份企伋光兇兆先全�".split(""); +for(j = 0; j != D[165].length; ++j) if(D[165][j].charCodeAt(0) !== 0xFFFD) { e[D[165][j]] = 42240 + j; d[42240 + j] = D[165][j];} +D[166] = "����������������������������������������������������������������共再冰列刑划刎刖劣匈匡匠印危吉吏同吊吐吁吋各向名合吃后吆吒因回囝圳地在圭圬圯圩夙多夷夸妄奸妃好她如妁字存宇守宅安寺尖屹州帆并年����������������������������������式弛忙忖戎戌戍成扣扛托收早旨旬旭曲曳有朽朴朱朵次此死氖汝汗汙江池汐汕污汛汍汎灰牟牝百竹米糸缶羊羽老考而耒耳聿肉肋肌臣自至臼舌舛舟艮色艾虫血行衣西阡串亨位住佇佗佞伴佛何估佐佑伽伺伸佃佔似但佣�".split(""); +for(j = 0; j != D[166].length; ++j) if(D[166][j].charCodeAt(0) !== 0xFFFD) { e[D[166][j]] = 42496 + j; d[42496 + j] = D[166][j];} +D[167] = "����������������������������������������������������������������作你伯低伶余佝佈佚兌克免兵冶冷別判利刪刨劫助努劬匣即卵吝吭吞吾否呎吧呆呃吳呈呂君吩告吹吻吸吮吵吶吠吼呀吱含吟听囪困囤囫坊坑址坍����������������������������������均坎圾坐坏圻壯夾妝妒妨妞妣妙妖妍妤妓妊妥孝孜孚孛完宋宏尬局屁尿尾岐岑岔岌巫希序庇床廷弄弟彤形彷役忘忌志忍忱快忸忪戒我抄抗抖技扶抉扭把扼找批扳抒扯折扮投抓抑抆改攻攸旱更束李杏材村杜杖杞杉杆杠�".split(""); +for(j = 0; j != D[167].length; ++j) if(D[167][j].charCodeAt(0) !== 0xFFFD) { e[D[167][j]] = 42752 + j; d[42752 + j] = D[167][j];} +D[168] = "����������������������������������������������������������������杓杗步每求汞沙沁沈沉沅沛汪決沐汰沌汨沖沒汽沃汲汾汴沆汶沍沔沘沂灶灼災灸牢牡牠狄狂玖甬甫男甸皂盯矣私秀禿究系罕肖肓肝肘肛肚育良芒����������������������������������芋芍見角言谷豆豕貝赤走足身車辛辰迂迆迅迄巡邑邢邪邦那酉釆里防阮阱阪阬並乖乳事些亞享京佯依侍佳使佬供例來侃佰併侈佩佻侖佾侏侑佺兔兒兕兩具其典冽函刻券刷刺到刮制剁劾劻卒協卓卑卦卷卸卹取叔受味呵�".split(""); +for(j = 0; j != D[168].length; ++j) if(D[168][j].charCodeAt(0) !== 0xFFFD) { e[D[168][j]] = 43008 + j; d[43008 + j] = D[168][j];} +D[169] = "����������������������������������������������������������������咖呸咕咀呻呷咄咒咆呼咐呱呶和咚呢周咋命咎固垃坷坪坩坡坦坤坼夜奉奇奈奄奔妾妻委妹妮姑姆姐姍始姓姊妯妳姒姅孟孤季宗定官宜宙宛尚屈居����������������������������������屆岷岡岸岩岫岱岳帘帚帖帕帛帑幸庚店府底庖延弦弧弩往征彿彼忝忠忽念忿怏怔怯怵怖怪怕怡性怩怫怛或戕房戾所承拉拌拄抿拂抹拒招披拓拔拋拈抨抽押拐拙拇拍抵拚抱拘拖拗拆抬拎放斧於旺昔易昌昆昂明昀昏昕昊�".split(""); +for(j = 0; j != D[169].length; ++j) if(D[169][j].charCodeAt(0) !== 0xFFFD) { e[D[169][j]] = 43264 + j; d[43264 + j] = D[169][j];} +D[170] = "����������������������������������������������������������������昇服朋杭枋枕東果杳杷枇枝林杯杰板枉松析杵枚枓杼杪杲欣武歧歿氓氛泣注泳沱泌泥河沽沾沼波沫法泓沸泄油況沮泗泅泱沿治泡泛泊沬泯泜泖泠����������������������������������炕炎炒炊炙爬爭爸版牧物狀狎狙狗狐玩玨玟玫玥甽疝疙疚的盂盲直知矽社祀祁秉秈空穹竺糾罔羌羋者肺肥肢肱股肫肩肴肪肯臥臾舍芳芝芙芭芽芟芹花芬芥芯芸芣芰芾芷虎虱初表軋迎返近邵邸邱邶采金長門阜陀阿阻附�".split(""); +for(j = 0; j != D[170].length; ++j) if(D[170][j].charCodeAt(0) !== 0xFFFD) { e[D[170][j]] = 43520 + j; d[43520 + j] = D[170][j];} +D[171] = "����������������������������������������������������������������陂隹雨青非亟亭亮信侵侯便俠俑俏保促侶俘俟俊俗侮俐俄係俚俎俞侷兗冒冑冠剎剃削前剌剋則勇勉勃勁匍南卻厚叛咬哀咨哎哉咸咦咳哇哂咽咪品����������������������������������哄哈咯咫咱咻咩咧咿囿垂型垠垣垢城垮垓奕契奏奎奐姜姘姿姣姨娃姥姪姚姦威姻孩宣宦室客宥封屎屏屍屋峙峒巷帝帥帟幽庠度建弈弭彥很待徊律徇後徉怒思怠急怎怨恍恰恨恢恆恃恬恫恪恤扁拜挖按拼拭持拮拽指拱拷�".split(""); +for(j = 0; j != D[171].length; ++j) if(D[171][j].charCodeAt(0) !== 0xFFFD) { e[D[171][j]] = 43776 + j; d[43776 + j] = D[171][j];} +D[172] = "����������������������������������������������������������������拯括拾拴挑挂政故斫施既春昭映昧是星昨昱昤曷柿染柱柔某柬架枯柵柩柯柄柑枴柚查枸柏柞柳枰柙柢柝柒歪殃殆段毒毗氟泉洋洲洪流津洌洱洞洗����������������������������������活洽派洶洛泵洹洧洸洩洮洵洎洫炫為炳炬炯炭炸炮炤爰牲牯牴狩狠狡玷珊玻玲珍珀玳甚甭畏界畎畋疫疤疥疢疣癸皆皇皈盈盆盃盅省盹相眉看盾盼眇矜砂研砌砍祆祉祈祇禹禺科秒秋穿突竿竽籽紂紅紀紉紇約紆缸美羿耄�".split(""); +for(j = 0; j != D[172].length; ++j) if(D[172][j].charCodeAt(0) !== 0xFFFD) { e[D[172][j]] = 44032 + j; d[44032 + j] = D[172][j];} +D[173] = "����������������������������������������������������������������耐耍耑耶胖胥胚胃胄背胡胛胎胞胤胝致舢苧范茅苣苛苦茄若茂茉苒苗英茁苜苔苑苞苓苟苯茆虐虹虻虺衍衫要觔計訂訃貞負赴赳趴軍軌述迦迢迪迥����������������������������������迭迫迤迨郊郎郁郃酋酊重閂限陋陌降面革韋韭音頁風飛食首香乘亳倌倍倣俯倦倥俸倩倖倆值借倚倒們俺倀倔倨俱倡個候倘俳修倭倪俾倫倉兼冤冥冢凍凌准凋剖剜剔剛剝匪卿原厝叟哨唐唁唷哼哥哲唆哺唔哩哭員唉哮哪�".split(""); +for(j = 0; j != D[173].length; ++j) if(D[173][j].charCodeAt(0) !== 0xFFFD) { e[D[173][j]] = 44288 + j; d[44288 + j] = D[173][j];} +D[174] = "����������������������������������������������������������������哦唧唇哽唏圃圄埂埔埋埃堉夏套奘奚娑娘娜娟娛娓姬娠娣娩娥娌娉孫屘宰害家宴宮宵容宸射屑展屐峭峽峻峪峨峰島崁峴差席師庫庭座弱徒徑徐恙����������������������������������恣恥恐恕恭恩息悄悟悚悍悔悌悅悖扇拳挈拿捎挾振捕捂捆捏捉挺捐挽挪挫挨捍捌效敉料旁旅時晉晏晃晒晌晅晁書朔朕朗校核案框桓根桂桔栩梳栗桌桑栽柴桐桀格桃株桅栓栘桁殊殉殷氣氧氨氦氤泰浪涕消涇浦浸海浙涓�".split(""); +for(j = 0; j != D[174].length; ++j) if(D[174][j].charCodeAt(0) !== 0xFFFD) { e[D[174][j]] = 44544 + j; d[44544 + j] = D[174][j];} +D[175] = "����������������������������������������������������������������浬涉浮浚浴浩涌涊浹涅浥涔烊烘烤烙烈烏爹特狼狹狽狸狷玆班琉珮珠珪珞畔畝畜畚留疾病症疲疳疽疼疹痂疸皋皰益盍盎眩真眠眨矩砰砧砸砝破砷����������������������������������砥砭砠砟砲祕祐祠祟祖神祝祗祚秤秣秧租秦秩秘窄窈站笆笑粉紡紗紋紊素索純紐紕級紜納紙紛缺罟羔翅翁耆耘耕耙耗耽耿胱脂胰脅胭胴脆胸胳脈能脊胼胯臭臬舀舐航舫舨般芻茫荒荔荊茸荐草茵茴荏茲茹茶茗荀茱茨荃�".split(""); +for(j = 0; j != D[175].length; ++j) if(D[175][j].charCodeAt(0) !== 0xFFFD) { e[D[175][j]] = 44800 + j; d[44800 + j] = D[175][j];} +D[176] = "����������������������������������������������������������������虔蚊蚪蚓蚤蚩蚌蚣蚜衰衷袁袂衽衹記訐討訌訕訊託訓訖訏訑豈豺豹財貢起躬軒軔軏辱送逆迷退迺迴逃追逅迸邕郡郝郢酒配酌釘針釗釜釙閃院陣陡����������������������������������陛陝除陘陞隻飢馬骨高鬥鬲鬼乾偺偽停假偃偌做偉健偶偎偕偵側偷偏倏偯偭兜冕凰剪副勒務勘動匐匏匙匿區匾參曼商啪啦啄啞啡啃啊唱啖問啕唯啤唸售啜唬啣唳啁啗圈國圉域堅堊堆埠埤基堂堵執培夠奢娶婁婉婦婪婀�".split(""); +for(j = 0; j != D[176].length; ++j) if(D[176][j].charCodeAt(0) !== 0xFFFD) { e[D[176][j]] = 45056 + j; d[45056 + j] = D[176][j];} +D[177] = "����������������������������������������������������������������娼婢婚婆婊孰寇寅寄寂宿密尉專將屠屜屝崇崆崎崛崖崢崑崩崔崙崤崧崗巢常帶帳帷康庸庶庵庾張強彗彬彩彫得徙從徘御徠徜恿患悉悠您惋悴惦悽����������������������������������情悻悵惜悼惘惕惆惟悸惚惇戚戛扈掠控捲掖探接捷捧掘措捱掩掉掃掛捫推掄授掙採掬排掏掀捻捩捨捺敝敖救教敗啟敏敘敕敔斜斛斬族旋旌旎晝晚晤晨晦晞曹勗望梁梯梢梓梵桿桶梱梧梗械梃棄梭梆梅梔條梨梟梡梂欲殺�".split(""); +for(j = 0; j != D[177].length; ++j) if(D[177][j].charCodeAt(0) !== 0xFFFD) { e[D[177][j]] = 45312 + j; d[45312 + j] = D[177][j];} +D[178] = "����������������������������������������������������������������毫毬氫涎涼淳淙液淡淌淤添淺清淇淋涯淑涮淞淹涸混淵淅淒渚涵淚淫淘淪深淮淨淆淄涪淬涿淦烹焉焊烽烯爽牽犁猜猛猖猓猙率琅琊球理現琍瓠瓶����������������������������������瓷甜產略畦畢異疏痔痕疵痊痍皎盔盒盛眷眾眼眶眸眺硫硃硎祥票祭移窒窕笠笨笛第符笙笞笮粒粗粕絆絃統紮紹紼絀細紳組累終紲紱缽羞羚翌翎習耜聊聆脯脖脣脫脩脰脤舂舵舷舶船莎莞莘荸莢莖莽莫莒莊莓莉莠荷荻荼�".split(""); +for(j = 0; j != D[178].length; ++j) if(D[178][j].charCodeAt(0) !== 0xFFFD) { e[D[178][j]] = 45568 + j; d[45568 + j] = D[178][j];} +D[179] = "����������������������������������������������������������������莆莧處彪蛇蛀蚶蛄蚵蛆蛋蚱蚯蛉術袞袈被袒袖袍袋覓規訪訝訣訥許設訟訛訢豉豚販責貫貨貪貧赧赦趾趺軛軟這逍通逗連速逝逐逕逞造透逢逖逛途����������������������������������部郭都酗野釵釦釣釧釭釩閉陪陵陳陸陰陴陶陷陬雀雪雩章竟頂頃魚鳥鹵鹿麥麻傢傍傅備傑傀傖傘傚最凱割剴創剩勞勝勛博厥啻喀喧啼喊喝喘喂喜喪喔喇喋喃喳單喟唾喲喚喻喬喱啾喉喫喙圍堯堪場堤堰報堡堝堠壹壺奠�".split(""); +for(j = 0; j != D[179].length; ++j) if(D[179][j].charCodeAt(0) !== 0xFFFD) { e[D[179][j]] = 45824 + j; d[45824 + j] = D[179][j];} +D[180] = "����������������������������������������������������������������婷媚婿媒媛媧孳孱寒富寓寐尊尋就嵌嵐崴嵇巽幅帽幀幃幾廊廁廂廄弼彭復循徨惑惡悲悶惠愜愣惺愕惰惻惴慨惱愎惶愉愀愒戟扉掣掌描揀揩揉揆揍����������������������������������插揣提握揖揭揮捶援揪換摒揚揹敞敦敢散斑斐斯普晰晴晶景暑智晾晷曾替期朝棺棕棠棘棗椅棟棵森棧棹棒棲棣棋棍植椒椎棉棚楮棻款欺欽殘殖殼毯氮氯氬港游湔渡渲湧湊渠渥渣減湛湘渤湖湮渭渦湯渴湍渺測湃渝渾滋�".split(""); +for(j = 0; j != D[180].length; ++j) if(D[180][j].charCodeAt(0) !== 0xFFFD) { e[D[180][j]] = 46080 + j; d[46080 + j] = D[180][j];} +D[181] = "����������������������������������������������������������������溉渙湎湣湄湲湩湟焙焚焦焰無然煮焜牌犄犀猶猥猴猩琺琪琳琢琥琵琶琴琯琛琦琨甥甦畫番痢痛痣痙痘痞痠登發皖皓皴盜睏短硝硬硯稍稈程稅稀窘����������������������������������窗窖童竣等策筆筐筒答筍筋筏筑粟粥絞結絨絕紫絮絲絡給絢絰絳善翔翕耋聒肅腕腔腋腑腎脹腆脾腌腓腴舒舜菩萃菸萍菠菅萋菁華菱菴著萊菰萌菌菽菲菊萸萎萄菜萇菔菟虛蛟蛙蛭蛔蛛蛤蛐蛞街裁裂袱覃視註詠評詞証詁�".split(""); +for(j = 0; j != D[181].length; ++j) if(D[181][j].charCodeAt(0) !== 0xFFFD) { e[D[181][j]] = 46336 + j; d[46336 + j] = D[181][j];} +D[182] = "����������������������������������������������������������������詔詛詐詆訴診訶詖象貂貯貼貳貽賁費賀貴買貶貿貸越超趁跎距跋跚跑跌跛跆軻軸軼辜逮逵週逸進逶鄂郵鄉郾酣酥量鈔鈕鈣鈉鈞鈍鈐鈇鈑閔閏開閑����������������������������������間閒閎隊階隋陽隅隆隍陲隄雁雅雄集雇雯雲韌項順須飧飪飯飩飲飭馮馭黃黍黑亂傭債傲傳僅傾催傷傻傯僇剿剷剽募勦勤勢勣匯嗟嗨嗓嗦嗎嗜嗇嗑嗣嗤嗯嗚嗡嗅嗆嗥嗉園圓塞塑塘塗塚塔填塌塭塊塢塒塋奧嫁嫉嫌媾媽媼�".split(""); +for(j = 0; j != D[182].length; ++j) if(D[182][j].charCodeAt(0) !== 0xFFFD) { e[D[182][j]] = 46592 + j; d[46592 + j] = D[182][j];} +D[183] = "����������������������������������������������������������������媳嫂媲嵩嵯幌幹廉廈弒彙徬微愚意慈感想愛惹愁愈慎慌慄慍愾愴愧愍愆愷戡戢搓搾搞搪搭搽搬搏搜搔損搶搖搗搆敬斟新暗暉暇暈暖暄暘暍會榔業����������������������������������楚楷楠楔極椰概楊楨楫楞楓楹榆楝楣楛歇歲毀殿毓毽溢溯滓溶滂源溝滇滅溥溘溼溺溫滑準溜滄滔溪溧溴煎煙煩煤煉照煜煬煦煌煥煞煆煨煖爺牒猷獅猿猾瑯瑚瑕瑟瑞瑁琿瑙瑛瑜當畸瘀痰瘁痲痱痺痿痴痳盞盟睛睫睦睞督�".split(""); +for(j = 0; j != D[183].length; ++j) if(D[183][j].charCodeAt(0) !== 0xFFFD) { e[D[183][j]] = 46848 + j; d[46848 + j] = D[183][j];} +D[184] = "����������������������������������������������������������������睹睪睬睜睥睨睢矮碎碰碗碘碌碉硼碑碓硿祺祿禁萬禽稜稚稠稔稟稞窟窠筷節筠筮筧粱粳粵經絹綑綁綏絛置罩罪署義羨群聖聘肆肄腱腰腸腥腮腳腫����������������������������������腹腺腦舅艇蒂葷落萱葵葦葫葉葬葛萼萵葡董葩葭葆虞虜號蛹蜓蜈蜇蜀蛾蛻蜂蜃蜆蜊衙裟裔裙補裘裝裡裊裕裒覜解詫該詳試詩詰誇詼詣誠話誅詭詢詮詬詹詻訾詨豢貊貉賊資賈賄貲賃賂賅跡跟跨路跳跺跪跤跦躲較載軾輊�".split(""); +for(j = 0; j != D[184].length; ++j) if(D[184][j].charCodeAt(0) !== 0xFFFD) { e[D[184][j]] = 47104 + j; d[47104 + j] = D[184][j];} +D[185] = "����������������������������������������������������������������辟農運遊道遂達逼違遐遇遏過遍遑逾遁鄒鄗酬酪酩釉鈷鉗鈸鈽鉀鈾鉛鉋鉤鉑鈴鉉鉍鉅鈹鈿鉚閘隘隔隕雍雋雉雊雷電雹零靖靴靶預頑頓頊頒頌飼飴����������������������������������飽飾馳馱馴髡鳩麂鼎鼓鼠僧僮僥僖僭僚僕像僑僱僎僩兢凳劃劂匱厭嗾嘀嘛嘗嗽嘔嘆嘉嘍嘎嗷嘖嘟嘈嘐嗶團圖塵塾境墓墊塹墅塽壽夥夢夤奪奩嫡嫦嫩嫗嫖嫘嫣孵寞寧寡寥實寨寢寤察對屢嶄嶇幛幣幕幗幔廓廖弊彆彰徹慇�".split(""); +for(j = 0; j != D[185].length; ++j) if(D[185][j].charCodeAt(0) !== 0xFFFD) { e[D[185][j]] = 47360 + j; d[47360 + j] = D[185][j];} +D[186] = "����������������������������������������������������������������愿態慷慢慣慟慚慘慵截撇摘摔撤摸摟摺摑摧搴摭摻敲斡旗旖暢暨暝榜榨榕槁榮槓構榛榷榻榫榴槐槍榭槌榦槃榣歉歌氳漳演滾漓滴漩漾漠漬漏漂漢����������������������������������滿滯漆漱漸漲漣漕漫漯澈漪滬漁滲滌滷熔熙煽熊熄熒爾犒犖獄獐瑤瑣瑪瑰瑭甄疑瘧瘍瘋瘉瘓盡監瞄睽睿睡磁碟碧碳碩碣禎福禍種稱窪窩竭端管箕箋筵算箝箔箏箸箇箄粹粽精綻綰綜綽綾綠緊綴網綱綺綢綿綵綸維緒緇綬�".split(""); +for(j = 0; j != D[186].length; ++j) if(D[186][j].charCodeAt(0) !== 0xFFFD) { e[D[186][j]] = 47616 + j; d[47616 + j] = D[186][j];} +D[187] = "����������������������������������������������������������������罰翠翡翟聞聚肇腐膀膏膈膊腿膂臧臺與舔舞艋蓉蒿蓆蓄蒙蒞蒲蒜蓋蒸蓀蓓蒐蒼蓑蓊蜿蜜蜻蜢蜥蜴蜘蝕蜷蜩裳褂裴裹裸製裨褚裯誦誌語誣認誡誓誤����������������������������������說誥誨誘誑誚誧豪貍貌賓賑賒赫趙趕跼輔輒輕輓辣遠遘遜遣遙遞遢遝遛鄙鄘鄞酵酸酷酴鉸銀銅銘銖鉻銓銜銨鉼銑閡閨閩閣閥閤隙障際雌雒需靼鞅韶頗領颯颱餃餅餌餉駁骯骰髦魁魂鳴鳶鳳麼鼻齊億儀僻僵價儂儈儉儅凜�".split(""); +for(j = 0; j != D[187].length; ++j) if(D[187][j].charCodeAt(0) !== 0xFFFD) { e[D[187][j]] = 47872 + j; d[47872 + j] = D[187][j];} +D[188] = "����������������������������������������������������������������劇劈劉劍劊勰厲嘮嘻嘹嘲嘿嘴嘩噓噎噗噴嘶嘯嘰墀墟增墳墜墮墩墦奭嬉嫻嬋嫵嬌嬈寮寬審寫層履嶝嶔幢幟幡廢廚廟廝廣廠彈影德徵慶慧慮慝慕憂����������������������������������慼慰慫慾憧憐憫憎憬憚憤憔憮戮摩摯摹撞撲撈撐撰撥撓撕撩撒撮播撫撚撬撙撢撳敵敷數暮暫暴暱樣樟槨樁樞標槽模樓樊槳樂樅槭樑歐歎殤毅毆漿潼澄潑潦潔澆潭潛潸潮澎潺潰潤澗潘滕潯潠潟熟熬熱熨牖犛獎獗瑩璋璃�".split(""); +for(j = 0; j != D[188].length; ++j) if(D[188][j].charCodeAt(0) !== 0xFFFD) { e[D[188][j]] = 48128 + j; d[48128 + j] = D[188][j];} +D[189] = "����������������������������������������������������������������瑾璀畿瘠瘩瘟瘤瘦瘡瘢皚皺盤瞎瞇瞌瞑瞋磋磅確磊碾磕碼磐稿稼穀稽稷稻窯窮箭箱範箴篆篇篁箠篌糊締練緯緻緘緬緝編緣線緞緩綞緙緲緹罵罷羯����������������������������������翩耦膛膜膝膠膚膘蔗蔽蔚蓮蔬蔭蔓蔑蔣蔡蔔蓬蔥蓿蔆螂蝴蝶蝠蝦蝸蝨蝙蝗蝌蝓衛衝褐複褒褓褕褊誼諒談諄誕請諸課諉諂調誰論諍誶誹諛豌豎豬賠賞賦賤賬賭賢賣賜質賡赭趟趣踫踐踝踢踏踩踟踡踞躺輝輛輟輩輦輪輜輞�".split(""); +for(j = 0; j != D[189].length; ++j) if(D[189][j].charCodeAt(0) !== 0xFFFD) { e[D[189][j]] = 48384 + j; d[48384 + j] = D[189][j];} +D[190] = "����������������������������������������������������������������輥適遮遨遭遷鄰鄭鄧鄱醇醉醋醃鋅銻銷鋪銬鋤鋁銳銼鋒鋇鋰銲閭閱霄霆震霉靠鞍鞋鞏頡頫頜颳養餓餒餘駝駐駟駛駑駕駒駙骷髮髯鬧魅魄魷魯鴆鴉����������������������������������鴃麩麾黎墨齒儒儘儔儐儕冀冪凝劑劓勳噙噫噹噩噤噸噪器噥噱噯噬噢噶壁墾壇壅奮嬝嬴學寰導彊憲憑憩憊懍憶憾懊懈戰擅擁擋撻撼據擄擇擂操撿擒擔撾整曆曉暹曄曇暸樽樸樺橙橫橘樹橄橢橡橋橇樵機橈歙歷氅濂澱澡�".split(""); +for(j = 0; j != D[190].length; ++j) if(D[190][j].charCodeAt(0) !== 0xFFFD) { e[D[190][j]] = 48640 + j; d[48640 + j] = D[190][j];} +D[191] = "����������������������������������������������������������������濃澤濁澧澳激澹澶澦澠澴熾燉燐燒燈燕熹燎燙燜燃燄獨璜璣璘璟璞瓢甌甍瘴瘸瘺盧盥瞠瞞瞟瞥磨磚磬磧禦積穎穆穌穋窺篙簑築篤篛篡篩篦糕糖縊����������������������������������縑縈縛縣縞縝縉縐罹羲翰翱翮耨膳膩膨臻興艘艙蕊蕙蕈蕨蕩蕃蕉蕭蕪蕞螃螟螞螢融衡褪褲褥褫褡親覦諦諺諫諱謀諜諧諮諾謁謂諷諭諳諶諼豫豭貓賴蹄踱踴蹂踹踵輻輯輸輳辨辦遵遴選遲遼遺鄴醒錠錶鋸錳錯錢鋼錫錄錚�".split(""); +for(j = 0; j != D[191].length; ++j) if(D[191][j].charCodeAt(0) !== 0xFFFD) { e[D[191][j]] = 48896 + j; d[48896 + j] = D[191][j];} +D[192] = "����������������������������������������������������������������錐錦錡錕錮錙閻隧隨險雕霎霑霖霍霓霏靛靜靦鞘頰頸頻頷頭頹頤餐館餞餛餡餚駭駢駱骸骼髻髭鬨鮑鴕鴣鴦鴨鴒鴛默黔龍龜優償儡儲勵嚎嚀嚐嚅嚇����������������������������������嚏壕壓壑壎嬰嬪嬤孺尷屨嶼嶺嶽嶸幫彌徽應懂懇懦懋戲戴擎擊擘擠擰擦擬擱擢擭斂斃曙曖檀檔檄檢檜櫛檣橾檗檐檠歜殮毚氈濘濱濟濠濛濤濫濯澀濬濡濩濕濮濰燧營燮燦燥燭燬燴燠爵牆獰獲璩環璦璨癆療癌盪瞳瞪瞰瞬�".split(""); +for(j = 0; j != D[192].length; ++j) if(D[192][j].charCodeAt(0) !== 0xFFFD) { e[D[192][j]] = 49152 + j; d[49152 + j] = D[192][j];} +D[193] = "����������������������������������������������������������������瞧瞭矯磷磺磴磯礁禧禪穗窿簇簍篾篷簌篠糠糜糞糢糟糙糝縮績繆縷縲繃縫總縱繅繁縴縹繈縵縿縯罄翳翼聱聲聰聯聳臆臃膺臂臀膿膽臉膾臨舉艱薪����������������������������������薄蕾薜薑薔薯薛薇薨薊虧蟀蟑螳蟒蟆螫螻螺蟈蟋褻褶襄褸褽覬謎謗謙講謊謠謝謄謐豁谿豳賺賽購賸賻趨蹉蹋蹈蹊轄輾轂轅輿避遽還邁邂邀鄹醣醞醜鍍鎂錨鍵鍊鍥鍋錘鍾鍬鍛鍰鍚鍔闊闋闌闈闆隱隸雖霜霞鞠韓顆颶餵騁�".split(""); +for(j = 0; j != D[193].length; ++j) if(D[193][j].charCodeAt(0) !== 0xFFFD) { e[D[193][j]] = 49408 + j; d[49408 + j] = D[193][j];} +D[194] = "����������������������������������������������������������������駿鮮鮫鮪鮭鴻鴿麋黏點黜黝黛鼾齋叢嚕嚮壙壘嬸彝懣戳擴擲擾攆擺擻擷斷曜朦檳檬櫃檻檸櫂檮檯歟歸殯瀉瀋濾瀆濺瀑瀏燻燼燾燸獷獵璧璿甕癖癘����������������������������������癒瞽瞿瞻瞼礎禮穡穢穠竄竅簫簧簪簞簣簡糧織繕繞繚繡繒繙罈翹翻職聶臍臏舊藏薩藍藐藉薰薺薹薦蟯蟬蟲蟠覆覲觴謨謹謬謫豐贅蹙蹣蹦蹤蹟蹕軀轉轍邇邃邈醫醬釐鎔鎊鎖鎢鎳鎮鎬鎰鎘鎚鎗闔闖闐闕離雜雙雛雞霤鞣鞦�".split(""); +for(j = 0; j != D[194].length; ++j) if(D[194][j].charCodeAt(0) !== 0xFFFD) { e[D[194][j]] = 49664 + j; d[49664 + j] = D[194][j];} +D[195] = "����������������������������������������������������������������鞭韹額顏題顎顓颺餾餿餽餮馥騎髁鬃鬆魏魎魍鯊鯉鯽鯈鯀鵑鵝鵠黠鼕鼬儳嚥壞壟壢寵龐廬懲懷懶懵攀攏曠曝櫥櫝櫚櫓瀛瀟瀨瀚瀝瀕瀘爆爍牘犢獸����������������������������������獺璽瓊瓣疇疆癟癡矇礙禱穫穩簾簿簸簽簷籀繫繭繹繩繪羅繳羶羹羸臘藩藝藪藕藤藥藷蟻蠅蠍蟹蟾襠襟襖襞譁譜識證譚譎譏譆譙贈贊蹼蹲躇蹶蹬蹺蹴轔轎辭邊邋醱醮鏡鏑鏟鏃鏈鏜鏝鏖鏢鏍鏘鏤鏗鏨關隴難霪霧靡韜韻類�".split(""); +for(j = 0; j != D[195].length; ++j) if(D[195][j].charCodeAt(0) !== 0xFFFD) { e[D[195][j]] = 49920 + j; d[49920 + j] = D[195][j];} +D[196] = "����������������������������������������������������������������願顛颼饅饉騖騙鬍鯨鯧鯖鯛鶉鵡鵲鵪鵬麒麗麓麴勸嚨嚷嚶嚴嚼壤孀孃孽寶巉懸懺攘攔攙曦朧櫬瀾瀰瀲爐獻瓏癢癥礦礪礬礫竇競籌籃籍糯糰辮繽繼����������������������������������纂罌耀臚艦藻藹蘑藺蘆蘋蘇蘊蠔蠕襤覺觸議譬警譯譟譫贏贍躉躁躅躂醴釋鐘鐃鏽闡霰飄饒饑馨騫騰騷騵鰓鰍鹹麵黨鼯齟齣齡儷儸囁囀囂夔屬巍懼懾攝攜斕曩櫻欄櫺殲灌爛犧瓖瓔癩矓籐纏續羼蘗蘭蘚蠣蠢蠡蠟襪襬覽譴�".split(""); +for(j = 0; j != D[196].length; ++j) if(D[196][j].charCodeAt(0) !== 0xFFFD) { e[D[196][j]] = 50176 + j; d[50176 + j] = D[196][j];} +D[197] = "����������������������������������������������������������������護譽贓躊躍躋轟辯醺鐮鐳鐵鐺鐸鐲鐫闢霸霹露響顧顥饗驅驃驀騾髏魔魑鰭鰥鶯鶴鷂鶸麝黯鼙齜齦齧儼儻囈囊囉孿巔巒彎懿攤權歡灑灘玀瓤疊癮癬����������������������������������禳籠籟聾聽臟襲襯觼讀贖贗躑躓轡酈鑄鑑鑒霽霾韃韁顫饕驕驍髒鬚鱉鰱鰾鰻鷓鷗鼴齬齪龔囌巖戀攣攫攪曬欐瓚竊籤籣籥纓纖纔臢蘸蘿蠱變邐邏鑣鑠鑤靨顯饜驚驛驗髓體髑鱔鱗鱖鷥麟黴囑壩攬灞癱癲矗罐羈蠶蠹衢讓讒�".split(""); +for(j = 0; j != D[197].length; ++j) if(D[197][j].charCodeAt(0) !== 0xFFFD) { e[D[197][j]] = 50432 + j; d[50432 + j] = D[197][j];} +D[198] = "����������������������������������������������������������������讖艷贛釀鑪靂靈靄韆顰驟鬢魘鱟鷹鷺鹼鹽鼇齷齲廳欖灣籬籮蠻觀躡釁鑲鑰顱饞髖鬣黌灤矚讚鑷韉驢驥纜讜躪釅鑽鑾鑼鱷鱸黷豔鑿鸚爨驪鬱鸛鸞籲���������������������������������������������������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[198].length; ++j) if(D[198][j].charCodeAt(0) !== 0xFFFD) { e[D[198][j]] = 50688 + j; d[50688 + j] = D[198][j];} +D[201] = "����������������������������������������������������������������乂乜凵匚厂万丌乇亍囗兀屮彳丏冇与丮亓仂仉仈冘勼卬厹圠夃夬尐巿旡殳毌气爿丱丼仨仜仩仡仝仚刌匜卌圢圣夗夯宁宄尒尻屴屳帄庀庂忉戉扐氕����������������������������������氶汃氿氻犮犰玊禸肊阞伎优伬仵伔仱伀价伈伝伂伅伢伓伄仴伒冱刓刉刐劦匢匟卍厊吇囡囟圮圪圴夼妀奼妅奻奾奷奿孖尕尥屼屺屻屾巟幵庄异弚彴忕忔忏扜扞扤扡扦扢扙扠扚扥旯旮朾朹朸朻机朿朼朳氘汆汒汜汏汊汔汋�".split(""); +for(j = 0; j != D[201].length; ++j) if(D[201][j].charCodeAt(0) !== 0xFFFD) { e[D[201][j]] = 51456 + j; d[51456 + j] = D[201][j];} +D[202] = "����������������������������������������������������������������汌灱牞犴犵玎甪癿穵网艸艼芀艽艿虍襾邙邗邘邛邔阢阤阠阣佖伻佢佉体佤伾佧佒佟佁佘伭伳伿佡冏冹刜刞刡劭劮匉卣卲厎厏吰吷吪呔呅吙吜吥吘����������������������������������吽呏呁吨吤呇囮囧囥坁坅坌坉坋坒夆奀妦妘妠妗妎妢妐妏妧妡宎宒尨尪岍岏岈岋岉岒岊岆岓岕巠帊帎庋庉庌庈庍弅弝彸彶忒忑忐忭忨忮忳忡忤忣忺忯忷忻怀忴戺抃抌抎抏抔抇扱扻扺扰抁抈扷扽扲扴攷旰旴旳旲旵杅杇�".split(""); +for(j = 0; j != D[202].length; ++j) if(D[202][j].charCodeAt(0) !== 0xFFFD) { e[D[202][j]] = 51712 + j; d[51712 + j] = D[202][j];} +D[203] = "����������������������������������������������������������������杙杕杌杈杝杍杚杋毐氙氚汸汧汫沄沋沏汱汯汩沚汭沇沕沜汦汳汥汻沎灴灺牣犿犽狃狆狁犺狅玕玗玓玔玒町甹疔疕皁礽耴肕肙肐肒肜芐芏芅芎芑芓����������������������������������芊芃芄豸迉辿邟邡邥邞邧邠阰阨阯阭丳侘佼侅佽侀侇佶佴侉侄佷佌侗佪侚佹侁佸侐侜侔侞侒侂侕佫佮冞冼冾刵刲刳剆刱劼匊匋匼厒厔咇呿咁咑咂咈呫呺呾呥呬呴呦咍呯呡呠咘呣呧呤囷囹坯坲坭坫坱坰坶垀坵坻坳坴坢�".split(""); +for(j = 0; j != D[203].length; ++j) if(D[203][j].charCodeAt(0) !== 0xFFFD) { e[D[203][j]] = 51968 + j; d[51968 + j] = D[203][j];} +D[204] = "����������������������������������������������������������������坨坽夌奅妵妺姏姎妲姌姁妶妼姃姖妱妽姀姈妴姇孢孥宓宕屄屇岮岤岠岵岯岨岬岟岣岭岢岪岧岝岥岶岰岦帗帔帙弨弢弣弤彔徂彾彽忞忥怭怦怙怲怋����������������������������������怴怊怗怳怚怞怬怢怍怐怮怓怑怌怉怜戔戽抭抴拑抾抪抶拊抮抳抯抻抩抰抸攽斨斻昉旼昄昒昈旻昃昋昍昅旽昑昐曶朊枅杬枎枒杶杻枘枆构杴枍枌杺枟枑枙枃杽极杸杹枔欥殀歾毞氝沓泬泫泮泙沶泔沭泧沷泐泂沺泃泆泭泲�".split(""); +for(j = 0; j != D[204].length; ++j) if(D[204][j].charCodeAt(0) !== 0xFFFD) { e[D[204][j]] = 52224 + j; d[52224 + j] = D[204][j];} +D[205] = "����������������������������������������������������������������泒泝沴沊沝沀泞泀洰泍泇沰泹泏泩泑炔炘炅炓炆炄炑炖炂炚炃牪狖狋狘狉狜狒狔狚狌狑玤玡玭玦玢玠玬玝瓝瓨甿畀甾疌疘皯盳盱盰盵矸矼矹矻矺����������������������������������矷祂礿秅穸穻竻籵糽耵肏肮肣肸肵肭舠芠苀芫芚芘芛芵芧芮芼芞芺芴芨芡芩苂芤苃芶芢虰虯虭虮豖迒迋迓迍迖迕迗邲邴邯邳邰阹阽阼阺陃俍俅俓侲俉俋俁俔俜俙侻侳俛俇俖侺俀侹俬剄剉勀勂匽卼厗厖厙厘咺咡咭咥哏�".split(""); +for(j = 0; j != D[205].length; ++j) if(D[205][j].charCodeAt(0) !== 0xFFFD) { e[D[205][j]] = 52480 + j; d[52480 + j] = D[205][j];} +D[206] = "����������������������������������������������������������������哃茍咷咮哖咶哅哆咠呰咼咢咾呲哞咰垵垞垟垤垌垗垝垛垔垘垏垙垥垚垕壴复奓姡姞姮娀姱姝姺姽姼姶姤姲姷姛姩姳姵姠姾姴姭宨屌峐峘峌峗峋峛����������������������������������峞峚峉峇峊峖峓峔峏峈峆峎峟峸巹帡帢帣帠帤庰庤庢庛庣庥弇弮彖徆怷怹恔恲恞恅恓恇恉恛恌恀恂恟怤恄恘恦恮扂扃拏挍挋拵挎挃拫拹挏挌拸拶挀挓挔拺挕拻拰敁敃斪斿昶昡昲昵昜昦昢昳昫昺昝昴昹昮朏朐柁柲柈枺�".split(""); +for(j = 0; j != D[206].length; ++j) if(D[206][j].charCodeAt(0) !== 0xFFFD) { e[D[206][j]] = 52736 + j; d[52736 + j] = D[206][j];} +D[207] = "����������������������������������������������������������������柜枻柸柘柀枷柅柫柤柟枵柍枳柷柶柮柣柂枹柎柧柰枲柼柆柭柌枮柦柛柺柉柊柃柪柋欨殂殄殶毖毘毠氠氡洨洴洭洟洼洿洒洊泚洳洄洙洺洚洑洀洝浂����������������������������������洁洘洷洃洏浀洇洠洬洈洢洉洐炷炟炾炱炰炡炴炵炩牁牉牊牬牰牳牮狊狤狨狫狟狪狦狣玅珌珂珈珅玹玶玵玴珫玿珇玾珃珆玸珋瓬瓮甮畇畈疧疪癹盄眈眃眄眅眊盷盻盺矧矨砆砑砒砅砐砏砎砉砃砓祊祌祋祅祄秕种秏秖秎窀�".split(""); +for(j = 0; j != D[207].length; ++j) if(D[207][j].charCodeAt(0) !== 0xFFFD) { e[D[207][j]] = 52992 + j; d[52992 + j] = D[207][j];} +D[208] = "����������������������������������������������������������������穾竑笀笁籺籸籹籿粀粁紃紈紁罘羑羍羾耇耎耏耔耷胘胇胠胑胈胂胐胅胣胙胜胊胕胉胏胗胦胍臿舡芔苙苾苹茇苨茀苕茺苫苖苴苬苡苲苵茌苻苶苰苪����������������������������������苤苠苺苳苭虷虴虼虳衁衎衧衪衩觓訄訇赲迣迡迮迠郱邽邿郕郅邾郇郋郈釔釓陔陏陑陓陊陎倞倅倇倓倢倰倛俵俴倳倷倬俶俷倗倜倠倧倵倯倱倎党冔冓凊凄凅凈凎剡剚剒剞剟剕剢勍匎厞唦哢唗唒哧哳哤唚哿唄唈哫唑唅哱�".split(""); +for(j = 0; j != D[208].length; ++j) if(D[208][j].charCodeAt(0) !== 0xFFFD) { e[D[208][j]] = 53248 + j; d[53248 + j] = D[208][j];} +D[209] = "����������������������������������������������������������������唊哻哷哸哠唎唃唋圁圂埌堲埕埒垺埆垽垼垸垶垿埇埐垹埁夎奊娙娖娭娮娕娏娗娊娞娳孬宧宭宬尃屖屔峬峿峮峱峷崀峹帩帨庨庮庪庬弳弰彧恝恚恧����������������������������������恁悢悈悀悒悁悝悃悕悛悗悇悜悎戙扆拲挐捖挬捄捅挶捃揤挹捋捊挼挩捁挴捘捔捙挭捇挳捚捑挸捗捀捈敊敆旆旃旄旂晊晟晇晑朒朓栟栚桉栲栳栻桋桏栖栱栜栵栫栭栯桎桄栴栝栒栔栦栨栮桍栺栥栠欬欯欭欱欴歭肂殈毦毤�".split(""); +for(j = 0; j != D[209].length; ++j) if(D[209][j].charCodeAt(0) !== 0xFFFD) { e[D[209][j]] = 53504 + j; d[53504 + j] = D[209][j];} +D[210] = "����������������������������������������������������������������毨毣毢毧氥浺浣浤浶洍浡涒浘浢浭浯涑涍淯浿涆浞浧浠涗浰浼浟涂涘洯浨涋浾涀涄洖涃浻浽浵涐烜烓烑烝烋缹烢烗烒烞烠烔烍烅烆烇烚烎烡牂牸����������������������������������牷牶猀狺狴狾狶狳狻猁珓珙珥珖玼珧珣珩珜珒珛珔珝珚珗珘珨瓞瓟瓴瓵甡畛畟疰痁疻痄痀疿疶疺皊盉眝眛眐眓眒眣眑眕眙眚眢眧砣砬砢砵砯砨砮砫砡砩砳砪砱祔祛祏祜祓祒祑秫秬秠秮秭秪秜秞秝窆窉窅窋窌窊窇竘笐�".split(""); +for(j = 0; j != D[210].length; ++j) if(D[210][j].charCodeAt(0) !== 0xFFFD) { e[D[210][j]] = 53760 + j; d[53760 + j] = D[210][j];} +D[211] = "����������������������������������������������������������������笄笓笅笏笈笊笎笉笒粄粑粊粌粈粍粅紞紝紑紎紘紖紓紟紒紏紌罜罡罞罠罝罛羖羒翃翂翀耖耾耹胺胲胹胵脁胻脀舁舯舥茳茭荄茙荑茥荖茿荁茦茜茢����������������������������������荂荎茛茪茈茼荍茖茤茠茷茯茩荇荅荌荓茞茬荋茧荈虓虒蚢蚨蚖蚍蚑蚞蚇蚗蚆蚋蚚蚅蚥蚙蚡蚧蚕蚘蚎蚝蚐蚔衃衄衭衵衶衲袀衱衿衯袃衾衴衼訒豇豗豻貤貣赶赸趵趷趶軑軓迾迵适迿迻逄迼迶郖郠郙郚郣郟郥郘郛郗郜郤酐�".split(""); +for(j = 0; j != D[211].length; ++j) if(D[211][j].charCodeAt(0) !== 0xFFFD) { e[D[211][j]] = 54016 + j; d[54016 + j] = D[211][j];} +D[212] = "����������������������������������������������������������������酎酏釕釢釚陜陟隼飣髟鬯乿偰偪偡偞偠偓偋偝偲偈偍偁偛偊偢倕偅偟偩偫偣偤偆偀偮偳偗偑凐剫剭剬剮勖勓匭厜啵啶唼啍啐唴唪啑啢唶唵唰啒啅����������������������������������唌唲啥啎唹啈唭唻啀啋圊圇埻堔埢埶埜埴堀埭埽堈埸堋埳埏堇埮埣埲埥埬埡堎埼堐埧堁堌埱埩埰堍堄奜婠婘婕婧婞娸娵婭婐婟婥婬婓婤婗婃婝婒婄婛婈媎娾婍娹婌婰婩婇婑婖婂婜孲孮寁寀屙崞崋崝崚崠崌崨崍崦崥崏�".split(""); +for(j = 0; j != D[212].length; ++j) if(D[212][j].charCodeAt(0) !== 0xFFFD) { e[D[212][j]] = 54272 + j; d[54272 + j] = D[212][j];} +D[213] = "����������������������������������������������������������������崰崒崣崟崮帾帴庱庴庹庲庳弶弸徛徖徟悊悐悆悾悰悺惓惔惏惤惙惝惈悱惛悷惊悿惃惍惀挲捥掊掂捽掽掞掭掝掗掫掎捯掇掐据掯捵掜捭掮捼掤挻掟����������������������������������捸掅掁掑掍捰敓旍晥晡晛晙晜晢朘桹梇梐梜桭桮梮梫楖桯梣梬梩桵桴梲梏桷梒桼桫桲梪梀桱桾梛梖梋梠梉梤桸桻梑梌梊桽欶欳欷欸殑殏殍殎殌氪淀涫涴涳湴涬淩淢涷淶淔渀淈淠淟淖涾淥淜淝淛淴淊涽淭淰涺淕淂淏淉�".split(""); +for(j = 0; j != D[213].length; ++j) if(D[213][j].charCodeAt(0) !== 0xFFFD) { e[D[213][j]] = 54528 + j; d[54528 + j] = D[213][j];} +D[214] = "����������������������������������������������������������������淐淲淓淽淗淍淣涻烺焍烷焗烴焌烰焄烳焐烼烿焆焓焀烸烶焋焂焎牾牻牼牿猝猗猇猑猘猊猈狿猏猞玈珶珸珵琄琁珽琇琀珺珼珿琌琋珴琈畤畣痎痒痏����������������������������������痋痌痑痐皏皉盓眹眯眭眱眲眴眳眽眥眻眵硈硒硉硍硊硌砦硅硐祤祧祩祪祣祫祡离秺秸秶秷窏窔窐笵筇笴笥笰笢笤笳笘笪笝笱笫笭笯笲笸笚笣粔粘粖粣紵紽紸紶紺絅紬紩絁絇紾紿絊紻紨罣羕羜羝羛翊翋翍翐翑翇翏翉耟�".split(""); +for(j = 0; j != D[214].length; ++j) if(D[214][j].charCodeAt(0) !== 0xFFFD) { e[D[214][j]] = 54784 + j; d[54784 + j] = D[214][j];} +D[215] = "����������������������������������������������������������������耞耛聇聃聈脘脥脙脛脭脟脬脞脡脕脧脝脢舑舸舳舺舴舲艴莐莣莨莍荺荳莤荴莏莁莕莙荵莔莩荽莃莌莝莛莪莋荾莥莯莈莗莰荿莦莇莮荶莚虙虖蚿蚷����������������������������������蛂蛁蛅蚺蚰蛈蚹蚳蚸蛌蚴蚻蚼蛃蚽蚾衒袉袕袨袢袪袚袑袡袟袘袧袙袛袗袤袬袌袓袎覂觖觙觕訰訧訬訞谹谻豜豝豽貥赽赻赹趼跂趹趿跁軘軞軝軜軗軠軡逤逋逑逜逌逡郯郪郰郴郲郳郔郫郬郩酖酘酚酓酕釬釴釱釳釸釤釹釪�".split(""); +for(j = 0; j != D[215].length; ++j) if(D[215][j].charCodeAt(0) !== 0xFFFD) { e[D[215][j]] = 55040 + j; d[55040 + j] = D[215][j];} +D[216] = "����������������������������������������������������������������釫釷釨釮镺閆閈陼陭陫陱陯隿靪頄飥馗傛傕傔傞傋傣傃傌傎傝偨傜傒傂傇兟凔匒匑厤厧喑喨喥喭啷噅喢喓喈喏喵喁喣喒喤啽喌喦啿喕喡喎圌堩堷����������������������������������堙堞堧堣堨埵塈堥堜堛堳堿堶堮堹堸堭堬堻奡媯媔媟婺媢媞婸媦婼媥媬媕媮娷媄媊媗媃媋媩婻婽媌媜媏媓媝寪寍寋寔寑寊寎尌尰崷嵃嵫嵁嵋崿崵嵑嵎嵕崳崺嵒崽崱嵙嵂崹嵉崸崼崲崶嵀嵅幄幁彘徦徥徫惉悹惌惢惎惄愔�".split(""); +for(j = 0; j != D[216].length; ++j) if(D[216][j].charCodeAt(0) !== 0xFFFD) { e[D[216][j]] = 55296 + j; d[55296 + j] = D[216][j];} +D[217] = "����������������������������������������������������������������惲愊愖愅惵愓惸惼惾惁愃愘愝愐惿愄愋扊掔掱掰揎揥揨揯揃撝揳揊揠揶揕揲揵摡揟掾揝揜揄揘揓揂揇揌揋揈揰揗揙攲敧敪敤敜敨敥斌斝斞斮旐旒����������������������������������晼晬晻暀晱晹晪晲朁椌棓椄棜椪棬棪棱椏棖棷棫棤棶椓椐棳棡椇棌椈楰梴椑棯棆椔棸棐棽棼棨椋椊椗棎棈棝棞棦棴棑椆棔棩椕椥棇欹欻欿欼殔殗殙殕殽毰毲毳氰淼湆湇渟湉溈渼渽湅湢渫渿湁湝湳渜渳湋湀湑渻渃渮湞�".split(""); +for(j = 0; j != D[217].length; ++j) if(D[217][j].charCodeAt(0) !== 0xFFFD) { e[D[217][j]] = 55552 + j; d[55552 + j] = D[217][j];} +D[218] = "����������������������������������������������������������������湨湜湡渱渨湠湱湫渹渢渰湓湥渧湸湤湷湕湹湒湦渵渶湚焠焞焯烻焮焱焣焥焢焲焟焨焺焛牋牚犈犉犆犅犋猒猋猰猢猱猳猧猲猭猦猣猵猌琮琬琰琫琖����������������������������������琚琡琭琱琤琣琝琩琠琲瓻甯畯畬痧痚痡痦痝痟痤痗皕皒盚睆睇睄睍睅睊睎睋睌矞矬硠硤硥硜硭硱硪确硰硩硨硞硢祴祳祲祰稂稊稃稌稄窙竦竤筊笻筄筈筌筎筀筘筅粢粞粨粡絘絯絣絓絖絧絪絏絭絜絫絒絔絩絑絟絎缾缿罥�".split(""); +for(j = 0; j != D[218].length; ++j) if(D[218][j].charCodeAt(0) !== 0xFFFD) { e[D[218][j]] = 55808 + j; d[55808 + j] = D[218][j];} +D[219] = "����������������������������������������������������������������罦羢羠羡翗聑聏聐胾胔腃腊腒腏腇脽腍脺臦臮臷臸臹舄舼舽舿艵茻菏菹萣菀菨萒菧菤菼菶萐菆菈菫菣莿萁菝菥菘菿菡菋菎菖菵菉萉萏菞萑萆菂菳����������������������������������菕菺菇菑菪萓菃菬菮菄菻菗菢萛菛菾蛘蛢蛦蛓蛣蛚蛪蛝蛫蛜蛬蛩蛗蛨蛑衈衖衕袺裗袹袸裀袾袶袼袷袽袲褁裉覕覘覗觝觚觛詎詍訹詙詀詗詘詄詅詒詈詑詊詌詏豟貁貀貺貾貰貹貵趄趀趉跘跓跍跇跖跜跏跕跙跈跗跅軯軷軺�".split(""); +for(j = 0; j != D[219].length; ++j) if(D[219][j].charCodeAt(0) !== 0xFFFD) { e[D[219][j]] = 56064 + j; d[56064 + j] = D[219][j];} +D[220] = "����������������������������������������������������������������軹軦軮軥軵軧軨軶軫軱軬軴軩逭逴逯鄆鄬鄄郿郼鄈郹郻鄁鄀鄇鄅鄃酡酤酟酢酠鈁鈊鈥鈃鈚鈦鈏鈌鈀鈒釿釽鈆鈄鈧鈂鈜鈤鈙鈗鈅鈖镻閍閌閐隇陾隈����������������������������������隉隃隀雂雈雃雱雰靬靰靮頇颩飫鳦黹亃亄亶傽傿僆傮僄僊傴僈僂傰僁傺傱僋僉傶傸凗剺剸剻剼嗃嗛嗌嗐嗋嗊嗝嗀嗔嗄嗩喿嗒喍嗏嗕嗢嗖嗈嗲嗍嗙嗂圔塓塨塤塏塍塉塯塕塎塝塙塥塛堽塣塱壼嫇嫄嫋媺媸媱媵媰媿嫈媻嫆�".split(""); +for(j = 0; j != D[220].length; ++j) if(D[220][j].charCodeAt(0) !== 0xFFFD) { e[D[220][j]] = 56320 + j; d[56320 + j] = D[220][j];} +D[221] = "����������������������������������������������������������������媷嫀嫊媴媶嫍媹媐寖寘寙尟尳嵱嵣嵊嵥嵲嵬嵞嵨嵧嵢巰幏幎幊幍幋廅廌廆廋廇彀徯徭惷慉慊愫慅愶愲愮慆愯慏愩慀戠酨戣戥戤揅揱揫搐搒搉搠搤����������������������������������搳摃搟搕搘搹搷搢搣搌搦搰搨摁搵搯搊搚摀搥搧搋揧搛搮搡搎敯斒旓暆暌暕暐暋暊暙暔晸朠楦楟椸楎楢楱椿楅楪椹楂楗楙楺楈楉椵楬椳椽楥棰楸椴楩楀楯楄楶楘楁楴楌椻楋椷楜楏楑椲楒椯楻椼歆歅歃歂歈歁殛嗀毻毼�".split(""); +for(j = 0; j != D[221].length; ++j) if(D[221][j].charCodeAt(0) !== 0xFFFD) { e[D[221][j]] = 56576 + j; d[56576 + j] = D[221][j];} +D[222] = "����������������������������������������������������������������毹毷毸溛滖滈溏滀溟溓溔溠溱溹滆滒溽滁溞滉溷溰滍溦滏溲溾滃滜滘溙溒溎溍溤溡溿溳滐滊溗溮溣煇煔煒煣煠煁煝煢煲煸煪煡煂煘煃煋煰煟煐煓����������������������������������煄煍煚牏犍犌犑犐犎猼獂猻猺獀獊獉瑄瑊瑋瑒瑑瑗瑀瑏瑐瑎瑂瑆瑍瑔瓡瓿瓾瓽甝畹畷榃痯瘏瘃痷痾痼痹痸瘐痻痶痭痵痽皙皵盝睕睟睠睒睖睚睩睧睔睙睭矠碇碚碔碏碄碕碅碆碡碃硹碙碀碖硻祼禂祽祹稑稘稙稒稗稕稢稓�".split(""); +for(j = 0; j != D[222].length; ++j) if(D[222][j].charCodeAt(0) !== 0xFFFD) { e[D[222][j]] = 56832 + j; d[56832 + j] = D[222][j];} +D[223] = "����������������������������������������������������������������稛稐窣窢窞竫筦筤筭筴筩筲筥筳筱筰筡筸筶筣粲粴粯綈綆綀綍絿綅絺綎絻綃絼綌綔綄絽綒罭罫罧罨罬羦羥羧翛翜耡腤腠腷腜腩腛腢腲朡腞腶腧腯����������������������������������腄腡舝艉艄艀艂艅蓱萿葖葶葹蒏蒍葥葑葀蒆葧萰葍葽葚葙葴葳葝蔇葞萷萺萴葺葃葸萲葅萩菙葋萯葂萭葟葰萹葎葌葒葯蓅蒎萻葇萶萳葨葾葄萫葠葔葮葐蜋蜄蛷蜌蛺蛖蛵蝍蛸蜎蜉蜁蛶蜍蜅裖裋裍裎裞裛裚裌裐覅覛觟觥觤�".split(""); +for(j = 0; j != D[223].length; ++j) if(D[223][j].charCodeAt(0) !== 0xFFFD) { e[D[223][j]] = 57088 + j; d[57088 + j] = D[223][j];} +D[224] = "����������������������������������������������������������������觡觠觢觜触詶誆詿詡訿詷誂誄詵誃誁詴詺谼豋豊豥豤豦貆貄貅賌赨赩趑趌趎趏趍趓趔趐趒跰跠跬跱跮跐跩跣跢跧跲跫跴輆軿輁輀輅輇輈輂輋遒逿����������������������������������遄遉逽鄐鄍鄏鄑鄖鄔鄋鄎酮酯鉈鉒鈰鈺鉦鈳鉥鉞銃鈮鉊鉆鉭鉬鉏鉠鉧鉯鈶鉡鉰鈱鉔鉣鉐鉲鉎鉓鉌鉖鈲閟閜閞閛隒隓隑隗雎雺雽雸雵靳靷靸靲頏頍頎颬飶飹馯馲馰馵骭骫魛鳪鳭鳧麀黽僦僔僗僨僳僛僪僝僤僓僬僰僯僣僠�".split(""); +for(j = 0; j != D[224].length; ++j) if(D[224][j].charCodeAt(0) !== 0xFFFD) { e[D[224][j]] = 57344 + j; d[57344 + j] = D[224][j];} +D[225] = "����������������������������������������������������������������凘劀劁勩勫匰厬嘧嘕嘌嘒嗼嘏嘜嘁嘓嘂嗺嘝嘄嗿嗹墉塼墐墘墆墁塿塴墋塺墇墑墎塶墂墈塻墔墏壾奫嫜嫮嫥嫕嫪嫚嫭嫫嫳嫢嫠嫛嫬嫞嫝嫙嫨嫟孷寠����������������������������������寣屣嶂嶀嵽嶆嵺嶁嵷嶊嶉嶈嵾嵼嶍嵹嵿幘幙幓廘廑廗廎廜廕廙廒廔彄彃彯徶愬愨慁慞慱慳慒慓慲慬憀慴慔慺慛慥愻慪慡慖戩戧戫搫摍摛摝摴摶摲摳摽摵摦撦摎撂摞摜摋摓摠摐摿搿摬摫摙摥摷敳斠暡暠暟朅朄朢榱榶槉�".split(""); +for(j = 0; j != D[225].length; ++j) if(D[225][j].charCodeAt(0) !== 0xFFFD) { e[D[225][j]] = 57600 + j; d[57600 + j] = D[225][j];} +D[226] = "����������������������������������������������������������������榠槎榖榰榬榼榑榙榎榧榍榩榾榯榿槄榽榤槔榹槊榚槏榳榓榪榡榞槙榗榐槂榵榥槆歊歍歋殞殟殠毃毄毾滎滵滱漃漥滸漷滻漮漉潎漙漚漧漘漻漒滭漊����������������������������������漶潳滹滮漭潀漰漼漵滫漇漎潃漅滽滶漹漜滼漺漟漍漞漈漡熇熐熉熀熅熂熏煻熆熁熗牄牓犗犕犓獃獍獑獌瑢瑳瑱瑵瑲瑧瑮甀甂甃畽疐瘖瘈瘌瘕瘑瘊瘔皸瞁睼瞅瞂睮瞀睯睾瞃碲碪碴碭碨硾碫碞碥碠碬碢碤禘禊禋禖禕禔禓�".split(""); +for(j = 0; j != D[226].length; ++j) if(D[226][j].charCodeAt(0) !== 0xFFFD) { e[D[226][j]] = 57856 + j; d[57856 + j] = D[226][j];} +D[227] = "����������������������������������������������������������������禗禈禒禐稫穊稰稯稨稦窨窫窬竮箈箜箊箑箐箖箍箌箛箎箅箘劄箙箤箂粻粿粼粺綧綷緂綣綪緁緀緅綝緎緄緆緋緌綯綹綖綼綟綦綮綩綡緉罳翢翣翥翞����������������������������������耤聝聜膉膆膃膇膍膌膋舕蒗蒤蒡蒟蒺蓎蓂蒬蒮蒫蒹蒴蓁蓍蒪蒚蒱蓐蒝蒧蒻蒢蒔蓇蓌蒛蒩蒯蒨蓖蒘蒶蓏蒠蓗蓔蓒蓛蒰蒑虡蜳蜣蜨蝫蝀蜮蜞蜡蜙蜛蝃蜬蝁蜾蝆蜠蜲蜪蜭蜼蜒蜺蜱蜵蝂蜦蜧蜸蜤蜚蜰蜑裷裧裱裲裺裾裮裼裶裻�".split(""); +for(j = 0; j != D[227].length; ++j) if(D[227][j].charCodeAt(0) !== 0xFFFD) { e[D[227][j]] = 58112 + j; d[58112 + j] = D[227][j];} +D[228] = "����������������������������������������������������������������裰裬裫覝覡覟覞觩觫觨誫誙誋誒誏誖谽豨豩賕賏賗趖踉踂跿踍跽踊踃踇踆踅跾踀踄輐輑輎輍鄣鄜鄠鄢鄟鄝鄚鄤鄡鄛酺酲酹酳銥銤鉶銛鉺銠銔銪銍����������������������������������銦銚銫鉹銗鉿銣鋮銎銂銕銢鉽銈銡銊銆銌銙銧鉾銇銩銝銋鈭隞隡雿靘靽靺靾鞃鞀鞂靻鞄鞁靿韎韍頖颭颮餂餀餇馝馜駃馹馻馺駂馽駇骱髣髧鬾鬿魠魡魟鳱鳲鳵麧僿儃儰僸儆儇僶僾儋儌僽儊劋劌勱勯噈噂噌嘵噁噊噉噆噘�".split(""); +for(j = 0; j != D[228].length; ++j) if(D[228][j].charCodeAt(0) !== 0xFFFD) { e[D[228][j]] = 58368 + j; d[58368 + j] = D[228][j];} +D[229] = "����������������������������������������������������������������噚噀嘳嘽嘬嘾嘸嘪嘺圚墫墝墱墠墣墯墬墥墡壿嫿嫴嫽嫷嫶嬃嫸嬂嫹嬁嬇嬅嬏屧嶙嶗嶟嶒嶢嶓嶕嶠嶜嶡嶚嶞幩幝幠幜緳廛廞廡彉徲憋憃慹憱憰憢憉����������������������������������憛憓憯憭憟憒憪憡憍慦憳戭摮摰撖撠撅撗撜撏撋撊撌撣撟摨撱撘敶敺敹敻斲斳暵暰暩暲暷暪暯樀樆樗槥槸樕槱槤樠槿槬槢樛樝槾樧槲槮樔槷槧橀樈槦槻樍槼槫樉樄樘樥樏槶樦樇槴樖歑殥殣殢殦氁氀毿氂潁漦潾澇濆澒�".split(""); +for(j = 0; j != D[229].length; ++j) if(D[229][j].charCodeAt(0) !== 0xFFFD) { e[D[229][j]] = 58624 + j; d[58624 + j] = D[229][j];} +D[230] = "����������������������������������������������������������������澍澉澌潢潏澅潚澖潶潬澂潕潲潒潐潗澔澓潝漀潡潫潽潧澐潓澋潩潿澕潣潷潪潻熲熯熛熰熠熚熩熵熝熥熞熤熡熪熜熧熳犘犚獘獒獞獟獠獝獛獡獚獙����������������������������������獢璇璉璊璆璁瑽璅璈瑼瑹甈甇畾瘥瘞瘙瘝瘜瘣瘚瘨瘛皜皝皞皛瞍瞏瞉瞈磍碻磏磌磑磎磔磈磃磄磉禚禡禠禜禢禛歶稹窲窴窳箷篋箾箬篎箯箹篊箵糅糈糌糋緷緛緪緧緗緡縃緺緦緶緱緰緮緟罶羬羰羭翭翫翪翬翦翨聤聧膣膟�".split(""); +for(j = 0; j != D[230].length; ++j) if(D[230][j].charCodeAt(0) !== 0xFFFD) { e[D[230][j]] = 58880 + j; d[58880 + j] = D[230][j];} +D[231] = "����������������������������������������������������������������膞膕膢膙膗舖艏艓艒艐艎艑蔤蔻蔏蔀蔩蔎蔉蔍蔟蔊蔧蔜蓻蔫蓺蔈蔌蓴蔪蓲蔕蓷蓫蓳蓼蔒蓪蓩蔖蓾蔨蔝蔮蔂蓽蔞蓶蔱蔦蓧蓨蓰蓯蓹蔘蔠蔰蔋蔙蔯虢����������������������������������蝖蝣蝤蝷蟡蝳蝘蝔蝛蝒蝡蝚蝑蝞蝭蝪蝐蝎蝟蝝蝯蝬蝺蝮蝜蝥蝏蝻蝵蝢蝧蝩衚褅褌褔褋褗褘褙褆褖褑褎褉覢覤覣觭觰觬諏諆誸諓諑諔諕誻諗誾諀諅諘諃誺誽諙谾豍貏賥賟賙賨賚賝賧趠趜趡趛踠踣踥踤踮踕踛踖踑踙踦踧�".split(""); +for(j = 0; j != D[231].length; ++j) if(D[231][j].charCodeAt(0) !== 0xFFFD) { e[D[231][j]] = 59136 + j; d[59136 + j] = D[231][j];} +D[232] = "����������������������������������������������������������������踔踒踘踓踜踗踚輬輤輘輚輠輣輖輗遳遰遯遧遫鄯鄫鄩鄪鄲鄦鄮醅醆醊醁醂醄醀鋐鋃鋄鋀鋙銶鋏鋱鋟鋘鋩鋗鋝鋌鋯鋂鋨鋊鋈鋎鋦鋍鋕鋉鋠鋞鋧鋑鋓����������������������������������銵鋡鋆銴镼閬閫閮閰隤隢雓霅霈霂靚鞊鞎鞈韐韏頞頝頦頩頨頠頛頧颲餈飺餑餔餖餗餕駜駍駏駓駔駎駉駖駘駋駗駌骳髬髫髳髲髱魆魃魧魴魱魦魶魵魰魨魤魬鳼鳺鳽鳿鳷鴇鴀鳹鳻鴈鴅鴄麃黓鼏鼐儜儓儗儚儑凞匴叡噰噠噮�".split(""); +for(j = 0; j != D[232].length; ++j) if(D[232][j].charCodeAt(0) !== 0xFFFD) { e[D[232][j]] = 59392 + j; d[59392 + j] = D[232][j];} +D[233] = "����������������������������������������������������������������噳噦噣噭噲噞噷圜圛壈墽壉墿墺壂墼壆嬗嬙嬛嬡嬔嬓嬐嬖嬨嬚嬠嬞寯嶬嶱嶩嶧嶵嶰嶮嶪嶨嶲嶭嶯嶴幧幨幦幯廩廧廦廨廥彋徼憝憨憖懅憴懆懁懌憺����������������������������������憿憸憌擗擖擐擏擉撽撉擃擛擳擙攳敿敼斢曈暾曀曊曋曏暽暻暺曌朣樴橦橉橧樲橨樾橝橭橶橛橑樨橚樻樿橁橪橤橐橏橔橯橩橠樼橞橖橕橍橎橆歕歔歖殧殪殫毈毇氄氃氆澭濋澣濇澼濎濈潞濄澽澞濊澨瀄澥澮澺澬澪濏澿澸�".split(""); +for(j = 0; j != D[233].length; ++j) if(D[233][j].charCodeAt(0) !== 0xFFFD) { e[D[233][j]] = 59648 + j; d[59648 + j] = D[233][j];} +D[234] = "����������������������������������������������������������������澢濉澫濍澯澲澰燅燂熿熸燖燀燁燋燔燊燇燏熽燘熼燆燚燛犝犞獩獦獧獬獥獫獪瑿璚璠璔璒璕璡甋疀瘯瘭瘱瘽瘳瘼瘵瘲瘰皻盦瞚瞝瞡瞜瞛瞢瞣瞕瞙����������������������������������瞗磝磩磥磪磞磣磛磡磢磭磟磠禤穄穈穇窶窸窵窱窷篞篣篧篝篕篥篚篨篹篔篪篢篜篫篘篟糒糔糗糐糑縒縡縗縌縟縠縓縎縜縕縚縢縋縏縖縍縔縥縤罃罻罼罺羱翯耪耩聬膱膦膮膹膵膫膰膬膴膲膷膧臲艕艖艗蕖蕅蕫蕍蕓蕡蕘�".split(""); +for(j = 0; j != D[234].length; ++j) if(D[234][j].charCodeAt(0) !== 0xFFFD) { e[D[234][j]] = 59904 + j; d[59904 + j] = D[234][j];} +D[235] = "����������������������������������������������������������������蕀蕆蕤蕁蕢蕄蕑蕇蕣蔾蕛蕱蕎蕮蕵蕕蕧蕠薌蕦蕝蕔蕥蕬虣虥虤螛螏螗螓螒螈螁螖螘蝹螇螣螅螐螑螝螄螔螜螚螉褞褦褰褭褮褧褱褢褩褣褯褬褟觱諠����������������������������������諢諲諴諵諝謔諤諟諰諈諞諡諨諿諯諻貑貒貐賵賮賱賰賳赬赮趥趧踳踾踸蹀蹅踶踼踽蹁踰踿躽輶輮輵輲輹輷輴遶遹遻邆郺鄳鄵鄶醓醐醑醍醏錧錞錈錟錆錏鍺錸錼錛錣錒錁鍆錭錎錍鋋錝鋺錥錓鋹鋷錴錂錤鋿錩錹錵錪錔錌�".split(""); +for(j = 0; j != D[235].length; ++j) if(D[235][j].charCodeAt(0) !== 0xFFFD) { e[D[235][j]] = 60160 + j; d[60160 + j] = D[235][j];} +D[236] = "����������������������������������������������������������������錋鋾錉錀鋻錖閼闍閾閹閺閶閿閵閽隩雔霋霒霐鞙鞗鞔韰韸頵頯頲餤餟餧餩馞駮駬駥駤駰駣駪駩駧骹骿骴骻髶髺髹髷鬳鮀鮅鮇魼魾魻鮂鮓鮒鮐魺鮕����������������������������������魽鮈鴥鴗鴠鴞鴔鴩鴝鴘鴢鴐鴙鴟麈麆麇麮麭黕黖黺鼒鼽儦儥儢儤儠儩勴嚓嚌嚍嚆嚄嚃噾嚂噿嚁壖壔壏壒嬭嬥嬲嬣嬬嬧嬦嬯嬮孻寱寲嶷幬幪徾徻懃憵憼懧懠懥懤懨懞擯擩擣擫擤擨斁斀斶旚曒檍檖檁檥檉檟檛檡檞檇檓檎�".split(""); +for(j = 0; j != D[236].length; ++j) if(D[236][j].charCodeAt(0) !== 0xFFFD) { e[D[236][j]] = 60416 + j; d[60416 + j] = D[236][j];} +D[237] = "����������������������������������������������������������������檕檃檨檤檑橿檦檚檅檌檒歛殭氉濌澩濴濔濣濜濭濧濦濞濲濝濢濨燡燱燨燲燤燰燢獳獮獯璗璲璫璐璪璭璱璥璯甐甑甒甏疄癃癈癉癇皤盩瞵瞫瞲瞷瞶����������������������������������瞴瞱瞨矰磳磽礂磻磼磲礅磹磾礄禫禨穜穛穖穘穔穚窾竀竁簅簏篲簀篿篻簎篴簋篳簂簉簃簁篸篽簆篰篱簐簊糨縭縼繂縳顈縸縪繉繀繇縩繌縰縻縶繄縺罅罿罾罽翴翲耬膻臄臌臊臅臇膼臩艛艚艜薃薀薏薧薕薠薋薣蕻薤薚薞�".split(""); +for(j = 0; j != D[237].length; ++j) if(D[237][j].charCodeAt(0) !== 0xFFFD) { e[D[237][j]] = 60672 + j; d[60672 + j] = D[237][j];} +D[238] = "����������������������������������������������������������������蕷蕼薉薡蕺蕸蕗薎薖薆薍薙薝薁薢薂薈薅蕹蕶薘薐薟虨螾螪螭蟅螰螬螹螵螼螮蟉蟃蟂蟌螷螯蟄蟊螴螶螿螸螽蟞螲褵褳褼褾襁襒褷襂覭覯覮觲觳謞����������������������������������謘謖謑謅謋謢謏謒謕謇謍謈謆謜謓謚豏豰豲豱豯貕貔賹赯蹎蹍蹓蹐蹌蹇轃轀邅遾鄸醚醢醛醙醟醡醝醠鎡鎃鎯鍤鍖鍇鍼鍘鍜鍶鍉鍐鍑鍠鍭鎏鍌鍪鍹鍗鍕鍒鍏鍱鍷鍻鍡鍞鍣鍧鎀鍎鍙闇闀闉闃闅閷隮隰隬霠霟霘霝霙鞚鞡鞜�".split(""); +for(j = 0; j != D[238].length; ++j) if(D[238][j].charCodeAt(0) !== 0xFFFD) { e[D[238][j]] = 60928 + j; d[60928 + j] = D[238][j];} +D[239] = "����������������������������������������������������������������鞞鞝韕韔韱顁顄顊顉顅顃餥餫餬餪餳餲餯餭餱餰馘馣馡騂駺駴駷駹駸駶駻駽駾駼騃骾髾髽鬁髼魈鮚鮨鮞鮛鮦鮡鮥鮤鮆鮢鮠鮯鴳鵁鵧鴶鴮鴯鴱鴸鴰����������������������������������鵅鵂鵃鴾鴷鵀鴽翵鴭麊麉麍麰黈黚黻黿鼤鼣鼢齔龠儱儭儮嚘嚜嚗嚚嚝嚙奰嬼屩屪巀幭幮懘懟懭懮懱懪懰懫懖懩擿攄擽擸攁攃擼斔旛曚曛曘櫅檹檽櫡櫆檺檶檷櫇檴檭歞毉氋瀇瀌瀍瀁瀅瀔瀎濿瀀濻瀦濼濷瀊爁燿燹爃燽獶�".split(""); +for(j = 0; j != D[239].length; ++j) if(D[239][j].charCodeAt(0) !== 0xFFFD) { e[D[239][j]] = 61184 + j; d[61184 + j] = D[239][j];} +D[240] = "����������������������������������������������������������������璸瓀璵瓁璾璶璻瓂甔甓癜癤癙癐癓癗癚皦皽盬矂瞺磿礌礓礔礉礐礒礑禭禬穟簜簩簙簠簟簭簝簦簨簢簥簰繜繐繖繣繘繢繟繑繠繗繓羵羳翷翸聵臑臒����������������������������������臐艟艞薴藆藀藃藂薳薵薽藇藄薿藋藎藈藅薱薶藒蘤薸薷薾虩蟧蟦蟢蟛蟫蟪蟥蟟蟳蟤蟔蟜蟓蟭蟘蟣螤蟗蟙蠁蟴蟨蟝襓襋襏襌襆襐襑襉謪謧謣謳謰謵譇謯謼謾謱謥謷謦謶謮謤謻謽謺豂豵貙貘貗賾贄贂贀蹜蹢蹠蹗蹖蹞蹥蹧�".split(""); +for(j = 0; j != D[240].length; ++j) if(D[240][j].charCodeAt(0) !== 0xFFFD) { e[D[240][j]] = 61440 + j; d[61440 + j] = D[240][j];} +D[241] = "����������������������������������������������������������������蹛蹚蹡蹝蹩蹔轆轇轈轋鄨鄺鄻鄾醨醥醧醯醪鎵鎌鎒鎷鎛鎝鎉鎧鎎鎪鎞鎦鎕鎈鎙鎟鎍鎱鎑鎲鎤鎨鎴鎣鎥闒闓闑隳雗雚巂雟雘雝霣霢霥鞬鞮鞨鞫鞤鞪����������������������������������鞢鞥韗韙韖韘韺顐顑顒颸饁餼餺騏騋騉騍騄騑騊騅騇騆髀髜鬈鬄鬅鬩鬵魊魌魋鯇鯆鯃鮿鯁鮵鮸鯓鮶鯄鮹鮽鵜鵓鵏鵊鵛鵋鵙鵖鵌鵗鵒鵔鵟鵘鵚麎麌黟鼁鼀鼖鼥鼫鼪鼩鼨齌齕儴儵劖勷厴嚫嚭嚦嚧嚪嚬壚壝壛夒嬽嬾嬿巃幰�".split(""); +for(j = 0; j != D[241].length; ++j) if(D[241][j].charCodeAt(0) !== 0xFFFD) { e[D[241][j]] = 61696 + j; d[61696 + j] = D[241][j];} +D[242] = "����������������������������������������������������������������徿懻攇攐攍攉攌攎斄旞旝曞櫧櫠櫌櫑櫙櫋櫟櫜櫐櫫櫏櫍櫞歠殰氌瀙瀧瀠瀖瀫瀡瀢瀣瀩瀗瀤瀜瀪爌爊爇爂爅犥犦犤犣犡瓋瓅璷瓃甖癠矉矊矄矱礝礛����������������������������������礡礜礗礞禰穧穨簳簼簹簬簻糬糪繶繵繸繰繷繯繺繲繴繨罋罊羃羆羷翽翾聸臗臕艤艡艣藫藱藭藙藡藨藚藗藬藲藸藘藟藣藜藑藰藦藯藞藢蠀蟺蠃蟶蟷蠉蠌蠋蠆蟼蠈蟿蠊蠂襢襚襛襗襡襜襘襝襙覈覷覶觶譐譈譊譀譓譖譔譋譕�".split(""); +for(j = 0; j != D[242].length; ++j) if(D[242][j].charCodeAt(0) !== 0xFFFD) { e[D[242][j]] = 61952 + j; d[61952 + j] = D[242][j];} +D[243] = "����������������������������������������������������������������譑譂譒譗豃豷豶貚贆贇贉趬趪趭趫蹭蹸蹳蹪蹯蹻軂轒轑轏轐轓辴酀鄿醰醭鏞鏇鏏鏂鏚鏐鏹鏬鏌鏙鎩鏦鏊鏔鏮鏣鏕鏄鏎鏀鏒鏧镽闚闛雡霩霫霬霨霦����������������������������������鞳鞷鞶韝韞韟顜顙顝顗颿颽颻颾饈饇饃馦馧騚騕騥騝騤騛騢騠騧騣騞騜騔髂鬋鬊鬎鬌鬷鯪鯫鯠鯞鯤鯦鯢鯰鯔鯗鯬鯜鯙鯥鯕鯡鯚鵷鶁鶊鶄鶈鵱鶀鵸鶆鶋鶌鵽鵫鵴鵵鵰鵩鶅鵳鵻鶂鵯鵹鵿鶇鵨麔麑黀黼鼭齀齁齍齖齗齘匷嚲�".split(""); +for(j = 0; j != D[243].length; ++j) if(D[243][j].charCodeAt(0) !== 0xFFFD) { e[D[243][j]] = 62208 + j; d[62208 + j] = D[243][j];} +D[244] = "����������������������������������������������������������������嚵嚳壣孅巆巇廮廯忀忁懹攗攖攕攓旟曨曣曤櫳櫰櫪櫨櫹櫱櫮櫯瀼瀵瀯瀷瀴瀱灂瀸瀿瀺瀹灀瀻瀳灁爓爔犨獽獼璺皫皪皾盭矌矎矏矍矲礥礣礧礨礤礩����������������������������������禲穮穬穭竷籉籈籊籇籅糮繻繾纁纀羺翿聹臛臙舋艨艩蘢藿蘁藾蘛蘀藶蘄蘉蘅蘌藽蠙蠐蠑蠗蠓蠖襣襦覹觷譠譪譝譨譣譥譧譭趮躆躈躄轙轖轗轕轘轚邍酃酁醷醵醲醳鐋鐓鏻鐠鐏鐔鏾鐕鐐鐨鐙鐍鏵鐀鏷鐇鐎鐖鐒鏺鐉鏸鐊鏿�".split(""); +for(j = 0; j != D[244].length; ++j) if(D[244][j].charCodeAt(0) !== 0xFFFD) { e[D[244][j]] = 62464 + j; d[62464 + j] = D[244][j];} +D[245] = "����������������������������������������������������������������鏼鐌鏶鐑鐆闞闠闟霮霯鞹鞻韽韾顠顢顣顟飁飂饐饎饙饌饋饓騲騴騱騬騪騶騩騮騸騭髇髊髆鬐鬒鬑鰋鰈鯷鰅鰒鯸鱀鰇鰎鰆鰗鰔鰉鶟鶙鶤鶝鶒鶘鶐鶛����������������������������������鶠鶔鶜鶪鶗鶡鶚鶢鶨鶞鶣鶿鶩鶖鶦鶧麙麛麚黥黤黧黦鼰鼮齛齠齞齝齙龑儺儹劘劗囃嚽嚾孈孇巋巏廱懽攛欂櫼欃櫸欀灃灄灊灈灉灅灆爝爚爙獾甗癪矐礭礱礯籔籓糲纊纇纈纋纆纍罍羻耰臝蘘蘪蘦蘟蘣蘜蘙蘧蘮蘡蘠蘩蘞蘥�".split(""); +for(j = 0; j != D[245].length; ++j) if(D[245][j].charCodeAt(0) !== 0xFFFD) { e[D[245][j]] = 62720 + j; d[62720 + j] = D[245][j];} +D[246] = "����������������������������������������������������������������蠩蠝蠛蠠蠤蠜蠫衊襭襩襮襫觺譹譸譅譺譻贐贔趯躎躌轞轛轝酆酄酅醹鐿鐻鐶鐩鐽鐼鐰鐹鐪鐷鐬鑀鐱闥闤闣霵霺鞿韡顤飉飆飀饘饖騹騽驆驄驂驁騺����������������������������������騿髍鬕鬗鬘鬖鬺魒鰫鰝鰜鰬鰣鰨鰩鰤鰡鶷鶶鶼鷁鷇鷊鷏鶾鷅鷃鶻鶵鷎鶹鶺鶬鷈鶱鶭鷌鶳鷍鶲鹺麜黫黮黭鼛鼘鼚鼱齎齥齤龒亹囆囅囋奱孋孌巕巑廲攡攠攦攢欋欈欉氍灕灖灗灒爞爟犩獿瓘瓕瓙瓗癭皭礵禴穰穱籗籜籙籛籚�".split(""); +for(j = 0; j != D[246].length; ++j) if(D[246][j].charCodeAt(0) !== 0xFFFD) { e[D[246][j]] = 62976 + j; d[62976 + j] = D[246][j];} +D[247] = "����������������������������������������������������������������糴糱纑罏羇臞艫蘴蘵蘳蘬蘲蘶蠬蠨蠦蠪蠥襱覿覾觻譾讄讂讆讅譿贕躕躔躚躒躐躖躗轠轢酇鑌鑐鑊鑋鑏鑇鑅鑈鑉鑆霿韣顪顩飋饔饛驎驓驔驌驏驈驊����������������������������������驉驒驐髐鬙鬫鬻魖魕鱆鱈鰿鱄鰹鰳鱁鰼鰷鰴鰲鰽鰶鷛鷒鷞鷚鷋鷐鷜鷑鷟鷩鷙鷘鷖鷵鷕鷝麶黰鼵鼳鼲齂齫龕龢儽劙壨壧奲孍巘蠯彏戁戃戄攩攥斖曫欑欒欏毊灛灚爢玂玁玃癰矔籧籦纕艬蘺虀蘹蘼蘱蘻蘾蠰蠲蠮蠳襶襴襳觾�".split(""); +for(j = 0; j != D[247].length; ++j) if(D[247][j].charCodeAt(0) !== 0xFFFD) { e[D[247][j]] = 63232 + j; d[63232 + j] = D[247][j];} +D[248] = "����������������������������������������������������������������讌讎讋讈豅贙躘轤轣醼鑢鑕鑝鑗鑞韄韅頀驖驙鬞鬟鬠鱒鱘鱐鱊鱍鱋鱕鱙鱌鱎鷻鷷鷯鷣鷫鷸鷤鷶鷡鷮鷦鷲鷰鷢鷬鷴鷳鷨鷭黂黐黲黳鼆鼜鼸鼷鼶齃齏����������������������������������齱齰齮齯囓囍孎屭攭曭曮欓灟灡灝灠爣瓛瓥矕礸禷禶籪纗羉艭虃蠸蠷蠵衋讔讕躞躟躠躝醾醽釂鑫鑨鑩雥靆靃靇韇韥驞髕魙鱣鱧鱦鱢鱞鱠鸂鷾鸇鸃鸆鸅鸀鸁鸉鷿鷽鸄麠鼞齆齴齵齶囔攮斸欘欙欗欚灢爦犪矘矙礹籩籫糶纚�".split(""); +for(j = 0; j != D[248].length; ++j) if(D[248][j].charCodeAt(0) !== 0xFFFD) { e[D[248][j]] = 63488 + j; d[63488 + j] = D[248][j];} +D[249] = "����������������������������������������������������������������纘纛纙臠臡虆虇虈襹襺襼襻觿讘讙躥躤躣鑮鑭鑯鑱鑳靉顲饟鱨鱮鱭鸋鸍鸐鸏鸒鸑麡黵鼉齇齸齻齺齹圞灦籯蠼趲躦釃鑴鑸鑶鑵驠鱴鱳鱱鱵鸔鸓黶鼊����������������������������������龤灨灥糷虪蠾蠽蠿讞貜躩軉靋顳顴飌饡馫驤驦驧鬤鸕鸗齈戇欞爧虌躨钂钀钁驩驨鬮鸙爩虋讟钃鱹麷癵驫鱺鸝灩灪麤齾齉龘碁銹裏墻恒粧嫺╔╦╗╠╬╣╚╩╝╒╤╕╞╪╡╘╧╛╓╥╖╟╫╢╙╨╜║═╭╮╰╯▓�".split(""); +for(j = 0; j != D[249].length; ++j) if(D[249][j].charCodeAt(0) !== 0xFFFD) { e[D[249][j]] = 63744 + j; d[63744 + j] = D[249][j];} +return {"enc": e, "dec": d }; })(); +cptable[1250] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€�‚�„…†‡�‰Š‹ŚŤŽŹ�‘’“”•–—�™š›śťžź ˇ˘Ł¤Ą¦§¨©Ş«¬­®Ż°±˛ł´µ¶·¸ąş»Ľ˝ľżŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[1251] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ЂЃ‚ѓ„…†‡€‰Љ‹ЊЌЋЏђ‘’“”•–—�™љ›њќћџ ЎўЈ¤Ґ¦§Ё©Є«¬­®Ї°±Ііґµ¶·ё№є»јЅѕїАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[1252] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€�‚ƒ„…†‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[1253] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€�‚ƒ„…†‡�‰�‹�����‘’“”•–—�™�›���� ΅Ά£¤¥¦§¨©�«¬­®―°±²³΄µ¶·ΈΉΊ»Ό½ΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ�ΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ�", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[1254] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€�‚ƒ„…†‡ˆ‰Š‹Œ����‘’“”•–—˜™š›œ��Ÿ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖרÙÚÛÜİŞßàáâãäåæçèéêëìíîïğñòóôõö÷øùúûüışÿ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[1255] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€�‚ƒ„…†‡ˆ‰�‹�����‘’“”•–—˜™�›���� ¡¢£₪¥¦§¨©×«¬­®¯°±²³´µ¶·¸¹÷»¼½¾¿ְֱֲֳִֵֶַָֹ�ֻּֽ־ֿ׀ׁׂ׃װױײ׳״�������אבגדהוזחטיךכלםמןנסעףפץצקרשת��‎‏�", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[1256] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€پ‚ƒ„…†‡ˆ‰ٹ‹Œچژڈگ‘’“”•–—ک™ڑ›œ‌‍ں ،¢£¤¥¦§¨©ھ«¬­®¯°±²³´µ¶·¸¹؛»¼½¾؟ہءآأؤإئابةتثجحخدذرزسشصض×طظعغـفقكàلâمنهوçèéêëىيîïًٌٍَôُِ÷ّùْûü‎‏ے", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[1257] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€�‚�„…†‡�‰�‹�¨ˇ¸�‘’“”•–—�™�›�¯˛� �¢£¤�¦§Ø©Ŗ«¬­®Æ°±²³´µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽßąįāćäåęēčéźėģķīļšńņóōõö÷ųłśūüżž˙", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[1258] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€�‚ƒ„…†‡ˆ‰�‹Œ����‘’“”•–—˜™�›œ��Ÿ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂĂÄÅÆÇÈÉÊË̀ÍÎÏĐÑ̉ÓÔƠÖרÙÚÛÜỮßàáâăäåæçèéêë́íîïđṇ̃óôơö÷øùúûüư₫ÿ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[10000] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤‹›fifl‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[10006] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ĺ²É³ÖÜ΅àâä΄¨çéèê룙î‰ôö¦­ùûü†ΓΔΘΛΞΠß®©ΣΪ§≠°·Α±≤≥¥ΒΕΖΗΙΚΜΦΫΨΩάΝ¬ΟΡ≈Τ«»… ΥΧΆΈœ–―“”‘’÷ΉΊΌΎέήίόΏύαβψδεφγηιξκλμνοπώρστθωςχυζϊϋΐΰ�", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[10007] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°¢£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµ∂ЈЄєЇїЉљЊњјЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю¤", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[10008] = (function(){ var d = [], e = {}, D = [], j; +D[0] = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€���������������������������������������������������������������������������������������".split(""); +for(j = 0; j != D[0].length; ++j) if(D[0][j].charCodeAt(0) !== 0xFFFD) { e[D[0][j]] = 0 + j; d[0 + j] = D[0][j];} +D[161] = "����������������������������������������������������������������������������������������������������������������������������������������������������������������� 、。・ˉˇ¨〃々―~�…‘’“”〔〕〈〉《》「」『』〖〗【】±×÷∶∧∨∑∏∪∩∈∷√⊥∥∠⌒⊙∫∮≡≌≈∽∝≠≮≯≤≥∞∵∴♂♀°′″℃$¤¢£‰§№☆★○●◎◇◆□■△▲※→←↑↓〓�".split(""); +for(j = 0; j != D[161].length; ++j) if(D[161][j].charCodeAt(0) !== 0xFFFD) { e[D[161][j]] = 41216 + j; d[41216 + j] = D[161][j];} +D[162] = "���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇①②③④⑤⑥⑦⑧⑨⑩��㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩��ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ���".split(""); +for(j = 0; j != D[162].length; ++j) if(D[162][j].charCodeAt(0) !== 0xFFFD) { e[D[162][j]] = 41472 + j; d[41472 + j] = D[162][j];} +D[163] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������!"#¥%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|} ̄�".split(""); +for(j = 0; j != D[163].length; ++j) if(D[163][j].charCodeAt(0) !== 0xFFFD) { e[D[163][j]] = 41728 + j; d[41728 + j] = D[163][j];} +D[164] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをん������������".split(""); +for(j = 0; j != D[164].length; ++j) if(D[164][j].charCodeAt(0) !== 0xFFFD) { e[D[164][j]] = 41984 + j; d[41984 + j] = D[164][j];} +D[165] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶ���������".split(""); +for(j = 0; j != D[165].length; ++j) if(D[165][j].charCodeAt(0) !== 0xFFFD) { e[D[165][j]] = 42240 + j; d[42240 + j] = D[165][j];} +D[166] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ��������αβγδεζηθικλμνξοπρστυφχψω���������������������������������������".split(""); +for(j = 0; j != D[166].length; ++j) if(D[166][j].charCodeAt(0) !== 0xFFFD) { e[D[166][j]] = 42496 + j; d[42496 + j] = D[166][j];} +D[167] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ���������������абвгдеёжзийклмнопрстуфхцчшщъыьэюя��������������".split(""); +for(j = 0; j != D[167].length; ++j) if(D[167][j].charCodeAt(0) !== 0xFFFD) { e[D[167][j]] = 42752 + j; d[42752 + j] = D[167][j];} +D[168] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜüê����������ㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩ����������������������".split(""); +for(j = 0; j != D[168].length; ++j) if(D[168][j].charCodeAt(0) !== 0xFFFD) { e[D[168][j]] = 43008 + j; d[43008 + j] = D[168][j];} +D[169] = "��������������������������������������������������������������������������������������������������������������������������������������������������������������������─━│┃┄┅┆┇┈┉┊┋┌┍┎┏┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋����������������".split(""); +for(j = 0; j != D[169].length; ++j) if(D[169][j].charCodeAt(0) !== 0xFFFD) { e[D[169][j]] = 43264 + j; d[43264 + j] = D[169][j];} +D[176] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������啊阿埃挨哎唉哀皑癌蔼矮艾碍爱隘鞍氨安俺按暗岸胺案肮昂盎凹敖熬翱袄傲奥懊澳芭捌扒叭吧笆八疤巴拔跋靶把耙坝霸罢爸白柏百摆佰败拜稗斑班搬扳般颁板版扮拌伴瓣半办绊邦帮梆榜膀绑棒磅蚌镑傍谤苞胞包褒剥�".split(""); +for(j = 0; j != D[176].length; ++j) if(D[176][j].charCodeAt(0) !== 0xFFFD) { e[D[176][j]] = 45056 + j; d[45056 + j] = D[176][j];} +D[177] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������薄雹保堡饱宝抱报暴豹鲍爆杯碑悲卑北辈背贝钡倍狈备惫焙被奔苯本笨崩绷甭泵蹦迸逼鼻比鄙笔彼碧蓖蔽毕毙毖币庇痹闭敝弊必辟壁臂避陛鞭边编贬扁便变卞辨辩辫遍标彪膘表鳖憋别瘪彬斌濒滨宾摈兵冰柄丙秉饼炳�".split(""); +for(j = 0; j != D[177].length; ++j) if(D[177][j].charCodeAt(0) !== 0xFFFD) { e[D[177][j]] = 45312 + j; d[45312 + j] = D[177][j];} +D[178] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������病并玻菠播拨钵波博勃搏铂箔伯帛舶脖膊渤泊驳捕卜哺补埠不布步簿部怖擦猜裁材才财睬踩采彩菜蔡餐参蚕残惭惨灿苍舱仓沧藏操糙槽曹草厕策侧册测层蹭插叉茬茶查碴搽察岔差诧拆柴豺搀掺蝉馋谗缠铲产阐颤昌猖�".split(""); +for(j = 0; j != D[178].length; ++j) if(D[178][j].charCodeAt(0) !== 0xFFFD) { e[D[178][j]] = 45568 + j; d[45568 + j] = D[178][j];} +D[179] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������场尝常长偿肠厂敞畅唱倡超抄钞朝嘲潮巢吵炒车扯撤掣彻澈郴臣辰尘晨忱沉陈趁衬撑称城橙成呈乘程惩澄诚承逞骋秤吃痴持匙池迟弛驰耻齿侈尺赤翅斥炽充冲虫崇宠抽酬畴踌稠愁筹仇绸瞅丑臭初出橱厨躇锄雏滁除楚�".split(""); +for(j = 0; j != D[179].length; ++j) if(D[179][j].charCodeAt(0) !== 0xFFFD) { e[D[179][j]] = 45824 + j; d[45824 + j] = D[179][j];} +D[180] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������础储矗搐触处揣川穿椽传船喘串疮窗幢床闯创吹炊捶锤垂春椿醇唇淳纯蠢戳绰疵茨磁雌辞慈瓷词此刺赐次聪葱囱匆从丛凑粗醋簇促蹿篡窜摧崔催脆瘁粹淬翠村存寸磋撮搓措挫错搭达答瘩打大呆歹傣戴带殆代贷袋待逮�".split(""); +for(j = 0; j != D[180].length; ++j) if(D[180][j].charCodeAt(0) !== 0xFFFD) { e[D[180][j]] = 46080 + j; d[46080 + j] = D[180][j];} +D[181] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������怠耽担丹单郸掸胆旦氮但惮淡诞弹蛋当挡党荡档刀捣蹈倒岛祷导到稻悼道盗德得的蹬灯登等瞪凳邓堤低滴迪敌笛狄涤翟嫡抵底地蒂第帝弟递缔颠掂滇碘点典靛垫电佃甸店惦奠淀殿碉叼雕凋刁掉吊钓调跌爹碟蝶迭谍叠�".split(""); +for(j = 0; j != D[181].length; ++j) if(D[181][j].charCodeAt(0) !== 0xFFFD) { e[D[181][j]] = 46336 + j; d[46336 + j] = D[181][j];} +D[182] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������丁盯叮钉顶鼎锭定订丢东冬董懂动栋侗恫冻洞兜抖斗陡豆逗痘都督毒犊独读堵睹赌杜镀肚度渡妒端短锻段断缎堆兑队对墩吨蹲敦顿囤钝盾遁掇哆多夺垛躲朵跺舵剁惰堕蛾峨鹅俄额讹娥恶厄扼遏鄂饿恩而儿耳尔饵洱二�".split(""); +for(j = 0; j != D[182].length; ++j) if(D[182][j].charCodeAt(0) !== 0xFFFD) { e[D[182][j]] = 46592 + j; d[46592 + j] = D[182][j];} +D[183] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������贰发罚筏伐乏阀法珐藩帆番翻樊矾钒繁凡烦反返范贩犯饭泛坊芳方肪房防妨仿访纺放菲非啡飞肥匪诽吠肺废沸费芬酚吩氛分纷坟焚汾粉奋份忿愤粪丰封枫蜂峰锋风疯烽逢冯缝讽奉凤佛否夫敷肤孵扶拂辐幅氟符伏俘服�".split(""); +for(j = 0; j != D[183].length; ++j) if(D[183][j].charCodeAt(0) !== 0xFFFD) { e[D[183][j]] = 46848 + j; d[46848 + j] = D[183][j];} +D[184] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������浮涪福袱弗甫抚辅俯釜斧脯腑府腐赴副覆赋复傅付阜父腹负富讣附妇缚咐噶嘎该改概钙盖溉干甘杆柑竿肝赶感秆敢赣冈刚钢缸肛纲岗港杠篙皋高膏羔糕搞镐稿告哥歌搁戈鸽胳疙割革葛格蛤阁隔铬个各给根跟耕更庚羹�".split(""); +for(j = 0; j != D[184].length; ++j) if(D[184][j].charCodeAt(0) !== 0xFFFD) { e[D[184][j]] = 47104 + j; d[47104 + j] = D[184][j];} +D[185] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������埂耿梗工攻功恭龚供躬公宫弓巩汞拱贡共钩勾沟苟狗垢构购够辜菇咕箍估沽孤姑鼓古蛊骨谷股故顾固雇刮瓜剐寡挂褂乖拐怪棺关官冠观管馆罐惯灌贯光广逛瑰规圭硅归龟闺轨鬼诡癸桂柜跪贵刽辊滚棍锅郭国果裹过哈�".split(""); +for(j = 0; j != D[185].length; ++j) if(D[185][j].charCodeAt(0) !== 0xFFFD) { e[D[185][j]] = 47360 + j; d[47360 + j] = D[185][j];} +D[186] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������骸孩海氦亥害骇酣憨邯韩含涵寒函喊罕翰撼捍旱憾悍焊汗汉夯杭航壕嚎豪毫郝好耗号浩呵喝荷菏核禾和何合盒貉阂河涸赫褐鹤贺嘿黑痕很狠恨哼亨横衡恒轰哄烘虹鸿洪宏弘红喉侯猴吼厚候后呼乎忽瑚壶葫胡蝴狐糊湖�".split(""); +for(j = 0; j != D[186].length; ++j) if(D[186][j].charCodeAt(0) !== 0xFFFD) { e[D[186][j]] = 47616 + j; d[47616 + j] = D[186][j];} +D[187] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������弧虎唬护互沪户花哗华猾滑画划化话槐徊怀淮坏欢环桓还缓换患唤痪豢焕涣宦幻荒慌黄磺蝗簧皇凰惶煌晃幌恍谎灰挥辉徽恢蛔回毁悔慧卉惠晦贿秽会烩汇讳诲绘荤昏婚魂浑混豁活伙火获或惑霍货祸击圾基机畸稽积箕�".split(""); +for(j = 0; j != D[187].length; ++j) if(D[187][j].charCodeAt(0) !== 0xFFFD) { e[D[187][j]] = 47872 + j; d[47872 + j] = D[187][j];} +D[188] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������肌饥迹激讥鸡姬绩缉吉极棘辑籍集及急疾汲即嫉级挤几脊己蓟技冀季伎祭剂悸济寄寂计记既忌际妓继纪嘉枷夹佳家加荚颊贾甲钾假稼价架驾嫁歼监坚尖笺间煎兼肩艰奸缄茧检柬碱硷拣捡简俭剪减荐槛鉴践贱见键箭件�".split(""); +for(j = 0; j != D[188].length; ++j) if(D[188][j].charCodeAt(0) !== 0xFFFD) { e[D[188][j]] = 48128 + j; d[48128 + j] = D[188][j];} +D[189] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������健舰剑饯渐溅涧建僵姜将浆江疆蒋桨奖讲匠酱降蕉椒礁焦胶交郊浇骄娇嚼搅铰矫侥脚狡角饺缴绞剿教酵轿较叫窖揭接皆秸街阶截劫节桔杰捷睫竭洁结解姐戒藉芥界借介疥诫届巾筋斤金今津襟紧锦仅谨进靳晋禁近烬浸�".split(""); +for(j = 0; j != D[189].length; ++j) if(D[189][j].charCodeAt(0) !== 0xFFFD) { e[D[189][j]] = 48384 + j; d[48384 + j] = D[189][j];} +D[190] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������尽劲荆兢茎睛晶鲸京惊精粳经井警景颈静境敬镜径痉靖竟竞净炯窘揪究纠玖韭久灸九酒厩救旧臼舅咎就疚鞠拘狙疽居驹菊局咀矩举沮聚拒据巨具距踞锯俱句惧炬剧捐鹃娟倦眷卷绢撅攫抉掘倔爵觉决诀绝均菌钧军君峻�".split(""); +for(j = 0; j != D[190].length; ++j) if(D[190][j].charCodeAt(0) !== 0xFFFD) { e[D[190][j]] = 48640 + j; d[48640 + j] = D[190][j];} +D[191] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������俊竣浚郡骏喀咖卡咯开揩楷凯慨刊堪勘坎砍看康慷糠扛抗亢炕考拷烤靠坷苛柯棵磕颗科壳咳可渴克刻客课肯啃垦恳坑吭空恐孔控抠口扣寇枯哭窟苦酷库裤夸垮挎跨胯块筷侩快宽款匡筐狂框矿眶旷况亏盔岿窥葵奎魁傀�".split(""); +for(j = 0; j != D[191].length; ++j) if(D[191][j].charCodeAt(0) !== 0xFFFD) { e[D[191][j]] = 48896 + j; d[48896 + j] = D[191][j];} +D[192] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������馈愧溃坤昆捆困括扩廓阔垃拉喇蜡腊辣啦莱来赖蓝婪栏拦篮阑兰澜谰揽览懒缆烂滥琅榔狼廊郎朗浪捞劳牢老佬姥酪烙涝勒乐雷镭蕾磊累儡垒擂肋类泪棱楞冷厘梨犁黎篱狸离漓理李里鲤礼莉荔吏栗丽厉励砾历利傈例俐�".split(""); +for(j = 0; j != D[192].length; ++j) if(D[192][j].charCodeAt(0) !== 0xFFFD) { e[D[192][j]] = 49152 + j; d[49152 + j] = D[192][j];} +D[193] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������痢立粒沥隶力璃哩俩联莲连镰廉怜涟帘敛脸链恋炼练粮凉梁粱良两辆量晾亮谅撩聊僚疗燎寥辽潦了撂镣廖料列裂烈劣猎琳林磷霖临邻鳞淋凛赁吝拎玲菱零龄铃伶羚凌灵陵岭领另令溜琉榴硫馏留刘瘤流柳六龙聋咙笼窿�".split(""); +for(j = 0; j != D[193].length; ++j) if(D[193][j].charCodeAt(0) !== 0xFFFD) { e[D[193][j]] = 49408 + j; d[49408 + j] = D[193][j];} +D[194] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������隆垄拢陇楼娄搂篓漏陋芦卢颅庐炉掳卤虏鲁麓碌露路赂鹿潞禄录陆戮驴吕铝侣旅履屡缕虑氯律率滤绿峦挛孪滦卵乱掠略抡轮伦仑沦纶论萝螺罗逻锣箩骡裸落洛骆络妈麻玛码蚂马骂嘛吗埋买麦卖迈脉瞒馒蛮满蔓曼慢漫�".split(""); +for(j = 0; j != D[194].length; ++j) if(D[194][j].charCodeAt(0) !== 0xFFFD) { e[D[194][j]] = 49664 + j; d[49664 + j] = D[194][j];} +D[195] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������谩芒茫盲氓忙莽猫茅锚毛矛铆卯茂冒帽貌贸么玫枚梅酶霉煤没眉媒镁每美昧寐妹媚门闷们萌蒙檬盟锰猛梦孟眯醚靡糜迷谜弥米秘觅泌蜜密幂棉眠绵冕免勉娩缅面苗描瞄藐秒渺庙妙蔑灭民抿皿敏悯闽明螟鸣铭名命谬摸�".split(""); +for(j = 0; j != D[195].length; ++j) if(D[195][j].charCodeAt(0) !== 0xFFFD) { e[D[195][j]] = 49920 + j; d[49920 + j] = D[195][j];} +D[196] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������摹蘑模膜磨摩魔抹末莫墨默沫漠寞陌谋牟某拇牡亩姆母墓暮幕募慕木目睦牧穆拿哪呐钠那娜纳氖乃奶耐奈南男难囊挠脑恼闹淖呢馁内嫩能妮霓倪泥尼拟你匿腻逆溺蔫拈年碾撵捻念娘酿鸟尿捏聂孽啮镊镍涅您柠狞凝宁�".split(""); +for(j = 0; j != D[196].length; ++j) if(D[196][j].charCodeAt(0) !== 0xFFFD) { e[D[196][j]] = 50176 + j; d[50176 + j] = D[196][j];} +D[197] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������拧泞牛扭钮纽脓浓农弄奴努怒女暖虐疟挪懦糯诺哦欧鸥殴藕呕偶沤啪趴爬帕怕琶拍排牌徘湃派攀潘盘磐盼畔判叛乓庞旁耪胖抛咆刨炮袍跑泡呸胚培裴赔陪配佩沛喷盆砰抨烹澎彭蓬棚硼篷膨朋鹏捧碰坯砒霹批披劈琵毗�".split(""); +for(j = 0; j != D[197].length; ++j) if(D[197][j].charCodeAt(0) !== 0xFFFD) { e[D[197][j]] = 50432 + j; d[50432 + j] = D[197][j];} +D[198] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������啤脾疲皮匹痞僻屁譬篇偏片骗飘漂瓢票撇瞥拼频贫品聘乒坪苹萍平凭瓶评屏坡泼颇婆破魄迫粕剖扑铺仆莆葡菩蒲埔朴圃普浦谱曝瀑期欺栖戚妻七凄漆柒沏其棋奇歧畦崎脐齐旗祈祁骑起岂乞企启契砌器气迄弃汽泣讫掐�".split(""); +for(j = 0; j != D[198].length; ++j) if(D[198][j].charCodeAt(0) !== 0xFFFD) { e[D[198][j]] = 50688 + j; d[50688 + j] = D[198][j];} +D[199] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������恰洽牵扦钎铅千迁签仟谦乾黔钱钳前潜遣浅谴堑嵌欠歉枪呛腔羌墙蔷强抢橇锹敲悄桥瞧乔侨巧鞘撬翘峭俏窍切茄且怯窃钦侵亲秦琴勤芹擒禽寝沁青轻氢倾卿清擎晴氰情顷请庆琼穷秋丘邱球求囚酋泅趋区蛆曲躯屈驱渠�".split(""); +for(j = 0; j != D[199].length; ++j) if(D[199][j].charCodeAt(0) !== 0xFFFD) { e[D[199][j]] = 50944 + j; d[50944 + j] = D[199][j];} +D[200] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������取娶龋趣去圈颧权醛泉全痊拳犬券劝缺炔瘸却鹊榷确雀裙群然燃冉染瓤壤攘嚷让饶扰绕惹热壬仁人忍韧任认刃妊纫扔仍日戎茸蓉荣融熔溶容绒冗揉柔肉茹蠕儒孺如辱乳汝入褥软阮蕊瑞锐闰润若弱撒洒萨腮鳃塞赛三叁�".split(""); +for(j = 0; j != D[200].length; ++j) if(D[200][j].charCodeAt(0) !== 0xFFFD) { e[D[200][j]] = 51200 + j; d[51200 + j] = D[200][j];} +D[201] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������伞散桑嗓丧搔骚扫嫂瑟色涩森僧莎砂杀刹沙纱傻啥煞筛晒珊苫杉山删煽衫闪陕擅赡膳善汕扇缮墒伤商赏晌上尚裳梢捎稍烧芍勺韶少哨邵绍奢赊蛇舌舍赦摄射慑涉社设砷申呻伸身深娠绅神沈审婶甚肾慎渗声生甥牲升绳�".split(""); +for(j = 0; j != D[201].length; ++j) if(D[201][j].charCodeAt(0) !== 0xFFFD) { e[D[201][j]] = 51456 + j; d[51456 + j] = D[201][j];} +D[202] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������省盛剩胜圣师失狮施湿诗尸虱十石拾时什食蚀实识史矢使屎驶始式示士世柿事拭誓逝势是嗜噬适仕侍释饰氏市恃室视试收手首守寿授售受瘦兽蔬枢梳殊抒输叔舒淑疏书赎孰熟薯暑曙署蜀黍鼠属术述树束戍竖墅庶数漱�".split(""); +for(j = 0; j != D[202].length; ++j) if(D[202][j].charCodeAt(0) !== 0xFFFD) { e[D[202][j]] = 51712 + j; d[51712 + j] = D[202][j];} +D[203] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������恕刷耍摔衰甩帅栓拴霜双爽谁水睡税吮瞬顺舜说硕朔烁斯撕嘶思私司丝死肆寺嗣四伺似饲巳松耸怂颂送宋讼诵搜艘擞嗽苏酥俗素速粟僳塑溯宿诉肃酸蒜算虽隋随绥髓碎岁穗遂隧祟孙损笋蓑梭唆缩琐索锁所塌他它她塔�".split(""); +for(j = 0; j != D[203].length; ++j) if(D[203][j].charCodeAt(0) !== 0xFFFD) { e[D[203][j]] = 51968 + j; d[51968 + j] = D[203][j];} +D[204] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������獭挞蹋踏胎苔抬台泰酞太态汰坍摊贪瘫滩坛檀痰潭谭谈坦毯袒碳探叹炭汤塘搪堂棠膛唐糖倘躺淌趟烫掏涛滔绦萄桃逃淘陶讨套特藤腾疼誊梯剔踢锑提题蹄啼体替嚏惕涕剃屉天添填田甜恬舔腆挑条迢眺跳贴铁帖厅听烃�".split(""); +for(j = 0; j != D[204].length; ++j) if(D[204][j].charCodeAt(0) !== 0xFFFD) { e[D[204][j]] = 52224 + j; d[52224 + j] = D[204][j];} +D[205] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������汀廷停亭庭挺艇通桐酮瞳同铜彤童桶捅筒统痛偷投头透凸秃突图徒途涂屠土吐兔湍团推颓腿蜕褪退吞屯臀拖托脱鸵陀驮驼椭妥拓唾挖哇蛙洼娃瓦袜歪外豌弯湾玩顽丸烷完碗挽晚皖惋宛婉万腕汪王亡枉网往旺望忘妄威�".split(""); +for(j = 0; j != D[205].length; ++j) if(D[205][j].charCodeAt(0) !== 0xFFFD) { e[D[205][j]] = 52480 + j; d[52480 + j] = D[205][j];} +D[206] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������巍微危韦违桅围唯惟为潍维苇萎委伟伪尾纬未蔚味畏胃喂魏位渭谓尉慰卫瘟温蚊文闻纹吻稳紊问嗡翁瓮挝蜗涡窝我斡卧握沃巫呜钨乌污诬屋无芜梧吾吴毋武五捂午舞伍侮坞戊雾晤物勿务悟误昔熙析西硒矽晰嘻吸锡牺�".split(""); +for(j = 0; j != D[206].length; ++j) if(D[206][j].charCodeAt(0) !== 0xFFFD) { e[D[206][j]] = 52736 + j; d[52736 + j] = D[206][j];} +D[207] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������稀息希悉膝夕惜熄烯溪汐犀檄袭席习媳喜铣洗系隙戏细瞎虾匣霞辖暇峡侠狭下厦夏吓掀锨先仙鲜纤咸贤衔舷闲涎弦嫌显险现献县腺馅羡宪陷限线相厢镶香箱襄湘乡翔祥详想响享项巷橡像向象萧硝霄削哮嚣销消宵淆晓�".split(""); +for(j = 0; j != D[207].length; ++j) if(D[207][j].charCodeAt(0) !== 0xFFFD) { e[D[207][j]] = 52992 + j; d[52992 + j] = D[207][j];} +D[208] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������小孝校肖啸笑效楔些歇蝎鞋协挟携邪斜胁谐写械卸蟹懈泄泻谢屑薪芯锌欣辛新忻心信衅星腥猩惺兴刑型形邢行醒幸杏性姓兄凶胸匈汹雄熊休修羞朽嗅锈秀袖绣墟戌需虚嘘须徐许蓄酗叙旭序畜恤絮婿绪续轩喧宣悬旋玄�".split(""); +for(j = 0; j != D[208].length; ++j) if(D[208][j].charCodeAt(0) !== 0xFFFD) { e[D[208][j]] = 53248 + j; d[53248 + j] = D[208][j];} +D[209] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������选癣眩绚靴薛学穴雪血勋熏循旬询寻驯巡殉汛训讯逊迅压押鸦鸭呀丫芽牙蚜崖衙涯雅哑亚讶焉咽阉烟淹盐严研蜒岩延言颜阎炎沿奄掩眼衍演艳堰燕厌砚雁唁彦焰宴谚验殃央鸯秧杨扬佯疡羊洋阳氧仰痒养样漾邀腰妖瑶�".split(""); +for(j = 0; j != D[209].length; ++j) if(D[209][j].charCodeAt(0) !== 0xFFFD) { e[D[209][j]] = 53504 + j; d[53504 + j] = D[209][j];} +D[210] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������摇尧遥窑谣姚咬舀药要耀椰噎耶爷野冶也页掖业叶曳腋夜液一壹医揖铱依伊衣颐夷遗移仪胰疑沂宜姨彝椅蚁倚已乙矣以艺抑易邑屹亿役臆逸肄疫亦裔意毅忆义益溢诣议谊译异翼翌绎茵荫因殷音阴姻吟银淫寅饮尹引隐�".split(""); +for(j = 0; j != D[210].length; ++j) if(D[210][j].charCodeAt(0) !== 0xFFFD) { e[D[210][j]] = 53760 + j; d[53760 + j] = D[210][j];} +D[211] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������印英樱婴鹰应缨莹萤营荧蝇迎赢盈影颖硬映哟拥佣臃痈庸雍踊蛹咏泳涌永恿勇用幽优悠忧尤由邮铀犹油游酉有友右佑釉诱又幼迂淤于盂榆虞愚舆余俞逾鱼愉渝渔隅予娱雨与屿禹宇语羽玉域芋郁吁遇喻峪御愈欲狱育誉�".split(""); +for(j = 0; j != D[211].length; ++j) if(D[211][j].charCodeAt(0) !== 0xFFFD) { e[D[211][j]] = 54016 + j; d[54016 + j] = D[211][j];} +D[212] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������浴寓裕预豫驭鸳渊冤元垣袁原援辕园员圆猿源缘远苑愿怨院曰约越跃钥岳粤月悦阅耘云郧匀陨允运蕴酝晕韵孕匝砸杂栽哉灾宰载再在咱攒暂赞赃脏葬遭糟凿藻枣早澡蚤躁噪造皂灶燥责择则泽贼怎增憎曾赠扎喳渣札轧�".split(""); +for(j = 0; j != D[212].length; ++j) if(D[212][j].charCodeAt(0) !== 0xFFFD) { e[D[212][j]] = 54272 + j; d[54272 + j] = D[212][j];} +D[213] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������铡闸眨栅榨咋乍炸诈摘斋宅窄债寨瞻毡詹粘沾盏斩辗崭展蘸栈占战站湛绽樟章彰漳张掌涨杖丈帐账仗胀瘴障招昭找沼赵照罩兆肇召遮折哲蛰辙者锗蔗这浙珍斟真甄砧臻贞针侦枕疹诊震振镇阵蒸挣睁征狰争怔整拯正政�".split(""); +for(j = 0; j != D[213].length; ++j) if(D[213][j].charCodeAt(0) !== 0xFFFD) { e[D[213][j]] = 54528 + j; d[54528 + j] = D[213][j];} +D[214] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������帧症郑证芝枝支吱蜘知肢脂汁之织职直植殖执值侄址指止趾只旨纸志挚掷至致置帜峙制智秩稚质炙痔滞治窒中盅忠钟衷终种肿重仲众舟周州洲诌粥轴肘帚咒皱宙昼骤珠株蛛朱猪诸诛逐竹烛煮拄瞩嘱主著柱助蛀贮铸筑�".split(""); +for(j = 0; j != D[214].length; ++j) if(D[214][j].charCodeAt(0) !== 0xFFFD) { e[D[214][j]] = 54784 + j; d[54784 + j] = D[214][j];} +D[215] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������住注祝驻抓爪拽专砖转撰赚篆桩庄装妆撞壮状椎锥追赘坠缀谆准捉拙卓桌琢茁酌啄着灼浊兹咨资姿滋淄孜紫仔籽滓子自渍字鬃棕踪宗综总纵邹走奏揍租足卒族祖诅阻组钻纂嘴醉最罪尊遵昨左佐柞做作坐座������".split(""); +for(j = 0; j != D[215].length; ++j) if(D[215][j].charCodeAt(0) !== 0xFFFD) { e[D[215][j]] = 55040 + j; d[55040 + j] = D[215][j];} +D[216] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������亍丌兀丐廿卅丕亘丞鬲孬噩丨禺丿匕乇夭爻卮氐囟胤馗毓睾鼗丶亟鼐乜乩亓芈孛啬嘏仄厍厝厣厥厮靥赝匚叵匦匮匾赜卦卣刂刈刎刭刳刿剀剌剞剡剜蒯剽劂劁劐劓冂罔亻仃仉仂仨仡仫仞伛仳伢佤仵伥伧伉伫佞佧攸佚佝�".split(""); +for(j = 0; j != D[216].length; ++j) if(D[216][j].charCodeAt(0) !== 0xFFFD) { e[D[216][j]] = 55296 + j; d[55296 + j] = D[216][j];} +D[217] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������佟佗伲伽佶佴侑侉侃侏佾佻侪佼侬侔俦俨俪俅俚俣俜俑俟俸倩偌俳倬倏倮倭俾倜倌倥倨偾偃偕偈偎偬偻傥傧傩傺僖儆僭僬僦僮儇儋仝氽佘佥俎龠汆籴兮巽黉馘冁夔勹匍訇匐凫夙兕亠兖亳衮袤亵脔裒禀嬴蠃羸冫冱冽冼�".split(""); +for(j = 0; j != D[217].length; ++j) if(D[217][j].charCodeAt(0) !== 0xFFFD) { e[D[217][j]] = 55552 + j; d[55552 + j] = D[217][j];} +D[218] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������凇冖冢冥讠讦讧讪讴讵讷诂诃诋诏诎诒诓诔诖诘诙诜诟诠诤诨诩诮诰诳诶诹诼诿谀谂谄谇谌谏谑谒谔谕谖谙谛谘谝谟谠谡谥谧谪谫谮谯谲谳谵谶卩卺阝阢阡阱阪阽阼陂陉陔陟陧陬陲陴隈隍隗隰邗邛邝邙邬邡邴邳邶邺�".split(""); +for(j = 0; j != D[218].length; ++j) if(D[218][j].charCodeAt(0) !== 0xFFFD) { e[D[218][j]] = 55808 + j; d[55808 + j] = D[218][j];} +D[219] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������邸邰郏郅邾郐郄郇郓郦郢郜郗郛郫郯郾鄄鄢鄞鄣鄱鄯鄹酃酆刍奂劢劬劭劾哿勐勖勰叟燮矍廴凵凼鬯厶弁畚巯坌垩垡塾墼壅壑圩圬圪圳圹圮圯坜圻坂坩垅坫垆坼坻坨坭坶坳垭垤垌垲埏垧垴垓垠埕埘埚埙埒垸埴埯埸埤埝�".split(""); +for(j = 0; j != D[219].length; ++j) if(D[219][j].charCodeAt(0) !== 0xFFFD) { e[D[219][j]] = 56064 + j; d[56064 + j] = D[219][j];} +D[220] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������堋堍埽埭堀堞堙塄堠塥塬墁墉墚墀馨鼙懿艹艽艿芏芊芨芄芎芑芗芙芫芸芾芰苈苊苣芘芷芮苋苌苁芩芴芡芪芟苄苎芤苡茉苷苤茏茇苜苴苒苘茌苻苓茑茚茆茔茕苠苕茜荑荛荜茈莒茼茴茱莛荞茯荏荇荃荟荀茗荠茭茺茳荦荥�".split(""); +for(j = 0; j != D[220].length; ++j) if(D[220][j].charCodeAt(0) !== 0xFFFD) { e[D[220][j]] = 56320 + j; d[56320 + j] = D[220][j];} +D[221] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������荨茛荩荬荪荭荮莰荸莳莴莠莪莓莜莅荼莶莩荽莸荻莘莞莨莺莼菁萁菥菘堇萘萋菝菽菖萜萸萑萆菔菟萏萃菸菹菪菅菀萦菰菡葜葑葚葙葳蒇蒈葺蒉葸萼葆葩葶蒌蒎萱葭蓁蓍蓐蓦蒽蓓蓊蒿蒺蓠蒡蒹蒴蒗蓥蓣蔌甍蔸蓰蔹蔟蔺�".split(""); +for(j = 0; j != D[221].length; ++j) if(D[221][j].charCodeAt(0) !== 0xFFFD) { e[D[221][j]] = 56576 + j; d[56576 + j] = D[221][j];} +D[222] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������蕖蔻蓿蓼蕙蕈蕨蕤蕞蕺瞢蕃蕲蕻薤薨薇薏蕹薮薜薅薹薷薰藓藁藜藿蘧蘅蘩蘖蘼廾弈夼奁耷奕奚奘匏尢尥尬尴扌扪抟抻拊拚拗拮挢拶挹捋捃掭揶捱捺掎掴捭掬掊捩掮掼揲揸揠揿揄揞揎摒揆掾摅摁搋搛搠搌搦搡摞撄摭撖�".split(""); +for(j = 0; j != D[222].length; ++j) if(D[222][j].charCodeAt(0) !== 0xFFFD) { e[D[222][j]] = 56832 + j; d[56832 + j] = D[222][j];} +D[223] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������摺撷撸撙撺擀擐擗擤擢攉攥攮弋忒甙弑卟叱叽叩叨叻吒吖吆呋呒呓呔呖呃吡呗呙吣吲咂咔呷呱呤咚咛咄呶呦咝哐咭哂咴哒咧咦哓哔呲咣哕咻咿哌哙哚哜咩咪咤哝哏哞唛哧唠哽唔哳唢唣唏唑唧唪啧喏喵啉啭啁啕唿啐唼�".split(""); +for(j = 0; j != D[223].length; ++j) if(D[223][j].charCodeAt(0) !== 0xFFFD) { e[D[223][j]] = 57088 + j; d[57088 + j] = D[223][j];} +D[224] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������唷啖啵啶啷唳唰啜喋嗒喃喱喹喈喁喟啾嗖喑啻嗟喽喾喔喙嗪嗷嗉嘟嗑嗫嗬嗔嗦嗝嗄嗯嗥嗲嗳嗌嗍嗨嗵嗤辔嘞嘈嘌嘁嘤嘣嗾嘀嘧嘭噘嘹噗嘬噍噢噙噜噌噔嚆噤噱噫噻噼嚅嚓嚯囔囗囝囡囵囫囹囿圄圊圉圜帏帙帔帑帱帻帼�".split(""); +for(j = 0; j != D[224].length; ++j) if(D[224][j].charCodeAt(0) !== 0xFFFD) { e[D[224][j]] = 57344 + j; d[57344 + j] = D[224][j];} +D[225] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������帷幄幔幛幞幡岌屺岍岐岖岈岘岙岑岚岜岵岢岽岬岫岱岣峁岷峄峒峤峋峥崂崃崧崦崮崤崞崆崛嵘崾崴崽嵬嵛嵯嵝嵫嵋嵊嵩嵴嶂嶙嶝豳嶷巅彳彷徂徇徉後徕徙徜徨徭徵徼衢彡犭犰犴犷犸狃狁狎狍狒狨狯狩狲狴狷猁狳猃狺�".split(""); +for(j = 0; j != D[225].length; ++j) if(D[225][j].charCodeAt(0) !== 0xFFFD) { e[D[225][j]] = 57600 + j; d[57600 + j] = D[225][j];} +D[226] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������狻猗猓猡猊猞猝猕猢猹猥猬猸猱獐獍獗獠獬獯獾舛夥飧夤夂饣饧饨饩饪饫饬饴饷饽馀馄馇馊馍馐馑馓馔馕庀庑庋庖庥庠庹庵庾庳赓廒廑廛廨廪膺忄忉忖忏怃忮怄忡忤忾怅怆忪忭忸怙怵怦怛怏怍怩怫怊怿怡恸恹恻恺恂�".split(""); +for(j = 0; j != D[226].length; ++j) if(D[226][j].charCodeAt(0) !== 0xFFFD) { e[D[226][j]] = 57856 + j; d[57856 + j] = D[226][j];} +D[227] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������恪恽悖悚悭悝悃悒悌悛惬悻悱惝惘惆惚悴愠愦愕愣惴愀愎愫慊慵憬憔憧憷懔懵忝隳闩闫闱闳闵闶闼闾阃阄阆阈阊阋阌阍阏阒阕阖阗阙阚丬爿戕氵汔汜汊沣沅沐沔沌汨汩汴汶沆沩泐泔沭泷泸泱泗沲泠泖泺泫泮沱泓泯泾�".split(""); +for(j = 0; j != D[227].length; ++j) if(D[227][j].charCodeAt(0) !== 0xFFFD) { e[D[227][j]] = 58112 + j; d[58112 + j] = D[227][j];} +D[228] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������洹洧洌浃浈洇洄洙洎洫浍洮洵洚浏浒浔洳涑浯涞涠浞涓涔浜浠浼浣渚淇淅淞渎涿淠渑淦淝淙渖涫渌涮渫湮湎湫溲湟溆湓湔渲渥湄滟溱溘滠漭滢溥溧溽溻溷滗溴滏溏滂溟潢潆潇漤漕滹漯漶潋潴漪漉漩澉澍澌潸潲潼潺濑�".split(""); +for(j = 0; j != D[228].length; ++j) if(D[228][j].charCodeAt(0) !== 0xFFFD) { e[D[228][j]] = 58368 + j; d[58368 + j] = D[228][j];} +D[229] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������濉澧澹澶濂濡濮濞濠濯瀚瀣瀛瀹瀵灏灞宀宄宕宓宥宸甯骞搴寤寮褰寰蹇謇辶迓迕迥迮迤迩迦迳迨逅逄逋逦逑逍逖逡逵逶逭逯遄遑遒遐遨遘遢遛暹遴遽邂邈邃邋彐彗彖彘尻咫屐屙孱屣屦羼弪弩弭艴弼鬻屮妁妃妍妩妪妣�".split(""); +for(j = 0; j != D[229].length; ++j) if(D[229][j].charCodeAt(0) !== 0xFFFD) { e[D[229][j]] = 58624 + j; d[58624 + j] = D[229][j];} +D[230] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������妗姊妫妞妤姒妲妯姗妾娅娆姝娈姣姘姹娌娉娲娴娑娣娓婀婧婊婕娼婢婵胬媪媛婷婺媾嫫媲嫒嫔媸嫠嫣嫱嫖嫦嫘嫜嬉嬗嬖嬲嬷孀尕尜孚孥孳孑孓孢驵驷驸驺驿驽骀骁骅骈骊骐骒骓骖骘骛骜骝骟骠骢骣骥骧纟纡纣纥纨纩�".split(""); +for(j = 0; j != D[230].length; ++j) if(D[230][j].charCodeAt(0) !== 0xFFFD) { e[D[230][j]] = 58880 + j; d[58880 + j] = D[230][j];} +D[231] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������纭纰纾绀绁绂绉绋绌绐绔绗绛绠绡绨绫绮绯绱绲缍绶绺绻绾缁缂缃缇缈缋缌缏缑缒缗缙缜缛缟缡缢缣缤缥缦缧缪缫缬缭缯缰缱缲缳缵幺畿巛甾邕玎玑玮玢玟珏珂珑玷玳珀珉珈珥珙顼琊珩珧珞玺珲琏琪瑛琦琥琨琰琮琬�".split(""); +for(j = 0; j != D[231].length; ++j) if(D[231][j].charCodeAt(0) !== 0xFFFD) { e[D[231][j]] = 59136 + j; d[59136 + j] = D[231][j];} +D[232] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������琛琚瑁瑜瑗瑕瑙瑷瑭瑾璜璎璀璁璇璋璞璨璩璐璧瓒璺韪韫韬杌杓杞杈杩枥枇杪杳枘枧杵枨枞枭枋杷杼柰栉柘栊柩枰栌柙枵柚枳柝栀柃枸柢栎柁柽栲栳桠桡桎桢桄桤梃栝桕桦桁桧桀栾桊桉栩梵梏桴桷梓桫棂楮棼椟椠棹�".split(""); +for(j = 0; j != D[232].length; ++j) if(D[232][j].charCodeAt(0) !== 0xFFFD) { e[D[232][j]] = 59392 + j; d[59392 + j] = D[232][j];} +D[233] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������椤棰椋椁楗棣椐楱椹楠楂楝榄楫榀榘楸椴槌榇榈槎榉楦楣楹榛榧榻榫榭槔榱槁槊槟榕槠榍槿樯槭樗樘橥槲橄樾檠橐橛樵檎橹樽樨橘橼檑檐檩檗檫猷獒殁殂殇殄殒殓殍殚殛殡殪轫轭轱轲轳轵轶轸轷轹轺轼轾辁辂辄辇辋�".split(""); +for(j = 0; j != D[233].length; ++j) if(D[233][j].charCodeAt(0) !== 0xFFFD) { e[D[233][j]] = 59648 + j; d[59648 + j] = D[233][j];} +D[234] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������辍辎辏辘辚軎戋戗戛戟戢戡戥戤戬臧瓯瓴瓿甏甑甓攴旮旯旰昊昙杲昃昕昀炅曷昝昴昱昶昵耆晟晔晁晏晖晡晗晷暄暌暧暝暾曛曜曦曩贲贳贶贻贽赀赅赆赈赉赇赍赕赙觇觊觋觌觎觏觐觑牮犟牝牦牯牾牿犄犋犍犏犒挈挲掰�".split(""); +for(j = 0; j != D[234].length; ++j) if(D[234][j].charCodeAt(0) !== 0xFFFD) { e[D[234][j]] = 59904 + j; d[59904 + j] = D[234][j];} +D[235] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������搿擘耄毪毳毽毵毹氅氇氆氍氕氘氙氚氡氩氤氪氲攵敕敫牍牒牖爰虢刖肟肜肓肼朊肽肱肫肭肴肷胧胨胩胪胛胂胄胙胍胗朐胝胫胱胴胭脍脎胲胼朕脒豚脶脞脬脘脲腈腌腓腴腙腚腱腠腩腼腽腭腧塍媵膈膂膑滕膣膪臌朦臊膻�".split(""); +for(j = 0; j != D[235].length; ++j) if(D[235][j].charCodeAt(0) !== 0xFFFD) { e[D[235][j]] = 60160 + j; d[60160 + j] = D[235][j];} +D[236] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������臁膦欤欷欹歃歆歙飑飒飓飕飙飚殳彀毂觳斐齑斓於旆旄旃旌旎旒旖炀炜炖炝炻烀炷炫炱烨烊焐焓焖焯焱煳煜煨煅煲煊煸煺熘熳熵熨熠燠燔燧燹爝爨灬焘煦熹戾戽扃扈扉礻祀祆祉祛祜祓祚祢祗祠祯祧祺禅禊禚禧禳忑忐�".split(""); +for(j = 0; j != D[236].length; ++j) if(D[236][j].charCodeAt(0) !== 0xFFFD) { e[D[236][j]] = 60416 + j; d[60416 + j] = D[236][j];} +D[237] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������怼恝恚恧恁恙恣悫愆愍慝憩憝懋懑戆肀聿沓泶淼矶矸砀砉砗砘砑斫砭砜砝砹砺砻砟砼砥砬砣砩硎硭硖硗砦硐硇硌硪碛碓碚碇碜碡碣碲碹碥磔磙磉磬磲礅磴礓礤礞礴龛黹黻黼盱眄眍盹眇眈眚眢眙眭眦眵眸睐睑睇睃睚睨�".split(""); +for(j = 0; j != D[237].length; ++j) if(D[237][j].charCodeAt(0) !== 0xFFFD) { e[D[237][j]] = 60672 + j; d[60672 + j] = D[237][j];} +D[238] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������睢睥睿瞍睽瞀瞌瞑瞟瞠瞰瞵瞽町畀畎畋畈畛畲畹疃罘罡罟詈罨罴罱罹羁罾盍盥蠲钅钆钇钋钊钌钍钏钐钔钗钕钚钛钜钣钤钫钪钭钬钯钰钲钴钶钷钸钹钺钼钽钿铄铈铉铊铋铌铍铎铐铑铒铕铖铗铙铘铛铞铟铠铢铤铥铧铨铪�".split(""); +for(j = 0; j != D[238].length; ++j) if(D[238][j].charCodeAt(0) !== 0xFFFD) { e[D[238][j]] = 60928 + j; d[60928 + j] = D[238][j];} +D[239] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������铩铫铮铯铳铴铵铷铹铼铽铿锃锂锆锇锉锊锍锎锏锒锓锔锕锖锘锛锝锞锟锢锪锫锩锬锱锲锴锶锷锸锼锾锿镂锵镄镅镆镉镌镎镏镒镓镔镖镗镘镙镛镞镟镝镡镢镤镥镦镧镨镩镪镫镬镯镱镲镳锺矧矬雉秕秭秣秫稆嵇稃稂稞稔�".split(""); +for(j = 0; j != D[239].length; ++j) if(D[239][j].charCodeAt(0) !== 0xFFFD) { e[D[239][j]] = 61184 + j; d[61184 + j] = D[239][j];} +D[240] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������稹稷穑黏馥穰皈皎皓皙皤瓞瓠甬鸠鸢鸨鸩鸪鸫鸬鸲鸱鸶鸸鸷鸹鸺鸾鹁鹂鹄鹆鹇鹈鹉鹋鹌鹎鹑鹕鹗鹚鹛鹜鹞鹣鹦鹧鹨鹩鹪鹫鹬鹱鹭鹳疒疔疖疠疝疬疣疳疴疸痄疱疰痃痂痖痍痣痨痦痤痫痧瘃痱痼痿瘐瘀瘅瘌瘗瘊瘥瘘瘕瘙�".split(""); +for(j = 0; j != D[240].length; ++j) if(D[240][j].charCodeAt(0) !== 0xFFFD) { e[D[240][j]] = 61440 + j; d[61440 + j] = D[240][j];} +D[241] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������瘛瘼瘢瘠癀瘭瘰瘿瘵癃瘾瘳癍癞癔癜癖癫癯翊竦穸穹窀窆窈窕窦窠窬窨窭窳衤衩衲衽衿袂袢裆袷袼裉裢裎裣裥裱褚裼裨裾裰褡褙褓褛褊褴褫褶襁襦襻疋胥皲皴矜耒耔耖耜耠耢耥耦耧耩耨耱耋耵聃聆聍聒聩聱覃顸颀颃�".split(""); +for(j = 0; j != D[241].length; ++j) if(D[241][j].charCodeAt(0) !== 0xFFFD) { e[D[241][j]] = 61696 + j; d[61696 + j] = D[241][j];} +D[242] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������颉颌颍颏颔颚颛颞颟颡颢颥颦虍虔虬虮虿虺虼虻蚨蚍蚋蚬蚝蚧蚣蚪蚓蚩蚶蛄蚵蛎蚰蚺蚱蚯蛉蛏蚴蛩蛱蛲蛭蛳蛐蜓蛞蛴蛟蛘蛑蜃蜇蛸蜈蜊蜍蜉蜣蜻蜞蜥蜮蜚蜾蝈蜴蜱蜩蜷蜿螂蜢蝽蝾蝻蝠蝰蝌蝮螋蝓蝣蝼蝤蝙蝥螓螯螨蟒�".split(""); +for(j = 0; j != D[242].length; ++j) if(D[242][j].charCodeAt(0) !== 0xFFFD) { e[D[242][j]] = 61952 + j; d[61952 + j] = D[242][j];} +D[243] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������蟆螈螅螭螗螃螫蟥螬螵螳蟋蟓螽蟑蟀蟊蟛蟪蟠蟮蠖蠓蟾蠊蠛蠡蠹蠼缶罂罄罅舐竺竽笈笃笄笕笊笫笏筇笸笪笙笮笱笠笥笤笳笾笞筘筚筅筵筌筝筠筮筻筢筲筱箐箦箧箸箬箝箨箅箪箜箢箫箴篑篁篌篝篚篥篦篪簌篾篼簏簖簋�".split(""); +for(j = 0; j != D[243].length; ++j) if(D[243][j].charCodeAt(0) !== 0xFFFD) { e[D[243][j]] = 62208 + j; d[62208 + j] = D[243][j];} +D[244] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������簟簪簦簸籁籀臾舁舂舄臬衄舡舢舣舭舯舨舫舸舻舳舴舾艄艉艋艏艚艟艨衾袅袈裘裟襞羝羟羧羯羰羲籼敉粑粝粜粞粢粲粼粽糁糇糌糍糈糅糗糨艮暨羿翎翕翥翡翦翩翮翳糸絷綦綮繇纛麸麴赳趄趔趑趱赧赭豇豉酊酐酎酏酤�".split(""); +for(j = 0; j != D[244].length; ++j) if(D[244][j].charCodeAt(0) !== 0xFFFD) { e[D[244][j]] = 62464 + j; d[62464 + j] = D[244][j];} +D[245] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������酢酡酰酩酯酽酾酲酴酹醌醅醐醍醑醢醣醪醭醮醯醵醴醺豕鹾趸跫踅蹙蹩趵趿趼趺跄跖跗跚跞跎跏跛跆跬跷跸跣跹跻跤踉跽踔踝踟踬踮踣踯踺蹀踹踵踽踱蹉蹁蹂蹑蹒蹊蹰蹶蹼蹯蹴躅躏躔躐躜躞豸貂貊貅貘貔斛觖觞觚觜�".split(""); +for(j = 0; j != D[245].length; ++j) if(D[245][j].charCodeAt(0) !== 0xFFFD) { e[D[245][j]] = 62720 + j; d[62720 + j] = D[245][j];} +D[246] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������觥觫觯訾謦靓雩雳雯霆霁霈霏霎霪霭霰霾龀龃龅龆龇龈龉龊龌黾鼋鼍隹隼隽雎雒瞿雠銎銮鋈錾鍪鏊鎏鐾鑫鱿鲂鲅鲆鲇鲈稣鲋鲎鲐鲑鲒鲔鲕鲚鲛鲞鲟鲠鲡鲢鲣鲥鲦鲧鲨鲩鲫鲭鲮鲰鲱鲲鲳鲴鲵鲶鲷鲺鲻鲼鲽鳄鳅鳆鳇鳊鳋�".split(""); +for(j = 0; j != D[246].length; ++j) if(D[246][j].charCodeAt(0) !== 0xFFFD) { e[D[246][j]] = 62976 + j; d[62976 + j] = D[246][j];} +D[247] = "�����������������������������������������������������������������������������������������������������������������������������������������������������������������鳌鳍鳎鳏鳐鳓鳔鳕鳗鳘鳙鳜鳝鳟鳢靼鞅鞑鞒鞔鞯鞫鞣鞲鞴骱骰骷鹘骶骺骼髁髀髅髂髋髌髑魅魃魇魉魈魍魑飨餍餮饕饔髟髡髦髯髫髻髭髹鬈鬏鬓鬟鬣麽麾縻麂麇麈麋麒鏖麝麟黛黜黝黠黟黢黩黧黥黪黯鼢鼬鼯鼹鼷鼽鼾齄�".split(""); +for(j = 0; j != D[247].length; ++j) if(D[247][j].charCodeAt(0) !== 0xFFFD) { e[D[247][j]] = 63232 + j; d[63232 + j] = D[247][j];} +return {"enc": e, "dec": d }; })(); +cptable[10029] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÄĀāÉĄÖÜáąČäčĆć鏟ĎíďĒēĖóėôöõúĚěü†°Ę£§•¶ß®©™ę¨≠ģĮįĪ≤≥īĶ∂∑łĻļĽľĹĺŅņѬ√ńŇ∆«»… ňŐÕőŌ–—“”‘’÷◊ōŔŕŘ‹›řŖŗŠ‚„šŚśÁŤťÍŽžŪÓÔūŮÚůŰűŲųÝýķŻŁżĢˇ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[10079] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûüݰ¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤ÐðÞþý·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[10081] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸĞğİıŞş‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙ�ˆ˜¯˘˙˚¸˝˛ˇ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +cptable[28591] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); +// eslint-disable-next-line no-undef +if (typeof module !== 'undefined' && module.exports && typeof DO_NOT_EXPORT_CODEPAGE === 'undefined') module.exports = cptable; +/*! cputils.js (C) 2013-present SheetJS -- http://sheetjs.com */ +/* vim: set ft=javascript: */ +/*jshint newcap: false */ +(function(root, factory) { + /*jshint ignore:start */ + /*eslint-disable */ + "use strict"; + if(typeof cptable === "undefined") { + if(typeof require !== "undefined"){ + var cpt = cptable; + if (typeof module !== 'undefined' && module.exports && typeof DO_NOT_EXPORT_CODEPAGE === 'undefined') module.exports = factory(cpt); + else root.cptable = factory(cpt); + } else throw new Error("cptable not found"); + } else cptable = factory(cptable); + /*eslint-enable */ + /*jshint ignore:end */ +}(this, function(cpt){ + "use strict"; + /*global module, Buffer */ + var magic = { + "1200":"utf16le", + "1201":"utf16be", + "12000":"utf32le", + "12001":"utf32be", + "16969":"utf64le", + "20127":"ascii", + "65000":"utf7", + "65001":"utf8" + }; + + var sbcs_cache = [874,1250,1251,1252,1253,1254,1255,1256,10000]; + var dbcs_cache = [932,936,949,950]; + var magic_cache = [65001]; + var magic_decode = {}; + var magic_encode = {}; + var cpdcache = {}; + var cpecache = {}; + + var sfcc = function sfcc(x) { return String.fromCharCode(x); }; + var cca = function cca(x) { return x.charCodeAt(0); }; + + var has_buf = (typeof Buffer !== 'undefined'); + var Buffer_from = function(){}; + if(has_buf) { + var nbfs = !Buffer.from; + if(!nbfs) try { Buffer.from("foo", "utf8"); } catch(e) { nbfs = true; } + Buffer_from = nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer); + // $FlowIgnore + if(!Buffer.allocUnsafe) Buffer.allocUnsafe = function(n) { return new Buffer(n); }; + + var mdl = 1024, mdb = Buffer.allocUnsafe(mdl); + var make_EE = function make_EE(E){ + var EE = Buffer.allocUnsafe(65536); + for(var i = 0; i < 65536;++i) EE[i] = 0; + var keys = Object.keys(E), len = keys.length; + for(var ee = 0, e = keys[ee]; ee < len; ++ee) { + if(!(e = keys[ee])) continue; + EE[e.charCodeAt(0)] = E[e]; + } + return EE; + }; + var sbcs_encode = function make_sbcs_encode(cp) { + var EE = make_EE(cpt[cp].enc); + return function sbcs_e(data, ofmt) { + var len = data.length; + var out, i=0, j=0, D=0, w=0; + if(typeof data === 'string') { + out = Buffer.allocUnsafe(len); + for(i = 0; i < len; ++i) out[i] = EE[data.charCodeAt(i)]; + } else if(Buffer.isBuffer(data)) { + out = Buffer.allocUnsafe(2*len); + j = 0; + for(i = 0; i < len; ++i) { + D = data[i]; + if(D < 128) out[j++] = EE[D]; + else if(D < 224) { out[j++] = EE[((D&31)<<6)+(data[i+1]&63)]; ++i; } + else if(D < 240) { out[j++] = EE[((D&15)<<12)+((data[i+1]&63)<<6)+(data[i+2]&63)]; i+=2; } + else { + w = ((D&7)<<18)+((data[i+1]&63)<<12)+((data[i+2]&63)<<6)+(data[i+3]&63); i+=3; + if(w < 65536) out[j++] = EE[w]; + else { w -= 65536; out[j++] = EE[0xD800 + ((w>>10)&1023)]; out[j++] = EE[0xDC00 + (w&1023)]; } + } + } + out = out.slice(0,j); + } else { + out = Buffer.allocUnsafe(len); + for(i = 0; i < len; ++i) out[i] = EE[data[i].charCodeAt(0)]; + } + if(!ofmt || ofmt === 'buf') return out; + if(ofmt !== 'arr') return out.toString('binary'); + return [].slice.call(out); + }; + }; + var sbcs_decode = function make_sbcs_decode(cp) { + var D = cpt[cp].dec; + var DD = Buffer.allocUnsafe(131072), d=0, c=""; + for(d=0;d>8; + } + return function sbcs_d(data) { + var len = data.length, i=0, j=0; + if(2 * len > mdl) { mdl = 2 * len; mdb = Buffer.allocUnsafe(mdl); } + if(Buffer.isBuffer(data)) { + for(i = 0; i < len; i++) { + j = 2*data[i]; + mdb[2*i] = DD[j]; mdb[2*i+1] = DD[j+1]; + } + } else if(typeof data === "string") { + for(i = 0; i < len; i++) { + j = 2*data.charCodeAt(i); + mdb[2*i] = DD[j]; mdb[2*i+1] = DD[j+1]; + } + } else { + for(i = 0; i < len; i++) { + j = 2*data[i]; + mdb[2*i] = DD[j]; mdb[2*i+1] = DD[j+1]; + } + } + return mdb.slice(0, 2 * len).toString('ucs2'); + }; + }; + var dbcs_encode = function make_dbcs_encode(cp) { + var E = cpt[cp].enc; + var EE = Buffer.allocUnsafe(131072); + for(var i = 0; i < 131072; ++i) EE[i] = 0; + var keys = Object.keys(E); + for(var ee = 0, e = keys[ee]; ee < keys.length; ++ee) { + if(!(e = keys[ee])) continue; + var f = e.charCodeAt(0); + EE[2*f] = E[e] & 255; EE[2*f+1] = E[e]>>8; + } + return function dbcs_e(data, ofmt) { + var len = data.length, out = Buffer.allocUnsafe(2*len), i=0, j=0, jj=0, k=0, D=0; + if(typeof data === 'string') { + for(i = k = 0; i < len; ++i) { + j = data.charCodeAt(i)*2; + out[k++] = EE[j+1] || EE[j]; if(EE[j+1] > 0) out[k++] = EE[j]; + } + out = out.slice(0,k); + } else if(Buffer.isBuffer(data)) { + for(i = k = 0; i < len; ++i) { + D = data[i]; + if(D < 128) j = D; + else if(D < 224) { j = ((D&31)<<6)+(data[i+1]&63); ++i; } + else if(D < 240) { j = ((D&15)<<12)+((data[i+1]&63)<<6)+(data[i+2]&63); i+=2; } + else { j = ((D&7)<<18)+((data[i+1]&63)<<12)+((data[i+2]&63)<<6)+(data[i+3]&63); i+=3; } + if(j<65536) { j*=2; out[k++] = EE[j+1] || EE[j]; if(EE[j+1] > 0) out[k++] = EE[j]; } + else { jj = j-65536; + j=2*(0xD800 + ((jj>>10)&1023)); out[k++] = EE[j+1] || EE[j]; if(EE[j+1] > 0) out[k++] = EE[j]; + j=2*(0xDC00 + (jj&1023)); out[k++] = EE[j+1] || EE[j]; if(EE[j+1] > 0) out[k++] = EE[j]; + } + } + out = out.slice(0,k); + } else { + for(i = k = 0; i < len; i++) { + j = data[i].charCodeAt(0)*2; + out[k++] = EE[j+1] || EE[j]; if(EE[j+1] > 0) out[k++] = EE[j]; + } + } + if(!ofmt || ofmt === 'buf') return out; + if(ofmt !== 'arr') return out.toString('binary'); + return [].slice.call(out); + }; + }; + var dbcs_decode = function make_dbcs_decode(cp) { + var D = cpt[cp].dec; + var DD = Buffer.allocUnsafe(131072), d=0, c, w=0, j=0, i=0; + for(i = 0; i < 65536; ++i) { DD[2*i] = 0xFF; DD[2*i+1] = 0xFD;} + for(d = 0; d < D.length; ++d) { + if(!(c=D[d])) continue; + w = c.charCodeAt(0); + j = 2*d; + DD[j] = w&255; DD[j+1] = w>>8; + } + return function dbcs_d(data) { + var len = data.length, out = Buffer.allocUnsafe(2*len), i=0, j=0, k=0; + if(Buffer.isBuffer(data)) { + for(i = 0; i < len; i++) { + j = 2*data[i]; + if(DD[j]===0xFF && DD[j+1]===0xFD) { j=2*((data[i]<<8)+data[i+1]); ++i; } + out[k++] = DD[j]; out[k++] = DD[j+1]; + } + } else if(typeof data === "string") { + for(i = 0; i < len; i++) { + j = 2*data.charCodeAt(i); + if(DD[j]===0xFF && DD[j+1]===0xFD) { j=2*((data.charCodeAt(i)<<8)+data.charCodeAt(i+1)); ++i; } + out[k++] = DD[j]; out[k++] = DD[j+1]; + } + } else { + for(i = 0; i < len; i++) { + j = 2*data[i]; + if(DD[j]===0xFF && DD[j+1]===0xFD) { j=2*((data[i]<<8)+data[i+1]); ++i; } + out[k++] = DD[j]; out[k++] = DD[j+1]; + } + } + return out.slice(0,k).toString('ucs2'); + }; + }; + magic_decode[65001] = function utf8_d(data) { + if(typeof data === "string") return utf8_d(data.split("").map(cca)); + var len = data.length, w = 0, ww = 0; + if(4 * len > mdl) { mdl = 4 * len; mdb = Buffer.allocUnsafe(mdl); } + var i = 0; + if(len >= 3 && data[0] == 0xEF) if(data[1] == 0xBB && data[2] == 0xBF) i = 3; + for(var j = 1, k = 0, D = 0; i < len; i+=j) { + j = 1; D = data[i]; + if(D < 128) w = D; + else if(D < 224) { w=(D&31)*64+(data[i+1]&63); j=2; } + else if(D < 240) { w=((D&15)<<12)+(data[i+1]&63)*64+(data[i+2]&63); j=3; } + else { w=(D&7)*262144+((data[i+1]&63)<<12)+(data[i+2]&63)*64+(data[i+3]&63); j=4; } + if(w < 65536) { mdb[k++] = w&255; mdb[k++] = w>>8; } + else { + w -= 65536; ww = 0xD800 + ((w>>10)&1023); w = 0xDC00 + (w&1023); + mdb[k++] = ww&255; mdb[k++] = ww>>>8; mdb[k++] = w&255; mdb[k++] = (w>>>8)&255; + } + } + return mdb.slice(0,k).toString('ucs2'); + }; + magic_encode[65001] = function utf8_e(data, ofmt) { + if(has_buf && Buffer.isBuffer(data)) { + if(!ofmt || ofmt === 'buf') return data; + if(ofmt !== 'arr') return data.toString('binary'); + return [].slice.call(data); + } + var len = data.length, w = 0, ww = 0, j = 0; + var direct = typeof data === "string"; + if(4 * len > mdl) { mdl = 4 * len; mdb = Buffer.allocUnsafe(mdl); } + for(var i = 0; i < len; ++i) { + w = direct ? data.charCodeAt(i) : data[i].charCodeAt(0); + if(w <= 0x007F) mdb[j++] = w; + else if(w <= 0x07FF) { + mdb[j++] = 192 + (w >> 6); + mdb[j++] = 128 + (w&63); + } else if(w >= 0xD800 && w <= 0xDFFF) { + w -= 0xD800; ++i; + ww = (direct ? data.charCodeAt(i) : data[i].charCodeAt(0)) - 0xDC00 + (w << 10); + mdb[j++] = 240 + ((ww>>>18) & 0x07); + mdb[j++] = 144 + ((ww>>>12) & 0x3F); + mdb[j++] = 128 + ((ww>>>6) & 0x3F); + mdb[j++] = 128 + (ww & 0x3F); + } else { + mdb[j++] = 224 + (w >> 12); + mdb[j++] = 128 + ((w >> 6)&63); + mdb[j++] = 128 + (w&63); + } + } + if(!ofmt || ofmt === 'buf') return mdb.slice(0,j); + if(ofmt !== 'arr') return mdb.slice(0,j).toString('binary'); + return [].slice.call(mdb, 0, j); + }; + } + + var encache = function encache() { + if(has_buf) { + if(cpdcache[sbcs_cache[0]]) return; + var i=0, s=0; + for(i = 0; i < sbcs_cache.length; ++i) { + s = sbcs_cache[i]; + if(cpt[s]) { + cpdcache[s] = sbcs_decode(s); + cpecache[s] = sbcs_encode(s); + } + } + for(i = 0; i < dbcs_cache.length; ++i) { + s = dbcs_cache[i]; + if(cpt[s]) { + cpdcache[s] = dbcs_decode(s); + cpecache[s] = dbcs_encode(s); + } + } + for(i = 0; i < magic_cache.length; ++i) { + s = magic_cache[i]; + if(magic_decode[s]) cpdcache[s] = magic_decode[s]; + if(magic_encode[s]) cpecache[s] = magic_encode[s]; + } + } + }; + var null_enc = function(data, ofmt) { void ofmt; return ""; }; + var cp_decache = function cp_decache(cp) { delete cpdcache[cp]; delete cpecache[cp]; }; + var decache = function decache() { + if(has_buf) { + if(!cpdcache[sbcs_cache[0]]) return; + sbcs_cache.forEach(cp_decache); + dbcs_cache.forEach(cp_decache); + magic_cache.forEach(cp_decache); + } + last_enc = null_enc; last_cp = 0; + }; + var cache = { + encache: encache, + decache: decache, + sbcs: sbcs_cache, + dbcs: dbcs_cache + }; + + encache(); + + var BM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var SetD = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'(),-./:?"; + var last_enc = null_enc, last_cp = 0; + var encode = function encode(cp, data, ofmt) { + if(cp === last_cp && last_enc) { return last_enc(data, ofmt); } + if(cpecache[cp]) { last_enc = cpecache[last_cp=cp]; return last_enc(data, ofmt); } + if(has_buf && Buffer.isBuffer(data)) data = data.toString('utf8'); + var len = data.length; + var out = has_buf ? Buffer.allocUnsafe(4*len) : [], w=0, i=0, j = 0, ww=0; + var C = cpt[cp], E, M = ""; + var isstr = typeof data === 'string'; + if(C && (E=C.enc)) for(i = 0; i < len; ++i, ++j) { + w = E[isstr? data.charAt(i) : data[i]]; + if(w > 255) { + out[j] = w>>8; + out[++j] = w&255; + } else out[j] = w&255; + } + else if((M=magic[cp])) switch(M) { + case "utf8": + if(has_buf && isstr) { out = Buffer_from(data, M); j = out.length; break; } + for(i = 0; i < len; ++i, ++j) { + w = isstr ? data.charCodeAt(i) : data[i].charCodeAt(0); + if(w <= 0x007F) out[j] = w; + else if(w <= 0x07FF) { + out[j] = 192 + (w >> 6); + out[++j] = 128 + (w&63); + } else if(w >= 0xD800 && w <= 0xDFFF) { + w -= 0xD800; + ww = (isstr ? data.charCodeAt(++i) : data[++i].charCodeAt(0)) - 0xDC00 + (w << 10); + out[j] = 240 + ((ww>>>18) & 0x07); + out[++j] = 144 + ((ww>>>12) & 0x3F); + out[++j] = 128 + ((ww>>>6) & 0x3F); + out[++j] = 128 + (ww & 0x3F); + } else { + out[j] = 224 + (w >> 12); + out[++j] = 128 + ((w >> 6)&63); + out[++j] = 128 + (w&63); + } + } + break; + case "ascii": + if(has_buf && typeof data === "string") { out = Buffer_from(data, M); j = out.length; break; } + for(i = 0; i < len; ++i, ++j) { + w = isstr ? data.charCodeAt(i) : data[i].charCodeAt(0); + if(w <= 0x007F) out[j] = w; + else throw new Error("bad ascii " + w); + } + break; + case "utf16le": + if(has_buf && typeof data === "string") { out = Buffer_from(data, M); j = out.length; break; } + for(i = 0; i < len; ++i) { + w = isstr ? data.charCodeAt(i) : data[i].charCodeAt(0); + out[j++] = w&255; + out[j++] = w>>8; + } + break; + case "utf16be": + for(i = 0; i < len; ++i) { + w = isstr ? data.charCodeAt(i) : data[i].charCodeAt(0); + out[j++] = w>>8; + out[j++] = w&255; + } + break; + case "utf32le": + for(i = 0; i < len; ++i) { + w = isstr ? data.charCodeAt(i) : data[i].charCodeAt(0); + if(w >= 0xD800 && w <= 0xDFFF) w = 0x10000 + ((w - 0xD800) << 10) + (data[++i].charCodeAt(0) - 0xDC00); + out[j++] = w&255; w >>= 8; + out[j++] = w&255; w >>= 8; + out[j++] = w&255; w >>= 8; + out[j++] = w&255; + } + break; + case "utf32be": + for(i = 0; i < len; ++i) { + w = isstr ? data.charCodeAt(i) : data[i].charCodeAt(0); + if(w >= 0xD800 && w <= 0xDFFF) w = 0x10000 + ((w - 0xD800) << 10) + (data[++i].charCodeAt(0) - 0xDC00); + out[j+3] = w&255; w >>= 8; + out[j+2] = w&255; w >>= 8; + out[j+1] = w&255; w >>= 8; + out[j] = w&255; + j+=4; + } + break; + case "utf7": + for(i = 0; i < len; i++) { + var c = isstr ? data.charAt(i) : data[i].charAt(0); + if(c === "+") { out[j++] = 0x2b; out[j++] = 0x2d; continue; } + if(SetD.indexOf(c) > -1) { out[j++] = c.charCodeAt(0); continue; } + var tt = encode(1201, c); + out[j++] = 0x2b; + out[j++] = BM.charCodeAt(tt[0]>>2); + out[j++] = BM.charCodeAt(((tt[0]&0x03)<<4) + ((tt[1]||0)>>4)); + out[j++] = BM.charCodeAt(((tt[1]&0x0F)<<2) + ((tt[2]||0)>>6)); + out[j++] = 0x2d; + } + break; + default: throw new Error("Unsupported magic: " + cp + " " + magic[cp]); + } + else throw new Error("Unrecognized CP: " + cp); + out = out.slice(0,j); + if(!has_buf) return (ofmt == 'str') ? (out).map(sfcc).join("") : out; + if(!ofmt || ofmt === 'buf') return out; + if(ofmt !== 'arr') return out.toString('binary'); + return [].slice.call(out); + }; + var decode = function decode(cp, data) { + var F; if((F=cpdcache[cp])) return F(data); + if(typeof data === "string") return decode(cp, data.split("").map(cca)); + var len = data.length, out = new Array(len), s="", w=0, i=0, j=1, k=0, ww=0; + var C = cpt[cp], D, M=""; + if(C && (D=C.dec)) { + for(i = 0; i < len; i+=j) { + j = 2; + s = D[(data[i]<<8)+ data[i+1]]; + if(!s) { + j = 1; + s = D[data[i]]; + } + if(!s) throw new Error('Unrecognized code: ' + data[i] + ' ' + data[i+j-1] + ' ' + i + ' ' + j + ' ' + D[data[i]]); + out[k++] = s; + } + } + else if((M=magic[cp])) switch(M) { + case "utf8": + if(len >= 3 && data[0] == 0xEF) if(data[1] == 0xBB && data[2] == 0xBF) i = 3; + for(; i < len; i+=j) { + j = 1; + if(data[i] < 128) w = data[i]; + else if(data[i] < 224) { w=(data[i]&31)*64+(data[i+1]&63); j=2; } + else if(data[i] < 240) { w=((data[i]&15)<<12)+(data[i+1]&63)*64+(data[i+2]&63); j=3; } + else { w=(data[i]&7)*262144+((data[i+1]&63)<<12)+(data[i+2]&63)*64+(data[i+3]&63); j=4; } + if(w < 65536) { out[k++] = String.fromCharCode(w); } + else { + w -= 65536; ww = 0xD800 + ((w>>10)&1023); w = 0xDC00 + (w&1023); + out[k++] = String.fromCharCode(ww); out[k++] = String.fromCharCode(w); + } + } + break; + case "ascii": + if(has_buf && Buffer.isBuffer(data)) return data.toString(M); + for(i = 0; i < len; i++) out[i] = String.fromCharCode(data[i]); + k = len; break; + case "utf16le": + if(len >= 2 && data[0] == 0xFF) if(data[1] == 0xFE) i = 2; + if(has_buf && Buffer.isBuffer(data)) return data.toString(M); + j = 2; + for(; i+1 < len; i+=j) { + out[k++] = String.fromCharCode((data[i+1]<<8) + data[i]); + } + break; + case "utf16be": + if(len >= 2 && data[0] == 0xFE) if(data[1] == 0xFF) i = 2; + j = 2; + for(; i+1 < len; i+=j) { + out[k++] = String.fromCharCode((data[i]<<8) + data[i+1]); + } + break; + case "utf32le": + if(len >= 4 && data[0] == 0xFF) if(data[1] == 0xFE && data[2] === 0 && data[3] === 0) i = 4; + j = 4; + for(; i < len; i+=j) { + w = (data[i+3]<<24) + (data[i+2]<<16) + (data[i+1]<<8) + (data[i]); + if(w > 0xFFFF) { + w -= 0x10000; + out[k++] = String.fromCharCode(0xD800 + ((w >> 10) & 0x3FF)); + out[k++] = String.fromCharCode(0xDC00 + (w & 0x3FF)); + } + else out[k++] = String.fromCharCode(w); + } + break; + case "utf32be": + if(len >= 4 && data[3] == 0xFF) if(data[2] == 0xFE && data[1] === 0 && data[0] === 0) i = 4; + j = 4; + for(; i < len; i+=j) { + w = (data[i]<<24) + (data[i+1]<<16) + (data[i+2]<<8) + (data[i+3]); + if(w > 0xFFFF) { + w -= 0x10000; + out[k++] = String.fromCharCode(0xD800 + ((w >> 10) & 0x3FF)); + out[k++] = String.fromCharCode(0xDC00 + (w & 0x3FF)); + } + else out[k++] = String.fromCharCode(w); + } + break; + case "utf7": + if(len >= 4 && data[0] == 0x2B && data[1] == 0x2F && data[2] == 0x76) { + if(len >= 5 && data[3] == 0x38 && data[4] == 0x2D) i = 5; + else if(data[3] == 0x38 || data[3] == 0x39 || data[3] == 0x2B || data[3] == 0x2F) i = 4; + } + for(; i < len; i+=j) { + if(data[i] !== 0x2b) { j=1; out[k++] = String.fromCharCode(data[i]); continue; } + j=1; + if(data[i+1] === 0x2d) { j = 2; out[k++] = "+"; continue; } + // eslint-disable-next-line no-useless-escape + while(String.fromCharCode(data[i+j]).match(/[A-Za-z0-9+\/]/)) j++; + var dash = 0; + if(data[i+j] === 0x2d) { ++j; dash=1; } + var tt = []; + var o64 = ""; + var c1=0, c2=0, c3=0; + var e1=0, e2=0, e3=0, e4=0; + for(var l = 1; l < j - dash;) { + e1 = BM.indexOf(String.fromCharCode(data[i+l++])); + e2 = BM.indexOf(String.fromCharCode(data[i+l++])); + c1 = e1 << 2 | e2 >> 4; + tt.push(c1); + e3 = BM.indexOf(String.fromCharCode(data[i+l++])); + if(e3 === -1) break; + c2 = (e2 & 15) << 4 | e3 >> 2; + tt.push(c2); + e4 = BM.indexOf(String.fromCharCode(data[i+l++])); + if(e4 === -1) break; + c3 = (e3 & 3) << 6 | e4; + if(e4 < 64) tt.push(c3); + } + o64 = decode(1201, tt); + for(l = 0; l < o64.length; ++l) out[k++] = o64.charAt(l); + } + break; + default: throw new Error("Unsupported magic: " + cp + " " + magic[cp]); + } + else throw new Error("Unrecognized CP: " + cp); + return out.slice(0,k).join(""); + }; + var hascp = function hascp(cp) { return !!(cpt[cp] || magic[cp]); }; + cpt.utils = { decode: decode, encode: encode, hascp: hascp, magic: magic, cache:cache }; + return cpt; +})); diff --git a/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/lib/xlsx.style.js b/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/lib/xlsx.style.js new file mode 100644 index 0000000..9e2345e --- /dev/null +++ b/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/lib/xlsx.style.js @@ -0,0 +1,3 @@ +/* xlsx-js-style 1.2.0-beta @ 2022-04-05T01:40:48.447Z */ +var XLSX={};function make_xlsx_lib(a){a.version="0.18.5",a.style_version="1.2.0";var re,f=1200,_=1252;"undefined"!=typeof cptable?re=cptable:"undefined"!=typeof module&&"undefined"!=typeof require&&(re=require("./cpexcel.js"));var t=[874,932,936,949,950,1250,1251,1252,1253,1254,1255,1256,1257,1258,1e4],l={0:1252,1:65001,2:65001,77:1e4,128:932,129:949,130:1361,134:936,136:950,161:1253,162:1254,163:1258,177:1255,178:1256,186:1257,204:1251,222:874,238:1250,255:1252,69:6969},c=function(e){-1!=t.indexOf(e)&&(_=l[0]=e)};var ie=function(e){c(f=e)};function h(){ie(1200),c(1252)}function ae(e){for(var t=[],r=0,a=e.length;r>1;++r)t[r]=String.fromCharCode(e.charCodeAt(2*r+1)+(e.charCodeAt(2*r)<<8));return t.join("")}var ne=function(e){var t=e.charCodeAt(0),r=e.charCodeAt(1);return 255==t&&254==r?function(e){for(var t=[],r=0;r>1;++r)t[r]=String.fromCharCode(e.charCodeAt(2*r)+(e.charCodeAt(2*r+1)<<8));return t.join("")}(e.slice(2)):254==t&&255==r?s(e.slice(2)):65279==t?e.slice(1):e},u=function(e){return String.fromCharCode(e)},n=function(e){return String.fromCharCode(e)};void 0!==re&&(ie=function(e){c(f=e)},ne=function(e){return 255===e.charCodeAt(0)&&254===e.charCodeAt(1)?re.utils.decode(1200,ae(e.slice(2))):e},u=function(e){return 1200===f?String.fromCharCode(e):re.utils.decode(f,[255&e,e>>8])[0]},n=function(e){return re.utils.decode(_,[e])[0]});var oe=null,d=!0,p="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";function ee(e){for(var t,r,a,n,s,i="",o=0,c=0,l=0;l>2,s=(3&t)<<4|(r=e.charCodeAt(l++))>>4,o=(15&r)<<2|(a=e.charCodeAt(l++))>>6,c=63&a,isNaN(r)?o=c=64:isNaN(a)&&(c=64),i+=p.charAt(n)+p.charAt(s)+p.charAt(o)+p.charAt(c);return i}function te(e){var t,r,a,n,s,i,o="";e=e.replace(/[^\w\+\/\=]/g,"");for(var c=0;c>4,o+=String.fromCharCode(t),r=(15&n)<<4|(s=p.indexOf(e.charAt(c++)))>>2,64!==s&&(o+=String.fromCharCode(r)),a=(3&s)<<6|(i=p.indexOf(e.charAt(c++))),64!==i&&(o+=String.fromCharCode(a));return o}var se="undefined"!=typeof Buffer&&"undefined"!=typeof process&&void 0!==process.versions&&!!process.versions.node,ce=function(){if("undefined"==typeof Buffer)return function(){};var t=!Buffer.from;if(!t)try{Buffer.from("foo","utf8")}catch(e){t=!0}return t?function(e,t){return t?new Buffer(e,t):new Buffer(e)}:Buffer.from.bind(Buffer)}();function le(e){return se?Buffer.alloc?Buffer.alloc(e):new Buffer(e):new("undefined"!=typeof Uint8Array?Uint8Array:Array)(e)}function fe(e){return se?Buffer.allocUnsafe?Buffer.allocUnsafe(e):new Buffer(e):new("undefined"!=typeof Uint8Array?Uint8Array:Array)(e)}var he=function(e){return se?ce(e,"binary"):e.split("").map(function(e){return 255&e.charCodeAt(0)})};function o(e){if("undefined"==typeof ArrayBuffer)return he(e);for(var t=new ArrayBuffer(e.length),r=new Uint8Array(t),a=0;a!=e.length;++a)r[a]=255&e.charCodeAt(a);return t}function i(e){if(Array.isArray(e))return e.map(function(e){return String.fromCharCode(e)}).join("");for(var t=[],r=0;r=7+t&&103==(32|e.charCodeAt(t))&&101==(32|e.charCodeAt(t+1))&&110==(32|e.charCodeAt(t+2))&&101==(32|e.charCodeAt(t+3))&&114==(32|e.charCodeAt(t+4))&&97==(32|e.charCodeAt(t+5))&&108==(32|e.charCodeAt(t+6))}var C=[["Sun","Sunday"],["Mon","Monday"],["Tue","Tuesday"],["Wed","Wednesday"],["Thu","Thursday"],["Fri","Friday"],["Sat","Saturday"]],R=[["J","Jan","January"],["F","Feb","February"],["M","Mar","March"],["A","Apr","April"],["M","May","May"],["J","Jun","June"],["J","Jul","July"],["A","Aug","August"],["S","Sep","September"],["O","Oct","October"],["N","Nov","November"],["D","Dec","December"]];var me={0:"General",1:"0",2:"0.00",3:"#,##0",4:"#,##0.00",9:"0%",10:"0.00%",11:"0.00E+00",12:"# ?/?",13:"# ??/??",14:"m/d/yy",15:"d-mmm-yy",16:"d-mmm",17:"mmm-yy",18:"h:mm AM/PM",19:"h:mm:ss AM/PM",20:"h:mm",21:"h:mm:ss",22:"m/d/yy h:mm",37:"#,##0 ;(#,##0)",38:"#,##0 ;[Red](#,##0)",39:"#,##0.00;(#,##0.00)",40:"#,##0.00;[Red](#,##0.00)",45:"mm:ss",46:"[h]:mm:ss",47:"mmss.0",48:"##0.0E+0",49:"@",56:'"上午/下午 "hh"時"mm"分"ss"秒 "'},b={5:37,6:38,7:39,8:40,23:0,24:0,25:0,26:0,27:14,28:14,29:14,30:14,31:14,50:14,51:14,52:14,53:14,54:14,55:14,56:14,57:14,58:14,59:1,60:2,61:3,62:4,67:9,68:10,69:12,70:13,71:14,72:14,73:15,74:16,75:17,76:20,77:21,78:22,79:45,80:46,81:47,82:0},k={5:'"$"#,##0_);\\("$"#,##0\\)',63:'"$"#,##0_);\\("$"#,##0\\)',6:'"$"#,##0_);[Red]\\("$"#,##0\\)',64:'"$"#,##0_);[Red]\\("$"#,##0\\)',7:'"$"#,##0.00_);\\("$"#,##0.00\\)',65:'"$"#,##0.00_);\\("$"#,##0.00\\)',8:'"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',66:'"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',41:'_(* #,##0_);_(* \\(#,##0\\);_(* "-"_);_(@_)',42:'_("$"* #,##0_);_("$"* \\(#,##0\\);_("$"* "-"_);_(@_)',43:'_(* #,##0.00_);_(* \\(#,##0.00\\);_(* "-"??_);_(@_)',44:'_("$"* #,##0.00_);_("$"* \\(#,##0.00\\);_("$"* "-"??_);_(@_)'};function y(e,t,r){for(var a=e<0?-1:1,n=e*a,s=0,i=1,o=0,c=1,l=0,f=0,h=Math.floor(n);l(e<0?12:11)||"0"===s||"-0"===s?e.toPrecision(6):s;return F(-1==(s=s.toUpperCase()).indexOf("E")?s:s.replace(/(?:\.0*|(\.\d*[1-9])0+)[Ee]/,"$1E").replace(/(E[+-])(\d)$/,"$10$2"))}function P(e,t){switch(typeof e){case"string":return e;case"boolean":return e?"TRUE":"FALSE";case"number":return(0|e)===e?e.toString(10):D(e);case"undefined":return"";case"object":if(null==e)return"";if(e instanceof Date)return ve(14,N(e,t&&t.date1904),t)}throw new Error("unsupported value in General format: "+e)}function M(e){if(e.length<=3)return e;for(var t=e.length%3,r=e.substr(0,t);t!=e.length;t+=3)r+=(0t.length?n:V(t.substr(0,t.length-n.length))+n;if(s=t.match(B))return h=s,o=u,c=d,l=parseInt(h[4],10),f=Math.round(o*l),o=Math.floor(f/l),l,c+(0===o?"":""+o)+" "+(0==(f-=o*l)?Ge(" ",h[1].length+1+h[4].length):w(f,h[1].length)+h[2]+"/"+h[3]+x(l,h[4].length));if(t.match(/^#+0+$/))return d+E(u,t.length-t.indexOf("0"));if(s=t.match(W))return n=G(r,s[1].length).replace(/^([^\.]+)$/,"$1."+V(s[1])).replace(/\.$/,"."+V(s[1])).replace(/\.(\d*)$/,function(e,t){return"."+t+Ge("0",V(s[1]).length-t.length)}),-1!==t.indexOf("0.")?n:n.replace(/^0\./,".");if(t=t.replace(/^#+([0.])/,"$1"),s=t.match(/^(0*)\.(#*)$/))return d+G(u,s[2].length).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,s[1].length?"0.":".");if(s=t.match(/^#{1,3},##0(\.?)$/))return d+M(E(u,0));if(s=t.match(/^#,##0\.([#0]*0)$/))return r<0?"-"+X(e,t,-r):M(""+(Math.floor(r)+(h=r,(p=s[1].length)<(""+Math.round((h-Math.floor(h))*Math.pow(10,p))).length?1:0)))+"."+x(j(r,s[1].length),s[1].length);if(s=t.match(/^#,#*,#0/))return X(e,t.replace(/^#,#*,/,""),r);if(s=t.match(/^([0#]+)(\\?-([0#]+))+$/))return n=v(X(e,t.replace(/[\\-]/g,""),r)),i=0,v(v(t.replace(/\\/g,"")).replace(/[0#]/g,function(e){return it.length?o:V(t.substr(0,t.length-o.length))+o;if(c=t.match(B))return h+(0===(u=f)?"":""+u)+Ge(" ",(u=c)[1].length+2+u[4].length);if(t.match(/^#+0+$/))return h+x(f,t.length-t.indexOf("0"));if(c=t.match(W))return o=(o=(""+r).replace(/^([^\.]+)$/,"$1."+V(c[1])).replace(/\.$/,"."+V(c[1]))).replace(/\.(\d*)$/,function(e,t){return"."+t+Ge("0",V(c[1]).length-t.length)}),-1!==t.indexOf("0.")?o:o.replace(/^0\./,".");if(t=t.replace(/^#+([0.])/,"$1"),c=t.match(/^(0*)\.(#*)$/))return h+(""+f).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,c[1].length?"0.":".");if(c=t.match(/^#{1,3},##0(\.?)$/))return h+M(""+f);if(c=t.match(/^#,##0\.([#0]*0)$/))return r<0?"-"+Y(e,t,-r):M(""+r)+"."+Ge("0",c[1].length);if(c=t.match(/^#,#*,#0/))return Y(e,t.replace(/^#,#*,/,""),r);if(c=t.match(/^([0#]+)(\\?-([0#]+))+$/))return o=v(Y(e,t.replace(/[\\-]/g,""),r)),l=0,v(v(t.replace(/\\/g,"")).replace(/[0#]/g,function(e){return l=€acfijklopqrtuvwxzP".indexOf(f))throw new Error("unrecognized character "+f+" in "+e);o[o.length]={t:"t",v:f},++l}var m,g=0,b=0;for(l=o.length-1,h="t";0<=l;--l)switch(o[l].t){case"h":case"H":o[l].t=u,h="h",g<1&&(g=1);break;case"s":(m=o[l].v.match(/\.0+$/))&&(b=Math.max(b,m[0].length-1)),g<3&&(g=3);case"d":case"y":case"M":case"e":h=o[l].t;break;case"m":"s"===h&&(o[l].t="M",g<2&&(g=2));break;case"X":break;case"Z":(g=(g=g<1&&o[l].v.match(/[Hh]/)?1:g)<2&&o[l].v.match(/[Mm]/)?2:g)<3&&o[l].v.match(/[Ss]/)&&(g=3)}switch(g){case 0:break;case 1:.5<=n.u&&(n.u=0,++n.S),60<=n.S&&(n.S=0,++n.M),60<=n.M&&(n.M=0,++n.H);break;case 2:.5<=n.u&&(n.u=0,++n.S),60<=n.S&&(n.S=0,++n.M)}var v,w="";for(l=0;l=o[l].v.length-1?(v-=o[l].v.length,o[l].v=E.substr(v+1,o[l].v.length)):v<0?o[l].v="":(o[l].v=E.substr(0,v+1),v=-1),o[l].t="t",S=l);0<=v&&S[=]?|<[>=]?)(-?\d+(?:\.\d*)?)\]/;function ge(e,t){if(null!=t){var r=parseFloat(t[2]);switch(t[1]){case"=":if(e==r)return 1;break;case">":if(r":if(e!=r)return 1;break;case">=":if(r<=e)return 1;break;case"<=":if(e<=r)return 1}}}function be(e,t){var r=function(e){for(var t=[],r=!1,a=0,n=0;a]/)&&null==r[1].match(/\[[=<>]/))return[a,s];e=r[0].match(Q),s=r[1].match(Q);return ge(t,e)?[a,r[0]]:ge(t,s)?[a,r[1]]:[a,r[null!=e&&null!=s?2:1]]}function ve(e,t,r){null==r&&(r={});var a="";switch(typeof e){case"string":a="m/d/yy"==e&&r.dateNF?r.dateNF:e;break;case"number":null==(a=null==(a=14==e&&r.dateNF?r.dateNF:(null!=r.table?r.table:me)[e])?r.table&&r.table[b[e]]||me[b[e]]:a)&&(a=k[e]||"General")}if(A(a,0))return P(t,r);var n=be(a,t=t instanceof Date?N(t,r.date1904):t);if(A(n[1]))return P(t,r);if(!0===t)t="TRUE";else if(!1===t)t="FALSE";else if(""===t||null==t)return"";return Z(n[1],t,r,n[0])}function we(e,t){if("number"!=typeof t){t=+t||-1;for(var r=0;r<392;++r)if(null!=me[r]){if(me[r]==e){t=r;break}}else t<0&&(t=r);t<0&&(t=391)}return me[t]=e,t}function Te(e){for(var t=0;392!=t;++t)void 0!==e[t]&&we(e[t],t)}function Ee(){var e;(e=e||{})[0]="General",e[1]="0",e[2]="0.00",e[3]="#,##0",e[4]="#,##0.00",e[9]="0%",e[10]="0.00%",e[11]="0.00E+00",e[12]="# ?/?",e[13]="# ??/??",e[14]="m/d/yy",e[15]="d-mmm-yy",e[16]="d-mmm",e[17]="mmm-yy",e[18]="h:mm AM/PM",e[19]="h:mm:ss AM/PM",e[20]="h:mm",e[21]="h:mm:ss",e[22]="m/d/yy h:mm",e[37]="#,##0 ;(#,##0)",e[38]="#,##0 ;[Red](#,##0)",e[39]="#,##0.00;(#,##0.00)",e[40]="#,##0.00;[Red](#,##0.00)",e[45]="mm:ss",e[46]="[h]:mm:ss",e[47]="mmss.0",e[48]="##0.0E+0",e[49]="@",e[56]='"上午/下午 "hh"時"mm"分"ss"秒 "',me=e}var e={format:ve,load:we,_table:me,load_table:Te,parse_date_code:L,is_date:q,get_table:function(){return e._table=me}},ke={5:'"$"#,##0_);\\("$"#,##0\\)',6:'"$"#,##0_);[Red]\\("$"#,##0\\)',7:'"$"#,##0.00_);\\("$"#,##0.00\\)',8:'"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',23:"General",24:"General",25:"General",26:"General",27:"m/d/yy",28:"m/d/yy",29:"m/d/yy",30:"m/d/yy",31:"m/d/yy",32:"h:mm:ss",33:"h:mm:ss",34:"h:mm:ss",35:"h:mm:ss",36:"m/d/yy",41:'_(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)',42:'_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)',43:'_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)',44:'_("$"* #,##0.00_);_("$"* (#,##0.00);_("$"* "-"??_);_(@_)',50:"m/d/yy",51:"m/d/yy",52:"m/d/yy",53:"m/d/yy",54:"m/d/yy",55:"m/d/yy",56:"m/d/yy",57:"m/d/yy",58:"m/d/yy",59:"0",60:"0.00",61:"#,##0",62:"#,##0.00",63:'"$"#,##0_);\\("$"#,##0\\)',64:'"$"#,##0_);[Red]\\("$"#,##0\\)',65:'"$"#,##0.00_);\\("$"#,##0.00\\)',66:'"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',67:"0%",68:"0.00%",69:"# ?/?",70:"# ??/??",71:"m/d/yy",72:"m/d/yy",73:"d-mmm-yy",74:"d-mmm",75:"mmm-yy",76:"h:mm",77:"h:mm:ss",78:"m/d/yy h:mm",79:"mm:ss",80:"[h]:mm:ss",81:"mmss.0"},ye=/[dD]+|[mM]+|[yYeE]+|[Hh]+|[Ss]+/g;var Se,_e=function(){var e={};e.version="1.2.0";var o=function(){for(var e=0,t=new Array(256),r=0;256!=r;++r)e=1&(e=1&(e=1&(e=1&(e=1&(e=1&(e=1&(e=1&(e=r)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1,t[r]=e;return"undefined"!=typeof Int32Array?new Int32Array(t):t}();var t=function(e){for(var t=0,r=0,a=0,n=new("undefined"!=typeof Int32Array?Int32Array:Array)(4096),a=0;256!=a;++a)n[a]=e[a];for(a=0;256!=a;++a)for(r=e[a],t=256+a;t<4096;t+=256)r=n[t]=r>>>8^e[255&r];var s=[];for(a=1;16!=a;++a)s[a-1]="undefined"!=typeof Int32Array?n.subarray(256*a,256*a+256):n.slice(256*a,256*a+256);return s}(o),s=t[0],i=t[1],c=t[2],l=t[3],f=t[4],h=t[5],u=t[6],d=t[7],p=t[8],m=t[9],g=t[10],b=t[11],v=t[12],w=t[13],T=t[14];return e.table=o,e.bstr=function(e,t){for(var r=-1^t,a=0,n=e.length;a>>8^o[255&(r^e.charCodeAt(a++))];return~r},e.buf=function(e,t){for(var r=-1^t,a=e.length-15,n=0;n>8&255]^v[e[n++]^r>>16&255]^b[e[n++]^r>>>24]^g[e[n++]]^m[e[n++]]^p[e[n++]]^d[e[n++]]^u[e[n++]]^h[e[n++]]^f[e[n++]]^l[e[n++]]^c[e[n++]]^i[e[n++]]^s[e[n++]]^o[e[n++]];for(a+=15;n>>8^o[255&(r^e[n++])];return~r},e.str=function(e,t){for(var r,a=-1^t,n=0,s=e.length,i=0;n>>8^o[255&(a^i)]:i<2048?(a=a>>>8^o[255&(a^(192|i>>6&31))])>>>8^o[255&(a^(128|63&i))]:55296<=i&&i<57344?(i=64+(1023&i),r=1023&e.charCodeAt(n++),(a=(a=(a=a>>>8^o[255&(a^(240|i>>8&7))])>>>8^o[255&(a^(128|i>>2&63))])>>>8^o[255&(a^(128|r>>6&15|(3&i)<<4))])>>>8^o[255&(a^(128|63&r))]):(a=(a=a>>>8^o[255&(a^(224|i>>12&15))])>>>8^o[255&(a^(128|i>>6&63))])>>>8^o[255&(a^(128|63&i))];return~a},e}(),xe=function(){var s,e={};function d(e){if("/"==e.charAt(e.length-1))return-1===e.slice(0,-1).indexOf("/")?e:d(e.slice(0,-1));var t=e.lastIndexOf("/");return-1===t?e:e.slice(0,t+1)}function p(e){if("/"==e.charAt(e.length-1))return p(e.slice(0,-1));var t=e.lastIndexOf("/");return-1===t?e:e.slice(t+1)}function g(e){Dr(e,0);for(var t,r={};e.l<=e.length-4;){var a=e.read_shift(2),n=e.read_shift(2),s=e.l+n,i={};21589===a&&(1&(t=e.read_shift(1))&&(i.mtime=e.read_shift(4)),5>>2)-1;if(o){for(var l=0;l=l.length?-1:o,o=n+1;o=l.length?-1:o,h.type=1}else d(e.FullPaths[n+1]||"")==d(u)&&(h.R=n+1),h.type=2}}}function a(e,t){var r=t||{};if("mad"==r.fileType)return function(e,t){for(var r=t||{},a=r.boundary||"SheetJS",n=["MIME-Version: 1.0",'Content-Type: multipart/related; boundary="'+(a="------="+a).slice(2)+'"',"","",""],s=e.FullPaths[0],i=s,o=e.FileIndex[0],c=1;c>>1,e.write_shift(2,r),r=(r=(r=t.getFullYear()-1980)<<4|t.getMonth()+1)<<5|t.getDate(),e.write_shift(2,r)}(n,d.mt):n.write_shift(4,0),n.write_shift(-4,8&i?0:p[f]),n.write_shift(4,8&i?0:v.length),n.write_shift(4,8&i?0:d.content.length),n.write_shift(2,b.length),n.write_shift(2,0),l+=n.length,r.push(n),l+=b.length,r.push(b),l+=v.length,r.push(v),8&i&&((n=Lr(12)).write_shift(-4,p[f]),n.write_shift(4,v.length),n.write_shift(4,d.content.length),l+=n.l,r.push(n)),(n=Lr(46)).write_shift(4,33639248),n.write_shift(2,0),n.write_shift(2,20),n.write_shift(2,i),n.write_shift(2,s),n.write_shift(4,0),n.write_shift(-4,p[f]),n.write_shift(4,v.length),n.write_shift(4,d.content.length),n.write_shift(2,b.length),n.write_shift(2,0),n.write_shift(2,0),n.write_shift(2,0),n.write_shift(2,0),n.write_shift(4,0),n.write_shift(4,g),m+=n.l,a.push(n),m+=b.length,a.push(b),++f}return(n=Lr(22)).write_shift(4,101010256),n.write_shift(2,0),n.write_shift(2,0),n.write_shift(2,f),n.write_shift(2,f),n.write_shift(4,m),n.write_shift(4,l),n.write_shift(2,0),ue([ue(r),ue(a),n])}(e,r);for(var a=function(e){for(var t=0,r=0,a=0;a>6:r+=n+511>>9))}for(var s=e.FullPaths.length+3>>2,i=t+127>>7,o=(t+7>>3)+r+s+i,c=o+127>>7,l=c<=109?0:Math.ceil((c-109)/127);c>7;)l=++c<=109?0:Math.ceil((c-109)/127);s=[1,l,c,i,s,r,t,0];return e.FileIndex[0].size=t<<6,s[7]=(e.FileIndex[0].start=s[0]+s[1]+s[2]+s[3]+s[4]+s[5])+(s[6]+7>>3),s}(e),n=Lr(a[7]<<9),s=0,i=0,s=0;s<8;++s)n.write_shift(1,m[s]);for(s=0;s<8;++s)n.write_shift(2,0);for(n.write_shift(2,62),n.write_shift(2,3),n.write_shift(2,65534),n.write_shift(2,9),n.write_shift(2,6),s=0;s<3;++s)n.write_shift(2,0);for(n.write_shift(4,0),n.write_shift(4,a[2]),n.write_shift(4,a[0]+a[1]+a[2]+a[3]-1),n.write_shift(4,0),n.write_shift(4,4096),n.write_shift(4,a[3]?a[0]+a[1]+a[2]-1:k),n.write_shift(4,a[3]),n.write_shift(-4,a[1]?a[0]-1:k),n.write_shift(4,a[1]),s=0;s<109;++s)n.write_shift(-4,s>9)));for(o(a[6]+7>>3);511&n.l;)n.write_shift(-4,S.ENDOFCHAIN);for(c=i=s=0;c>6)));for(;511&n.l;)n.write_shift(-4,S.ENDOFCHAIN);for(s=0;s>16|t>>8|t);function I(e,t){var r=7&t,t=t>>>3;return(e[t]|(r<=5?0:e[1+t]<<8))>>>r&7}function N(e,t){var r=7&t,t=t>>>3;return(e[t]|(r<=3?0:e[1+t]<<8))>>>r&31}function F(e,t){var r=7&t,t=t>>>3;return(e[t]|(r<=1?0:e[1+t]<<8))>>>r&127}function D(e,t,r){var a=7&t,n=t>>>3,s=(1<>>a;return r<8-a?t&s:(t|=e[1+n]<<8-a,r<16-a?t&s:(t|=e[2+n]<<16-a,r<24-a?t&s:(t|=e[3+n]<<24-a)&s))}function P(e,t,r){var a=7&t,n=t>>>3;return a<=5?e[n]|=(7&r)<>8-a),t+3}function L(e,t,r){var a=t>>>3;return r<<=7&t,e[a]|=255&r,r>>>=8,e[1+a]=r,t+8}function M(e,t,r){var a=t>>>3;return r<<=7&t,e[a]|=255&r,r>>>=8,e[1+a]=255&r,e[2+a]=r>>>8,t+16}function U(e,t){var r=e.length,a=t<2*r?2*r:t+5,n=0;if(t<=r)return e;if(se){var s=fe(a);if(e.copy)e.copy(s);else for(;n>>8-d:(p=p<<8|O[u>>8&255],d<=16?p>>>16-d:(p=p<<8|O[u>>16&255])>>>24-d))>>n-h,i=(1<>1)-1:(L(t,r,3),L(t,r+=5,O[o-23]>>5),r+=3);var f=o<8?0:o-4>>2;0>3),r-=3;var h=o<4?0:o-2>>1;0>>3]|=f,r=h+1),r=L(t,r,O[o]),n[i]=32767&a,++a}r=L(t,r,0)-1}}return t.l=(r+7)/8|0,t.l})(e,t)}}();function V(e){var t=Lr(50+Math.floor(1.1*e.length)),e=c(e,t);return t.slice(0,e)}var G=R?new Uint16Array(32768):B(32768),j=R?new Uint16Array(32768):B(32768),$=R?new Uint16Array(128):B(128),X=1,Y=1;function l(e,t){if(3==e[0]&&!(3&e[1]))return[le(t),2];for(var r=0,a=0,n=fe(t||1<<18),s=0,i=n.length>>>0,o=0,c=0;0==(1&a);)if(a=I(e,r),r+=3,a>>>1!=0)for(c=a>>1==1?(o=9,5):(r=function(e,t){var r,a,n,s=N(e,t)+257,i=N(e,t+=5)+1,o=(n=7&(a=t+=5),4+(((r=e)[a=a>>>3]|(n<=4?0:r[1+a]<<8))>>>n&15));t+=4;for(var c=0,l=R?new Uint8Array(19):B(19),f=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],h=1,u=R?new Uint8Array(8):B(8),d=R?new Uint8Array(8):B(8),p=l.length,m=0;m>8-b;for(var v=(1<<7-b)-1;0<=v;--v)$[g|v<>>=3){case 16:for(c=3+(E=void 0,E=7&(T=t),((w=e)[T=T>>>3]|(E<=6?0:w[1+T]<<8))>>>E&3),t+=2,g=k[k.length-1];0>>1==1?H:G)[l];if(r+=15&f,0==((f>>>=4)>>>8&255))n[s++]=f;else{if(256==f)break;var h=(f-=257)<8?0:f-4>>2;5>>1==1?z:j)[l]);var l=(f>>>=4)<4?0:f-2>>1,d=C[f];for(0>>3]|e[1+(r>>>3)]<<8;if(r+=32,0>>3],r+=8}return t?[n,r+7>>>3]:[n.slice(0,s),r+7>>>3]}function K(e,t){t=l(e.slice(e.l||0),t);return e.l+=t[1],t[0]}function J(e,t){if(!e)throw new Error(t);"undefined"!=typeof console&&console.error(t)}function q(e,t){var r=e;Dr(r,0);var a={FileIndex:[],FullPaths:[]};w(a,{root:t.root});for(var n=r.length-4;(80!=r[n]||75!=r[n+1]||5!=r[n+2]||6!=r[n+3])&&0<=n;)--n;r.l=n+4,r.l+=4;var s=r.read_shift(2);r.l+=6;t=r.read_shift(4);for(r.l=t,n=0;n>>=5);return r>>>=4,a.setMilliseconds(0),a.setFullYear(1980+r),a.setMonth(e-1),a.setDate(n),e=31&t,n=63&(t>>>=5),t>>>=6,a.setHours(t),a.setMinutes(n),a.setSeconds(e<<1),a}(e);if(8257&s)throw new Error("Unsupported ZIP encryption");e.read_shift(4);for(var c,l=e.read_shift(4),f=e.read_shift(4),h=e.read_shift(2),u=e.read_shift(2),d="",p=0;p>6&31,n[r++]=128|63&o):55296<=o&&o<57344?(o=64+(1023&o),i=1023&e.charCodeAt(++s),n[r++]=240|o>>8&7,n[r++]=128|o>>2&63,n[r++]=128|i>>6&15|(3&o)<<4,n[r++]=128|63&i):(n[r++]=224|o>>12&15,n[r++]=128|o>>6&63,n[r++]=128|63&o),a\/]+)\s*=\s*((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g,lt=/<[\/\?]?[a-zA-Z0-9:_-]+(?:\s+[^"\s?>\/]+\s*=\s*(?:"[^"]*"|'[^']*'|[^'">\s=]+))*\s*[\/\?]?>/gm,ft=ot.match(lt)?lt:/<[^>]*>/g,ht=/<\w*:/,ut=/<(\/?)\w+:/;function dt(e,t,r){for(var a={},n=0,s=0;n!==e.length&&(32!==(s=e.charCodeAt(n))&&10!==s&&13!==s);++n);if(t||(a[0]=e.slice(0,n)),n===e.length)return a;var i,o,c,l=e.match(ct),f=0,h=0,u="",d="";if(l)for(h=0;h!=l.length;++h){for(d=l[h],s=0;s!=d.length&&61!==d.charCodeAt(s);++s);for(u=d.slice(0,s).trim();32==d.charCodeAt(s+1);)++s;for(o=34==(n=d.charCodeAt(s+1))||39==n?1:0,i=d.slice(s+1+o,d.length-o),f=0;f!=u.length&&58!==u.charCodeAt(f);++f);f===u.length?(a[u=0","<":"<","&":"&"},vt=Ie(bt),wt=(mt=/&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/gi,gt=/_x([\da-fA-F]{4})_/gi,function e(t){var r=t+"",a=r.indexOf("");return e(r.slice(0,a))+r.slice(a+9,t)+e(r.slice(t+3))}),Tt=/[&<>'"]/g,Et=/[\u0000-\u0008\u000b-\u001f]/g;function kt(e){return(e+"").replace(Tt,function(e){return vt[e]}).replace(Et,function(e){return"_x"+("000"+e.charCodeAt(0).toString(16)).slice(-4)+"_"})}function yt(e){return kt(e).replace(/ /g,"_x0020_")}var St=/[\u0000-\u001f]/g;function _t(e){return(e+"").replace(Tt,function(e){return vt[e]}).replace(/\n/g,"
").replace(St,function(e){return"&#x"+("000"+e.charCodeAt(0).toString(16)).slice(-4)+";"})}var xt,At=(xt=/&#(\d+);/g,function(e){return e.replace(xt,Ct)});function Ct(e,t){return String.fromCharCode(parseInt(t,10))}function Rt(e){switch(e){case 1:case!0:case"1":case"true":case"TRUE":return!0;default:return!1}}function Ot(e){for(var t,r,a,n,s="",i=0,o=0;i>>10&1023)),s+=String.fromCharCode(56320+(1023&n)))));return s}function It(e){for(var t,r,a=le(2*e.length),n=1,s=0,i=0,o=0;o>>10&1023),t=56320+(1023&t)),0!==i&&(a[s++]=255&i,a[s++]=i>>>8,i=0),a[s++]=t%256,a[s++]=t>>>8;return a.slice(0,s).toString("ucs2")}function Nt(e){return ce(e,"binary").toString("utf8")}var Ft,Dt,Pt,Lt="foo bar baz☃🍣",Mt=se&&(Nt(Lt)==Ot(Lt)?Nt:It(Lt)==Ot(Lt)&&It)||Ot,Ut=se?function(e){return ce(e,"utf8").toString("binary")}:function(e){for(var t,r=[],a=0,n=0;a>6))),r.push(String.fromCharCode(128+(63&n)));break;case 55296<=n&&n<57344:n-=55296,t=e.charCodeAt(a++)-56320+(n<<10),r.push(String.fromCharCode(240+(t>>18&7))),r.push(String.fromCharCode(144+(t>>12&63))),r.push(String.fromCharCode(128+(t>>6&63))),r.push(String.fromCharCode(128+(63&t)));break;default:r.push(String.fromCharCode(224+(n>>12))),r.push(String.fromCharCode(128+(n>>6&63))),r.push(String.fromCharCode(128+(63&n)))}return r.join("")},Bt=(Ft={},function(e,t){var r=e+"|"+(t||"");return Ft[r]||(Ft[r]=new RegExp("<(?:\\w+:)?"+e+'(?: xml:space="preserve")?(?:[^>]*)>([\\s\\S]*?)",t||""))}),Wt=(Dt=[["nbsp"," "],["middot","·"],["quot",'"'],["apos","'"],["gt",">"],["lt","<"],["amp","&"]].map(function(e){return[new RegExp("&"+e[0]+";","ig"),e[1]]}),function(e){for(var t=e.replace(/^[\t\n\r ]+/,"").replace(/[\t\n\r ]+$/,"").replace(/>\s+/g,">").replace(/\s+/g,"\n").replace(/<[^>]*>/g,""),r=0;r([\\s\\S]*?)","g")}),zt=/<\/?(?:vt:)?variant>/g,Vt=/<(?:vt:)([^>]*)>([\s\S]*)"+t+""}function Xt(t){return Re(t).map(function(e){return" "+e+'="'+t[e]+'"'}).join("")}function Yt(e,t,r){return"<"+e+(null!=r?Xt(r):"")+(null!=t?(t.match(jt)?' xml:space="preserve"':"")+">"+t+""}function Kt(e,t){try{return e.toISOString().replace(/\.\d*/,"")}catch(e){if(t)throw e}return""}function Jt(e){if(se&&Buffer.isBuffer(e))return e.toString("utf8");if("string"==typeof e)return e;if("undefined"!=typeof Uint8Array&&e instanceof Uint8Array)return Mt(i(m(e)));throw new Error("Bad input format: expected Buffer or string")}var qt=/<(\/?)([^\s?>:\/]+)(?:[\s?:\/][^>]*)?>/gm,Zt={CORE_PROPS:"http://schemas.openxmlformats.org/package/2006/metadata/core-properties",CUST_PROPS:"http://schemas.openxmlformats.org/officeDocument/2006/custom-properties",EXT_PROPS:"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties",CT:"http://schemas.openxmlformats.org/package/2006/content-types",RELS:"http://schemas.openxmlformats.org/package/2006/relationships",TCMNT:"http://schemas.microsoft.com/office/spreadsheetml/2018/threadedcomments",dc:"http://purl.org/dc/elements/1.1/",dcterms:"http://purl.org/dc/terms/",dcmitype:"http://purl.org/dc/dcmitype/",mx:"http://schemas.microsoft.com/office/mac/excel/2008/main",r:"http://schemas.openxmlformats.org/officeDocument/2006/relationships",sjs:"http://schemas.openxmlformats.org/package/2006/sheetjs/core-properties",vt:"http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes",xsi:"http://www.w3.org/2001/XMLSchema-instance",xsd:"http://www.w3.org/2001/XMLSchema"},Qt=["http://schemas.openxmlformats.org/spreadsheetml/2006/main","http://purl.oclc.org/ooxml/spreadsheetml/main","http://schemas.microsoft.com/office/excel/2006/main","http://schemas.microsoft.com/office/excel/2006/2"],er={o:"urn:schemas-microsoft-com:office:office",x:"urn:schemas-microsoft-com:office:excel",ss:"urn:schemas-microsoft-com:office:spreadsheet",dt:"uuid:C2F41010-65B3-11d1-A29F-00AA00C14882",mv:"http://macVmlSchemaUri",v:"urn:schemas-microsoft-com:vml",html:"http://www.w3.org/TR/REC-html40"};function tr(e){for(var t=[],r=0;r>>7),a=((127&e[t+7])<<4)+(e[t+6]>>>4&15),n=15&e[t+6],s=5;0<=s;--s)n=256*n+e[t+s];return 2047==a?0==n?1/0*r:NaN:(0==a?a=-1022:(a-=1023,n+=Math.pow(2,52)),r*Math.pow(2,a-52)*n)}var hr=se?function(e){return 0>>8&255,e[r+2]=t>>>16&255,e[r+3]=t>>>24&255},Or=function(e,t,r){e[r]=255&t,e[r+1]=t>>8&255,e[r+2]=t>>16&255,e[r+3]=t>>24&255},Ir=function(e,t,r){e[r]=255&t,e[r+1]=t>>>8&255};function Nr(e,t,r){var a=0,n=0;if("dbcs"===r){for(n=0;n!=t.length;++n)Ir(this,t.charCodeAt(n),this.l+2*n);a=2*t.length}else if("sbcs"===r){if(void 0!==re&&874==_)for(n=0;n!=t.length;++n){var s=re.utils.encode(_,t.charAt(n));this[this.l+n]=s[0]}else for(t=t.replace(/[^\x00-\x7F]/g,"_"),n=0;n!=t.length;++n)this[this.l+n]=255&t.charCodeAt(n);a=t.length}else{if("hex"===r){for(;n>8}for(;this.l>>=8,this[this.l+1]=255&t;break;case 3:a=3,this[this.l]=255&t,t>>>=8,this[this.l+1]=255&t,t>>>=8,this[this.l+2]=255&t;break;case 4:a=4,Rr(this,t,this.l);break;case 8:if(a=8,"f"===r){!function(e,t,r){var a=(t<0||1/t==-1/0?1:0)<<7,n=0,s=0,i=a?-t:t;isFinite(i)?0==i?n=s=0:(n=Math.floor(Math.log(i)/Math.LN2),s=i*Math.pow(2,52-n),n<=-1023&&(!isFinite(s)||s>4|a}(this,t,this.l);break}case 16:break;case-4:a=4,Or(this,t,this.l)}}return this.l+=a,this}function Fr(e,t){var r=dr(this,this.l,e.length>>1);if(r!==e)throw new Error(t+"Expected "+e+" saw "+r);this.l+=e.length>>1}function Dr(e,t){e.l=t,e.read_shift=Cr,e.chk=Fr,e.write_shift=Nr}function Pr(e,t){e.l+=t}function Lr(e){e=le(e);return Dr(e,0),e}function Mr(e,t,r){if(e){Dr(e,e.l||0);for(var a,n=e.length,s=0;e.ls.l&&((s=s.slice(0,s.l)).l=s.length),0>7));for(var i=0;4!=i;++i){if(!(128<=a)){s.write_shift(1,a);break}s.write_shift(1,128+(127&a)),a>>=7}0d&&(l.s.r=d),l.s.c>p&&(l.s.c=p),l.e.r>2;return r?t/100:t}function ka(e,t){null==t&&(t=Lr(4));var r=0,a=0,n=100*e;if(e==(0|e)&&-(1<<29)<=e&&e<1<<29?a=1:n==(0|n)&&-(1<<29)<=n&&n<1<<29&&(r=a=1),!a)throw new Error("unsupported RkNumber "+e);t.write_shift(-4,((r?n:e)<<2)+(r+2))}function ya(e){var t={s:{},e:{}};return t.s.r=e.read_shift(4),t.e.r=e.read_shift(4),t.s.c=e.read_shift(4),t.e.c=e.read_shift(4),t}var Sa=ya,_a=function(e,t){return(t=t||Lr(16)).write_shift(4,e.s.r),t.write_shift(4,e.e.r),t.write_shift(4,e.s.c),t.write_shift(4,e.e.c),t};function xa(e){if(e.length-e.l<8)throw"XLS Xnum Buffer underflow";return e.read_shift(8,"f")}function Aa(e,t){return(t||Lr(8)).write_shift(8,e,"f")}function Ca(e,t){if(t=t||Lr(8),!e||e.auto)return t.write_shift(4,0),t.write_shift(4,0),t;null!=e.index?(t.write_shift(1,2),t.write_shift(1,e.index)):null!=e.theme?(t.write_shift(1,6),t.write_shift(1,e.theme)):(t.write_shift(1,5),t.write_shift(1,0));var r=e.tint||0;return 0>16&255,e>>8&255,255&e]})),Wa={0:"#NULL!",7:"#DIV/0!",15:"#VALUE!",23:"#REF!",29:"#NAME?",36:"#NUM!",42:"#N/A",43:"#GETTING_DATA",255:"#WTF?"},Ha={"#NULL!":0,"#DIV/0!":7,"#VALUE!":15,"#REF!":23,"#NAME?":29,"#NUM!":36,"#N/A":42,"#GETTING_DATA":43,"#WTF?":255},za={"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml":"workbooks","application/vnd.ms-excel.sheet.macroEnabled.main+xml":"workbooks","application/vnd.ms-excel.sheet.binary.macroEnabled.main":"workbooks","application/vnd.ms-excel.addin.macroEnabled.main+xml":"workbooks","application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml":"workbooks","application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml":"sheets","application/vnd.ms-excel.worksheet":"sheets","application/vnd.ms-excel.binIndexWs":"TODO","application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml":"charts","application/vnd.ms-excel.chartsheet":"charts","application/vnd.ms-excel.macrosheet+xml":"macros","application/vnd.ms-excel.macrosheet":"macros","application/vnd.ms-excel.intlmacrosheet":"TODO","application/vnd.ms-excel.binIndexMs":"TODO","application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml":"dialogs","application/vnd.ms-excel.dialogsheet":"dialogs","application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml":"strs","application/vnd.ms-excel.sharedStrings":"strs","application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml":"styles","application/vnd.ms-excel.styles":"styles","application/vnd.openxmlformats-package.core-properties+xml":"coreprops","application/vnd.openxmlformats-officedocument.custom-properties+xml":"custprops","application/vnd.openxmlformats-officedocument.extended-properties+xml":"extprops","application/vnd.openxmlformats-officedocument.customXmlProperties+xml":"TODO","application/vnd.openxmlformats-officedocument.spreadsheetml.customProperty":"TODO","application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml":"comments","application/vnd.ms-excel.comments":"comments","application/vnd.ms-excel.threadedcomments+xml":"threadedcomments","application/vnd.ms-excel.person+xml":"people","application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml":"metadata","application/vnd.ms-excel.sheetMetadata":"metadata","application/vnd.ms-excel.pivotTable":"TODO","application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml":"TODO","application/vnd.openxmlformats-officedocument.drawingml.chart+xml":"TODO","application/vnd.ms-office.chartcolorstyle+xml":"TODO","application/vnd.ms-office.chartstyle+xml":"TODO","application/vnd.ms-office.chartex+xml":"TODO","application/vnd.ms-excel.calcChain":"calcchains","application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml":"calcchains","application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings":"TODO","application/vnd.ms-office.activeX":"TODO","application/vnd.ms-office.activeX+xml":"TODO","application/vnd.ms-excel.attachedToolbars":"TODO","application/vnd.ms-excel.connections":"TODO","application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml":"TODO","application/vnd.ms-excel.externalLink":"links","application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml":"links","application/vnd.ms-excel.pivotCacheDefinition":"TODO","application/vnd.ms-excel.pivotCacheRecords":"TODO","application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml":"TODO","application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml":"TODO","application/vnd.ms-excel.queryTable":"TODO","application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml":"TODO","application/vnd.ms-excel.userNames":"TODO","application/vnd.ms-excel.revisionHeaders":"TODO","application/vnd.ms-excel.revisionLog":"TODO","application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml":"TODO","application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml":"TODO","application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml":"TODO","application/vnd.ms-excel.tableSingleCells":"TODO","application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml":"TODO","application/vnd.ms-excel.slicer":"TODO","application/vnd.ms-excel.slicerCache":"TODO","application/vnd.ms-excel.slicer+xml":"TODO","application/vnd.ms-excel.slicerCache+xml":"TODO","application/vnd.ms-excel.wsSortMap":"TODO","application/vnd.ms-excel.table":"TODO","application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml":"TODO","application/vnd.openxmlformats-officedocument.theme+xml":"themes","application/vnd.openxmlformats-officedocument.themeOverride+xml":"TODO","application/vnd.ms-excel.Timeline+xml":"TODO","application/vnd.ms-excel.TimelineCache+xml":"TODO","application/vnd.ms-office.vbaProject":"vba","application/vnd.ms-office.vbaProjectSignature":"TODO","application/vnd.ms-office.volatileDependencies":"TODO","application/vnd.openxmlformats-officedocument.spreadsheetml.volatileDependencies+xml":"TODO","application/vnd.ms-excel.controlproperties+xml":"TODO","application/vnd.openxmlformats-officedocument.model+data":"TODO","application/vnd.ms-excel.Survey+xml":"TODO","application/vnd.openxmlformats-officedocument.drawing+xml":"drawings","application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml":"TODO","application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml":"TODO","application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml":"TODO","application/vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml":"TODO","application/vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml":"TODO","application/vnd.openxmlformats-officedocument.vmlDrawing":"TODO","application/vnd.openxmlformats-package.relationships+xml":"rels","application/vnd.openxmlformats-officedocument.oleObject":"TODO","image/png":"TODO",sheet:"js"},Va={workbooks:{xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",xlsm:"application/vnd.ms-excel.sheet.macroEnabled.main+xml",xlsb:"application/vnd.ms-excel.sheet.binary.macroEnabled.main",xlam:"application/vnd.ms-excel.addin.macroEnabled.main+xml",xltx:"application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml"},strs:{xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",xlsb:"application/vnd.ms-excel.sharedStrings"},comments:{xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",xlsb:"application/vnd.ms-excel.comments"},sheets:{xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",xlsb:"application/vnd.ms-excel.worksheet"},charts:{xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml",xlsb:"application/vnd.ms-excel.chartsheet"},dialogs:{xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml",xlsb:"application/vnd.ms-excel.dialogsheet"},macros:{xlsx:"application/vnd.ms-excel.macrosheet+xml",xlsb:"application/vnd.ms-excel.macrosheet"},metadata:{xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml",xlsb:"application/vnd.ms-excel.sheetMetadata"},styles:{xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",xlsb:"application/vnd.ms-excel.styles"}};function Ga(){return{workbooks:[],sheets:[],charts:[],dialogs:[],macros:[],rels:[],strs:[],comments:[],threadedcomments:[],links:[],coreprops:[],extprops:[],custprops:[],themes:[],styles:[],calcchains:[],vba:[],drawings:[],metadata:[],people:[],TODO:[],xmlns:""}}function ja(r,a){var t,n=function(e){for(var t=[],r=Re(e),a=0;a!==r.length;++a)null==t[e[r[a]]]&&(t[e[r[a]]]=[]),t[e[r[a]]].push(r[a]);return t}(za),s=[];s[s.length]=ot,s[s.length]=Yt("Types",null,{xmlns:Zt.CT,"xmlns:xsd":Zt.xsd,"xmlns:xsi":Zt.xsi}),s=s.concat([["xml","application/xml"],["bin","application/vnd.ms-excel.sheet.binary.macroEnabled.main"],["vml","application/vnd.openxmlformats-officedocument.vmlDrawing"],["data","application/vnd.openxmlformats-officedocument.model+data"],["bmp","image/bmp"],["png","image/png"],["gif","image/gif"],["emf","image/x-emf"],["wmf","image/x-wmf"],["jpg","image/jpeg"],["jpeg","image/jpeg"],["tif","image/tiff"],["tiff","image/tiff"],["pdf","application/pdf"],["rels","application/vnd.openxmlformats-package.relationships+xml"]].map(function(e){return Yt("Default",null,{Extension:e[0],ContentType:e[1]})}));function e(e){r[e]&&0",">")),s.join("")}var $a={WB:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",SHEET:"http://sheetjs.openxmlformats.org/officeDocument/2006/relationships/officeDocument",HLINK:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",VML:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing",XPATH:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath",XMISS:"http://schemas.microsoft.com/office/2006/relationships/xlExternalLinkPath/xlPathMissing",XLINK:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink",CXML:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml",CXMLP:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps",CMNT:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments",CORE_PROPS:"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties",EXT_PROPS:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties",CUST_PROPS:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties",SST:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings",STY:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",THEME:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme",CHART:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart",CHARTEX:"http://schemas.microsoft.com/office/2014/relationships/chartEx",CS:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet",WS:["http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet","http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet"],DS:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet",MS:"http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet",IMG:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",DRAW:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing",XLMETA:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata",TCMNT:"http://schemas.microsoft.com/office/2017/10/relationships/threadedComment",PEOPLE:"http://schemas.microsoft.com/office/2017/10/relationships/person",VBA:"http://schemas.microsoft.com/office/2006/relationships/vbaProject"};function Xa(e){var t=e.lastIndexOf("/");return e.slice(0,t+1)+"_rels/"+e.slice(t+1)+".rels"}function Ya(e,a){var n={"!id":{}};if(!e)return n;"/"!==a.charAt(0)&&(a="/"+a);var s={};return(e.match(ft)||[]).forEach(function(e){var t,r=dt(e);"",r[1]=r[1].replace("/>",">")),r.join("")}function Ja(e,t,r,a,n,s){if(n=n||{},e["!id"]||(e["!id"]={}),e["!idx"]||(e["!idx"]=1),t<0)for(t=e["!idx"];e["!id"]["rId"+t];++t);if(e["!idx"]=t+1,n.Id="rId"+t,n.Type=a,n.Target=r,s?n.TargetMode=s:-1<[$a.HLINK,$a.XPATH,$a.XMISS].indexOf(n.Type)&&(n.TargetMode="External"),e["!id"][n.Id])throw new Error("Cannot rewrite rId "+t);return e["!id"][n.Id]=n,e[("/"+n.Target).replace("//","/")]=n,t}var qa="application/vnd.oasis.opendocument.spreadsheet";function Za(e,t,r){return[' \n',' \n'," \n"].join("")}function Qa(){return'SheetJS '+a.version+""}var en=[["cp:category","Category"],["cp:contentStatus","ContentStatus"],["cp:keywords","Keywords"],["cp:lastModifiedBy","LastAuthor"],["cp:lastPrinted","LastPrinted"],["cp:revision","RevNumber"],["cp:version","Version"],["dc:creator","Author"],["dc:description","Comments"],["dc:identifier","Identifier"],["dc:language","Language"],["dc:subject","Subject"],["dc:title","Title"],["dcterms:created","CreatedDate","date"],["dcterms:modified","ModifiedDate","date"]],tn=function(){for(var e=new Array(en.length),t=0;t]*>([\\s\\S]*?)")}return e}();function rn(e){var t={};e=Mt(e);for(var r=0;r",">")),a.join("")}var sn=[["Application","Application","string"],["AppVersion","AppVersion","string"],["Company","Company","string"],["DocSecurity","DocSecurity","string"],["Manager","Manager","string"],["HyperlinksChanged","HyperlinksChanged","bool"],["SharedDoc","SharedDoc","bool"],["LinksUpToDate","LinksUpToDate","bool"],["ScaleCrop","ScaleCrop","bool"],["HeadingPairs","HeadingPairs","raw"],["TitlesOfParts","TitlesOfParts","raw"]],on=["Worksheets","SheetNames","NamedRanges","DefinedNames","Chartsheets","ChartNames"];function cn(e,t,r,a){var n=[];if("string"==typeof e)n=Gt(e,a);else for(var s=0;sWorksheets")+n("vt:variant",n("vt:i4",String(r.Worksheets))),{size:2,baseType:"variant"})),a[a.length]=n("TitlesOfParts",n("vt:vector",r.SheetNames.map(function(e){return""+kt(e)+""}).join(""),{size:r.Worksheets,baseType:"lpstr"})),2",a[1]=a[1].replace("/>",">")),a.join("")}var fn=/<[^>]+>[^<]*/g;function hn(t){var r=[ot,Yt("Properties",null,{xmlns:Zt.CUST_PROPS,"xmlns:vt":Zt.vt})];if(!t)return r.join("");var a=1;return Re(t).forEach(function(e){++a,r[r.length]=Yt("property",function(e,t){switch(typeof e){case"string":var r=Yt("vt:lpwstr",kt(e));return r=t?r.replace(/"/g,"_x0022_"):r;case"number":return Yt((0|e)==e?"vt:i4":"vt:r8",kt(String(e)));case"boolean":return Yt("vt:bool",e?"true":"false")}if(e instanceof Date)return Yt("vt:filetime",Kt(e));throw new Error("Unable to serialize "+e)}(t[e],!0),{fmtid:"{D5CDD505-2E9C-101B-9397-08002B2CF9AE}",pid:a,name:kt(e)})}),2",r[1]=r[1].replace("/>",">")),r.join("")}var un,dn={Title:"Title",Subject:"Subject",Author:"Author",Keywords:"Keywords",Comments:"Description",LastAuthor:"LastAuthor",RevNumber:"Revision",Application:"AppName",LastPrinted:"LastPrinted",CreatedDate:"Created",ModifiedDate:"LastSaved",Category:"Category",Manager:"Manager",Company:"Company",AppVersion:"Version",ContentStatus:"ContentStatus",Identifier:"Identifier",Language:"Language"};function pn(e){var t=e.read_shift(4),e=e.read_shift(4);return new Date(1e3*(e/1e7*Math.pow(2,32)+t/1e7-11644473600)).toISOString().replace(/\.000/,"")}function mn(e,t,r){var a=e.l,n=e.read_shift(0,"lpstr-cp");if(r)for(;e.l-a&3;)++e.l;return n}function gn(e,t,r){var a=e.read_shift(0,"lpwstr");return r&&(e.l+=4-(a.length+1&3)&3),a}function bn(e,t,r){return 31===t?gn(e):mn(e,0,r)}function vn(e,t,r){return bn(e,t,!1===r?0:4)}function wn(e){for(var t,r,a,n=e.read_shift(4),s=[],i=0;i>3<<2),a}function En(e){var t=e.read_shift(4),r=e.slice(e.l,e.l+t);return e.l+=t,0<(3&t)&&(e.l+=4-(3&t)&3),r}function kn(e,t,r){var a,n,s=e.read_shift(2),i=r||{};if(e.l+=2,t!==Na&&s!==t&&-1===Da.indexOf(t)&&(4126!=(65534&t)||4126!=(65534&s)))throw new Error("Expected type "+t+" saw "+s);switch(t===Na?s:t){case 2:return a=e.read_shift(2,"i"),i.raw||(e.l+=2),a;case 3:return a=e.read_shift(4,"i");case 11:return 0!==e.read_shift(4);case 19:return a=e.read_shift(4);case 30:return mn(e,0,4).replace(de,"");case 31:return gn(e);case 64:return pn(e);case 65:return En(e);case 71:return(n={}).Size=(a=e).read_shift(4),a.l+=n.Size+3-(n.Size-1)%4,n;case 80:return vn(e,s,!i.raw).replace(de,"");case 81:return function(e,t){if(!t)throw new Error("VtUnalignedString must have positive length");return bn(e,t,0)}(e,s).replace(de,"");case 4108:return wn(e);case 4126:case 4127:return(4127==s?function(e){for(var t=e.read_shift(4),r=[],a=0;a!=t;++a){var n=e.l;r[a]=e.read_shift(0,"lpwstr").replace(de,""),e.l-n&2&&(e.l+=2)}return r}:function(e){for(var t=e.read_shift(4),r=[],a=0;a!=t;++a)r[a]=e.read_shift(0,"lpstr-cp").replace(de,"");return r})(e);default:throw new Error("TypedPropertyValue unrecognized type "+t+" "+s)}}function yn(e,t){var r,a,n,s=Lr(4),i=Lr(4);switch(s.write_shift(4,80==e?31:e),e){case 3:i.write_shift(-4,t);break;case 5:(i=Lr(8)).write_shift(8,t,"f");break;case 11:i.write_shift(4,t?1:0);break;case 64:a=("string"==typeof(r=t)?new Date(Date.parse(r)):r).getTime()/1e3+11644473600,n=a%Math.pow(2,32),r=(a-n)/Math.pow(2,32),r*=1e7,0<(a=(n*=1e7)/Math.pow(2,32)|0)&&(n%=Math.pow(2,32),r+=a),(a=Lr(8)).write_shift(4,n),a.write_shift(4,r),i=a;break;case 31:case 80:for((i=Lr(4+2*(t.length+1)+(t.length%2?0:2))).write_shift(4,t.length+1),i.write_shift(0,t,"dbcs");i.l!=i.length;)i.write_shift(1,0);break;default:throw new Error("TypedPropertyValue unrecognized type "+e+" "+t)}return ue([s,i])}function Sn(e,t){for(var r=e.l,a=e.read_shift(4),n=e.read_shift(4),s=[],i=0,o=0,c=-1,l={},i=0;i!=n;++i){var f=e.read_shift(4),h=e.read_shift(4);s[i]=[f,h+r]}s.sort(function(e,t){return e[1]-t[1]});var u={};for(i=0;i!=n;++i){if(e.l!==s[i][1]){var d=!0;if(0>16)+"."+("0000"+String(65535&u[p.n])).slice(-4)),"CodePage"==p.n)switch(u[p.n]){case 0:u[p.n]=1252;case 874:case 932:case 936:case 949:case 950:case 1250:case 1251:case 1253:case 1254:case 1255:case 1256:case 1257:case 1258:case 1e4:case 1200:case 1201:case 1252:case 65e3:case-536:case 65001:case-535:ie(o=u[p.n]>>>0&65535);break;default:throw new Error("Unsupported CodePage: "+u[p.n])}}else if(1===s[i][0]){o=u.CodePage=kn(e,Oa);ie(o),-1!==c&&(g=e.l,e.l=s[c][1],l=Tn(e,o),e.l=g)}else if(0===s[i][0])0!==o?l=Tn(e,o):(c=i,e.l=s[i+1][1]);else{var m,g=l[s[i][0]];switch(e[e.l]){case 65:e.l+=4,m=En(e);break;case 30:case 31:e.l+=4,m=vn(e,e[e.l-4]).replace(/\u0000+$/,"");break;case 3:e.l+=4,m=e.read_shift(4,"i");break;case 19:e.l+=4,m=e.read_shift(4);break;case 5:e.l+=4,m=e.read_shift(8,"f");break;case 11:e.l+=4,m=On(e,4);break;case 64:e.l+=4,m=He(pn(e));break;default:throw new Error("unparsed value: "+e[e.l])}u[g]=m}}return e.l=r+a,u}var _n=["CodePage","Thumbnail","_PID_LINKBASE","_PID_HLINKS","SystemIdentifier","FMTID"];function xn(e,t,r){var a,n,s,i,o=Lr(8),c=[],l=[],f=8,h=0,u=Lr(8),d=Lr(8);if(u.write_shift(4,2),u.write_shift(4,1200),d.write_shift(4,1),l.push(u),c.push(d),f+=8+u.length,!t){(d=Lr(8)).write_shift(4,0),c.unshift(d);var p=[Lr(4)];for(p[0].write_shift(4,e.length),h=0;h>1,"utf16le").replace(de,""),n&&(t.l+=24),r;case"0303000000000000c000000000000046":return function(e){for(var t=e.read_shift(2),r="";0>1,"utf16le").replace(de,"")}(e);default:throw new Error("Unsupported Moniker "+s)}}function zn(e){var t=e.read_shift(4);return 0>15),e&=32767),[{Unsynced:1&a,DyZero:(2&a)>>1,ExAsc:(4&a)>>2,ExDsc:(8&a)>>3},e]}var is=Bn;function os(e,t,r){var a=e.l+t,n=8!=r.biff&&r.biff?2:4,s=e.read_shift(n),t=e.read_shift(n),r=e.read_shift(2),n=e.read_shift(2);return e.l=a,{s:{r:s,c:r},e:{r:t,c:n}}}function cs(e,t,r,a){r=r&&5==r.biff;(a=a||Lr(r?16:20)).write_shift(2,0),e.style?(a.write_shift(2,e.numFmtId||0),a.write_shift(2,65524)):(a.write_shift(2,e.numFmtId||0),a.write_shift(2,t<<4));t=0;return 0>>1&1,fWantPict:n>>>2&1,fOle:n>>>3&1,fOleLink:n>>>4&1,cf:n>>>5&1023,fIcon:n>>>15&1};return 14849===r.sbcch&&(a=function(e,t,r){e.l+=4,t-=4;var a=e.l+t,t=Ln(e,0,r);if((r=e.read_shift(2))!==(a-=e.l))throw new Error("Malformed AddinUdf: padding = "+a+" != "+r);return e.l+=r,t}(e,t-2,r)),n.body=a||e.read_shift(t-2),"string"==typeof a&&(n.Name=a),n}var us=["_xlnm.Consolidate_Area","_xlnm.Auto_Open","_xlnm.Auto_Close","_xlnm.Extract","_xlnm.Database","_xlnm.Criteria","_xlnm.Print_Area","_xlnm.Print_Titles","_xlnm.Recorder","_xlnm.Data_Form","_xlnm.Auto_Activate","_xlnm.Auto_Deactivate","_xlnm.Sheet_Title","_xlnm._FilterDatabase"];function ds(e,t,r){var a=e.l+t,n=e.read_shift(2),s=e.read_shift(1),i=e.read_shift(1),o=e.read_shift(r&&2==r.biff?1:2),t=0;(!r||5<=r.biff)&&(5!=r.biff&&(e.l+=2),t=e.read_shift(2),5==r.biff&&(e.l+=2),e.l+=4);i=Mn(e,i,r);32&n&&(i=us[i.charCodeAt(0)]);n=a-e.l;return r&&2==r.biff&&--n,{chKey:s,Name:i,itab:t,rgce:a!=e.l&&0!==o&&0>8&7),o}var ws=$n,Ts=Dn,Es=Un;var ks,ys,Ss,_s=[2,3,48,49,131,139,140,245],xs=(ks={1:437,2:850,3:1252,4:1e4,100:852,101:866,102:865,103:861,104:895,105:620,106:737,107:857,120:950,121:949,122:936,123:932,124:874,125:1255,126:1256,150:10007,151:10029,152:10006,200:1250,201:1251,202:1254,203:1253,0:20127,8:865,9:437,10:850,11:437,13:437,14:850,15:437,16:850,17:437,18:850,19:932,20:850,21:437,22:850,23:865,24:437,25:437,26:850,27:437,28:863,29:850,31:852,34:852,35:852,36:860,37:850,38:866,55:850,64:852,77:936,78:949,79:950,80:874,87:1252,88:1252,89:1252,108:863,134:737,135:852,136:857,204:1257,255:16969},ys=Ie({1:437,2:850,3:1252,4:1e4,100:852,101:866,102:865,103:861,104:895,105:620,106:737,107:857,120:950,121:949,122:936,123:932,124:874,125:1255,126:1256,150:10007,151:10029,152:10006,200:1250,201:1251,202:1254,203:1253,0:20127}),Ss={B:8,C:250,L:1,D:8,"?":0,"":0},{to_workbook:function(e,t){try{return ta(As(e,t),t)}catch(e){if(t&&t.WTF)throw e}return{SheetNames:[],Sheets:{}}},to_sheet:As,from_sheet:function(e,t){if(0<=+(t=t||{}).codepage&&ie(+t.codepage),"string"==t.type)throw new Error("Cannot write DBF to JS string");for(var r=Ur(),a=(t=iu(e,{header:1,raw:!0,cellDates:!0}))[0],n=t.slice(1),s=e["!cols"]||[],i=0,o=0,c=0,l=1,i=0;ig&&(g=s[i].DBF.len),"B"==p&&"N"==m&&(p="N",d[i]=s[i].DBF.dec,g=s[i].DBF.len),u[i]="C"==p||"N"==m?g:Ss[p]||0,l+=u[i],h[i]=p}else h[i]="?"}var v,w,T=r.next(32);for(T.write_shift(4,318902576),T.write_shift(4,n.length),T.write_shift(2,296+32*c),T.write_shift(2,l),i=0;i<4;++i)T.write_shift(4,0);for(T.write_shift(4,0|(+ys[_]||3)<<8),o=i=0;i":190,"?":191,"{":223},Rs=new RegExp("N("+Re(Cs).join("|").replace(/\|\|\|/,"|\\||").replace(/([?()+])/g,"\\$1")+"|\\|)","gm"),Os=function(e,t){t=Cs[t];return"number"==typeof t?n(t):t},Is=function(e,t,r){r=t.charCodeAt(0)-32<<4|r.charCodeAt(0)-48;return 59==r?e:n(r)},Cs["|"]=254,{to_workbook:function(e,t){return ta(Ds(e,t),t)},to_sheet:Ds,from_sheet:function(e,t){var r,a,n=["ID;PWXL;N;E"],s=[],i=Zr(e["!ref"]),o=Array.isArray(e),c="\r\n";n.push("P;PGeneral"),n.push("F;P0;DG0G8;M255"),e["!cols"]&&(r=n,e["!cols"].forEach(function(e,t){t="F;W"+(t+1)+" "+(t+1)+" ";e.hidden?t+="0":("number"!=typeof e.width||e.wpx||(e.wpx=so(e.width)),"number"!=typeof e.wpx||e.wch||(e.wch=io(e.wpx)),"number"==typeof e.wch&&(t+=Math.round(e.wch)))," "!=t.charAt(t.length-1)&&r.push(t)})),e["!rows"]&&(a=n,e["!rows"].forEach(function(e,t){var r="F;";e.hidden?r+="M0;":e.hpt?r+="M"+20*e.hpt+";":e.hpx&&(r+="M"+20*uo(e.hpx)+";"),2","<=",">=","<",">","","","","","&","","","","","","",""],ai={0:{n:"BOF",f:Nn},1:{n:"EOF"},2:{n:"CALCMODE"},3:{n:"CALCORDER"},4:{n:"SPLIT"},5:{n:"SYNC"},6:{n:"RANGE",f:function(e,t,r){var a={s:{c:0,r:0},e:{c:0,r:0}};return 8==t&&r.qpro?(a.s.c=e.read_shift(1),e.l++,a.s.r=e.read_shift(2),a.e.c=e.read_shift(1),e.l++,a.e.r=e.read_shift(2)):(a.s.c=e.read_shift(2),a.s.r=e.read_shift(2),12==t&&r.qpro&&(e.l+=2),a.e.c=e.read_shift(2),a.e.r=e.read_shift(2),12==t&&r.qpro&&(e.l+=2),65535==a.s.c&&(a.s.c=a.e.c=a.s.r=a.e.r=0)),a}},7:{n:"WINDOW1"},8:{n:"COLW1"},9:{n:"WINTWO"},10:{n:"COLW2"},11:{n:"NAME"},12:{n:"BLANK"},13:{n:"INTEGER",f:function(e,t,r){return(r=ci(e,0,r))[1].v=e.read_shift(2,"i"),r}},14:{n:"NUMBER",f:function(e,t,r){return(r=ci(e,0,r))[1].v=e.read_shift(8,"f"),r}},15:{n:"LABEL",f:li},16:{n:"FORMULA",f:function(e,t,r){var a=e.l+t;return(t=ci(e,0,r))[1].v=e.read_shift(8,"f"),r.qpro?e.l=a:(a=e.read_shift(2),function(e,t){Dr(e,0);for(var r=[],a=0,n="",s="",i="",o="";e.lr.length)return console.error("WK1 bad formula parse 0x"+c.toString(16)+":|"+r.join("|")+"|");f=r.slice(-a);r.length-=a,r.push(ti[c][0]+"("+f.join(",")+")")}}}1==r.length?t[1].f=""+r[0]:console.error("WK1 bad formula parse |"+r.join("|")+"|")}(e.slice(e.l,e.l+a),t),e.l+=a),t}},24:{n:"TABLE"},25:{n:"ORANGE"},26:{n:"PRANGE"},27:{n:"SRANGE"},28:{n:"FRANGE"},29:{n:"KRANGE1"},32:{n:"HRANGE"},35:{n:"KRANGE2"},36:{n:"PROTEC"},37:{n:"FOOTER"},38:{n:"HEADER"},39:{n:"SETUP"},40:{n:"MARGINS"},41:{n:"LABELFMT"},42:{n:"TITLES"},43:{n:"SHEETJS"},45:{n:"GRAPH"},46:{n:"NGRAPH"},47:{n:"CALCCOUNT"},48:{n:"UNFORMATTED"},49:{n:"CURSORW12"},50:{n:"WINDOW"},51:{n:"STRING",f:li},55:{n:"PASSWORD"},56:{n:"LOCKED"},60:{n:"QUERY"},61:{n:"QUERYNAME"},62:{n:"PRINT"},63:{n:"PRINTNAME"},64:{n:"GRAPH2"},65:{n:"GRAPHNAME"},66:{n:"ZOOM"},67:{n:"SYMSPLIT"},68:{n:"NSROWS"},69:{n:"NSCOLS"},70:{n:"RULER"},71:{n:"NNAME"},72:{n:"ACOMM"},73:{n:"AMACRO"},74:{n:"PARSE"},102:{n:"PRANGES??"},103:{n:"RRANGES??"},104:{n:"FNAME??"},105:{n:"MRANGES??"},204:{n:"SHEETNAMECS",f:pi},222:{n:"SHEETNAMELP",f:function(e,t){var r=e[e.l++];t-1>1;if(1&r[1].v)switch(7&a){case 0:a=5e3*(a>>3);break;case 1:a=500*(a>>3);break;case 2:a=(a>>3)/20;break;case 3:a=(a>>3)/200;break;case 4:a=(a>>3)/2e3;break;case 5:a=(a>>3)/2e4;break;case 6:a=(a>>3)/16;break;case 7:a=(a>>3)/64}return r[1].v=a,r}},25:{n:"FORMULA19",f:function(e,t){var r=ui(e);return e.l+=t-14,r}},26:{n:"FORMULA1A"},27:{n:"XFORMAT",f:function(e,t){for(var r={},a=e.l+t;e.l>6,r}},38:{n:"??"},39:{n:"NUMBER27",f:di},40:{n:"FORMULA28",f:function(e,t){var r=di(e);return e.l+=t-10,r}},142:{n:"??"},147:{n:"??"},150:{n:"??"},151:{n:"??"},152:{n:"??"},153:{n:"??"},154:{n:"??"},155:{n:"??"},156:{n:"??"},163:{n:"??"},174:{n:"??"},175:{n:"??"},176:{n:"??"},177:{n:"??"},184:{n:"??"},185:{n:"??"},186:{n:"??"},187:{n:"??"},188:{n:"??"},195:{n:"??"},201:{n:"??"},204:{n:"SHEETNAMECS",f:pi},205:{n:"??"},206:{n:"??"},207:{n:"??"},208:{n:"??"},256:{n:"??"},259:{n:"??"},260:{n:"??"},261:{n:"??"},262:{n:"??"},263:{n:"??"},265:{n:"??"},266:{n:"??"},267:{n:"??"},268:{n:"??"},270:{n:"??"},271:{n:"??"},384:{n:"??"},389:{n:"??"},390:{n:"??"},393:{n:"??"},396:{n:"??"},512:{n:"??"},514:{n:"??"},513:{n:"??"},516:{n:"??"},517:{n:"??"},640:{n:"??"},641:{n:"??"},642:{n:"??"},643:{n:"??"},644:{n:"??"},645:{n:"??"},646:{n:"??"},647:{n:"??"},648:{n:"??"},658:{n:"??"},659:{n:"??"},660:{n:"??"},661:{n:"??"},662:{n:"??"},665:{n:"??"},666:{n:"??"},768:{n:"??"},772:{n:"??"},1537:{n:"SHEETINFOQP",f:function(e,t,r){if(r.qpro&&!(t<21)){r=e.read_shift(1);return e.l+=17,e.l+=1,e.l+=2,[r,e.read_shift(t-21,"cstr")]}}},1600:{n:"??"},1602:{n:"??"},1793:{n:"??"},1794:{n:"??"},1795:{n:"??"},1796:{n:"??"},1920:{n:"??"},2048:{n:"??"},2049:{n:"??"},2052:{n:"??"},2688:{n:"??"},10998:{n:"??"},12849:{n:"??"},28233:{n:"??"},28484:{n:"??"},65535:{n:""}},{sheet_to_wk1:function(e,t){var r=t||{};if(0<=+r.codepage&&ie(+r.codepage),"string"==r.type)throw new Error("Cannot write WK1 to JS string");var a=Ur(),n=Zr(e["!ref"]),s=Array.isArray(e),i=[];Lf(a,0,(t=1030,(r=Lr(2)).write_shift(2,t),r)),Lf(a,6,(t=n,(r=Lr(8)).write_shift(2,t.s.c),r.write_shift(2,t.s.r),r.write_shift(2,t.e.c),r.write_shift(2,t.e.r),r));for(var o,c,l,f,h=Math.min(n.e.r,8191),u=n.s.r;u<=h;++u)for(var d=jr(u),p=n.s.c;p<=n.e.c;++p){u===n.s.r&&(i[p]=Xr(p));var m=i[p]+d,m=s?(e[u]||[])[p]:e[m];m&&"z"!=m.t&&("n"==m.t?(0|m.v)==m.v&&-32768<=m.v&&m.v<=32767?Lf(a,13,(o=u,c=p,l=m.v,f=void 0,(f=Lr(7)).write_shift(1,255),f.write_shift(2,c),f.write_shift(2,o),f.write_shift(2,l,"i"),f)):Lf(a,14,(c=u,o=p,l=m.v,f=void 0,(f=Lr(13)).write_shift(1,255),f.write_shift(2,o),f.write_shift(2,c),f.write_shift(8,l,"f"),f)):Lf(a,15,function(e,t,r){var a=Lr(7+r.length);a.write_shift(1,255),a.write_shift(2,t),a.write_shift(2,e),a.write_shift(1,39);for(var n=0;n>>0))&&(++e,t=(a/=2)>>>0);return a-=t,t|=2147483648,t>>>=0,a*=Math.pow(2,32),r=a>>>0,n.write_shift(4,r),n.write_shift(4,t),e+=16383+(s?32768:0),n.write_shift(2,e),n}(h,d,s,p.v)):Lf(r,22,function(e,t,r,a){var n=Lr(6+a.length);n.write_shift(2,e),n.write_shift(1,r),n.write_shift(1,t),n.write_shift(1,39);for(var s=0;sc&&(s["!ref"]=qr(h),l[i]=s,f.push(i),s=n.dense?[]:{},h={s:{r:0,c:0},e:{r:0,c:0}},c=e[3],i=o||"Sheet"+(c+1),o="");var a=n.dense?(s[e[0].r]||[])[e[0].c]:s[Kr(e[0])];if(a){a.t=e[1].t,a.v=e[1].v,null!=e[1].z&&(a.z=e[1].z),null!=e[1].f&&(a.f=e[1].f);break}n.dense?(s[e[0].r]||(s[e[0].r]=[]),s[e[0].r][e[0].c]=e[1]):s[Kr(e[0])]=e[1]}},n);else{if(26!=e[2]&&14!=e[2])throw new Error("Unrecognized LOTUS BOF "+e[2]);n.Enum=ni,14==e[2]&&(n.qpro=!0,e.l=0),ii(e,function(e,t,r){switch(r){case 204:i=e;break;case 22:e[1].v=e[1].v.slice(1);case 23:case 24:case 25:case 37:case 39:case 40:if(e[3]>c&&(s["!ref"]=qr(h),l[i]=s,f.push(i),s=n.dense?[]:{},h={s:{r:0,c:0},e:{r:0,c:0}},c=e[3],i="Sheet"+(c+1)),0=u)break;n.dense?(s[e[0].r]||(s[e[0].r]=[]),s[e[0].r][e[0].c]=e[1]):s[Kr(e[0])]=e[1],h.e.c/g,vi=/<\/(?:\w+:)?r>/,function(e){return e.replace(bi,"").split(vi).map(Ti).filter(function(e){return e.v})});function Ti(e){var t=e.match(mi);if(!t)return{t:"s",v:""};t={t:"s",v:wt(t[1])},e=e.match(gi);return e&&(t.s=function(e){var t={},r=e.match(ft),a=0,n=!1;if(r)for(;a!=r.length;++a){var s=dt(r[a]);switch(s[0].replace(/\w*:/g,"")){case"":case"":t.shadow=1;break;case"":break;case"":case"":t.outline=1;break;case"":break;case"":case"":t.strike=1;break;case"":break;case"":case"":t.u=1;break;case"":break;case"":case"":t.b=1;break;case"":break;case"":case"":t.i=1;break;case"":break;case"":case"":case"":break;case"":case"":case"":break;case"":case"":case"":case"":case"":case"":break;case"":case"":break;case"":n=!1;break;default:if(47!==s[0].charCodeAt(1)&&!n)throw new Error("Unrecognized rich format "+s[0])}}return t}(e[1])),t}var Ei,ki=(Ei=/(\r\n|\n)/g,function(e){return e.map(yi).join("")});function yi(e){var t,r,a,n=[[],e.v,[]];return e.v?(e.s&&(t=e.s,r=n[0],a=n[2],e=[],t.u&&e.push("text-decoration: underline;"),t.uval&&e.push("text-underline-style:"+t.uval+";"),t.sz&&e.push("font-size:"+t.sz+"pt;"),t.outline&&e.push("text-effect: outline;"),t.shadow&&e.push("text-shadow: auto;"),r.push(''),t.b&&(r.push(""),a.push("")),t.i&&(r.push(""),a.push("")),t.strike&&(r.push(""),a.push("")),"superscript"==(e=t.valign||"")||"super"==e?e="sup":"subscript"==e&&(e="sub"),""!=e&&(r.push("<"+e+">"),a.push("")),a.push("")),n[0].join("")+n[1].replace(Ei,"
")+n[2].join("")):""}var Si=/<(?:\w+:)?t[^>]*>([^<]*)<\/(?:\w+:)?t>/g,_i=/<(?:\w+:)?r>/,xi=/<(?:\w+:)?rPh.*?>([\s\S]*?)<\/(?:\w+:)?rPh>/g;function Ai(e,t){var r=!t||t.cellHTML,t={};return e?(e.match(/^\s*<(?:\w+:)?t[^>]*>/)?(t.t=wt(Mt(e.slice(e.indexOf(">")+1).split(/<\/(?:\w+:)?t>/)[0]||"")),t.r=Mt(e),r&&(t.h=_t(t.t))):e.match(_i)&&(t.r=Mt(e),t.t=wt(Mt((e.replace(xi,"").match(Si)||[]).join("").replace(ft,""))),r&&(t.h=ki(wi(t.r)))),t):{t:""}}var Ci=/<(?:\w+:)?sst([^>]*)>([\s\S]*)<\/(?:\w+:)?sst>/,Ri=/<(?:\w+:)?(?:si|sstItem)>/g,Oi=/<\/(?:\w+:)?(?:si|sstItem)>/;var Ii=/^\s|\s$|[\t\n\r]/;function Ni(e,t){if(!t.bookSST)return"";var r=[ot];r[r.length]=Yt("sst",null,{xmlns:Qt[0],count:e.Count,uniqueCount:e.Unique});for(var a,n,s=0;s!=e.length;++s)null!=e[s]&&(n="",(a=e[s]).r?n+=a.r:(n+=""),n+="",r[r.length]=n);return 2",r[1]=r[1].replace("/>",">")),r.join("")}var Fi=function(e,t){var r=!1;return null==t&&(r=!0,t=Lr(15+4*e.t.length)),t.write_shift(1,0),ia(e.t,t),r?t.slice(0,t.l):t};function Di(e){var t,r,a=Ur();Br(a,159,(t=e,(r=r||Lr(8)).write_shift(4,t.Count),r.write_shift(4,t.Unique),r));for(var n=0;n>1,"utf16le"),e.l=t,r}function Wi(e,t){var r={},t=e.l+t;return e.l+=4,r.Salt=e.slice(e.l,e.l+16),e.l+=16,r.Verifier=e.slice(e.l,e.l+16),e.l+=16,e.read_shift(4),r.VerifierHash=e.slice(e.l,t),e.l=t,r}function Hi(e){var t=Li(e);switch(t.Minor){case 2:return[t.Minor,function(e){if(36!=(63&e.read_shift(4)))throw new Error("EncryptionInfo mismatch");var t=e.read_shift(4),t=Bi(e,t),e=Wi(e,e.length-e.l);return{t:"Std",h:t,v:e}}(e)];case 3:return[t.Minor,function(){throw new Error("File is password-protected: ECMA-376 Extensible")}()];case 4:return[t.Minor,function(e){var r=["saltSize","blockSize","keyBits","hashSize","cipherAlgorithm","cipherChaining","hashAlgorithm","saltValue"];e.l+=4;var e=e.read_shift(e.length-e.l,"utf8"),a={};return e.replace(ft,function(e){var t=dt(e);switch(pt(t[0])){case"":break;case"":case"":break;case"":break;case">8,i[s]=Xi(Vi[0],t),--s,t=255&n,e=a[a.length-1],i[s]=Xi(e,t));0>8,i[--s]=Xi(a[s],t),t=255&n,i[--s]=Xi(a[s],t);for(r=(s=15)-a.length;0>8,i[s]=Xi(Vi[r],t),--r,t=255&n,i[--s]=Xi(a[s],t),--s,--r;return i});function Xi(e,t){return 255&((t=e^t)/2|128*t)}var Yi=function(e){var t=0,r=$i(e);return function(e){e=function(e,t,r,a,n){var s,i;for(n=n||t,a=a||$i(e),s=0;s!=t.length;++s)i=t[s],i=255&((i^=a[r])>>5|i<<3),n[s]=i,++r;return[n,r,a]}("",e,t,r);return t=e[1],e[0]}};function Ki(e,t,r){r=r||{};return r.Info=e.read_shift(2),e.l-=2,1===r.Info?r.Data=function(e){var t={},r=t.EncryptionVersionInfo=Li(e,4);if(1!=r.Major||1!=r.Minor)throw"unrecognized version code "+r.Major+" : "+r.Minor;return t.Salt=e.read_shift(16),t.EncryptedVerifier=e.read_shift(16),t.EncryptedVerifierHash=e.read_shift(16),t}(e):r.Data=function(e,t){var r={},a=r.EncryptionVersionInfo=Li(e,4);if(t-=4,2!=a.Minor)throw new Error("unrecognized minor version code: "+a.Minor);if(4o.e.c&&(o.e.c=s)}),i["!ref"]=qr(o),i}function Qi(e){for(var t=0,r=1;3!=t;++t)r=256*r+(255]*)>[\S\s]*?<\/(?:\w+:)?numFmts>/,wo=/<(?:\w+:)?cellXfs([^>]*)>[\S\s]*?<\/(?:\w+:)?cellXfs>/,To=/<(?:\w+:)?fills([^>]*)>[\S\s]*?<\/(?:\w+:)?fills>/,Eo=/<(?:\w+:)?fonts([^>]*)>[\S\s]*?<\/(?:\w+:)?fonts>/,ko=/<(?:\w+:)?borders([^>]*)>[\S\s]*?<\/(?:\w+:)?borders>/,function(e,t,r){var a,n,s,i,o,c={};return e&&((a=(e=e.replace(//gm,"").replace(//gm,"")).match(vo))&&function(e,t,r){t.NumberFmt=[];for(var a=Re(me),n=0;n":case"":case"":break;case"":break;default:if(r.WTF)throw new Error("unrecognized "+i[0]+" in numFmts")}}}(a,c,r),(a=e.match(Eo))&&function(e,a,n,s){a.Fonts=[];var i={},o=!1;(e[0].match(ft)||[]).forEach(function(e){var t,r=dt(e);switch(pt(r[0])){case"":case"":break;case"":break;case"":case"":a.Fonts.push(i),i={};break;case"":case"":break;case"":i.bold=1;break;case"":i.italic=1;break;case"":i.underline=1;break;case"":i.strike=1;break;case"":i.outline=1;break;case"":i.shadow=1;break;case"":i.condense=1;break;case"":i.extend=1;break;case"":case"":break;case"":case"":break;case"":case"":break;case"":case"":break;case"":case"":break;case"":o=!1;break;case"":case"":break;case"":o=!1;break;default:if(s&&s.WTF&&!o)throw new Error("unrecognized "+r[0]+" in fonts")}})}(a,c,t,r),(a=e.match(To))&&function(e,r,a){r.Fills=[];var n={},s=!1;(e[0].match(ft)||[]).forEach(function(e){var t=dt(e);switch(pt(t[0])){case"":case"":break;case"":case"":n={},r.Fills.push(n);break;case"":case"":break;case"":r.Fills.push(n),n={};break;case"":t.patternType&&(n.patternType=t.patternType);break;case"":case"":break;case"":case"":break;case"":case"":break;case"":case"":break;case"":case"":break;case"":case"":break;case"":s=!1;break;default:if(a&&a.WTF&&!s)throw new Error("unrecognized "+t[0]+" in fills")}})}(a,c,r),(a=e.match(ko))&&function(e,r,a){r.Borders=[];var n={},s=!1;(e[0].match(ft)||[]).forEach(function(e){var t=dt(e);switch(pt(t[0])){case"":case"":break;case"":case"":n={},t.diagonalUp&&(n.diagonalUp=Rt(t.diagonalUp)),t.diagonalDown&&(n.diagonalDown=Rt(t.diagonalDown)),r.Borders.push(n);break;case"":case"":break;case"":case"":case"":break;case"":case"":case"":break;case"":case"":case"":break;case"":case"":break;case"":case"":case"":break;case"":case"":case"":break;case"":case"":case"":break;case"":case"":case"":break;case"":case"":case"":break;case"":break;case"":case"":break;case"":case"":break;case"":s=!1;break;default:if(a&&a.WTF&&!s)throw new Error("unrecognized "+t[0]+" in borders")}})}(a,c,r),(a=e.match(wo))&&(a=a,s=r,o=!((n=c).CellXf=[]),(a[0].match(ft)||[]).forEach(function(e){var t=dt(e),r=0;switch(pt(t[0])){case"":case"":case"":break;case"":for(delete(i=t)[0],r=0;r":break;case"":var a={};t.vertical&&(a.vertical=t.vertical),t.horizontal&&(a.horizontal=t.horizontal),null!=t.textRotation&&(a.textRotation=t.textRotation),t.indent&&(a.indent=t.indent),t.wrapText&&(a.wrapText=Rt(t.wrapText)),i.alignment=a;break;case"":case"":case"":break;case"":o=!1;break;case"":case"":break;case"":o=!1;break;default:if(s&&s.WTF&&!o)throw new Error("unrecognized "+t[0]+" in cellXfs")}}))),c});function _o(e,t){if(void 0!==yo)return yo.toXml();var r,a,n,s,i=[ot,Yt("styleSheet",null,{xmlns:Qt[0],"xmlns:vt":Zt.vt})];return e.SSF&&null!=(a=e.SSF,n=[""],[[5,8],[23,26],[41,44],[50,392]].forEach(function(e){for(var t=e[0];t<=e[1];++t)null!=a[t]&&(n[n.length]=Yt("numFmt",null,{numFmtId:t,formatCode:kt(a[t])}))}),r=1===n.length?"":(n[n.length]="",n[0]=Yt("numFmts",null,{count:n.length-2}).replace("/>",">"),n.join("")))&&(i[i.length]=r),i[i.length]='',i[i.length]='',i[i.length]='',i[i.length]='',t=t.cellXfs,(s=[])[s.length]="",t.forEach(function(e){s[s.length]=Yt("xf",null,e)}),s[s.length]="",(r=2===s.length?"":(s[0]=Yt("cellXfs",null,{count:s.length-2}).replace("/>",">"),s.join("")))&&(i[i.length]=r),i[i.length]='',i[i.length]='',i[i.length]='',2",i[1]=i[1].replace("/>",">")),i.join("")}function xo(e,t){var r;(t=t||Lr(153)).write_shift(2,20*e.sz),r=e,a=(a=t)||Lr(2),r=(r.italic?2:0)|(r.strike?8:0)|(r.outline?16:0)|(r.shadow?32:0)|(r.condense?64:0)|(r.extend?128:0),a.write_shift(1,r),a.write_shift(1,0),t.write_shift(2,e.bold?700:400);var a=0;"superscript"==e.vertAlign?a=1:"subscript"==e.vertAlign&&(a=2),t.write_shift(2,a),t.write_shift(1,e.underline||0),t.write_shift(1,e.family||0),t.write_shift(1,e.charset||0),t.write_shift(1,0),Ca(e.color,t);a=0;return"major"==e.scheme&&(a=1),"minor"==e.scheme&&(a=2),t.write_shift(1,a),ia(e.name,t),t.length>t.l?t.slice(0,t.l):t}var Ao,Co=["none","solid","mediumGray","darkGray","lightGray","darkHorizontal","darkVertical","darkDown","darkUp","darkGrid","darkTrellis","lightHorizontal","lightVertical","lightDown","lightUp","lightGrid","lightTrellis","gray125","gray0625"],Ro=Pr;function Oo(e,t){t=t||Lr(84);e=(Ao=Ao||Ie(Co))[e.patternType];null==e&&(e=40),t.write_shift(4,e);var r=0;if(40!=e)for(Ca({auto:1},t),Ca({auto:1},t);r<12;++r)t.write_shift(4,0);else{for(;r<4;++r)t.write_shift(4,0);for(;r<12;++r)t.write_shift(4,0)}return t.length>t.l?t.slice(0,t.l):t}function Io(e,t,r){(r=r||Lr(16)).write_shift(2,t||0),r.write_shift(2,e.numFmtId||0),r.write_shift(2,0),r.write_shift(2,0),r.write_shift(2,0),r.write_shift(1,0),r.write_shift(1,0);return r.write_shift(1,0),r.write_shift(1,0),r.write_shift(1,0),r.write_shift(1,0),r}function No(e,t){return(t=t||Lr(10)).write_shift(1,0),t.write_shift(1,0),t.write_shift(4,0),t.write_shift(4,0),t}r=Pr;function Fo(s,i){var r;i&&(r=0,[[5,8],[23,26],[41,44],[50,392]].forEach(function(e){for(var t=e[0];t<=e[1];++t)null!=i[t]&&++r}),0!=r&&(Br(s,615,na(r)),[[5,8],[23,26],[41,44],[50,392]].forEach(function(e){for(var t,r,a,n=e[0];n<=e[1];++n)null!=i[n]&&Br(s,44,(t=n,r=i[n],(a=(a=void 0)||Lr(6+4*r.length)).write_shift(2,t),ia(r,a),r=a.length>a.l?a.slice(0,a.l):a,null==a.l&&(a.l=a.length),r))}),Br(s,616)))}function Do(e){var t;Br(e,613,na(1)),Br(e,46,((t=t||Lr(51)).write_shift(1,0),No(0,t),No(0,t),No(0,t),No(0,t),No(0,t),t.length>t.l?t.slice(0,t.l):t)),Br(e,614)}function Po(e){var t,r;Br(e,619,na(1)),Br(e,48,(t={xfId:0,builtinId:0,name:"Normal"},(r=r||Lr(52)).write_shift(4,t.xfId),r.write_shift(2,1),r.write_shift(1,+t.builtinId),r.write_shift(1,0),ba(t.name||"",r),r.length>r.l?r.slice(0,r.l):r)),Br(e,620)}function Lo(e){var t,r,a,n;Br(e,508,(t=0,r="TableStyleMedium9",a="PivotStyleMedium4",(n=Lr(2052)).write_shift(4,t),ba(r,n),ba(a,n),n.length>n.l?n.slice(0,n.l):n)),Br(e,509)}function Mo(e,t){var r,a=Ur();return Br(a,278),Fo(a,e.SSF),Br(e=a,611,na(1)),Br(e,43,xo({sz:12,color:{theme:1},name:"Calibri",family:2,scheme:"minor"})),Br(e,612),Br(e=a,603,na(2)),Br(e,45,Oo({patternType:"none"})),Br(e,45,Oo({patternType:"gray125"})),Br(e,604),Do(a),Br(e=a,626,na(1)),Br(e,47,Io({numFmtId:0,fontId:0,fillId:0,borderId:0},65535)),Br(e,627),r=a,t=t.cellXfs,Br(r,617,na(t.length)),t.forEach(function(e){Br(r,47,Io(e,0))}),Br(r,618),Po(a),Br(t=a,505,na(0)),Br(t,506),Lo(a),Br(a,279),a.end()}var Uo=["","","","","","","","","","","",""];function Bo(e,r,a){r.themeElements.clrScheme=[];var n={};(e[0].match(ft)||[]).forEach(function(e){var t=dt(e);switch(t[0]){case"":break;case"":case"":case"":case"":case"":case"":case"":case"":case"":case"":case"":case"":case"":case"":case"":case"":case"":case"":case"":case"":case"":case"":case"":case"":"/"===t[0].charAt(1)?(r.themeElements.clrScheme[Uo.indexOf(t[0])]=n,n={}):n.name=t[0].slice(3,t[0].length-1);break;default:if(a&&a.WTF)throw new Error("Unrecognized "+t[0]+" in clrScheme")}})}function Wo(){}function Ho(){}var zo=/]*)>[\s\S]*<\/a:clrScheme>/,Vo=/]*)>[\s\S]*<\/a:fontScheme>/,Go=/]*)>[\s\S]*<\/a:fmtScheme>/;var jo=/]*)>[\s\S]*<\/a:themeElements>/;function $o(e,t){var r,a,n,s,i,o={};if(!(r=(e=!e||0===e.length?Xo():e).match(jo)))throw new Error("themeElements not found in theme");return a=r[0],s=t,(n=o).themeElements={},[["clrScheme",zo,Bo],["fontScheme",Vo,Wo],["fmtScheme",Go,Ho]].forEach(function(e){if(!(i=a.match(e[1])))throw new Error(e[0]+" not found in themeElements");e[2](i,n,s)}),o.raw=e,o}function Xo(e,t){if(t&&t.themeXLSX)return t.themeXLSX;if(e&&"string"==typeof e.raw)return e.raw;e=[ot];return e[e.length]='',e[e.length]="",e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]="",e[e.length]='',e[e.length]="",e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]="",e[e.length]="",e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]="",e[e.length]="",e[e.length]='',e[e.length]="",e[e.length]='',e[e.length]='',e[e.length]="",e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]="",e[e.length]='',e[e.length]="",e[e.length]='',e[e.length]="",e[e.length]='',e[e.length]='',e[e.length]="",e[e.length]='',e[e.length]="",e[e.length]="",e[e.length]="",e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]="",e[e.length]="",e[e.length]="",e[e.length]="",e[e.length]='',e[e.length]="",e[e.length]="",e[e.length]="",e[e.length]="",e[e.length]='',e[e.length]="",e[e.length]="",e[e.length]="",e[e.length]="",e[e.length]='',e[e.length]="",e[e.length]='',e[e.length]='',e[e.length]="",e[e.length]="",e[e.length]="",e[e.length]='',e[e.length]='',e[e.length]="",e[e.length]='',e[e.length]='',e[e.length]='',e[e.length]="",e[e.length]='',e[e.length]="",e[e.length]='',e[e.length]="",e[e.length]='',e[e.length]='',e[e.length]="",e[e.length]='',e[e.length]="",e[e.length]="",e[e.length]="",e[e.length]="",e[e.length]="",e[e.length]="",e[e.length]='',e[e.length]="",e[e.length]="",e[e.length]='',e[e.length]="",e[e.length]="",e[e.length]="",e[e.length]="",e.join("")}function Yo(e){var t={};switch(t.xclrType=e.read_shift(2),t.nTintShade=e.read_shift(2),t.xclrType){case 0:e.l+=4;break;case 1:t.xclrValue=Pr(e,4);break;case 2:t.xclrValue=Gn(e);break;case 3:t.xclrValue=e.read_shift(4);break;case 4:e.l+=4}return e.l+=8,t}function Ko(e){var t=e.read_shift(2),r=e.read_shift(2)-4,a=[t];switch(t){case 4:case 5:case 7:case 8:case 9:case 10:case 11:case 13:a[1]=Yo(e);break;case 6:a[1]=Pr(e,r);break;case 14:case 15:a[1]=e.read_shift(1==r?1:2);break;default:throw new Error("Unrecognized ExtProp type: "+t+" "+r)}return a}function Jo(){var e,t,r,a=Ur();return Br(a,332),Br(a,334,na(1)),Br(a,335,((r=Lr(12+2*(t={name:"XLDAPR",version:12e4,flags:3496657072}).name.length)).write_shift(4,t.flags),r.write_shift(4,t.version),ia(t.name,r),r.slice(0,r.l))),Br(a,336),Br(a,339,(e=1,(r=Lr(8+2*(t="XLDAPR").length)).write_shift(4,e),ia(t,r),r.slice(0,r.l))),Br(a,52),Br(a,35,na(514)),Br(a,4096,na(0)),Br(a,4097,Fn(1)),Br(a,36),Br(a,53),Br(a,340),Br(a,337,(e=1,t=!0,(r=Lr(8)).write_shift(4,e),r.write_shift(4,t?1:0),r)),Br(a,51,function(e){var t=Lr(4+8*e.length);t.write_shift(4,e.length);for(var r=0;r\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n'),e.join("")}var Zo=1024;function Qo(e,t){for(var r=[21600,21600],a=["m0,0l0",r[1],r[0],r[1],r[0],"0xe"].join(","),n=[Yt("xml",null,{"xmlns:v":er.v,"xmlns:o":er.o,"xmlns:x":er.x,"xmlns:mv":er.mv}).replace(/\/>/,">"),Yt("o:shapelayout",Yt("o:idmap",null,{"v:ext":"edit",data:e}),{"v:ext":"edit"}),Yt("v:shapetype",[Yt("v:stroke",null,{joinstyle:"miter"}),Yt("v:path",null,{gradientshapeok:"t","o:connecttype":"rect"})].join(""),{id:"_x0000_t202","o:spt":202,coordsize:r.join(","),path:a})];Zo<1e3*e;)Zo+=1e3;return t.forEach(function(e){var t=Yr(e[0]),r={color2:"#BEFF82",type:"gradient"};"gradient"==r.type&&(r.angle="-180");var a="gradient"==r.type?Yt("o:fill",null,{type:"gradientUnscaled","v:ext":"view"}):null,r=Yt("v:fill",a,r);++Zo,n=n.concat(["",r,Yt("v:shadow",null,{on:"t",obscured:"t"}),Yt("v:path",null,{"o:connecttype":"none"}),'
','',"","",$t("x:Anchor",[t.c+1,0,t.r+1,0,t.c+3,20,t.r+5,20].join(",")),$t("x:AutoFill","False"),$t("x:Row",String(t.r)),$t("x:Column",String(t.c)),e[1].hidden?"":"","",""])}),n.push(""),n.join("")}function ec(s,e,i,o){var c,l=Array.isArray(s);e.forEach(function(e){var t,r=Yr(e.ref);(c=l?(s[r.r]||(s[r.r]=[]),s[r.r][r.c]):s[e.ref])||(c={t:"z"},l?s[r.r][r.c]=c:s[e.ref]=c,(t=Zr(s["!ref"]||"BDWGO1000001:A1")).s.r>r.r&&(t.s.r=r.r),t.e.rr.c&&(t.s.c=r.c),t.e.c"),e.forEach(function(e){e[1].forEach(function(e){var t=kt(e.a);-1==i.indexOf(t)&&(i.push(t),s.push(""+t+"")),e.T&&e.ID&&-1==i.indexOf("tc="+e.ID)&&(i.push("tc="+e.ID),s.push("tc="+e.ID+""))})}),0==i.length&&(i.push("SheetJ5"),s.push("SheetJ5")),s.push(""),s.push(""),e.forEach(function(e){var t=0,r=[];if(e[1][0]&&e[1][0].T&&e[1][0].ID?t=i.indexOf("tc="+e[1][0].ID):e[1].forEach(function(e){e.a&&(t=i.indexOf(kt(e.a))),r.push(e.t||"")}),s.push(''),r.length<=1)s.push($t("t",kt(r[0]||"")));else{for(var a="Comment:\n "+r[0]+"\n",n=1;n")}),s.push(""),2",s[1]=s[1].replace("/>",">")),s.join("")}Ue=sa;function rc(e){var n=Ur(),s=[];return Br(n,628),Br(n,630),e.forEach(function(e){e[1].forEach(function(e){-1>14&1,t>>15&1]}function mc(e,t,r){var a=2;if(r){if(2<=r.biff&&r.biff<=5)return gc(e);12==r.biff&&(a=4)}var n=e.read_shift(a),r=e.read_shift(a),a=pc(e,2),e=pc(e,2);return{s:{r:n,c:a[0],cRel:a[1],rRel:a[2]},e:{r:r,c:e[0],cRel:e[1],rRel:e[2]}}}function gc(e){var t=pc(e,2),r=pc(e,2),a=e.read_shift(1),e=e.read_shift(1);return{s:{r:t[0],c:a,cRel:t[1],rRel:t[2]},e:{r:r[0],c:e,cRel:r[1],rRel:r[2]}}}function bc(e,t,r){if(r&&2<=r.biff&&r.biff<=5)return n=pc(a=e,2),a=a.read_shift(1),{r:n[0],c:a,cRel:n[1],rRel:n[2]};var a,n,r=e.read_shift(r&&12==r.biff?4:2),e=pc(e,2);return{r:r,c:e[0],cRel:e[1],rRel:e[2]}}function vc(e,t,r){r=r&&r.biff?r.biff:8;if(2<=r&&r<=5)return function(e){var t=e.read_shift(2),r=e.read_shift(1),a=(32768&t)>>15,e=(16384&t)>>14;t&=16383,1==a&&8192<=t&&(t-=16384);1==e&&128<=r&&(r-=256);return{r:t,c:r,cRel:e,rRel:a}}(e);var a=e.read_shift(12<=r?4:2),n=e.read_shift(2),r=(16384&n)>>14,e=(32768&n)>>15;if(n&=16383,1==e)for(;524287>15,rRel:a>>15})];var a}function yc(e){return e.l+=6,[]}function Sc(e){return e.l+=2,[Nn(e),1&e.read_shift(2)]}var _c=["Data","All","Headers","??","?Data2","??","?DataHeaders","??","Totals","??","??","??","?DataTotals","??","??","??","?Current"];var xc={1:{n:"PtgExp",f:function(e,t,r){return e.l++,r&&12==r.biff?[e.read_shift(4,"i"),0]:[e.read_shift(2),e.read_shift(r&&2==r.biff?1:2)]}},2:{n:"PtgTbl",f:Pr},3:{n:"PtgAdd",f:dc},4:{n:"PtgSub",f:dc},5:{n:"PtgMul",f:dc},6:{n:"PtgDiv",f:dc},7:{n:"PtgPower",f:dc},8:{n:"PtgConcat",f:dc},9:{n:"PtgLt",f:dc},10:{n:"PtgLe",f:dc},11:{n:"PtgEq",f:dc},12:{n:"PtgGe",f:dc},13:{n:"PtgGt",f:dc},14:{n:"PtgNe",f:dc},15:{n:"PtgIsect",f:dc},16:{n:"PtgUnion",f:dc},17:{n:"PtgRange",f:dc},18:{n:"PtgUplus",f:dc},19:{n:"PtgUminus",f:dc},20:{n:"PtgPercent",f:dc},21:{n:"PtgParen",f:dc},22:{n:"PtgMissArg",f:dc},23:{n:"PtgStr",f:function(e,t,r){return e.l++,Ln(e,0,r)}},26:{n:"PtgSheet",f:function(e,t,r){return e.l+=5,e.l+=2,e.l+=2==r.biff?1:4,["PTGSHEET"]}},27:{n:"PtgEndSheet",f:function(e,t,r){return e.l+=2==r.biff?4:5,["PTGENDSHEET"]}},28:{n:"PtgErr",f:function(e){return e.l++,Wa[e.read_shift(1)]}},29:{n:"PtgBool",f:function(e){return e.l++,0!==e.read_shift(1)}},30:{n:"PtgInt",f:function(e){return e.l++,e.read_shift(2)}},31:{n:"PtgNum",f:function(e){return e.l++,xa(e)}},32:{n:"PtgArray",f:function(e,t,r){var a=(96&e[e.l++])>>5;return e.l+=2==r.biff?6:12==r.biff?14:7,[a]}},33:{n:"PtgFunc",f:function(e,t,r){var a=(96&e[e.l])>>5;return e.l+=1,r=e.read_shift(r&&r.biff<=3?1:2),[jc[r],Gc[r],a]}},34:{n:"PtgFuncVar",f:function(e,t,r){var a=e[e.l++],n=e.read_shift(1),s=r&&r.biff<=3?[88==a?-1:0,e.read_shift(1)]:[(s=e)[s.l+1]>>7,32767&s.read_shift(2)];return[n,(0===s[0]?Gc:Vc)[s[1]]]}},35:{n:"PtgName",f:function(e,t,r){var a=e.read_shift(1)>>>5&3,n=!r||8<=r.biff?4:2,n=e.read_shift(n);switch(r.biff){case 2:e.l+=5;break;case 3:case 4:e.l+=8;break;case 5:e.l+=12}return[a,0,n]}},36:{n:"PtgRef",f:function(e,t,r){var a=(96&e[e.l])>>5;return e.l+=1,[a,bc(e,0,r)]}},37:{n:"PtgArea",f:function(e,t,r){return[(96&e[e.l++])>>5,mc(e,2<=r.biff&&r.biff,r)]}},38:{n:"PtgMemArea",f:function(e,t,r){var a=e.read_shift(1)>>>5&3;return e.l+=r&&2==r.biff?3:4,[a,e.read_shift(r&&2==r.biff?1:2)]}},39:{n:"PtgMemErr",f:Pr},40:{n:"PtgMemNoMem",f:Pr},41:{n:"PtgMemFunc",f:function(e,t,r){return[e.read_shift(1)>>>5&3,e.read_shift(r&&2==r.biff?1:2)]}},42:{n:"PtgRefErr",f:function(e,t,r){var a=e.read_shift(1)>>>5&3;return e.l+=4,r.biff<8&&e.l--,12==r.biff&&(e.l+=2),[a]}},43:{n:"PtgAreaErr",f:function(e,t,r){var a=(96&e[e.l++])>>5;return e.l+=r&&8>5;return e.l+=1,[a,vc(e,0,r)]}},45:{n:"PtgAreaN",f:function(e,t,r){return[(96&e[e.l++])>>5,function(e,t){if(t.biff<8)return gc(e);var r=e.read_shift(12==t.biff?4:2),a=e.read_shift(12==t.biff?4:2),t=pc(e,2),e=pc(e,2);return{s:{r:r,c:t[0],cRel:t[1],rRel:t[2]},e:{r:a,c:e[0],cRel:e[1],rRel:e[2]}}}(e,r)]}},46:{n:"PtgMemAreaN",f:function(e){return[e.read_shift(1)>>>5&3,e.read_shift(2)]}},47:{n:"PtgMemNoMemN",f:function(e){return[e.read_shift(1)>>>5&3,e.read_shift(2)]}},57:{n:"PtgNameX",f:function(e,t,r){return 5==r.biff?function(e){var t=e.read_shift(1)>>>5&3,r=e.read_shift(2,"i");e.l+=8;var a=e.read_shift(2);return e.l+=12,[t,r,a]}(e):[e.read_shift(1)>>>5&3,e.read_shift(2),e.read_shift(4)]}},58:{n:"PtgRef3d",f:function(e,t,r){var a=(96&e[e.l])>>5;e.l+=1;var n=e.read_shift(2);return r&&5==r.biff&&(e.l+=12),[a,n,bc(e,0,r)]}},59:{n:"PtgArea3d",f:function(e,t,r){var a=(96&e[e.l++])>>5,n=e.read_shift(2,"i");if(r)switch(r.biff){case 5:e.l+=12,0;break;case 12:0}return[a,n,mc(e,0,r)]}},60:{n:"PtgRefErr3d",f:function(e,t,r){var a=(96&e[e.l++])>>5,n=e.read_shift(2),s=4;if(r)switch(r.biff){case 5:s=15;break;case 12:s=6}return e.l+=s,[a,n]}},61:{n:"PtgAreaErr3d",f:function(e,t,r){var a=(96&e[e.l++])>>5,n=e.read_shift(2),s=8;if(r)switch(r.biff){case 5:e.l+=12,s=6;break;case 12:s=12}return e.l+=s,[a,n]}},255:{}},Ac={64:32,96:32,65:33,97:33,66:34,98:34,67:35,99:35,68:36,100:36,69:37,101:37,70:38,102:38,71:39,103:39,72:40,104:40,73:41,105:41,74:42,106:42,75:43,107:43,76:44,108:44,77:45,109:45,78:46,110:46,79:47,111:47,88:34,120:34,89:57,121:57,90:58,122:58,91:59,123:59,92:60,124:60,93:61,125:61},Cc={1:{n:"PtgElfLel",f:Sc},2:{n:"PtgElfRw",f:kc},3:{n:"PtgElfCol",f:kc},6:{n:"PtgElfRwV",f:kc},7:{n:"PtgElfColV",f:kc},10:{n:"PtgElfRadical",f:kc},11:{n:"PtgElfRadicalS",f:yc},13:{n:"PtgElfColS",f:yc},15:{n:"PtgElfColSV",f:yc},16:{n:"PtgElfRadicalLel",f:Sc},25:{n:"PtgList",f:function(e){e.l+=2;var t=e.read_shift(2),r=e.read_shift(2),a=e.read_shift(4),n=e.read_shift(2),e=e.read_shift(2);return{ixti:t,coltype:3&r,rt:_c[r>>2&31],idx:a,c:n,C:e}}},29:{n:"PtgSxName",f:function(e){return e.l+=2,[e.read_shift(4)]}},255:{}},Rc={0:{n:"PtgAttrNoop",f:function(e){return e.l+=4,[0,0]}},1:{n:"PtgAttrSemi",f:function(e,t,r){var a=255&e[e.l+1]?1:0;return e.l+=r&&2==r.biff?3:4,[a]}},2:{n:"PtgAttrIf",f:function(e,t,r){var a=255&e[e.l+1]?1:0;return e.l+=2,[a,e.read_shift(r&&2==r.biff?1:2)]}},4:{n:"PtgAttrChoose",f:function(e,t,r){e.l+=2;for(var a=e.read_shift(r&&2==r.biff?1:2),n=[],s=0;s<=a;++s)n.push(e.read_shift(r&&2==r.biff?1:2));return n}},8:{n:"PtgAttrGoto",f:function(e,t,r){var a=255&e[e.l+1]?1:0;return e.l+=2,[a,e.read_shift(r&&2==r.biff?1:2)]}},16:{n:"PtgAttrSum",f:function(e,t,r){e.l+=r&&2==r.biff?3:4}},32:{n:"PtgAttrBaxcel",f:wc},33:{n:"PtgAttrBaxcel",f:wc},64:{n:"PtgAttrSpace",f:function(e){return e.read_shift(2),Tc(e)}},65:{n:"PtgAttrSpaceSemi",f:function(e){return e.read_shift(2),Tc(e)}},128:{n:"PtgAttrIfError",f:function(e){var t=255&e[e.l+1]?1:0;return e.l+=2,[t,e.read_shift(2)]}},255:{}};function Oc(e,t,r,a){if(a.biff<8)return Pr(e,t);for(var n=e.l+t,s=[],i=0;i!==r.length;++i)switch(r[i][0]){case"PtgArray":r[i][1]=Ec(e,0,a),s.push(r[i][1]);break;case"PtgMemArea":r[i][2]=function(e,t){for(var r=e.read_shift(12==t.biff?4:2),a=[],n=0;n!=r;++n)a.push((12==t.biff?Sa:Kn)(e,8));return a}(e,(r[i][1],a)),s.push(r[i][2]);break;case"PtgExp":a&&12==a.biff&&(r[i][1][1]=e.read_shift(4),s.push(r[i][1]));break;case"PtgList":case"PtgElfRadicalS":case"PtgElfColS":case"PtgElfColSV":throw"Unsupported "+r[i][0]}return 0!==(t=n-e.l)&&s.push(Pr(e,t)),s}function Ic(e,t,r){for(var a,n,s=e.l+t,i=[];s!=e.l;)t=s-e.l,n=e[e.l],a=xc[n]||xc[Ac[n]],(a=24===n||25===n?(24===n?Cc:Rc)[e[e.l+1]]:a)&&a.f?i.push([a.n,a.f(e,t,r)]):Pr(e,t);return i}var Nc={PtgAdd:"+",PtgConcat:"&",PtgDiv:"/",PtgEq:"=",PtgGe:">=",PtgGt:">",PtgLe:"<=",PtgLt:"<",PtgMul:"*",PtgNe:"<>",PtgPower:"^",PtgSub:"-"};function Fc(e,t,r){if(!e)return"SH33TJSERR0";if(8s[0].e.c||i.rs[0].e.r)){f.push(Pc(s[1],0,C,a,n)),R=!0;break}R||f.push(v[1])}break;case"PtgArray":f.push("{"+function(e){for(var t=[],r=0;r>3&1,tt:s[1]}}function Mc(e,t,r,a,n){t=Xn(t,r,n),n=null!=(r=e.v)?Aa("number"==typeof r?r:0):((r=Lr(8)).write_shift(1,3),r.write_shift(1,0),r.write_shift(2,0),r.write_shift(2,0),r.write_shift(2,65535),r),r=Lr(6);r.write_shift(2,33),r.write_shift(4,0);for(var s=Lr(e.bf.length),i=0;i/g,al=/<(?:\w+:)?sheetData[^>]*>([\s\S]*)<\/(?:\w+:)?sheetData>/,nl=/<(?:\w:)?hyperlink [^>]*>/gm,sl=/"(\w*:\w*)"/,il=/<(?:\w:)?col\b[^>]*[\/]?>/g,ol=/<(?:\w:)?autoFilter[^>]*([\/]|>([\s\S]*)<\/(?:\w:)?autoFilter)>/g,cl=/<(?:\w:)?pageMargins[^>]*\/>/g,ll=/<(?:\w:)?sheetPr\b(?:[^>a-z][^>]*)?\/>/,fl=/<(?:\w:)?sheetPr[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetPr)>/,hl=/<(?:\w:)?sheetViews[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetViews)>/;function ul(e,t,r,a,n,s,i){if(!e)return e;a=a||{"!id":{}},null!=oe&&null==t.dense&&(t.dense=oe);var o=t.dense?[]:{},c={s:{r:2e6,c:2e6},e:{r:0,c:0}},l="",f="",h=e.match(al);h?(l=e.slice(0,h.index),f=e.slice(h.index+h[0].length)):l=f=e;var u=l.match(ll);u?dl(u[0],0,n,r):(u=l.match(fl))&&(e=u[0],u[1],u=o,d=n,p=r,dl(e.slice(0,e.indexOf(">")),0,d,p));var d,p,m=(l.match(/<(?:\w*:)?dimension/)||{index:-1}).index;0=c.s.c&&c.e.r>=c.s.r&&(o["!ref"]=qr(c)),0c.e.r&&(f.e.r=c.e.r),f.e.rc.e.c&&(f.e.c=c.e.c),f.e.ca-z][^>]*)?\/?>/;var bl,vl,wl,Tl,El,kl,yl,Sl=(bl=/<(?:\w+:)?c[ \/>]/,vl=/<\/(?:\w+:)?row>/,wl=/r=["']([^"']*)["']/,Tl=/<(?:\w+:)?is>([\S\s]*?)<\/(?:\w+:)?is>/,El=/ref=["']([^"']*)["']/,kl=Bt("v"),yl=Bt("f"),function(e,t,r,a,n,s){for(var i,o,c,l,f,h,u=0,d="",p=[],m=[],g=0,b=0,v="",w=0,T=0,E=0,k=0,y=Array.isArray(s.CellXf),S=[],_=[],x=Array.isArray(t),A=[],C={},R=!1,O=!!r.sheetStubs,I=e.split(vl),N=0,F=I.length;N!=F;++N){var D=(d=I[N].trim()).length;if(0!==D){var P=0;e:for(u=0;u":if("/"!=d[u-1]){++u;break e}if(r&&r.cellStyles){if(w=null!=(c=dt(d.slice(P,u),!0)).r?parseInt(c.r,10):w+1,T=-1,r.sheetRows&&r.sheetRowsw-1&&(a.s.r=w-1),a.e.r":"")+d,null!=m&&2===m.length){for(g=0,v=m[1],b=0;b!=v.length&&!((i=v.charCodeAt(b)-64)<1||26]*\/>/))&&_[(f=dt(m[0])).si]&&(o.f=(h=_[f.si][1],W=_[f.si][2],L=c.r,W=Jr(W).s,L=Yr(L),hc(h,{r:L.r-W.r,c:L.c-W.c})));for(var U=Yr(c.r),b=0;b=S[b][0].s.r&&U.r<=S[b][0].e.r&&U.c>=S[b][0].s.c&&U.c<=S[b][0].e.c&&(o.F=S[b][1])}if(null==c.t&&void 0===o.v)if(o.f||o.F)o.v=0,o.t="n";else{if(!O)continue;o.t="z"}else o.t=c.t||"n";switch(a.s.c>T&&(a.s.c=T),a.e.c"],a=0;a!=e.length;++a)(t=e[a])&&(r[r.length]=Yt("col",null,Zc(a,t)));return r[r.length]="",r.join("")}(c["!cols"])),i[n=i.length]="",c["!links"]=[],null!=c["!ref"]&&0<(s=_l(c,t)).length&&(i[i.length]=s),i.length>n+1&&(i[i.length]="",i[n]=i[n].replace("/>",">")),c["!protect"]&&(i[i.length]=(h=c["!protect"],u={sheet:1},pl.forEach(function(e){null!=h[e]&&h[e]&&(u[e]="1")}),ml.forEach(function(e){null==h[e]||h[e]||(u[e]="0")}),h.password&&(u.password=zi(h.password).toString(16).toUpperCase()),Yt("sheetProtection",null,u))),null!=c["!autofilter"]&&(i[i.length]=function(e,t,r,a){var n="string"==typeof e.ref?e.ref:qr(e.ref);r.Workbook||(r.Workbook={Sheets:[]}),r.Workbook.Names||(r.Workbook.Names=[]);var s=r.Workbook.Names;(e=Jr(n)).s.r==e.e.r&&(e.e.r=Jr(t["!ref"]).e.r,n=qr(e));for(var i=0;i',r=0;r!=e.length;++r)t+='';return t+""}(c["!merges"]));var p,m,g=-1;return 0",c["!links"].forEach(function(e){e[1].Target&&(m={ref:e[0]},"#"!=e[1].Target.charAt(0)&&(g=Ja(a,-1,kt(e[1].Target).replace(/#.*$/,""),$a.HLINK),m["r:id"]="rId"+g),-1<(p=e[1].Target.indexOf("#"))&&(m.location=kt(e[1].Target.slice(p+1))),e[1].Tooltip&&(m.tooltip=kt(e[1].Tooltip)),i[i.length]=Yt("hyperlink",null,m))}),i[i.length]=""),delete c["!links"],null!=c["!margins"]&&(i[i.length]=(Qc(r=c["!margins"]),Yt("pageMargins",null,r))),t&&!t.ignoreEC&&null!=t.ignoreEC||(i[i.length]=$t("ignoredErrors",Yt("ignoredError",null,{numberStoredAsText:1,sqref:l}))),0",i[1]=i[1].replace("/>",">")),i.join("")}function Al(e,t,r,a){r=function(e,t,r){var a=Lr(145),n=(r["!rows"]||[])[e]||{};a.write_shift(4,e),a.write_shift(4,0);var s=320;n.hpx?s=20*uo(n.hpx):n.hpt&&(s=20*n.hpt),a.write_shift(2,s),a.write_shift(1,0),s=0,n.level&&(s|=n.level),n.hidden&&(s|=16),(n.hpx||n.hpt)&&(s|=32),a.write_shift(1,s),a.write_shift(1,0);var i=0,s=a.l;a.l+=4;for(var o={r:e,c:0},c=0;c<16;++c)if(!(t.s.c>c+1<<10||t.e.ca.l?a.slice(0,a.l):a}(a,r,t);(17k.l?k.slice(0,k.l):k)):Br(e,6,(E=t,ha(C,T=null==T?Lr(12+4*E.v.length):T),ia(E.v,T),T.length>T.l?T.slice(0,T.l):T))),!0;case"n":return t.v==(0|t.v)&&-1e3[\s\S]*?<\/c:numCache>/gm)||[]).forEach(function(e){var r=function(e){var t,r=[],a=e.match(/^/);(e.match(/(.*?)<\/c:pt>/gm)||[]).forEach(function(e){e=e.match(/(.*)<\/c:v><\/c:pt>/);e&&(r[+e[1]]=a?+e[2]:e[2])});var n=wt((e.match(/([\s\S]*?)<\/c:formatCode>/)||["","General"])[1]);return(e.match(/(.*?)<\/c:f>/gm)||[]).forEach(function(e){t=e.replace(/<.*?>/g,"")}),[r,n,t]}(e);f.s.r=f.s.c=0,f.e.c=c,o=Xr(c),r[0].forEach(function(e,t){i[o+jr(t)]={t:"n",v:e,z:r[1]},l=t}),f.e.r",s=0;s!=t.SheetNames.length&&n[s]&&n[s].Hidden;++s);s==t.SheetNames.length&&(s=0),r[r.length]='',r[r.length]=""}for(r[r.length]="",s=0;s!=t.SheetNames.length;++s){var i={name:kt(t.SheetNames[s].slice(0,31))};if(i.sheetId=""+(s+1),i["r:id"]="rId"+(s+1),n[s])switch(n[s].Hidden){case 1:i.state="hidden";break;case 2:i.state="veryHidden"}r[r.length]=Yt("sheet",null,i)}return r[r.length]="",e&&(r[r.length]="",t.Workbook&&t.Workbook.Names&&t.Workbook.Names.forEach(function(e){var t={name:e.Name};e.Comment&&(t.comment=e.Comment),null!=e.Sheet&&(t.localSheetId=""+e.Sheet),e.Hidden&&(t.hidden="1"),e.Ref&&(r[r.length]=Yt("definedName",kt(e.Ref),t))}),r[r.length]=""),2",r[1]=r[1].replace("/>",">")),r.join("")}function Ql(e,t){var r={};return e.read_shift(4),r.ArchID=e.read_shift(4),e.l+=t-8,r}function ef(e,t){Br(e,143);for(var r,a=0;a!=t.SheetNames.length;++a){var n={Hidden:t.Workbook&&t.Workbook.Sheets&&t.Workbook.Sheets[a]&&t.Workbook.Sheets[a].Hidden||0,iTabID:a+1,strRelID:"rId"+(a+1),name:t.SheetNames[a]};Br(e,156,(r=n,(n=(n=void 0)||Lr(127)).write_shift(4,r.Hidden),n.write_shift(4,r.iTabID),Ta(r.strRelID,n),ia(r.name.slice(0,31),n),n.length>n.l?n.slice(0,n.l):n))}Br(e,144)}function tf(e,t){if(t.Workbook&&t.Workbook.Sheets){for(var r,a=t.Workbook.Sheets,n=0,s=-1,i=-1;nr.l?r.slice(0,r.l):r)),Br(e,136))}}function rf(e,t){var r=Ur();return Br(r,131),Br(r,128,function(e){e=e||Lr(127);for(var t=0;4!=t;++t)e.write_shift(4,0);return ia("SheetJS",e),ia(a.version,e),ia(a.version,e),ia("7262",e),e.length>e.l?e.slice(0,e.l):e}()),Br(r,153,function(e,t){t=t||Lr(72);var r=0;return e&&e.filterPrivacy&&(r|=8),t.write_shift(4,r),t.write_shift(4,0),ma(e&&e.CodeName||"ThisWorkbook",t),t.slice(0,t.l)}(e.Workbook&&e.Workbook.WBProps||null)),tf(r,e),ef(r,e),Br(r,132),r.end()}function af(e,t,r){return(".bin"===t.slice(-4)?function(e,a){var n={AppVersion:{},WBProps:{},WBView:[],Sheets:[],CalcPr:{},xmlns:""},s=[],i=!1;(a=a||{}).biff=12;var o=[],c=[[]];return c.SheetNames=[],c.XTI=[],Df[16]={n:"BrtFRTArchID$",f:Ql},Mr(e,function(e,t,r){switch(r){case 156:c.SheetNames.push(e.name),n.Sheets.push(e);break;case 153:n.WBProps=e;break;case 39:null!=e.Sheet&&(a.SID=e.Sheet),e.Ref=Pc(e.Ptg,0,null,c,a),delete a.SID,delete e.Ptg,o.push(e);break;case 1036:break;case 357:case 358:case 355:case 667:c[0].length?c.push([r,e]):c[0]=[r,e],c[c.length-1].XTI=[];break;case 362:0===c.length&&(c[0]=[],c[0].XTI=[]),c[c.length-1].XTI=c[c.length-1].XTI.concat(e),c.XTI=c.XTI.concat(e);break;case 361:break;case 2071:case 158:case 143:case 664:case 353:break;case 3072:case 3073:case 534:case 677:case 157:case 610:case 2050:case 155:case 548:case 676:case 128:case 665:case 2128:case 2125:case 549:case 2053:case 596:case 2076:case 2075:case 2082:case 397:case 154:case 1117:case 553:case 2091:break;case 35:s.push(r),i=!0;break;case 36:s.pop(),i=!1;break;case 37:s.push(r),i=!0;break;case 38:s.pop(),i=!1;break;case 16:break;default:if(!t.T&&(!i||a.WTF&&37!=s[s.length-1]&&35!=s[s.length-1]))throw new Error("Unexpected record 0x"+r.toString(16))}},a),Xl(n),n.Names=o,n.supbooks=c,n}:function(a,n){if(!a)throw new Error("Could not find file");var s={AppVersion:{},WBProps:{},WBView:[],Sheets:[],CalcPr:{},Names:[],xmlns:""},i=!1,o="xmlns",c={},l=0;if(a.replace(ft,function(e,t){var r=dt(e);switch(pt(r[0])){case"":break;case"":case"":case"":break;case"":Hl.forEach(function(e){if(null!=r[e[0]])switch(e[2]){case"bool":s.WBProps[e[0]]=Rt(r[e[0]]);break;case"int":s.WBProps[e[0]]=parseInt(r[e[0]],10);break;default:s.WBProps[e[0]]=r[e[0]]}}),r.codeName&&(s.WBProps.CodeName=Mt(r.codeName));break;case"":case"":break;case"":case"":break;case"":delete r[0],s.WBView.push(r);break;case"":break;case"":case"":break;case"":break;case"":case"":case"":case"":break;case"":case"":i=!1;break;case"":c.Ref=wt(Mt(a.slice(l,t))),s.Names.push(c);break;case"":break;case"":delete r[0],s.CalcPr=r;break;case"":case"":case"":case"":break;case"":case"":case"":break;case"":case"":case"":break;case"":break;case"":case"":case"":case"":case"":break;case"":i=!1;break;case"":i=!0;break;case"":i=!1;break;case"=a[0].s.r&&u.r<=a[0].e.r&&g>=a[0].s.c&&g<=a[0].e.c&&(d.F=qr(a[0]),C=!0)}!C&&3u.r&&(k.s.r=u.r),k.s.c>g&&(k.s.c=g),k.e.ru.r&&(k.s.r=u.r),k.s.c>g&&(k.s.c=g),k.e.r=e.s;)F[e.e--]={width:e.w/256,hidden:!!(1&e.flags),level:e.level},P||(P=!0,lo(e.w/256)),fo(F[e.e+1]);break;case 161:E["!autofilter"]={ref:qr(e)};break;case 476:E["!margins"]=e;break;case 147:o.Sheets[s]||(o.Sheets[s]={}),e.name&&(o.Sheets[s].CodeName=e.name),(e.above||e.left)&&(E["!outline"]={above:e.above,left:e.left});break;case 137:o.Views||(o.Views=[{}]),o.Views[0]||(o.Views[0]={}),e.RTL&&(o.Views[0].RTL=!0);break;case 485:break;case 64:case 1053:case 151:break;case 152:case 175:case 644:case 625:case 562:case 396:case 1112:case 1146:case 471:case 1050:case 649:case 1105:case 589:case 607:case 564:case 1055:case 168:case 174:case 1180:case 499:case 507:case 550:case 171:case 167:case 1177:case 169:case 1181:case 551:case 552:case 661:case 639:case 478:case 537:case 477:case 536:case 1103:case 680:case 1104:case 1024:case 663:case 535:case 678:case 504:case 1043:case 428:case 170:case 3072:case 50:case 2070:case 1045:break;case 35:S=!0;break;case 36:S=!1;break;case 37:y.push(r),S=!0;break;case 38:y.pop(),S=!1;break;default:if(!t.T&&(!S||f.WTF))throw new Error("Unexpected record 0x"+r.toString(16))}},f),delete f.supbooks,delete f["!row"],!E["!ref"]&&(k.s.r<2e6||h&&(0k.e.r&&(e.e.r=k.e.r),e.e.rk.e.c&&(e.e.c=k.e.c),e.e.c/))return[];var n=[],s=[],t=e.match(/<(?:\w+:)?authors>([\s\S]*)<\/(?:\w+:)?authors>/);return t&&t[1]&&t[1].split(/<\/\w*:?author>/).forEach(function(e){""===e||""===e.trim()||(e=e.match(/<(?:\w+:)?author[^>]*>(.*)/))&&n.push(e[1])}),(e=e.match(/<(?:\w+:)?commentList>([\s\S]*)<\/(?:\w+:)?commentList>/))&&e[1]&&e[1].split(/<\/\w*:?comment>/).forEach(function(e){var t,r;""===e||""===e.trim()||(t=e.match(/<(?:\w+:)?comment[^>]*>/))&&(t={author:(r=dt(t[0])).authorId&&n[r.authorId]||"sheetjsghost",ref:r.ref,guid:r.guid},r=Yr(r.ref),a.sheetRows&&a.sheetRows<=r.r||(e=!!(e=e.match(/<(?:\w+:)?text>([\s\S]*)<\/(?:\w+:)?text>/))&&!!e[1]&&Ai(e[1])||{r:"",t:"",h:""},t.r=e.r,""==e.r&&(e.t=e.h=""),t.t=(e.t||"").replace(/\r\n/g,"\n").replace(/\r/g,"\n"),a.cellHTML&&(t.h=e.h),s.push(t)))}),s}(e,r);var a,n,s,i,o}function ff(e,t){return".bin"===t.slice(-4)?(a=[],Mr(e,function(e,t,r){if(63===r)a.push(e);else if(!t.T)throw new Error("Unexpected record 0x"+r.toString(16))}),a):function(e){var r=[];if(!e)return r;var a=1;return(e.match(ft)||[]).forEach(function(e){var t=dt(e);switch(t[0]){case"":case"":break;case"":break;case"":break;case"":break;case"":case"":case"":break;case"":break;case"":o=2;break;case"":o=2;break;case"":case"":case"":break;case"":i=!1;break;case""))>Math.min(1023&s.indexOf(","),1023&s.indexOf(";"))){var o=Ve(r);return o.type="string",Ks.to_workbook(n,o)}if(-1==s.indexOf("[\s\S]*?<\/table>/gi);if(!e||0==e.length)throw new Error("Invalid HTML: could not find ");if(1==e.length)return ta(Yf(e[0],r),r);var a=du();return e.forEach(function(e,t){pu(a,Yf(e,r),"Sheet"+(t+1))}),a}(n,r);df={"General Number":"General","General Date":me[22],"Long Date":"dddd, mmmm dd, yyyy","Medium Date":me[15],"Short Date":me[14],"Long Time":me[19],"Medium Time":me[18],"Short Time":me[20],Currency:'"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',Fixed:me[2],Standard:me[4],Percent:me[10],Scientific:me[11],"Yes/No":'"Yes";"Yes";"No";@',"True/False":'"True";"True";"False";@',"On/Off":'"Yes";"Yes";"No";@'};var c,l=[];null!=oe&&null==r.dense&&(r.dense=oe);var f,h={},u=[],d=r.dense?[]:{},p="",m={},g={},b=gf(''),v=0,w=0,T=0,E={s:{r:2e6,c:2e6},e:{r:0,c:0}},k={},y={},S="",_=0,x=[],A={},C={},R=0,O=[],I=[],N={},F=[],D=!1,P=[],L=[],M={},U=0,B=0,W={Sheets:[],WBProps:{date1904:!1}},H={};qt.lastIndex=0,n=n.replace(//gm,"");for(var z,V,G,j,$="";a=qt.exec(n);)switch(a[3]=($=a[3]).toLowerCase()){case"data":if("data"==$){if("/"===a[1]){if((c=l.pop())[0]!==a[3])throw new Error("Bad state: "+c.join("|"))}else"/"!==a[0].charAt(a[0].length-2)&&l.push([a[3],!0]);break}if(l[l.length-1][1])break;"/"===a[1]?function(e,t,r,a,n,s,i,o,c,l){var f="General",h=a.StyleID,u={};l=l||{};var d=[],p=0;for(void 0===(h=void 0===h&&o?o.StyleID:h)&&i&&(h=i.StyleID);void 0!==s[h]&&(s[h].nf&&(f=s[h].nf),s[h].Interior&&d.push(s[h].Interior),s[h].Parent);)h=s[h].Parent;switch(r.Type){case"Boolean":a.t="b",a.v=Rt(e);break;case"String":a.t="s",a.r=At(wt(e)),a.v=-1/g,""):a.r;break;case"DateTime":"Z"!=e.slice(-1)&&(e+="Z"),a.v=(He(e)-new Date(Date.UTC(1899,11,30)))/864e5,a.v!=a.v?a.v=wt(e):a.v<60&&(a.v=a.v-1),f&&"General"!=f||(f="yyyy-mm-dd");case"Number":void 0===a.v&&(a.v=+e),a.t||(a.t="n");break;case"Error":a.t="e",a.v=Ha[e],!1!==l.cellText&&(a.w=e);break;default:""==e&&""==t?a.t="z":(a.t="s",a.v=At(t||e))}if(bf(a,f,l),!1!==l.cellFormula)if(a.Formula){r=wt(a.Formula);61==r.charCodeAt(0)&&(r=r.slice(1)),a.f=oc(r,n),delete a.Formula,"RC"==a.ArrayRange?a.F=oc("RC:RC",n):a.ArrayRange&&(a.F=oc(a.ArrayRange,n),c.push([Zr(a.F),a.F]))}else for(p=0;p=c[p][0].s.r&&n.r<=c[p][0].e.r&&n.c>=c[p][0].s.c&&n.c<=c[p][0].e.c&&(a.F=c[p][1]);l.cellStyles&&(d.forEach(function(e){!u.patternType&&e.patternType&&(u.patternType=e.patternType)}),a.s=u),void 0!==a.StyleID&&(a.ixfe=a.StyleID)}(n.slice(v,a.index),S,b,"comment"==l[l.length-1][0]?N:m,{c:w,r:T},k,F[w],g,P,r):(S="",b=gf(a[0]),v=a.index+a[0].length);break;case"cell":if("/"===a[1])if(0T)&&void 0!==m.v&&(r.dense?(d[T]||(d[T]=[]),d[T][w]=m):d[Xr(w)+jr(T)]=m),m.HRef&&(m.l={Target:wt(m.HRef)},m.HRefScreenTip&&(m.l.Tooltip=m.HRefScreenTip),delete m.HRef,delete m.HRefScreenTip),(m.MergeAcross||m.MergeDown)&&(U=w+(0|parseInt(m.MergeAcross,10)),B=T+(0|parseInt(m.MergeDown,10)),x.push({s:{c:w,r:T},e:{c:U,r:B}})),r.sheetStubs)if(m.MergeAcross||m.MergeDown){for(var X=w;X<=U;++X)for(var Y=T;Y<=B;++Y)(wE.e.c&&(E.e.c=w),"/>"===a[0].slice(-2)&&++w,I=[];break;case"row":"/"===a[1]||"/>"===a[0].slice(-2)?(TE.e.r&&(E.e.r=T),"/>"===a[0].slice(-2)&&(g=gf(a[0])).Index&&(T=+g.Index-1),w=0,++T):((g=gf(a[0])).Index&&(T=+g.Index-1),M={},"0"!=g.AutoFitHeight&&!g.Height||(M.hpx=parseInt(g.Height,10),M.hpt=uo(M.hpx),L[T]=M),"1"==g.Hidden&&(M.hidden=!0,L[T]=M));break;case"worksheet":if("/"===a[1]){if((c=l.pop())[0]!==a[3])throw new Error("Bad state: "+c.join("|"));u.push(p),E.s.r<=E.e.r&&E.s.c<=E.e.c&&(d["!ref"]=qr(E),r.sheetRows&&r.sheetRows<=E.e.r&&(d["!fullref"]=d["!ref"],E.e.r=r.sheetRows-1,d["!ref"]=qr(E))),x.length&&(d["!merges"]=x),0"==a[0].slice(-2))break;l.push([a[3],!1]),D=!(F=[])}break;case"style":"/"===a[1]?(V=k,G=y,(j=r).cellStyles&&(!G.Interior||(j=G.Interior).Pattern&&(j.patternType=mo[j.Pattern]||j.Pattern)),V[G.ID]=G):y=gf(a[0]);break;case"numberformat":y.nf=wt(gf(a[0]).Format||"General"),df[y.nf]&&(y.nf=df[y.nf]);for(var K=0;392!=K&&me[K]!=y.nf;++K);if(392==K)for(K=57;392!=K;++K)if(null==me[K]){we(y.nf,K);break}break;case"column":if("table"!==l[l.length-1][0])break;if((f=gf(a[0])).Hidden&&(f.hidden=!0,delete f.Hidden),f.Width&&(f.wpx=parseInt(f.Width,10)),!D&&10"===a[0].slice(-2))break;"/"===a[1]?S+=n.slice(_,a.index):_=a.index+a[0].length;break;case"interior":if(!r.cellStyles)break;y.Interior=gf(a[0]);break;case"protection":break;case"author":case"title":case"description":case"created":case"keywords":case"subject":case"category":case"company":case"lastauthor":case"lastsaved":case"lastprinted":case"version":case"revision":case"totaltime":case"hyperlinkbase":case"manager":case"contentstatus":case"identifier":case"language":case"appname":if("/>"===a[0].slice(-2))break;"/"===a[1]?(G=A,Z=$,Q=n.slice(R,a.index),G[Z=(un=un||Ie(dn))[Z]||Z]=Q):R=a.index+a[0].length;break;case"paragraphs":break;case"styles":case"workbook":if("/"===a[1]){if((c=l.pop())[0]!==a[3])throw new Error("Bad state: "+c.join("|"))}else l.push([a[3],!1]);break;case"comment":if("/"===a[1]){if((c=l.pop())[0]!==a[3])throw new Error("Bad state: "+c.join("|"));(z=N).t=z.v||"",z.t=z.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n"),z.v=z.w=z.ixfe=void 0,I.push(N)}else l.push([a[3],!1]),N={a:(c=gf(a[0])).Author};break;case"autofilter":if("/"===a[1]){if((c=l.pop())[0]!==a[3])throw new Error("Bad state: "+c.join("|"))}else"/"!==a[0].charAt(a[0].length-2)&&(z=gf(a[0]),d["!autofilter"]={ref:oc(z.Range).replace(/\$/g,"")},l.push([a[3],!0]));break;case"name":break;case"datavalidation":if("/"===a[1]){if((c=l.pop())[0]!==a[3])throw new Error("Bad state: "+c.join("|"))}else"/"!==a[0].charAt(a[0].length-2)&&l.push([a[3],!0]);break;case"pixelsperinch":break;case"componentoptions":case"documentproperties":case"customdocumentproperties":case"officedocumentsettings":case"pivottable":case"pivotcache":case"names":case"mapinfo":case"pagebreaks":case"querytable":case"sorting":case"schema":case"conditionalformatting":case"smarttagtype":case"smarttags":case"excelworkbook":case"workbookoptions":case"worksheetoptions":if("/"===a[1]){if((c=l.pop())[0]!==a[3])throw new Error("Bad state: "+c.join("|"))}else"/"!==a[0].charAt(a[0].length-2)&&l.push([a[3],!0]);break;case"null":break;default:if(0==l.length&&"document"==a[3])return ih(n,r);if(0==l.length&&"uof"==a[3])return ih(n,r);var ee=!0;switch(l[l.length-1][0]){case"officedocumentsettings":switch(a[3]){case"allowpng":case"removepersonalinformation":case"downloadcomponents":case"locationofcomponents":case"colors":case"color":case"index":case"rgb":case"targetscreensize":case"readonlyrecommended":break;default:ee=!1}break;case"componentoptions":switch(a[3]){case"toolbar":case"hideofficelogo":case"spreadsheetautofit":case"label":case"caption":case"maxheight":case"maxwidth":case"nextsheetnumber":break;default:ee=!1}break;case"excelworkbook":switch(a[3]){case"date1904":W.WBProps.date1904=!0;break;case"windowheight":case"windowwidth":case"windowtopx":case"windowtopy":case"tabratio":case"protectstructure":case"protectwindow":case"protectwindows":case"activesheet":case"displayinknotes":case"firstvisiblesheet":case"supbook":case"sheetname":case"sheetindex":case"sheetindexfirst":case"sheetindexlast":case"dll":case"acceptlabelsinformulas":case"donotsavelinkvalues":case"iteration":case"maxiterations":case"maxchange":case"path":case"xct":case"count":case"selectedsheets":case"calculation":case"uncalced":case"startupprompt":case"crn":case"externname":case"formula":case"colfirst":case"collast":case"wantadvise":case"boolean":case"error":case"text":case"ole":case"noautorecover":case"publishobjects":case"donotcalculatebeforesave":case"number":case"refmoder1c1":case"embedsavesmarttags":break;default:ee=!1}break;case"workbookoptions":switch(a[3]){case"owcversion":case"height":case"width":break;default:ee=!1}break;case"worksheetoptions":switch(a[3]){case"visible":if("/>"!==a[0].slice(-2))if("/"===a[1])switch(n.slice(R,a.index)){case"SheetHidden":H.Hidden=1;break;case"SheetVeryHidden":H.Hidden=2}else R=a.index+a[0].length;break;case"header":d["!margins"]||Qc(d["!margins"]={},"xlml"),isNaN(+dt(a[0]).Margin)||(d["!margins"].header=+dt(a[0]).Margin);break;case"footer":d["!margins"]||Qc(d["!margins"]={},"xlml"),isNaN(+dt(a[0]).Margin)||(d["!margins"].footer=+dt(a[0]).Margin);break;case"pagemargins":var te=dt(a[0]);d["!margins"]||Qc(d["!margins"]={},"xlml"),isNaN(+te.Top)||(d["!margins"].top=+te.Top),isNaN(+te.Left)||(d["!margins"].left=+te.Left),isNaN(+te.Right)||(d["!margins"].right=+te.Right),isNaN(+te.Bottom)||(d["!margins"].bottom=+te.Bottom);break;case"displayrighttoleft":W.Views||(W.Views=[]),W.Views[0]||(W.Views[0]={}),W.Views[0].RTL=!0;break;case"freezepanes":case"frozennosplit":break;case"splithorizontal":case"splitvertical":case"donotdisplaygridlines":case"activerow":case"activecol":case"toprowbottompane":case"leftcolumnrightpane":case"unsynced":case"print":case"printerrors":case"panes":case"scale":case"pane":case"number":case"layout":case"pagesetup":case"selected":case"protectobjects":case"enableselection":case"protectscenarios":case"validprinterinfo":case"horizontalresolution":case"verticalresolution":case"numberofcopies":case"activepane":case"toprowvisible":case"leftcolumnvisible":case"fittopage":case"rangeselection":case"papersizeindex":case"pagelayoutzoom":case"pagebreakzoom":case"filteron":case"fitwidth":case"fitheight":case"commentslayout":case"zoom":case"lefttoright":case"gridlines":case"allowsort":case"allowfilter":case"allowinsertrows":case"allowdeleterows":case"allowinsertcols":case"allowdeletecols":case"allowinserthyperlinks":case"allowformatcells":case"allowsizecols":case"allowsizerows":break;case"nosummaryrowsbelowdetail":d["!outline"]||(d["!outline"]={}),d["!outline"].above=!0;break;case"tabcolorindex":case"donotdisplayheadings":case"showpagelayoutzoom":break;case"nosummarycolumnsrightdetail":d["!outline"]||(d["!outline"]={}),d["!outline"].left=!0;break;case"blackandwhite":case"donotdisplayzeros":case"displaypagebreak":case"rowcolheadings":case"donotdisplayoutline":case"noorientation":case"allowusepivottables":case"zeroheight":case"viewablerange":case"selection":case"protectcontents":break;default:ee=!1}break;case"pivottable":case"pivotcache":switch(a[3]){case"immediateitemsondrop":case"showpagemultipleitemlabel":case"compactrowindent":case"location":case"pivotfield":case"orientation":case"layoutform":case"layoutsubtotallocation":case"layoutcompactrow":case"position":case"pivotitem":case"datatype":case"datafield":case"sourcename":case"parentfield":case"ptlineitems":case"ptlineitem":case"countofsameitems":case"item":case"itemtype":case"ptsource":case"cacheindex":case"consolidationreference":case"filename":case"reference":case"nocolumngrand":case"norowgrand":case"blanklineafteritems":case"hidden":case"subtotal":case"basefield":case"mapchilditems":case"function":case"refreshonfileopen":case"printsettitles":case"mergelabels":case"defaultversion":case"refreshname":case"refreshdate":case"refreshdatecopy":case"versionlastrefresh":case"versionlastupdate":case"versionupdateablemin":case"versionrefreshablemin":case"calculation":break;default:ee=!1}break;case"pagebreaks":switch(a[3]){case"colbreaks":case"colbreak":case"rowbreaks":case"rowbreak":case"colstart":case"colend":case"rowend":break;default:ee=!1}break;case"autofilter":switch(a[3]){case"autofiltercolumn":case"autofiltercondition":case"autofilterand":case"autofilteror":break;default:ee=!1}break;case"querytable":switch(a[3]){case"id":case"autoformatfont":case"autoformatpattern":case"querysource":case"querytype":case"enableredirections":case"refreshedinxl9":case"urlstring":case"htmltables":case"connection":case"commandtext":case"refreshinfo":case"notitles":case"nextid":case"columninfo":case"overwritecells":case"donotpromptforfile":case"textwizardsettings":case"source":case"number":case"decimal":case"thousandseparator":case"trailingminusnumbers":case"formatsettings":case"fieldtype":case"delimiters":case"tab":case"comma":case"autoformatname":case"versionlastedit":case"versionlastrefresh":break;default:ee=!1}break;case"datavalidation":switch(a[3]){case"range":case"type":case"min":case"max":case"sort":case"descending":case"order":case"casesensitive":case"value":case"errorstyle":case"errormessage":case"errortitle":case"inputmessage":case"inputtitle":case"combohide":case"inputhide":case"condition":case"qualifier":case"useblank":case"value1":case"value2":case"format":case"cellrangelist":break;default:ee=!1}break;case"sorting":case"conditionalformatting":switch(a[3]){case"range":case"type":case"min":case"max":case"sort":case"descending":case"order":case"casesensitive":case"value":case"errorstyle":case"errormessage":case"errortitle":case"cellrangelist":case"inputmessage":case"inputtitle":case"combohide":case"inputhide":case"condition":case"qualifier":case"useblank":case"value1":case"value2":case"format":break;default:ee=!1}break;case"mapinfo":case"schema":case"data":switch(a[3]){case"map":case"entry":case"range":case"xpath":case"field":case"xsdtype":case"filteron":case"aggregate":case"elementtype":case"attributetype":break;case"schema":case"element":case"complextype":case"datatype":case"all":case"attribute":case"extends":case"row":break;default:ee=!1}break;case"smarttags":break;default:ee=!1}if(ee)break;if(a[3].match(/!\[CDATA/))break;if(!l[l.length-1][1])throw"Unrecognized tag: "+a[3]+"|"+l.join("|");if("customdocumentproperties"===l[l.length-1][0]){if("/>"===a[0].slice(-2))break;"/"===a[1]?function(e,t,r,a){var n=a;switch((r[0].match(/dt:dt="([\w.]+)"/)||["",""])[1]){case"boolean":n=Rt(a);break;case"i2":case"int":n=parseInt(a,10);break;case"r4":case"float":n=parseFloat(a);break;case"date":case"dateTime.tz":n=He(a);break;case"i8":case"string":case"fixed":case"uuid":case"bin.base64":break;default:throw new Error("bad custprop:"+r[0])}e[wt(t)]=n}(C,$,O,n.slice(R,a.index)):R=(O=a).index+a[0].length;break}if(r.WTF)throw"Unrecognized tag: "+a[3]+"|"+l.join("|")}o={};return r.bookSheets||r.bookProps||(o.Sheets=h),o.SheetNames=u,o.Workbook=W,o.SSF=Ve(me),o.Props=A,o.Custprops=C,o}function wf(e,t){switch(Mh(t=t||{}),t.type||"base64"){case"base64":return vf(te(e),t);case"binary":case"buffer":case"file":return vf(e,t);case"array":return vf(i(e),t)}}function Tf(e,t){var r,a,n,s,i,o,c,l=[];return e.Props&&l.push((r=e.Props,a=t,n=[],Re(dn).map(function(e){for(var t=0;t'+c.join("")+"")),l.join("")}function Ef(e){return Yt("NamedRange",null,{"ss:Name":e.Name,"ss:RefersTo":"="+fc(e.Ref,{r:0,c:0})})}function kf(e,t,r,a,n,s,i){if(!e||null==e.v&&null==e.f)return"";var o={};if(e.f&&(o["ss:Formula"]="="+kt(fc(e.f,i))),e.F&&e.F.slice(0,t.length)==t&&(t=Yr(e.F.slice(t.length+1)),o["ss:ArrayRange"]="RC:R"+(t.r==i.r?"":"["+(t.r-i.r)+"]")+"C"+(t.c==i.c?"":"["+(t.c-i.c)+"]")),e.l&&e.l.Target&&(o["ss:HRef"]=kt(e.l.Target),e.l.Tooltip&&(o["x:HRefScreenTip"]=kt(e.l.Tooltip))),r["!merges"])for(var c=r["!merges"],l=0;l!=c.length;++l)c[l].s.c==i.c&&c[l].s.r==i.r&&(c[l].e.c>c[l].s.c&&(o["ss:MergeAcross"]=c[l].e.c-c[l].s.c),c[l].e.r>c[l].s.r&&(o["ss:MergeDown"]=c[l].e.r-c[l].s.r));var f="",h="";switch(e.t){case"z":if(!a.sheetStubs)return"";break;case"n":f="Number",h=String(e.v);break;case"b":f="Boolean",h=e.v?"1":"0";break;case"e":f="Error",h=Wa[e.v];break;case"d":f="DateTime",h=new Date(e.v).toISOString(),null==e.z&&(e.z=e.z||me[14]);break;case"s":f="String",h=((e.v||"")+"").replace(Tt,function(e){return vt[e]}).replace(St,function(e){return"&#x"+e.charCodeAt(0).toString(16).toUpperCase()+";"})}r=el(a.cellXfs,e,a);o["ss:StyleID"]="s"+(21+r),o["ss:Index"]=i.c+1;r=null!=e.v?h:"",r="z"==e.t?"":''+r+"";return 0<(e.c||[]).length&&(r+=e.c.map(function(e){var t=Yt("ss:Data",(e.t||"").replace(/(\r\n|[\r\n])/g," "),{xmlns:"http://www.w3.org/TR/REC-html40"});return Yt("Comment",t,{"ss:Author":e.a})}).join("")),Yt("Cell",r,o)}function yf(e,t){if(!e["!ref"])return"";var r=Zr(e["!ref"]),a=e["!merges"]||[],n=0,s=[];e["!cols"]&&e["!cols"].forEach(function(e,t){fo(e);var r=!!e.width,a=Zc(t,e),t={"ss:Index":t+1};r&&(t["ss:Width"]=so(a.width)),e.hidden&&(t["ss:Hidden"]="1"),s.push(Yt("Column",null,t))});for(var i,o,c=Array.isArray(e),l=r.s.r;l<=r.e.r;++l){for(var f=[(i=l,o=(e["!rows"]||[])[l],i='")],h=r.s.c;h<=r.e.c;++h){for(var u,d,p,m=!1,n=0;n!=a.length;++n)if(!(a[n].s.c>h||a[n].s.r>l||a[n].e.c"),2"+n+""),0<(n=s?yf(s,t):"").length&&a.push("
"+n+"
"),a.push(function(t,e,r){if(!t)return"";var a=[];if(t["!margins"]&&(a.push(""),t["!margins"].header&&a.push(Yt("Header",null,{"x:Margin":t["!margins"].header})),t["!margins"].footer&&a.push(Yt("Footer",null,{"x:Margin":t["!margins"].footer})),a.push(Yt("PageMargins",null,{"x:Bottom":t["!margins"].bottom||"0.75","x:Left":t["!margins"].left||"0.7","x:Right":t["!margins"].right||"0.7","x:Top":t["!margins"].top||"0.75"})),a.push("")),r&&r.Workbook&&r.Workbook.Sheets&&r.Workbook.Sheets[e])if(r.Workbook.Sheets[e].Hidden)a.push(Yt("Visible",1==r.Workbook.Sheets[e].Hidden?"SheetHidden":"SheetVeryHidden",{}));else{for(var n=0;n")}return((((r||{}).Workbook||{}).Views||[])[0]||{}).RTL&&a.push(""),t["!protect"]&&(a.push($t("ProtectContents","True")),t["!protect"].objects&&a.push($t("ProtectObjects","True")),t["!protect"].scenarios&&a.push($t("ProtectScenarios","True")),null==t["!protect"].selectLockedCells||t["!protect"].selectLockedCells?null==t["!protect"].selectUnlockedCells||t["!protect"].selectUnlockedCells||a.push($t("EnableSelection","UnlockedCells")):a.push($t("EnableSelection","NoSelection")),[["formatCells","AllowFormatCells"],["formatColumns","AllowSizeCols"],["formatRows","AllowSizeRows"],["insertColumns","AllowInsertCols"],["insertRows","AllowInsertRows"],["insertHyperlinks","AllowInsertHyperlinks"],["deleteColumns","AllowDeleteCols"],["deleteRows","AllowDeleteRows"],["sort","AllowSort"],["autoFilter","AllowFilter"],["pivotTables","AllowUsePivotTables"]].forEach(function(e){t["!protect"][e[0]]&&a.push("<"+e[1]+"/>")})),0==a.length?"":Yt("WorksheetOptions",a.join(""),{xmlns:er.x})}(s,e,r)),a.join("")}function _f(e,t){t=t||{},e.SSF||(e.SSF=Ve(me)),e.SSF&&(Ee(),Te(e.SSF),t.revssf=Ne(e.SSF),t.revssf[e.SSF[65535]]=0,t.ssf=e.SSF,t.cellXfs=[],el(t.cellXfs,{},{revssf:{General:0}}));var r=[];r.push(Tf(e,t)),r.push(""),r.push(""),r.push("");for(var a,n=0;n'],t.cellXfs.forEach(function(e,t){var r=[];r.push(Yt("NumberFormat",null,{"ss:Format":kt(me[e.numFmtId])}));t={"ss:ID":"s"+(21+t)};a.push(Yt("Style",r.join(""),t))}),Yt("Styles",a.join(""))),r[3]=function(e){if(!((e||{}).Workbook||{}).Names)return"";for(var t=e.Workbook.Names,r=[],a=0;a=r.sheetRows)){var a,n,s;if(r.cellStyles&&t.XF&&t.XF.data&&(n=r,(s=(a=t).XF.data)&&s.patternType&&n&&n.cellStyles&&(a.s={},a.s.patternType=s.patternType,(n=Qi(o(s.icvFore)))&&(a.s.fgColor={rgb:n}),(n=Qi(o(s.icvBack)))&&(a.s.bgColor={rgb:n}))),delete t.ixfe,delete t.XF,v=Kr(c=e),d&&d.s&&d.e||(d={s:{r:0,c:0},e:{r:0,c:0}}),e.rd.e.r&&(d.e.r=e.r+1),e.c+1>d.e.c&&(d.e.c=e.c+1),r.cellFormula&&t.f)for(var i=0;ie.c||T[i][0].s.r>e.r||T[i][0].e.c>8)!==W)throw new Error("rt mismatch: "+V+"!="+W);12==z.r&&(e.l+=10,H-=10)}var G,j,$,X={},X=10===W?z.f(e,H,_):function(e,t,r,a,n){var s=a,i=[],o=r.slice(r.l,r.l+s);if(n&&n.enc&&n.enc.insitu&&0>8&63]),Cf(Z,t,r.opts.Date1904),n({c:X.c,r:X.r},Z,t);break;case 5:case 517:Z={ixfe:X.ixfe,XF:E[X.ixfe],v:X.val,t:X.t},0>8&63]),Cf(Z,t,r.opts.Date1904),n({c:X.c,r:X.r},Z,t);break;case 638:Z={ixfe:X.ixfe,XF:E[X.ixfe],v:X.rknum,t:"n"},0>8&63]),Cf(Z,t,r.opts.Date1904),n({c:X.c,r:X.r},Z,t);break;case 189:for(var J=X.c;J<=X.C;++J){var q=X.rkrec[J-X.c][0],Z={ixfe:q,XF:E[q],v:X.rkrec[J-X.c][1],t:"n"};0>8&63]),Cf(Z,t,r.opts.Date1904),n({c:J,r:X.r},Z,t)}break;case 6:case 518:case 1030:if("String"==X.val){p=X;break}(Z=Rf(X.val,X.cell.ixfe,X.tt)).XF=E[Z.ixfe],t.cellFormula&&(!((Q=X.formula)&&Q[0]&&Q[0][0]&&"PtgExp"==Q[0][0][0])||w[$=Kr({r:G=Q[0][0][1][0],c:j=Q[0][0][1][1]})]?Z.f=""+Pc(X.formula,0,X.cell,I,_):Z.F=((t.dense?(h[G]||[])[j]:h[$])||{}).F),0>8&63]),Cf(Z,t,r.opts.Date1904),n(X.cell,Z,t),p=X;break;case 7:case 519:if(!p)throw new Error("String record expects Formula");(Z=Rf(p.val=X,p.cell.ixfe,"s")).XF=E[Z.ixfe],t.cellFormula&&(Z.f=""+Pc(p.formula,0,p.cell,I,_)),0>8&63]),Cf(Z,t,r.opts.Date1904),n(p.cell,Z,t),p=null;break;case 33:case 545:T.push(X);var Q=Kr(X[0].s),ee=t.dense?(h[X[0].s.r]||[])[X[0].s.c]:h[Q];if(t.cellFormula&&ee){if(!p)break;if(!Q||!ee)break;ee.f=""+Pc(X[1],0,X[0],I,_),ee.F=qr(X[0])}break;case 1212:if(!t.cellFormula)break;if(v){if(!p)break;w[Kr(p.cell)]=X[0],((ee=t.dense?(h[p.cell.r]||[])[p.cell.c]:h[Kr(p.cell)])||{}).f=""+Pc(X[0],0,c,I,_)}break;case 253:Z=Rf(m[X.isst].t,X.ixfe,"s"),m[X.isst].h&&(Z.h=m[X.isst].h),Z.XF=E[Z.ixfe],0>8&63]),Cf(Z,t,r.opts.Date1904),n({c:X.c,r:X.r},Z,t);break;case 513:t.sheetStubs&&(Z={ixfe:X.ixfe,XF:E[X.ixfe],t:"z"},0>8&63]),Cf(Z,t,r.opts.Date1904),n({c:X.c,r:X.r},Z,t));break;case 190:if(t.sheetStubs)for(var te=X.c;te<=X.C;++te){var re=X.ixfe[te-X.c];Z={ixfe:re,XF:E[re],t:"z"},0>8&63]),Cf(Z,t,r.opts.Date1904),n({c:te,r:X.r},Z,t)}break;case 214:case 516:case 4:(Z=Rf(X.val,X.ixfe,"s")).XF=E[Z.ixfe],0>8&63]),Cf(Z,t,r.opts.Date1904),n({c:X.c,r:X.r},Z,t);break;case 0:case 512:1===D&&(d=X);break;case 252:m=X;break;case 1054:if(4==_.biff){L[P++]=X[1];for(var ae=0;ae=X.s;)C[X.e--]={width:X.w/256,level:X.level||0,hidden:!!(1&X.flags)},O||(O=!0,lo(X.w/256)),fo(C[X.e+1]);break;case 520:se={};null!=X.level&&((R[X.r]=se).level=X.level),X.hidden&&((R[X.r]=se).hidden=!0),X.hpt&&((R[X.r]=se).hpt=X.hpt,se.hpx=po(X.hpt));break;case 38:case 39:case 40:case 41:h["!margins"]||Qc(h["!margins"]={}),h["!margins"][{38:"left",39:"right",40:"top",41:"bottom"}[W]]=X;break;case 161:h["!margins"]||Qc(h["!margins"]={}),h["!margins"].header=X.header,h["!margins"].footer=X.footer;break;case 574:X.RTL&&(y.Views[0].RTL=!0);break;case 146:k=X;break;case 2198:f=X;break;case 140:l=X;break;case 442:g?S.CodeName=X||S.name:y.WBProps.CodeName=X||"ThisWorkbook"}}else z||console.error("Missing Info for XLS Record 0x"+W.toString(16)),e.l+=H}return r.SheetNames=Re(u).sort(function(e,t){return Number(e)-Number(t)}).map(function(e){return u[e].name}),t.bookSheets||(r.Sheets=a),!r.SheetNames.length&&b["!ref"]?(r.SheetNames.push("Sheet1"),r.Sheets&&(r.Sheets.Sheet1=b)):r.Preamble=b,r.Sheets&&M.forEach(function(e,t){r.Sheets[r.SheetNames[t]]["!autofilter"]=e}),r.Strings=m,r.SSF=Ve(me),_.enc&&(r.Encryption=_.enc),f&&(r.Themes=f),r.Metadata={},void 0!==l&&(r.Metadata.Country=l),0>>1,a=e.read_shift(1),n=e.read_shift(2,"i"),s=e.read_shift(1),i=e.read_shift(1),o=e.read_shift(1);switch(e.l++,r){case 0:t.auto=1;break;case 1:t.index=a;var c=Ba[a];c&&(t.rgb=Qi(c));break;case 2:t.rgb=Qi([s,i,o]);break;case 3:t.theme=a}return 0!=n&&(t.tint=0>13&3],r.showPivotChartFilter=!!(32768&a),r.updateLinks=["userSet","never","always"][a>>8&3],r}},154:{},155:{},156:{f:function(e,t){var r={};return r.Hidden=e.read_shift(4),r.iTabID=e.read_shift(4),r.strRelID=wa(e,t-8),r.name=sa(e),r}},157:{},158:{},159:{T:1,f:function(e){return[e.read_shift(4),e.read_shift(4)]}},160:{T:-1},161:{T:1,f:Sa},162:{T:-1},163:{T:1},164:{T:-1},165:{T:1},166:{T:-1},167:{},168:{},169:{},170:{},171:{},172:{T:1},173:{T:-1},174:{},175:{},176:{f:Lt},177:{T:1},178:{T:-1},179:{T:1},180:{T:-1},181:{T:1},182:{T:-1},183:{T:1},184:{T:-1},185:{T:1},186:{T:-1},187:{T:1},188:{T:-1},189:{T:1},190:{T:-1},191:{T:1},192:{T:-1},193:{T:1},194:{T:-1},195:{T:1},196:{T:-1},197:{T:1},198:{T:-1},199:{T:1},200:{T:-1},201:{T:1},202:{T:-1},203:{T:1},204:{T:-1},205:{T:1},206:{T:-1},207:{T:1},208:{T:-1},209:{T:1},210:{T:-1},211:{T:1},212:{T:-1},213:{T:1},214:{T:-1},215:{T:1},216:{T:-1},217:{T:1},218:{T:-1},219:{T:1},220:{T:-1},221:{T:1},222:{T:-1},223:{T:1},224:{T:-1},225:{T:1},226:{T:-1},227:{T:1},228:{T:-1},229:{T:1},230:{T:-1},231:{T:1},232:{T:-1},233:{T:1},234:{T:-1},235:{T:1},236:{T:-1},237:{T:1},238:{T:-1},239:{T:1},240:{T:-1},241:{T:1},242:{T:-1},243:{T:1},244:{T:-1},245:{T:1},246:{T:-1},247:{T:1},248:{T:-1},249:{T:1},250:{T:-1},251:{T:1},252:{T:-1},253:{T:1},254:{T:-1},255:{T:1},256:{T:-1},257:{T:1},258:{T:-1},259:{T:1},260:{T:-1},261:{T:1},262:{T:-1},263:{T:1},264:{T:-1},265:{T:1},266:{T:-1},267:{T:1},268:{T:-1},269:{T:1},270:{T:-1},271:{T:1},272:{T:-1},273:{T:1},274:{T:-1},275:{T:1},276:{T:-1},277:{},278:{T:1},279:{T:-1},280:{T:1},281:{T:-1},282:{T:1},283:{T:1},284:{T:-1},285:{T:1},286:{T:-1},287:{T:1},288:{T:-1},289:{T:1},290:{T:-1},291:{T:1},292:{T:-1},293:{T:1},294:{T:-1},295:{T:1},296:{T:-1},297:{T:1},298:{T:-1},299:{T:1},300:{T:-1},301:{T:1},302:{T:-1},303:{T:1},304:{T:-1},305:{T:1},306:{T:-1},307:{T:1},308:{T:-1},309:{T:1},310:{T:-1},311:{T:1},312:{T:-1},313:{T:-1},314:{T:1},315:{T:-1},316:{T:1},317:{T:-1},318:{T:1},319:{T:-1},320:{T:1},321:{T:-1},322:{T:1},323:{T:-1},324:{T:1},325:{T:-1},326:{T:1},327:{T:-1},328:{T:1},329:{T:-1},330:{T:1},331:{T:-1},332:{T:1},333:{T:-1},334:{T:1},335:{f:function(e,t){return{flags:e.read_shift(4),version:e.read_shift(4),name:sa(e)}}},336:{T:-1},337:{f:function(e){return e.l+=4,0!=e.read_shift(4)},T:1},338:{T:-1},339:{T:1},340:{T:-1},341:{T:1},342:{T:-1},343:{T:1},344:{T:-1},345:{T:1},346:{T:-1},347:{T:1},348:{T:-1},349:{T:1},350:{T:-1},351:{},352:{},353:{T:1},354:{T:-1},355:{f:wa},357:{},358:{},359:{},360:{T:1},361:{},362:{f:ps},363:{},364:{},366:{},367:{},368:{},369:{},370:{},371:{},372:{T:1},373:{T:-1},374:{T:1},375:{T:-1},376:{T:1},377:{T:-1},378:{T:1},379:{T:-1},380:{T:1},381:{T:-1},382:{T:1},383:{T:-1},384:{T:1},385:{T:-1},386:{T:1},387:{T:-1},388:{T:1},389:{T:-1},390:{T:1},391:{T:-1},392:{T:1},393:{T:-1},394:{T:1},395:{T:-1},396:{},397:{},398:{},399:{},400:{},401:{T:1},403:{},404:{},405:{},406:{},407:{},408:{},409:{},410:{},411:{},412:{},413:{},414:{},415:{},416:{},417:{},418:{},419:{},420:{},421:{},422:{T:1},423:{T:1},424:{T:-1},425:{T:-1},426:{f:function(e,t,r){var a=e.l+t,n=ya(e),t=e.read_shift(1);return(n=[n])[2]=t,r.cellFormula?(r=Bc(e,a-e.l,r),n[1]=r):e.l=a,n}},427:{f:function(e,t,r){var a=e.l+t,t=[Sa(e,16)];return r.cellFormula&&(r=zc(e,a-e.l,r),t[1]=r),e.l=a,t}},428:{},429:{T:1},430:{T:-1},431:{T:1},432:{T:-1},433:{T:1},434:{T:-1},435:{T:1},436:{T:-1},437:{T:1},438:{T:-1},439:{T:1},440:{T:-1},441:{T:1},442:{T:-1},443:{T:1},444:{T:-1},445:{T:1},446:{T:-1},447:{T:1},448:{T:-1},449:{T:1},450:{T:-1},451:{T:1},452:{T:-1},453:{T:1},454:{T:-1},455:{T:1},456:{T:-1},457:{T:1},458:{T:-1},459:{T:1},460:{T:-1},461:{T:1},462:{T:-1},463:{T:1},464:{T:-1},465:{T:1},466:{T:-1},467:{T:1},468:{T:-1},469:{T:1},470:{T:-1},471:{},472:{},473:{T:1},474:{T:-1},475:{},476:{f:function(t){var r={};return Il.forEach(function(e){r[e]=xa(t)}),r}},477:{},478:{},479:{T:1},480:{T:-1},481:{T:1},482:{T:-1},483:{T:1},484:{T:-1},485:{f:function(){}},486:{T:1},487:{T:-1},488:{T:1},489:{T:-1},490:{T:1},491:{T:-1},492:{T:1},493:{T:-1},494:{f:function(e,t){var r=e.l+t,a=Sa(e,16),n=ga(e),s=sa(e),i=sa(e),t=sa(e);return e.l=r,t={rfx:a,relId:n,loc:s,display:t},i&&(t.Tooltip=i),t}},495:{T:1},496:{T:-1},497:{T:1},498:{T:-1},499:{},500:{T:1},501:{T:-1},502:{T:1},503:{T:-1},504:{},505:{T:1},506:{T:-1},507:{},508:{T:1},509:{T:-1},510:{T:1},511:{T:-1},512:{},513:{},514:{T:1},515:{T:-1},516:{T:1},517:{T:-1},518:{T:1},519:{T:-1},520:{T:1},521:{T:-1},522:{},523:{},524:{},525:{},526:{},527:{},528:{T:1},529:{T:-1},530:{T:1},531:{T:-1},532:{T:1},533:{T:-1},534:{},535:{},536:{},537:{},538:{T:1},539:{T:-1},540:{T:1},541:{T:-1},542:{T:1},548:{},549:{},550:{f:wa},551:{},552:{},553:{},554:{T:1},555:{T:-1},556:{T:1},557:{T:-1},558:{T:1},559:{T:-1},560:{T:1},561:{T:-1},562:{},564:{},565:{T:1},566:{T:-1},569:{T:1},570:{T:-1},572:{},573:{T:1},574:{T:-1},577:{},578:{},579:{},580:{},581:{},582:{},583:{},584:{},585:{},586:{},587:{},588:{T:-1},589:{},590:{T:1},591:{T:-1},592:{T:1},593:{T:-1},594:{T:1},595:{T:-1},596:{},597:{T:1},598:{T:-1},599:{T:1},600:{T:-1},601:{T:1},602:{T:-1},603:{T:1},604:{T:-1},605:{T:1},606:{T:-1},607:{},608:{T:1},609:{T:-1},610:{},611:{T:1},612:{T:-1},613:{T:1},614:{T:-1},615:{T:1},616:{T:-1},617:{T:1},618:{T:-1},619:{T:1},620:{T:-1},625:{},626:{T:1},627:{T:-1},628:{T:1},629:{T:-1},630:{T:1},631:{T:-1},632:{f:Ue},633:{T:1},634:{T:-1},635:{T:1,f:function(e){var t={};t.iauthor=e.read_shift(4);var r=Sa(e,16);return t.rfx=r.s,t.ref=Kr(r.s),e.l+=16,t}},636:{T:-1},637:{f:ca},638:{T:1},639:{},640:{T:-1},641:{T:1},642:{T:-1},643:{T:1},644:{},645:{T:-1},646:{T:1},648:{T:1},649:{},650:{T:-1},651:{f:function(e,t){return e.l+=10,{name:sa(e)}}},652:{},653:{T:1},654:{T:-1},655:{T:1},656:{T:-1},657:{T:1},658:{T:-1},659:{},660:{T:1},661:{},662:{T:-1},663:{},664:{T:1},665:{},666:{T:-1},667:{},668:{},669:{},671:{T:1},672:{T:-1},673:{T:1},674:{T:-1},675:{},676:{},677:{},678:{},679:{},680:{},681:{},1024:{},1025:{},1026:{T:1},1027:{T:-1},1028:{T:1},1029:{T:-1},1030:{},1031:{T:1},1032:{T:-1},1033:{T:1},1034:{T:-1},1035:{},1036:{},1037:{},1038:{T:1},1039:{T:-1},1040:{},1041:{T:1},1042:{T:-1},1043:{},1044:{},1045:{},1046:{T:1},1047:{T:-1},1048:{T:1},1049:{T:-1},1050:{},1051:{T:1},1052:{T:1},1053:{f:function(){}},1054:{T:1},1055:{},1056:{T:1},1057:{T:-1},1058:{T:1},1059:{T:-1},1061:{},1062:{T:1},1063:{T:-1},1064:{T:1},1065:{T:-1},1066:{T:1},1067:{T:-1},1068:{T:1},1069:{T:-1},1070:{T:1},1071:{T:-1},1072:{T:1},1073:{T:-1},1075:{T:1},1076:{T:-1},1077:{T:1},1078:{T:-1},1079:{T:1},1080:{T:-1},1081:{T:1},1082:{T:-1},1083:{T:1},1084:{T:-1},1085:{},1086:{T:1},1087:{T:-1},1088:{T:1},1089:{T:-1},1090:{T:1},1091:{T:-1},1092:{T:1},1093:{T:-1},1094:{T:1},1095:{T:-1},1096:{},1097:{T:1},1098:{},1099:{T:-1},1100:{T:1},1101:{T:-1},1102:{},1103:{},1104:{},1105:{},1111:{},1112:{},1113:{T:1},1114:{T:-1},1115:{T:1},1116:{T:-1},1117:{},1118:{T:1},1119:{T:-1},1120:{T:1},1121:{T:-1},1122:{T:1},1123:{T:-1},1124:{T:1},1125:{T:-1},1126:{},1128:{T:1},1129:{T:-1},1130:{},1131:{T:1},1132:{T:-1},1133:{T:1},1134:{T:-1},1135:{T:1},1136:{T:-1},1137:{T:1},1138:{T:-1},1139:{T:1},1140:{T:-1},1141:{},1142:{T:1},1143:{T:-1},1144:{T:1},1145:{T:-1},1146:{},1147:{T:1},1148:{T:-1},1149:{T:1},1150:{T:-1},1152:{T:1},1153:{T:-1},1154:{T:-1},1155:{T:-1},1156:{T:-1},1157:{T:1},1158:{T:-1},1159:{T:1},1160:{T:-1},1161:{T:1},1162:{T:-1},1163:{T:1},1164:{T:-1},1165:{T:1},1166:{T:-1},1167:{T:1},1168:{T:-1},1169:{T:1},1170:{T:-1},1171:{},1172:{T:1},1173:{T:-1},1177:{},1178:{T:1},1180:{},1181:{},1182:{},2048:{T:1},2049:{T:-1},2050:{},2051:{T:1},2052:{T:-1},2053:{},2054:{},2055:{T:1},2056:{T:-1},2057:{T:1},2058:{T:-1},2060:{},2067:{},2068:{T:1},2069:{T:-1},2070:{},2071:{},2072:{T:1},2073:{T:-1},2075:{},2076:{},2077:{T:1},2078:{T:-1},2079:{},2080:{T:1},2081:{T:-1},2082:{},2083:{T:1},2084:{T:-1},2085:{T:1},2086:{T:-1},2087:{T:1},2088:{T:-1},2089:{T:1},2090:{T:-1},2091:{},2092:{},2093:{T:1},2094:{T:-1},2095:{},2096:{T:1},2097:{T:-1},2098:{T:1},2099:{T:-1},2100:{T:1},2101:{T:-1},2102:{},2103:{T:1},2104:{T:-1},2105:{},2106:{T:1},2107:{T:-1},2108:{},2109:{T:1},2110:{T:-1},2111:{T:1},2112:{T:-1},2113:{T:1},2114:{T:-1},2115:{},2116:{},2117:{},2118:{T:1},2119:{T:-1},2120:{},2121:{T:1},2122:{T:-1},2123:{T:1},2124:{T:-1},2125:{},2126:{T:1},2127:{T:-1},2128:{},2129:{T:1},2130:{T:-1},2131:{T:1},2132:{T:-1},2133:{T:1},2134:{},2135:{},2136:{},2137:{T:1},2138:{T:-1},2139:{T:1},2140:{T:-1},2141:{},3072:{},3073:{},4096:{T:1},4097:{T:-1},5002:{T:1},5003:{T:-1},5081:{T:1},5082:{T:-1},5083:{},5084:{T:1},5085:{T:-1},5086:{T:1},5087:{T:-1},5088:{},5089:{},5090:{},5092:{T:1},5093:{T:-1},5094:{},5095:{T:1},5096:{T:-1},5097:{},5099:{},65535:{n:""}},Pf={6:{f:Lc},10:{f:Rn},12:{f:Nn},13:{f:Nn},14:{f:On},15:{f:On},16:{f:xa},17:{f:On},18:{f:On},19:{f:Nn},20:{f:fs},21:{f:fs},23:{f:ps},24:{f:ds},25:{f:On},26:{},27:{},28:{f:function(e,t,r){return function(e,t){if(!(t.biff<8)){var r=e.read_shift(2),a=e.read_shift(2),n=e.read_shift(2),s=e.read_shift(2),i=Bn(e,0,t);return t.biff<8&&e.read_shift(1),[{r:r,c:a},i,s,n]}}(e,r)}},29:{},34:{f:On},35:{f:hs},38:{f:xa},39:{f:xa},40:{f:xa},41:{f:xa},42:{f:On},43:{f:On},47:{f:function(e,t,r){var a={Type:8<=r.biff?e.read_shift(2):0};return a.Type?Ki(e,t-2,a):(t=e,r.biff,e=r,r=a,t={key:Nn(t),verificationBytes:Nn(t)},e.password&&(t.verifier=zi(e.password)),r.valid=t.verificationBytes===t.verifier,r.valid&&(r.insitu=Yi(e.password))),a}},49:{f:function(e,t,r){var a={dyHeight:e.read_shift(2),fl:e.read_shift(2)};switch(r&&r.biff||8){case 2:break;case 3:case 4:e.l+=2;break;default:e.l+=10}return a.name=Ln(e,0,r),a}},51:{f:Nn},60:{},61:{f:function(e){return{Pos:[e.read_shift(2),e.read_shift(2)],Dim:[e.read_shift(2),e.read_shift(2)],Flags:e.read_shift(2),CurTab:e.read_shift(2),FirstTab:e.read_shift(2),Selected:e.read_shift(2),TabRatio:e.read_shift(2)}}},64:{f:On},65:{f:function(){}},66:{f:Nn},77:{},80:{},81:{},82:{},85:{f:Nn},89:{},90:{},91:{},92:{f:function(e,t,r){if(r.enc)return e.l+=t,"";var a=e.l,r=Bn(e,0,r);return e.read_shift(t+a-e.l),r}},93:{f:function(e,t,r){return r&&r.biff<8?function(e,t,r){e.l+=4;var a=e.read_shift(2),n=e.read_shift(2),s=e.read_shift(2);e.l+=2,e.l+=2,e.l+=2,e.l+=2,e.l+=2,e.l+=2,e.l+=2,e.l+=2,e.l+=2,e.l+=6,t-=36;var i=[];return i.push((gs[a]||Pr)(e,t,r)),{cmo:[n,a,s],ft:i}}(e,t,r):{cmo:r=Qn(e),ft:function(t,e){for(var r=t.l+e,a=[];t.l>2&1,t-=6,i.data=(a=e,i.fStyle,n=r,s={},t=a.read_shift(4),e=a.read_shift(4),r=a.read_shift(4),a=a.read_shift(2),s.patternType=Ua[r>>26],n.cellStyles&&(s.alc=7&t,s.fWrap=t>>3&1,s.alcV=t>>4&7,s.fJustLast=t>>7&1,s.trot=t>>8&255,s.cIndent=t>>16&15,s.fShrinkToFit=t>>20&1,s.iReadOrder=t>>22&2,s.fAtrNum=t>>26&1,s.fAtrFnt=t>>27&1,s.fAtrAlc=t>>28&1,s.fAtrBdr=t>>29&1,s.fAtrPat=t>>30&1,s.fAtrProt=t>>31&1,s.dgLeft=15&e,s.dgRight=e>>4&15,s.dgTop=e>>8&15,s.dgBottom=e>>12&15,s.icvLeft=e>>16&127,s.icvRight=e>>23&127,s.grbitDiag=e>>30&3,s.icvTop=127&r,s.icvBottom=r>>7&127,s.icvDiag=r>>14&127,s.dgDiag=r>>21&15,s.icvFore=127&a,s.icvBack=a>>7&127,s.fsxButton=a>>14&1),s),i}},225:{f:function(e,t){return 0===t||e.read_shift(2),1200}},226:{f:Rn},227:{},229:{f:function(e,t){for(var r=[],a=e.read_shift(2);a--;)r.push(Kn(e));return r}},233:{},235:{},236:{},237:{},239:{},240:{},241:{},242:{},244:{},245:{},246:{},247:{},248:{},249:{},251:{},252:{f:function(e,t){for(var r=e.l+t,t=e.read_shift(4),a=e.read_shift(4),n=[],s=0;s!=a&&e.l"+c.t+"",c.r=c.t),f=t,c}(e));return n.Count=t,n.Unique=a,n}},253:{f:function(e){var t=$n(e);return t.isst=e.read_shift(4),t}},255:{f:function(e,t){var r={};return r.dsst=e.read_shift(2),e.l+=t-2,r}},256:{},259:{},290:{},311:{},312:{},315:{},317:{f:Dn},318:{},319:{},320:{},330:{},331:{},333:{},334:{},335:{},336:{},337:{},338:{},339:{},340:{},351:{},352:{f:On},353:{f:Rn},401:{},402:{},403:{},404:{},405:{},406:{},407:{},408:{},425:{},426:{},427:{},428:{},429:{},430:{f:function(e,t,r){var a=e.l+t,n=e.read_shift(2),t=e.read_shift(2);if(1025==(r.sbcch=t)||14849==t)return[t,n];if(t<1||255e.l;)s.push(Un(e));return[t,n,r,s]}},431:{f:On},432:{},433:{},434:{},437:{},438:{f:function(t,r,e){var a=t.l,n="";try{t.l+=4;var s=(e.lastobj||{cmo:[0,0]}).cmo[1];-1==[0,5,7,11,12,14].indexOf(s)?t.l+=6:function(e){var t=e.read_shift(1);e.l++;var r=e.read_shift(2);e.l+=2}(t);var i=t.read_shift(2);t.read_shift(2),Nn(t);s=t.read_shift(2);t.l+=s;for(var o=1;o=(c?i:2*i))break}if(n.length!==i&&n.length!==2*i)throw new Error("cchText: "+i+" != "+n.length);return t.l=a+r,{t:n}}catch(e){return t.l=a+r,{t:n}}}},439:{f:On},440:{f:function(e,t){var r=Kn(e);return e.l+=16,[r,function(e,t){var r=e.l+t;if(2!==(c=e.read_shift(4)))throw new Error("Unrecognized streamVersion: "+c);t=e.read_shift(2),e.l+=2;var a,n,s,i,o,c="";16&t&&(a=zn(e,e.l)),128&t&&(n=zn(e,e.l)),257==(257&t)&&(s=zn(e,e.l)),1==(257&t)&&(l=Hn(e,e.l)),8&t&&(c=zn(e,e.l)),32&t&&(i=e.read_shift(16)),64&t&&(o=pn(e)),e.l=r;var l=n||s||l||"";return l&&c&&(l+="#"+c),l=l||"#"+c,l={Target:l=2&t&&"/"==l.charAt(0)&&"/"!=l.charAt(1)?"file://"+l:l},i&&(l.guid=i),o&&(l.time=o),a&&(l.Tooltip=a),l}(e,t-24)]}},441:{},442:{f:Un},443:{},444:{f:Nn},445:{},446:{},448:{f:Rn},449:{f:function(e){return e.read_shift(2),e.read_shift(4)},r:2},450:{f:Rn},512:{f:os},513:{f:ws},515:{f:function(e,t,r){return r.biffguess&&2==r.biff&&(r.biff=5),r=$n(e),e=xa(e),r.val=e,r}},516:{f:function(e,t,r){return r.biffguess&&2==r.biff&&(r.biff=5),e.l,t=$n(e),2==r.biff&&e.l++,r=Un(e,e.l,r),t.val=r,t}},517:{f:ls},519:{f:Es},520:{f:function(e){var t={};t.r=e.read_shift(2),t.c=e.read_shift(2),t.cnt=e.read_shift(2)-t.c;var r=e.read_shift(2);e.l+=4;var a=e.read_shift(1);return e.l+=3,7&a&&(t.level=7&a),32&a&&(t.hidden=!0),64&a&&(t.hpt=r/20),t}},523:{},545:{f:ms},549:{f:ss},566:{},574:{f:function(e,t,r){return r&&2<=r.biff&&r.biff<5?{}:{RTL:64&e.read_shift(2)}}},638:{f:function(e){var t=e.read_shift(2),r=e.read_shift(2),e=Yn(e);return{r:t,c:r,ixfe:e[0],rknum:e[1]}}},659:{},1048:{},1054:{f:function(e,t,r){return[e.read_shift(2),Bn(e,0,r)]}},1084:{},1212:{f:function(e,t,r){var a=qn(e);e.l++;var n=e.read_shift(1);return[function(e,t,r){var a,n=e.l+t,s=e.read_shift(2),i=Ic(e,s,r);if(65535==s)return[[],Pr(e,t-2)];t!==s+2&&(a=Oc(e,n-s-2,i,r));return[i,a]}(e,t-=8,r),n,a]}},2048:{f:function(e,t){return e.read_shift(2),[Kn(e),e.read_shift((t-10)/2,"dbcs-cont").replace(de,"")]}},2049:{},2050:{},2051:{},2052:{},2053:{},2054:{},2055:{},2056:{},2057:{f:rs},2058:{},2059:{},2060:{},2061:{},2062:{},2063:{},2064:{},2066:{},2067:{},2128:{},2129:{},2130:{},2131:{},2132:{},2133:{},2134:{},2135:{},2136:{},2137:{},2138:{},2146:{},2147:{r:12},2148:{},2149:{},2150:{},2151:{f:Rn},2152:{},2154:{},2155:{},2156:{},2161:{},2162:{},2164:{},2165:{},2166:{},2167:{},2168:{},2169:{},2170:{},2171:{},2172:{f:function(e){e.l+=2;var t={cxfs:0,crc:0};return t.cxfs=e.read_shift(2),t.crc=e.read_shift(4),t},r:12},2173:{f:function(e,t){e.l,e.l+=2,t=e.read_shift(2),e.l+=2;for(var r=e.read_shift(2),a=[];0n.l?n.slice(0,n.l):n).l&&(n.l=n.length),n))})}function zf(e,t){for(var r=0;r=p){if(t.WTF)throw new Error("Range "+(o["!ref"]||"A1")+" exceeds format limit A1:IV16384");d.e.c=Math.min(d.e.c,255),d.e.r=Math.min(d.e.c,p-1)}Lf(s,2057,as(0,16,t)),Lf(s,13,Fn(1)),Lf(s,12,Fn(100)),Lf(s,15,In(!0)),Lf(s,17,In(!1)),Lf(s,16,Aa(.001)),Lf(s,95,In(!0)),Lf(s,42,In(!1)),Lf(s,43,In(!1)),Lf(s,130,Fn(1)),Lf(s,128,(r=[0,0],(e=Lr(8)).write_shift(4,0),e.write_shift(2,r[0]?r[0]+1:0),e.write_shift(2,r[1]?r[1]+1:0),e)),Lf(s,131,In(!1)),Lf(s,132,In(!1)),h&&Vf(s,o["!cols"]),Lf(s,512,(p=d,(r=Lr(2*(e=8!=(r=t).biff&&r.biff?2:4)+6)).write_shift(e,p.s.r),r.write_shift(e,p.e.r+1),r.write_shift(2,p.s.c),r.write_shift(2,p.e.c+1),r.write_shift(2,0),r)),h&&(o["!links"]=[]);for(var m=d.s.r;m<=d.e.r;++m){n=jr(m);for(var g=d.s.c;g<=d.e.c;++g){m===d.s.r&&(u[g]=Xr(g)),a=u[g]+n;var b=f?(o[m]||[])[g]:o[a];b&&(Gf(s,b,m,g,t),h&&b.l&&o["!links"].push([a,b.l]))}}var v,w,i=l.CodeName||l.name||i;return h&&Lf(s,574,(c=(c.Views||[])[0],w=Lr(18),v=1718,c&&c.RTL&&(v|=64),w.write_shift(2,v),w.write_shift(4,0),w.write_shift(4,64),w.write_shift(4,0),w.write_shift(4,0),w)),h&&(o["!merges"]||[]).length&&Lf(s,229,function(e){var t=Lr(2+8*e.length);t.write_shift(2,e.length);for(var r=0;r/g,"")).match(/");for(var s,t=e.match(/<\/table/i),i=n.index,o=t&&t.index||e.length,c=Ke(e.slice(i,o),/(:?]*>)/i,""),l=-1,f=0,h={s:{r:1e7,c:1e7},e:{r:0,c:0}},u=[],i=0;i/i),o=0;o"));)b=b.slice(v+1);for(var w=0;w"))),k=E.colspan?+E.colspan:1;(1<(s=+E.rowspan)||1l&&(h.s.r=l),h.e.rf&&(h.s.c=f),h.e.cr||n[d].s.c>i||n[d].e.r'+l+"":c&&(f["data-t"]=c&&c.t||"z",null!=c.v&&(f["data-v"]=c.v),null!=c.z&&(f["data-z"]=c.z),c.l&&"#"!=(c.l.Target||"#").charAt(0)&&(l=''+l+"")),f.id=(a.id||"sjs")+"-"+o,s.push(Yt("td",l,f)))}return""+s.join("")+""}var Jf='SheetJS Table Export',qf="";function Zf(e,t,r){return[].join("")+""}function Qf(e,t){var r=t||{},a=null!=r.header?r.header:Jf,t=null!=r.footer?r.footer:qf,n=[a],s=Jr(e["!ref"]);r.dense=Array.isArray(e),n.push(Zf(0,0,r));for(var i=s.s.r;i<=s.e.r;++i)n.push(Kf(e,s,i,r));return n.push("
"+t),n.join("")}function eh(e,t,r){var a=r||{};null!=oe&&(a.dense=oe);var n=0,s=0;null!=a.origin&&("number"==typeof a.origin?n=a.origin:(n=(r="string"==typeof a.origin?Yr(a.origin):a.origin).r,s=r.c));var i=t.getElementsByTagName("tr"),o=Math.min(a.sheetRows||1e7,i.length),c={s:{r:0,c:0},e:{r:n,c:s}};e["!ref"]&&(t=Jr(e["!ref"]),c.s.r=Math.min(c.s.r,t.s.r),c.s.c=Math.min(c.s.c,t.s.c),c.e.r=Math.max(c.e.r,t.e.r),c.e.c=Math.max(c.e.c,t.e.c),-1==n&&(c.e.r=n=t.e.r+1));var l,f,h=[],u=0,d=e["!rows"]||(e["!rows"]=[]),p=0,m=0,g=0,b=0;for(e["!cols"]||(e["!cols"]=[]);p/gm,"").replace(//gm,"");i=qt.exec(c);)switch(i[3]=i[3].replace(/_.*$/,"")){case"table":case"工作表":"/"===i[1]?(k.e.c>=k.s.c&&k.e.r>=k.s.r?m["!ref"]=qr(k):m["!ref"]="A1:A1",0k.e.c&&(k.e.c=E),Ek.e.r&&(k.e.r=H),D=[],P={},o={t:(g=dt(i[0],!1))["数据类型"]||g["value-type"],v:null},r.cellFormula)if(g.formula&&(g.formula=wt(g.formula)),g["number-matrix-columns-spanned"]&&g["number-matrix-rows-spanned"]&&(x={s:{r:T,c:E},e:{r:T+(parseInt(g["number-matrix-rows-spanned"],10)||0)-1,c:E+(parseInt(g["number-matrix-columns-spanned"],10)||0)-1}},o.F=qr(x),O.push([x,o.F])),g.formula)o.f=$c(g.formula);else for(W=0;W=O[W][0].s.r&&T<=O[W][0].e.r&&E>=O[W][0].s.c&&E<=O[W][0].e.c&&(o.F=O[W][1]);switch((g["number-columns-spanned"]||g["number-rows-spanned"])&&(x={s:{r:T,c:E},e:{r:T+(parseInt(g["number-rows-spanned"],10)||0)-1,c:E+(parseInt(g["number-columns-spanned"],10)||0)-1}},_.push(x)),g["number-columns-repeated"]&&(R=parseInt(g["number-columns-repeated"],10)),o.t){case"boolean":o.t="b",o.v=Rt(g["boolean-value"]);break;case"float":case"percentage":case"currency":o.t="n",o.v=parseFloat(g.value);break;case"date":o.t="d",o.v=He(g["date-value"]),r.cellDates||(o.t="n",o.v=De(o.v)),o.z="m/d/yy";break;case"time":o.t="n",o.v=function(e){var t=0,r=0,a=!1,n=e.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);if(!n)throw new Error("|"+e+"| is not an ISO8601 Duration");for(var s=1;s!=n.length;++s)if(n[s]){switch(r=1,3"===i[0].slice(-2))break;if("/"===i[1])switch(l[l.length-1][0]){case"number-style":case"date-style":case"time-style":h+=c.slice(u,i.index)}else u=i.index+i[0].length;break;case"named-range":F=Xc((n=dt(i[0],!1))["cell-range-address"]);var V={Name:n.name,Ref:F[0]+"!"+F[1]};B&&(V.Sheet=p.length),I.Names.push(V);break;case"text-content":case"text-properties":case"embedded-text":break;case"body":case"电子表格":case"forms":case"table-column":case"table-header-rows":case"table-rows":case"table-column-group":case"table-header-columns":case"table-columns":case"null-date":case"graphic-properties":case"calculation-settings":case"named-expressions":case"label-range":case"label-ranges":case"named-expression":case"sort":case"sort-by":case"sort-groups":case"tab":case"line-break":case"span":break;case"p":case"文本串":if(-1<["master-styles"].indexOf(l[l.length-1][0]))break;"/"!==i[1]||g&&g["string-value"]?(dt(i[0],!1),v=i.index+i[0].length):(V=(V=c.slice(v,i.index)).replace(/[\t\r\n]/g," ").trim().replace(/ +/g," ").replace(//g," ").replace(//g,function(e,t){return Array(parseInt(t,10)+1).join(" ")}).replace(/]*\/>/g,"\t").replace(//g,"\n"),V=[wt(V.replace(/<[^>]*>/g,""))],b=(0",'',"",'',"",'',"",""].join(""),t=""+e+"";return function(){return ot+t}}(),ch=function(){function i(e,t,r){var a=[];a.push(' \n');var n=0,s=0,i=Jr(e["!ref"]||"A1"),o=e["!merges"]||[],c=0,l=Array.isArray(e);if(e["!cols"])for(s=0;s<=i.e.c;++s)a.push(" \n");for(var f="",h=e["!rows"]||[],n=0;n\n");for(;n<=i.e.r;++n){for(f=h[n]?' table:style-name="ro'+h[n].ods+'"':"",a.push(" \n"),s=0;ss||o[c].s.r>n||o[c].e.c\n");else{var m=Kr({r:n,c:s}),g=l?(e[n]||[])[s]:e[m];if(g&&g.f&&(d["table:formula"]=kt(("of:="+g.f.replace(lc,"$1[.$2$3$4$5]").replace(/\]:\[/g,":")).replace(/;/g,"|").replace(/,/g,";")),g.F&&g.F.slice(0,m.length)==m&&(b=Jr(g.F),d["table:number-matrix-columns-spanned"]=b.e.c-b.s.c+1,d["table:number-matrix-rows-spanned"]=b.e.r-b.s.r+1)),g){switch(g.t){case"b":p=g.v?"TRUE":"FALSE",d["office:value-type"]="boolean",d["office:boolean-value"]=g.v?"true":"false";break;case"n":p=g.w||String(g.v||0),d["office:value-type"]="float",d["office:value"]=g.v||0;break;case"s":case"str":p=null==g.v?"":g.v,d["office:value-type"]="string";break;case"d":p=g.w||He(g.v).toISOString(),d["office:value-type"]="date",d["office:date-value"]=He(g.v).toISOString(),d["table:style-name"]="ce1";break;default:a.push(v);continue}var b,m=kt(p).replace(/ +/g,function(e){return''}).replace(/\t/g,"").replace(/\n/g,"").replace(/^ /,"").replace(/ $/,"");g.l&&g.l.Target&&(m=Yt("text:a",m,{"xlink:href":(b="#"!=(b="#"==(b=g.l.Target).charAt(0)?"#"+b.slice(1).replace(/\./,"!"):b).charAt(0)&&!b.match(/^\w+:/)?"../"+b:b).replace(/&/g,"&")})),a.push(" "+Yt("table:table-cell",Yt("text:p",m,{}),d)+"\n")}else a.push(v)}}a.push(" \n")}return a.push(" \n"),a.join("")}var v=" \n";return function(e,t){var r=[ot],a=Xt({"xmlns:office":"urn:oasis:names:tc:opendocument:xmlns:office:1.0","xmlns:table":"urn:oasis:names:tc:opendocument:xmlns:table:1.0","xmlns:style":"urn:oasis:names:tc:opendocument:xmlns:style:1.0","xmlns:text":"urn:oasis:names:tc:opendocument:xmlns:text:1.0","xmlns:draw":"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0","xmlns:fo":"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0","xmlns:xlink":"http://www.w3.org/1999/xlink","xmlns:dc":"http://purl.org/dc/elements/1.1/","xmlns:meta":"urn:oasis:names:tc:opendocument:xmlns:meta:1.0","xmlns:number":"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0","xmlns:presentation":"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0","xmlns:svg":"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0","xmlns:chart":"urn:oasis:names:tc:opendocument:xmlns:chart:1.0","xmlns:dr3d":"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0","xmlns:math":"http://www.w3.org/1998/Math/MathML","xmlns:form":"urn:oasis:names:tc:opendocument:xmlns:form:1.0","xmlns:script":"urn:oasis:names:tc:opendocument:xmlns:script:1.0","xmlns:ooo":"http://openoffice.org/2004/office","xmlns:ooow":"http://openoffice.org/2004/writer","xmlns:oooc":"http://openoffice.org/2004/calc","xmlns:dom":"http://www.w3.org/2001/xml-events","xmlns:xforms":"http://www.w3.org/2002/xforms","xmlns:xsd":"http://www.w3.org/2001/XMLSchema","xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","xmlns:sheet":"urn:oasis:names:tc:opendocument:sh33tjs:1.0","xmlns:rpt":"http://openoffice.org/2005/report","xmlns:of":"urn:oasis:names:tc:opendocument:xmlns:of:1.2","xmlns:xhtml":"http://www.w3.org/1999/xhtml","xmlns:grddl":"http://www.w3.org/2003/g/data-view#","xmlns:tableooo":"http://openoffice.org/2009/table","xmlns:drawooo":"http://openoffice.org/2010/draw","xmlns:calcext":"urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0","xmlns:loext":"urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0","xmlns:field":"urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0","xmlns:formx":"urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0","xmlns:css3t":"http://www.w3.org/TR/css3-text/","office:version":"1.2"}),n=Xt({"xmlns:config":"urn:oasis:names:tc:opendocument:xmlns:config:1.0","office:mimetype":"application/vnd.oasis.opendocument.spreadsheet"});"fods"==t.bookType?(r.push("\n"),r.push(Qa().replace(/office:document-meta/g,"office:meta"))):r.push("\n"),function(a,t){a.push(" \n"),a.push(' \n'),a.push(' \n'),a.push(" /\n"),a.push(' \n'),a.push(" /\n"),a.push(" \n"),a.push(" \n");var n=0;t.SheetNames.map(function(e){return t.Sheets[e]}).forEach(function(e){if(e&&e["!cols"])for(var t=0;t\n'),a.push(' \n'),a.push(" \n"),++n}});var s=0;t.SheetNames.map(function(e){return t.Sheets[e]}).forEach(function(e){if(e&&e["!rows"])for(var t,r=0;r\n'),a.push(' \n'),a.push(" \n"),++s)}),a.push(' \n'),a.push(' \n'),a.push(" \n"),a.push(' \n'),a.push(" \n")}(r,e),r.push(" \n"),r.push(" \n");for(var s=0;s!=e.SheetNames.length;++s)r.push(i(e.Sheets[e.SheetNames[s]],e,s));return r.push(" \n"),r.push(" \n"),"fods"==t.bookType?r.push(""):r.push(""),r.join("")}}();function lh(e,t){if("fods"==t.bookType)return ch(e,t);var r=nt(),a=[],n=[];return at(r,"mimetype","application/vnd.oasis.opendocument.spreadsheet"),at(r,"content.xml",ch(e,t)),a.push(["content.xml","text/xml"]),n.push(["content.xml","ContentFile"]),at(r,"styles.xml",oh(e,t)),a.push(["styles.xml","text/xml"]),n.push(["styles.xml","StylesFile"]),at(r,"meta.xml",ot+Qa()),a.push(["meta.xml","text/xml"]),n.push(["meta.xml","MetadataFile"]),at(r,"manifest.rdf",function(e){var t=[ot];t.push('\n');for(var r=0;r!=e.length;++r)t.push(Za(e[r][0],e[r][1])),t.push([' \n',' \n'," \n"].join(""));return t.push(Za("","Document","pkg")),t.push(""),t.join("")}(n)),a.push(["manifest.rdf","application/rdf+xml"]),at(r,"META-INF/manifest.xml",function(e){var t=[ot];t.push('\n'),t.push(' \n');for(var r=0;r\n');return t.push(""),t.join("")}(a)),r}function fh(e){return new DataView(e.buffer,e.byteOffset,e.byteLength)}function hh(e){return"undefined"!=typeof TextDecoder?(new TextDecoder).decode(e):Mt(i(e))}function uh(e){return"undefined"!=typeof TextEncoder?(new TextEncoder).encode(e):he(Ut(e))}function dh(e){var t=e.reduce(function(e,t){return e+t.length},0),r=new Uint8Array(t),a=0;return e.forEach(function(e){r.set(e,a),a+=e.length}),r}function ph(e){return 16843009*((e=(858993459&(e-=e>>1&1431655765))+(e>>2&858993459))+(e>>4)&252645135)>>>24}function mh(e,t){var r=t?t[0]:0,a=127&e[r];return 128<=e[r++]&&(a|=(127&e[r])<<7,e[r++]<128||(a|=(127&e[r])<<14,e[r++]<128||(a|=(127&e[r])<<21,e[r++]<128||(a+=(127&e[r])*Math.pow(2,28),++r,e[r++]<128||(a+=(127&e[r])*Math.pow(2,35),++r,e[r++]<128||(a+=(127&e[r])*Math.pow(2,42),++r,e[r++])))))),t&&(t[0]=r),a}function gh(e){var t=new Uint8Array(7);t[0]=127&e;var r=1;return 127>7&127,++r,e<=16383||(t[r-1]|=128,t[r]=e>>14&127,++r,e<=2097151||(t[r-1]|=128,t[r]=e>>21&127,++r,e<=268435455||(t[r-1]|=128,t[r]=e/256>>>21&127,++r,e<=34359738367||(t[r-1]|=128,t[r]=e/65536>>>21&127,++r,e<=4398046511103||(t[r-1]|=128,t[r]=e/16777216>>>21&127,++r)))))),t.slice(0,r)}function bh(e){var t=0,r=127&e[0];return 128<=e[t++]&&(r|=(127&e[1])<<7,e[t++]<128||(r|=(127&e[2])<<14,e[t++]<128||(r|=(127&e[3])<<21,e[+t]<128||(r|=(127&e[4])<<28)))),r}function vh(e){for(var t=[],r=[0];r[0]>>0),e.push(s)}return e}function kh(e){var a=[];return e.forEach(function(e){var t=[[],[{data:gh(e.id),type:0}],[]];null!=e.merge&&(t[3]=[{data:gh(+!!e.merge),type:0}]);var r=[];e.messages.forEach(function(e){r.push(e.data),e.meta[3]=[{type:0,data:gh(e.data.length)}],t[2].push({data:wh(e.meta),type:2})});e=wh(t);a.push(gh(e.length)),a.push(e),r.forEach(function(e){return a.push(e)})}),dh(a)}function yh(e){for(var t=[],r=0;r>2&7),i=(224&t[r[0]++])<<3,i|=t[r[0]++]):(o=1+(t[r[0]++]>>2),2==s?(i=t[r[0]]|t[r[0]+1]<<8,r[0]+=2):(i=(t[r[0]]|t[r[0]+1]<<8|t[r[0]+2]<<16|t[r[0]+3]<<24)>>>0,r[0]+=4)),n=[dh(n)],0==i)throw new Error("Invalid offset 0");if(i>n[0].length)throw new Error("Invalid offset beyond length");if(i<=o)for(n.push(n[0].slice(-i)),o-=i;o>=n[n.length-1].length;)n.push(n[n.length-1]),o-=n[n.length-1].length;n.push(n[0].slice(-i,-i+o))}else{s=t[r[0]++]>>2;s<60?++s:(i=s-59,s=t[r[0]],1>>=0,s++,r[0]+=i),n.push(t.slice(r[0],r[0]+s)),r[0]+=s}}if((e=dh(n)).length!=a)throw new Error("Unexpected length: ".concat(e.length," != ").concat(a));return e}(a,e.slice(r,r+n))),r+=n}if(r!==e.length)throw new Error("data is not a valid framed stream!");return dh(t)}function Sh(e){for(var t=[],r=0;r>8&255]))):a<=16777216?(i+=4,t.push(new Uint8Array([248,a-1&255,a-1>>8&255,a-1>>16&255]))):a<=4294967296&&(i+=5,t.push(new Uint8Array([252,a-1&255,a-1>>8&255,a-1>>16&255,a-1>>>24&255]))),t.push(e.slice(r,r+a)),i+=a,n[0]=0,n[1]=255&i,n[2]=i>>8&255,n[3]=i>>16&255,r+=a}return dh(t)}function _h(e,t,r){var a,n=fh(e),s=n.getUint32(8,!0),i=12,o=-1,c=-1,l=NaN,f=NaN,h=new Date(2001,0,1);switch(1&s&&(l=function(e,t){for(var r=(127&e[t+15])<<7|e[t+14]>>1,a=1&e[t+14],n=t+13;t<=n;--n)a=256*a+e[n];return(128&e[t+15]?-a:a)*Math.pow(10,r-6176)}(e,i),i+=16),2&s&&(f=n.getFloat64(i,!0),i+=8),4&s&&(h.setTime(h.getTime()+1e3*n.getFloat64(i,!0)),i+=8),8&s&&(c=n.getUint32(i,!0),i+=4),16&s&&(o=n.getUint32(i,!0),i+=4),e[1]){case 0:break;case 2:a={t:"n",v:l};break;case 3:a={t:"s",v:t[c]};break;case 5:a={t:"d",v:h};break;case 6:a={t:"b",v:0>7,e[t+14]|=(127&a)<<1;for(var s=0;1<=n;++s,n/=256)e[t+s]=255&n;e[t+15]|=0<=r?0:128}(r,n,e.v),s|=1,n+=16;break;case"b":r[1]=6,a.setFloat64(n,e.v?1:0,!0),s|=2,n+=8;break;case"s":if(-1==t.indexOf(e.v))throw new Error("Value ".concat(e.v," missing from SST!"));r[1]=3,a.setUint32(n,t.indexOf(e.v),!0),s|=8,n+=4;break;default:throw"unsupported cell type "+e.t}return a.setUint32(8,s,!0),r.slice(0,n)}function Ah(e,t){var r=new Uint8Array(32),a=fh(r),n=12,s=0;switch(r[0]=3,e.t){case"n":r[2]=2,a.setFloat64(n,e.v,!0),s|=32,n+=8;break;case"b":r[2]=6,a.setFloat64(n,e.v?1:0,!0),s|=32,n+=8;break;case"s":if(-1==t.indexOf(e.v))throw new Error("Value ".concat(e.v," missing from SST!"));r[2]=3,a.setUint32(n,t.indexOf(e.v),!0),s|=16,n+=4;break;default:throw"unsupported cell type "+e.t}return a.setUint32(4,s,!0),r.slice(0,n)}function Ch(e,t,r){switch(e[0]){case 0:case 1:case 2:case 3:return function(e,t,r,a){var n,s=fh(e),i=s.getUint32(4,!0),o=(1>>0;switch(i){case 1:o[r]=hh(t[3][0].data);break;case 8:var a=vh(s[Rh(t[9][0].data)][0].data),n=s[Rh(a[1][0].data)][0],a=bh(n.meta[1][0].data);if(2001!=a)throw new Error("2000 unexpected reference to ".concat(a));n=vh(n.data);o[r]=n[3].map(function(e){return hh(e.data)}).join("")}}),o}function Ih(e,t){var r=vh(t.data),a=null!=(t=null==r?void 0:r[7])&&t[0]?0>>0?1:0:-1,t=Th(r[5],function(e){return function(e,t){var r,a,n,s=vh(e),i=bh(s[1][0].data)>>>0,o=bh(s[2][0].data)>>>0,c=(null==(e=null==(c=s[8])?void 0:c[0])?void 0:e.data)&&0>>0,data:t.reduce(function(r,a){return r[a.R]||(r[a.R]=[]),a.cells.forEach(function(e,t){if(r[a.R][t])throw new Error("Duplicate cell r=".concat(a.R," c=").concat(t));r[a.R][t]=e}),r},[])}}function Nh(e,t){var r={"!ref":"A1"},a=e[Rh(vh(t.data)[2][0].data)],t=bh(a[0].meta[1][0].data);if(6001!=t)throw new Error("6000 unexpected reference to ".concat(t));return function(r,e,a){var t=vh(e.data);if((e={s:{r:0,c:0},e:{r:0,c:0}}).e.r=(bh(t[6][0].data)>>>0)-1,e.e.r<0)throw new Error("Invalid row varint ".concat(t[6][0].data));if(e.e.c=(bh(t[7][0].data)>>>0)-1,e.e.c<0)throw new Error("Invalid col varint ".concat(t[7][0].data));a["!ref"]=qr(e);var e=vh(t[4][0].data),n=Oh(r,r[Rh(e[4][0].data)][0]),s=null!=(t=e[17])&&t[0]?Oh(r,r[Rh(e[17][0].data)][0]):[],t=vh(e[3][0].data),i=0;if(t[1].forEach(function(e){var t=vh(e.data),e=r[Rh(t[2][0].data)][0],t=bh(e.meta[1][0].data);if(6002!=t)throw new Error("6001 unexpected reference to ".concat(t));e=Ih(0,e);e.data.forEach(function(e,r){e.forEach(function(e,t){t=Kr({r:i+r,c:t}),e=Ch(e,n,s);e&&(a[t]=e)})}),i+=e.nrows}),null!=(t=e[13])&&t[0]){t=r[Rh(e[13][0].data)][0],e=bh(t.meta[1][0].data);if(6144!=e)throw new Error("Expected merge type 6144, found ".concat(e));a["!merges"]=null==(t=vh(t.data))?void 0:t[1].map(function(e){var t=vh(e.data),e=fh(vh(t[1][0].data)[1][0].data),t=fh(vh(t[2][0].data)[1][0].data);return{s:{r:e.getUint16(0,!0),c:e.getUint16(2,!0)},e:{r:e.getUint16(0,!0)+t.getUint16(0,!0)-1,c:e.getUint16(2,!0)+t.getUint16(2,!0)-1}}})}}(e,a[0],r),r}function Fh(s,e){var i=du(),t=vh(e.data);if(null!=(e=t[2])&&e[0])throw new Error("Keynote presentations are not supported");if(Th(t[1],Rh).forEach(function(e){s[e].forEach(function(e){var r,t,a,n;2==bh(e.meta[1][0].data)&&(t=s,e=vh((a=e).data),n={name:null!=(a=e[1])&&a[0]?hh(e[1][0].data):"",sheets:[]},Th(e[2],Rh).forEach(function(e){t[e].forEach(function(e){6e3==bh(e.meta[1][0].data)&&n.sheets.push(Nh(t,e))})}),(r=n).sheets.forEach(function(e,t){pu(i,e,0==t?r.name:r.name+"_"+t,!0)}))})}),0==i.SheetNames.length)throw new Error("Empty NUMBERS file");return i}function Dh(e){var a={},n=[];if(e.FullPaths.forEach(function(e){if(e.match(/\.iwpv2/))throw new Error("Unsupported password protection")}),e.FileIndex.forEach(function(t){if(t.name.match(/\.iwa$/)){var e,r;try{e=yh(t.content)}catch(e){return console.log("?? "+t.content.length+" "+(e.message||e))}try{r=Eh(e)}catch(e){return console.log("## "+(e.message||e))}r.forEach(function(e){a[e.id]=e.messages,n.push(e.id)})}}),!n.length)throw new Error("File has no messages");if(null!=(e=null==(e=null==(e=null==(e=null==a?void 0:a[1])?void 0:e[0])?void 0:e.meta)?void 0:e[1])&&e[0].data&&1e4==bh(a[1][0].meta[1][0].data))throw new Error("Pages documents are not supported");var t=(null==(e=null==(e=null==(e=null==(e=null==a?void 0:a[1])?void 0:e[0])?void 0:e.meta)?void 0:e[1])?void 0:e[0].data)&&1==bh(a[1][0].meta[1][0].data)&&a[1][0];if(t||n.forEach(function(e){a[e].forEach(function(e){if(1==bh(e.meta[1][0].data)>>>0){if(t)throw new Error("Document has multiple roots");t=e}})}),!t)throw new Error("Cannot find Document root");return Fh(a,t)}function Ph(e,t){if(!t||!t.numbers)throw new Error("Must pass a `numbers` option -- check the README");var r=e.Sheets[e.SheetNames[0]];1]*r:id="([^"]*)"/)||["",""])[1],p["!id"][m].Target):"??"),c),c=Xa(m),g=Wl(tt(l,m,!0),0,0,Ya(tt(l,c,!0),m),0,g);break;case"macro":v=f,u[h],v.slice(-4),g={"!type":"macro"};break;case"dialog":v=f,u[h],v.slice(-4),g={"!type":"dialog"};break;default:throw new Error("Unrecognized sheet type "+a)}r[h]=g;var b=[];u&&u[h]&&Re(u[h]).forEach(function(e){var a,n,s,i,o,c,t="";if(u[h][e].Type==$a.CMNT){t=it(u[h][e].Target,f);var r=lf(et(l,t,!0),t,d);if(!r||!r.length)return;ec(g,r,!1)}u[h][e].Type==$a.TCMNT&&(t=it(u[h][e].Target,f),b=b.concat((a=et(l,t,!0),n=d,i=!(s=[]),o={},c=0,a.replace(ft,function(e,t){var r=dt(e);switch(pt(r[0])){case"":break;case"":null!=o.t&&s.push(o);break;case"":case"":o.t=a.slice(c,t).replace(/\r\n/g,"\n").replace(/\r/g,"\n");break;case"":i=!0;break;case"":i=!1;break;case"":case"
":case"":break;case"":i=!1;break;default:if(!i&&n.WTF)throw new Error("unrecognized "+r[0]+" in threaded comments")}return e}),s)))}),b&&b.length&&ec(g,b,!0,d.people||[])}catch(e){if(d.WTF)throw e}var v,m}function Hh(e){return"/"==e.charAt(0)?e.slice(1):e}function zh(r,t){if(Ee(),Mh(t=t||{}),Ze(r,"META-INF/manifest.xml"))return sh(r,t);if(Ze(r,"objectdata.xml"))return sh(r,t);if(Ze(r,"Index/Document.iwa")){if("undefined"==typeof Uint8Array)throw new Error("NUMBERS file parsing requires Uint8Array support");if(0,r.FileIndex)return Dh(r);var a=xe.utils.cfb_new();return rt(r).forEach(function(e){at(a,e,function e(t,r,a){if(!a)return qe(Qe(t,r));if(!r)return null;try{return e(t,r)}catch(e){return null}}(r,e))}),Dh(a)}if(!Ze(r,"[Content_Types].xml")){if(Ze(r,"index.xml.gz"))throw new Error("Unsupported NUMBERS 08 file");if(Ze(r,"index.xml"))throw new Error("Unsupported NUMBERS 09 file");throw new Error("Unsupported ZIP file")}var e,n,s=rt(r),i=function(e){var r=Ga();if(!e||!e.match)return r;var a={};if((e.match(ft)||[]).forEach(function(e){var t=dt(e);switch(t[0].replace(ht,"<")){case"]*>([\\s\\S]*?)"));r&&0":a=null;break;default:if(0===i.indexOf(""),l=c[0].slice(4),f=c[1];switch(l){case"lpstr":case"bstr":case"lpwstr":r[a]=wt(f);break;case"bool":r[a]=Rt(f);break;case"i1":case"i2":case"i4":case"i8":case"int":case"uint":r[a]=parseInt(f,10);break;case"r4":case"r8":case"decimal":r[a]=parseFloat(f);break;case"filetime":case"date":r[a]=He(f);break;case"cy":case"error":r[a]=wt(f);break;default:if("/"==l.slice(-1))break;t.WTF&&"undefined"!=typeof console&&console.warn("Unexpected",i,l,c)}}else if("":break;case"":break;case"":case"":case"":break;case"":C=!1;break;default:if(!C&&x.WTF)throw new Error("unrecognized "+t[0]+" in threaded comments")}return e}),A)),R=R&&Bh(R,d.Sheets);var O=et(r,"xl/worksheets/sheet.xml",!0)?1:0;e:for(T=0;T!=p.Worksheets;++T){var I="sheet";if(R&&R[T]?(v="xl/"+R[T][1].replace(/[\/]?xl\//,""),Ze(r,v)||(v=R[T][1]),Ze(r,v)||(v=_.replace(/_rels\/.*$/,"")+R[T][1]),I=R[T][2]):v=(v="xl/worksheets/sheet"+(T+1-O)+"."+S).replace(/sheet0\./,"sheet."),w=v.replace(/^(.*)(\/)([^\/]*)$/,"$1/_rels/$3.rels"),t&&null!=t.sheets)switch(typeof t.sheets){case"number":if(T!=t.sheets)continue e;break;case"string":if(p.SheetNames[T].toLowerCase()!=t.sheets.toLowerCase())continue e;break;default:if(Array.isArray&&Array.isArray(t.sheets)){for(var N=!1,F=0;F!=t.sheets.length;++F)"number"==typeof t.sheets[F]&&t.sheets[F]==T&&(N=1),"string"==typeof t.sheets[F]&&t.sheets[F].toLowerCase()==p.SheetNames[T].toLowerCase()&&(N=1);if(!N)continue e}}Wh(r,v,w,p.SheetNames[T],T,E,e,I,t,d,c,l)}return b={Directory:i,Workbook:d,Props:p,Custprops:g,Deps:m,Sheets:e,SheetNames:p.SheetNames,Strings:Yc,Styles:l,Themes:c,SSF:Ve(me)},t&&t.bookFiles&&(r.files?(b.keys=s,b.files=r.files):(b.keys=[],b.files={},r.FullPaths.forEach(function(e,t){e=e.replace(/^Root Entry[\/]/,""),b.keys.push(e),b.files[e]=r.FileIndex[t]}))),t&&t.bookVBA&&(0/,">")];return e.forEach(function(a){var n="";(a[1]||[]).forEach(function(e,t){var r;e.T?(e.a&&-1==s.indexOf(e.a)&&s.push(e.a),r={ref:a[0],id:"{54EE7951-7262-4200-6969-"+("000000000000"+i.tcid++).slice(-12)+"}"},0==t?n=r.id:r.parentId=n,e.ID=r.id,e.a&&(r.personId="{54EE7950-7262-4200-6969-"+("000000000000"+s.indexOf(e.a)).slice(-12)+"}"),o.push(Yt("threadedComment",$t("text",e.t||""),r))):delete e.ID})}),o.push(""),o.join("")}(u,h,t)),n.threadedcomments.push(p),Ja(g,-1,"../threadedComments/threadedComment"+o+"."+r,$a.TCMNT)),at(s,p="xl/comments"+o+"."+r,tc(u)),n.comments.push(p),Ja(g,-1,"../comments"+o+"."+r,$a.CMNT),d=!0),b["!legacy"]&&d&&at(s,"xl/drawings/vmlDrawing"+o+".vml",Qo(o,b["!comments"])),delete b["!comments"],delete b["!legacy"]),g["!id"].rId1&&at(s,Xa(i),Ka(g))}return null!=t.Strings&&0/,">")],a.forEach(function(e,t){f.push(Yt("person",null,{displayName:e,id:"{54EE7950-7262-4200-6969-"+("000000000000"+t).slice(-12)+"}",userId:e,providerId:"None"}))}),f.push(""),f.join(""))),n.people.push(i),Ja(t.wbrels,-1,"persons/person.xml",$a.PEOPLE)),at(s,"[Content_Types].xml",ja(n,t)),at(s,"_rels/.rels",Ka(t.rels)),at(s,"xl/_rels/workbook.xml.rels",Ka(t.wbrels)),delete t.revssf,delete t.ssf,s}function $h(e,t){var r="";switch((t||{}).type||"base64"){case"buffer":return[e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7]];case"base64":r=te(e.slice(0,12));break;case"binary":r=e;break;case"array":return[e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7]];default:throw new Error("Unrecognized type "+(t&&t.type||"undefined"))}return[r.charCodeAt(0),r.charCodeAt(1),r.charCodeAt(2),r.charCodeAt(3),r.charCodeAt(4),r.charCodeAt(5),r.charCodeAt(6),r.charCodeAt(7)]}function Xh(e,t){var r=0;e:for(;rt)return t;throw new Error("Cannot find sheet # "+t)}if("string"!=typeof t)throw new Error("Cannot find sheet |"+t+"|");if(-1<(e=e.SheetNames.indexOf(t)))return e;throw new Error("Cannot find sheet name |"+t+"|")}(e,t),e.Workbook.Sheets[t]||(e.Workbook.Sheets[t]={}),r){case 0:case 1:case 2:break;default:throw new Error("Bad sheet visibility setting "+r)}e.Workbook.Sheets[t].Hidden=r},cell_set_number_format:function(e,t){return e.z=t,e},cell_set_hyperlink:mu,cell_set_internal_link:function(e,t,r){return mu(e,"#"+t,r)},cell_add_comment:function(e,t,r){e.c||(e.c=[]),e.c.push({t:t,a:r||"SheetJS"})},sheet_set_array_formula:function(e,t,r,a){for(var n="string"!=typeof t?t:Zr(t),s="string"==typeof t?t:qr(t),i=n.s.r;i<=n.e.r;++i)for(var o=n.s.c;o<=n.e.c;++o){var c=uu(e,i,o);c.t="n",c.F=s,delete c.v,i==n.s.r&&o==n.s.c&&(c.f=r,a&&(c.D=!0))}return e},consts:{SHEET_VISIBLE:0,SHEET_HIDDEN:1,SHEET_VERY_HIDDEN:2}};function bu(e){gu=e}var is={to_json:function(t,e){var r=gu({objectMode:!0});if(null==t||null==t["!ref"])return r.push(null),r;var a,n={t:"n",v:0},s=0,i=1,o=[],c="",l={s:{r:0,c:0},e:{r:0,c:0}},f=e||{},h=null!=f.range?f.range:t["!ref"];switch(1===f.header?s=1:"A"===f.header?s=2:Array.isArray(f.header)&&(s=3),typeof h){case"string":l=Zr(h);break;case"number":(l=Zr(t["!ref"])).s.r=h;break;default:l=h}0s.e.r)return o||(o=!0,r.push(""+n)),r.push(null);for(;i<=s.e.r;){r.push(Kf(e,s,i,a)),++i;break}},r},to_csv:function(e,t){var r=gu(),a=null==t?{}:t;if(null==e||null==e["!ref"])return r.push(null),r;var n=Zr(e["!ref"]),s=void 0!==a.FS?a.FS:",",i=s.charCodeAt(0),o=void 0!==a.RS?a.RS:"\n",c=o.charCodeAt(0),l=new RegExp(("|"==s?"\\|":s)+"+$"),f="",h=[];a.dense=Array.isArray(e);for(var u=a.skipHidden&&e["!cols"]||[],d=a.skipHidden&&e["!rows"]||[],p=n.s.c;p<=n.e.c;++p)(u[p]||{}).hidden||(h[p]=Xr(p));var m=n.s.r,g=!1,b=0;return r._read=function(){if(!g)return g=!0,r.push("\ufeff");for(;m<=n.e.r;)if(++m,!(d[m-1]||{}).hidden&&(f=cu(e,n,m-1,h,i,c,s,a),null!=f&&((f=a.strip?f.replace(l,""):f)||!1!==a.blankrows)))return r.push((b++?o:"")+f);return r.push(null)},r},set_readable:bu},vu=function(){function a(e,t,r){return this instanceof a?(this.tagName=e,this._attributes=t||{},this._children=r||[],this._prefix="",this):new a(e,t,r)}a.prototype.createElement=function(){return new a(arguments)},a.prototype.children=function(){return this._children},a.prototype.append=function(e){return this._children.push(e),this},a.prototype.prefix=function(e){return 0==arguments.length?this._prefix:(this._prefix=e,this)},a.prototype.attr=function(e,t){if(null==t)return delete this._attributes[e],this;if(0==arguments.length)return this._attributes;if("string"==typeof e&&1==arguments.length)return this._attributes.attr[e];if("object"==typeof e&&1==arguments.length)for(var r in e)this._attributes[r]=e[r];else 2==arguments.length&&"string"==typeof e&&(this._attributes[e]=t);return this};return a.prototype.escapeAttributeValue=function(e){return'"'+e.replace(/\"/g,""")+'"'},a.prototype.toXml=function(e){var t=(e=e||this)._prefix;if(t+="<"+e.tagName,e._attributes)for(var r in e._attributes)t+=" "+r+"="+this.escapeAttributeValue(""+e._attributes[r]);if(e._children&&0";for(var a=0;a"}else t+="/>";return t},a}(),wu=function(e){var t,r=164,a={0:"General",1:"0",2:"0.00",3:"#,##0",4:"#,##0.00",9:"0%",10:"0.00%",11:"0.00E+00",12:"# ?/?",13:"# ??/??",14:"m/d/yy",15:"d-mmm-yy",16:"d-mmm",17:"mmm-yy",18:"h:mm AM/PM",19:"h:mm:ss AM/PM",20:"h:mm",21:"h:mm:ss",22:"m/d/yy h:mm",37:"#,##0 ;(#,##0)",38:"#,##0 ;[Red](#,##0)",39:"#,##0.00;(#,##0.00)",40:"#,##0.00;[Red](#,##0.00)",45:"mm:ss",46:"[h]:mm:ss",47:"mmss.0",48:"##0.0E+0",49:"@",56:'"上午/下午 "hh"時"mm"分"ss"秒 "'},n={};for(t in a)n[a[t]]=t;var s={};return{initialize:function(e){this.$fonts=vu("fonts").attr("count",0).attr("x14ac:knownFonts","1"),this.$fills=vu("fills").attr("count",0),this.$borders=vu("borders").attr("count",0),this.$numFmts=vu("numFmts").attr("count",0),this.$cellStyleXfs=vu("cellStyleXfs"),this.$xf=vu("xf").attr("numFmtId",0).attr("fontId",0).attr("fillId",0).attr("borderId",0),this.$cellXfs=vu("cellXfs").attr("count",0),this.$cellStyles=vu("cellStyles").append(vu("cellStyle").attr("name","Normal").attr("xfId",0).attr("builtinId",0)),this.$dxfs=vu("dxfs").attr("count","0"),this.$tableStyles=vu("tableStyles").attr("count","0").attr("defaultTableStyle","TableStyleMedium9").attr("defaultPivotStyle","PivotStyleMedium4"),this.$styles=vu("styleSheet").attr("xmlns:mc","http://schemas.openxmlformats.org/markup-compatibility/2006").attr("xmlns:x14ac","http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac").attr("xmlns","http://schemas.openxmlformats.org/spreadsheetml/2006/main").attr("mc:Ignorable","x14ac").prefix('').append(this.$numFmts).append(this.$fonts).append(this.$fills).append(this.$borders).append(this.$cellStyleXfs.append(this.$xf)).append(this.$cellXfs).append(this.$cellStyles).append(this.$dxfs).append(this.$tableStyles);var t=e.defaultCellStyle||{};t.font||(t.font={name:"Calibri",sz:"11"}),t.font.name||(t.font.name="Calibri"),t.font.sz||(t.font.sz=11),t.fill||(t.fill={patternType:"none",fgColor:{}}),t.border||(t.border={}),t.numFmt||(t.numFmt=0),this.defaultStyle=t;e=JSON.parse(JSON.stringify(t));return e.fill={patternType:"gray125",fgColor:{}},this.addStyles([t,e]),this},addStyle:function(e){var t=JSON.stringify(e),r=s[t];return null==r?(r=this._addXf(e),s[t]=r):r=s[t],r},addStyles:function(e){var t=this;return e.map(function(e){return t.addStyle(e)})},_duckTypeStyle:function(e){return"object"==typeof e&&(e.patternFill||e.fgColor)?{fill:e}:e.font||e.numFmt||e.border||e.fill?e:this._getStyleCSS(e)},_getStyleCSS:function(e){return e},_addXf:function(e){var t=this._addFont(e.font),r=this._addFill(e.fill),a=this._addBorder(e.border),n=this._addNumFmt(e.numFmt),s=vu("xf").attr("numFmtId",n).attr("fontId",t).attr("fillId",r).attr("borderId",a).attr("xfId","0");0/g,">").replace(/"/g,""").replace(/'/g,"'");e=vu("numFmt").attr("numFmtId",++r).attr("formatCode",e);this.$numFmts.append(e);e=this.$numFmts.children().length;return this.$numFmts.attr("count",e),r},_addFill:function(e){if(!e)return 0;var t,r=vu("patternFill").attr("patternType",e.patternType||"solid");e.fgColor&&(t=vu("fgColor"),e.fgColor.rgb?(6==e.fgColor.rgb.length&&(e.fgColor.rgb="FF"+e.fgColor.rgb),t.attr("rgb",e.fgColor.rgb),r.append(t)):e.fgColor.theme&&(t.attr("theme",e.fgColor.theme),e.fgColor.tint&&t.attr("tint",e.fgColor.tint),r.append(t)),e.bgColor||(e.bgColor={indexed:"64"})),e.bgColor&&(e=vu("bgColor").attr(e.bgColor),r.append(e));r=vu("fill").append(r);this.$fills.append(r);r=this.$fills.children().length;return this.$fills.attr("count",r),r-1},_getSubBorder:function(e,t){var r=vu(e);return t&&(r.attr("style",t.style||"medium"),t.color&&(e=vu("color"),t.color.auto?e.attr("auto",t.color.auto):t.color.rgb?e.attr("rgb",t.color.rgb):(t.color.theme||t.color.tint)&&(e.attr("theme",t.color.theme||"1"),e.attr("tint",t.color.tint||"0")),r.append(e))),r},_addBorder:function(t){if(!t)return 0;var r=this,a=vu("border").attr("diagonalUp",t.diagonalUp).attr("diagonalDown",t.diagonalDown);["left","right","top","bottom","diagonal"].forEach(function(e){a.append(r._getSubBorder(e,t[e]))}),this.$borders.append(a);var e=this.$borders.children().length;return this.$borders.attr("count",e),e-1},toXml:function(){return this.$styles.toXml()}}.initialize(e||{})};void 0!==Nf&&(a.parse_xlscfb=Nf),a.parse_zip=zh,a.read=Kh,a.readFile=Jh,a.readFileSync=Jh,a.write=ru,a.writeFile=nu,a.writeFileSync=nu,a.writeFileAsync=function(e,t,r,a){var n=r||{};return n.type="file",n.file=e,au(n),n.type="buffer",a instanceof Function||(a=r),Se.writeFile(e,ru(t,n),a)},a.utils=Es,a.writeXLSX=tu,a.writeFileXLSX=function(e,t,r){return(r=r||{}).type="file",r.file=t,au(r),tu(e,r)},a.SSF=e,void 0!==is&&(a.stream=is),void 0!==xe&&(a.CFB=xe),"undefined"==typeof require||((is=require("stream"))||{}).Readable&&bu(is.Readable)}if("undefined"!=typeof exports?make_xlsx_lib(exports):"undefined"!=typeof module&&module.exports?make_xlsx_lib(module.exports):"function"==typeof define&&define.amd?define("xlsx",function(){return XLSX.version||make_xlsx_lib(XLSX),XLSX}):make_xlsx_lib(XLSX),"undefined"!=typeof window&&!window.XLSX)try{window.XLSX=XLSX}catch(e){} +//# sourceMappingURL=xlsx.bundle.js.map \ No newline at end of file diff --git a/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/package.json b/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/package.json new file mode 100644 index 0000000..177f297 --- /dev/null +++ b/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/package.json @@ -0,0 +1,12 @@ +{ + "name": "sv-excel-json-handler", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} \ No newline at end of file diff --git a/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/util/index.js b/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/util/index.js new file mode 100644 index 0000000..1faf854 --- /dev/null +++ b/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/common/sv-excel-json-handler/util/index.js @@ -0,0 +1,147 @@ +const xlsx = require('../lib/xlsx.style.js'); +//excel列转换 +const convertDSTo26BS = function(num) { + var code = ''; + var reg = /^\d+$/g; + if (!reg.test(num)) { + return code; + } + while (num > 0) { + m = num % 26 + if (m == 0) { + m = 26; + } + code = String.fromCharCode(64 + parseInt(m)) + code; + num = (num - m) / 26; + } + return code; +} +const convert26BSToDS = function(code) { + var num = -1; + var reg = /^[A-Z]+$/g; + if (!reg.test(code)) { + return num; + } + num = 0; + for (var i = code.length - 1, j = 1; i >= 0; i--, j *= 26) { + num += (code[i].charCodeAt() - 64) * j; + } + return num; +} +//读取base64xlsx数据 +const readXlsx = function(base64, options = []) { + let result = {}; + let xlsxInfo = xlsx.read(base64); + const readSheetsIndex = []; + options.forEach(item => { + if (item.index === -1) { + item.index = xlsxInfo.Workbook.WBView[0].activeTab + } + readSheetsIndex.push(item.index) + }) + let sheets = xlsxInfo.Sheets; + let list = []; + if (xlsxInfo.Workbook.Sheets.length > 0) { + for (var i = 0; i < xlsxInfo.Workbook.Sheets.length; i++) { + const key = xlsxInfo.Workbook.Sheets[i].name + const currentOption = options.find(item =>{ + return item.autoKey && item.index === i + }) + let autoKey; + if(currentOption){ + autoKey = currentOption.autoKey + } + if (readSheetsIndex.indexOf(i) === -1) { + list.push({ + name: key, + data: [] + }) + continue; + } + let sheet = []; + let item = sheets[key]; + for (let k in item) { + let ritem = item[k]; + let btn = true + if (k === '!ref') { + let strArr = ritem.split(':'); + let startRowIndex = Number(strArr[0].replace(/[^\d]/g, '')) - 1; + let endRowIndex = Number(strArr[1].replace(/[^\d]/g, '')) - 1; + let rowsCount = endRowIndex - startRowIndex + 1; + let startColIndex = 1; + let endColIndex = 1; + startColIndex = convert26BSToDS(strArr[0].replace(/[0-9]+/g, '')); + endColIndex = convert26BSToDS(strArr[1].replace(/[0-9]+/g, '')); + endColIndex -= 1; + startColIndex -= 1; + let colsCount = endColIndex - startColIndex + 1; + //let sheetArr = []; + for (var ri = startRowIndex; ri <= endRowIndex; ri++) { + let row = ri + 1; + let rowArr = []; + for (var ci = startColIndex; ci <= endColIndex; ci++) { + let col = convertDSTo26BS(ci + 1); + if (item[col + row]) { + if (item[col + row].t === 's') { + rowArr.push(item[col + row].v); + } else if (item[col + row].t === 'n') { + var reg = /^[0-9,/:-\s]+$/; + if (!isNaN(Date.parse(new Date(item[col + row].w.replace(/-/g, + '/')))) && isNaN( + item[col + row].w) && reg.test(item[col + row].w)) { + rowArr.push(item[col + row].w); + } else { + rowArr.push(item[col + row].v); + } + } + } else { + if(autoKey && item[col+ Number(currentOption.keysIndex+1)].v === autoKey){ + btn = false + break; + } + rowArr.push(''); + } + } + if(btn){ + sheet.push(rowArr); + }else{ + break; + } + } + } + } + list.push({ + name: key, + data: sheet + }) + } + return list + } + return [] +} + + +const formatExcelToJsonOptions = function(configArr = []) { + let defaultConfig = { + "index": 0, + "keysIndex": 0, + "startIndex": 1, + "endIndex": -1 + } + if (configArr && configArr.length > 0) { + return configArr.map(item => { + return { + ...defaultConfig, + ...item + } + }) + } else { + return [defaultConfig] + } +} + + +exports.convertDSTo26BS = convertDSTo26BS +exports.convert26BSToDS = convert26BSToDS +exports.readXlsx = readXlsx +exports.formatExcelToJsonOptions = formatExcelToJsonOptions \ No newline at end of file diff --git a/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/sv-excel-json-each/index.obj.js b/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/sv-excel-json-each/index.obj.js new file mode 100644 index 0000000..d33606b --- /dev/null +++ b/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/sv-excel-json-each/index.obj.js @@ -0,0 +1,21 @@ +const { excelTojson, jsonToexcel } = require('sv-excel-json-handler'); + +module.exports = { + _before: function() { // 通用预处理器 + + }, + async getExcelToJson(param) { + let data = await excelTojson(param.data, param.sheetList); + return { + code: 0, + data + } + }, + async getJsonToExcel(param) { + let data = await jsonToexcel(param); + return { + code: 0, + data + } + } +} \ No newline at end of file diff --git a/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/sv-excel-json-each/package-lock.json b/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/sv-excel-json-each/package-lock.json new file mode 100644 index 0000000..cdbd4f5 --- /dev/null +++ b/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/sv-excel-json-each/package-lock.json @@ -0,0 +1,21 @@ +{ + "name": "sv-excel-json-each", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sv-excel-json-each", + "dependencies": { + "sv-excel-json-handler": "file:../common/sv-excel-json-handler" + } + }, + "../common/sv-excel-json-handler": { + "version": "1.0.0", + "license": "ISC" + }, + "node_modules/sv-excel-json-handler": { + "resolved": "../common/sv-excel-json-handler", + "link": true + } + } +} diff --git a/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/sv-excel-json-each/package.json b/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/sv-excel-json-each/package.json new file mode 100644 index 0000000..900ce6d --- /dev/null +++ b/uni_modules/sv-excel-json-each/uniCloud/cloudfunctions/sv-excel-json-each/package.json @@ -0,0 +1,7 @@ +{ + "name": "sv-excel-json-each", + "dependencies": { + "sv-excel-json-handler": "file:../common/sv-excel-json-handler" + }, + "extensions": {} +} \ No newline at end of file diff --git a/uni_modules/uni-badge/changelog.md b/uni_modules/uni-badge/changelog.md new file mode 100644 index 0000000..e352c60 --- /dev/null +++ b/uni_modules/uni-badge/changelog.md @@ -0,0 +1,33 @@ +## 1.2.2(2023-01-28) +- 修复 运行/打包 控制台警告问题 +## 1.2.1(2022-09-05) +- 修复 当 text 超过 max-num 时,badge 的宽度计算是根据 text 的长度计算,更改为 css 计算实际展示宽度,详见:[https://ask.dcloud.net.cn/question/150473](https://ask.dcloud.net.cn/question/150473) +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-badge](https://uniapp.dcloud.io/component/uniui/uni-badge) +## 1.1.7(2021-11-08) +- 优化 升级ui +- 修改 size 属性默认值调整为 small +- 修改 type 属性,默认值调整为 error,info 替换 default +## 1.1.6(2021-09-22) +- 修复 在字节小程序上样式不生效的 bug +## 1.1.5(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.4(2021-07-29) +- 修复 去掉 nvue 不支持css 的 align-self 属性,nvue 下不暂支持 absolute 属性 +## 1.1.3(2021-06-24) +- 优化 示例项目 +## 1.1.1(2021-05-12) +- 新增 组件示例地址 +## 1.1.0(2021-05-12) +- 新增 uni-badge 的 absolute 属性,支持定位 +- 新增 uni-badge 的 offset 属性,支持定位偏移 +- 新增 uni-badge 的 is-dot 属性,支持仅显示有一个小点 +- 新增 uni-badge 的 max-num 属性,支持自定义封顶的数字值,超过 99 显示99+ +- 优化 uni-badge 属性 custom-style, 支持以对象形式自定义样式 +## 1.0.7(2021-05-07) +- 修复 uni-badge 在 App 端,数字小于10时不是圆形的bug +- 修复 uni-badge 在父元素不是 flex 布局时,宽度缩小的bug +- 新增 uni-badge 属性 custom-style, 支持自定义样式 +## 1.0.6(2021-02-04) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-badge/components/uni-badge/uni-badge.vue b/uni_modules/uni-badge/components/uni-badge/uni-badge.vue new file mode 100644 index 0000000..956354b --- /dev/null +++ b/uni_modules/uni-badge/components/uni-badge/uni-badge.vue @@ -0,0 +1,268 @@ + + + + + diff --git a/uni_modules/uni-badge/package.json b/uni_modules/uni-badge/package.json new file mode 100644 index 0000000..b0bac93 --- /dev/null +++ b/uni_modules/uni-badge/package.json @@ -0,0 +1,85 @@ +{ + "id": "uni-badge", + "displayName": "uni-badge 数字角标", + "version": "1.2.2", + "description": "数字角标(徽章)组件,在元素周围展示消息提醒,一般用于列表、九宫格、按钮等地方。", + "keywords": [ + "", + "badge", + "uni-ui", + "uniui", + "数字角标", + "徽章" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "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" + }, + "快应用": { + "华为": "y", + "联盟": "y" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-badge/readme.md b/uni_modules/uni-badge/readme.md new file mode 100644 index 0000000..bdf175d --- /dev/null +++ b/uni_modules/uni-badge/readme.md @@ -0,0 +1,10 @@ +## Badge 数字角标 +> **组件名:uni-badge** +> 代码块: `uBadge` + +数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景, + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-badge) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-calendar/changelog.md b/uni_modules/uni-calendar/changelog.md new file mode 100644 index 0000000..f291eec --- /dev/null +++ b/uni_modules/uni-calendar/changelog.md @@ -0,0 +1,26 @@ +## 1.4.10(2023-04-10) +- 修复 某些情况 monthSwitch 未触发的Bug +## 1.4.9(2023-02-02) +- 修复 某些情况切换月份错误的Bug +## 1.4.8(2023-01-30) +- 修复 某些情况切换月份错误的Bug [详情](https://ask.dcloud.net.cn/question/161964) +## 1.4.7(2022-09-16) +- 优化 支持使用 uni-scss 控制主题色 +## 1.4.6(2022-09-08) +- 修复 表头年月切换,导致改变当前日期为选择月1号,且未触发change事件的Bug +## 1.4.5(2022-02-25) +- 修复 条件编译 nvue 不支持的 css 样式的Bug +## 1.4.4(2022-02-25) +- 修复 条件编译 nvue 不支持的 css 样式的Bug +## 1.4.3(2021-09-22) +- 修复 startDate、 endDate 属性失效的Bug +## 1.4.2(2021-08-24) +- 新增 支持国际化 +## 1.4.1(2021-08-05) +- 修复 弹出层被 tabbar 遮盖的Bug +## 1.4.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.3.16(2021-05-12) +- 新增 组件示例地址 +## 1.3.15(2021-02-04) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-calendar/components/uni-calendar/calendar.js b/uni_modules/uni-calendar/components/uni-calendar/calendar.js new file mode 100644 index 0000000..b8d7d6f --- /dev/null +++ b/uni_modules/uni-calendar/components/uni-calendar/calendar.js @@ -0,0 +1,546 @@ +/** +* @1900-2100区间内的公历、农历互转 +* @charset UTF-8 +* @github https://github.com/jjonline/calendar.js +* @Author Jea杨(JJonline@JJonline.Cn) +* @Time 2014-7-21 +* @Time 2016-8-13 Fixed 2033hex、Attribution Annals +* @Time 2016-9-25 Fixed lunar LeapMonth Param Bug +* @Time 2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year +* @Version 1.0.3 +* @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0] +* @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0] +*/ +/* eslint-disable */ +var calendar = { + + /** + * 农历1900-2100的润大小信息表 + * @Array Of Property + * @return Hex + */ + lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909 + 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919 + 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929 + 0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939 + 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949 + 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959 + 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969 + 0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979 + 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989 + 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999 + 0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009 + 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019 + 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029 + 0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039 + 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049 + /** Add By JJonline@JJonline.Cn**/ + 0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059 + 0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069 + 0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079 + 0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089 + 0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099 + 0x0d520], // 2100 + + /** + * 公历每个月份的天数普通表 + * @Array Of Property + * @return Number + */ + solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], + + /** + * 天干地支之天干速查表 + * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"] + * @return Cn string + */ + Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'], + + /** + * 天干地支之地支速查表 + * @Array Of Property + * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"] + * @return Cn string + */ + Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5'], + + /** + * 天干地支之地支速查表<=>生肖 + * @Array Of Property + * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"] + * @return Cn string + */ + Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', '\u72d7', '\u732a'], + + /** + * 24节气速查表 + * @Array Of Property + * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"] + * @return Cn string + */ + solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3'], + + /** + * 1900-2100各年的24节气日期速查表 + * @Array Of Property + * @return 0x string For splice + */ + sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', + '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', + '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', + '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', + 'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f', + '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa', + '97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', + '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f', + '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', + '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', + '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', + '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', + '97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722', + '9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f', + '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e', + '97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', + '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722', + '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', + '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', + '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722', + '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', + '97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', + '9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', + '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e', + '97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', + '9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722', + '7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', + '7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', + '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', + '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', + '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', + '9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', + '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721', + '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2', + '977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722', + '7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', + '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd', + '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', + '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', + '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', + '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', + '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', + '977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', + '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721', + '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5', + '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722', + '7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', + '7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd', + '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', + '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', + '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721', + '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd', + '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35', + '7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', + '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721', + '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5', + '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35', + '665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', + '7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd', + '7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35', + '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'], + + /** + * 数字转中文速查表 + * @Array Of Property + * @trans ['日','一','二','三','四','五','六','七','八','九','十'] + * @return Cn string + */ + nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341'], + + /** + * 日期转农历称呼速查表 + * @Array Of Property + * @trans ['初','十','廿','卅'] + * @return Cn string + */ + nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'], + + /** + * 月份转农历称呼速查表 + * @Array Of Property + * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊'] + * @return Cn string + */ + nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a'], + + /** + * 返回农历y年一整年的总天数 + * @param lunar Year + * @return Number + * @eg:var count = calendar.lYearDays(1987) ;//count=387 + */ + lYearDays: function (y) { + var i; var sum = 348 + for (i = 0x8000; i > 0x8; i >>= 1) { sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 } + return (sum + this.leapDays(y)) + }, + + /** + * 返回农历y年闰月是哪个月;若y年没有闰月 则返回0 + * @param lunar Year + * @return Number (0-12) + * @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6 + */ + leapMonth: function (y) { // 闰字编码 \u95f0 + return (this.lunarInfo[y - 1900] & 0xf) + }, + + /** + * 返回农历y年闰月的天数 若该年没有闰月则返回0 + * @param lunar Year + * @return Number (0、29、30) + * @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29 + */ + leapDays: function (y) { + if (this.leapMonth(y)) { + return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29) + } + return (0) + }, + + /** + * 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法 + * @param lunar Year + * @return Number (-1、29、30) + * @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29 + */ + monthDays: function (y, m) { + if (m > 12 || m < 1) { return -1 }// 月份参数从1至12,参数错误返回-1 + return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29) + }, + + /** + * 返回公历(!)y年m月的天数 + * @param solar Year + * @return Number (-1、28、29、30、31) + * @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30 + */ + solarDays: function (y, m) { + if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1 + var ms = m - 1 + if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29 + return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28) + } else { + return (this.solarMonth[ms]) + } + }, + + /** + * 农历年份转换为干支纪年 + * @param lYear 农历年的年份数 + * @return Cn string + */ + toGanZhiYear: function (lYear) { + var ganKey = (lYear - 3) % 10 + var zhiKey = (lYear - 3) % 12 + if (ganKey == 0) ganKey = 10// 如果余数为0则为最后一个天干 + if (zhiKey == 0) zhiKey = 12// 如果余数为0则为最后一个地支 + return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1] + }, + + /** + * 公历月、日判断所属星座 + * @param cMonth [description] + * @param cDay [description] + * @return Cn string + */ + toAstro: function (cMonth, cDay) { + var s = '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf' + var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22] + return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7'// 座 + }, + + /** + * 传入offset偏移量返回干支 + * @param offset 相对甲子的偏移量 + * @return Cn string + */ + toGanZhi: function (offset) { + return this.Gan[offset % 10] + this.Zhi[offset % 12] + }, + + /** + * 传入公历(!)y年获得该年第n个节气的公历日期 + * @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起 + * @return day Number + * @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春 + */ + getTerm: function (y, n) { + if (y < 1900 || y > 2100) { return -1 } + if (n < 1 || n > 24) { return -1 } + var _table = this.sTermInfo[y - 1900] + var _info = [ + parseInt('0x' + _table.substr(0, 5)).toString(), + parseInt('0x' + _table.substr(5, 5)).toString(), + parseInt('0x' + _table.substr(10, 5)).toString(), + parseInt('0x' + _table.substr(15, 5)).toString(), + parseInt('0x' + _table.substr(20, 5)).toString(), + parseInt('0x' + _table.substr(25, 5)).toString() + ] + var _calday = [ + _info[0].substr(0, 1), + _info[0].substr(1, 2), + _info[0].substr(3, 1), + _info[0].substr(4, 2), + + _info[1].substr(0, 1), + _info[1].substr(1, 2), + _info[1].substr(3, 1), + _info[1].substr(4, 2), + + _info[2].substr(0, 1), + _info[2].substr(1, 2), + _info[2].substr(3, 1), + _info[2].substr(4, 2), + + _info[3].substr(0, 1), + _info[3].substr(1, 2), + _info[3].substr(3, 1), + _info[3].substr(4, 2), + + _info[4].substr(0, 1), + _info[4].substr(1, 2), + _info[4].substr(3, 1), + _info[4].substr(4, 2), + + _info[5].substr(0, 1), + _info[5].substr(1, 2), + _info[5].substr(3, 1), + _info[5].substr(4, 2) + ] + return parseInt(_calday[n - 1]) + }, + + /** + * 传入农历数字月份返回汉语通俗表示法 + * @param lunar month + * @return Cn string + * @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月' + */ + toChinaMonth: function (m) { // 月 => \u6708 + if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1 + var s = this.nStr3[m - 1] + s += '\u6708'// 加上月字 + return s + }, + + /** + * 传入农历日期数字返回汉字表示法 + * @param lunar day + * @return Cn string + * @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一' + */ + toChinaDay: function (d) { // 日 => \u65e5 + var s + switch (d) { + case 10: + s = '\u521d\u5341'; break + case 20: + s = '\u4e8c\u5341'; break + break + case 30: + s = '\u4e09\u5341'; break + break + default : + s = this.nStr2[Math.floor(d / 10)] + s += this.nStr1[d % 10] + } + return (s) + }, + + /** + * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春” + * @param y year + * @return Cn string + * @eg:var animal = calendar.getAnimal(1987) ;//animal='兔' + */ + getAnimal: function (y) { + return this.Animals[(y - 4) % 12] + }, + + /** + * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON + * @param y solar year + * @param m solar month + * @param d solar day + * @return JSON object + * @eg:console.log(calendar.solar2lunar(1987,11,01)); + */ + solar2lunar: function (y, m, d) { // 参数区间1900.1.31~2100.12.31 + // 年份限定、上限 + if (y < 1900 || y > 2100) { + return -1// undefined转换为数字变为NaN + } + // 公历传参最下限 + if (y == 1900 && m == 1 && d < 31) { + return -1 + } + // 未传参 获得当天 + if (!y) { + var objDate = new Date() + } else { + var objDate = new Date(y, parseInt(m) - 1, d) + } + var i; var leap = 0; var temp = 0 + // 修正ymd参数 + var y = objDate.getFullYear() + var m = objDate.getMonth() + 1 + var d = objDate.getDate() + var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000 + for (i = 1900; i < 2101 && offset > 0; i++) { + temp = this.lYearDays(i) + offset -= temp + } + if (offset < 0) { + offset += temp; i-- + } + + // 是否今天 + var isTodayObj = new Date() + var isToday = false + if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) { + isToday = true + } + // 星期几 + var nWeek = objDate.getDay() + var cWeek = this.nStr1[nWeek] + // 数字表示周几顺应天朝周一开始的惯例 + if (nWeek == 0) { + nWeek = 7 + } + // 农历年 + var year = i + var leap = this.leapMonth(i) // 闰哪个月 + var isLeap = false + + // 效验闰月 + for (i = 1; i < 13 && offset > 0; i++) { + // 闰月 + if (leap > 0 && i == (leap + 1) && isLeap == false) { + --i + isLeap = true; temp = this.leapDays(year) // 计算农历闰月天数 + } else { + temp = this.monthDays(year, i)// 计算农历普通月天数 + } + // 解除闰月 + if (isLeap == true && i == (leap + 1)) { isLeap = false } + offset -= temp + } + // 闰月导致数组下标重叠取反 + if (offset == 0 && leap > 0 && i == leap + 1) { + if (isLeap) { + isLeap = false + } else { + isLeap = true; --i + } + } + if (offset < 0) { + offset += temp; --i + } + // 农历月 + var month = i + // 农历日 + var day = offset + 1 + // 天干地支处理 + var sm = m - 1 + var gzY = this.toGanZhiYear(year) + + // 当月的两个节气 + // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year` + var firstNode = this.getTerm(y, (m * 2 - 1))// 返回当月「节」为几日开始 + var secondNode = this.getTerm(y, (m * 2))// 返回当月「节」为几日开始 + + // 依据12节气修正干支月 + var gzM = this.toGanZhi((y - 1900) * 12 + m + 11) + if (d >= firstNode) { + gzM = this.toGanZhi((y - 1900) * 12 + m + 12) + } + + // 传入的日期的节气与否 + var isTerm = false + var Term = null + if (firstNode == d) { + isTerm = true + Term = this.solarTerm[m * 2 - 2] + } + if (secondNode == d) { + isTerm = true + Term = this.solarTerm[m * 2 - 1] + } + // 日柱 当月一日与 1900/1/1 相差天数 + var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10 + var gzD = this.toGanZhi(dayCyclical + d - 1) + // 该日期所属的星座 + var astro = this.toAstro(m, d) + + return { 'lYear': year, 'lMonth': month, 'lDay': day, 'Animal': this.getAnimal(year), 'IMonthCn': (isLeap ? '\u95f0' : '') + this.toChinaMonth(month), 'IDayCn': this.toChinaDay(day), 'cYear': y, 'cMonth': m, 'cDay': d, 'gzYear': gzY, 'gzMonth': gzM, 'gzDay': gzD, 'isToday': isToday, 'isLeap': isLeap, 'nWeek': nWeek, 'ncWeek': '\u661f\u671f' + cWeek, 'isTerm': isTerm, 'Term': Term, 'astro': astro } + }, + + /** + * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON + * @param y lunar year + * @param m lunar month + * @param d lunar day + * @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可] + * @return JSON object + * @eg:console.log(calendar.lunar2solar(1987,9,10)); + */ + lunar2solar: function (y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1 + var isLeapMonth = !!isLeapMonth + var leapOffset = 0 + var leapMonth = this.leapMonth(y) + var leapDay = this.leapDays(y) + if (isLeapMonth && (leapMonth != m)) { return -1 }// 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同 + if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { return -1 }// 超出了最大极限值 + var day = this.monthDays(y, m) + var _day = day + // bugFix 2016-9-25 + // if month is leap, _day use leapDays method + if (isLeapMonth) { + _day = this.leapDays(y, m) + } + if (y < 1900 || y > 2100 || d > _day) { return -1 }// 参数合法性效验 + + // 计算农历的时间差 + var offset = 0 + for (var i = 1900; i < y; i++) { + offset += this.lYearDays(i) + } + var leap = 0; var isAdd = false + for (var i = 1; i < m; i++) { + leap = this.leapMonth(y) + if (!isAdd) { // 处理闰月 + if (leap <= i && leap > 0) { + offset += this.leapDays(y); isAdd = true + } + } + offset += this.monthDays(y, i) + } + // 转换闰月农历 需补充该年闰月的前一个月的时差 + if (isLeapMonth) { offset += day } + // 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点) + var stmap = Date.UTC(1900, 1, 30, 0, 0, 0) + var calObj = new Date((offset + d - 31) * 86400000 + stmap) + var cY = calObj.getUTCFullYear() + var cM = calObj.getUTCMonth() + 1 + var cD = calObj.getUTCDate() + + return this.solar2lunar(cY, cM, cD) + } +} + +export default calendar diff --git a/uni_modules/uni-calendar/components/uni-calendar/i18n/en.json b/uni_modules/uni-calendar/components/uni-calendar/i18n/en.json new file mode 100644 index 0000000..fcbd13c --- /dev/null +++ b/uni_modules/uni-calendar/components/uni-calendar/i18n/en.json @@ -0,0 +1,12 @@ +{ + "uni-calender.ok": "ok", + "uni-calender.cancel": "cancel", + "uni-calender.today": "today", + "uni-calender.MON": "MON", + "uni-calender.TUE": "TUE", + "uni-calender.WED": "WED", + "uni-calender.THU": "THU", + "uni-calender.FRI": "FRI", + "uni-calender.SAT": "SAT", + "uni-calender.SUN": "SUN" +} diff --git a/uni_modules/uni-calendar/components/uni-calendar/i18n/index.js b/uni_modules/uni-calendar/components/uni-calendar/i18n/index.js new file mode 100644 index 0000000..de7509c --- /dev/null +++ b/uni_modules/uni-calendar/components/uni-calendar/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json b/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json new file mode 100644 index 0000000..1ca43de --- /dev/null +++ b/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json @@ -0,0 +1,12 @@ +{ + "uni-calender.ok": "确定", + "uni-calender.cancel": "取消", + "uni-calender.today": "今日", + "uni-calender.SUN": "日", + "uni-calender.MON": "一", + "uni-calender.TUE": "二", + "uni-calender.WED": "三", + "uni-calender.THU": "四", + "uni-calender.FRI": "五", + "uni-calender.SAT": "六" +} diff --git a/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json b/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json new file mode 100644 index 0000000..e0fe33b --- /dev/null +++ b/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json @@ -0,0 +1,12 @@ +{ + "uni-calender.ok": "確定", + "uni-calender.cancel": "取消", + "uni-calender.today": "今日", + "uni-calender.SUN": "日", + "uni-calender.MON": "一", + "uni-calender.TUE": "二", + "uni-calender.WED": "三", + "uni-calender.THU": "四", + "uni-calender.FRI": "五", + "uni-calender.SAT": "六" +} diff --git a/uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue b/uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue new file mode 100644 index 0000000..a54135e --- /dev/null +++ b/uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue @@ -0,0 +1,187 @@ + + + + + diff --git a/uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue b/uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue new file mode 100644 index 0000000..17c958d --- /dev/null +++ b/uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue @@ -0,0 +1,566 @@ + + + + + diff --git a/uni_modules/uni-calendar/components/uni-calendar/util.js b/uni_modules/uni-calendar/components/uni-calendar/util.js new file mode 100644 index 0000000..5ec8a92 --- /dev/null +++ b/uni_modules/uni-calendar/components/uni-calendar/util.js @@ -0,0 +1,360 @@ +import CALENDAR from './calendar.js' + +class Calendar { + constructor({ + date, + selected, + startDate, + endDate, + range + } = {}) { + // 当前日期 + this.date = this.getDate(new Date()) // 当前初入日期 + // 打点信息 + this.selected = selected || []; + // 范围开始 + this.startDate = startDate + // 范围结束 + this.endDate = endDate + this.range = range + // 多选状态 + this.cleanMultipleStatus() + // 每周日期 + this.weeks = {} + // this._getWeek(this.date.fullDate) + } + /** + * 设置日期 + * @param {Object} date + */ + setDate(date) { + this.selectDate = this.getDate(date) + this._getWeek(this.selectDate.fullDate) + } + + /** + * 清理多选状态 + */ + cleanMultipleStatus() { + this.multipleStatus = { + before: '', + after: '', + data: [] + } + } + + /** + * 重置开始日期 + */ + resetSatrtDate(startDate) { + // 范围开始 + this.startDate = startDate + + } + + /** + * 重置结束日期 + */ + resetEndDate(endDate) { + // 范围结束 + this.endDate = endDate + } + + /** + * 获取任意时间 + */ + getDate(date, AddDayCount = 0, str = 'day') { + if (!date) { + date = new Date() + } + if (typeof date !== 'object') { + date = date.replace(/-/g, '/') + } + const dd = new Date(date) + switch (str) { + case 'day': + dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期 + break + case 'month': + if (dd.getDate() === 31 && AddDayCount>0) { + dd.setDate(dd.getDate() + AddDayCount) + } else { + const preMonth = dd.getMonth() + dd.setMonth(preMonth + AddDayCount) // 获取AddDayCount天后的日期 + const nextMonth = dd.getMonth() + // 处理 pre 切换月份目标月份为2月没有当前日(30 31) 切换错误问题 + if(AddDayCount<0 && preMonth!==0 && nextMonth-preMonth>AddDayCount){ + dd.setMonth(nextMonth+(nextMonth-preMonth+AddDayCount)) + } + // 处理 next 切换月份目标月份为2月没有当前日(30 31) 切换错误问题 + if(AddDayCount>0 && nextMonth-preMonth>AddDayCount){ + dd.setMonth(nextMonth-(nextMonth-preMonth-AddDayCount)) + } + } + break + case 'year': + dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期 + break + } + const y = dd.getFullYear() + const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0 + const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0 + return { + fullDate: y + '-' + m + '-' + d, + year: y, + month: m, + date: d, + day: dd.getDay() + } + } + + + /** + * 获取上月剩余天数 + */ + _getLastMonthDays(firstDay, full) { + let dateArr = [] + for (let i = firstDay; i > 0; i--) { + const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate() + dateArr.push({ + date: beforeDate, + month: full.month - 1, + lunar: this.getlunar(full.year, full.month - 1, beforeDate), + disable: true + }) + } + return dateArr + } + /** + * 获取本月天数 + */ + _currentMonthDys(dateData, full) { + let dateArr = [] + let fullDate = this.date.fullDate + for (let i = 1; i <= dateData; i++) { + let nowDate = full.year + '-' + (full.month < 10 ? + full.month : full.month) + '-' + (i < 10 ? + '0' + i : i) + // 是否今天 + let isDay = fullDate === nowDate + // 获取打点信息 + let info = this.selected && this.selected.find((item) => { + if (this.dateEqual(nowDate, item.date)) { + return item + } + }) + + // 日期禁用 + let disableBefore = true + let disableAfter = true + if (this.startDate) { + // let dateCompBefore = this.dateCompare(this.startDate, fullDate) + // disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate) + disableBefore = this.dateCompare(this.startDate, nowDate) + } + + if (this.endDate) { + // let dateCompAfter = this.dateCompare(fullDate, this.endDate) + // disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate) + disableAfter = this.dateCompare(nowDate, this.endDate) + } + let multiples = this.multipleStatus.data + let checked = false + let multiplesStatus = -1 + if (this.range) { + if (multiples) { + multiplesStatus = multiples.findIndex((item) => { + return this.dateEqual(item, nowDate) + }) + } + if (multiplesStatus !== -1) { + checked = true + } + } + let data = { + fullDate: nowDate, + year: full.year, + date: i, + multiple: this.range ? checked : false, + beforeMultiple: this.dateEqual(this.multipleStatus.before, nowDate), + afterMultiple: this.dateEqual(this.multipleStatus.after, nowDate), + month: full.month, + lunar: this.getlunar(full.year, full.month, i), + disable: !(disableBefore && disableAfter), + isDay + } + if (info) { + data.extraInfo = info + } + + dateArr.push(data) + } + return dateArr + } + /** + * 获取下月天数 + */ + _getNextMonthDays(surplus, full) { + let dateArr = [] + for (let i = 1; i < surplus + 1; i++) { + dateArr.push({ + date: i, + month: Number(full.month) + 1, + lunar: this.getlunar(full.year, Number(full.month) + 1, i), + disable: true + }) + } + return dateArr + } + + /** + * 获取当前日期详情 + * @param {Object} date + */ + getInfo(date) { + if (!date) { + date = new Date() + } + const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate) + return dateInfo + } + + /** + * 比较时间大小 + */ + dateCompare(startDate, endDate) { + // 计算截止时间 + startDate = new Date(startDate.replace('-', '/').replace('-', '/')) + // 计算详细项的截止时间 + endDate = new Date(endDate.replace('-', '/').replace('-', '/')) + if (startDate <= endDate) { + return true + } else { + return false + } + } + + /** + * 比较时间是否相等 + */ + dateEqual(before, after) { + // 计算截止时间 + before = new Date(before.replace('-', '/').replace('-', '/')) + // 计算详细项的截止时间 + after = new Date(after.replace('-', '/').replace('-', '/')) + if (before.getTime() - after.getTime() === 0) { + return true + } else { + return false + } + } + + + /** + * 获取日期范围内所有日期 + * @param {Object} begin + * @param {Object} end + */ + geDateAll(begin, end) { + var arr = [] + var ab = begin.split('-') + var ae = end.split('-') + var db = new Date() + db.setFullYear(ab[0], ab[1] - 1, ab[2]) + var de = new Date() + de.setFullYear(ae[0], ae[1] - 1, ae[2]) + var unixDb = db.getTime() - 24 * 60 * 60 * 1000 + var unixDe = de.getTime() - 24 * 60 * 60 * 1000 + for (var k = unixDb; k <= unixDe;) { + k = k + 24 * 60 * 60 * 1000 + arr.push(this.getDate(new Date(parseInt(k))).fullDate) + } + return arr + } + /** + * 计算阴历日期显示 + */ + getlunar(year, month, date) { + return CALENDAR.solar2lunar(year, month, date) + } + /** + * 设置打点 + */ + setSelectInfo(data, value) { + this.selected = value + this._getWeek(data) + } + + /** + * 获取多选状态 + */ + setMultiple(fullDate) { + let { + before, + after + } = this.multipleStatus + + if (!this.range) return + if (before && after) { + this.multipleStatus.before = '' + this.multipleStatus.after = '' + this.multipleStatus.data = [] + } else { + if (!before) { + this.multipleStatus.before = fullDate + } else { + this.multipleStatus.after = fullDate + if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) { + this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after); + } else { + this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before); + } + } + } + this._getWeek(fullDate) + } + + /** + * 获取每周数据 + * @param {Object} dateData + */ + _getWeek(dateData) { + const { + year, + month + } = this.getDate(dateData) + let firstDay = new Date(year, month - 1, 1).getDay() + let currentDay = new Date(year, month, 0).getDate() + let dates = { + lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天 + currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数 + nextMonthDays: [], // 下个月开始几天 + weeks: [] + } + let canlender = [] + const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length) + dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData)) + canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays) + let weeks = {} + // 拼接数组 上个月开始几天 + 本月天数+ 下个月开始几天 + for (let i = 0; i < canlender.length; i++) { + if (i % 7 === 0) { + weeks[parseInt(i / 7)] = new Array(7) + } + weeks[parseInt(i / 7)][i % 7] = canlender[i] + } + this.canlender = canlender + this.weeks = weeks + } + + //静态方法 + // static init(date) { + // if (!this.instance) { + // this.instance = new Calendar(date); + // } + // return this.instance; + // } +} + + +export default Calendar diff --git a/uni_modules/uni-calendar/package.json b/uni_modules/uni-calendar/package.json new file mode 100644 index 0000000..fad841f --- /dev/null +++ b/uni_modules/uni-calendar/package.json @@ -0,0 +1,85 @@ +{ + "id": "uni-calendar", + "displayName": "uni-calendar 日历", + "version": "1.4.10", + "description": "日历组件", + "keywords": [ + "uni-ui", + "uniui", + "日历", + "", + "打卡", + "日历选择" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-calendar/readme.md b/uni_modules/uni-calendar/readme.md new file mode 100644 index 0000000..4e1748c --- /dev/null +++ b/uni_modules/uni-calendar/readme.md @@ -0,0 +1,103 @@ + + +## Calendar 日历 +> **组件名:uni-calendar** +> 代码块: `uCalendar` + + +日历组件 + +> **注意事项** +> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。 +> - 本组件农历转换使用的js是 [@1900-2100区间内的公历、农历互转](https://github.com/jjonline/calendar.js) +> - 仅支持自定义组件模式 +> - `date`属性传入的应该是一个 String ,如: 2019-06-27 ,而不是 new Date() +> - 通过 `insert` 属性来确定当前的事件是 @change 还是 @confirm 。理应合并为一个事件,但是为了区分模式,现使用两个事件,这里需要注意 +> - 弹窗模式下无法阻止后面的元素滚动,如有需要阻止,请在弹窗弹出后,手动设置滚动元素为不可滚动 + + +### 安装方式 + +本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。 + +如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55) + +### 基本用法 + +在 ``template`` 中使用组件 + +```html + + + +``` + +### 通过方法打开日历 + +需要设置 `insert` 为 `false` + +```html + + + + +``` + +```javascript + +export default { + data() { + return {}; + }, + methods: { + open(){ + this.$refs.calendar.open(); + }, + confirm(e) { + console.log(e); + } + } +}; + +``` + + +## API + +### Calendar Props + +| 属性名 | 类型 | 默认值| 说明 | +| - | - | - | - | +| date | String |- | 自定义当前时间,默认为今天 | +| lunar | Boolean | false | 显示农历 | +| startDate | String |- | 日期选择范围-开始日期 | +| endDate | String |- | 日期选择范围-结束日期 | +| range | Boolean | false | 范围选择 | +| insert | Boolean | false | 插入模式,可选值,ture:插入模式;false:弹窗模式;默认为插入模式 | +|clearDate |Boolean |true |弹窗模式是否清空上次选择内容 | +| selected | Array |- | 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}] | +|showMonth | Boolean | true | 是否显示月份为背景 | + +### Calendar Events + +| 事件名 | 说明 |返回值| +| - | - | - | +| open | 弹出日历组件,`insert :false` 时生效|- | + + + + + +## 组件示例 + +点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar](https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar) diff --git a/uni_modules/uni-captcha/changelog.md b/uni_modules/uni-captcha/changelog.md new file mode 100644 index 0000000..8b4f585 --- /dev/null +++ b/uni_modules/uni-captcha/changelog.md @@ -0,0 +1,45 @@ +## 0.7.3(2023-11-15) +- 更新 uni-popup-captcha.uvue依赖的popup组件,直接使用uni_modules下的uni-popup组件 +## 0.7.2(2023-11-07) +- 新增 前端组件:uni-captcha.uvue、uni-popup-captcha +## 0.7.1(2023-11-07) +- 新增 前端组件:uni-captcha.uvue、uni-popup-captcha +## 0.7.0(2023-10-10) +- 新增 支持在`uni-config-center`中配置mode,可选值为svg和bmp,配置成bmp后可以在uniappx的uvue页面正常显示验证码(uvue不支持显示svg验证码) +## 0.6.4(2023-01-16) +- 修复 部分情况下APP端无法获取验证码的问题 +## 0.6.3(2023-01-11) +- 修复 抖音小程序无法显示的Bug +- 修复 刷新时兼容 device_uuid +## 0.6.1(2022-06-23) +- 修复:部分返回值,不符合响应体规范的问题 +## 0.6.0(2022-05-27) +- 新增:支持在`uni-config-center`中根据场景值配置 +- 修复:弹窗式验证码,输入内容后点击取消,重新打开验证码的值仍然存在的问题 +## 0.5.2(2022-05-19) +- 修复在Vue3的兼容问题 +## 0.5.1(2022-05-18) +- 修复在某些情况下微信小程序端验证码显示错误的问题 +## 0.5.0(2022-05-17) +- 新增支持在`uni-captcha-co`->`config`配置验证码 +## 0.4.1(2022-05-16) +- 新增示例项目 +## 0.4.0(2022-05-16) +- 集成创建、刷新、显示验证码的云端一体验证码组件 +- 云对象`uni-captcha-co`集成获取验证码的api,`getImageCaptcha` +## 0.3.1(2022-05-13) +- 新增 返回值符合响应体规范 +## 0.3.0(2022-05-13) +- 新增 支持 uni-config-center 配置 +## 0.2.2(2022-04-25) +- 修复 0.2.1 版本引起的使用 image 组件验证码不显示的Bug +## 0.2.1(2022-04-18) +- 更新 优化字体 +## 0.2.0(2022-04-14) +- 新增 使用 svg 表现形式更好 +- 新增 使用字体,可以任意替换默认字体 +- 新增 支持设置字体大小 +- 新增 支持忽略某些字符 +- 注意 更新之后请重新上传公共模块 +## 0.1.0(2021-03-01) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-captcha/components/uni-captcha/uni-captcha.uvue b/uni_modules/uni-captcha/components/uni-captcha/uni-captcha.uvue new file mode 100644 index 0000000..db3f707 --- /dev/null +++ b/uni_modules/uni-captcha/components/uni-captcha/uni-captcha.uvue @@ -0,0 +1,180 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-captcha/components/uni-captcha/uni-captcha.vue b/uni_modules/uni-captcha/components/uni-captcha/uni-captcha.vue new file mode 100644 index 0000000..3d33343 --- /dev/null +++ b/uni_modules/uni-captcha/components/uni-captcha/uni-captcha.vue @@ -0,0 +1,167 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-captcha/components/uni-popup-captcha/uni-popup-captcha.uvue b/uni_modules/uni-captcha/components/uni-popup-captcha/uni-popup-captcha.uvue new file mode 100644 index 0000000..9963e12 --- /dev/null +++ b/uni_modules/uni-captcha/components/uni-popup-captcha/uni-popup-captcha.uvue @@ -0,0 +1,134 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-captcha/components/uni-popup-captcha/uni-popup-captcha.vue b/uni_modules/uni-captcha/components/uni-popup-captcha/uni-popup-captcha.vue new file mode 100644 index 0000000..b89b003 --- /dev/null +++ b/uni_modules/uni-captcha/components/uni-popup-captcha/uni-popup-captcha.vue @@ -0,0 +1,140 @@ + + + + + diff --git a/uni_modules/uni-captcha/package.json b/uni_modules/uni-captcha/package.json new file mode 100644 index 0000000..f7e1d51 --- /dev/null +++ b/uni_modules/uni-captcha/package.json @@ -0,0 +1,81 @@ +{ + "id": "uni-captcha", + "displayName": "uni-captcha", + "version": "0.7.3", + "description": "云端一体图形验证码组件", + "keywords": [ + "captcha", + "图形验证码", + "人机验证", + "防刷", + "防脚本" +], + "repository": "https://gitee.com/dcloud/uni-captcha", + "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" + }, + "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" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-captcha/readme.md b/uni_modules/uni-captcha/readme.md new file mode 100644 index 0000000..d929f63 --- /dev/null +++ b/uni_modules/uni-captcha/readme.md @@ -0,0 +1,3 @@ +

+文档已移至 uni-captcha文档 +

\ No newline at end of file diff --git a/uni_modules/uni-captcha/static/run.gif b/uni_modules/uni-captcha/static/run.gif new file mode 100644 index 0000000000000000000000000000000000000000..6d164f2146c27a309af2de7862ee5641eb382c50 GIT binary patch literal 31089 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 Ve{ud#)9(LUSwpD82w-vC?=Ntyrv literal 0 HcmV?d00001 diff --git a/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/LICENSE.md b/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/LICENSE.md new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/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-captcha/uniCloud/cloudfunctions/common/uni-captcha/fonts/font.ttf b/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/fonts/font.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a60ce88613704bc7fe02dbff52043c3757a0c9d7 GIT binary patch literal 7080 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 literal 0 HcmV?d00001 diff --git a/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/index.js b/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/index.js new file mode 100644 index 0000000..8ad32e0 --- /dev/null +++ b/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/index.js @@ -0,0 +1 @@ +"use strict";var e=require("assert"),t=require("path");function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var o=n(e),r=n(t);const s={10001:"uni-captcha-create-fail",10002:"uni-captcha-verify-fail",10003:"uni-captcha-refresh-fail",10101:"uni-captcha-deviceId-required",10102:"uni-captcha-text-required",10103:"uni-captcha-verify-overdue",10104:"uni-captcha-verify-fail",50403:"uni-captcha-interior-fail"};function a(e){const t=.2*Math.random()-.1;switch(e.type){case"M":case"L":e.x+=t,e.y+=t;break;case"Q":case"C":e.x+=t,e.y+=t,e.x1+=t,e.y1+=t}return e}function i(e,t,n,o,r,s,a){let i,l,c,u,p,h;if(e<=0||e>=1)throw RangeError("spliteCurveAt requires position > 0 && position < 1");return u=[],p=0,i={},l={},c={},i.x=t,i.y=n,l.x=o,l.y=r,c.x=s,c.y=a,h=e,u[p++]=i.x,u[p++]=i.y,u[p++]=i.x+=(l.x-i.x)*h,u[p++]=i.y+=(l.y-i.y)*h,l.x+=(c.x-l.x)*h,l.y+=(c.y-l.y)*h,u[p++]=i.x+(l.x-i.x)*h,u[p++]=i.y+(l.y-i.y)*h,u[p++]=l.x,u[p++]=l.y,u[p++]=c.x,u[p++]=c.y,u}function l(e,t){return Math.random()*(t-e)+e}var c=function(e,t){const n=e[0];o.default(n,"expect a string");const r=t.fontSize,s=r/t.font.unitsPerEm,c=t.font.charToGlyph(n),u=c.advanceWidth?c.advanceWidth*s:0,p=t.x-u/2,h=(t.ascender+t.descender)*s,f=t.y+h/2,d=c.getPath(p,f,r);d.commands.forEach(a),d.commands=function(e,t){const n=[];for(let o=0;ot.truncateLineProbability){const e=l(-.1,.1);n.push(r),n.push({type:"L",x:(r.x+s.x)/2+e,y:(r.y+s.y)/2+e})}else n.push(r)}else if("Q"===r.type&&o>=1){const s=e[o-1];if(("L"===s.type||"M"===s.type)&&Math.random()>t.truncateCurveProbability){const e=s.x,o=s.y,a=l(-.1,.1),c=r.x1+a,u=r.y1+a,p=r.x+a,h=r.y+a,f=i(l(t.truncateCurvePositionMin,t.truncateCurvePositionMax),e,o,c,u,p,h),d={type:"Q",x1:f[2],y1:f[3],x:f[4],y:f[5]},g={type:"L",x:f[4],y:f[5]},m={type:"Q",x1:f[6],y1:f[7],x:f[8],y:f[9]},y={type:"L",x:f[8],y:f[9]};n.push(d),n.push(g),n.push(m),n.push(y)}}else n.push(r)}return n}(d.commands,t);return d.toPathData()};function u(){this.table=new Uint16Array(16),this.trans=new Uint16Array(288)}function p(e,t){this.source=e,this.sourceIndex=0,this.tag=0,this.bitcount=0,this.dest=t,this.destLen=0,this.ltree=new u,this.dtree=new u}var h=new u,f=new u,d=new Uint8Array(30),g=new Uint16Array(30),m=new Uint8Array(30),y=new Uint16Array(30),v=new Uint8Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),b=new u,x=new Uint8Array(320);function S(e,t,n,o){var r,s;for(r=0;r>>=1,t}function E(e,t,n){if(!t)return n;for(;e.bitcount<24;)e.tag|=e.source[e.sourceIndex++]<>>16-t;return e.tag>>>=t,e.bitcount-=t,o+n}function O(e,t){for(;e.bitcount<24;)e.tag|=e.source[e.sourceIndex++]<>>=1,++r,n+=t.table[r],o-=t.table[r]}while(o>=0);return e.tag=s,e.bitcount-=r,t.trans[n+o]}function L(e,t,n){var o,r,s,a,i,l;for(o=E(e,5,257),r=E(e,5,1),s=E(e,4,4),a=0;a<19;++a)x[a]=0;for(a=0;a8;)e.sourceIndex--,e.bitcount-=8;if((t=256*(t=e.source[e.sourceIndex+1])+e.source[e.sourceIndex])!==(65535&~(256*e.source[e.sourceIndex+3]+e.source[e.sourceIndex+2])))return-3;for(e.sourceIndex+=4,n=t;n;--n)e.dest[e.destLen++]=e.source[e.sourceIndex++];return e.bitcount=0,0}!function(e,t){var n;for(n=0;n<7;++n)e.table[n]=0;for(e.table[7]=24,e.table[8]=152,e.table[9]=112,n=0;n<24;++n)e.trans[n]=256+n;for(n=0;n<144;++n)e.trans[24+n]=n;for(n=0;n<8;++n)e.trans[168+n]=280+n;for(n=0;n<112;++n)e.trans[176+n]=144+n;for(n=0;n<5;++n)t.table[n]=0;for(t.table[5]=32,n=0;n<32;++n)t.trans[n]=n}(h,f),S(d,g,4,3),S(m,y,2,1),d[28]=0,g[28]=258;var D=function(e,t){var n,o,r=new p(e,t);do{switch(n=w(r),E(r,2,0)){case 0:o=R(r);break;case 1:o=k(r,h,f);break;case 2:L(r,r.ltree,r.dtree),o=k(r,r.ltree,r.dtree);break;default:o=-3}if(0!==o)throw new Error("Data error")}while(!n);return r.destLenthis.x2&&(this.x2=e)),"number"==typeof t&&((isNaN(this.y1)||isNaN(this.y2))&&(this.y1=t,this.y2=t),tthis.y2&&(this.y2=t))},M.prototype.addX=function(e){this.addPoint(e,null)},M.prototype.addY=function(e){this.addPoint(null,e)},M.prototype.addBezier=function(e,t,n,o,r,s,a,i){const l=[e,t],c=[n,o],u=[r,s],p=[a,i];this.addPoint(e,t),this.addPoint(a,i);for(let e=0;e<=1;e++){const t=6*l[e]-12*c[e]+6*u[e],n=-3*l[e]+9*c[e]-9*u[e]+3*p[e],o=3*c[e]-3*l[e];if(0===n){if(0===t)continue;const n=-o/t;0=0&&n>0&&(e+=" "),e+=t(o)}return e}e=void 0!==e?e:2;let o="";for(let e=0;e=0&&e<=255,"Byte value should be between 0 and 255."),[e]},F.BYTE=H(1),A.CHAR=function(e){return[e.charCodeAt(0)]},F.CHAR=H(1),A.CHARARRAY=function(e){const t=[];for(let n=0;n>8&255,255&e]},F.USHORT=H(2),A.SHORT=function(e){return e>=32768&&(e=-(65536-e)),[e>>8&255,255&e]},F.SHORT=H(2),A.UINT24=function(e){return[e>>16&255,e>>8&255,255&e]},F.UINT24=H(3),A.ULONG=function(e){return[e>>24&255,e>>16&255,e>>8&255,255&e]},F.ULONG=H(4),A.LONG=function(e){return e>=2147483648&&(e=-(4294967296-e)),[e>>24&255,e>>16&255,e>>8&255,255&e]},F.LONG=H(4),A.FIXED=A.ULONG,F.FIXED=F.ULONG,A.FWORD=A.SHORT,F.FWORD=F.SHORT,A.UFWORD=A.USHORT,F.UFWORD=F.USHORT,A.LONGDATETIME=function(e){return[0,0,0,0,e>>24&255,e>>16&255,e>>8&255,255&e]},F.LONGDATETIME=H(8),A.TAG=function(e){return G.argument(4===e.length,"Tag should be exactly 4 ASCII characters."),[e.charCodeAt(0),e.charCodeAt(1),e.charCodeAt(2),e.charCodeAt(3)]},F.TAG=H(4),A.Card8=A.BYTE,F.Card8=F.BYTE,A.Card16=A.USHORT,F.Card16=F.USHORT,A.OffSize=A.BYTE,F.OffSize=F.BYTE,A.SID=A.USHORT,F.SID=F.USHORT,A.NUMBER=function(e){return e>=-107&&e<=107?[e+139]:e>=108&&e<=1131?[247+((e-=108)>>8),255&e]:e>=-1131&&e<=-108?[251+((e=-e-108)>>8),255&e]:e>=-32768&&e<=32767?A.NUMBER16(e):A.NUMBER32(e)},F.NUMBER=function(e){return A.NUMBER(e).length},A.NUMBER16=function(e){return[28,e>>8&255,255&e]},F.NUMBER16=H(3),A.NUMBER32=function(e){return[29,e>>24&255,e>>16&255,e>>8&255,255&e]},F.NUMBER32=H(5),A.REAL=function(e){let t=e.toString();const n=/\.(\d*?)(?:9{5,20}|0{5,20})\d{0,2}(?:e(.+)|$)/.exec(t);if(n){const o=parseFloat("1e"+((n[2]?+n[2]:0)+n[1].length));t=(Math.round(e*o)/o).toString()}let o="";for(let e=0,n=t.length;e>8&255,t[t.length]=255&o}return t},F.UTF16=function(e){return 2*e.length};const z={"x-mac-croatian":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®Š™´¨≠ŽØ∞±≤≥∆µ∂∑∏š∫ªºΩžø¿¡¬√ƒ≈ƫȅ ÀÃÕŒœĐ—“”‘’÷◊©⁄€‹›Æ»–·‚„‰ÂćÁčÈÍÎÏÌÓÔđÒÚÛÙıˆ˜¯πË˚¸Êæˇ","x-mac-cyrillic":"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°Ґ£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµґЈЄєЇїЉљЊњјЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю","x-mac-gaelic":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØḂ±≤≥ḃĊċḊḋḞḟĠġṀæøṁṖṗɼƒſṠ«»… ÀÃÕŒœ–—“”‘’ṡẛÿŸṪ€‹›Ŷŷṫ·Ỳỳ⁊ÂÊÁËÈÍÎÏÌÓÔ♣ÒÚÛÙıÝýŴŵẄẅẀẁẂẃ","x-mac-greek":"Ĺ²É³ÖÜ΅àâä΄¨çéèê룙î‰ôö¦€ùûü†ΓΔΘΛΞΠß®©ΣΪ§≠°·Α±≤≥¥ΒΕΖΗΙΚΜΦΫΨΩάΝ¬ΟΡ≈Τ«»… ΥΧΆΈœ–―“”‘’÷ΉΊΌΎέήίόΏύαβψδεφγηιξκλμνοπώρστθωςχυζϊϋΐΰ­","x-mac-icelandic":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûüݰ¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€ÐðÞþý·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ","x-mac-inuit":"ᐃᐄᐅᐆᐊᐋᐱᐲᐳᐴᐸᐹᑉᑎᑏᑐᑑᑕᑖᑦᑭᑮᑯᑰᑲᑳᒃᒋᒌᒍᒎᒐᒑ°ᒡᒥᒦ•¶ᒧ®©™ᒨᒪᒫᒻᓂᓃᓄᓅᓇᓈᓐᓯᓰᓱᓲᓴᓵᔅᓕᓖᓗᓘᓚᓛᓪᔨᔩᔪᔫᔭ… ᔮᔾᕕᕖᕗ–—“”‘’ᕘᕙᕚᕝᕆᕇᕈᕉᕋᕌᕐᕿᖀᖁᖂᖃᖄᖅᖏᖐᖑᖒᖓᖔᖕᙱᙲᙳᙴᙵᙶᖖᖠᖡᖢᖣᖤᖥᖦᕼŁł","x-mac-ce":"ÄĀāÉĄÖÜáąČäčĆć鏟ĎíďĒēĖóėôöõúĚěü†°Ę£§•¶ß®©™ę¨≠ģĮįĪ≤≥īĶ∂∑łĻļĽľĹĺŅņѬ√ńŇ∆«»… ňŐÕőŌ–—“”‘’÷◊ōŔŕŘ‹›řŖŗŠ‚„šŚśÁŤťÍŽžŪÓÔūŮÚůŰűŲųÝýķŻŁżĢˇ",macintosh:"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›fifl‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ","x-mac-romanian":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ĂȘ∞±≤≥¥µ∂∑∏π∫ªºΩăș¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›Țț‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ","x-mac-turkish":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸĞğİıŞş‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙˆ˜¯˘˙˚¸˝˛ˇ"};P.MACSTRING=function(e,t,n,o){const r=z[o];if(void 0===r)return;let s="";for(let o=0;o=-128&&e<=127}function X(e,t,n){let o=0;const r=e.length;for(;t>8&255,t+256&255)}return s}A.MACSTRING=function(e,t){const n=function(e){if(!_){_={};for(let e in z)_[e]=new String(e)}const t=_[e];if(void 0===t)return;if(W){const e=W.get(t);if(void 0!==e)return e}const n=z[e];if(void 0===n)return;const o={};for(let e=0;e=128&&(r=n[r],void 0===r))return;o[t]=r}return o},F.MACSTRING=function(e,t){const n=A.MACSTRING(e,t);return void 0!==n?n.length:0},A.VARDELTAS=function(e){let t=0;const n=[];for(;t=-128&&o<=127?V(e,t,n):j(e,t,n)}return n},A.INDEX=function(e){let t=1;const n=[t],o=[];for(let r=0;r>8,t[s+1]=255&a,t=t.concat(o[n])}return t},F.TABLE=function(e){let t=0;const n=e.fields.length;for(let o=0;o0)return new ce(this.data,this.offset+t).parseStruct(e)},ce.prototype.parseListOfLists=function(e){const t=this.parseOffset16List(),n=t.length,o=this.relativeOffset,r=new Array(n);for(let o=0;o=0;r-=1){const n=pe.getUShort(e,t+4+8*r),s=pe.getUShort(e,t+4+8*r+2);if(3===n&&(0===s||1===s||10===s)){o=pe.getULong(e,t+4+8*r+4);break}}if(-1===o)throw new Error("No valid cmap sub-tables found.");const r=new pe.Parser(e,t+o);if(n.format=r.parseUShort(),12===n.format)!function(e,t){let n;t.parseUShort(),e.length=t.parseULong(),e.language=t.parseULong(),e.groupCount=n=t.parseULong(),e.glyphIndexMap={};for(let o=0;o>1,t.skip("uShort",3),e.glyphIndexMap={};const a=new pe.Parser(n,o+r+14),i=new pe.Parser(n,o+r+16+2*s),l=new pe.Parser(n,o+r+16+4*s),c=new pe.Parser(n,o+r+16+6*s);let u=o+r+16+8*s;for(let t=0;t0?(s=e.parseByte(),0==(t&r)&&(s=-s),s=n+s):s=(t&r)>0?n:n+e.parseShort(),s}function we(e,t,n){const o=new pe.Parser(t,n);let r,s;if(e.numberOfContours=o.parseShort(),e._xMin=o.parseShort(),e._yMin=o.parseShort(),e._xMax=o.parseShort(),e._yMax=o.parseShort(),e.numberOfContours>0){const t=e.endPointIndices=[];for(let n=0;n0){const t=o.parseByte();for(let n=0;n0){const a=[];let i;if(n>0){for(let e=0;e=0,a.push(i);let e=0;for(let t=0;t0?(2&r)>0?(n.dx=o.parseShort(),n.dy=o.parseShort()):n.matchedPoints=[o.parseUShort(),o.parseUShort()]:(2&r)>0?(n.dx=o.parseChar(),n.dy=o.parseChar()):n.matchedPoints=[o.parseByte(),o.parseByte()],(8&r)>0?n.xScale=n.yScale=o.parseF2Dot14():(64&r)>0?(n.xScale=o.parseF2Dot14(),n.yScale=o.parseF2Dot14()):(128&r)>0&&(n.xScale=o.parseF2Dot14(),n.scale01=o.parseF2Dot14(),n.scale10=o.parseF2Dot14(),n.yScale=o.parseF2Dot14()),e.components.push(n),t=!!(32&r)}if(256&r){e.instructionLength=o.parseUShort(),e.instructions=[];for(let t=0;tt.points.length-1||o.matchedPoints[1]>r.points.length-1)throw Error("Matched points out of range in "+t.name);const n=t.points[o.matchedPoints[0]];let s=r.points[o.matchedPoints[1]];const a={xScale:o.xScale,scale01:o.scale01,scale10:o.scale10,yScale:o.yScale,dx:0,dy:0};s=Ee([s],a)[0],a.dx=n.x-s.x,a.dy=n.y-s.y,e=Ee(r.points,a)}t.points=t.points.concat(e)}}return Oe(t.points)}var ke={getPath:Oe,parse:function(e,t,n,o){const r=new Me.GlyphSet(o);for(let s=0;s>4,s=15&o;if(15===r)break;if(t+=n[r],15===s)break;t+=n[s]}return parseFloat(t)}(e);if(t>=32&&t<=246)return t-139;if(t>=247&&t<=250)return n=e.parseByte(),256*(t-247)+n+108;if(t>=251&&t<=254)return n=e.parseByte(),256*-(t-251)-n-108;throw new Error("Invalid b0 "+t)}function Pe(e,t,n){t=void 0!==t?t:0;const o=new pe.Parser(e,t),r=[];let s=[];for(n=void 0!==n?n:e.length;o.relativeOffset>1,l.length=0,d=!0}return function n(p){let S,U,T,w,E,O,L,k,R,D,C,M,I=0;for(;I1&&!d&&(v=l.shift()+h,d=!0),y+=l.pop(),b(m,y);break;case 5:for(;l.length>0;)m+=l.shift(),y+=l.shift(),i.lineTo(m,y);break;case 6:for(;l.length>0&&(m+=l.shift(),i.lineTo(m,y),0!==l.length);)y+=l.shift(),i.lineTo(m,y);break;case 7:for(;l.length>0&&(y+=l.shift(),i.lineTo(m,y),0!==l.length);)m+=l.shift(),i.lineTo(m,y);break;case 8:for(;l.length>0;)o=m+l.shift(),r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),m=s+l.shift(),y=a+l.shift(),i.curveTo(o,r,s,a,m,y);break;case 10:E=l.pop()+u,O=c[E],O&&n(O);break;case 11:return;case 12:switch(B=p[I],I+=1,B){case 35:o=m+l.shift(),r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),L=s+l.shift(),k=a+l.shift(),R=L+l.shift(),D=k+l.shift(),C=R+l.shift(),M=D+l.shift(),m=C+l.shift(),y=M+l.shift(),l.shift(),i.curveTo(o,r,s,a,L,k),i.curveTo(R,D,C,M,m,y);break;case 34:o=m+l.shift(),r=y,s=o+l.shift(),a=r+l.shift(),L=s+l.shift(),k=a,R=L+l.shift(),D=a,C=R+l.shift(),M=y,m=C+l.shift(),i.curveTo(o,r,s,a,L,k),i.curveTo(R,D,C,M,m,y);break;case 36:o=m+l.shift(),r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),L=s+l.shift(),k=a,R=L+l.shift(),D=a,C=R+l.shift(),M=D+l.shift(),m=C+l.shift(),i.curveTo(o,r,s,a,L,k),i.curveTo(R,D,C,M,m,y);break;case 37:o=m+l.shift(),r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),L=s+l.shift(),k=a+l.shift(),R=L+l.shift(),D=k+l.shift(),C=R+l.shift(),M=D+l.shift(),Math.abs(C-m)>Math.abs(M-y)?m=C+l.shift():y=M+l.shift(),i.curveTo(o,r,s,a,L,k),i.curveTo(R,D,C,M,m,y);break;default:console.log("Glyph "+t.index+": unknown operator 1200"+B),l.length=0}break;case 14:l.length>0&&!d&&(v=l.shift()+h,d=!0),g&&(i.closePath(),g=!1);break;case 18:x();break;case 19:case 20:x(),I+=f+7>>3;break;case 21:l.length>2&&!d&&(v=l.shift()+h,d=!0),y+=l.pop(),m+=l.pop(),b(m,y);break;case 22:l.length>1&&!d&&(v=l.shift()+h,d=!0),m+=l.pop(),b(m,y);break;case 23:x();break;case 24:for(;l.length>2;)o=m+l.shift(),r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),m=s+l.shift(),y=a+l.shift(),i.curveTo(o,r,s,a,m,y);m+=l.shift(),y+=l.shift(),i.lineTo(m,y);break;case 25:for(;l.length>6;)m+=l.shift(),y+=l.shift(),i.lineTo(m,y);o=m+l.shift(),r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),m=s+l.shift(),y=a+l.shift(),i.curveTo(o,r,s,a,m,y);break;case 26:for(l.length%2&&(m+=l.shift());l.length>0;)o=m,r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),m=s,y=a+l.shift(),i.curveTo(o,r,s,a,m,y);break;case 27:for(l.length%2&&(y+=l.shift());l.length>0;)o=m+l.shift(),r=y,s=o+l.shift(),a=r+l.shift(),m=s+l.shift(),y=a,i.curveTo(o,r,s,a,m,y);break;case 28:S=p[I],U=p[I+1],l.push((S<<24|U<<16)>>16),I+=2;break;case 29:E=l.pop()+e.gsubrsBias,O=e.gsubrs[E],O&&n(O);break;case 30:for(;l.length>0&&(o=m,r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),m=s+l.shift(),y=a+(1===l.length?l.shift():0),i.curveTo(o,r,s,a,m,y),0!==l.length);)o=m+l.shift(),r=y,s=o+l.shift(),a=r+l.shift(),y=a+l.shift(),m=s+(1===l.length?l.shift():0),i.curveTo(o,r,s,a,m,y);break;case 31:for(;l.length>0&&(o=m+l.shift(),r=y,s=o+l.shift(),a=r+l.shift(),y=a+l.shift(),m=s+(1===l.length?l.shift():0),i.curveTo(o,r,s,a,m,y),0!==l.length);)o=m,r=y+l.shift(),s=o+l.shift(),a=r+l.shift(),m=s+l.shift(),y=a+(1===l.length?l.shift():0),i.curveTo(o,r,s,a,m,y);break;default:B<32?console.log("Glyph "+t.index+": unknown operator "+B):B<247?l.push(B-139):B<251?(S=p[I],I+=1,l.push(256*(B-247)+S+108)):B<255?(S=p[I],I+=1,l.push(256*-(B-251)-S-108)):(S=p[I],U=p[I+1],T=p[I+2],w=p[I+3],I+=4,l.push((S<<24|U<<16|T<<8|w)/65536))}}}(n),t.advanceWidth=v,i}function Ve(e,t){let n,o=de.indexOf(e);return o>=0&&(n=o),o=t.indexOf(e),o>=0?n=o+de.length:(n=de.length+t.length,t.push(e)),n}function je(e,t,n){const o={};for(let r=0;r=o)throw new Error("CFF table CID Font FDSelect has bad FD index value "+s+" (FD count "+o+")");r.push(s)}else{if(3!==i)throw new Error("CFF Table CID Font FDSelect table has unsupported format "+i);{const e=a.parseCard16();let t,i=a.parseCard16();if(0!==i)throw new Error("CFF Table CID Font FDSelect format 3 range has bad initial GID "+i);for(let l=0;l=o)throw new Error("CFF table CID Font FDSelect has bad FD index value "+s+" (FD count "+o+")");if(t>n)throw new Error("CFF Table CID Font FDSelect format 3 range has bad GID "+t);for(;i=1&&(n.ulCodePageRange1=o.parseULong(),n.ulCodePageRange2=o.parseULong()),n.version>=2&&(n.sxHeight=o.parseShort(),n.sCapHeight=o.parseShort(),n.usDefaultChar=o.parseUShort(),n.usBreakChar=o.parseUShort(),n.usMaxContent=o.parseUShort()),n},make:function(e){return new oe.Table("OS/2",[{name:"version",type:"USHORT",value:3},{name:"xAvgCharWidth",type:"SHORT",value:0},{name:"usWeightClass",type:"USHORT",value:0},{name:"usWidthClass",type:"USHORT",value:0},{name:"fsType",type:"USHORT",value:0},{name:"ySubscriptXSize",type:"SHORT",value:650},{name:"ySubscriptYSize",type:"SHORT",value:699},{name:"ySubscriptXOffset",type:"SHORT",value:0},{name:"ySubscriptYOffset",type:"SHORT",value:140},{name:"ySuperscriptXSize",type:"SHORT",value:650},{name:"ySuperscriptYSize",type:"SHORT",value:699},{name:"ySuperscriptXOffset",type:"SHORT",value:0},{name:"ySuperscriptYOffset",type:"SHORT",value:479},{name:"yStrikeoutSize",type:"SHORT",value:49},{name:"yStrikeoutPosition",type:"SHORT",value:258},{name:"sFamilyClass",type:"SHORT",value:0},{name:"bFamilyType",type:"BYTE",value:0},{name:"bSerifStyle",type:"BYTE",value:0},{name:"bWeight",type:"BYTE",value:0},{name:"bProportion",type:"BYTE",value:0},{name:"bContrast",type:"BYTE",value:0},{name:"bStrokeVariation",type:"BYTE",value:0},{name:"bArmStyle",type:"BYTE",value:0},{name:"bLetterform",type:"BYTE",value:0},{name:"bMidline",type:"BYTE",value:0},{name:"bXHeight",type:"BYTE",value:0},{name:"ulUnicodeRange1",type:"ULONG",value:0},{name:"ulUnicodeRange2",type:"ULONG",value:0},{name:"ulUnicodeRange3",type:"ULONG",value:0},{name:"ulUnicodeRange4",type:"ULONG",value:0},{name:"achVendID",type:"CHARARRAY",value:"XXXX"},{name:"fsSelection",type:"USHORT",value:0},{name:"usFirstCharIndex",type:"USHORT",value:0},{name:"usLastCharIndex",type:"USHORT",value:0},{name:"sTypoAscender",type:"SHORT",value:0},{name:"sTypoDescender",type:"SHORT",value:0},{name:"sTypoLineGap",type:"SHORT",value:0},{name:"usWinAscent",type:"USHORT",value:0},{name:"usWinDescent",type:"USHORT",value:0},{name:"ulCodePageRange1",type:"ULONG",value:0},{name:"ulCodePageRange2",type:"ULONG",value:0},{name:"sxHeight",type:"SHORT",value:0},{name:"sCapHeight",type:"SHORT",value:0},{name:"usDefaultChar",type:"USHORT",value:0},{name:"usBreakChar",type:"USHORT",value:0},{name:"usMaxContext",type:"USHORT",value:0}],e)},unicodeRanges:gt,getUnicodeRange:function(e){for(let t=0;t=n.begin&&e=ye.length){const e=o.parseChar();n.names.push(o.parseString(e))}break;case 2.5:n.numberOfGlyphs=o.parseUShort(),n.offset=new Array(n.numberOfGlyphs);for(let e=0;et.value.tag?1:-1})),t.fields=t.fields.concat(o),t.fields=t.fields.concat(r),t}function Lt(e,t,n){for(let n=0;n0){return e.glyphs.get(o).getMetrics()}}return n}function kt(e){let t=0;for(let n=0;nm||void 0===l)&&m>0&&(l=m),c 123 are reserved for internal usage");f|=1<0?tt.make(O):void 0,R=yt.make(),D=Qe.make(e.glyphs,{version:e.getEnglishName("version"),fullName:T,familyName:S,weightName:U,postScriptName:w,unitsPerEm:e.unitsPerEm,fontBBox:[0,d.yMin,d.ascender,d.advanceWidthMax]}),C=e.metas&&Object.keys(e.metas).length>0?Ut.make(e.metas):void 0,M=[g,m,y,v,L,x,R,D,b];k&&M.push(k),e.tables.gsub&&M.push(St.make(e.tables.gsub)),C&&M.push(C);const I=Ot(M),B=wt(I.encode()),N=I.fields;let G=!1;for(let e=0;e>>1,s=e[r].tag;if(s===t)return r;s>>1,s=e[r];if(s===t)return r;s=0)return o[r].script;if(t){const t={tag:e,script:{defaultLangSys:{reserved:0,reqFeatureIndex:65535,featureIndexes:[]},langSysRecords:[]}};return o.splice(-1-r,0,t),t.script}}},getLangSysTable:function(e,t,n){const o=this.getScriptTable(e,n);if(o){if(!t||"dflt"===t||"DFLT"===t)return o.defaultLangSys;const e=Dt(o.langSysRecords,t);if(e>=0)return o.langSysRecords[e].langSys;if(n){const n={tag:t,langSys:{reserved:0,reqFeatureIndex:65535,featureIndexes:[]}};return o.langSysRecords.splice(-1-e,0,n),n.langSys}}},getFeatureTable:function(e,t,n,o){const r=this.getLangSysTable(e,t,o);if(r){let e;const t=r.featureIndexes,s=this.font.tables[this.tableName].features;for(let o=0;o=s[o-1].tag,"Features must be added in alphabetical order."),e={tag:n,feature:{params:0,lookupListIndexes:[]}},s.push(e),t.push(o),e.feature}}},getLookupTables:function(e,t,n,o,r){const s=this.getFeatureTable(e,t,n,r),a=[];if(s){let e;const t=s.lookupListIndexes,n=this.font.tables[this.tableName].lookups;for(let r=0;r=0){const e=s.ligatureSets[c];for(let t=0;t0&&e<0?n:o<0&&e>0?-n:e*o},Zt={x:1,y:0,axis:"x",distance:function(e,t,n,o){return(n?e.xo:e.x)-(o?t.xo:t.x)},interpolate:function(e,t,n,o){let r,s,a,i,l,c,u;if(!o||o===this)return r=e.xo-t.xo,s=e.xo-n.xo,l=t.x-t.xo,c=n.x-n.xo,a=Math.abs(r),i=Math.abs(s),u=a+i,0===u?void(e.x=e.xo+(l+c)/2):void(e.x=e.xo+(l*i+c*a)/u);r=o.distance(e,t,!0,!0),s=o.distance(e,n,!0,!0),l=o.distance(t,t,!1,!0),c=o.distance(n,n,!1,!0),a=Math.abs(r),i=Math.abs(s),u=a+i,0!==u?Zt.setRelative(e,e,(l*i+c*a)/u,o,!0):Zt.setRelative(e,e,(l+c)/2,o,!0)},normalSlope:Number.NEGATIVE_INFINITY,setRelative:function(e,t,n,o,r){if(!o||o===this)return void(e.x=(r?t.xo:t.x)+n);const s=r?t.xo:t.x,a=r?t.yo:t.y,i=s+n*o.x,l=a+n*o.y;e.x=i+(e.y-l)/o.normalSlope},slope:0,touch:function(e){e.xTouched=!0},touched:function(e){return e.xTouched},untouch:function(e){e.xTouched=!1}},$t={x:0,y:1,axis:"y",distance:function(e,t,n,o){return(n?e.yo:e.y)-(o?t.yo:t.y)},interpolate:function(e,t,n,o){let r,s,a,i,l,c,u;if(!o||o===this)return r=e.yo-t.yo,s=e.yo-n.yo,l=t.y-t.yo,c=n.y-n.yo,a=Math.abs(r),i=Math.abs(s),u=a+i,0===u?void(e.y=e.yo+(l+c)/2):void(e.y=e.yo+(l*i+c*a)/u);r=o.distance(e,t,!0,!0),s=o.distance(e,n,!0,!0),l=o.distance(t,t,!1,!0),c=o.distance(n,n,!1,!0),a=Math.abs(r),i=Math.abs(s),u=a+i,0!==u?$t.setRelative(e,e,(l*i+c*a)/u,o,!0):$t.setRelative(e,e,(l+c)/2,o,!0)},normalSlope:0,setRelative:function(e,t,n,o,r){if(!o||o===this)return void(e.y=(r?t.yo:t.y)+n);const s=r?t.xo:t.x,a=r?t.yo:t.y,i=s+n*o.x,l=a+n*o.y;e.y=l+o.normalSlope*(e.x-i)},slope:Number.POSITIVE_INFINITY,touch:function(e){e.yTouched=!0},touched:function(e){return e.yTouched},untouch:function(e){e.yTouched=!1}};function Qt(e,t){this.x=e,this.y=t,this.axis=void 0,this.slope=t/e,this.normalSlope=-e/t,Object.freeze(this)}function Kt(e,t){const n=Math.sqrt(e*e+t*t);return t/=n,1===(e/=n)&&0===t?Zt:0===e&&1===t?$t:new Qt(e,t)}function Jt(e,t,n,o){this.x=this.xo=Math.round(64*e)/64,this.y=this.yo=Math.round(64*t)/64,this.lastPointOfContour=n,this.onCurve=o,this.prevPointOnContour=void 0,this.nextPointOnContour=void 0,this.xTouched=!1,this.yTouched=!1,Object.preventExtensions(this)}Object.freeze(Zt),Object.freeze($t),Qt.prototype.distance=function(e,t,n,o){return this.x*Zt.distance(e,t,n,o)+this.y*$t.distance(e,t,n,o)},Qt.prototype.interpolate=function(e,t,n,o){let r,s,a,i,l,c,u;a=o.distance(e,t,!0,!0),i=o.distance(e,n,!0,!0),r=o.distance(t,t,!1,!0),s=o.distance(n,n,!1,!0),l=Math.abs(a),c=Math.abs(i),u=l+c,0!==u?this.setRelative(e,e,(r*c+s*l)/u,o,!0):this.setRelative(e,e,(r+s)/2,o,!0)},Qt.prototype.setRelative=function(e,t,n,o,r){o=o||this;const s=r?t.xo:t.x,a=r?t.yo:t.y,i=s+n*o.x,l=a+n*o.y,c=o.normalSlope,u=this.slope,p=e.x,h=e.y;e.x=(u*p-c*i+l-h)/(u-c),e.y=u*(e.x-p)+h},Qt.prototype.touch=function(e){e.xTouched=!0,e.yTouched=!0},Jt.prototype.nextTouched=function(e){let t=this.nextPointOnContour;for(;!e.touched(t)&&t!==this;)t=t.nextPointOnContour;return t},Jt.prototype.prevTouched=function(e){let t=this.prevPointOnContour;for(;!e.touched(t)&&t!==this;)t=t.prevPointOnContour;return t};const en=Object.freeze(new Jt(0,0)),tn={cvCutIn:17/16,deltaBase:9,deltaShift:.125,loop:1,minDis:1,autoFlip:!0};function nn(e,t){switch(this.env=e,this.stack=[],this.prog=t,e){case"glyf":this.zp0=this.zp1=this.zp2=1,this.rp0=this.rp1=this.rp2=0;case"prep":this.fv=this.pv=this.dpv=Zt,this.round=_t}}function on(e){const t=e.tZone=new Array(e.gZone.length);for(let e=0;e=176&&o<=183)r+=o-176+1;else if(o>=184&&o<=191)r+=2*(o-184+1);else if(t&&1===s&&27===o)break}while(s>0);e.ip=r}function sn(e,t){exports.DEBUG&&console.log(t.step,"SVTCA["+e.axis+"]"),t.fv=t.pv=t.dpv=e}function an(e,t){exports.DEBUG&&console.log(t.step,"SPVTCA["+e.axis+"]"),t.pv=t.dpv=e}function ln(e,t){exports.DEBUG&&console.log(t.step,"SFVTCA["+e.axis+"]"),t.fv=e}function cn(e,t){const n=t.stack,o=n.pop(),r=n.pop(),s=t.z2[o],a=t.z1[r];let i,l;exports.DEBUG&&console.log("SPVTL["+e+"]",o,r),e?(i=s.y-a.y,l=a.x-s.x):(i=a.x-s.x,l=a.y-s.y),t.pv=t.dpv=Kt(i,l)}function un(e,t){const n=t.stack,o=n.pop(),r=n.pop(),s=t.z2[o],a=t.z1[r];let i,l;exports.DEBUG&&console.log("SFVTL["+e+"]",o,r),e?(i=s.y-a.y,l=a.x-s.x):(i=a.x-s.x,l=a.y-s.y),t.fv=Kt(i,l)}function pn(e){exports.DEBUG&&console.log(e.step,"POP[]"),e.stack.pop()}function hn(e,t){const n=t.stack.pop(),o=t.z0[n],r=t.fv,s=t.pv;exports.DEBUG&&console.log(t.step,"MDAP["+e+"]",n);let a=s.distance(o,en);e&&(a=t.round(a)),r.setRelative(o,en,a,s),r.touch(o),t.rp0=t.rp1=n}function fn(e,t){const n=t.z2,o=n.length-2;let r,s,a;exports.DEBUG&&console.log(t.step,"IUP["+e.axis+"]");for(let t=0;t1?"loop "+(t.loop-i)+": ":"")+"SHP["+(e?"rp1":"rp2")+"]",o)}t.loop=1}function gn(e,t){const n=t.stack,o=e?t.rp1:t.rp2,r=(e?t.z0:t.z1)[o],s=t.fv,a=t.pv,i=n.pop(),l=t.z2[t.contours[i]];let c=l;exports.DEBUG&&console.log(t.step,"SHC["+e+"]",i);const u=a.distance(r,r,!1,!0);do{c!==r&&s.setRelative(c,c,u,a),c=c.nextPointOnContour}while(c!==l)}function mn(e,t){const n=t.stack,o=e?t.rp1:t.rp2,r=(e?t.z0:t.z1)[o],s=t.fv,a=t.pv,i=n.pop();let l,c;switch(exports.DEBUG&&console.log(t.step,"SHZ["+e+"]",i),i){case 0:l=t.tZone;break;case 1:l=t.gZone;break;default:throw new Error("Invalid zone")}const u=a.distance(r,r,!1,!0),p=l.length-2;for(let e=0;e",i),t.stack.push(Math.round(64*i))}function Sn(e,t){const n=t.stack,o=n.pop(),r=t.fv,s=t.pv,a=t.ppem,i=t.deltaBase+16*(e-1),l=t.deltaShift,c=t.z0;exports.DEBUG&&console.log(t.step,"DELTAP["+e+"]",o,n);for(let e=0;e>4)!==a)continue;let u=(15&o)-8;u>=0&&u++,exports.DEBUG&&console.log(t.step,"DELTAPFIX",e,"by",u*l);const p=c[e];r.setRelative(p,p,u*l,s)}}function Un(e,t){const n=t.stack,o=n.pop();exports.DEBUG&&console.log(t.step,"ROUND[]"),n.push(64*t.round(o/64))}function Tn(e,t){const n=t.stack,o=n.pop(),r=t.ppem,s=t.deltaBase+16*(e-1),a=t.deltaShift;exports.DEBUG&&console.log(t.step,"DELTAC["+e+"]",o,n);for(let e=0;e>4)!==r)continue;let i=(15&o)-8;i>=0&&i++;const l=i*a;exports.DEBUG&&console.log(t.step,"DELTACFIX",e,"by",l),t.cvt[e]+=l}}function wn(e,t){const n=t.stack,o=n.pop(),r=n.pop(),s=t.z2[o],a=t.z1[r];let i,l;exports.DEBUG&&console.log("SDPVTL["+e+"]",o,r),e?(i=s.y-a.y,l=a.x-s.x):(i=a.x-s.x,l=a.y-s.y),t.dpv=Kt(i,l)}function En(e,t){const n=t.stack,o=t.prog;let r=t.ip;exports.DEBUG&&console.log(t.step,"PUSHB["+e+"]");for(let t=0;t=0?1:-1,m=Math.abs(m),e&&(v=s.cvt[i],o&&Math.abs(m-v)":"_")+(o?"R":"_")+(0===r?"Gr":1===r?"Bl":2===r?"Wh":"")+"]",e?i+"("+s.cvt[i]+","+v+")":"",l,"(d =",g,"->",y*m,")"),s.rp1=s.rp0,s.rp2=l,t&&(s.rp0=l)}function kn(e){(e=e||{}).empty||(Gt(e.familyName,"When creating a new Font object, familyName is required."),Gt(e.styleName,"When creating a new Font object, styleName is required."),Gt(e.unitsPerEm,"When creating a new Font object, unitsPerEm is required."),Gt(e.ascender,"When creating a new Font object, ascender is required."),Gt(e.descender,"When creating a new Font object, descender is required."),Gt(e.descender<0,"Descender should be negative (e.g. -512)."),this.names={fontFamily:{en:e.familyName||" "},fontSubfamily:{en:e.styleName||" "},fullName:{en:e.fullName||e.familyName+" "+e.styleName},postScriptName:{en:e.postScriptName||e.familyName+e.styleName},designer:{en:e.designer||" "},designerURL:{en:e.designerURL||" "},manufacturer:{en:e.manufacturer||" "},manufacturerURL:{en:e.manufacturerURL||" "},license:{en:e.license||" "},licenseURL:{en:e.licenseURL||" "},version:{en:e.version||"Version 0.1"},description:{en:e.description||" "},copyright:{en:e.copyright||" "},trademark:{en:e.trademark||" "}},this.unitsPerEm=e.unitsPerEm||1e3,this.ascender=e.ascender,this.descender=e.descender,this.createdTimestamp=e.createdTimestamp,this.tables={os2:{usWeightClass:e.weightClass||this.usWeightClasses.MEDIUM,usWidthClass:e.widthClass||this.usWidthClasses.MEDIUM,fsSelection:e.fsSelection||this.fsSelectionValues.REGULAR}}),this.supported=!0,this.glyphs=new Me.GlyphSet(this,e.glyphs||[]),this.encoding=new ve(this),this.substitution=new Mt(this),this.tables=this.tables||{},Object.defineProperty(this,"hinting",{get:function(){return this._hinting?this._hinting:"truetype"===this.outlinesFormat?this._hinting=new zt(this):void 0}})}function Rn(e,t){const n=JSON.stringify(e);let o=256;for(let e in t){let r=parseInt(e);if(r&&!(r<256)){if(JSON.stringify(t[e])===n)return r;o<=r&&(o=r+1)}}return t[o]=e,o}function Dn(e,t,n){const o=Rn(t.name,n);return[{name:"tag_"+e,type:"TAG",value:t.tag},{name:"minValue_"+e,type:"FIXED",value:t.minValue<<16},{name:"defaultValue_"+e,type:"FIXED",value:t.defaultValue<<16},{name:"maxValue_"+e,type:"FIXED",value:t.maxValue<<16},{name:"flags_"+e,type:"USHORT",value:0},{name:"nameID_"+e,type:"USHORT",value:o}]}function Cn(e,t,n){const o={},r=new pe.Parser(e,t);return o.tag=r.parseTag(),o.minValue=r.parseFixed(),o.defaultValue=r.parseFixed(),o.maxValue=r.parseFixed(),r.skip("uShort",1),o.name=n[r.parseUShort()]||{},o}function Mn(e,t,n,o){const r=[{name:"nameID_"+e,type:"USHORT",value:Rn(t.name,o)},{name:"flags_"+e,type:"USHORT",value:0}];for(let o=0;o2)return;const n=this.font;let o=this._prepState;if(!o||o.ppem!==t){let e=this._fpgmState;if(!e){nn.prototype=tn,e=this._fpgmState=new nn("fpgm",n.tables.fpgm),e.funcs=[],e.font=n,exports.DEBUG&&(console.log("---EXEC FPGM---"),e.step=-1);try{At(e)}catch(e){return console.log("Hinting error in FPGM:"+e),void(this._errorState=3)}}nn.prototype=e,o=this._prepState=new nn("prep",n.tables.prep),o.ppem=t;const r=n.tables.cvt;if(r){const e=o.cvt=new Array(r.length),s=t/n.unitsPerEm;for(let t=0;t1))try{return Ft(e,o)}catch(e){return this._errorState<1&&(console.log("Hinting error:"+e),console.log("Note: further hinting errors are silenced")),void(this._errorState=1)}},Ft=function(e,t){const n=t.ppem/t.font.unitsPerEm,o=n;let r,s,a,i=e.components;if(nn.prototype=t,i){const l=t.font;s=[],r=[];for(let e=0;e1?"loop "+(e.loop-n)+": ":"")+"SHPIX[]",a,r),o.setRelative(i,i,r),o.touch(i)}e.loop=1},function(e){const t=e.stack,n=e.rp1,o=e.rp2;let r=e.loop;const s=e.z0[n],a=e.z1[o],i=e.fv,l=e.dpv,c=e.z2;for(;r--;){const u=t.pop(),p=c[u];exports.DEBUG&&console.log(e.step,(e.loop>1?"loop "+(e.loop-r)+": ":"")+"IP[]",u,n,"<->",o),i.interpolate(p,s,a,l),i.touch(p)}e.loop=1},yn.bind(void 0,0),yn.bind(void 0,1),function(e){const t=e.stack,n=e.rp0,o=e.z0[n];let r=e.loop;const s=e.fv,a=e.pv,i=e.z1;for(;r--;){const n=t.pop(),l=i[n];exports.DEBUG&&console.log(e.step,(e.loop>1?"loop "+(e.loop-r)+": ":"")+"ALIGNRP[]",n),s.setRelative(l,o,0,a),s.touch(l)}e.loop=1},function(e){exports.DEBUG&&console.log(e.step,"RTDG[]"),e.round=qt},vn.bind(void 0,0),vn.bind(void 0,1),function(e){const t=e.prog;let n=e.ip;const o=e.stack,r=t[++n];exports.DEBUG&&console.log(e.step,"NPUSHB[]",r);for(let e=0;en?1:0)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"GTEQ[]",n,o),t.push(o>=n?1:0)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"EQ[]",n,o),t.push(n===o?1:0)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"NEQ[]",n,o),t.push(n!==o?1:0)},function(e){const t=e.stack,n=t.pop();exports.DEBUG&&console.log(e.step,"ODD[]",n),t.push(Math.trunc(n)%2?1:0)},function(e){const t=e.stack,n=t.pop();exports.DEBUG&&console.log(e.step,"EVEN[]",n),t.push(Math.trunc(n)%2?0:1)},function(e){let t=e.stack.pop();exports.DEBUG&&console.log(e.step,"IF[]",t),t||(rn(e,!0),exports.DEBUG&&console.log(e.step,"EIF[]"))},function(e){exports.DEBUG&&console.log(e.step,"EIF[]")},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"AND[]",n,o),t.push(n&&o?1:0)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"OR[]",n,o),t.push(n||o?1:0)},function(e){const t=e.stack,n=t.pop();exports.DEBUG&&console.log(e.step,"NOT[]",n),t.push(n?0:1)},Sn.bind(void 0,1),function(e){const t=e.stack.pop();exports.DEBUG&&console.log(e.step,"SDB[]",t),e.deltaBase=t},function(e){const t=e.stack.pop();exports.DEBUG&&console.log(e.step,"SDS[]",t),e.deltaShift=Math.pow(.5,t)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"ADD[]",n,o),t.push(o+n)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"SUB[]",n,o),t.push(o-n)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"DIV[]",n,o),t.push(64*o/n)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"MUL[]",n,o),t.push(o*n/64)},function(e){const t=e.stack,n=t.pop();exports.DEBUG&&console.log(e.step,"ABS[]",n),t.push(Math.abs(n))},function(e){const t=e.stack;let n=t.pop();exports.DEBUG&&console.log(e.step,"NEG[]",n),t.push(-n)},function(e){const t=e.stack,n=t.pop();exports.DEBUG&&console.log(e.step,"FLOOR[]",n),t.push(64*Math.floor(n/64))},function(e){const t=e.stack,n=t.pop();exports.DEBUG&&console.log(e.step,"CEILING[]",n),t.push(64*Math.ceil(n/64))},Un.bind(void 0,0),Un.bind(void 0,1),Un.bind(void 0,2),Un.bind(void 0,3),void 0,void 0,void 0,void 0,function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"WCVTF[]",n,o),e.cvt[o]=n*e.ppem/e.font.unitsPerEm},Sn.bind(void 0,2),Sn.bind(void 0,3),Tn.bind(void 0,1),Tn.bind(void 0,2),Tn.bind(void 0,3),function(e){let t,n=e.stack.pop();switch(exports.DEBUG&&console.log(e.step,"SROUND[]",n),e.round=Yt,192&n){case 0:t=.5;break;case 64:t=1;break;case 128:t=2;break;default:throw new Error("invalid SROUND value")}switch(e.srPeriod=t,48&n){case 0:e.srPhase=0;break;case 16:e.srPhase=.25*t;break;case 32:e.srPhase=.5*t;break;case 48:e.srPhase=.75*t;break;default:throw new Error("invalid SROUND value")}n&=15,e.srThreshold=0===n?0:(n/8-.5)*t},function(e){let t,n=e.stack.pop();switch(exports.DEBUG&&console.log(e.step,"S45ROUND[]",n),e.round=Yt,192&n){case 0:t=Math.sqrt(2)/2;break;case 64:t=Math.sqrt(2);break;case 128:t=2*Math.sqrt(2);break;default:throw new Error("invalid S45ROUND value")}switch(e.srPeriod=t,48&n){case 0:e.srPhase=0;break;case 16:e.srPhase=.25*t;break;case 32:e.srPhase=.5*t;break;case 48:e.srPhase=.75*t;break;default:throw new Error("invalid S45ROUND value")}n&=15,e.srThreshold=0===n?0:(n/8-.5)*t},void 0,void 0,function(e){exports.DEBUG&&console.log(e.step,"ROFF[]"),e.round=Wt},void 0,function(e){exports.DEBUG&&console.log(e.step,"RUTG[]"),e.round=Vt},function(e){exports.DEBUG&&console.log(e.step,"RDTG[]"),e.round=jt},pn,pn,void 0,void 0,void 0,void 0,void 0,function(e){const t=e.stack.pop();exports.DEBUG&&console.log(e.step,"SCANCTRL[]",t)},wn.bind(void 0,0),wn.bind(void 0,1),function(e){const t=e.stack,n=t.pop();let o=0;exports.DEBUG&&console.log(e.step,"GETINFO[]",n),1&n&&(o=35),32&n&&(o|=4096),t.push(o)},void 0,function(e){const t=e.stack,n=t.pop(),o=t.pop(),r=t.pop();exports.DEBUG&&console.log(e.step,"ROLL[]"),t.push(o),t.push(n),t.push(r)},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"MAX[]",n,o),t.push(Math.max(o,n))},function(e){const t=e.stack,n=t.pop(),o=t.pop();exports.DEBUG&&console.log(e.step,"MIN[]",n,o),t.push(Math.min(o,n))},function(e){const t=e.stack.pop();exports.DEBUG&&console.log(e.step,"SCANTYPE[]",t)},function(e){const t=e.stack.pop();let n=e.stack.pop();switch(exports.DEBUG&&console.log(e.step,"INSTCTRL[]",t,n),t){case 1:return void(e.inhibitGridFit=!!n);case 2:return void(e.ignoreCvt=!!n);default:throw new Error("invalid INSTCTRL[] selector")}},void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,En.bind(void 0,1),En.bind(void 0,2),En.bind(void 0,3),En.bind(void 0,4),En.bind(void 0,5),En.bind(void 0,6),En.bind(void 0,7),En.bind(void 0,8),On.bind(void 0,1),On.bind(void 0,2),On.bind(void 0,3),On.bind(void 0,4),On.bind(void 0,5),On.bind(void 0,6),On.bind(void 0,7),On.bind(void 0,8),Ln.bind(void 0,0,0,0,0,0),Ln.bind(void 0,0,0,0,0,1),Ln.bind(void 0,0,0,0,0,2),Ln.bind(void 0,0,0,0,0,3),Ln.bind(void 0,0,0,0,1,0),Ln.bind(void 0,0,0,0,1,1),Ln.bind(void 0,0,0,0,1,2),Ln.bind(void 0,0,0,0,1,3),Ln.bind(void 0,0,0,1,0,0),Ln.bind(void 0,0,0,1,0,1),Ln.bind(void 0,0,0,1,0,2),Ln.bind(void 0,0,0,1,0,3),Ln.bind(void 0,0,0,1,1,0),Ln.bind(void 0,0,0,1,1,1),Ln.bind(void 0,0,0,1,1,2),Ln.bind(void 0,0,0,1,1,3),Ln.bind(void 0,0,1,0,0,0),Ln.bind(void 0,0,1,0,0,1),Ln.bind(void 0,0,1,0,0,2),Ln.bind(void 0,0,1,0,0,3),Ln.bind(void 0,0,1,0,1,0),Ln.bind(void 0,0,1,0,1,1),Ln.bind(void 0,0,1,0,1,2),Ln.bind(void 0,0,1,0,1,3),Ln.bind(void 0,0,1,1,0,0),Ln.bind(void 0,0,1,1,0,1),Ln.bind(void 0,0,1,1,0,2),Ln.bind(void 0,0,1,1,0,3),Ln.bind(void 0,0,1,1,1,0),Ln.bind(void 0,0,1,1,1,1),Ln.bind(void 0,0,1,1,1,2),Ln.bind(void 0,0,1,1,1,3),Ln.bind(void 0,1,0,0,0,0),Ln.bind(void 0,1,0,0,0,1),Ln.bind(void 0,1,0,0,0,2),Ln.bind(void 0,1,0,0,0,3),Ln.bind(void 0,1,0,0,1,0),Ln.bind(void 0,1,0,0,1,1),Ln.bind(void 0,1,0,0,1,2),Ln.bind(void 0,1,0,0,1,3),Ln.bind(void 0,1,0,1,0,0),Ln.bind(void 0,1,0,1,0,1),Ln.bind(void 0,1,0,1,0,2),Ln.bind(void 0,1,0,1,0,3),Ln.bind(void 0,1,0,1,1,0),Ln.bind(void 0,1,0,1,1,1),Ln.bind(void 0,1,0,1,1,2),Ln.bind(void 0,1,0,1,1,3),Ln.bind(void 0,1,1,0,0,0),Ln.bind(void 0,1,1,0,0,1),Ln.bind(void 0,1,1,0,0,2),Ln.bind(void 0,1,1,0,0,3),Ln.bind(void 0,1,1,0,1,0),Ln.bind(void 0,1,1,0,1,1),Ln.bind(void 0,1,1,0,1,2),Ln.bind(void 0,1,1,0,1,3),Ln.bind(void 0,1,1,1,0,0),Ln.bind(void 0,1,1,1,0,1),Ln.bind(void 0,1,1,1,0,2),Ln.bind(void 0,1,1,1,0,3),Ln.bind(void 0,1,1,1,1,0),Ln.bind(void 0,1,1,1,1,1),Ln.bind(void 0,1,1,1,1,2),Ln.bind(void 0,1,1,1,1,3)],kn.prototype.hasChar=function(e){return null!==this.encoding.charToGlyphIndex(e)},kn.prototype.charToGlyphIndex=function(e){return this.encoding.charToGlyphIndex(e)},kn.prototype.charToGlyph=function(e){const t=this.charToGlyphIndex(e);let n=this.glyphs.get(t);return n||(n=this.glyphs.get(0)),n},kn.prototype.stringToGlyphs=function(e,t){t=t||this.defaultRenderOptions;const n=[];for(let t=0;t>1;e1&&console.warn("Only the first kern subtable is supported."),e.skip("uLong");const n=255&e.parseUShort();if(e.skip("uShort"),0===n){const n=e.parseUShort();e.skip("uShort",3);for(let o=0;o{const t=jn.loadSync(e);$n.font=t,$n.ascender=t.ascender,$n.descender=t.descender}};const Kn=Qn.options,Jn=function(e,t){return Math.round(e+Math.random()*(t-e))};const eo=function(e,t){return{text:(e+t).toString(),equation:e+"+"+t}},to=function(e,t){return{text:(e-t).toString(),equation:e+"-"+t}};function no(e,t,n){return 6*(n=(n+1)%1)<1?e+(t-e)*n*6:2*n<1?t:3*n<2?e+(t-e)*(2/3-n)*6:e}var oo={int:Jn,greyColor:function(e,t){const n=Jn(e=e||1,t=t||9).toString(16);return`#${n}${n}${n}`},captchaText:function(e){"number"==typeof e&&(e={size:e});const t=(e=e||{}).size||4,n=e.ignoreChars||"";let o=-1,r="",s=e.charPreset||Kn.charPreset;n&&(s=function(e,t){return e.split("").filter(e=>-1===t.indexOf(e))}(s,n));const a=s.length-1;for(;++o>16,o=t>>8&255,r=255&t,s=Math.max(n,o,r),a=Math.min(n,o,r);return(s+a)/510}(e):1;let r,s;o>=.5?(r=Math.round(100*o)-45,s=Math.round(100*o)-25):(r=Math.round(100*o)+25,s=Math.round(100*o)+45);const a=Jn(r,s)/100,i=a<.5?a*(a+n):a+n-a*n,l=2*a-i,c=Math.floor(255*no(l,i,t+1/3)),u=Math.floor(255*no(l,i,t));return"#"+(Math.floor(255*no(l,i,t-1/3))|u<<8|c<<16|1<<24).toString(16).slice(1)}};const ro=Qn.options,so=function(e,t){e=e||oo.captchaText();const n=(t=Object.assign({},ro,t)).width,o=t.height,r=t.background||t.backgroundColor;r&&(t.color=!0);const s=r?``:"",a=[].concat(function(e,t,n){const o=n.color,r=[],s=n.inverse?7:1,a=n.inverse?15:9;let i=-1;for(;++i`)}return r}(n,o,t)).concat(function(e,t,n,o,r){const s=e.length,a=(t-2)/(s+1),i=o.inverse?10:0,l=o.inverse?14:4;let u=-1;const p=[],h=r||o.color?oo.color(o.background):oo.greyColor(i,l);for(;++u`)}return p}(e,n,o,t)).sort(()=>Math.random()-.5).join("");return`${``}${s}${a}`};var ao=so,io=oo.captchaText,lo=function(e){const t=e.text||oo.captchaText(e);return{text:t,data:so(t,e)}},co=function(e){const t=oo.mathExpr(e.mathMin,e.mathMax,e.mathOperator);return{text:t.text,data:so(t.equation,e)}},uo=ro,po=Qn.loadFont;ao.randomText=io,ao.create=lo,ao.createMathExpr=co,ao.options=uo,ao.loadFont=po;var ho=ao;var fo=class{constructor(e={}){let{level:t=2,...n}=e;this.width=300,this.height=100;const o=[Math.floor(256*Math.random()),Math.floor(256*Math.random()),Math.floor(256*Math.random())];-1===[1,2,3,4].indexOf(t)&&(t=2);const r={};1===t?Object.assign(r,{lineWidth:5,textColor:o,textLength:4,lineOffset:0,background:[255,250,232],randomLineNum:5},n):2===t?Object.assign(r,{lineWidth:5,textColor:o,textLength:4,lineOffset:0,background:[255,250,232],randomLineNum:10},n):3===t?Object.assign(r,{lineWidth:5,textColor:o,textLength:4,lineOffset:1,background:[255,250,232],randomLineNum:15},n):4===t&&(Object.assign(r,{lineWidth:5,textColor:o,textLength:4,lineOffset:1,background:[255,250,232],randomLineNum:15},n),r.textColor=function(){return[Math.floor(256*Math.random()),Math.floor(256*Math.random()),Math.floor(256*Math.random())]}),this.config=r,this.data=Buffer.alloc(9e4)}setPixel(e,t,n){const o=3*(t*this.width+e);this.data[o]=n.b,this.data[o+1]=n.g,this.data[o+2]=n.r}getFileBuffer(e){const t=54+this.data.length,n=Buffer.alloc(t);return n.write("BM",0),n.writeUInt32LE(t,2),n.writeUInt32LE(0,6),n.writeUInt32LE(54,10),n.writeUInt32LE(40,14),n.writeInt32LE(this.width,18),n.writeInt32LE(-this.height,22),n.writeUInt16LE(1,26),n.writeUInt16LE(24,28),n.writeUInt32LE(0,30),n.writeUInt32LE(this.data.length,34),this.data.copy(n,54),n}setImageBackground(e,t,n){for(let o=0;o=3?Math.floor(11*Math.random())-6:0}getTextOffset(e=0){const t=this.config.textLength,n=Math.round((300-50*t)/2/t);return{x:e*(300/this.config.textLength)+n,y:0}}drawRandomLinesWithVaryingWidth(e){const t=this.width,n=this.height;for(let o=0;o-i&&(u-=i,e+=l),p0){const e=s.data[0];if(e.expired_date{e.scene&&delete e.scene,this.pluginConfig.scene[n]=Object.assign({},t,e[n])})}}}{constructor(){super(),this.DEVICEID2opts={}}mergeConfig(e){const t=yo(this.pluginConfig.scene)?this.pluginConfig.scene[e.scene]:e.scene;return Object.assign({},yo(t)?t:this.pluginConfig,e)}async create(e={}){if(!e.scene)throw new Error("scene验证码场景不可为空");e=this.mergeConfig(e);let{scene:t,expiresDate:n,deviceId:o,clientIP:r,...s}=e;if(o=o||__ctx__.DEVICEID,r=r||__ctx__.CLIENTIP,!o)throw new Error("deviceId不可为空");const a=new To;try{const{text:i,base64:l}=function(e={}){const{uniPlatform:t="",mode:n="svg"}=e;if("svg"===n){let n;n=e.mathExpr?ho.createMathExpr(e):ho.create(e);let o="data:image/svg+xml;utf8,"+n.data.replace(/#/g,"%23");return(!t||["mp-toutiao","h5","web","app","app-plus"].indexOf(t)>-1)&&(o=o.replace(/"/g,"'").replace(//g,"%3E")),{text:n.text,base64:o}}{const t=new fo(JSON.parse(JSON.stringify({...e,textLength:e.size?Number(e.size):void 0,textColor:go(e.color),background:go(e.background)}))),{text:n,base64:o}=t.draw();return{text:n,base64:o}}}(s),c=await a.setVerifyCode({clientIP:r,deviceId:o,code:i,expiresDate:n,scene:t});return c.code>0?{...c,code:10001}:(this.DEVICEID2opts[o]=e,{code:0,msg:"验证码获取成功",captchaBase64:l})}catch(e){return{code:10001,msg:"验证码生成失败:"+e.message}}}async verify({deviceId:e,captcha:t,scene:n}){if(!(e=e||__ctx__.DEVICEID))throw new Error("deviceId不可为空");if(!n)throw new Error("scene验证码场景不可为空");const o=new To;try{const r=await o.verifyCode({deviceId:e,code:t,scene:n});return r.code>0?r:{code:0,msg:"验证码通过"}}catch(e){return{code:10002,msg:"验证码校验失败:"+e.message}}}async refresh(e={}){let{scene:t,expiresDate:n,deviceId:o,...r}=e;if(o=o||__ctx__.DEVICEID,!o)throw new Error("deviceId不可为空");if(!t)throw new Error("scene验证码场景不可为空");const s=await Uo.where(So.command.or([{device_uuid:o,scene:t},{deviceId:o,scene:t}])).orderBy("created_date","desc").limit(1).get();if(s&&s.data&&s.data.length>0){const e=s.data[0];await Uo.doc(e._id).update({state:2}),Object.keys(r).length>0&&(this.DEVICEID2opts[o]=Object.assign({},this.DEVICEID2opts[o],r));let a={};try{a=await this.create(Object.assign({},this.DEVICEID2opts[o],{deviceId:o,scene:t,expiresDate:n}))}catch(e){return{code:50403,msg:e.message}}return a.code>0?{...a,code:50403}:{code:0,msg:"验证码刷新成功",captchaBase64:a.captchaBase64}}return{code:10003,msg:`验证码刷新失败:无此设备在 ${t} 场景信息,请重新获取`}}}const Oo=new To;Object.keys(Oo).forEach(e=>{Eo.prototype[e]=xo(Oo[e])});const Lo=new Eo,ko=new Proxy(Lo,{get(e,t){if(t in e)return"function"==typeof e[t]?xo(e[t]).bind(ko):e[t]}});module.exports=ko; diff --git a/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/package.json b/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/package.json new file mode 100644 index 0000000..6df8de3 --- /dev/null +++ b/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/package.json @@ -0,0 +1,16 @@ +{ + "name": "uni-captcha", + "version": "0.7.0", + "description": "uni-captcha", + "main": "index.js", + "homepage": "https://ext.dcloud.net.cn/plugin?id=4048", + "repository": { + "type": "git", + "url": "git+https://gitee.com/dcloud/uni-captcha" + }, + "author": "DCloud", + "license": "Apache-2.0", + "dependencies": { + "uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } +} \ No newline at end of file diff --git a/uni_modules/uni-captcha/uniCloud/cloudfunctions/uni-captcha-co/config.js b/uni_modules/uni-captcha/uniCloud/cloudfunctions/uni-captcha-co/config.js new file mode 100644 index 0000000..c37b38b --- /dev/null +++ b/uni_modules/uni-captcha/uniCloud/cloudfunctions/uni-captcha-co/config.js @@ -0,0 +1,17 @@ +module.exports = { + "image-captcha":{ + "width": 150, //图片宽度 + "height": 44, //图片高度 + "background": "#FFFAE8", //验证码背景色,设置空字符`''`不使用背景颜色 + // "size": 4, //验证码长度,最多 6 个字符 + // "noise": 4, //验证码干扰线条数 + // "color": false, //字体是否使用随机颜色,当设置`background`后恒为`true` + // "fontSize": 40, //字体大小 + // "ignoreChars": '', //忽略那些字符 + // "mathExpr": false, //是否使用数学表达式 + // "mathMin": 1, //表达式所使用的最小数字 + // "mathMax": 9, //表达式所使用的最大数字 + // "mathOperator": '' //表达式所使用的运算符,支持 `+`、`-`。不传随机使用 + // "expiresDate":180 //验证码过期时间(s) + } +} \ No newline at end of file diff --git a/uni_modules/uni-captcha/uniCloud/cloudfunctions/uni-captcha-co/index.obj.js b/uni_modules/uni-captcha/uniCloud/cloudfunctions/uni-captcha-co/index.obj.js new file mode 100644 index 0000000..186e82c --- /dev/null +++ b/uni_modules/uni-captcha/uniCloud/cloudfunctions/uni-captcha-co/index.obj.js @@ -0,0 +1,35 @@ +// 开发文档: https://uniapp.dcloud.net.cn/uniCloud/cloud-obj +//导入验证码公共模块 +const uniCaptcha = require('uni-captcha') +//获取数据库对象 +const db = uniCloud.database(); +//获取数据表opendb-verify-codes对象 +const verifyCodes = db.collection('opendb-verify-codes') +module.exports = { + async getImageCaptcha({ + scene,isUniAppX + }) { + //获取设备id + let { + deviceId, + platform + } = this.getClientInfo(); + //根据:设备id、场景值、状态,查找记录是否存在 + let res = await verifyCodes.where({ + scene, + deviceId, + state: 0 + }).limit(1).get() + //如果已存在则调用刷新接口,反之调用插件接口 + let action = res.data.length ? 'refresh' : 'create' + //执行并返回结果 + let option = { + scene, //来源客户端传递,表示:使用场景值,用于防止不同功能的验证码混用 + uniPlatform: platform + } + if(isUniAppX){ + option.mode = "bmp" + } + return await uniCaptcha[action](option) + } +} \ No newline at end of file diff --git a/uni_modules/uni-captcha/uniCloud/cloudfunctions/uni-captcha-co/package.json b/uni_modules/uni-captcha/uniCloud/cloudfunctions/uni-captcha-co/package.json new file mode 100644 index 0000000..b5188c3 --- /dev/null +++ b/uni_modules/uni-captcha/uniCloud/cloudfunctions/uni-captcha-co/package.json @@ -0,0 +1,10 @@ +{ + "name": "uni-captcha-co", + "dependencies": { + "uni-captcha": "file:../common/uni-captcha", + "uni-config-center": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + }, + "extensions": { + "uni-cloud-jql": {} + } +} \ No newline at end of file diff --git a/uni_modules/uni-card/changelog.md b/uni_modules/uni-card/changelog.md new file mode 100644 index 0000000..c3cd8c4 --- /dev/null +++ b/uni_modules/uni-card/changelog.md @@ -0,0 +1,26 @@ +## 1.3.1(2021-12-20) +- 修复 在vue页面下略缩图显示不正常的bug +## 1.3.0(2021-11-19) +- 重构插槽的用法 ,header 替换为 title +- 新增 actions 插槽 +- 新增 cover 封面图属性和插槽 +- 新增 padding 内容默认内边距离 +- 新增 margin 卡片默认外边距离 +- 新增 spacing 卡片默认内边距 +- 新增 shadow 卡片阴影属性 +- 取消 mode 属性,可使用组合插槽代替 +- 取消 note 属性 ,使用actions插槽代替 +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-card](https://uniapp.dcloud.io/component/uniui/uni-card) +## 1.2.1(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.2.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.8(2021-07-01) +- 优化 图文卡片无图片加载时,提供占位图标 +- 新增 header 插槽,自定义卡片头部( 图文卡片 mode="style" 时,不支持) +- 修复 thumbnail 不存在仍然占位的 bug +## 1.1.7(2021-05-12) +- 新增 组件示例地址 +## 1.1.6(2021-02-04) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-card/components/uni-card/uni-card.vue b/uni_modules/uni-card/components/uni-card/uni-card.vue new file mode 100644 index 0000000..38cf594 --- /dev/null +++ b/uni_modules/uni-card/components/uni-card/uni-card.vue @@ -0,0 +1,270 @@ + + + + + diff --git a/uni_modules/uni-card/package.json b/uni_modules/uni-card/package.json new file mode 100644 index 0000000..f16224d --- /dev/null +++ b/uni_modules/uni-card/package.json @@ -0,0 +1,90 @@ +{ + "id": "uni-card", + "displayName": "uni-card 卡片", + "version": "1.3.1", + "description": "Card 组件,提供常见的卡片样式。", + "keywords": [ + "uni-ui", + "uniui", + "card", + "", + "卡片" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": [ + "uni-icons", + "uni-scss" + ], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-card/readme.md b/uni_modules/uni-card/readme.md new file mode 100644 index 0000000..7434e71 --- /dev/null +++ b/uni_modules/uni-card/readme.md @@ -0,0 +1,12 @@ + + +## Card 卡片 +> **组件名:uni-card** +> 代码块: `uCard` + +卡片视图组件。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-card) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-cloud-s2s/changelog.md b/uni_modules/uni-cloud-s2s/changelog.md new file mode 100644 index 0000000..727d5b2 --- /dev/null +++ b/uni_modules/uni-cloud-s2s/changelog.md @@ -0,0 +1,2 @@ +## 1.0.1(2023-03-02) +- 修复 方法名错误 diff --git a/uni_modules/uni-cloud-s2s/package.json b/uni_modules/uni-cloud-s2s/package.json new file mode 100644 index 0000000..339d219 --- /dev/null +++ b/uni_modules/uni-cloud-s2s/package.json @@ -0,0 +1,83 @@ +{ + "id": "uni-cloud-s2s", + "displayName": "服务空间与服务器安全通讯模块", + "version": "1.0.1", + "description": "用于解决服务空间与服务器通讯时互相信任问题", + "keywords": [ + "安全通讯", + "服务器请求云函数", + "云函数请求服务器" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "type": "unicloud-template-function", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "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", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-cloud-s2s/readme.md b/uni_modules/uni-cloud-s2s/readme.md new file mode 100644 index 0000000..3c8ed0c --- /dev/null +++ b/uni_modules/uni-cloud-s2s/readme.md @@ -0,0 +1,3 @@ +# uni-cloud-s2s + +文档见:[外部服务器如何与uniCloud安全通讯](https://uniapp.dcloud.net.cn/uniCloud/uni-cloud-s2s.html) \ No newline at end of file diff --git a/uni_modules/uni-cloud-s2s/uniCloud/cloudfunctions/common/uni-cloud-s2s/index.js b/uni_modules/uni-cloud-s2s/uniCloud/cloudfunctions/common/uni-cloud-s2s/index.js new file mode 100644 index 0000000..da9a36c --- /dev/null +++ b/uni_modules/uni-cloud-s2s/uniCloud/cloudfunctions/common/uni-cloud-s2s/index.js @@ -0,0 +1 @@ +"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("crypto"),t=require("path");function s(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}require("fs");var o=s(e),n=s(t);const i="uni-cloud-s2s",r={code:5e4,message:"Config error"},c={code:51e3,message:"Access denied"};class a extends Error{constructor(e){super(e.message),this.errMsg=e.message||"",this.code=this.errCode=e.code,this.errSubject=e.subject,this.forceReturn=e.forceReturn||!1,this.cause=e.cause,Object.defineProperties(this,{message:{get(){return this.errMsg},set(e){this.errMsg=e}}})}toJSON(e=0){if(!(e>=10))return e++,{errCode:this.errCode,errMsg:this.errMsg,errSubject:this.errSubject,cause:this.cause&&this.cause.toJSON?this.cause.toJSON(e):this.cause}}}const d=Object.prototype.toString;const h=50002,u=Object.create(null);["string","boolean","number","null"].forEach((e=>{u[e]=function(t,s){if(function(e){return d.call(e).slice(8,-1).toLowerCase()}(t)!==e)return{code:h,message:`${s} is invalid`}}}));const f="Unicloud-S2s-Authorization";class g{constructor(e){const{config:t}=e||{};this.config=t;const{connectCode:s}=t||{};if(this.connectCode=s,!s||"string"!=typeof s)throw new a({subject:i,code:r.code,message:"Invalid connectCode in config"})}getHeadersValue(e={},t,s){const o=Object.keys(e||{}).find((e=>e.toLowerCase()===t.toLowerCase()));return o?e[o]:s}verifyHttpInfo(e){const t=this.getHeadersValue(e.headers,f,""),[s="",o=""]=t.split(" ");if(s.toLowerCase()==="CONNECTCODE".toLowerCase()&&o===this.config.connectCode)return!0;throw new a({subject:i,code:c.code,message:`Invalid CONNECTCODE in headers['${f}']`})}getSecureHeaders(e){return{[f]:`CONNECTCODE ${this.config.connectCode}`}}}function l(e){return function(t){const{content:s,signKey:n}=t||{};return o.default.createHash(e).update(s+"\n"+n).digest("hex")}}const p={md5:l("md5"),sha1:l("sha1"),sha256:l("md5"),"hmac-sha256":function(e){const{content:t,signKey:s}=e||{};return o.default.createHmac("sha256",s).update(t).digest("hex")}};function m(e){const{timestamp:t,data:s={},signKey:o,hashMethod:n="hmac-sha256"}=e||{},i=p[n],r=["number","string","boolean"],c=Object.keys(s).sort(),a=[];for(let e=0;ee.toLowerCase()===t.toLowerCase()));return o?e[o]:s}getHttpData(e){const t=e.httpMethod.toLowerCase(),s=this.getHttpHeaders(e),o=this.getHeadersValue(s,"Content-Type","");if("get"===t)return e.queryStringParameters;if("post"!==t)throw new a({subject:i,code:c.code,message:`Invalid http method, expected "POST" or "get", got "${t}"`});if(0===o.indexOf("application/json"))return JSON.parse(e.body);if(0===o.indexOf("application/x-www-form-urlencoded"))return require("querystring").parse(e.body);throw new a({subject:i,code:c.code,message:`Invalid content type of POST method, expected "application/json" or "application/x-www-form-urlencoded", got "${o}"`})}verifyHttpInfo(e){const t=e.headers||{},s=this.getHeadersValue(t,"Unicloud-S2s-Timestamp","0");let[o,n]=this.getHeadersValue(t,"Unicloud-S2s-Signature","").split(" ");if(o=o.toLowerCase(),o!==this.hashMethod)throw new a({subject:i,code:c.code,message:`Invalid hash method, expected "${this.hashMethod}", got "${o}"`});const r=parseInt(s),d=Date.now();if(Math.abs(d-r)>1e3*this.timeDiffTolerance)throw new a({subject:i,code:c.code,message:`Invalid timestamp, server timestamp is ${d}, ${r} exceed max timeDiffTolerance(${this.timeDiffTolerance} seconds)`});return m({timestamp:r,data:this.getHttpData(e),signKey:this.signKey,hashMethod:this.hashMethod})===n}getSecureHeaders(e){const{data:t}=e||{},s=Date.now(),o=m({timestamp:s,data:t,signKey:this.signKey,hashMethod:this.hashMethod});return{"Unicloud-S2s-Timestamp":s+"","Unicloud-S2s-Signature":this.hashMethod+" "+o}}}const y=require("uni-config-center")({pluginId:i});class b{constructor(){this.config=y.config();const e=n.default.resolve(require.resolve("uni-config-center"),i,"config.json");if(!this.config)throw new a({subject:i,code:r.code,message:`${i} config required, please check your config file: ${e}`});if("connectCode"===this.config.type)this.verifier=new g({config:this.config});else{if(!function(e){return"sign"===e.type}(this.config))throw new a({subject:i,code:r.code,message:`Invalid ${i} config, expected policy is "code" or "sign", got ${this.config.policy}`});this.verifier=new w({config:this.config})}}verifyHttpInfo(e){if(!e)throw new a({subject:i,code:c.code,message:"Access denied, httpInfo required"});return this.verifier.verifyHttpInfo(e)}getSecureHeaders(e){return this.verifier.getSecureHeaders(e)}}exports.getSecureHeaders=function(e){return(new b).getSecureHeaders(e)},exports.verifyHttpInfo=function(e){const t=(new b).verifyHttpInfo(e);if(!t)throw new a({subject:i,code:c.code,message:c.message});return t}; diff --git a/uni_modules/uni-cloud-s2s/uniCloud/cloudfunctions/common/uni-cloud-s2s/package.json b/uni_modules/uni-cloud-s2s/uniCloud/cloudfunctions/common/uni-cloud-s2s/package.json new file mode 100644 index 0000000..e99f52c --- /dev/null +++ b/uni_modules/uni-cloud-s2s/uniCloud/cloudfunctions/common/uni-cloud-s2s/package.json @@ -0,0 +1,11 @@ +{ + "name": "uni-cloud-s2s", + "version": "1.0.1", + "description": "", + "keywords": [], + "author": "DCloud", + "main": "index.js", + "dependencies": { + "uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } +} \ No newline at end of file diff --git a/uni_modules/uni-collapse/changelog.md b/uni_modules/uni-collapse/changelog.md new file mode 100644 index 0000000..292e4c7 --- /dev/null +++ b/uni_modules/uni-collapse/changelog.md @@ -0,0 +1,36 @@ +## 1.4.3(2022-01-25) +- 修复 初始化的时候 ,open 属性失效的bug +## 1.4.2(2022-01-21) +- 修复 微信小程序resize后组件收起的bug +## 1.4.1(2021-11-22) +- 修复 vue3中个别scss变量无法找到的问题 +## 1.4.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-collapse](https://uniapp.dcloud.io/component/uniui/uni-collapse) +## 1.3.3(2021-08-17) +- 优化 show-arrow 属性默认为true +## 1.3.2(2021-08-17) +- 新增 show-arrow 属性,控制是否显示右侧箭头 +## 1.3.1(2021-07-30) +- 优化 vue3下小程序事件警告的问题 +## 1.3.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.2.2(2021-07-21) +- 修复 由1.2.0版本引起的 change 事件返回 undefined 的Bug +## 1.2.1(2021-07-21) +- 优化 组件示例 +## 1.2.0(2021-07-21) +- 新增 组件折叠动画 +- 新增 value\v-model 属性 ,动态修改面板折叠状态 +- 新增 title 插槽 ,可定义面板标题 +- 新增 border 属性 ,显示隐藏面板内容分隔线 +- 新增 title-border 属性 ,显示隐藏面板标题分隔线 +- 修复 resize 方法失效的Bug +- 修复 change 事件返回参数不正确的Bug +- 优化 H5、App 平台自动更具内容更新高度,无需调用 reszie() 方法 +## 1.1.7(2021-05-12) +- 新增 组件示例地址 +## 1.1.6(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 +## 1.1.5(2021-02-05) +- 调整为uni_modules目录规范 \ No newline at end of file diff --git a/uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue b/uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue new file mode 100644 index 0000000..d62a6a7 --- /dev/null +++ b/uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue @@ -0,0 +1,402 @@ + + + + + diff --git a/uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue b/uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue new file mode 100644 index 0000000..384c39a --- /dev/null +++ b/uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue @@ -0,0 +1,147 @@ + + + diff --git a/uni_modules/uni-collapse/package.json b/uni_modules/uni-collapse/package.json new file mode 100644 index 0000000..65349cf --- /dev/null +++ b/uni_modules/uni-collapse/package.json @@ -0,0 +1,89 @@ +{ + "id": "uni-collapse", + "displayName": "uni-collapse 折叠面板", + "version": "1.4.3", + "description": "Collapse 组件,可以折叠 / 展开的内容区域。", + "keywords": [ + "uni-ui", + "折叠", + "折叠面板", + "手风琴" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-icons" + ], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-collapse/readme.md b/uni_modules/uni-collapse/readme.md new file mode 100644 index 0000000..bc758eb --- /dev/null +++ b/uni_modules/uni-collapse/readme.md @@ -0,0 +1,12 @@ + + +## Collapse 折叠面板 +> **组件名:uni-collapse** +> 代码块: `uCollapse` +> 关联组件:`uni-collapse-item`、`uni-icons`。 + + +折叠面板用来折叠/显示过长的内容或者是列表。通常是在多内容分类项使用,折叠不重要的内容,显示重要内容。点击可以展开折叠部分。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-collapse) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-combox/changelog.md b/uni_modules/uni-combox/changelog.md new file mode 100644 index 0000000..23c2748 --- /dev/null +++ b/uni_modules/uni-combox/changelog.md @@ -0,0 +1,15 @@ +## 1.0.1(2021-11-23) +- 优化 label、label-width 属性 +## 1.0.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-combox](https://uniapp.dcloud.io/component/uniui/uni-combox) +## 0.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 0.0.6(2021-05-12) +- 新增 组件示例地址 +## 0.0.5(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 0.0.4(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 +## 0.0.3(2021-02-04) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-combox/components/uni-combox/uni-combox.vue b/uni_modules/uni-combox/components/uni-combox/uni-combox.vue new file mode 100644 index 0000000..d4cb79d --- /dev/null +++ b/uni_modules/uni-combox/components/uni-combox/uni-combox.vue @@ -0,0 +1,275 @@ + + + + + diff --git a/uni_modules/uni-combox/package.json b/uni_modules/uni-combox/package.json new file mode 100644 index 0000000..4a05c3f --- /dev/null +++ b/uni_modules/uni-combox/package.json @@ -0,0 +1,90 @@ +{ + "id": "uni-combox", + "displayName": "uni-combox 组合框", + "version": "1.0.1", + "description": "可以选择也可以输入的表单项 ", + "keywords": [ + "uni-ui", + "uniui", + "combox", + "组合框", + "select" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "n" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-combox/readme.md b/uni_modules/uni-combox/readme.md new file mode 100644 index 0000000..ffa2cc8 --- /dev/null +++ b/uni_modules/uni-combox/readme.md @@ -0,0 +1,11 @@ + + +## Combox 组合框 +> **组件名:uni-combox** +> 代码块: `uCombox` + + +组合框组件。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-combox) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file 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 + + {{ d }} + {{dayText}} + {{ h }} + {{ showColon ? ':' : hourText }} + {{ i }} + {{ showColon ? ':' : minuteText }} + {{ s }} + {{secondText}} + + + + diff --git a/uni_modules/uni-countdown/package.json b/uni_modules/uni-countdown/package.json new file mode 100644 index 0000000..70e99ee --- /dev/null +++ b/uni_modules/uni-countdown/package.json @@ -0,0 +1,86 @@ +{ + "id": "uni-countdown", + "displayName": "uni-countdown 倒计时", + "version": "1.2.2", + "description": "CountDown 倒计时组件", + "keywords": [ + "uni-ui", + "uniui", + "countdown", + "倒计时" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-countdown/readme.md b/uni_modules/uni-countdown/readme.md new file mode 100644 index 0000000..4bcb1aa --- /dev/null +++ b/uni_modules/uni-countdown/readme.md @@ -0,0 +1,10 @@ + + +## CountDown 倒计时 +> **组件名:uni-countdown** +> 代码块: `uCountDown` + +倒计时组件。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-countdown) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-data-checkbox/changelog.md b/uni_modules/uni-data-checkbox/changelog.md new file mode 100644 index 0000000..b475fcb --- /dev/null +++ b/uni_modules/uni-data-checkbox/changelog.md @@ -0,0 +1,49 @@ +## 1.0.5(2024-03-20) +- 修复 单选模式下选中样式不生效的bug +## 1.0.4(2024-01-27) +- 修复 修复错别字chagne为change +## 1.0.3(2022-09-16) +- 可以使用 uni-scss 控制主题色 +## 1.0.2(2022-06-30) +- 优化 在 uni-forms 中的依赖注入方式 +## 1.0.1(2022-02-07) +- 修复 multiple 为 true 时,v-model 的值为 null 报错的 bug +## 1.0.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-checkbox](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox) +## 0.2.5(2021-08-23) +- 修复 在uni-forms中 modelValue 中不存在当前字段,当前字段必填写也不参与校验的问题 +## 0.2.4(2021-08-17) +- 修复 单选 list 模式下 ,icon 为 left 时,选中图标不显示的问题 +## 0.2.3(2021-08-11) +- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题 +## 0.2.2(2021-07-30) +- 优化 在uni-forms组件,与label不对齐的问题 +## 0.2.1(2021-07-27) +- 修复 单选默认值为0不能选中的Bug +## 0.2.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 0.1.11(2021-07-06) +- 优化 删除无用日志 +## 0.1.10(2021-07-05) +- 修复 由 0.1.9 引起的非 nvue 端图标不显示的问题 +## 0.1.9(2021-07-05) +- 修复 nvue 黑框样式问题 +## 0.1.8(2021-06-28) +- 修复 selectedTextColor 属性不生效的Bug +## 0.1.7(2021-06-02) +- 新增 map 属性,可以方便映射text/value属性 +## 0.1.6(2021-05-26) +- 修复 不关联服务空间的情况下组件报错的Bug +## 0.1.5(2021-05-12) +- 新增 组件示例地址 +## 0.1.4(2021-04-09) +- 修复 nvue 下无法选中的问题 +## 0.1.3(2021-03-22) +- 新增 disabled属性 +## 0.1.2(2021-02-24) +- 优化 默认颜色显示 +## 0.1.1(2021-02-24) +- 新增 支持nvue +## 0.1.0(2021-02-18) +- “暂无数据”显示居中 diff --git a/uni_modules/uni-data-checkbox/components/uni-data-checkbox/clientdb.js b/uni_modules/uni-data-checkbox/components/uni-data-checkbox/clientdb.js new file mode 100644 index 0000000..ff7501b --- /dev/null +++ b/uni_modules/uni-data-checkbox/components/uni-data-checkbox/clientdb.js @@ -0,0 +1,316 @@ + +const events = { + load: 'load', + error: 'error' +} +const pageMode = { + add: 'add', + replace: 'replace' +} + +const attrs = [ + 'pageCurrent', + 'pageSize', + 'collection', + 'action', + 'field', + 'getcount', + 'orderby', + 'where' +] + +export default { + data() { + return { + loading: false, + listData: this.getone ? {} : [], + paginationInternal: { + current: this.pageCurrent, + size: this.pageSize, + count: 0 + }, + errorMessage: '' + } + }, + created() { + let db = null; + let dbCmd = null; + + if(this.collection){ + this.db = uniCloud.database(); + this.dbCmd = this.db.command; + } + + this._isEnded = false + + this.$watch(() => { + var al = [] + attrs.forEach(key => { + al.push(this[key]) + }) + return al + }, (newValue, oldValue) => { + this.paginationInternal.pageSize = this.pageSize + + let needReset = false + for (let i = 2; i < newValue.length; i++) { + if (newValue[i] != oldValue[i]) { + needReset = true + break + } + } + if (needReset) { + this.clear() + this.reset() + } + if (newValue[0] != oldValue[0]) { + this.paginationInternal.current = this.pageCurrent + } + + this._execLoadData() + }) + + // #ifdef H5 + if (process.env.NODE_ENV === 'development') { + this._debugDataList = [] + if (!window.unidev) { + window.unidev = { + clientDB: { + data: [] + } + } + } + unidev.clientDB.data.push(this._debugDataList) + } + // #endif + + // #ifdef MP-TOUTIAO + let changeName + let events = this.$scope.dataset.eventOpts + for (var i = 0; i < events.length; i++) { + let event = events[i] + if (event[0].includes('^load')) { + changeName = event[1][0][0] + } + } + if (changeName) { + let parent = this.$parent + let maxDepth = 16 + this._changeDataFunction = null + while (parent && maxDepth > 0) { + let fun = parent[changeName] + if (fun && typeof fun === 'function') { + this._changeDataFunction = fun + maxDepth = 0 + break + } + parent = parent.$parent + maxDepth--; + } + } + // #endif + + // if (!this.manual) { + // this.loadData() + // } + }, + // #ifdef H5 + beforeDestroy() { + if (process.env.NODE_ENV === 'development' && window.unidev) { + var cd = this._debugDataList + var dl = unidev.clientDB.data + for (var i = dl.length - 1; i >= 0; i--) { + if (dl[i] === cd) { + dl.splice(i, 1) + break + } + } + } + }, + // #endif + methods: { + loadData(args1, args2) { + let callback = null + if (typeof args1 === 'object') { + if (args1.clear) { + this.clear() + this.reset() + } + if (args1.current !== undefined) { + this.paginationInternal.current = args1.current + } + if (typeof args2 === 'function') { + callback = args2 + } + } else if (typeof args1 === 'function') { + callback = args1 + } + + this._execLoadData(callback) + }, + loadMore() { + if (this._isEnded) { + return + } + this._execLoadData() + }, + refresh() { + this.clear() + this._execLoadData() + }, + clear() { + this._isEnded = false + this.listData = [] + }, + reset() { + this.paginationInternal.current = 1 + }, + remove(id, { + action, + callback, + confirmTitle, + confirmContent + } = {}) { + if (!id || !id.length) { + return + } + uni.showModal({ + title: confirmTitle || '提示', + content: confirmContent || '是否删除该数据', + showCancel: true, + success: (res) => { + if (!res.confirm) { + return + } + this._execRemove(id, action, callback) + } + }) + }, + _execLoadData(callback) { + if (this.loading) { + return + } + this.loading = true + this.errorMessage = '' + + this._getExec().then((res) => { + this.loading = false + const { + data, + count + } = res.result + this._isEnded = data.length < this.pageSize + + callback && callback(data, this._isEnded) + this._dispatchEvent(events.load, data) + + if (this.getone) { + this.listData = data.length ? data[0] : undefined + } else if (this.pageData === pageMode.add) { + this.listData.push(...data) + if (this.listData.length) { + this.paginationInternal.current++ + } + } else if (this.pageData === pageMode.replace) { + this.listData = data + this.paginationInternal.count = count + } + + // #ifdef H5 + if (process.env.NODE_ENV === 'development') { + this._debugDataList.length = 0 + this._debugDataList.push(...JSON.parse(JSON.stringify(this.listData))) + } + // #endif + }).catch((err) => { + this.loading = false + this.errorMessage = err + callback && callback() + this.$emit(events.error, err) + }) + }, + _getExec() { + let exec = this.db + if (this.action) { + exec = exec.action(this.action) + } + + exec = exec.collection(this.collection) + + if (!(!this.where || !Object.keys(this.where).length)) { + exec = exec.where(this.where) + } + if (this.field) { + exec = exec.field(this.field) + } + if (this.orderby) { + exec = exec.orderBy(this.orderby) + } + + const { + current, + size + } = this.paginationInternal + exec = exec.skip(size * (current - 1)).limit(size).get({ + getCount: this.getcount + }) + + return exec + }, + _execRemove(id, action, callback) { + if (!this.collection || !id) { + return + } + + const ids = Array.isArray(id) ? id : [id] + if (!ids.length) { + return + } + + uni.showLoading({ + mask: true + }) + + let exec = this.db + if (action) { + exec = exec.action(action) + } + + exec.collection(this.collection).where({ + _id: dbCmd.in(ids) + }).remove().then((res) => { + callback && callback(res.result) + if (this.pageData === pageMode.replace) { + this.refresh() + } else { + this.removeData(ids) + } + }).catch((err) => { + uni.showModal({ + content: err.message, + showCancel: false + }) + }).finally(() => { + uni.hideLoading() + }) + }, + removeData(ids) { + let il = ids.slice(0) + let dl = this.listData + for (let i = dl.length - 1; i >= 0; i--) { + let index = il.indexOf(dl[i]._id) + if (index >= 0) { + dl.splice(i, 1) + il.splice(index, 1) + } + } + }, + _dispatchEvent(type, data) { + if (this._changeDataFunction) { + this._changeDataFunction(data, this._isEnded) + } else { + this.$emit(type, data, this._isEnded) + } + } + } +} diff --git a/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue b/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue new file mode 100644 index 0000000..81d3f07 --- /dev/null +++ b/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue @@ -0,0 +1,849 @@ + + + + + diff --git a/uni_modules/uni-data-checkbox/package.json b/uni_modules/uni-data-checkbox/package.json new file mode 100644 index 0000000..fc15e8b --- /dev/null +++ b/uni_modules/uni-data-checkbox/package.json @@ -0,0 +1,84 @@ +{ + "id": "uni-data-checkbox", + "displayName": "uni-data-checkbox 数据选择器", + "version": "1.0.5", + "description": "通过数据驱动的单选框和复选框", + "keywords": [ + "uni-ui", + "checkbox", + "单选", + "多选", + "单选多选" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.1.1" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-load-more","uni-scss"], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-data-checkbox/readme.md b/uni_modules/uni-data-checkbox/readme.md new file mode 100644 index 0000000..6eb253d --- /dev/null +++ b/uni_modules/uni-data-checkbox/readme.md @@ -0,0 +1,18 @@ + + +## DataCheckbox 数据驱动的单选复选框 +> **组件名:uni-data-checkbox** +> 代码块: `uDataCheckbox` + + +本组件是基于uni-app基础组件checkbox的封装。本组件要解决问题包括: + +1. 数据绑定型组件:给本组件绑定一个data,会自动渲染一组候选内容。再以往,开发者需要编写不少代码实现类似功能 +2. 自动的表单校验:组件绑定了data,且符合[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)组件的表单校验规范,搭配使用会自动实现表单校验 +3. 本组件合并了单选多选 +4. 本组件有若干风格选择,如普通的单选多选框、并列button风格、tag风格。开发者可以快速选择需要的风格。但作为一个封装组件,样式代码虽然不用自己写了,却会牺牲一定的样式自定义性 + +在uniCloud开发中,`DB Schema`中配置了enum枚举等类型后,在web控制台的[自动生成表单](https://uniapp.dcloud.io/uniCloud/schema?id=autocode)功能中,会自动生成``uni-data-checkbox``组件并绑定好data + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-data-picker/changelog.md b/uni_modules/uni-data-picker/changelog.md new file mode 100644 index 0000000..8aaad24 --- /dev/null +++ b/uni_modules/uni-data-picker/changelog.md @@ -0,0 +1,77 @@ +## 2.0.0(2023-12-14) +- 新增 支持 uni-app-x +## 1.1.2(2023-04-11) +- 修复 更改 modelValue 报错的 bug +- 修复 v-for 未使用 key 值控制台 warning +## 1.1.1(2023-02-21) +- 修复代码合并时引发 value 属性为空时不渲染数据的问题 +## 1.1.0(2023-02-15) +- 修复 localdata 不支持动态更新的bug +## 1.0.9(2023-02-15) +- 修复 localdata 不支持动态更新的bug +## 1.0.8(2022-09-16) +- 可以使用 uni-scss 控制主题色 +## 1.0.7(2022-07-06) +- 优化 pc端图标位置不正确的问题 +## 1.0.6(2022-07-05) +- 优化 显示样式 +## 1.0.5(2022-07-04) +- 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug +## 1.0.4(2022-04-19) +- 修复 字节小程序 本地数据无法选择下一级的Bug +## 1.0.3(2022-02-25) +- 修复 nvue 不支持的 v-show 的 bug +## 1.0.2(2022-02-25) +- 修复 条件编译 nvue 不支持的 css 样式 +## 1.0.1(2021-11-23) +- 修复 由上个版本引发的map、v-model等属性不生效的bug +## 1.0.0(2021-11-19) +- 优化 组件 UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-picker](https://uniapp.dcloud.io/component/uniui/uni-data-picker) +## 0.4.9(2021-10-28) +- 修复 VUE2 v-model 概率无效的 bug +## 0.4.8(2021-10-27) +- 修复 v-model 概率无效的 bug +## 0.4.7(2021-10-25) +- 新增 属性 spaceInfo 服务空间配置 HBuilderX 3.2.11+ +- 修复 树型 uniCloud 数据类型为 int 时报错的 bug +## 0.4.6(2021-10-19) +- 修复 非 VUE3 v-model 为 0 时无法选中的 bug +## 0.4.5(2021-09-26) +- 新增 清除已选项的功能(通过 clearIcon 属性配置是否显示按钮),同时提供 clear 方法以供调用,二者等效 +- 修复 readonly 为 true 时报错的 bug +## 0.4.4(2021-09-26) +- 修复 上一版本造成的 map 属性失效的 bug +- 新增 ellipsis 属性,支持配置 tab 选项长度过长时是否自动省略 +## 0.4.3(2021-09-24) +- 修复 某些情况下级联未触发的 bug +## 0.4.2(2021-09-23) +- 新增 提供 show 和 hide 方法,开发者可以通过 ref 调用 +- 新增 选项内容过长自动添加省略号 +## 0.4.1(2021-09-15) +- 新增 map 属性 字段映射,将 text/value 映射到数据中的其他字段 +## 0.4.0(2021-07-13) +- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 0.3.5(2021-06-04) +- 修复 无法加载云端数据的问题 +## 0.3.4(2021-05-28) +- 修复 v-model 无效问题 +- 修复 loaddata 为空数据组时加载时间过长问题 +- 修复 上个版本引出的本地数据无法选择带有 children 的 2 级节点 +## 0.3.3(2021-05-12) +- 新增 组件示例地址 +## 0.3.2(2021-04-22) +- 修复 非树形数据有 where 属性查询报错的问题 +## 0.3.1(2021-04-15) +- 修复 本地数据概率无法回显时问题 +## 0.3.0(2021-04-07) +- 新增 支持云端非树形表结构数据 +- 修复 根节点 parent_field 字段等于 null 时选择界面错乱问题 +## 0.2.0(2021-03-15) +- 修复 nodeclick、popupopened、popupclosed 事件无法触发的问题 +## 0.1.9(2021-03-09) +- 修复 微信小程序某些情况下无法选择的问题 +## 0.1.8(2021-02-05) +- 优化 部分样式在 nvue 上的兼容表现 +## 0.1.7(2021-02-05) +- 调整为 uni_modules 目录规范 diff --git a/uni_modules/uni-data-picker/components/uni-data-picker/config.json b/uni_modules/uni-data-picker/components/uni-data-picker/config.json new file mode 100644 index 0000000..dc6b403 --- /dev/null +++ b/uni_modules/uni-data-picker/components/uni-data-picker/config.json @@ -0,0 +1,12 @@ +{ + "id": "3796", + "name": "DataPicker", + "desc": "数据驱动的picker选择器", + "url": "data-picker", + "type": "表单组件", + "edition": "0.0.8", + "suffix": "vue", + "module": ["uni-data-picker","uni-data-pickerview","uni-load-more"], + "path": "https://ext.dcloud.net.cn/plugin?id=3796", + "update_log": ["- 优化 增加下拉箭头"] +} diff --git a/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js b/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js new file mode 100644 index 0000000..6ef26a2 --- /dev/null +++ b/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js @@ -0,0 +1,45 @@ +// #ifdef H5 +export default { + name: 'Keypress', + props: { + disable: { + type: Boolean, + default: false + } + }, + mounted () { + const keyNames = { + esc: ['Esc', 'Escape'], + tab: 'Tab', + enter: 'Enter', + space: [' ', 'Spacebar'], + up: ['Up', 'ArrowUp'], + left: ['Left', 'ArrowLeft'], + right: ['Right', 'ArrowRight'], + down: ['Down', 'ArrowDown'], + delete: ['Backspace', 'Delete', 'Del'] + } + const listener = ($event) => { + if (this.disable) { + return + } + const keyName = Object.keys(keyNames).find(key => { + const keyName = $event.key + const value = keyNames[key] + return value === keyName || (Array.isArray(value) && value.includes(keyName)) + }) + if (keyName) { + // 避免和其他按键事件冲突 + setTimeout(() => { + this.$emit(keyName, {}) + }, 0) + } + } + document.addEventListener('keyup', listener) + this.$once('hook:beforeDestroy', () => { + document.removeEventListener('keyup', listener) + }) + }, + render: () => {} +} +// #endif diff --git a/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.uvue b/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.uvue new file mode 100644 index 0000000..82031e1 --- /dev/null +++ b/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.uvue @@ -0,0 +1,380 @@ + + + + + diff --git a/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue b/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue new file mode 100644 index 0000000..179a4e0 --- /dev/null +++ b/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue @@ -0,0 +1,551 @@ + + + + + diff --git a/uni_modules/uni-data-picker/components/uni-data-pickerview/loading.uts b/uni_modules/uni-data-picker/components/uni-data-pickerview/loading.uts new file mode 100644 index 0000000..baa0dff --- /dev/null +++ b/uni_modules/uni-data-picker/components/uni-data-pickerview/loading.uts @@ -0,0 +1 @@ +export const imgbase : string = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QzlBMzU3OTlEOUM0MTFFOUI0NTZDNERBQURBQzI4RkUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QzlBMzU3OUFEOUM0MTFFOUI0NTZDNERBQURBQzI4RkUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDOUEzNTc5N0Q5QzQxMUU5QjQ1NkM0REFBREFDMjhGRSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDOUEzNTc5OEQ5QzQxMUU5QjQ1NkM0REFBREFDMjhGRSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pt+ALSwAAA6CSURBVHja1FsLkFZVHb98LM+F5bHL8khA1iSeiyQBCRM+YGqKUnnJTDLGI0BGZlKDIU2MMglUiDApEZvSsZnQtBRJtKwQNKQMFYeRDR10WOLd8ljYXdh+v8v5fR3Od+797t1dnOnO/Ofce77z+J//+b/P+ZqtXbs2sJ9MJhNUV1cHJ06cCJo3bx7EPc2aNcvpy7pWrVoF+/fvDyoqKoI2bdoE9fX1F7TjN8a+EXBn/fkfvw942Tf+wYMHg9mzZwfjxo0LDhw4EPa1x2MbFw/fOGfPng1qa2tzcCkILsLDydq2bRsunpOTMM7TD/W/tZDZhPdeKD+yGxHhdu3aBV27dg3OnDlzMVANMheLAO3btw8KCwuDmpoaX5OxbgUIMEq7K8IcPnw4KCsrC/r37x8cP378/4cAXAB3vqSkJMuiDhTkw+XcuXNhOWbMmKBly5YhUT8xArhyFvP0BfwRsAuwxJZJsm/nzp2DTp06he/OU+cZ64K6o0ePBkOHDg2GDx8e6gEbJ5Q/NHNuAJQ1hgBeHUDlR7nVTkY8rQAvAi4z34vR/mPs1FoRsaCgIJThI0eOBC1atEiFGGV+5MiRoS45efJkqFjJFXV1dQuA012m2WcwTw98fy6CqBdsaiIO4CScrGPHjvk4odhavPquRtFWXEC25VgkREKOCh/qDSq+vn37htzD/mZTOmOc5U7zKzBPEedygWshcDyWvs30igAbU+6oyMgJBCFhwQE0fccxN60Ay9iebbjoDh06hMowjQxT4fXq1SskArmHZpkArvixp/kWzHdMeArExSJEaiXIjjRjRJ4DaAGWpibLzXN3Fm1vA5teBgh3j1Rv3bp1YgKwPdmf2p9zcyNYYgPKMfY0T5f5nNYdw158nJ8QawW4CLKwiOBSEgO/hok2eBydR+3dYH+PLxA5J8Vv0KBBwenTp0P2JWAx6+yFEBfs8lMY+y0SWMBNI9E4ThKi58VKTg3FQZS1RQF1cz27eC0QHMu+3E0SkUowjhVt5VdaWhp07949ZHv2Qd1EjDXM2cla1M0nl3GxAs3J9yREzyTdFVKVFOaE9qRA8GM0WebRuo9JGZKA7Mv2SeS/Z8+eoQ9BArMfFrLGo6jvxbhHbJZnKX2Rzz1O7QhJJ9Cs2ZMaWIyq/zhdeqPNfIoHd58clIQD+JSXl4dKlyIAuBdVXZwFVWKspSSoxE++h8x4k3uCnEhE4I5KwRiFWGOU0QWKiCYLbdoRMRKAu2kQ9vkfLU6dOhX06NEjlH+yMRZSinnuyWnYosVcji8CEA/6Cg2JF+IIUBqnGKUTCNwtwBN4f89RiK1R96DEgO2o0NDmtEdvVFdVVYV+P3UAPUEs6GFwV3PHmXkD4vh74iDFJysVI/MlaQhwKeBNTLYX5VuA8T4/gZxA4MRGFxDB6R7OmYPfyykGRJbyie+XnGYnQIC/coH9+vULiYrxrkL9ZA9+0ykaHIfEpM7ge8TiJ2CsHYwyMfafAF1yCGBHYIbCVDjDjKt7BeB51D+LgQa6OkG7IDYEEtvQ7lnXLKLtLdLuJBpE4gPUXcW2+PkZwOex+4cGDhwYDBkyRL7/HFcEwUGPo/8uWRUpYnfxGHco8HkewLHLyYmAawAPuIFZxhOpDfJQ8gbUv41yORAptMWBNr6oqMhWird5+u+iHmBb2nhjDV7HWBNQTgK8y11l5NetWzc5ULscAtSj7nbNI0skhWeUZCc0W4nyH/jO4Vz0u1IeYhbk4AiwM6tjxIWByHsoZ9qcIBPJd/y+DwPfBESOmCa/QF3WiZHucLlEDpNxcNhmheEOPgdQNx6/VZFQzFZ5TN08AHXQt2Ii3EdyFuUsPtTcGPhW5iMiCNELvz+Gdn9huG4HUJaW/w3g0wxV0XaG7arG2WeKiUWYM4Y7GO5ezshTARbbWGw/DvXkpp/ivVvE0JVoMxN4rpGzJMhE5Pl+xlATsDIqikP9F9D2z3h9nOksEUFhK+qO4rcPkoalMQ/HqJLIyb3F3JdjrCcw1yZ8joyJLR5gCo54etlag7qIoeNh1N1BRYj3DTFJ0elotxPlVzkGuYAmL0VSJVGAJA41c4Z6A3BzTLfn0HYwYKEI6CUAMzZEWvLsIcQOo1AmmyyM72nHJCfYsogflGV6jEk9vyQZXSuq6w4c16NsGcGZbwOPr+H1RkOk2LEzjNepxQkihHSCQ4ynAYNRx2zMKV92CQMWqj8J0BRE8EShxRFN6YrfCRhC0x3r/Zm4IbQCcmJoV0kMamllccR6FjHqUC5F2R/wS2dcymOlfAKOS4KmzQb5cpNC2MC7JhVn5wjXoJ44rYhLh8n0eXOCorJxa7POjbSlCGVczr34/RsAmrcvo9s+wGp3tzVhntxiXiJ4nvEYb4FJkf0O8HocAePmLvCxnL0AORraVekJk6TYjDabRVXfRE2lCN1h6ZQRN1+InUbsCpKwoBZHh0dODN9JBCUffItXxEavTQkUtnfTVAplCWL3JISz29h4NjotnuSsQKJCk8dF+kJR6RARjrqFVmfPnj3ZbK8cIJ0msd6jgHPGtfVTQ8VLmlvh4mct9sobRmPic0DyDQQnx/NlfYUgyz59+oScsH379pAwXABD32nTpoUHIToESeI5mnbE/UqDdyLcafEBf2MCqgC7NwxIbMREJQ0g4D4sfJwnD+AmRrII05cfMWJE+L1169bQr+fip06dGp4oJ83lmYd5wj/EmMa4TaHivo4EeCguYZBnkB5g2aWA69OIEnUHOaGysjIYMGBAMGnSpODYsWPZwCpFmm4lNq+4gSLQA7jcX8DwtjEyRC8wjabnXEx9kfWnTJkSJkAo90xpJVV+FmcVNeYAF5zWngS4C4O91MBxmAv8blLEpbjI5sz9MTdAhcgkCT1RO8mZkAjfiYpTEvStAS53Uw1vAiUGgZ3GpuQEYvoiBqlIan7kSDHnTwJQFNiPu0+5VxCVYhcZIjNrdXUDdp+Eq5AZ3Gkg8QAyVZRZIk4Tl4QAbF9cXJxNYZMAtAokgs4BrNxEpCtteXg7DDTMDKYNSuQdKsnJBek7HxewvxaosWxLYXtw+cJp18217wql4aKCfBNoEu0O5VU+PhctJ0YeXD4C6JQpyrlpSLTojpGGGN5YwNziChdIZLk4lvLcFJ9jMX3QdiImY9bmGQU+TRUL5CHITTRlgF8D9ouD1MfmLoEPl5xokIumZ2cfgMpHt47IW9N64Hsh7wQYYjyIugWuF5fCqYncXRd5vPMWyizzvhi/32+nvG0dZc9vR6fZOu0md5e+uC408FvKSIOZwXlGvxPv95izA2Vtvg1xKFWARI+vMX66HUhpQQb643uW1bSjuTWyw2SBvDrBvjFic1eGGlz5esq3ko9uSIlBRqPuFcCv8F4WIcN12nVaBd0SaYwI6PDDImR11JkqgHcPmQssjxIn6bUshygDFJUTxPMpHk+jfjPgupgdnYV2R/g7xSjtpah8RJBewhwf0gGK6XI92u4wXFEU40afJ4DN4h5LcAd+40HI3JgJecuT0c062W0i2hQJUTcxan3/CMW1PF2K6bbA+Daz4xRs1D3Br1Cm0OihKCqizW78/nXAF/G5TXrEcVzaNMH6CyMswqsAHqDyDLEyou8lwOXnKF8DjI6KjV3KzMBiXkDH8ij/H214J5A596ekrZ3F0zXlWeL7+P5eUrNo3/QwC15uxthuzidy7DzKRwEDaAViiDgKbTbz7CJnzo0bN7pIfIiid8SuPwn25o3QCmpnyjlZkyxPP8EomCJzrGb7GJMx7tNsq4MT2xMUYaiErZOluTzKsnz3gwCeCZyVRZJfYplNEokEjwrPtxlxjeYAk+F1F74VAzPxQRNYYdtpOUvWs8J1sGhBJMNsb7igN8plJs1eSmLIhLKE4rvaCX27gOhLpLOsIzJ7qn/i+wZzcvSOZ23/du8TZjwV8zHIXoP4R3ifBxiFz1dcVpa3aPntPE+c6TmIWE9EtcMmAcPdWAhYhAXxcLOQi9L1WhD1Sc8p1d2oL7XGiRKp8F4A2i8K/nfI+y/gsTDJ/YC/8+AD5Uh04KHiGl+cIFPnBDDrPMjwRGkLXyxO4VGbfQWnDH2v0bVWE3C9QOXlepbgjEfIJQI6XDG3z5ahD9cw2pS78ipB85wyScNTvsVzlzzhL8/jRrnmVjfFJK/m3m4nj9vbgQTguT8XZTjsm672R5uJKEaQmBI/c58gyus8ZDagLpEVSJBIyHp4jn++xqPV71OgQgJYEWOtZ/haxRtKmWOBu8xdBLftWltsY84zE6WIEy/eIOWL+BaayMx+KHtL7EAkqdNDLiEXmEMUHniedtJqg9HmZtfvt26vNi0BdG3Ft3g8ZOf7PAu59TxtzivLNIekyi+wD1i8CuUiD9FXAa8C+/xS3JPmZnomyc7H+fb4/Se0bk41Fel621r4cgVxbq91V4jVqwB7HTe2M7jgB+QWHavZkDRPmZcASoZEmBx6i75bGjPcMdL4/VKGFAGWZkGzPG0XAbdL9A81G5LOmUnC9hHKJeO7dcUMjblSl12867ElFTtaGl20xvvLGPdVz/8TVuU7y0x1PG7vtNg24oz9Uo/Z412++VFWI7Fcog9tu9Lm6gvRmIPv9x1xmQAu6RDkXtbOtlGEmpgD5Nvnyc0dcv0EE6cfdi1HmhMf9wDF3k3gtRvEedhxjpgfqPb9PU9iEJHnyOUA7bQUXh6kq/D7l2iTjWv7XOD530BDr8jIrus+srXjt4MzumJMHuTsBa63YKE1+RR5lBjEikCCnWKWiHdzOgKO+nRIBAF88za/IFmJ3eMZov4CYxGBabcpGL8EYx+SeMXJeRwHNsV/h+vdxeuhEpN3ZyNY78Gm2fknJxVGhyjixPiQvVkNzT1elD9Py/aTAL64Hb9vcYmC9zfdXdT/C1LeGbg4rnBaAihDFJH12W5ulfNCNe/xTsP3bp8ikzJs5BF+5PNfAQYAPaseTdsEcaYAAAAASUVORK5CYII=' \ No newline at end of file diff --git a/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js new file mode 100644 index 0000000..cfae22a --- /dev/null +++ b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js @@ -0,0 +1,622 @@ +export default { + props: { + localdata: { + type: [Array, Object], + default () { + return [] + } + }, + spaceInfo: { + type: Object, + default () { + return {} + } + }, + collection: { + type: String, + default: '' + }, + action: { + type: String, + default: '' + }, + field: { + type: String, + default: '' + }, + orderby: { + type: String, + default: '' + }, + where: { + type: [String, Object], + default: '' + }, + pageData: { + type: String, + default: 'add' + }, + pageCurrent: { + type: Number, + default: 1 + }, + pageSize: { + type: Number, + default: 500 + }, + getcount: { + type: [Boolean, String], + default: false + }, + getone: { + type: [Boolean, String], + default: false + }, + gettree: { + type: [Boolean, String], + default: false + }, + manual: { + type: Boolean, + default: false + }, + value: { + type: [Array, String, Number], + default () { + return [] + } + }, + modelValue: { + type: [Array, String, Number], + default () { + return [] + } + }, + preload: { + type: Boolean, + default: false + }, + stepSearh: { + type: Boolean, + default: true + }, + selfField: { + type: String, + default: '' + }, + parentField: { + type: String, + default: '' + }, + multiple: { + type: Boolean, + default: false + }, + map: { + type: Object, + default () { + return { + text: "text", + value: "value" + } + } + } + }, + data() { + return { + loading: false, + errorMessage: '', + loadMore: { + contentdown: '', + contentrefresh: '', + contentnomore: '' + }, + dataList: [], + selected: [], + selectedIndex: 0, + page: { + current: this.pageCurrent, + size: this.pageSize, + count: 0 + } + } + }, + computed: { + isLocalData() { + return !this.collection.length; + }, + isCloudData() { + return this.collection.length > 0; + }, + isCloudDataList() { + return (this.isCloudData && (!this.parentField && !this.selfField)); + }, + isCloudDataTree() { + return (this.isCloudData && this.parentField && this.selfField); + }, + dataValue() { + let isModelValue = Array.isArray(this.modelValue) ? (this.modelValue.length > 0) : (this.modelValue !== null || + this.modelValue !== undefined); + return isModelValue ? this.modelValue : this.value; + }, + hasValue() { + if (typeof this.dataValue === 'number') { + return true + } + return (this.dataValue != null) && (this.dataValue.length > 0) + } + }, + created() { + this.$watch(() => { + var al = []; + ['pageCurrent', + 'pageSize', + 'spaceInfo', + 'value', + 'modelValue', + 'localdata', + 'collection', + 'action', + 'field', + 'orderby', + 'where', + 'getont', + 'getcount', + 'gettree' + ].forEach(key => { + al.push(this[key]) + }); + return al + }, (newValue, oldValue) => { + let needReset = false + for (let i = 2; i < newValue.length; i++) { + if (newValue[i] != oldValue[i]) { + needReset = true + break + } + } + if (newValue[0] != oldValue[0]) { + this.page.current = this.pageCurrent + } + this.page.size = this.pageSize + + this.onPropsChange() + }) + this._treeData = [] + }, + methods: { + onPropsChange() { + this._treeData = []; + }, + + // 填充 pickview 数据 + async loadData() { + if (this.isLocalData) { + this.loadLocalData(); + } else if (this.isCloudDataList) { + this.loadCloudDataList(); + } else if (this.isCloudDataTree) { + this.loadCloudDataTree(); + } + }, + + // 加载本地数据 + async loadLocalData() { + this._treeData = []; + this._extractTree(this.localdata, this._treeData); + + let inputValue = this.dataValue; + if (inputValue === undefined) { + return; + } + + if (Array.isArray(inputValue)) { + inputValue = inputValue[inputValue.length - 1]; + if (typeof inputValue === 'object' && inputValue[this.map.value]) { + inputValue = inputValue[this.map.value]; + } + } + + this.selected = this._findNodePath(inputValue, this.localdata); + }, + + // 加载 Cloud 数据 (单列) + async loadCloudDataList() { + if (this.loading) { + return; + } + this.loading = true; + + try { + let response = await this.getCommand(); + let responseData = response.result.data; + + this._treeData = responseData; + + this._updateBindData(); + this._updateSelected(); + + this.onDataChange(); + } catch (e) { + this.errorMessage = e; + } finally { + this.loading = false; + } + }, + + // 加载 Cloud 数据 (树形) + async loadCloudDataTree() { + if (this.loading) { + return; + } + this.loading = true; + + try { + let commandOptions = { + field: this._cloudDataPostField(), + where: this._cloudDataTreeWhere() + }; + if (this.gettree) { + commandOptions.startwith = `${this.selfField}=='${this.dataValue}'`; + } + + let response = await this.getCommand(commandOptions); + let responseData = response.result.data; + + this._treeData = responseData; + this._updateBindData(); + this._updateSelected(); + + this.onDataChange(); + } catch (e) { + this.errorMessage = e; + } finally { + this.loading = false; + } + }, + + // 加载 Cloud 数据 (节点) + async loadCloudDataNode(callback) { + if (this.loading) { + return; + } + this.loading = true; + + try { + let commandOptions = { + field: this._cloudDataPostField(), + where: this._cloudDataNodeWhere() + }; + + let response = await this.getCommand(commandOptions); + let responseData = response.result.data; + + callback(responseData); + } catch (e) { + this.errorMessage = e; + } finally { + this.loading = false; + } + }, + + // 回显 Cloud 数据 + getCloudDataValue() { + if (this.isCloudDataList) { + return this.getCloudDataListValue(); + } + + if (this.isCloudDataTree) { + return this.getCloudDataTreeValue(); + } + }, + + // 回显 Cloud 数据 (单列) + getCloudDataListValue() { + // 根据 field's as value标识匹配 where 条件 + let where = []; + let whereField = this._getForeignKeyByField(); + if (whereField) { + where.push(`${whereField} == '${this.dataValue}'`) + } + + where = where.join(' || '); + + if (this.where) { + where = `(${this.where}) && (${where})` + } + + return this.getCommand({ + field: this._cloudDataPostField(), + where + }).then((res) => { + this.selected = res.result.data; + return res.result.data; + }); + }, + + // 回显 Cloud 数据 (树形) + getCloudDataTreeValue() { + return this.getCommand({ + field: this._cloudDataPostField(), + getTreePath: { + startWith: `${this.selfField}=='${this.dataValue}'` + } + }).then((res) => { + let treePath = []; + this._extractTreePath(res.result.data, treePath); + this.selected = treePath; + return treePath; + }); + }, + + getCommand(options = {}) { + /* eslint-disable no-undef */ + let db = uniCloud.database(this.spaceInfo) + + const action = options.action || this.action + if (action) { + db = db.action(action) + } + + const collection = options.collection || this.collection + db = db.collection(collection) + + const where = options.where || this.where + if (!(!where || !Object.keys(where).length)) { + db = db.where(where) + } + + const field = options.field || this.field + if (field) { + db = db.field(field) + } + + const orderby = options.orderby || this.orderby + if (orderby) { + db = db.orderBy(orderby) + } + + const current = options.pageCurrent !== undefined ? options.pageCurrent : this.page.current + const size = options.pageSize !== undefined ? options.pageSize : this.page.size + const getCount = options.getcount !== undefined ? options.getcount : this.getcount + const getTree = options.gettree !== undefined ? options.gettree : this.gettree + + const getOptions = { + getCount, + getTree + } + if (options.getTreePath) { + getOptions.getTreePath = options.getTreePath + } + + db = db.skip(size * (current - 1)).limit(size).get(getOptions) + + return db + }, + + _cloudDataPostField() { + let fields = [this.field]; + if (this.parentField) { + fields.push(`${this.parentField} as parent_value`); + } + return fields.join(','); + }, + + _cloudDataTreeWhere() { + let result = [] + let selected = this.selected + let parentField = this.parentField + if (parentField) { + result.push(`${parentField} == null || ${parentField} == ""`) + } + if (selected.length) { + for (var i = 0; i < selected.length - 1; i++) { + result.push(`${parentField} == '${selected[i].value}'`) + } + } + + let where = [] + if (this.where) { + where.push(`(${this.where})`) + } + + if (result.length) { + where.push(`(${result.join(' || ')})`) + } + + return where.join(' && ') + }, + + _cloudDataNodeWhere() { + let where = [] + let selected = this.selected; + if (selected.length) { + where.push(`${this.parentField} == '${selected[selected.length - 1].value}'`); + } + + where = where.join(' || '); + + if (this.where) { + return `(${this.where}) && (${where})` + } + + return where + }, + + _getWhereByForeignKey() { + let result = [] + let whereField = this._getForeignKeyByField(); + if (whereField) { + result.push(`${whereField} == '${this.dataValue}'`) + } + + if (this.where) { + return `(${this.where}) && (${result.join(' || ')})` + } + + return result.join(' || ') + }, + + _getForeignKeyByField() { + let fields = this.field.split(','); + let whereField = null; + for (let i = 0; i < fields.length; i++) { + const items = fields[i].split('as'); + if (items.length < 2) { + continue; + } + if (items[1].trim() === 'value') { + whereField = items[0].trim(); + break; + } + } + return whereField; + }, + + _updateBindData(node) { + const { + dataList, + hasNodes + } = this._filterData(this._treeData, this.selected) + + let isleaf = this._stepSearh === false && !hasNodes + + if (node) { + node.isleaf = isleaf + } + + this.dataList = dataList + this.selectedIndex = dataList.length - 1 + + if (!isleaf && this.selected.length < dataList.length) { + this.selected.push({ + value: null, + text: "请选择" + }) + } + + return { + isleaf, + hasNodes + } + }, + + _updateSelected() { + let dl = this.dataList + let sl = this.selected + let textField = this.map.text + let valueField = this.map.value + for (let i = 0; i < sl.length; i++) { + let value = sl[i].value + let dl2 = dl[i] + for (let j = 0; j < dl2.length; j++) { + let item2 = dl2[j] + if (item2[valueField] === value) { + sl[i].text = item2[textField] + break + } + } + } + }, + + _filterData(data, paths) { + let dataList = [] + let hasNodes = true + + dataList.push(data.filter((item) => { + return (item.parent_value === null || item.parent_value === undefined || item.parent_value === '') + })) + for (let i = 0; i < paths.length; i++) { + let value = paths[i].value + let nodes = data.filter((item) => { + return item.parent_value === value + }) + + if (nodes.length) { + dataList.push(nodes) + } else { + hasNodes = false + } + } + + return { + dataList, + hasNodes + } + }, + + _extractTree(nodes, result, parent_value) { + let list = result || [] + let valueField = this.map.value + for (let i = 0; i < nodes.length; i++) { + let node = nodes[i] + + let child = {} + for (let key in node) { + if (key !== 'children') { + child[key] = node[key] + } + } + if (parent_value !== null && parent_value !== undefined && parent_value !== '') { + child.parent_value = parent_value + } + result.push(child) + + let children = node.children + if (children) { + this._extractTree(children, result, node[valueField]) + } + } + }, + + _extractTreePath(nodes, result) { + let list = result || [] + for (let i = 0; i < nodes.length; i++) { + let node = nodes[i] + + let child = {} + for (let key in node) { + if (key !== 'children') { + child[key] = node[key] + } + } + result.push(child) + + let children = node.children + if (children) { + this._extractTreePath(children, result) + } + } + }, + + _findNodePath(key, nodes, path = []) { + let textField = this.map.text + let valueField = this.map.value + for (let i = 0; i < nodes.length; i++) { + let node = nodes[i] + let children = node.children + let text = node[textField] + let value = node[valueField] + + path.push({ + value, + text + }) + + if (value === key) { + return path + } + + if (children) { + const p = this._findNodePath(key, children, path) + if (p.length) { + return p + } + } + + path.pop() + } + return [] + } + } +} diff --git a/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.uts b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.uts new file mode 100644 index 0000000..372795d --- /dev/null +++ b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.uts @@ -0,0 +1,693 @@ +export type PaginationType = { + current : number, + size : number, + count : number +} + +export type LoadMoreType = { + contentdown : string, + contentrefresh : string, + contentnomore : string +} + +export type SelectedItemType = { + name : string, + value : string, +} + +export type GetCommandOptions = { + collection ?: UTSJSONObject, + field ?: string, + orderby ?: string, + where ?: any, + pageData ?: string, + pageCurrent ?: number, + pageSize ?: number, + getCount ?: boolean, + getTree ?: any, + getTreePath ?: UTSJSONObject, + startwith ?: string, + limitlevel ?: number, + groupby ?: string, + groupField ?: string, + distinct ?: boolean, + pageIndistinct ?: boolean, + foreignKey ?: string, + loadtime ?: string, + manual ?: boolean +} + +const DefaultSelectedNode = { + text: '请选择', + value: '' +} + +export const dataPicker = defineMixin({ + props: { + localdata: { + type: Array as PropType>, + default: [] as Array + }, + collection: { + type: Object, + default: '' + }, + field: { + type: String, + default: '' + }, + orderby: { + type: String, + default: '' + }, + where: { + type: Object, + default: '' + }, + pageData: { + type: String, + default: 'add' + }, + pageCurrent: { + type: Number, + default: 1 + }, + pageSize: { + type: Number, + default: 20 + }, + getcount: { + type: Boolean, + default: false + }, + gettree: { + type: Object, + default: '' + }, + gettreepath: { + type: Object, + default: '' + }, + startwith: { + type: String, + default: '' + }, + limitlevel: { + type: Number, + default: 10 + }, + groupby: { + type: String, + default: '' + }, + groupField: { + type: String, + default: '' + }, + distinct: { + type: Boolean, + default: false + }, + pageIndistinct: { + type: Boolean, + default: false + }, + foreignKey: { + type: String, + default: '' + }, + loadtime: { + type: String, + default: 'auto' + }, + manual: { + type: Boolean, + default: false + }, + preload: { + type: Boolean, + default: false + }, + stepSearh: { + type: Boolean, + default: true + }, + selfField: { + type: String, + default: '' + }, + parentField: { + type: String, + default: '' + }, + multiple: { + type: Boolean, + default: false + }, + value: { + type: Object, + default: '' + }, + modelValue: { + type: Object, + default: '' + }, + defaultProps: { + type: Object as PropType, + } + }, + data() { + return { + loading: false, + error: null as UniCloudError | null, + treeData: [] as Array, + selectedIndex: 0, + selectedNodes: [] as Array, + selectedPages: [] as Array[], + selectedValue: '', + selectedPaths: [] as Array, + pagination: { + current: 1, + size: 20, + count: 0 + } as PaginationType + } + }, + computed: { + mappingTextName() : string { + // TODO + return (this.defaultProps != null) ? this.defaultProps!.getString('text', 'text') : 'text' + }, + mappingValueName() : string { + // TODO + return (this.defaultProps != null) ? this.defaultProps!.getString('value', 'value') : 'value' + }, + currentDataList() : Array { + if (this.selectedIndex > this.selectedPages.length - 1) { + return [] as Array + } + return this.selectedPages[this.selectedIndex] + }, + isLocalData() : boolean { + return this.localdata.length > 0 + }, + isCloudData() : boolean { + return this._checkIsNotNull(this.collection) + }, + isCloudDataList() : boolean { + return (this.isCloudData && (this.parentField.length == 0 && this.selfField.length == 0)) + }, + isCloudDataTree() : boolean { + return (this.isCloudData && this.parentField.length > 0 && this.selfField.length > 0) + }, + dataValue() : any { + return this.hasModelValue ? this.modelValue : this.value + }, + hasCloudTreeData() : boolean { + return this.treeData.length > 0 + }, + hasModelValue() : boolean { + if (typeof this.modelValue == 'string') { + const valueString = this.modelValue as string + return (valueString.length > 0) + } else if (Array.isArray(this.modelValue)) { + const valueArray = this.modelValue as Array + return (valueArray.length > 0) + } + return false + }, + hasCloudDataValue() : boolean { + if (typeof this.dataValue == 'string') { + const valueString = this.dataValue as string + return (valueString.length > 0) + } + return false + } + }, + created() { + this.pagination.current = this.pageCurrent + this.pagination.size = this.pageSize + + this.$watch( + () : any => [ + this.pageCurrent, + this.pageSize, + this.localdata, + this.value, + this.collection, + this.field, + this.getcount, + this.orderby, + this.where, + this.groupby, + this.groupField, + this.distinct + ], + (newValue : Array, oldValue : Array) => { + this.pagination.size = this.pageSize + if (newValue[0] !== oldValue[0]) { + this.pagination.current = this.pageCurrent + } + + this.onPropsChange() + } + ) + }, + methods: { + onPropsChange() { + this.selectedIndex = 0 + this.treeData.length = 0 + this.selectedNodes.length = 0 + this.selectedPages.length = 0 + this.selectedPaths.length = 0 + + // 加载数据 + this.$nextTick(() => { + this.loadData() + }) + }, + + onTabSelect(index : number) { + this.selectedIndex = index + }, + + onNodeClick(nodeData : UTSJSONObject) { + if (nodeData.getBoolean('disable', false)) { + return + } + + const isLeaf = this._checkIsLeafNode(nodeData) + + this._trimSelectedNodes(nodeData) + + this.$emit('nodeclick', nodeData) + + if (this.isLocalData) { + if (isLeaf || !this._checkHasChildren(nodeData)) { + this.onFinish() + } + } else if (this.isCloudDataList) { + this.onFinish() + } else if (this.isCloudDataTree) { + if (isLeaf) { + this.onFinish() + } else if (!this._checkHasChildren(nodeData)) { + // 尝试请求一次,如果没有返回数据标记为叶子节点 + this.loadCloudDataNode(nodeData) + } + } + }, + + getChangeNodes(): Array { + const nodes: Array = [] + this.selectedNodes.forEach((node : UTSJSONObject) => { + const newNode: UTSJSONObject = {} + newNode[this.mappingTextName] = node.getString(this.mappingTextName) + newNode[this.mappingValueName] = node.getString(this.mappingValueName) + nodes.push(newNode) + }) + return nodes + }, + + onFinish() { }, + + // 加载数据(自动判定环境) + loadData() { + if (this.isLocalData) { + this.loadLocalData() + } else if (this.isCloudDataList) { + this.loadCloudDataList() + } else if (this.isCloudDataTree) { + this.loadCloudDataTree() + } + }, + + // 加载本地数据 + loadLocalData() { + this.treeData = this.localdata + if (Array.isArray(this.dataValue)) { + const value = this.dataValue as Array + this.selectedPaths = value.slice(0) + this._pushSelectedTreeNodes(value, this.localdata) + } else { + this._pushSelectedNodes(this.localdata) + } + }, + + // 加载 Cloud 数据 (单列) + loadCloudDataList() { + this._loadCloudData(null, (data : Array) => { + this.treeData = data + this._pushSelectedNodes(data) + }) + }, + + // 加载 Cloud 数据 (树形) + loadCloudDataTree() { + let commandOptions = { + field: this._cloudDataPostField(), + where: this._cloudDataTreeWhere(), + getTree: true + } as GetCommandOptions + if (this._checkIsNotNull(this.gettree)) { + commandOptions.startwith = `${this.selfField}=='${this.dataValue as string}'` + } + this._loadCloudData(commandOptions, (data : Array) => { + this.treeData = data + if (this.selectedPaths.length > 0) { + this._pushSelectedTreeNodes(this.selectedPaths, data) + } else { + this._pushSelectedNodes(data) + } + }) + }, + + // 加载 Cloud 数据 (节点) + loadCloudDataNode(nodeData : UTSJSONObject) { + const commandOptions = { + field: this._cloudDataPostField(), + where: this._cloudDataNodeWhere() + } as GetCommandOptions + this._loadCloudData(commandOptions, (data : Array) => { + nodeData['children'] = data + if (data.length == 0) { + nodeData['isleaf'] = true + this.onFinish() + } else { + this._pushSelectedNodes(data) + } + }) + }, + + // 回显 Cloud Tree Path + loadCloudDataPath() { + if (!this.hasCloudDataValue) { + return + } + + const command : GetCommandOptions = {} + + // 单列 + if (this.isCloudDataList) { + // 根据 field's as value标识匹配 where 条件 + let where : Array = []; + let whereField = this._getForeignKeyByField(); + if (whereField.length > 0) { + where.push(`${whereField} == '${this.dataValue as string}'`) + } + + let whereString = where.join(' || ') + if (this._checkIsNotNull(this.where)) { + whereString = `(${this.where}) && (${whereString})` + } + + command.field = this._cloudDataPostField() + command.where = whereString + } + + // 树形 + if (this.isCloudDataTree) { + command.field = this._cloudDataPostField() + command.getTreePath = { + startWith: `${this.selfField}=='${this.dataValue as string}'` + } + } + + this._loadCloudData(command, (data : Array) => { + this._extractTreePath(data, this.selectedPaths) + }) + }, + + _loadCloudData(options ?: GetCommandOptions, callback ?: ((data : Array) => void)) { + if (this.loading) { + return + } + this.loading = true + + this.error = null + + this._getCommand(options).then((response : UniCloudDBGetResult) => { + callback?.(response.data) + }).catch((err : any | null) => { + this.error = err as UniCloudError + }).finally(() => { + this.loading = false + }) + }, + + _cloudDataPostField() : string { + let fields = [this.field]; + if (this.parentField.length > 0) { + fields.push(`${this.parentField} as parent_value`) + } + return fields.join(',') + }, + + _cloudDataTreeWhere() : string { + let result : Array = [] + let selectedNodes = this.selectedNodes.length > 0 ? this.selectedNodes : this.selectedPaths + let parentField = this.parentField + if (parentField.length > 0) { + result.push(`${parentField} == null || ${parentField} == ""`) + } + if (selectedNodes.length > 0) { + for (var i = 0; i < selectedNodes.length - 1; i++) { + const parentFieldValue = selectedNodes[i].getString('value', '') + result.push(`${parentField} == '${parentFieldValue}'`) + } + } + + let where : Array = [] + if (this._checkIsNotNull(this.where)) { + where.push(`(${this.where as string})`) + } + + if (result.length > 0) { + where.push(`(${result.join(' || ')})`) + } + + return where.join(' && ') + }, + + _cloudDataNodeWhere() : string { + const where : Array = [] + if (this.selectedNodes.length > 0) { + const value = this.selectedNodes[this.selectedNodes.length - 1].getString('value', '') + where.push(`${this.parentField} == '${value}'`) + } + + let whereString = where.join(' || ') + if (this._checkIsNotNull(this.where)) { + return `(${this.where as string}) && (${whereString})` + } + + return whereString + }, + + _getWhereByForeignKey() : string { + let result : Array = [] + let whereField = this._getForeignKeyByField(); + if (whereField.length > 0) { + result.push(`${whereField} == '${this.dataValue as string}'`) + } + + if (this._checkIsNotNull(this.where)) { + return `(${this.where}) && (${result.join(' || ')})` + } + + return result.join(' || ') + }, + + _getForeignKeyByField() : string { + const fields = this.field.split(',') + let whereField = '' + for (let i = 0; i < fields.length; i++) { + const items = fields[i].split('as') + if (items.length < 2) { + continue + } + if (items[1].trim() === 'value') { + whereField = items[0].trim() + break + } + } + return whereField + }, + + _getCommand(options ?: GetCommandOptions) : Promise { + let db = uniCloud.databaseForJQL() + + let collection = Array.isArray(this.collection) ? db.collection(...(this.collection as Array)) : db.collection(this.collection) + + let filter : UniCloudDBFilter | null = null + if (this.foreignKey.length > 0) { + filter = collection.foreignKey(this.foreignKey) + } + + const where : any = options?.where ?? this.where + if (typeof where == 'string') { + const whereString = where as string + if (whereString.length > 0) { + filter = (filter != null) ? filter.where(where) : collection.where(where) + } + } else { + filter = (filter != null) ? filter.where(where) : collection.where(where) + } + + let query : UniCloudDBQuery | null = null + if (this.field.length > 0) { + query = (filter != null) ? filter.field(this.field) : collection.field(this.field) + } + if (this.groupby.length > 0) { + if (query != null) { + query = query.groupBy(this.groupby) + } else if (filter != null) { + query = filter.groupBy(this.groupby) + } + } + if (this.groupField.length > 0) { + if (query != null) { + query = query.groupField(this.groupField) + } else if (filter != null) { + query = filter.groupField(this.groupField) + } + } + if (this.distinct == true) { + if (query != null) { + query = query.distinct(this.field) + } else if (filter != null) { + query = filter.distinct(this.field) + } + } + if (this.orderby.length > 0) { + if (query != null) { + query = query.orderBy(this.orderby) + } else if (filter != null) { + query = filter.orderBy(this.orderby) + } + } + + const size = this.pagination.size + const current = this.pagination.current + if (query != null) { + query = query.skip(size * (current - 1)).limit(size) + } else if (filter != null) { + query = filter.skip(size * (current - 1)).limit(size) + } else { + query = collection.skip(size * (current - 1)).limit(size) + } + + const getOptions = {} + const treeOptions = { + limitLevel: this.limitlevel, + startWith: this.startwith + } + if (this.getcount == true) { + getOptions['getCount'] = this.getcount + } + + const getTree : any = options?.getTree ?? this.gettree + if (typeof getTree == 'string') { + const getTreeString = getTree as string + if (getTreeString.length > 0) { + getOptions['getTree'] = treeOptions + } + } else if (typeof getTree == 'object') { + getOptions['getTree'] = treeOptions + } else { + getOptions['getTree'] = getTree + } + + const getTreePath = options?.getTreePath ?? this.gettreepath + if (typeof getTreePath == 'string') { + const getTreePathString = getTreePath as string + if (getTreePathString.length > 0) { + getOptions['getTreePath'] = getTreePath + } + } else { + getOptions['getTreePath'] = getTreePath + } + + return query.get(getOptions) + }, + + _checkIsNotNull(value : any) : boolean { + if (typeof value == 'string') { + const valueString = value as string + return (valueString.length > 0) + } else if (value instanceof UTSJSONObject) { + return true + } + return false + }, + + _checkIsLeafNode(nodeData : UTSJSONObject) : boolean { + if (this.selectedIndex >= this.limitlevel) { + return true + } + + if (nodeData.getBoolean('isleaf', false)) { + return true + } + + return false + }, + + _checkHasChildren(nodeData : UTSJSONObject) : boolean { + const children = nodeData.getArray('children') ?? ([] as Array) + return children.length > 0 + }, + + _pushSelectedNodes(nodes : Array) { + this.selectedNodes.push(DefaultSelectedNode) + this.selectedPages.push(nodes) + this.selectedIndex = this.selectedPages.length - 1 + }, + + _trimSelectedNodes(nodeData : UTSJSONObject) { + this.selectedNodes.splice(this.selectedIndex) + this.selectedNodes.push(nodeData) + + if (this.selectedPages.length > 0) { + this.selectedPages.splice(this.selectedIndex + 1) + } + + const children = nodeData.getArray('children') ?? ([] as Array) + if (children.length > 0) { + this.selectedNodes.push(DefaultSelectedNode) + this.selectedPages.push(children) + } + + this.selectedIndex = this.selectedPages.length - 1 + }, + + _pushSelectedTreeNodes(paths : Array, nodes : Array) { + let children : Array = nodes + paths.forEach((node : UTSJSONObject) => { + const findNode = children.find((item : UTSJSONObject) : boolean => { + return (item.getString(this.mappingValueName) == node.getString(this.mappingValueName)) + }) + if (findNode != null) { + this.selectedPages.push(children) + this.selectedNodes.push(node) + children = findNode.getArray('children') ?? ([] as Array) + } + }) + this.selectedIndex = this.selectedPages.length - 1 + }, + + _extractTreePath(nodes : Array, result : Array) { + if (nodes.length == 0) { + return + } + + const node = nodes[0] + result.push(node) + + const children = node.getArray('children') + if (Array.isArray(children) && children!.length > 0) { + this._extractTreePath(children, result) + } + } + } +}) diff --git a/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.css b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.css new file mode 100644 index 0000000..39fe1c3 --- /dev/null +++ b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.css @@ -0,0 +1,76 @@ +.uni-data-pickerview { + position: relative; + flex-direction: column; + overflow: hidden; +} + +.loading-cover { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + align-items: center; + justify-content: center; + background-color: rgba(150, 150, 150, .1); +} + +.error { + background-color: #fff; + padding: 15px; +} + +.error-text { + color: #DD524D; +} + +.selected-node-list { + flex-direction: row; + flex-wrap: nowrap; +} + +.selected-node-item { + margin-left: 10px; + margin-right: 10px; + padding: 8px 10px 8px 10px; + border-bottom: 2px solid transparent; +} + +.selected-node-item-active { + color: #007aff; + border-bottom-color: #007aff; +} + +.list-view { + flex: 1; +} + +.list-item { + flex-direction: row; + justify-content: space-between; + padding: 12px 15px; + border-bottom: 1px solid #f0f0f0; +} + +.item-text { + color: #333333; +} + +.item-text-disabled { + opacity: .5; +} + +.item-text-overflow { + overflow: hidden; +} + +.check { + margin-right: 5px; + border: 2px solid #007aff; + border-left: 0; + border-top: 0; + height: 12px; + width: 6px; + transform-origin: center; + transform: rotate(45deg); +} diff --git a/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.uvue b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.uvue new file mode 100644 index 0000000..f4780f3 --- /dev/null +++ b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.uvue @@ -0,0 +1,69 @@ + + + + + diff --git a/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue new file mode 100644 index 0000000..6ebced9 --- /dev/null +++ b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue @@ -0,0 +1,323 @@ + + + + + diff --git a/uni_modules/uni-data-picker/package.json b/uni_modules/uni-data-picker/package.json new file mode 100644 index 0000000..a508162 --- /dev/null +++ b/uni_modules/uni-data-picker/package.json @@ -0,0 +1,91 @@ +{ + "id": "uni-data-picker", + "displayName": "uni-data-picker 数据驱动的picker选择器", + "version": "2.0.0", + "description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景", + "keywords": [ + "uni-ui", + "uniui", + "picker", + "级联", + "省市区", + "" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [ + "uni-load-more", + "uni-icons", + "uni-scss" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y", + "app-uvue": "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-data-picker/readme.md b/uni_modules/uni-data-picker/readme.md new file mode 100644 index 0000000..19dd0e8 --- /dev/null +++ b/uni_modules/uni-data-picker/readme.md @@ -0,0 +1,22 @@ +## DataPicker 级联选择 +> **组件名:uni-data-picker** +> 代码块: `uDataPicker` +> 关联组件:`uni-data-pickerview`、`uni-load-more`。 + + +`` 是一个选择类[datacom组件](https://uniapp.dcloud.net.cn/component/datacom)。 + +支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。 + +候选数据支持一次性加载完毕,也支持懒加载,比如示例图中,选择了“北京”后,动态加载北京的区县数据。 + +`` 组件尤其适用于地址选择、分类选择等选择类。 + +`` 支持本地数据、云端静态数据(json),uniCloud云数据库数据。 + +`` 可以通过JQL直连uniCloud云数据库,配套[DB Schema](https://uniapp.dcloud.net.cn/uniCloud/schema),可在schema2code中自动生成前端页面,还支持服务器端校验。 + +在uniCloud数据表中新建表“uni-id-address”和“opendb-city-china”,这2个表的schema自带foreignKey关联。在“uni-id-address”表的表结构页面使用schema2code生成前端页面,会自动生成地址管理的维护页面,自动从“opendb-city-china”表包含的中国所有省市区信息里选择地址。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-picker) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-data-select/changelog.md b/uni_modules/uni-data-select/changelog.md new file mode 100644 index 0000000..eb3d1ce --- /dev/null +++ b/uni_modules/uni-data-select/changelog.md @@ -0,0 +1,35 @@ +## 1.0.6(2023-04-12) +- 修复 微信小程序点击时会改变背景颜色的 bug +## 1.0.5(2023-02-03) +- 修复 禁用时会显示清空按钮 +## 1.0.4(2023-02-02) +- 优化 查询条件短期内多次变更只查询最后一次变更后的结果 +- 调整 内部缓存键名调整为 uni-data-select-lastSelectedValue +## 1.0.3(2023-01-16) +- 修复 不关联服务空间报错的问题 +## 1.0.2(2023-01-14) +- 新增 属性 `format` 可用于格式化显示选项内容 +## 1.0.1(2022-12-06) +- 修复 当where变化时,数据不会自动更新的问题 +## 0.1.9(2022-09-05) +- 修复 微信小程序下拉框出现后选择会点击到蒙板后面的输入框 +## 0.1.8(2022-08-29) +- 修复 点击的位置不准确 +## 0.1.7(2022-08-12) +- 新增 支持 disabled 属性 +## 0.1.6(2022-07-06) +- 修复 pc端宽度异常的bug +## 0.1.5 +- 修复 pc端宽度异常的bug +## 0.1.4(2022-07-05) +- 优化 显示样式 +## 0.1.3(2022-06-02) +- 修复 localdata 赋值不生效的 bug +- 新增 支持 uni.scss 修改颜色 +- 新增 支持选项禁用(数据选项设置 disabled: true 即禁用) +## 0.1.2(2022-05-08) +- 修复 当 value 为 0 时选择不生效的 bug +## 0.1.1(2022-05-07) +- 新增 记住上次的选项(仅 collection 存在时有效) +## 0.1.0(2022-04-22) +- 初始化 diff --git a/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue b/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue new file mode 100644 index 0000000..9b32348 --- /dev/null +++ b/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue @@ -0,0 +1,517 @@ + + + + + diff --git a/uni_modules/uni-data-select/package.json b/uni_modules/uni-data-select/package.json new file mode 100644 index 0000000..0187429 --- /dev/null +++ b/uni_modules/uni-data-select/package.json @@ -0,0 +1,85 @@ +{ + "id": "uni-data-select", + "displayName": "uni-data-select 下拉框选择器", + "version": "1.0.6", + "description": "通过数据驱动的下拉框选择器", + "keywords": [ + "uni-ui", + "select", + "uni-data-select", + "下拉框", + "下拉选" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.1.1" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-load-more"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "u", + "app-nvue": "n" + }, + "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", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-data-select/readme.md b/uni_modules/uni-data-select/readme.md new file mode 100644 index 0000000..eb58de3 --- /dev/null +++ b/uni_modules/uni-data-select/readme.md @@ -0,0 +1,8 @@ +## DataSelect 下拉框选择器 +> **组件名:uni-data-select** +> 代码块: `uDataSelect` + +当选项过多时,使用下拉菜单展示并选择内容 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-select) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 diff --git a/uni_modules/uni-dateformat/changelog.md b/uni_modules/uni-dateformat/changelog.md new file mode 100644 index 0000000..d551d7b --- /dev/null +++ b/uni_modules/uni-dateformat/changelog.md @@ -0,0 +1,10 @@ +## 1.0.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-dateformat](https://uniapp.dcloud.io/component/uniui/uni-dateformat) +## 0.0.5(2021-07-08) +- 调整 默认时间不再是当前时间,而是显示'-'字符 +## 0.0.4(2021-05-12) +- 新增 组件示例地址 +## 0.0.3(2021-02-04) +- 调整为uni_modules目录规范 +- 修复 iOS 平台日期格式化出错的问题 diff --git a/uni_modules/uni-dateformat/components/uni-dateformat/date-format.js b/uni_modules/uni-dateformat/components/uni-dateformat/date-format.js new file mode 100644 index 0000000..e00d559 --- /dev/null +++ b/uni_modules/uni-dateformat/components/uni-dateformat/date-format.js @@ -0,0 +1,200 @@ +// yyyy-MM-dd hh:mm:ss.SSS 所有支持的类型 +function pad(str, length = 2) { + str += '' + while (str.length < length) { + str = '0' + str + } + return str.slice(-length) +} + +const parser = { + yyyy: (dateObj) => { + return pad(dateObj.year, 4) + }, + yy: (dateObj) => { + return pad(dateObj.year) + }, + MM: (dateObj) => { + return pad(dateObj.month) + }, + M: (dateObj) => { + return dateObj.month + }, + dd: (dateObj) => { + return pad(dateObj.day) + }, + d: (dateObj) => { + return dateObj.day + }, + hh: (dateObj) => { + return pad(dateObj.hour) + }, + h: (dateObj) => { + return dateObj.hour + }, + mm: (dateObj) => { + return pad(dateObj.minute) + }, + m: (dateObj) => { + return dateObj.minute + }, + ss: (dateObj) => { + return pad(dateObj.second) + }, + s: (dateObj) => { + return dateObj.second + }, + SSS: (dateObj) => { + return pad(dateObj.millisecond, 3) + }, + S: (dateObj) => { + return dateObj.millisecond + }, +} + +// 这都n年了iOS依然不认识2020-12-12,需要转换为2020/12/12 +function getDate(time) { + if (time instanceof Date) { + return time + } + switch (typeof time) { + case 'string': + { + // 2020-12-12T12:12:12.000Z、2020-12-12T12:12:12.000 + if (time.indexOf('T') > -1) { + return new Date(time) + } + return new Date(time.replace(/-/g, '/')) + } + default: + return new Date(time) + } +} + +export function formatDate(date, format = 'yyyy/MM/dd hh:mm:ss') { + if (!date && date !== 0) { + return '' + } + date = getDate(date) + const dateObj = { + year: date.getFullYear(), + month: date.getMonth() + 1, + day: date.getDate(), + hour: date.getHours(), + minute: date.getMinutes(), + second: date.getSeconds(), + millisecond: date.getMilliseconds() + } + const tokenRegExp = /yyyy|yy|MM|M|dd|d|hh|h|mm|m|ss|s|SSS|SS|S/ + let flag = true + let result = format + while (flag) { + flag = false + result = result.replace(tokenRegExp, function(matched) { + flag = true + return parser[matched](dateObj) + }) + } + return result +} + +export function friendlyDate(time, { + locale = 'zh', + threshold = [60000, 3600000], + format = 'yyyy/MM/dd hh:mm:ss' +}) { + if (time === '-') { + return time + } + if (!time && time !== 0) { + return '' + } + const localeText = { + zh: { + year: '年', + month: '月', + day: '天', + hour: '小时', + minute: '分钟', + second: '秒', + ago: '前', + later: '后', + justNow: '刚刚', + soon: '马上', + template: '{num}{unit}{suffix}' + }, + en: { + year: 'year', + month: 'month', + day: 'day', + hour: 'hour', + minute: 'minute', + second: 'second', + ago: 'ago', + later: 'later', + justNow: 'just now', + soon: 'soon', + template: '{num} {unit} {suffix}' + } + } + const text = localeText[locale] || localeText.zh + let date = getDate(time) + let ms = date.getTime() - Date.now() + let absMs = Math.abs(ms) + if (absMs < threshold[0]) { + return ms < 0 ? text.justNow : text.soon + } + if (absMs >= threshold[1]) { + return formatDate(date, format) + } + let num + let unit + let suffix = text.later + if (ms < 0) { + suffix = text.ago + ms = -ms + } + const seconds = Math.floor((ms) / 1000) + const minutes = Math.floor(seconds / 60) + const hours = Math.floor(minutes / 60) + const days = Math.floor(hours / 24) + const months = Math.floor(days / 30) + const years = Math.floor(months / 12) + switch (true) { + case years > 0: + num = years + unit = text.year + break + case months > 0: + num = months + unit = text.month + break + case days > 0: + num = days + unit = text.day + break + case hours > 0: + num = hours + unit = text.hour + break + case minutes > 0: + num = minutes + unit = text.minute + break + default: + num = seconds + unit = text.second + break + } + + if (locale === 'en') { + if (num === 1) { + num = 'a' + } else { + unit += 's' + } + } + + return text.template.replace(/{\s*num\s*}/g, num + '').replace(/{\s*unit\s*}/g, unit).replace(/{\s*suffix\s*}/g, + suffix) +} diff --git a/uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue b/uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue new file mode 100644 index 0000000..c5ed030 --- /dev/null +++ b/uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/uni_modules/uni-dateformat/package.json b/uni_modules/uni-dateformat/package.json new file mode 100644 index 0000000..786a670 --- /dev/null +++ b/uni_modules/uni-dateformat/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-dateformat", + "displayName": "uni-dateformat 日期格式化", + "version": "1.0.0", + "description": "日期格式化组件,可以将日期格式化为1分钟前、刚刚等形式", + "keywords": [ + "uni-ui", + "uniui", + "日期格式化", + "时间格式化", + "格式化时间", + "" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "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" + }, + "快应用": { + "华为": "y", + "联盟": "y" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-dateformat/readme.md b/uni_modules/uni-dateformat/readme.md new file mode 100644 index 0000000..37ddb6e --- /dev/null +++ b/uni_modules/uni-dateformat/readme.md @@ -0,0 +1,11 @@ + + +### DateFormat 日期格式化 +> **组件名:uni-dateformat** +> 代码块: `uDateformat` + + +日期格式化组件。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-dateformat) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-datetime-picker/changelog.md b/uni_modules/uni-datetime-picker/changelog.md new file mode 100644 index 0000000..8798e93 --- /dev/null +++ b/uni_modules/uni-datetime-picker/changelog.md @@ -0,0 +1,160 @@ +## 2.2.34(2024-04-24) +- 新增 日期点击事件,在点击日期时会触发该事件。 +## 2.2.33(2024-04-15) +- 修复 抖音小程序事件传递失效bug +## 2.2.32(2024-02-20) +- 修复 日历的close事件触发异常的bug [详情](https://github.com/dcloudio/uni-ui/issues/844) +## 2.2.31(2024-02-20) +- 修复 h5平台 右边日历的月份默认+1的bug [详情](https://github.com/dcloudio/uni-ui/issues/841) +## 2.2.30(2024-01-31) +- 修复 隐藏“秒”时,在IOS15及以下版本时出现 结束时间在开始时间之前 的bug [详情](https://github.com/dcloudio/uni-ui/issues/788) +## 2.2.29(2024-01-20) +- 新增 show事件,弹窗弹出时触发该事件 [详情](https://github.com/dcloudio/uni-app/issues/4694) +## 2.2.28(2024-01-18) +- 去除 noChange事件,当进行日期范围选择时,若只选了一天,则开始结束日期都为同一天 [详情](https://github.com/dcloudio/uni-ui/issues/815) +## 2.2.27(2024-01-10) +- 优化 增加noChange事件,当进行日期范围选择时,若有空值,则触发该事件 [详情](https://github.com/dcloudio/uni-ui/issues/815) +## 2.2.26(2024-01-08) +- 修复 字节小程序时间选择范围器失效问题 [详情](https://github.com/dcloudio/uni-ui/issues/834) +## 2.2.25(2023-10-18) +- 修复 PC端初次修改时间,开始时间未更新的Bug [详情](https://github.com/dcloudio/uni-ui/issues/737) +## 2.2.24(2023-06-02) +- 修复 部分情况修改时间,开始、结束时间显示异常的Bug [详情](https://ask.dcloud.net.cn/question/171146) +- 优化 当前月可以选择上月、下月的日期的Bug +## 2.2.23(2023-05-02) +- 修复 部分情况修改时间,开始时间未更新的Bug [详情](https://github.com/dcloudio/uni-ui/issues/737) +- 修复 部分平台及设备第一次点击无法显示弹框的Bug +- 修复 ios 日期格式未补零显示及使用异常的Bug [详情](https://ask.dcloud.net.cn/question/162979) +## 2.2.22(2023-03-30) +- 修复 日历 picker 修改年月后,自动选中当月1日的Bug [详情](https://ask.dcloud.net.cn/question/165937) +- 修复 小程序端 低版本 ios NaN的Bug [详情](https://ask.dcloud.net.cn/question/162979) +## 2.2.21(2023-02-20) +- 修复 firefox 浏览器显示区域点击无法拉起日历弹框的Bug [详情](https://ask.dcloud.net.cn/question/163362) +## 2.2.20(2023-02-17) +- 优化 值为空依然选中当天问题 +- 优化 提供 default-value 属性支持配置选择器打开时默认显示的时间 +- 优化 非范围选择未选择日期时间,点击确认按钮选中当前日期时间 +- 优化 字节小程序日期时间范围选择,底部日期换行的Bug +## 2.2.19(2023-02-09) +- 修复 2.2.18 引起范围选择配置 end 选择无效的Bug [详情](https://github.com/dcloudio/uni-ui/issues/686) +## 2.2.18(2023-02-08) +- 修复 移动端范围选择change事件触发异常的Bug [详情](https://github.com/dcloudio/uni-ui/issues/684) +- 优化 PC端输入日期格式错误时返回当前日期时间 +- 优化 PC端输入日期时间超出 start、end 限制的Bug +- 优化 移动端日期时间范围用法时间展示不完整问题 +## 2.2.17(2023-02-04) +- 修复 小程序端绑定 Date 类型报错的Bug [详情](https://github.com/dcloudio/uni-ui/issues/679) +- 修复 vue3 time-picker 无法显示绑定时分秒的Bug +## 2.2.16(2023-02-02) +- 修复 字节小程序报错的Bug +## 2.2.15(2023-02-02) +- 修复 某些情况切换月份错误的Bug +## 2.2.14(2023-01-30) +- 修复 某些情况切换月份错误的Bug [详情](https://ask.dcloud.net.cn/question/162033) +## 2.2.13(2023-01-10) +- 修复 多次加载组件造成内存占用的Bug +## 2.2.12(2022-12-01) +- 修复 vue3 下 i18n 国际化初始值不正确的Bug +## 2.2.11(2022-09-19) +- 修复 支付宝小程序样式错乱的Bug [详情](https://github.com/dcloudio/uni-app/issues/3861) +## 2.2.10(2022-09-19) +- 修复 反向选择日期范围,日期显示异常的Bug [详情](https://ask.dcloud.net.cn/question/153401?item_id=212892&rf=false) +## 2.2.9(2022-09-16) +- 可以使用 uni-scss 控制主题色 +## 2.2.8(2022-09-08) +- 修复 close事件无效的Bug +## 2.2.7(2022-09-05) +- 修复 移动端 maskClick 无效的Bug [详情](https://ask.dcloud.net.cn/question/140824) +## 2.2.6(2022-06-30) +- 优化 组件样式,调整了组件图标大小、高度、颜色等,与uni-ui风格保持一致 +## 2.2.5(2022-06-24) +- 修复 日历顶部年月及底部确认未国际化的Bug +## 2.2.4(2022-03-31) +- 修复 Vue3 下动态赋值,单选类型未响应的Bug +## 2.2.3(2022-03-28) +- 修复 Vue3 下动态赋值未响应的Bug +## 2.2.2(2021-12-10) +- 修复 clear-icon 属性在小程序平台不生效的Bug +## 2.2.1(2021-12-10) +- 修复 日期范围选在小程序平台,必须多点击一次才能取消选中状态的Bug +## 2.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源 [详情](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移 [https://uniapp.dcloud.io/component/uniui/uni-datetime-picker](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker) +## 2.1.5(2021-11-09) +- 新增 提供组件设计资源,组件样式调整 +## 2.1.4(2021-09-10) +- 修复 hide-second 在移动端的Bug +- 修复 单选赋默认值时,赋值日期未高亮的Bug +- 修复 赋默认值时,移动端未正确显示时间的Bug +## 2.1.3(2021-09-09) +- 新增 hide-second 属性,支持只使用时分,隐藏秒 +## 2.1.2(2021-09-03) +- 优化 取消选中时(范围选)直接开始下一次选择, 避免多点一次 +- 优化 移动端支持清除按钮,同时支持通过 ref 调用组件的 clear 方法 +- 优化 调整字号大小,美化日历界面 +- 修复 因国际化导致的 placeholder 失效的Bug +## 2.1.1(2021-08-24) +- 新增 支持国际化 +- 优化 范围选择器在 pc 端过宽的问题 +## 2.1.0(2021-08-09) +- 新增 适配 vue3 +## 2.0.19(2021-08-09) +- 新增 支持作为 uni-forms 子组件相关功能 +- 修复 在 uni-forms 中使用时,选择时间报 NAN 错误的Bug +## 2.0.18(2021-08-05) +- 修复 type 属性动态赋值无效的Bug +- 修复 ‘确认’按钮被 tabbar 遮盖 bug +- 修复 组件未赋值时范围选左、右日历相同的Bug +## 2.0.17(2021-08-04) +- 修复 范围选未正确显示当前值的Bug +- 修复 h5 平台(移动端)报错 'cale' of undefined 的Bug +## 2.0.16(2021-07-21) +- 新增 return-type 属性支持返回 date 日期对象 +## 2.0.15(2021-07-14) +- 修复 单选日期类型,初始赋值后不在当前日历的Bug +- 新增 clearIcon 属性,显示框的清空按钮可配置显示隐藏(仅 pc 有效) +- 优化 移动端移除显示框的清空按钮,无实际用途 +## 2.0.14(2021-07-14) +- 修复 组件赋值为空,界面未更新的Bug +- 修复 start 和 end 不能动态赋值的Bug +- 修复 范围选类型,用户选择后再次选择右侧日历(结束日期)显示不正确的Bug +## 2.0.13(2021-07-08) +- 修复 范围选择不能动态赋值的Bug +## 2.0.12(2021-07-08) +- 修复 范围选择的初始时间在一个月内时,造成无法选择的bug +## 2.0.11(2021-07-08) +- 优化 弹出层在超出视窗边缘定位不准确的问题 +## 2.0.10(2021-07-08) +- 修复 范围起始点样式的背景色与今日样式的字体前景色融合,导致日期字体看不清的Bug +- 优化 弹出层在超出视窗边缘被遮盖的问题 +## 2.0.9(2021-07-07) +- 新增 maskClick 事件 +- 修复 特殊情况日历 rpx 布局错误的Bug,rpx -> px +- 修复 范围选择时清空返回值不合理的bug,['', ''] -> [] +## 2.0.8(2021-07-07) +- 新增 日期时间显示框支持插槽 +## 2.0.7(2021-07-01) +- 优化 添加 uni-icons 依赖 +## 2.0.6(2021-05-22) +- 修复 图标在小程序上不显示的Bug +- 优化 重命名引用组件,避免潜在组件命名冲突 +## 2.0.5(2021-05-20) +- 优化 代码目录扁平化 +## 2.0.4(2021-05-12) +- 新增 组件示例地址 +## 2.0.3(2021-05-10) +- 修复 ios 下不识别 '-' 日期格式的Bug +- 优化 pc 下弹出层添加边框和阴影 +## 2.0.2(2021-05-08) +- 修复 在 admin 中获取弹出层定位错误的bug +## 2.0.1(2021-05-08) +- 修复 type 属性向下兼容,默认值从 date 变更为 datetime +## 2.0.0(2021-04-30) +- 支持日历形式的日期+时间的范围选择 + > 注意:此版本不向后兼容,不再支持单独时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker) +## 1.0.6(2021-03-18) +- 新增 hide-second 属性,时间支持仅选择时、分 +- 修复 选择跟显示的日期不一样的Bug +- 修复 chang事件触发2次的Bug +- 修复 分、秒 end 范围错误的Bug +- 优化 更好的 nvue 适配 diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue new file mode 100644 index 0000000..dba9887 --- /dev/null +++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue @@ -0,0 +1,177 @@ + + + + + diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.js b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.js new file mode 100644 index 0000000..b8d7d6f --- /dev/null +++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.js @@ -0,0 +1,546 @@ +/** +* @1900-2100区间内的公历、农历互转 +* @charset UTF-8 +* @github https://github.com/jjonline/calendar.js +* @Author Jea杨(JJonline@JJonline.Cn) +* @Time 2014-7-21 +* @Time 2016-8-13 Fixed 2033hex、Attribution Annals +* @Time 2016-9-25 Fixed lunar LeapMonth Param Bug +* @Time 2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year +* @Version 1.0.3 +* @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0] +* @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0] +*/ +/* eslint-disable */ +var calendar = { + + /** + * 农历1900-2100的润大小信息表 + * @Array Of Property + * @return Hex + */ + lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909 + 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919 + 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929 + 0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939 + 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949 + 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959 + 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969 + 0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979 + 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989 + 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999 + 0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009 + 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019 + 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029 + 0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039 + 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049 + /** Add By JJonline@JJonline.Cn**/ + 0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059 + 0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069 + 0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079 + 0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089 + 0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099 + 0x0d520], // 2100 + + /** + * 公历每个月份的天数普通表 + * @Array Of Property + * @return Number + */ + solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], + + /** + * 天干地支之天干速查表 + * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"] + * @return Cn string + */ + Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'], + + /** + * 天干地支之地支速查表 + * @Array Of Property + * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"] + * @return Cn string + */ + Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5'], + + /** + * 天干地支之地支速查表<=>生肖 + * @Array Of Property + * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"] + * @return Cn string + */ + Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', '\u72d7', '\u732a'], + + /** + * 24节气速查表 + * @Array Of Property + * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"] + * @return Cn string + */ + solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3'], + + /** + * 1900-2100各年的24节气日期速查表 + * @Array Of Property + * @return 0x string For splice + */ + sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', + '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', + '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', + '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', + 'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f', + '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa', + '97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', + '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f', + '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', + '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', + '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', + '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', + '97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722', + '9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f', + '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e', + '97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', + '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722', + '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', + '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', + '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722', + '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', + '97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', + '9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', + '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e', + '97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', + '9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722', + '7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', + '7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', + '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', + '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', + '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa', + '97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', + '9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', + '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721', + '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2', + '977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722', + '7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', + '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd', + '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', + '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', + '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', + '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', + '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', + '977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', + '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721', + '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5', + '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722', + '7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', + '7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd', + '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', + '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', + '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721', + '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd', + '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35', + '7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', + '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721', + '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5', + '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35', + '665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', + '7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd', + '7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35', + '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'], + + /** + * 数字转中文速查表 + * @Array Of Property + * @trans ['日','一','二','三','四','五','六','七','八','九','十'] + * @return Cn string + */ + nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341'], + + /** + * 日期转农历称呼速查表 + * @Array Of Property + * @trans ['初','十','廿','卅'] + * @return Cn string + */ + nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'], + + /** + * 月份转农历称呼速查表 + * @Array Of Property + * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊'] + * @return Cn string + */ + nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a'], + + /** + * 返回农历y年一整年的总天数 + * @param lunar Year + * @return Number + * @eg:var count = calendar.lYearDays(1987) ;//count=387 + */ + lYearDays: function (y) { + var i; var sum = 348 + for (i = 0x8000; i > 0x8; i >>= 1) { sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 } + return (sum + this.leapDays(y)) + }, + + /** + * 返回农历y年闰月是哪个月;若y年没有闰月 则返回0 + * @param lunar Year + * @return Number (0-12) + * @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6 + */ + leapMonth: function (y) { // 闰字编码 \u95f0 + return (this.lunarInfo[y - 1900] & 0xf) + }, + + /** + * 返回农历y年闰月的天数 若该年没有闰月则返回0 + * @param lunar Year + * @return Number (0、29、30) + * @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29 + */ + leapDays: function (y) { + if (this.leapMonth(y)) { + return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29) + } + return (0) + }, + + /** + * 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法 + * @param lunar Year + * @return Number (-1、29、30) + * @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29 + */ + monthDays: function (y, m) { + if (m > 12 || m < 1) { return -1 }// 月份参数从1至12,参数错误返回-1 + return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29) + }, + + /** + * 返回公历(!)y年m月的天数 + * @param solar Year + * @return Number (-1、28、29、30、31) + * @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30 + */ + solarDays: function (y, m) { + if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1 + var ms = m - 1 + if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29 + return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28) + } else { + return (this.solarMonth[ms]) + } + }, + + /** + * 农历年份转换为干支纪年 + * @param lYear 农历年的年份数 + * @return Cn string + */ + toGanZhiYear: function (lYear) { + var ganKey = (lYear - 3) % 10 + var zhiKey = (lYear - 3) % 12 + if (ganKey == 0) ganKey = 10// 如果余数为0则为最后一个天干 + if (zhiKey == 0) zhiKey = 12// 如果余数为0则为最后一个地支 + return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1] + }, + + /** + * 公历月、日判断所属星座 + * @param cMonth [description] + * @param cDay [description] + * @return Cn string + */ + toAstro: function (cMonth, cDay) { + var s = '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf' + var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22] + return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7'// 座 + }, + + /** + * 传入offset偏移量返回干支 + * @param offset 相对甲子的偏移量 + * @return Cn string + */ + toGanZhi: function (offset) { + return this.Gan[offset % 10] + this.Zhi[offset % 12] + }, + + /** + * 传入公历(!)y年获得该年第n个节气的公历日期 + * @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起 + * @return day Number + * @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春 + */ + getTerm: function (y, n) { + if (y < 1900 || y > 2100) { return -1 } + if (n < 1 || n > 24) { return -1 } + var _table = this.sTermInfo[y - 1900] + var _info = [ + parseInt('0x' + _table.substr(0, 5)).toString(), + parseInt('0x' + _table.substr(5, 5)).toString(), + parseInt('0x' + _table.substr(10, 5)).toString(), + parseInt('0x' + _table.substr(15, 5)).toString(), + parseInt('0x' + _table.substr(20, 5)).toString(), + parseInt('0x' + _table.substr(25, 5)).toString() + ] + var _calday = [ + _info[0].substr(0, 1), + _info[0].substr(1, 2), + _info[0].substr(3, 1), + _info[0].substr(4, 2), + + _info[1].substr(0, 1), + _info[1].substr(1, 2), + _info[1].substr(3, 1), + _info[1].substr(4, 2), + + _info[2].substr(0, 1), + _info[2].substr(1, 2), + _info[2].substr(3, 1), + _info[2].substr(4, 2), + + _info[3].substr(0, 1), + _info[3].substr(1, 2), + _info[3].substr(3, 1), + _info[3].substr(4, 2), + + _info[4].substr(0, 1), + _info[4].substr(1, 2), + _info[4].substr(3, 1), + _info[4].substr(4, 2), + + _info[5].substr(0, 1), + _info[5].substr(1, 2), + _info[5].substr(3, 1), + _info[5].substr(4, 2) + ] + return parseInt(_calday[n - 1]) + }, + + /** + * 传入农历数字月份返回汉语通俗表示法 + * @param lunar month + * @return Cn string + * @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月' + */ + toChinaMonth: function (m) { // 月 => \u6708 + if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1 + var s = this.nStr3[m - 1] + s += '\u6708'// 加上月字 + return s + }, + + /** + * 传入农历日期数字返回汉字表示法 + * @param lunar day + * @return Cn string + * @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一' + */ + toChinaDay: function (d) { // 日 => \u65e5 + var s + switch (d) { + case 10: + s = '\u521d\u5341'; break + case 20: + s = '\u4e8c\u5341'; break + break + case 30: + s = '\u4e09\u5341'; break + break + default : + s = this.nStr2[Math.floor(d / 10)] + s += this.nStr1[d % 10] + } + return (s) + }, + + /** + * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春” + * @param y year + * @return Cn string + * @eg:var animal = calendar.getAnimal(1987) ;//animal='兔' + */ + getAnimal: function (y) { + return this.Animals[(y - 4) % 12] + }, + + /** + * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON + * @param y solar year + * @param m solar month + * @param d solar day + * @return JSON object + * @eg:console.log(calendar.solar2lunar(1987,11,01)); + */ + solar2lunar: function (y, m, d) { // 参数区间1900.1.31~2100.12.31 + // 年份限定、上限 + if (y < 1900 || y > 2100) { + return -1// undefined转换为数字变为NaN + } + // 公历传参最下限 + if (y == 1900 && m == 1 && d < 31) { + return -1 + } + // 未传参 获得当天 + if (!y) { + var objDate = new Date() + } else { + var objDate = new Date(y, parseInt(m) - 1, d) + } + var i; var leap = 0; var temp = 0 + // 修正ymd参数 + var y = objDate.getFullYear() + var m = objDate.getMonth() + 1 + var d = objDate.getDate() + var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000 + for (i = 1900; i < 2101 && offset > 0; i++) { + temp = this.lYearDays(i) + offset -= temp + } + if (offset < 0) { + offset += temp; i-- + } + + // 是否今天 + var isTodayObj = new Date() + var isToday = false + if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) { + isToday = true + } + // 星期几 + var nWeek = objDate.getDay() + var cWeek = this.nStr1[nWeek] + // 数字表示周几顺应天朝周一开始的惯例 + if (nWeek == 0) { + nWeek = 7 + } + // 农历年 + var year = i + var leap = this.leapMonth(i) // 闰哪个月 + var isLeap = false + + // 效验闰月 + for (i = 1; i < 13 && offset > 0; i++) { + // 闰月 + if (leap > 0 && i == (leap + 1) && isLeap == false) { + --i + isLeap = true; temp = this.leapDays(year) // 计算农历闰月天数 + } else { + temp = this.monthDays(year, i)// 计算农历普通月天数 + } + // 解除闰月 + if (isLeap == true && i == (leap + 1)) { isLeap = false } + offset -= temp + } + // 闰月导致数组下标重叠取反 + if (offset == 0 && leap > 0 && i == leap + 1) { + if (isLeap) { + isLeap = false + } else { + isLeap = true; --i + } + } + if (offset < 0) { + offset += temp; --i + } + // 农历月 + var month = i + // 农历日 + var day = offset + 1 + // 天干地支处理 + var sm = m - 1 + var gzY = this.toGanZhiYear(year) + + // 当月的两个节气 + // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year` + var firstNode = this.getTerm(y, (m * 2 - 1))// 返回当月「节」为几日开始 + var secondNode = this.getTerm(y, (m * 2))// 返回当月「节」为几日开始 + + // 依据12节气修正干支月 + var gzM = this.toGanZhi((y - 1900) * 12 + m + 11) + if (d >= firstNode) { + gzM = this.toGanZhi((y - 1900) * 12 + m + 12) + } + + // 传入的日期的节气与否 + var isTerm = false + var Term = null + if (firstNode == d) { + isTerm = true + Term = this.solarTerm[m * 2 - 2] + } + if (secondNode == d) { + isTerm = true + Term = this.solarTerm[m * 2 - 1] + } + // 日柱 当月一日与 1900/1/1 相差天数 + var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10 + var gzD = this.toGanZhi(dayCyclical + d - 1) + // 该日期所属的星座 + var astro = this.toAstro(m, d) + + return { 'lYear': year, 'lMonth': month, 'lDay': day, 'Animal': this.getAnimal(year), 'IMonthCn': (isLeap ? '\u95f0' : '') + this.toChinaMonth(month), 'IDayCn': this.toChinaDay(day), 'cYear': y, 'cMonth': m, 'cDay': d, 'gzYear': gzY, 'gzMonth': gzM, 'gzDay': gzD, 'isToday': isToday, 'isLeap': isLeap, 'nWeek': nWeek, 'ncWeek': '\u661f\u671f' + cWeek, 'isTerm': isTerm, 'Term': Term, 'astro': astro } + }, + + /** + * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON + * @param y lunar year + * @param m lunar month + * @param d lunar day + * @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可] + * @return JSON object + * @eg:console.log(calendar.lunar2solar(1987,9,10)); + */ + lunar2solar: function (y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1 + var isLeapMonth = !!isLeapMonth + var leapOffset = 0 + var leapMonth = this.leapMonth(y) + var leapDay = this.leapDays(y) + if (isLeapMonth && (leapMonth != m)) { return -1 }// 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同 + if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { return -1 }// 超出了最大极限值 + var day = this.monthDays(y, m) + var _day = day + // bugFix 2016-9-25 + // if month is leap, _day use leapDays method + if (isLeapMonth) { + _day = this.leapDays(y, m) + } + if (y < 1900 || y > 2100 || d > _day) { return -1 }// 参数合法性效验 + + // 计算农历的时间差 + var offset = 0 + for (var i = 1900; i < y; i++) { + offset += this.lYearDays(i) + } + var leap = 0; var isAdd = false + for (var i = 1; i < m; i++) { + leap = this.leapMonth(y) + if (!isAdd) { // 处理闰月 + if (leap <= i && leap > 0) { + offset += this.leapDays(y); isAdd = true + } + } + offset += this.monthDays(y, i) + } + // 转换闰月农历 需补充该年闰月的前一个月的时差 + if (isLeapMonth) { offset += day } + // 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点) + var stmap = Date.UTC(1900, 1, 30, 0, 0, 0) + var calObj = new Date((offset + d - 31) * 86400000 + stmap) + var cY = calObj.getUTCFullYear() + var cM = calObj.getUTCMonth() + 1 + var cD = calObj.getUTCDate() + + return this.solar2lunar(cY, cM, cD) + } +} + +export default calendar diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue new file mode 100644 index 0000000..0f9e121 --- /dev/null +++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue @@ -0,0 +1,947 @@ + + + + + diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json new file mode 100644 index 0000000..024f22f --- /dev/null +++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json @@ -0,0 +1,22 @@ +{ + "uni-datetime-picker.selectDate": "select date", + "uni-datetime-picker.selectTime": "select time", + "uni-datetime-picker.selectDateTime": "select date and time", + "uni-datetime-picker.startDate": "start date", + "uni-datetime-picker.endDate": "end date", + "uni-datetime-picker.startTime": "start time", + "uni-datetime-picker.endTime": "end time", + "uni-datetime-picker.ok": "ok", + "uni-datetime-picker.clear": "clear", + "uni-datetime-picker.cancel": "cancel", + "uni-datetime-picker.year": "-", + "uni-datetime-picker.month": "", + "uni-calender.MON": "MON", + "uni-calender.TUE": "TUE", + "uni-calender.WED": "WED", + "uni-calender.THU": "THU", + "uni-calender.FRI": "FRI", + "uni-calender.SAT": "SAT", + "uni-calender.SUN": "SUN", + "uni-calender.confirm": "confirm" +} diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js new file mode 100644 index 0000000..de7509c --- /dev/null +++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json new file mode 100644 index 0000000..d2df5e7 --- /dev/null +++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json @@ -0,0 +1,22 @@ +{ + "uni-datetime-picker.selectDate": "选择日期", + "uni-datetime-picker.selectTime": "选择时间", + "uni-datetime-picker.selectDateTime": "选择日期时间", + "uni-datetime-picker.startDate": "开始日期", + "uni-datetime-picker.endDate": "结束日期", + "uni-datetime-picker.startTime": "开始时间", + "uni-datetime-picker.endTime": "结束时间", + "uni-datetime-picker.ok": "确定", + "uni-datetime-picker.clear": "清除", + "uni-datetime-picker.cancel": "取消", + "uni-datetime-picker.year": "年", + "uni-datetime-picker.month": "月", + "uni-calender.SUN": "日", + "uni-calender.MON": "一", + "uni-calender.TUE": "二", + "uni-calender.WED": "三", + "uni-calender.THU": "四", + "uni-calender.FRI": "五", + "uni-calender.SAT": "六", + "uni-calender.confirm": "确认" +} \ No newline at end of file diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json new file mode 100644 index 0000000..d23fa3c --- /dev/null +++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json @@ -0,0 +1,22 @@ +{ + "uni-datetime-picker.selectDate": "選擇日期", + "uni-datetime-picker.selectTime": "選擇時間", + "uni-datetime-picker.selectDateTime": "選擇日期時間", + "uni-datetime-picker.startDate": "開始日期", + "uni-datetime-picker.endDate": "結束日期", + "uni-datetime-picker.startTime": "開始时间", + "uni-datetime-picker.endTime": "結束时间", + "uni-datetime-picker.ok": "確定", + "uni-datetime-picker.clear": "清除", + "uni-datetime-picker.cancel": "取消", + "uni-datetime-picker.year": "年", + "uni-datetime-picker.month": "月", + "uni-calender.SUN": "日", + "uni-calender.MON": "一", + "uni-calender.TUE": "二", + "uni-calender.WED": "三", + "uni-calender.THU": "四", + "uni-calender.FRI": "五", + "uni-calender.SAT": "六", + "uni-calender.confirm": "確認" +} \ No newline at end of file diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/keypress.js b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/keypress.js new file mode 100644 index 0000000..9601aba --- /dev/null +++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/keypress.js @@ -0,0 +1,45 @@ +// #ifdef H5 +export default { + name: 'Keypress', + props: { + disable: { + type: Boolean, + default: false + } + }, + mounted () { + const keyNames = { + esc: ['Esc', 'Escape'], + tab: 'Tab', + enter: 'Enter', + space: [' ', 'Spacebar'], + up: ['Up', 'ArrowUp'], + left: ['Left', 'ArrowLeft'], + right: ['Right', 'ArrowRight'], + down: ['Down', 'ArrowDown'], + delete: ['Backspace', 'Delete', 'Del'] + } + const listener = ($event) => { + if (this.disable) { + return + } + const keyName = Object.keys(keyNames).find(key => { + const keyName = $event.key + const value = keyNames[key] + return value === keyName || (Array.isArray(value) && value.includes(keyName)) + }) + if (keyName) { + // 避免和其他按键事件冲突 + setTimeout(() => { + this.$emit(keyName, {}) + }, 0) + } + } + document.addEventListener('keyup', listener) + this.$once('hook:beforeDestroy', () => { + document.removeEventListener('keyup', listener) + }) + }, + render: () => {} +} +// #endif \ No newline at end of file diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue new file mode 100644 index 0000000..1817692 --- /dev/null +++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue @@ -0,0 +1,940 @@ + + + + + diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue new file mode 100644 index 0000000..11fc45a --- /dev/null +++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue @@ -0,0 +1,1057 @@ + + + + diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js new file mode 100644 index 0000000..01802fa --- /dev/null +++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js @@ -0,0 +1,421 @@ +class Calendar { + constructor({ + selected, + startDate, + endDate, + range, + } = {}) { + // 当前日期 + this.date = this.getDateObj(new Date()) // 当前初入日期 + // 打点信息 + this.selected = selected || []; + // 起始时间 + this.startDate = startDate + // 终止时间 + this.endDate = endDate + // 是否范围选择 + this.range = range + // 多选状态 + this.cleanMultipleStatus() + // 每周日期 + this.weeks = {} + this.lastHover = false + } + /** + * 设置日期 + * @param {Object} date + */ + setDate(date) { + const selectDate = this.getDateObj(date) + this.getWeeks(selectDate.fullDate) + } + + /** + * 清理多选状态 + */ + cleanMultipleStatus() { + this.multipleStatus = { + before: '', + after: '', + data: [] + } + } + + setStartDate(startDate) { + this.startDate = startDate + } + + setEndDate(endDate) { + this.endDate = endDate + } + + getPreMonthObj(date) { + date = fixIosDateFormat(date) + date = new Date(date) + + const oldMonth = date.getMonth() + date.setMonth(oldMonth - 1) + const newMonth = date.getMonth() + if (oldMonth !== 0 && newMonth - oldMonth === 0) { + date.setMonth(newMonth - 1) + } + return this.getDateObj(date) + } + getNextMonthObj(date) { + date = fixIosDateFormat(date) + date = new Date(date) + + const oldMonth = date.getMonth() + date.setMonth(oldMonth + 1) + const newMonth = date.getMonth() + if (newMonth - oldMonth > 1) { + date.setMonth(newMonth - 1) + } + return this.getDateObj(date) + } + + /** + * 获取指定格式Date对象 + */ + getDateObj(date) { + date = fixIosDateFormat(date) + date = new Date(date) + + return { + fullDate: getDate(date), + year: date.getFullYear(), + month: addZero(date.getMonth() + 1), + date: addZero(date.getDate()), + day: date.getDay() + } + } + + /** + * 获取上一个月日期集合 + */ + getPreMonthDays(amount, dateObj) { + const result = [] + for (let i = amount - 1; i >= 0; i--) { + const month = dateObj.month - 1 + result.push({ + date: new Date(dateObj.year, month, -i).getDate(), + month, + disable: true + }) + } + return result + } + /** + * 获取本月日期集合 + */ + getCurrentMonthDays(amount, dateObj) { + const result = [] + const fullDate = this.date.fullDate + for (let i = 1; i <= amount; i++) { + const currentDate = `${dateObj.year}-${dateObj.month}-${addZero(i)}` + const isToday = fullDate === currentDate + // 获取打点信息 + const info = this.selected && this.selected.find((item) => { + if (this.dateEqual(currentDate, item.date)) { + return item + } + }) + + // 日期禁用 + let disableBefore = true + let disableAfter = true + if (this.startDate) { + disableBefore = dateCompare(this.startDate, currentDate) + } + + if (this.endDate) { + disableAfter = dateCompare(currentDate, this.endDate) + } + + let multiples = this.multipleStatus.data + let multiplesStatus = -1 + if (this.range && multiples) { + multiplesStatus = multiples.findIndex((item) => { + return this.dateEqual(item, currentDate) + }) + } + const checked = multiplesStatus !== -1 + + result.push({ + fullDate: currentDate, + year: dateObj.year, + date: i, + multiple: this.range ? checked : false, + beforeMultiple: this.isLogicBefore(currentDate, this.multipleStatus.before, this.multipleStatus.after), + afterMultiple: this.isLogicAfter(currentDate, this.multipleStatus.before, this.multipleStatus.after), + month: dateObj.month, + disable: (this.startDate && !dateCompare(this.startDate, currentDate)) || (this.endDate && !dateCompare( + currentDate, this.endDate)), + isToday, + userChecked: false, + extraInfo: info + }) + } + return result + } + /** + * 获取下一个月日期集合 + */ + _getNextMonthDays(amount, dateObj) { + const result = [] + const month = dateObj.month + 1 + for (let i = 1; i <= amount; i++) { + result.push({ + date: i, + month, + disable: true + }) + } + return result + } + + /** + * 获取当前日期详情 + * @param {Object} date + */ + getInfo(date) { + if (!date) { + date = new Date() + } + + return this.calendar.find(item => item.fullDate === this.getDateObj(date).fullDate) + } + + /** + * 比较时间是否相等 + */ + dateEqual(before, after) { + before = new Date(fixIosDateFormat(before)) + after = new Date(fixIosDateFormat(after)) + return before.valueOf() === after.valueOf() + } + + /** + * 比较真实起始日期 + */ + + isLogicBefore(currentDate, before, after) { + let logicBefore = before + if (before && after) { + logicBefore = dateCompare(before, after) ? before : after + } + return this.dateEqual(logicBefore, currentDate) + } + + isLogicAfter(currentDate, before, after) { + let logicAfter = after + if (before && after) { + logicAfter = dateCompare(before, after) ? after : before + } + return this.dateEqual(logicAfter, currentDate) + } + + /** + * 获取日期范围内所有日期 + * @param {Object} begin + * @param {Object} end + */ + geDateAll(begin, end) { + var arr = [] + var ab = begin.split('-') + var ae = end.split('-') + var db = new Date() + db.setFullYear(ab[0], ab[1] - 1, ab[2]) + var de = new Date() + de.setFullYear(ae[0], ae[1] - 1, ae[2]) + var unixDb = db.getTime() - 24 * 60 * 60 * 1000 + var unixDe = de.getTime() - 24 * 60 * 60 * 1000 + for (var k = unixDb; k <= unixDe;) { + k = k + 24 * 60 * 60 * 1000 + arr.push(this.getDateObj(new Date(parseInt(k))).fullDate) + } + return arr + } + + /** + * 获取多选状态 + */ + setMultiple(fullDate) { + if (!this.range) return + + let { + before, + after + } = this.multipleStatus + if (before && after) { + if (!this.lastHover) { + this.lastHover = true + return + } + this.multipleStatus.before = fullDate + this.multipleStatus.after = '' + this.multipleStatus.data = [] + this.multipleStatus.fulldate = '' + this.lastHover = false + } else { + if (!before) { + this.multipleStatus.before = fullDate + this.multipleStatus.after = undefined; + this.lastHover = false + } else { + this.multipleStatus.after = fullDate + if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) { + this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus + .after); + } else { + this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus + .before); + } + this.lastHover = true + } + } + this.getWeeks(fullDate) + } + + /** + * 鼠标 hover 更新多选状态 + */ + setHoverMultiple(fullDate) { + //抖音小程序点击会触发hover事件,需要避免一下 + // #ifndef MP-TOUTIAO + if (!this.range || this.lastHover) return + const { + before + } = this.multipleStatus + + if (!before) { + this.multipleStatus.before = fullDate + } else { + this.multipleStatus.after = fullDate + if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) { + this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after); + } else { + this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before); + } + } + this.getWeeks(fullDate) + // #endif + + } + + /** + * 更新默认值多选状态 + */ + setDefaultMultiple(before, after) { + this.multipleStatus.before = before + this.multipleStatus.after = after + if (before && after) { + if (dateCompare(before, after)) { + this.multipleStatus.data = this.geDateAll(before, after); + this.getWeeks(after) + } else { + this.multipleStatus.data = this.geDateAll(after, before); + this.getWeeks(before) + } + } + } + + /** + * 获取每周数据 + * @param {Object} dateData + */ + getWeeks(dateData) { + const { + year, + month, + } = this.getDateObj(dateData) + + const preMonthDayAmount = new Date(year, month - 1, 1).getDay() + const preMonthDays = this.getPreMonthDays(preMonthDayAmount, this.getDateObj(dateData)) + + const currentMonthDayAmount = new Date(year, month, 0).getDate() + const currentMonthDays = this.getCurrentMonthDays(currentMonthDayAmount, this.getDateObj(dateData)) + + const nextMonthDayAmount = 42 - preMonthDayAmount - currentMonthDayAmount + const nextMonthDays = this._getNextMonthDays(nextMonthDayAmount, this.getDateObj(dateData)) + + const calendarDays = [...preMonthDays, ...currentMonthDays, ...nextMonthDays] + + const weeks = new Array(6) + for (let i = 0; i < calendarDays.length; i++) { + const index = Math.floor(i / 7) + if (!weeks[index]) { + weeks[index] = new Array(7) + } + weeks[index][i % 7] = calendarDays[i] + } + + this.calendar = calendarDays + this.weeks = weeks + } +} + +function getDateTime(date, hideSecond) { + return `${getDate(date)} ${getTime(date, hideSecond)}` +} + +function getDate(date) { + date = fixIosDateFormat(date) + date = new Date(date) + const year = date.getFullYear() + const month = date.getMonth() + 1 + const day = date.getDate() + return `${year}-${addZero(month)}-${addZero(day)}` +} + +function getTime(date, hideSecond) { + date = fixIosDateFormat(date) + date = new Date(date) + const hour = date.getHours() + const minute = date.getMinutes() + const second = date.getSeconds() + return hideSecond ? `${addZero(hour)}:${addZero(minute)}` : `${addZero(hour)}:${addZero(minute)}:${addZero(second)}` +} + +function addZero(num) { + if (num < 10) { + num = `0${num}` + } + return num +} + +function getDefaultSecond(hideSecond) { + return hideSecond ? '00:00' : '00:00:00' +} + +function dateCompare(startDate, endDate) { + startDate = new Date(fixIosDateFormat(startDate)) + endDate = new Date(fixIosDateFormat(endDate)) + return startDate <= endDate +} + +function checkDate(date) { + const dateReg = /((19|20)\d{2})(-|\/)\d{1,2}(-|\/)\d{1,2}/g + return date.match(dateReg) +} +//ios低版本15及以下,无法匹配 没有 ’秒‘ 时的情况,所以需要在末尾 秒 加上 问号 +const dateTimeReg = /^\d{4}-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])( [0-5]?[0-9]:[0-5]?[0-9](:[0-5]?[0-9])?)?$/; + +function fixIosDateFormat(value) { + if (typeof value === 'string' && dateTimeReg.test(value)) { + value = value.replace(/-/g, '/') + } + return value +} + +export { + Calendar, + getDateTime, + getDate, + getTime, + addZero, + getDefaultSecond, + dateCompare, + checkDate, + fixIosDateFormat +} diff --git a/uni_modules/uni-datetime-picker/package.json b/uni_modules/uni-datetime-picker/package.json new file mode 100644 index 0000000..4d1b05c --- /dev/null +++ b/uni_modules/uni-datetime-picker/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-datetime-picker", + "displayName": "uni-datetime-picker 日期选择器", + "version": "2.2.34", + "description": "uni-datetime-picker 日期时间选择器,支持日历,支持范围选择", + "keywords": [ + "uni-datetime-picker", + "uni-ui", + "uniui", + "日期时间选择器", + "日期时间" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "n" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-datetime-picker/readme.md b/uni_modules/uni-datetime-picker/readme.md new file mode 100644 index 0000000..162fbef --- /dev/null +++ b/uni_modules/uni-datetime-picker/readme.md @@ -0,0 +1,21 @@ + + +> `重要通知:组件升级更新 2.0.0 后,支持日期+时间范围选择,组件 ui 将使用日历选择日期,ui 变化较大,同时支持 PC 和 移动端。此版本不向后兼容,不再支持单独的时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker)。若仍需使用旧版本,可在插件市场下载*非uni_modules版本*,旧版本将不再维护` + +## DatetimePicker 时间选择器 + +> **组件名:uni-datetime-picker** +> 代码块: `uDatetimePicker` + + +该组件的优势是,支持**时间戳**输入和输出(起始时间、终止时间也支持时间戳),可**同时选择**日期和时间。 + +若只是需要单独选择日期和时间,不需要时间戳输入和输出,可使用原生的 picker 组件。 + +**_点击 picker 默认值规则:_** + +- 若设置初始值 value, 会显示在 picker 显示框中 +- 若无初始值 value,则初始值 value 为当前本地时间 Date.now(), 但不会显示在 picker 显示框中 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-drawer/changelog.md b/uni_modules/uni-drawer/changelog.md new file mode 100644 index 0000000..6d2488c --- /dev/null +++ b/uni_modules/uni-drawer/changelog.md @@ -0,0 +1,13 @@ +## 1.2.1(2021-11-22) +- 修复 vue3中个别scss变量无法找到的问题 +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-drawer](https://uniapp.dcloud.io/component/uniui/uni-drawer) +## 1.1.1(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.1.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.7(2021-05-12) +- 新增 组件示例地址 +## 1.0.6(2021-02-04) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-drawer/components/uni-drawer/keypress.js b/uni_modules/uni-drawer/components/uni-drawer/keypress.js new file mode 100644 index 0000000..62dda46 --- /dev/null +++ b/uni_modules/uni-drawer/components/uni-drawer/keypress.js @@ -0,0 +1,45 @@ +// #ifdef H5 +export default { + name: 'Keypress', + props: { + disable: { + type: Boolean, + default: false + } + }, + mounted () { + const keyNames = { + esc: ['Esc', 'Escape'], + tab: 'Tab', + enter: 'Enter', + space: [' ', 'Spacebar'], + up: ['Up', 'ArrowUp'], + left: ['Left', 'ArrowLeft'], + right: ['Right', 'ArrowRight'], + down: ['Down', 'ArrowDown'], + delete: ['Backspace', 'Delete', 'Del'] + } + const listener = ($event) => { + if (this.disable) { + return + } + const keyName = Object.keys(keyNames).find(key => { + const keyName = $event.key + const value = keyNames[key] + return value === keyName || (Array.isArray(value) && value.includes(keyName)) + }) + if (keyName) { + // 避免和其他按键事件冲突 + setTimeout(() => { + this.$emit(keyName, {}) + }, 0) + } + } + document.addEventListener('keyup', listener) + // this.$once('hook:beforeDestroy', () => { + // document.removeEventListener('keyup', listener) + // }) + }, + render: () => {} +} +// #endif diff --git a/uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue b/uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue new file mode 100644 index 0000000..2471521 --- /dev/null +++ b/uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue @@ -0,0 +1,183 @@ + + + + + diff --git a/uni_modules/uni-drawer/package.json b/uni_modules/uni-drawer/package.json new file mode 100644 index 0000000..dd056e4 --- /dev/null +++ b/uni_modules/uni-drawer/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-drawer", + "displayName": "uni-drawer 抽屉", + "version": "1.2.1", + "description": "抽屉式导航,用于展示侧滑菜单,侧滑导航。", + "keywords": [ + "uni-ui", + "uniui", + "drawer", + "抽屉", + "侧滑导航" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-drawer/readme.md b/uni_modules/uni-drawer/readme.md new file mode 100644 index 0000000..dcf6e6b --- /dev/null +++ b/uni_modules/uni-drawer/readme.md @@ -0,0 +1,10 @@ + + +## Drawer 抽屉 +> **组件名:uni-drawer** +> 代码块: `uDrawer` + +抽屉侧滑菜单。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-drawer) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-easyinput/changelog.md b/uni_modules/uni-easyinput/changelog.md new file mode 100644 index 0000000..6677b07 --- /dev/null +++ b/uni_modules/uni-easyinput/changelog.md @@ -0,0 +1,113 @@ +## 1.1.18(2024-04-11) +- 修复 easyinput组件双向绑定问题 +## 1.1.17(2024-03-28) +- 修复 在头条小程序下丢失事件绑定的问题 +## 1.1.16(2024-03-20) +- 修复 在密码输入情况下 清除和小眼睛覆盖bug 在edge浏览器下显示双眼睛bug +## 1.1.15(2024-02-21) +- 新增 左侧插槽:left +## 1.1.14(2024-02-19) +- 修复 onBlur的emit传值错误 +## 1.1.12(2024-01-29) +- 补充 adjust-position文档属性补充 +## 1.1.11(2024-01-29) +- 补充 adjust-position属性传递值:(Boolean)当键盘弹起时,是否自动上推页面 +## 1.1.10(2024-01-22) +- 去除 移除无用的log输出 +## 1.1.9(2023-04-11) +- 修复 vue3 下 keyboardheightchange 事件报错的bug +## 1.1.8(2023-03-29) +- 优化 trim 属性默认值 +## 1.1.7(2023-03-29) +- 新增 cursor-spacing 属性 +## 1.1.6(2023-01-28) +- 新增 keyboardheightchange 事件,可监听键盘高度变化 +## 1.1.5(2022-11-29) +- 优化 主题样式 +## 1.1.4(2022-10-27) +- 修复 props 中背景颜色无默认值的bug +## 1.1.0(2022-06-30) + +- 新增 在 uni-forms 1.4.0 中使用可以在 blur 时校验内容 +- 新增 clear 事件,点击右侧叉号图标触发 +- 新增 change 事件 ,仅在输入框失去焦点或用户按下回车时触发 +- 优化 组件样式,组件获取焦点时高亮显示,图标颜色调整等 + +## 1.0.5(2022-06-07) + +- 优化 clearable 显示策略 + +## 1.0.4(2022-06-07) + +- 优化 clearable 显示策略 + +## 1.0.3(2022-05-20) + +- 修复 关闭图标某些情况下无法取消的 bug + +## 1.0.2(2022-04-12) + +- 修复 默认值不生效的 bug + +## 1.0.1(2022-04-02) + +- 修复 value 不能为 0 的 bug + +## 1.0.0(2021-11-19) + +- 优化 组件 UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-easyinput](https://uniapp.dcloud.io/component/uniui/uni-easyinput) + +## 0.1.4(2021-08-20) + +- 修复 在 uni-forms 的动态表单中默认值校验不通过的 bug + +## 0.1.3(2021-08-11) + +- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题 + +## 0.1.2(2021-07-30) + +- 优化 vue3 下事件警告的问题 + +## 0.1.1 + +- 优化 errorMessage 属性支持 Boolean 类型 + +## 0.1.0(2021-07-13) + +- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) + +## 0.0.16(2021-06-29) + +- 修复 confirmType 属性(仅 type="text" 生效)导致多行文本框无法换行的 bug + +## 0.0.15(2021-06-21) + +- 修复 passwordIcon 属性拼写错误的 bug + +## 0.0.14(2021-06-18) + +- 新增 passwordIcon 属性,当 type=password 时是否显示小眼睛图标 +- 修复 confirmType 属性不生效的问题 + +## 0.0.13(2021-06-04) + +- 修复 disabled 状态可清出内容的 bug + +## 0.0.12(2021-05-12) + +- 新增 组件示例地址 + +## 0.0.11(2021-05-07) + +- 修复 input-border 属性不生效的问题 + +## 0.0.10(2021-04-30) + +- 修复 ios 遮挡文字、显示一半的问题 + +## 0.0.9(2021-02-05) + +- 调整为 uni_modules 目录规范 +- 优化 兼容 nvue 页面 diff --git a/uni_modules/uni-easyinput/components/uni-easyinput/common.js b/uni_modules/uni-easyinput/components/uni-easyinput/common.js new file mode 100644 index 0000000..fde8d3c --- /dev/null +++ b/uni_modules/uni-easyinput/components/uni-easyinput/common.js @@ -0,0 +1,54 @@ +/** + * @desc 函数防抖 + * @param func 目标函数 + * @param wait 延迟执行毫秒数 + * @param immediate true - 立即执行, false - 延迟执行 + */ +export const debounce = function(func, wait = 1000, immediate = true) { + let timer; + return function() { + let context = this, + args = arguments; + if (timer) clearTimeout(timer); + if (immediate) { + let callNow = !timer; + timer = setTimeout(() => { + timer = null; + }, wait); + if (callNow) func.apply(context, args); + } else { + timer = setTimeout(() => { + func.apply(context, args); + }, wait) + } + } +} +/** + * @desc 函数节流 + * @param func 函数 + * @param wait 延迟执行毫秒数 + * @param type 1 使用表时间戳,在时间段开始的时候触发 2 使用表定时器,在时间段结束的时候触发 + */ +export const throttle = (func, wait = 1000, type = 1) => { + let previous = 0; + let timeout; + return function() { + let context = this; + let args = arguments; + if (type === 1) { + let now = Date.now(); + + if (now - previous > wait) { + func.apply(context, args); + previous = now; + } + } else if (type === 2) { + if (!timeout) { + timeout = setTimeout(() => { + timeout = null; + func.apply(context, args) + }, wait) + } + } + } +} diff --git a/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue b/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue new file mode 100644 index 0000000..d41411b --- /dev/null +++ b/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue @@ -0,0 +1,693 @@ + + + + + diff --git a/uni_modules/uni-easyinput/package.json b/uni_modules/uni-easyinput/package.json new file mode 100644 index 0000000..62bbff5 --- /dev/null +++ b/uni_modules/uni-easyinput/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-easyinput", + "displayName": "uni-easyinput 增强输入框", + "version": "1.1.18", + "description": "Easyinput 组件是对原生input组件的增强", + "keywords": [ + "uni-ui", + "uniui", + "input", + "uni-easyinput", + "输入框" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-easyinput/readme.md b/uni_modules/uni-easyinput/readme.md new file mode 100644 index 0000000..f1faf8f --- /dev/null +++ b/uni_modules/uni-easyinput/readme.md @@ -0,0 +1,11 @@ + + +### Easyinput 增强输入框 +> **组件名:uni-easyinput** +> 代码块: `uEasyinput` + + +easyinput 组件是对原生input组件的增强 ,是专门为配合表单组件[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)而设计的,easyinput 内置了边框,图标等,同时包含 input 所有功能 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-easyinput) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-fab/changelog.md b/uni_modules/uni-fab/changelog.md new file mode 100644 index 0000000..9bd4729 --- /dev/null +++ b/uni_modules/uni-fab/changelog.md @@ -0,0 +1,23 @@ +## 1.2.5(2023-03-29) +- 新增 pattern.icon 属性,可自定义图标 +## 1.2.4(2022-09-07) +小程序端由于 style 使用了对象导致报错,[详情](https://ask.dcloud.net.cn/question/152790?item_id=211778&rf=false) +## 1.2.3(2022-09-05) +- 修复 nvue 环境下,具有 tabBar 时,fab 组件下部位置无法正常获取 --window-bottom 的bug,详见:[https://ask.dcloud.net.cn/question/110638?notification_id=826310](https://ask.dcloud.net.cn/question/110638?notification_id=826310) +## 1.2.2(2021-12-29) +- 更新 组件依赖 +## 1.2.1(2021-11-19) +- 修复 阴影颜色不正确的bug +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-fab](https://uniapp.dcloud.io/component/uniui/uni-fab) +## 1.1.1(2021-11-09) +- 新增 提供组件设计资源,组件样式调整 +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.7(2021-05-12) +- 新增 组件示例地址 +## 1.0.6(2021-02-05) +- 调整为uni_modules目录规范 +- 优化 按钮背景色调整 +- 优化 兼容pc端 diff --git a/uni_modules/uni-fab/components/uni-fab/uni-fab.vue b/uni_modules/uni-fab/components/uni-fab/uni-fab.vue new file mode 100644 index 0000000..dfa65c1 --- /dev/null +++ b/uni_modules/uni-fab/components/uni-fab/uni-fab.vue @@ -0,0 +1,491 @@ + + + + + diff --git a/uni_modules/uni-fab/components/uni-fab/uni-fab.vue.bak b/uni_modules/uni-fab/components/uni-fab/uni-fab.vue.bak new file mode 100644 index 0000000..9df4dcd --- /dev/null +++ b/uni_modules/uni-fab/components/uni-fab/uni-fab.vue.bak @@ -0,0 +1,383 @@ + + + + + diff --git a/uni_modules/uni-fab/package.json b/uni_modules/uni-fab/package.json new file mode 100644 index 0000000..18c0810 --- /dev/null +++ b/uni_modules/uni-fab/package.json @@ -0,0 +1,84 @@ +{ + "id": "uni-fab", + "displayName": "uni-fab 悬浮按钮", + "version": "1.2.5", + "description": "悬浮按钮 fab button ,点击可展开一个图标按钮菜单。", + "keywords": [ + "uni-ui", + "uniui", + "按钮", + "悬浮按钮", + "fab" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-scss","uni-icons"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-fab/readme.md b/uni_modules/uni-fab/readme.md new file mode 100644 index 0000000..9a444e8 --- /dev/null +++ b/uni_modules/uni-fab/readme.md @@ -0,0 +1,9 @@ +## Fab 悬浮按钮 +> **组件名:uni-fab** +> 代码块: `uFab` + + +点击可展开一个图形按钮菜单 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-fab) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-fav/changelog.md b/uni_modules/uni-fav/changelog.md new file mode 100644 index 0000000..d8a08d4 --- /dev/null +++ b/uni_modules/uni-fav/changelog.md @@ -0,0 +1,19 @@ +## 1.2.1(2022-05-30) +- 新增 stat 属性 ,是否开启uni统计功能 +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-fav](https://uniapp.dcloud.io/component/uniui/uni-fav) +## 1.1.1(2021-08-24) +- 新增 支持国际化 +## 1.1.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.6(2021-05-12) +- 新增 组件示例地址 +## 1.0.5(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 1.0.4(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 +## 1.0.3(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 +## 1.0.2(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-fav/components/uni-fav/i18n/en.json b/uni_modules/uni-fav/components/uni-fav/i18n/en.json new file mode 100644 index 0000000..9a0759e --- /dev/null +++ b/uni_modules/uni-fav/components/uni-fav/i18n/en.json @@ -0,0 +1,4 @@ +{ + "uni-fav.collect": "collect", + "uni-fav.collected": "collected" +} diff --git a/uni_modules/uni-fav/components/uni-fav/i18n/index.js b/uni_modules/uni-fav/components/uni-fav/i18n/index.js new file mode 100644 index 0000000..de7509c --- /dev/null +++ b/uni_modules/uni-fav/components/uni-fav/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hans.json b/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hans.json new file mode 100644 index 0000000..67c89bf --- /dev/null +++ b/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hans.json @@ -0,0 +1,4 @@ +{ + "uni-fav.collect": "收藏", + "uni-fav.collected": "已收藏" +} diff --git a/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hant.json b/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hant.json new file mode 100644 index 0000000..67c89bf --- /dev/null +++ b/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hant.json @@ -0,0 +1,4 @@ +{ + "uni-fav.collect": "收藏", + "uni-fav.collected": "已收藏" +} diff --git a/uni_modules/uni-fav/components/uni-fav/uni-fav.vue b/uni_modules/uni-fav/components/uni-fav/uni-fav.vue new file mode 100644 index 0000000..d2c58df --- /dev/null +++ b/uni_modules/uni-fav/components/uni-fav/uni-fav.vue @@ -0,0 +1,161 @@ + + + + + diff --git a/uni_modules/uni-fav/package.json b/uni_modules/uni-fav/package.json new file mode 100644 index 0000000..cc14697 --- /dev/null +++ b/uni_modules/uni-fav/package.json @@ -0,0 +1,89 @@ +{ + "id": "uni-fav", + "displayName": "uni-fav 收藏按钮", + "version": "1.2.1", + "description": " Fav 收藏组件,可自定义颜色、大小。", + "keywords": [ + "fav", + "uni-ui", + "uniui", + "收藏" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-icons" + ], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-fav/readme.md b/uni_modules/uni-fav/readme.md new file mode 100644 index 0000000..4de125d --- /dev/null +++ b/uni_modules/uni-fav/readme.md @@ -0,0 +1,10 @@ + + +## Fav 收藏按钮 +> **组件名:uni-fav** +> 代码块: `uFav` + +用于收藏功能,可点击切换选中、不选中的状态。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-fav) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-feedback/changelog.md b/uni_modules/uni-feedback/changelog.md new file mode 100644 index 0000000..9ba4692 --- /dev/null +++ b/uni_modules/uni-feedback/changelog.md @@ -0,0 +1,8 @@ +## 1.1.0(2022-07-13) +新增,应用[pages_init](https://uniapp.dcloud.io/plugin/publish.html#pages-init)当导入插件到项目工程时,自动合并本插件的页面路由到项目的pages.json +## 1.0.5(2022-07-13) +新增,应用[pages_init](https://uniapp.dcloud.io/plugin/publish.html#pages-init)当导入插件到项目工程时,自动合并本插件的页面路由到项目的pages.json +## 1.0.4(2021-09-26) +为了数据安全,`opendb-feedback`表的`permission`中`delete`,`update`的值默认为`false` +## 1.0.3(2021-08-26) +删除多余的云函数test2 \ No newline at end of file diff --git a/uni_modules/uni-feedback/js_sdk/validator/opendb-feedback.js b/uni_modules/uni-feedback/js_sdk/validator/opendb-feedback.js new file mode 100644 index 0000000..be3d330 --- /dev/null +++ b/uni_modules/uni-feedback/js_sdk/validator/opendb-feedback.js @@ -0,0 +1,98 @@ +// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema + + +const validator = { + "content": { + "rules": [ + { + "required": true + }, + { + "format": "string" + } + ], + "label": "留言内容/回复内容" + }, + "imgs": { + "rules": [ + { + "format": "array" + }, + { + "arrayType": "file" + }, + { + "maxLength": 6 + } + ], + "label": "图片列表" + }, + "contact": { + "rules": [ + { + "format": "string" + } + ], + "label": "联系人" + }, + "mobile": { + "rules": [ + { + "format": "string" + }, + { + "pattern": "^\\+?[0-9-]{3,20}$" + } + ], + "label": "联系电话" + } +} + +const enumConverter = {} + +function filterToWhere(filter, command) { + let where = {} + for (let field in filter) { + let { type, value } = filter[field] + switch (type) { + case "search": + if (typeof value === 'string' && value.length) { + where[field] = new RegExp(value) + } + break; + case "select": + if (value.length) { + let selectValue = [] + for (let s of value) { + selectValue.push(command.eq(s)) + } + where[field] = command.or(selectValue) + } + break; + case "range": + if (value.length) { + let gt = value[0] + let lt = value[1] + where[field] = command.and([command.gte(gt), command.lte(lt)]) + } + break; + case "date": + if (value.length) { + let [s, e] = value + let startDate = new Date(s) + let endDate = new Date(e) + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + case "timestamp": + if (value.length) { + let [startDate, endDate] = value + where[field] = command.and([command.gte(startDate), command.lte(endDate)]) + } + break; + } + } + return where +} + +export { validator, enumConverter, filterToWhere } diff --git a/uni_modules/uni-feedback/package.json b/uni_modules/uni-feedback/package.json new file mode 100644 index 0000000..8d1818f --- /dev/null +++ b/uni_modules/uni-feedback/package.json @@ -0,0 +1,92 @@ +{ + "id": "uni-feedback", + "displayName": "问题反馈页面模板", + "version": "1.1.0", + "description": "问题反馈页面模板,方便开发者快速搭建问题反馈界面", + "keywords": [ + "问题反馈页面模板" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "category": [ + "uniCloud", + "云端一体页面模板" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [ + "uni-forms", + "uni-file-picker", + "uni-easyinput", + "uni-load-more", + "uni-list", + "uni-fab", + "uni-link" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "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", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-feedback/pages/opendb-feedback/detail.vue b/uni_modules/uni-feedback/pages/opendb-feedback/detail.vue new file mode 100644 index 0000000..fa28fca --- /dev/null +++ b/uni_modules/uni-feedback/pages/opendb-feedback/detail.vue @@ -0,0 +1,113 @@ + + + + + diff --git a/uni_modules/uni-feedback/pages/opendb-feedback/edit.vue b/uni_modules/uni-feedback/pages/opendb-feedback/edit.vue new file mode 100644 index 0000000..bd65125 --- /dev/null +++ b/uni_modules/uni-feedback/pages/opendb-feedback/edit.vue @@ -0,0 +1,167 @@ + + + + + diff --git a/uni_modules/uni-feedback/pages/opendb-feedback/list.vue b/uni_modules/uni-feedback/pages/opendb-feedback/list.vue new file mode 100644 index 0000000..1131edb --- /dev/null +++ b/uni_modules/uni-feedback/pages/opendb-feedback/list.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/uni_modules/uni-feedback/pages/opendb-feedback/opendb-feedback.vue b/uni_modules/uni-feedback/pages/opendb-feedback/opendb-feedback.vue new file mode 100644 index 0000000..f8bc77e --- /dev/null +++ b/uni_modules/uni-feedback/pages/opendb-feedback/opendb-feedback.vue @@ -0,0 +1,141 @@ + + + + + diff --git a/uni_modules/uni-feedback/readme.md b/uni_modules/uni-feedback/readme.md new file mode 100644 index 0000000..65d9192 --- /dev/null +++ b/uni_modules/uni-feedback/readme.md @@ -0,0 +1 @@ +这是一个问题反馈客户端插件,admin端插件:[https://ext.dcloud.net.cn/plugin?id=4992](https://ext.dcloud.net.cn/plugin?id=4992) \ No newline at end of file diff --git a/uni_modules/uni-file-picker/changelog.md b/uni_modules/uni-file-picker/changelog.md new file mode 100644 index 0000000..81e43b9 --- /dev/null +++ b/uni_modules/uni-file-picker/changelog.md @@ -0,0 +1,75 @@ +## 1.0.8(2024-03-20) +- 补充 删除文件时返回文件下标 +## 1.0.7(2024-02-21) +- 新增 微信小程序选择视频时改用chooseMedia,并返回视频缩略图 +## 1.0.6(2024-01-06) +- 新增 微信小程序不再调用chooseImage,而是调用chooseMedia +## 1.0.5(2024-01-03) +- 新增 上传文件至云存储携带本地文件名称 +## 1.0.4(2023-03-29) +- 修复 手动上传删除一个文件后不能再上传的bug +## 1.0.3(2022-12-19) +- 新增 sourceType 属性, 可以自定义图片和视频选择的来源 +## 1.0.2(2022-07-04) +- 修复 在uni-forms下样式不生效的bug +## 1.0.1(2021-11-23) +- 修复 参数为对象的情况下,url在某些情况显示错误的bug +## 1.0.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-file-picker](https://uniapp.dcloud.io/component/uniui/uni-file-picker) +## 0.2.16(2021-11-08) +- 修复 传入空对象 ,显示错误的Bug +## 0.2.15(2021-08-30) +- 修复 return-type="object" 时且存在v-model时,无法删除文件的Bug +## 0.2.14(2021-08-23) +- 新增 参数中返回 fileID 字段 +## 0.2.13(2021-08-23) +- 修复 腾讯云传入fileID 不能回显的bug +- 修复 选择图片后,不能放大的问题 +## 0.2.12(2021-08-17) +- 修复 由于 0.2.11 版本引起的不能回显图片的Bug +## 0.2.11(2021-08-16) +- 新增 clearFiles(index) 方法,可以手动删除指定文件 +- 修复 v-model 值设为 null 报错的Bug +## 0.2.10(2021-08-13) +- 修复 return-type="object" 时,无法删除文件的Bug +## 0.2.9(2021-08-03) +- 修复 auto-upload 属性失效的Bug +## 0.2.8(2021-07-31) +- 修复 fileExtname属性不指定值报错的Bug +## 0.2.7(2021-07-31) +- 修复 在某种场景下图片不回显的Bug +## 0.2.6(2021-07-30) +- 修复 return-type为object下,返回值不正确的Bug +## 0.2.5(2021-07-30) +- 修复(重要) H5 平台下如果和uni-forms组件一同使用导致页面卡死的问题 +## 0.2.3(2021-07-28) +- 优化 调整示例代码 +## 0.2.2(2021-07-27) +- 修复 vue3 下赋值错误的Bug +- 优化 h5平台下上传文件导致页面卡死的问题 +## 0.2.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 0.1.1(2021-07-02) +- 修复 sourceType 缺少默认值导致 ios 无法选择文件 +## 0.1.0(2021-06-30) +- 优化 解耦与uniCloud的强绑定关系 ,如不绑定服务空间,默认autoUpload为false且不可更改 +## 0.0.11(2021-06-30) +- 修复 由 0.0.10 版本引发的 returnType 属性失效的问题 +## 0.0.10(2021-06-29) +- 优化 文件上传后进度条消失时机 +## 0.0.9(2021-06-29) +- 修复 在uni-forms 中,删除文件 ,获取的值不对的Bug +## 0.0.8(2021-06-15) +- 修复 删除文件时无法触发 v-model 的Bug +## 0.0.7(2021-05-12) +- 新增 组件示例地址 +## 0.0.6(2021-04-09) +- 修复 选择的文件非 file-extname 字段指定的扩展名报错的Bug +## 0.0.5(2021-04-09) +- 优化 更新组件示例 +## 0.0.4(2021-04-09) +- 优化 file-extname 字段支持字符串写法,多个扩展名需要用逗号分隔 +## 0.0.3(2021-02-05) +- 调整为uni_modules目录规范 +- 修复 微信小程序不指定 fileExtname 属性选择失败的Bug diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js b/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js new file mode 100644 index 0000000..9c6bcdf --- /dev/null +++ b/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js @@ -0,0 +1,287 @@ +'use strict'; + +const ERR_MSG_OK = 'chooseAndUploadFile:ok'; +const ERR_MSG_FAIL = 'chooseAndUploadFile:fail'; + +function chooseImage(opts) { + const { + count, + sizeType = ['original', 'compressed'], + sourceType, + extension + } = opts + return new Promise((resolve, reject) => { + // 微信由于旧接口不再维护,针对微信小程序平台改用chooseMedia接口 + // #ifdef MP-WEIXIN + uni.chooseMedia({ + count, + sizeType, + sourceType, + mediaType: ['image'], + extension, + success(res) { + res.tempFiles.forEach(item => { + item.path = item.tempFilePath; + }) + resolve(normalizeChooseAndUploadFileRes(res, 'image')); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL), + }); + }, + }) + // #endif + // #ifndef MP-WEIXIN + uni.chooseImage({ + count, + sizeType, + sourceType, + extension, + success(res) { + resolve(normalizeChooseAndUploadFileRes(res, 'image')); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL), + }); + }, + }); + // #endif + + }); +} + +function chooseVideo(opts) { + const { + count, + camera, + compressed, + maxDuration, + sourceType, + extension + } = opts; + return new Promise((resolve, reject) => { + // 微信由于旧接口不再维护,针对微信小程序平台改用chooseMedia接口 + // #ifdef MP-WEIXIN + uni.chooseMedia({ + count, + compressed, + maxDuration, + sourceType, + extension, + mediaType: ['video'], + success(res) { + const { + tempFiles, + } = res; + resolve(normalizeChooseAndUploadFileRes({ + errMsg: 'chooseVideo:ok', + tempFiles: tempFiles.map(item => { + return { + name: item.name || '', + path: item.tempFilePath, + thumbTempFilePath: item.thumbTempFilePath, + size:item.size, + type: (res.tempFile && res.tempFile.type) || '', + width:item.width, + height:item.height, + duration:item.duration, + fileType: 'video', + cloudPath: '', + } + }), + }, 'video')); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL), + }); + }, + }) + // #endif + // #ifndef MP-WEIXIN + uni.chooseVideo({ + camera, + compressed, + maxDuration, + sourceType, + extension, + success(res) { + const { + tempFilePath, + duration, + size, + height, + width + } = res; + resolve(normalizeChooseAndUploadFileRes({ + errMsg: 'chooseVideo:ok', + tempFilePaths: [tempFilePath], + tempFiles: [{ + name: (res.tempFile && res.tempFile.name) || '', + path: tempFilePath, + size, + type: (res.tempFile && res.tempFile.type) || '', + width, + height, + duration, + fileType: 'video', + cloudPath: '', + }, ], + }, 'video')); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL), + }); + }, + }); + // #endif + }); +} + +function chooseAll(opts) { + const { + count, + extension + } = opts; + return new Promise((resolve, reject) => { + let chooseFile = uni.chooseFile; + if (typeof wx !== 'undefined' && + typeof wx.chooseMessageFile === 'function') { + chooseFile = wx.chooseMessageFile; + } + if (typeof chooseFile !== 'function') { + return reject({ + errMsg: ERR_MSG_FAIL + ' 请指定 type 类型,该平台仅支持选择 image 或 video。', + }); + } + chooseFile({ + type: 'all', + count, + extension, + success(res) { + resolve(normalizeChooseAndUploadFileRes(res)); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseFile:fail', ERR_MSG_FAIL), + }); + }, + }); + }); +} + +function normalizeChooseAndUploadFileRes(res, fileType) { + res.tempFiles.forEach((item, index) => { + if (!item.name) { + item.name = item.path.substring(item.path.lastIndexOf('/') + 1); + } + if (fileType) { + item.fileType = fileType; + } + item.cloudPath = + Date.now() + '_' + index + item.name.substring(item.name.lastIndexOf('.')); + }); + if (!res.tempFilePaths) { + res.tempFilePaths = res.tempFiles.map((file) => file.path); + } + return res; +} + +function uploadCloudFiles(files, max = 5, onUploadProgress) { + files = JSON.parse(JSON.stringify(files)) + const len = files.length + let count = 0 + let self = this + return new Promise(resolve => { + while (count < max) { + next() + } + + function next() { + let cur = count++ + if (cur >= len) { + !files.find(item => !item.url && !item.errMsg) && resolve(files) + return + } + const fileItem = files[cur] + const index = self.files.findIndex(v => v.uuid === fileItem.uuid) + fileItem.url = '' + delete fileItem.errMsg + + uniCloud + .uploadFile({ + filePath: fileItem.path, + cloudPath: fileItem.cloudPath, + fileType: fileItem.fileType, + onUploadProgress: res => { + res.index = index + onUploadProgress && onUploadProgress(res) + } + }) + .then(res => { + fileItem.url = res.fileID + fileItem.index = index + if (cur < len) { + next() + } + }) + .catch(res => { + fileItem.errMsg = res.errMsg || res.message + fileItem.index = index + if (cur < len) { + next() + } + }) + } + }) +} + + + + + +function uploadFiles(choosePromise, { + onChooseFile, + onUploadProgress +}) { + return choosePromise + .then((res) => { + if (onChooseFile) { + const customChooseRes = onChooseFile(res); + if (typeof customChooseRes !== 'undefined') { + return Promise.resolve(customChooseRes).then((chooseRes) => typeof chooseRes === 'undefined' ? + res : chooseRes); + } + } + return res; + }) + .then((res) => { + if (res === false) { + return { + errMsg: ERR_MSG_OK, + tempFilePaths: [], + tempFiles: [], + }; + } + return res + }) +} + +function chooseAndUploadFile(opts = { + type: 'all' +}) { + if (opts.type === 'image') { + return uploadFiles(chooseImage(opts), opts); + } else if (opts.type === 'video') { + return uploadFiles(chooseVideo(opts), opts); + } + return uploadFiles(chooseAll(opts), opts); +} + +export { + chooseAndUploadFile, + uploadCloudFiles +}; diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue b/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue new file mode 100644 index 0000000..fb83f63 --- /dev/null +++ b/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue @@ -0,0 +1,678 @@ + + + + + diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue b/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue new file mode 100644 index 0000000..625d92e --- /dev/null +++ b/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue @@ -0,0 +1,325 @@ + + + + + diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue b/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue new file mode 100644 index 0000000..2a29bc2 --- /dev/null +++ b/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue @@ -0,0 +1,292 @@ + + + + + diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/utils.js b/uni_modules/uni-file-picker/components/uni-file-picker/utils.js new file mode 100644 index 0000000..1bc9259 --- /dev/null +++ b/uni_modules/uni-file-picker/components/uni-file-picker/utils.js @@ -0,0 +1,110 @@ +/** + * 获取文件名和后缀 + * @param {String} name + */ +export const get_file_ext = (name) => { + const last_len = name.lastIndexOf('.') + const len = name.length + return { + name: name.substring(0, last_len), + ext: name.substring(last_len + 1, len) + } +} + +/** + * 获取扩展名 + * @param {Array} fileExtname + */ +export const get_extname = (fileExtname) => { + if (!Array.isArray(fileExtname)) { + let extname = fileExtname.replace(/(\[|\])/g, '') + return extname.split(',') + } else { + return fileExtname + } + return [] +} + +/** + * 获取文件和检测是否可选 + */ +export const get_files_and_is_max = (res, _extname) => { + let filePaths = [] + let files = [] + if(!_extname || _extname.length === 0){ + return { + filePaths, + files + } + } + res.tempFiles.forEach(v => { + let fileFullName = get_file_ext(v.name) + const extname = fileFullName.ext.toLowerCase() + if (_extname.indexOf(extname) !== -1) { + files.push(v) + filePaths.push(v.path) + } + }) + if (files.length !== res.tempFiles.length) { + uni.showToast({ + title: `当前选择了${res.tempFiles.length}个文件 ,${res.tempFiles.length - files.length} 个文件格式不正确`, + icon: 'none', + duration: 5000 + }) + } + + return { + filePaths, + files + } +} + + +/** + * 获取图片信息 + * @param {Object} filepath + */ +export const get_file_info = (filepath) => { + return new Promise((resolve, reject) => { + uni.getImageInfo({ + src: filepath, + success(res) { + resolve(res) + }, + fail(err) { + reject(err) + } + }) + }) +} +/** + * 获取封装数据 + */ +export const get_file_data = async (files, type = 'image') => { + // 最终需要上传数据库的数据 + let fileFullName = get_file_ext(files.name) + const extname = fileFullName.ext.toLowerCase() + let filedata = { + name: files.name, + uuid: files.uuid, + extname: extname || '', + cloudPath: files.cloudPath, + fileType: files.fileType, + thumbTempFilePath: files.thumbTempFilePath, + url: files.path || files.path, + size: files.size, //单位是字节 + image: {}, + path: files.path, + video: {} + } + if (type === 'image') { + const imageinfo = await get_file_info(files.path) + delete filedata.video + filedata.image.width = imageinfo.width + filedata.image.height = imageinfo.height + filedata.image.location = imageinfo.path + } else { + delete filedata.image + } + return filedata +} diff --git a/uni_modules/uni-file-picker/package.json b/uni_modules/uni-file-picker/package.json new file mode 100644 index 0000000..004d330 --- /dev/null +++ b/uni_modules/uni-file-picker/package.json @@ -0,0 +1,83 @@ +{ + "id": "uni-file-picker", + "displayName": "uni-file-picker 文件选择上传", + "version": "1.0.8", + "description": "文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间", + "keywords": [ + "uni-ui", + "uniui", + "图片上传", + "文件上传" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "n" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-file-picker/readme.md b/uni_modules/uni-file-picker/readme.md new file mode 100644 index 0000000..c8399a5 --- /dev/null +++ b/uni_modules/uni-file-picker/readme.md @@ -0,0 +1,11 @@ + +## FilePicker 文件选择上传 + +> **组件名:uni-file-picker** +> 代码块: `uFilePicker` + + +文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-file-picker) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-forms/changelog.md b/uni_modules/uni-forms/changelog.md new file mode 100644 index 0000000..3d998bc --- /dev/null +++ b/uni_modules/uni-forms/changelog.md @@ -0,0 +1,94 @@ +## 1.4.10(2023-11-03) +- 优化 labelWidth 描述错误 +## 1.4.9(2023-02-10) +- 修复 required 参数无法动态绑定 +## 1.4.8(2022-08-23) +- 优化 根据 rules 自动添加 required 的问题 +## 1.4.7(2022-08-22) +- 修复 item 未设置 require 属性,rules 设置 require 后,星号也显示的 bug,详见:[https://ask.dcloud.net.cn/question/151540](https://ask.dcloud.net.cn/question/151540) +## 1.4.6(2022-07-13) +- 修复 model 需要校验的值没有声明对应字段时,导致第一次不触发校验的bug +## 1.4.5(2022-07-05) +- 新增 更多表单示例 +- 优化 子表单组件过期提示的问题 +- 优化 子表单组件uni-datetime-picker、uni-data-select、uni-data-picker的显示样式 +## 1.4.4(2022-07-04) +- 更新 删除组件日志 +## 1.4.3(2022-07-04) +- 修复 由 1.4.0 引发的 label 插槽不生效的bug +## 1.4.2(2022-07-04) +- 修复 子组件找不到 setValue 报错的bug +## 1.4.1(2022-07-04) +- 修复 uni-data-picker 在 uni-forms-item 中报错的bug +- 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug +## 1.4.0(2022-06-30) +- 【重要】组件逻辑重构,部分用法用旧版本不兼容,请注意兼容问题 +- 【重要】组件使用 Provide/Inject 方式注入依赖,提供了自定义表单组件调用 uni-forms 校验表单的能力 +- 新增 model 属性,等同于原 value/modelValue 属性,旧属性即将废弃 +- 新增 validateTrigger 属性的 blur 值,仅 uni-easyinput 生效 +- 新增 onFieldChange 方法,可以对子表单进行校验,可替代binddata方法 +- 新增 子表单的 setRules 方法,配合自定义校验函数使用 +- 新增 uni-forms-item 的 setRules 方法,配置动态表单使用可动态更新校验规则 +- 优化 动态表单校验方式,废弃拼接name的方式 +## 1.3.3(2022-06-22) +- 修复 表单校验顺序无序问题 +## 1.3.2(2021-12-09) +- +## 1.3.1(2021-11-19) +- 修复 label 插槽不生效的bug +## 1.3.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-forms](https://uniapp.dcloud.io/component/uniui/uni-forms) +## 1.2.7(2021-08-13) +- 修复 没有添加校验规则的字段依然报错的Bug +## 1.2.6(2021-08-11) +- 修复 重置表单错误信息无法清除的问题 +## 1.2.5(2021-08-11) +- 优化 组件文档 +## 1.2.4(2021-08-11) +- 修复 表单验证只生效一次的问题 +## 1.2.3(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.2.2(2021-07-26) +- 修复 vue2 下条件编译导致destroyed生命周期失效的Bug +- 修复 1.2.1 引起的示例在小程序平台报错的Bug +## 1.2.1(2021-07-22) +- 修复 动态校验表单,默认值为空的情况下校验失效的Bug +- 修复 不指定name属性时,运行报错的Bug +- 优化 label默认宽度从65调整至70,使required为true且四字时不换行 +- 优化 组件示例,新增动态校验示例代码 +- 优化 组件文档,使用方式更清晰 +## 1.2.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.2(2021-06-25) +- 修复 pattern 属性在微信小程序平台无效的问题 +## 1.1.1(2021-06-22) +- 修复 validate-trigger属性为submit且err-show-type属性为toast时不能弹出的Bug +## 1.1.0(2021-06-22) +- 修复 只写setRules方法而导致校验不生效的Bug +- 修复 由上个办法引发的错误提示文字错位的Bug +## 1.0.48(2021-06-21) +- 修复 不设置 label 属性 ,无法设置label插槽的问题 +## 1.0.47(2021-06-21) +- 修复 不设置label属性,label-width属性不生效的bug +- 修复 setRules 方法与rules属性冲突的问题 +## 1.0.46(2021-06-04) +- 修复 动态删减数据导致报错的问题 +## 1.0.45(2021-06-04) +- 新增 modelValue 属性 ,value 即将废弃 +## 1.0.44(2021-06-02) +- 新增 uni-forms-item 可以设置单独的 rules +- 新增 validate 事件增加 keepitem 参数,可以选择那些字段不过滤 +- 优化 submit 事件重命名为 validate +## 1.0.43(2021-05-12) +- 新增 组件示例地址 +## 1.0.42(2021-04-30) +- 修复 自定义检验器失效的问题 +## 1.0.41(2021-03-05) +- 更新 校验器 +- 修复 表单规则设置类型为 number 的情况下,值为0校验失败的Bug +## 1.0.40(2021-03-04) +- 修复 动态显示uni-forms-item的情况下,submit 方法获取值错误的Bug +## 1.0.39(2021-02-05) +- 调整为uni_modules目录规范 +- 修复 校验器传入 int 等类型 ,返回String类型的Bug diff --git a/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue b/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue new file mode 100644 index 0000000..0aef9cc --- /dev/null +++ b/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue @@ -0,0 +1,627 @@ + + + + + diff --git a/uni_modules/uni-forms/components/uni-forms/uni-forms.vue b/uni_modules/uni-forms/components/uni-forms/uni-forms.vue new file mode 100644 index 0000000..9bb9ae7 --- /dev/null +++ b/uni_modules/uni-forms/components/uni-forms/uni-forms.vue @@ -0,0 +1,397 @@ + + + + + diff --git a/uni_modules/uni-forms/components/uni-forms/utils.js b/uni_modules/uni-forms/components/uni-forms/utils.js new file mode 100644 index 0000000..6da2421 --- /dev/null +++ b/uni_modules/uni-forms/components/uni-forms/utils.js @@ -0,0 +1,293 @@ +/** + * 简单处理对象拷贝 + * @param {Obejct} 被拷贝对象 + * @@return {Object} 拷贝对象 + */ +export const deepCopy = (val) => { + return JSON.parse(JSON.stringify(val)) +} +/** + * 过滤数字类型 + * @param {String} format 数字类型 + * @@return {Boolean} 返回是否为数字类型 + */ +export const typeFilter = (format) => { + return format === 'int' || format === 'double' || format === 'number' || format === 'timestamp'; +} + +/** + * 把 value 转换成指定的类型,用于处理初始值,原因是初始值需要入库不能为 undefined + * @param {String} key 字段名 + * @param {any} value 字段值 + * @param {Object} rules 表单校验规则 + */ +export const getValue = (key, value, rules) => { + const isRuleNumType = rules.find(val => val.format && typeFilter(val.format)); + const isRuleBoolType = rules.find(val => (val.format && val.format === 'boolean') || val.format === 'bool'); + // 输入类型为 number + if (!!isRuleNumType) { + if (!value && value !== 0) { + value = null + } else { + value = isNumber(Number(value)) ? Number(value) : value + } + } + + // 输入类型为 boolean + if (!!isRuleBoolType) { + value = isBoolean(value) ? value : false + } + + return value; +} + +/** + * 获取表单数据 + * @param {String|Array} name 真实名称,需要使用 realName 获取 + * @param {Object} data 原始数据 + * @param {any} value 需要设置的值 + */ +export const setDataValue = (field, formdata, value) => { + formdata[field] = value + return value || '' +} + +/** + * 获取表单数据 + * @param {String|Array} field 真实名称,需要使用 realName 获取 + * @param {Object} data 原始数据 + */ +export const getDataValue = (field, data) => { + return objGet(data, field) +} + +/** + * 获取表单类型 + * @param {String|Array} field 真实名称,需要使用 realName 获取 + */ +export const getDataValueType = (field, data) => { + const value = getDataValue(field, data) + return { + type: type(value), + value + } +} + +/** + * 获取表单可用的真实name + * @param {String|Array} name 表单name + * @@return {String} 表单可用的真实name + */ +export const realName = (name, data = {}) => { + const base_name = _basePath(name) + if (typeof base_name === 'object' && Array.isArray(base_name) && base_name.length > 1) { + const realname = base_name.reduce((a, b) => a += `#${b}`, '_formdata_') + return realname + } + return base_name[0] || name +} + +/** + * 判断是否表单可用的真实name + * @param {String|Array} name 表单name + * @@return {String} 表单可用的真实name + */ +export const isRealName = (name) => { + const reg = /^_formdata_#*/ + return reg.test(name) +} + +/** + * 获取表单数据的原始格式 + * @@return {Object|Array} object 需要解析的数据 + */ +export const rawData = (object = {}, name) => { + let newData = JSON.parse(JSON.stringify(object)) + let formData = {} + for(let i in newData){ + let path = name2arr(i) + objSet(formData,path,newData[i]) + } + return formData +} + +/** + * 真实name还原为 array + * @param {*} name + */ +export const name2arr = (name) => { + let field = name.replace('_formdata_#', '') + field = field.split('#').map(v => (isNumber(v) ? Number(v) : v)) + return field +} + +/** + * 对象中设置值 + * @param {Object|Array} object 源数据 + * @param {String| Array} path 'a.b.c' 或 ['a',0,'b','c'] + * @param {String} value 需要设置的值 + */ +export const objSet = (object, path, value) => { + if (typeof object !== 'object') return object; + _basePath(path).reduce((o, k, i, _) => { + if (i === _.length - 1) { + // 若遍历结束直接赋值 + o[k] = value + return null + } else if (k in o) { + // 若存在对应路径,则返回找到的对象,进行下一次遍历 + return o[k] + } else { + // 若不存在对应路径,则创建对应对象,若下一路径是数字,新对象赋值为空数组,否则赋值为空对象 + o[k] = /^[0-9]{1,}$/.test(_[i + 1]) ? [] : {} + return o[k] + } + }, object) + // 返回object + return object; +} + +// 处理 path, path有三种形式:'a[0].b.c'、'a.0.b.c' 和 ['a','0','b','c'],需要统一处理成数组,便于后续使用 +function _basePath(path) { + // 若是数组,则直接返回 + if (Array.isArray(path)) return path + // 若有 '[',']',则替换成将 '[' 替换成 '.',去掉 ']' + return path.replace(/\[/g, '.').replace(/\]/g, '').split('.') +} + +/** + * 从对象中获取值 + * @param {Object|Array} object 源数据 + * @param {String| Array} path 'a.b.c' 或 ['a',0,'b','c'] + * @param {String} defaultVal 如果无法从调用链中获取值的默认值 + */ +export const objGet = (object, path, defaultVal = 'undefined') => { + // 先将path处理成统一格式 + let newPath = _basePath(path) + // 递归处理,返回最后结果 + let val = newPath.reduce((o, k) => { + return (o || {})[k] + }, object); + return !val || val !== undefined ? val : defaultVal +} + + +/** + * 是否为 number 类型 + * @param {any} num 需要判断的值 + * @return {Boolean} 是否为 number + */ +export const isNumber = (num) => { + return !isNaN(Number(num)) +} + +/** + * 是否为 boolean 类型 + * @param {any} bool 需要判断的值 + * @return {Boolean} 是否为 boolean + */ +export const isBoolean = (bool) => { + return (typeof bool === 'boolean') +} +/** + * 是否有必填字段 + * @param {Object} rules 规则 + * @return {Boolean} 是否有必填字段 + */ +export const isRequiredField = (rules) => { + let isNoField = false; + for (let i = 0; i < rules.length; i++) { + const ruleData = rules[i]; + if (ruleData.required) { + isNoField = true; + break; + } + } + return isNoField; +} + + +/** + * 获取数据类型 + * @param {Any} obj 需要获取数据类型的值 + */ +export const type = (obj) => { + var class2type = {}; + + // 生成class2type映射 + "Boolean Number String Function Array Date RegExp Object Error".split(" ").map(function(item, index) { + class2type["[object " + item + "]"] = item.toLowerCase(); + }) + if (obj == null) { + return obj + ""; + } + return typeof obj === "object" || typeof obj === "function" ? + class2type[Object.prototype.toString.call(obj)] || "object" : + typeof obj; +} + +/** + * 判断两个值是否相等 + * @param {any} a 值 + * @param {any} b 值 + * @return {Boolean} 是否相等 + */ +export const isEqual = (a, b) => { + //如果a和b本来就全等 + if (a === b) { + //判断是否为0和-0 + return a !== 0 || 1 / a === 1 / b; + } + //判断是否为null和undefined + if (a == null || b == null) { + return a === b; + } + //接下来判断a和b的数据类型 + var classNameA = toString.call(a), + classNameB = toString.call(b); + //如果数据类型不相等,则返回false + if (classNameA !== classNameB) { + return false; + } + //如果数据类型相等,再根据不同数据类型分别判断 + switch (classNameA) { + case '[object RegExp]': + case '[object String]': + //进行字符串转换比较 + return '' + a === '' + b; + case '[object Number]': + //进行数字转换比较,判断是否为NaN + if (+a !== +a) { + return +b !== +b; + } + //判断是否为0或-0 + return +a === 0 ? 1 / +a === 1 / b : +a === +b; + case '[object Date]': + case '[object Boolean]': + return +a === +b; + } + //如果是对象类型 + if (classNameA == '[object Object]') { + //获取a和b的属性长度 + var propsA = Object.getOwnPropertyNames(a), + propsB = Object.getOwnPropertyNames(b); + if (propsA.length != propsB.length) { + return false; + } + for (var i = 0; i < propsA.length; i++) { + var propName = propsA[i]; + //如果对应属性对应值不相等,则返回false + if (a[propName] !== b[propName]) { + return false; + } + } + return true; + } + //如果是数组类型 + if (classNameA == '[object Array]') { + if (a.toString() == b.toString()) { + return true; + } + return false; + } +} diff --git a/uni_modules/uni-forms/components/uni-forms/validate.js b/uni_modules/uni-forms/components/uni-forms/validate.js new file mode 100644 index 0000000..1834c6c --- /dev/null +++ b/uni_modules/uni-forms/components/uni-forms/validate.js @@ -0,0 +1,486 @@ +var pattern = { + email: /^\S+?@\S+?\.\S+?$/, + idcard: /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/, + url: new RegExp( + "^(?!mailto:)(?:(?:http|https|ftp)://|//)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$", + 'i') +}; + +const FORMAT_MAPPING = { + "int": 'integer', + "bool": 'boolean', + "double": 'number', + "long": 'number', + "password": 'string' + // "fileurls": 'array' +} + +function formatMessage(args, resources = '') { + var defaultMessage = ['label'] + defaultMessage.forEach((item) => { + if (args[item] === undefined) { + args[item] = '' + } + }) + + let str = resources + for (let key in args) { + let reg = new RegExp('{' + key + '}') + str = str.replace(reg, args[key]) + } + return str +} + +function isEmptyValue(value, type) { + if (value === undefined || value === null) { + return true; + } + + if (typeof value === 'string' && !value) { + return true; + } + + if (Array.isArray(value) && !value.length) { + return true; + } + + if (type === 'object' && !Object.keys(value).length) { + return true; + } + + return false; +} + +const types = { + integer(value) { + return types.number(value) && parseInt(value, 10) === value; + }, + string(value) { + return typeof value === 'string'; + }, + number(value) { + if (isNaN(value)) { + return false; + } + return typeof value === 'number'; + }, + "boolean": function(value) { + return typeof value === 'boolean'; + }, + "float": function(value) { + return types.number(value) && !types.integer(value); + }, + array(value) { + return Array.isArray(value); + }, + object(value) { + return typeof value === 'object' && !types.array(value); + }, + date(value) { + return value instanceof Date; + }, + timestamp(value) { + if (!this.integer(value) || Math.abs(value).toString().length > 16) { + return false + } + return true; + }, + file(value) { + return typeof value.url === 'string'; + }, + email(value) { + return typeof value === 'string' && !!value.match(pattern.email) && value.length < 255; + }, + url(value) { + return typeof value === 'string' && !!value.match(pattern.url); + }, + pattern(reg, value) { + try { + return new RegExp(reg).test(value); + } catch (e) { + return false; + } + }, + method(value) { + return typeof value === 'function'; + }, + idcard(value) { + return typeof value === 'string' && !!value.match(pattern.idcard); + }, + 'url-https'(value) { + return this.url(value) && value.startsWith('https://'); + }, + 'url-scheme'(value) { + return value.startsWith('://'); + }, + 'url-web'(value) { + return false; + } +} + +class RuleValidator { + + constructor(message) { + this._message = message + } + + async validateRule(fieldKey, fieldValue, value, data, allData) { + var result = null + + let rules = fieldValue.rules + + let hasRequired = rules.findIndex((item) => { + return item.required + }) + if (hasRequired < 0) { + if (value === null || value === undefined) { + return result + } + if (typeof value === 'string' && !value.length) { + return result + } + } + + var message = this._message + + if (rules === undefined) { + return message['default'] + } + + for (var i = 0; i < rules.length; i++) { + let rule = rules[i] + let vt = this._getValidateType(rule) + + Object.assign(rule, { + label: fieldValue.label || `["${fieldKey}"]` + }) + + if (RuleValidatorHelper[vt]) { + result = RuleValidatorHelper[vt](rule, value, message) + if (result != null) { + break + } + } + + if (rule.validateExpr) { + let now = Date.now() + let resultExpr = rule.validateExpr(value, allData, now) + if (resultExpr === false) { + result = this._getMessage(rule, rule.errorMessage || this._message['default']) + break + } + } + + if (rule.validateFunction) { + result = await this.validateFunction(rule, value, data, allData, vt) + if (result !== null) { + break + } + } + } + + if (result !== null) { + result = message.TAG + result + } + + return result + } + + async validateFunction(rule, value, data, allData, vt) { + let result = null + try { + let callbackMessage = null + const res = await rule.validateFunction(rule, value, allData || data, (message) => { + callbackMessage = message + }) + if (callbackMessage || (typeof res === 'string' && res) || res === false) { + result = this._getMessage(rule, callbackMessage || res, vt) + } + } catch (e) { + result = this._getMessage(rule, e.message, vt) + } + return result + } + + _getMessage(rule, message, vt) { + return formatMessage(rule, message || rule.errorMessage || this._message[vt] || message['default']) + } + + _getValidateType(rule) { + var result = '' + if (rule.required) { + result = 'required' + } else if (rule.format) { + result = 'format' + } else if (rule.arrayType) { + result = 'arrayTypeFormat' + } else if (rule.range) { + result = 'range' + } else if (rule.maximum !== undefined || rule.minimum !== undefined) { + result = 'rangeNumber' + } else if (rule.maxLength !== undefined || rule.minLength !== undefined) { + result = 'rangeLength' + } else if (rule.pattern) { + result = 'pattern' + } else if (rule.validateFunction) { + result = 'validateFunction' + } + return result + } +} + +const RuleValidatorHelper = { + required(rule, value, message) { + if (rule.required && isEmptyValue(value, rule.format || typeof value)) { + return formatMessage(rule, rule.errorMessage || message.required); + } + + return null + }, + + range(rule, value, message) { + const { + range, + errorMessage + } = rule; + + let list = new Array(range.length); + for (let i = 0; i < range.length; i++) { + const item = range[i]; + if (types.object(item) && item.value !== undefined) { + list[i] = item.value; + } else { + list[i] = item; + } + } + + let result = false + if (Array.isArray(value)) { + result = (new Set(value.concat(list)).size === list.length); + } else { + if (list.indexOf(value) > -1) { + result = true; + } + } + + if (!result) { + return formatMessage(rule, errorMessage || message['enum']); + } + + return null + }, + + rangeNumber(rule, value, message) { + if (!types.number(value)) { + return formatMessage(rule, rule.errorMessage || message.pattern.mismatch); + } + + let { + minimum, + maximum, + exclusiveMinimum, + exclusiveMaximum + } = rule; + let min = exclusiveMinimum ? value <= minimum : value < minimum; + let max = exclusiveMaximum ? value >= maximum : value > maximum; + + if (minimum !== undefined && min) { + return formatMessage(rule, rule.errorMessage || message['number'][exclusiveMinimum ? + 'exclusiveMinimum' : 'minimum' + ]) + } else if (maximum !== undefined && max) { + return formatMessage(rule, rule.errorMessage || message['number'][exclusiveMaximum ? + 'exclusiveMaximum' : 'maximum' + ]) + } else if (minimum !== undefined && maximum !== undefined && (min || max)) { + return formatMessage(rule, rule.errorMessage || message['number'].range) + } + + return null + }, + + rangeLength(rule, value, message) { + if (!types.string(value) && !types.array(value)) { + return formatMessage(rule, rule.errorMessage || message.pattern.mismatch); + } + + let min = rule.minLength; + let max = rule.maxLength; + let val = value.length; + + if (min !== undefined && val < min) { + return formatMessage(rule, rule.errorMessage || message['length'].minLength) + } else if (max !== undefined && val > max) { + return formatMessage(rule, rule.errorMessage || message['length'].maxLength) + } else if (min !== undefined && max !== undefined && (val < min || val > max)) { + return formatMessage(rule, rule.errorMessage || message['length'].range) + } + + return null + }, + + pattern(rule, value, message) { + if (!types['pattern'](rule.pattern, value)) { + return formatMessage(rule, rule.errorMessage || message.pattern.mismatch); + } + + return null + }, + + format(rule, value, message) { + var customTypes = Object.keys(types); + var format = FORMAT_MAPPING[rule.format] ? FORMAT_MAPPING[rule.format] : (rule.format || rule.arrayType); + + if (customTypes.indexOf(format) > -1) { + if (!types[format](value)) { + return formatMessage(rule, rule.errorMessage || message.typeError); + } + } + + return null + }, + + arrayTypeFormat(rule, value, message) { + if (!Array.isArray(value)) { + return formatMessage(rule, rule.errorMessage || message.typeError); + } + + for (let i = 0; i < value.length; i++) { + const element = value[i]; + let formatResult = this.format(rule, element, message) + if (formatResult !== null) { + return formatResult + } + } + + return null + } +} + +class SchemaValidator extends RuleValidator { + + constructor(schema, options) { + super(SchemaValidator.message); + + this._schema = schema + this._options = options || null + } + + updateSchema(schema) { + this._schema = schema + } + + async validate(data, allData) { + let result = this._checkFieldInSchema(data) + if (!result) { + result = await this.invokeValidate(data, false, allData) + } + return result.length ? result[0] : null + } + + async validateAll(data, allData) { + let result = this._checkFieldInSchema(data) + if (!result) { + result = await this.invokeValidate(data, true, allData) + } + return result + } + + async validateUpdate(data, allData) { + let result = this._checkFieldInSchema(data) + if (!result) { + result = await this.invokeValidateUpdate(data, false, allData) + } + return result.length ? result[0] : null + } + + async invokeValidate(data, all, allData) { + let result = [] + let schema = this._schema + for (let key in schema) { + let value = schema[key] + let errorMessage = await this.validateRule(key, value, data[key], data, allData) + if (errorMessage != null) { + result.push({ + key, + errorMessage + }) + if (!all) break + } + } + return result + } + + async invokeValidateUpdate(data, all, allData) { + let result = [] + for (let key in data) { + let errorMessage = await this.validateRule(key, this._schema[key], data[key], data, allData) + if (errorMessage != null) { + result.push({ + key, + errorMessage + }) + if (!all) break + } + } + return result + } + + _checkFieldInSchema(data) { + var keys = Object.keys(data) + var keys2 = Object.keys(this._schema) + if (new Set(keys.concat(keys2)).size === keys2.length) { + return '' + } + + var noExistFields = keys.filter((key) => { + return keys2.indexOf(key) < 0; + }) + var errorMessage = formatMessage({ + field: JSON.stringify(noExistFields) + }, SchemaValidator.message.TAG + SchemaValidator.message['defaultInvalid']) + return [{ + key: 'invalid', + errorMessage + }] + } +} + +function Message() { + return { + TAG: "", + default: '验证错误', + defaultInvalid: '提交的字段{field}在数据库中并不存在', + validateFunction: '验证无效', + required: '{label}必填', + 'enum': '{label}超出范围', + timestamp: '{label}格式无效', + whitespace: '{label}不能为空', + typeError: '{label}类型无效', + date: { + format: '{label}日期{value}格式无效', + parse: '{label}日期无法解析,{value}无效', + invalid: '{label}日期{value}无效' + }, + length: { + minLength: '{label}长度不能少于{minLength}', + maxLength: '{label}长度不能超过{maxLength}', + range: '{label}必须介于{minLength}和{maxLength}之间' + }, + number: { + minimum: '{label}不能小于{minimum}', + maximum: '{label}不能大于{maximum}', + exclusiveMinimum: '{label}不能小于等于{minimum}', + exclusiveMaximum: '{label}不能大于等于{maximum}', + range: '{label}必须介于{minimum}and{maximum}之间' + }, + pattern: { + mismatch: '{label}格式不匹配' + } + }; +} + + +SchemaValidator.message = new Message(); + +export default SchemaValidator diff --git a/uni_modules/uni-forms/package.json b/uni_modules/uni-forms/package.json new file mode 100644 index 0000000..464b4e6 --- /dev/null +++ b/uni_modules/uni-forms/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-forms", + "displayName": "uni-forms 表单", + "version": "1.4.10", + "description": "由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据", + "keywords": [ + "uni-ui", + "表单", + "校验", + "表单校验", + "表单验证" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-forms/readme.md b/uni_modules/uni-forms/readme.md new file mode 100644 index 0000000..63d5a04 --- /dev/null +++ b/uni_modules/uni-forms/readme.md @@ -0,0 +1,23 @@ + + +## Forms 表单 + +> **组件名:uni-forms** +> 代码块: `uForms`、`uni-forms-item` +> 关联组件:`uni-forms-item`、`uni-easyinput`、`uni-data-checkbox`、`uni-group`。 + + +uni-app的内置组件已经有了 `
`组件,用于提交表单内容。 + +然而几乎每个表单都需要做表单验证,为了方便做表单验证,减少重复开发,`uni ui` 又基于 ``组件封装了 ``组件,内置了表单验证功能。 + +`` 提供了 `rules`属性来描述校验规则、``子组件来包裹具体的表单项,以及给原生或三方组件提供了 `binddata()` 来设置表单值。 + +每个要校验的表单项,不管input还是checkbox,都必须放在``组件中,且一个``组件只能放置一个表单项。 + +``组件内部预留了显示error message的区域,默认是在表单项的底部。 + +另外,``组件下面的各个表单项,可以通过``包裹为不同的分组。同一``下的不同表单项目将聚拢在一起,同其他group保持垂直间距。``仅影响视觉效果。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-forms) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-goods-nav/changelog.md b/uni_modules/uni-goods-nav/changelog.md new file mode 100644 index 0000000..c6264c6 --- /dev/null +++ b/uni_modules/uni-goods-nav/changelog.md @@ -0,0 +1,18 @@ +## 1.2.1(2022-05-30) +- 新增 stat属性,是否开启uni统计功能 +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-goods-nav](https://uniapp.dcloud.io/component/uniui/uni-goods-nav) +## 1.1.1(2021-08-24) +- 新增 支持国际化 +## 1.1.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.7(2021-05-12) +- 新增 组件示例地址 +## 1.0.6(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 1.0.5(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.4(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/en.json b/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/en.json new file mode 100644 index 0000000..dcdba41 --- /dev/null +++ b/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/en.json @@ -0,0 +1,6 @@ +{ + "uni-goods-nav.options.shop": "shop", + "uni-goods-nav.options.cart": "cart", + "uni-goods-nav.buttonGroup.addToCart": "add to cart", + "uni-goods-nav.buttonGroup.buyNow": "buy now" +} diff --git a/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/index.js b/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/index.js new file mode 100644 index 0000000..de7509c --- /dev/null +++ b/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hans.json b/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hans.json new file mode 100644 index 0000000..48ee344 --- /dev/null +++ b/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hans.json @@ -0,0 +1,6 @@ +{ + "uni-goods-nav.options.shop": "店铺", + "uni-goods-nav.options.cart": "购物车", + "uni-goods-nav.buttonGroup.addToCart": "加入购物车", + "uni-goods-nav.buttonGroup.buyNow": "立即购买" +} diff --git a/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hant.json b/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hant.json new file mode 100644 index 0000000..d0a0255 --- /dev/null +++ b/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hant.json @@ -0,0 +1,6 @@ +{ + "uni-goods-nav.options.shop": "店鋪", + "uni-goods-nav.options.cart": "購物車", + "uni-goods-nav.buttonGroup.addToCart": "加入購物車", + "uni-goods-nav.buttonGroup.buyNow": "立即購買" +} diff --git a/uni_modules/uni-goods-nav/components/uni-goods-nav/uni-goods-nav.vue b/uni_modules/uni-goods-nav/components/uni-goods-nav/uni-goods-nav.vue new file mode 100644 index 0000000..8a16b17 --- /dev/null +++ b/uni_modules/uni-goods-nav/components/uni-goods-nav/uni-goods-nav.vue @@ -0,0 +1,229 @@ + + + + + diff --git a/uni_modules/uni-goods-nav/package.json b/uni_modules/uni-goods-nav/package.json new file mode 100644 index 0000000..636e45e --- /dev/null +++ b/uni_modules/uni-goods-nav/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-goods-nav", + "displayName": "uni-goods-nav 商品导航", + "version": "1.2.1", + "description": "商品导航组件主要用于电商类应用底部导航,可自定义加入购物车,购买等操作", + "keywords": [ + "uni-ui", + "uniui", + "商品导航" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-icons" + ], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-goods-nav/readme.md b/uni_modules/uni-goods-nav/readme.md new file mode 100644 index 0000000..07df93f --- /dev/null +++ b/uni_modules/uni-goods-nav/readme.md @@ -0,0 +1,10 @@ + + +## GoodsNav 商品导航 +> **组件名:uni-goods-nav** +> 代码块: `uGoodsNav` + +商品加入购物车,立即购买等。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-goods-nav) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-grid/changelog.md b/uni_modules/uni-grid/changelog.md new file mode 100644 index 0000000..d301166 --- /dev/null +++ b/uni_modules/uni-grid/changelog.md @@ -0,0 +1,13 @@ +## 1.4.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-grid](https://uniapp.dcloud.io/component/uniui/uni-grid) +## 1.3.2(2021-11-09) +- 新增 提供组件设计资源,组件样式调整 +## 1.3.1(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.3.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.2.4(2021-05-12) +- 新增 组件示例地址 +## 1.2.3(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue b/uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue new file mode 100644 index 0000000..19c08d7 --- /dev/null +++ b/uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue @@ -0,0 +1,127 @@ + + + + + diff --git a/uni_modules/uni-grid/components/uni-grid/uni-grid.vue b/uni_modules/uni-grid/components/uni-grid/uni-grid.vue new file mode 100644 index 0000000..0edc7ff --- /dev/null +++ b/uni_modules/uni-grid/components/uni-grid/uni-grid.vue @@ -0,0 +1,142 @@ + + + + + diff --git a/uni_modules/uni-grid/package.json b/uni_modules/uni-grid/package.json new file mode 100644 index 0000000..ccb2c91 --- /dev/null +++ b/uni_modules/uni-grid/package.json @@ -0,0 +1,86 @@ +{ + "id": "uni-grid", + "displayName": "uni-grid 宫格", + "version": "1.4.0", + "description": "Grid 宫格组件,提供移动端常见的宫格布局,如九宫格。", + "keywords": [ + "uni-ui", + "uniui", + "九宫格", + "表格" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": ["uni-scss","uni-icons"], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-grid/readme.md b/uni_modules/uni-grid/readme.md new file mode 100644 index 0000000..0aa44cc --- /dev/null +++ b/uni_modules/uni-grid/readme.md @@ -0,0 +1,11 @@ + + +## Grid 宫格 +> **组件名:uni-grid** +> 代码块: `uGrid` + + +宫格组件。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-grid) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-group/changelog.md b/uni_modules/uni-group/changelog.md new file mode 100644 index 0000000..a7024fd --- /dev/null +++ b/uni_modules/uni-group/changelog.md @@ -0,0 +1,16 @@ +## 1.2.2(2022-05-30) +- 新增 stat属性,是否开启uni统计功能 +## 1.2.1(2021-11-22) +- 修复 vue3中某些scss变量无法找到的问题 +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-group](https://uniapp.dcloud.io/component/uniui/uni-group) +## 1.1.7(2021-11-08) +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +- 优化 组件文档 +## 1.0.3(2021-05-12) +- 新增 组件示例地址 +## 1.0.2(2021-02-05) +- 调整为uni_modules目录规范 +- 优化 兼容 nvue 页面 diff --git a/uni_modules/uni-group/components/uni-group/uni-group.vue b/uni_modules/uni-group/components/uni-group/uni-group.vue new file mode 100644 index 0000000..3425ecd --- /dev/null +++ b/uni_modules/uni-group/components/uni-group/uni-group.vue @@ -0,0 +1,134 @@ + + + + diff --git a/uni_modules/uni-group/package.json b/uni_modules/uni-group/package.json new file mode 100644 index 0000000..ea00a08 --- /dev/null +++ b/uni_modules/uni-group/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-group", + "displayName": "uni-group 分组", + "version": "1.2.2", + "description": "分组组件可用于将组件用于分组,添加间隔,以产生明显的区块", + "keywords": [ + "uni-ui", + "uniui", + "group", + "分组", + "" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-group/readme.md b/uni_modules/uni-group/readme.md new file mode 100644 index 0000000..bae67f4 --- /dev/null +++ b/uni_modules/uni-group/readme.md @@ -0,0 +1,9 @@ + +## Group 分组 +> **组件名:uni-group** +> 代码块: `uGroup` + +分组组件可用于将组件分组,添加间隔,以产生明显的区块。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-group) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-icons/changelog.md b/uni_modules/uni-icons/changelog.md new file mode 100644 index 0000000..0261131 --- /dev/null +++ b/uni_modules/uni-icons/changelog.md @@ -0,0 +1,42 @@ +## 2.0.10(2024-06-07) +- 优化 uni-app x 中,size 属性的类型 +## 2.0.9(2024-01-12) +fix: 修复图标大小默认值错误的问题 +## 2.0.8(2023-12-14) +- 修复 项目未使用 ts 情况下,打包报错的bug +## 2.0.7(2023-12-14) +- 修复 size 属性为 string 时,不加单位导致尺寸异常的bug +## 2.0.6(2023-12-11) +- 优化 兼容老版本icon类型,如 top ,bottom 等 +## 2.0.5(2023-12-11) +- 优化 兼容老版本icon类型,如 top ,bottom 等 +## 2.0.4(2023-12-06) +- 优化 uni-app x 下示例项目图标排序 +## 2.0.3(2023-12-06) +- 修复 nvue下引入组件报错的bug +## 2.0.2(2023-12-05) +-优化 size 属性支持单位 +## 2.0.1(2023-12-05) +- 新增 uni-app x 支持定义图标 +## 1.3.5(2022-01-24) +- 优化 size 属性可以传入不带单位的字符串数值 +## 1.3.4(2022-01-24) +- 优化 size 支持其他单位 +## 1.3.3(2022-01-17) +- 修复 nvue 有些图标不显示的bug,兼容老版本图标 +## 1.3.2(2021-12-01) +- 优化 示例可复制图标名称 +## 1.3.1(2021-11-23) +- 优化 兼容旧组件 type 值 +## 1.3.0(2021-11-19) +- 新增 更多图标 +- 优化 自定义图标使用方式 +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-icons](https://uniapp.dcloud.io/component/uniui/uni-icons) +## 1.1.7(2021-11-08) +## 1.2.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.5(2021-05-12) +- 新增 组件示例地址 +## 1.1.4(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-icons/components/uni-icons/icons.js b/uni_modules/uni-icons/components/uni-icons/icons.js new file mode 100644 index 0000000..7889936 --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/icons.js @@ -0,0 +1,1169 @@ +export default { + "id": "2852637", + "name": "uniui图标库", + "font_family": "uniicons", + "css_prefix_text": "uniui-", + "description": "", + "glyphs": [ + { + "icon_id": "25027049", + "name": "yanse", + "font_class": "color", + "unicode": "e6cf", + "unicode_decimal": 59087 + }, + { + "icon_id": "25027048", + "name": "wallet", + "font_class": "wallet", + "unicode": "e6b1", + "unicode_decimal": 59057 + }, + { + "icon_id": "25015720", + "name": "settings-filled", + "font_class": "settings-filled", + "unicode": "e6ce", + "unicode_decimal": 59086 + }, + { + "icon_id": "25015434", + "name": "shimingrenzheng-filled", + "font_class": "auth-filled", + "unicode": "e6cc", + "unicode_decimal": 59084 + }, + { + "icon_id": "24934246", + "name": "shop-filled", + "font_class": "shop-filled", + "unicode": "e6cd", + "unicode_decimal": 59085 + }, + { + "icon_id": "24934159", + "name": "staff-filled-01", + "font_class": "staff-filled", + "unicode": "e6cb", + "unicode_decimal": 59083 + }, + { + "icon_id": "24932461", + "name": "VIP-filled", + "font_class": "vip-filled", + "unicode": "e6c6", + "unicode_decimal": 59078 + }, + { + "icon_id": "24932462", + "name": "plus_circle_fill", + "font_class": "plus-filled", + "unicode": "e6c7", + "unicode_decimal": 59079 + }, + { + "icon_id": "24932463", + "name": "folder_add-filled", + "font_class": "folder-add-filled", + "unicode": "e6c8", + "unicode_decimal": 59080 + }, + { + "icon_id": "24932464", + "name": "yanse-filled", + "font_class": "color-filled", + "unicode": "e6c9", + "unicode_decimal": 59081 + }, + { + "icon_id": "24932465", + "name": "tune-filled", + "font_class": "tune-filled", + "unicode": "e6ca", + "unicode_decimal": 59082 + }, + { + "icon_id": "24932455", + "name": "a-rilidaka-filled", + "font_class": "calendar-filled", + "unicode": "e6c0", + "unicode_decimal": 59072 + }, + { + "icon_id": "24932456", + "name": "notification-filled", + "font_class": "notification-filled", + "unicode": "e6c1", + "unicode_decimal": 59073 + }, + { + "icon_id": "24932457", + "name": "wallet-filled", + "font_class": "wallet-filled", + "unicode": "e6c2", + "unicode_decimal": 59074 + }, + { + "icon_id": "24932458", + "name": "paihangbang-filled", + "font_class": "medal-filled", + "unicode": "e6c3", + "unicode_decimal": 59075 + }, + { + "icon_id": "24932459", + "name": "gift-filled", + "font_class": "gift-filled", + "unicode": "e6c4", + "unicode_decimal": 59076 + }, + { + "icon_id": "24932460", + "name": "fire-filled", + "font_class": "fire-filled", + "unicode": "e6c5", + "unicode_decimal": 59077 + }, + { + "icon_id": "24928001", + "name": "refreshempty", + "font_class": "refreshempty", + "unicode": "e6bf", + "unicode_decimal": 59071 + }, + { + "icon_id": "24926853", + "name": "location-ellipse", + "font_class": "location-filled", + "unicode": "e6af", + "unicode_decimal": 59055 + }, + { + "icon_id": "24926735", + "name": "person-filled", + "font_class": "person-filled", + "unicode": "e69d", + "unicode_decimal": 59037 + }, + { + "icon_id": "24926703", + "name": "personadd-filled", + "font_class": "personadd-filled", + "unicode": "e698", + "unicode_decimal": 59032 + }, + { + "icon_id": "24923351", + "name": "back", + "font_class": "back", + "unicode": "e6b9", + "unicode_decimal": 59065 + }, + { + "icon_id": "24923352", + "name": "forward", + "font_class": "forward", + "unicode": "e6ba", + "unicode_decimal": 59066 + }, + { + "icon_id": "24923353", + "name": "arrowthinright", + "font_class": "arrow-right", + "unicode": "e6bb", + "unicode_decimal": 59067 + }, + { + "icon_id": "24923353", + "name": "arrowthinright", + "font_class": "arrowthinright", + "unicode": "e6bb", + "unicode_decimal": 59067 + }, + { + "icon_id": "24923354", + "name": "arrowthinleft", + "font_class": "arrow-left", + "unicode": "e6bc", + "unicode_decimal": 59068 + }, + { + "icon_id": "24923354", + "name": "arrowthinleft", + "font_class": "arrowthinleft", + "unicode": "e6bc", + "unicode_decimal": 59068 + }, + { + "icon_id": "24923355", + "name": "arrowthinup", + "font_class": "arrow-up", + "unicode": "e6bd", + "unicode_decimal": 59069 + }, + { + "icon_id": "24923355", + "name": "arrowthinup", + "font_class": "arrowthinup", + "unicode": "e6bd", + "unicode_decimal": 59069 + }, + { + "icon_id": "24923356", + "name": "arrowthindown", + "font_class": "arrow-down", + "unicode": "e6be", + "unicode_decimal": 59070 + },{ + "icon_id": "24923356", + "name": "arrowthindown", + "font_class": "arrowthindown", + "unicode": "e6be", + "unicode_decimal": 59070 + }, + { + "icon_id": "24923349", + "name": "arrowdown", + "font_class": "bottom", + "unicode": "e6b8", + "unicode_decimal": 59064 + },{ + "icon_id": "24923349", + "name": "arrowdown", + "font_class": "arrowdown", + "unicode": "e6b8", + "unicode_decimal": 59064 + }, + { + "icon_id": "24923346", + "name": "arrowright", + "font_class": "right", + "unicode": "e6b5", + "unicode_decimal": 59061 + }, + { + "icon_id": "24923346", + "name": "arrowright", + "font_class": "arrowright", + "unicode": "e6b5", + "unicode_decimal": 59061 + }, + { + "icon_id": "24923347", + "name": "arrowup", + "font_class": "top", + "unicode": "e6b6", + "unicode_decimal": 59062 + }, + { + "icon_id": "24923347", + "name": "arrowup", + "font_class": "arrowup", + "unicode": "e6b6", + "unicode_decimal": 59062 + }, + { + "icon_id": "24923348", + "name": "arrowleft", + "font_class": "left", + "unicode": "e6b7", + "unicode_decimal": 59063 + }, + { + "icon_id": "24923348", + "name": "arrowleft", + "font_class": "arrowleft", + "unicode": "e6b7", + "unicode_decimal": 59063 + }, + { + "icon_id": "24923334", + "name": "eye", + "font_class": "eye", + "unicode": "e651", + "unicode_decimal": 58961 + }, + { + "icon_id": "24923335", + "name": "eye-filled", + "font_class": "eye-filled", + "unicode": "e66a", + "unicode_decimal": 58986 + }, + { + "icon_id": "24923336", + "name": "eye-slash", + "font_class": "eye-slash", + "unicode": "e6b3", + "unicode_decimal": 59059 + }, + { + "icon_id": "24923337", + "name": "eye-slash-filled", + "font_class": "eye-slash-filled", + "unicode": "e6b4", + "unicode_decimal": 59060 + }, + { + "icon_id": "24923305", + "name": "info-filled", + "font_class": "info-filled", + "unicode": "e649", + "unicode_decimal": 58953 + }, + { + "icon_id": "24923299", + "name": "reload-01", + "font_class": "reload", + "unicode": "e6b2", + "unicode_decimal": 59058 + }, + { + "icon_id": "24923195", + "name": "mic_slash_fill", + "font_class": "micoff-filled", + "unicode": "e6b0", + "unicode_decimal": 59056 + }, + { + "icon_id": "24923165", + "name": "map-pin-ellipse", + "font_class": "map-pin-ellipse", + "unicode": "e6ac", + "unicode_decimal": 59052 + }, + { + "icon_id": "24923166", + "name": "map-pin", + "font_class": "map-pin", + "unicode": "e6ad", + "unicode_decimal": 59053 + }, + { + "icon_id": "24923167", + "name": "location", + "font_class": "location", + "unicode": "e6ae", + "unicode_decimal": 59054 + }, + { + "icon_id": "24923064", + "name": "starhalf", + "font_class": "starhalf", + "unicode": "e683", + "unicode_decimal": 59011 + }, + { + "icon_id": "24923065", + "name": "star", + "font_class": "star", + "unicode": "e688", + "unicode_decimal": 59016 + }, + { + "icon_id": "24923066", + "name": "star-filled", + "font_class": "star-filled", + "unicode": "e68f", + "unicode_decimal": 59023 + }, + { + "icon_id": "24899646", + "name": "a-rilidaka", + "font_class": "calendar", + "unicode": "e6a0", + "unicode_decimal": 59040 + }, + { + "icon_id": "24899647", + "name": "fire", + "font_class": "fire", + "unicode": "e6a1", + "unicode_decimal": 59041 + }, + { + "icon_id": "24899648", + "name": "paihangbang", + "font_class": "medal", + "unicode": "e6a2", + "unicode_decimal": 59042 + }, + { + "icon_id": "24899649", + "name": "font", + "font_class": "font", + "unicode": "e6a3", + "unicode_decimal": 59043 + }, + { + "icon_id": "24899650", + "name": "gift", + "font_class": "gift", + "unicode": "e6a4", + "unicode_decimal": 59044 + }, + { + "icon_id": "24899651", + "name": "link", + "font_class": "link", + "unicode": "e6a5", + "unicode_decimal": 59045 + }, + { + "icon_id": "24899652", + "name": "notification", + "font_class": "notification", + "unicode": "e6a6", + "unicode_decimal": 59046 + }, + { + "icon_id": "24899653", + "name": "staff", + "font_class": "staff", + "unicode": "e6a7", + "unicode_decimal": 59047 + }, + { + "icon_id": "24899654", + "name": "VIP", + "font_class": "vip", + "unicode": "e6a8", + "unicode_decimal": 59048 + }, + { + "icon_id": "24899655", + "name": "folder_add", + "font_class": "folder-add", + "unicode": "e6a9", + "unicode_decimal": 59049 + }, + { + "icon_id": "24899656", + "name": "tune", + "font_class": "tune", + "unicode": "e6aa", + "unicode_decimal": 59050 + }, + { + "icon_id": "24899657", + "name": "shimingrenzheng", + "font_class": "auth", + "unicode": "e6ab", + "unicode_decimal": 59051 + }, + { + "icon_id": "24899565", + "name": "person", + "font_class": "person", + "unicode": "e699", + "unicode_decimal": 59033 + }, + { + "icon_id": "24899566", + "name": "email-filled", + "font_class": "email-filled", + "unicode": "e69a", + "unicode_decimal": 59034 + }, + { + "icon_id": "24899567", + "name": "phone-filled", + "font_class": "phone-filled", + "unicode": "e69b", + "unicode_decimal": 59035 + }, + { + "icon_id": "24899568", + "name": "phone", + "font_class": "phone", + "unicode": "e69c", + "unicode_decimal": 59036 + }, + { + "icon_id": "24899570", + "name": "email", + "font_class": "email", + "unicode": "e69e", + "unicode_decimal": 59038 + }, + { + "icon_id": "24899571", + "name": "personadd", + "font_class": "personadd", + "unicode": "e69f", + "unicode_decimal": 59039 + }, + { + "icon_id": "24899558", + "name": "chatboxes-filled", + "font_class": "chatboxes-filled", + "unicode": "e692", + "unicode_decimal": 59026 + }, + { + "icon_id": "24899559", + "name": "contact", + "font_class": "contact", + "unicode": "e693", + "unicode_decimal": 59027 + }, + { + "icon_id": "24899560", + "name": "chatbubble-filled", + "font_class": "chatbubble-filled", + "unicode": "e694", + "unicode_decimal": 59028 + }, + { + "icon_id": "24899561", + "name": "contact-filled", + "font_class": "contact-filled", + "unicode": "e695", + "unicode_decimal": 59029 + }, + { + "icon_id": "24899562", + "name": "chatboxes", + "font_class": "chatboxes", + "unicode": "e696", + "unicode_decimal": 59030 + }, + { + "icon_id": "24899563", + "name": "chatbubble", + "font_class": "chatbubble", + "unicode": "e697", + "unicode_decimal": 59031 + }, + { + "icon_id": "24881290", + "name": "upload-filled", + "font_class": "upload-filled", + "unicode": "e68e", + "unicode_decimal": 59022 + }, + { + "icon_id": "24881292", + "name": "upload", + "font_class": "upload", + "unicode": "e690", + "unicode_decimal": 59024 + }, + { + "icon_id": "24881293", + "name": "weixin", + "font_class": "weixin", + "unicode": "e691", + "unicode_decimal": 59025 + }, + { + "icon_id": "24881274", + "name": "compose", + "font_class": "compose", + "unicode": "e67f", + "unicode_decimal": 59007 + }, + { + "icon_id": "24881275", + "name": "qq", + "font_class": "qq", + "unicode": "e680", + "unicode_decimal": 59008 + }, + { + "icon_id": "24881276", + "name": "download-filled", + "font_class": "download-filled", + "unicode": "e681", + "unicode_decimal": 59009 + }, + { + "icon_id": "24881277", + "name": "pengyouquan", + "font_class": "pyq", + "unicode": "e682", + "unicode_decimal": 59010 + }, + { + "icon_id": "24881279", + "name": "sound", + "font_class": "sound", + "unicode": "e684", + "unicode_decimal": 59012 + }, + { + "icon_id": "24881280", + "name": "trash-filled", + "font_class": "trash-filled", + "unicode": "e685", + "unicode_decimal": 59013 + }, + { + "icon_id": "24881281", + "name": "sound-filled", + "font_class": "sound-filled", + "unicode": "e686", + "unicode_decimal": 59014 + }, + { + "icon_id": "24881282", + "name": "trash", + "font_class": "trash", + "unicode": "e687", + "unicode_decimal": 59015 + }, + { + "icon_id": "24881284", + "name": "videocam-filled", + "font_class": "videocam-filled", + "unicode": "e689", + "unicode_decimal": 59017 + }, + { + "icon_id": "24881285", + "name": "spinner-cycle", + "font_class": "spinner-cycle", + "unicode": "e68a", + "unicode_decimal": 59018 + }, + { + "icon_id": "24881286", + "name": "weibo", + "font_class": "weibo", + "unicode": "e68b", + "unicode_decimal": 59019 + }, + { + "icon_id": "24881288", + "name": "videocam", + "font_class": "videocam", + "unicode": "e68c", + "unicode_decimal": 59020 + }, + { + "icon_id": "24881289", + "name": "download", + "font_class": "download", + "unicode": "e68d", + "unicode_decimal": 59021 + }, + { + "icon_id": "24879601", + "name": "help", + "font_class": "help", + "unicode": "e679", + "unicode_decimal": 59001 + }, + { + "icon_id": "24879602", + "name": "navigate-filled", + "font_class": "navigate-filled", + "unicode": "e67a", + "unicode_decimal": 59002 + }, + { + "icon_id": "24879603", + "name": "plusempty", + "font_class": "plusempty", + "unicode": "e67b", + "unicode_decimal": 59003 + }, + { + "icon_id": "24879604", + "name": "smallcircle", + "font_class": "smallcircle", + "unicode": "e67c", + "unicode_decimal": 59004 + }, + { + "icon_id": "24879605", + "name": "minus-filled", + "font_class": "minus-filled", + "unicode": "e67d", + "unicode_decimal": 59005 + }, + { + "icon_id": "24879606", + "name": "micoff", + "font_class": "micoff", + "unicode": "e67e", + "unicode_decimal": 59006 + }, + { + "icon_id": "24879588", + "name": "closeempty", + "font_class": "closeempty", + "unicode": "e66c", + "unicode_decimal": 58988 + }, + { + "icon_id": "24879589", + "name": "clear", + "font_class": "clear", + "unicode": "e66d", + "unicode_decimal": 58989 + }, + { + "icon_id": "24879590", + "name": "navigate", + "font_class": "navigate", + "unicode": "e66e", + "unicode_decimal": 58990 + }, + { + "icon_id": "24879591", + "name": "minus", + "font_class": "minus", + "unicode": "e66f", + "unicode_decimal": 58991 + }, + { + "icon_id": "24879592", + "name": "image", + "font_class": "image", + "unicode": "e670", + "unicode_decimal": 58992 + }, + { + "icon_id": "24879593", + "name": "mic", + "font_class": "mic", + "unicode": "e671", + "unicode_decimal": 58993 + }, + { + "icon_id": "24879594", + "name": "paperplane", + "font_class": "paperplane", + "unicode": "e672", + "unicode_decimal": 58994 + }, + { + "icon_id": "24879595", + "name": "close", + "font_class": "close", + "unicode": "e673", + "unicode_decimal": 58995 + }, + { + "icon_id": "24879596", + "name": "help-filled", + "font_class": "help-filled", + "unicode": "e674", + "unicode_decimal": 58996 + }, + { + "icon_id": "24879597", + "name": "plus-filled", + "font_class": "paperplane-filled", + "unicode": "e675", + "unicode_decimal": 58997 + }, + { + "icon_id": "24879598", + "name": "plus", + "font_class": "plus", + "unicode": "e676", + "unicode_decimal": 58998 + }, + { + "icon_id": "24879599", + "name": "mic-filled", + "font_class": "mic-filled", + "unicode": "e677", + "unicode_decimal": 58999 + }, + { + "icon_id": "24879600", + "name": "image-filled", + "font_class": "image-filled", + "unicode": "e678", + "unicode_decimal": 59000 + }, + { + "icon_id": "24855900", + "name": "locked-filled", + "font_class": "locked-filled", + "unicode": "e668", + "unicode_decimal": 58984 + }, + { + "icon_id": "24855901", + "name": "info", + "font_class": "info", + "unicode": "e669", + "unicode_decimal": 58985 + }, + { + "icon_id": "24855903", + "name": "locked", + "font_class": "locked", + "unicode": "e66b", + "unicode_decimal": 58987 + }, + { + "icon_id": "24855884", + "name": "camera-filled", + "font_class": "camera-filled", + "unicode": "e658", + "unicode_decimal": 58968 + }, + { + "icon_id": "24855885", + "name": "chat-filled", + "font_class": "chat-filled", + "unicode": "e659", + "unicode_decimal": 58969 + }, + { + "icon_id": "24855886", + "name": "camera", + "font_class": "camera", + "unicode": "e65a", + "unicode_decimal": 58970 + }, + { + "icon_id": "24855887", + "name": "circle", + "font_class": "circle", + "unicode": "e65b", + "unicode_decimal": 58971 + }, + { + "icon_id": "24855888", + "name": "checkmarkempty", + "font_class": "checkmarkempty", + "unicode": "e65c", + "unicode_decimal": 58972 + }, + { + "icon_id": "24855889", + "name": "chat", + "font_class": "chat", + "unicode": "e65d", + "unicode_decimal": 58973 + }, + { + "icon_id": "24855890", + "name": "circle-filled", + "font_class": "circle-filled", + "unicode": "e65e", + "unicode_decimal": 58974 + }, + { + "icon_id": "24855891", + "name": "flag", + "font_class": "flag", + "unicode": "e65f", + "unicode_decimal": 58975 + }, + { + "icon_id": "24855892", + "name": "flag-filled", + "font_class": "flag-filled", + "unicode": "e660", + "unicode_decimal": 58976 + }, + { + "icon_id": "24855893", + "name": "gear-filled", + "font_class": "gear-filled", + "unicode": "e661", + "unicode_decimal": 58977 + }, + { + "icon_id": "24855894", + "name": "home", + "font_class": "home", + "unicode": "e662", + "unicode_decimal": 58978 + }, + { + "icon_id": "24855895", + "name": "home-filled", + "font_class": "home-filled", + "unicode": "e663", + "unicode_decimal": 58979 + }, + { + "icon_id": "24855896", + "name": "gear", + "font_class": "gear", + "unicode": "e664", + "unicode_decimal": 58980 + }, + { + "icon_id": "24855897", + "name": "smallcircle-filled", + "font_class": "smallcircle-filled", + "unicode": "e665", + "unicode_decimal": 58981 + }, + { + "icon_id": "24855898", + "name": "map-filled", + "font_class": "map-filled", + "unicode": "e666", + "unicode_decimal": 58982 + }, + { + "icon_id": "24855899", + "name": "map", + "font_class": "map", + "unicode": "e667", + "unicode_decimal": 58983 + }, + { + "icon_id": "24855825", + "name": "refresh-filled", + "font_class": "refresh-filled", + "unicode": "e656", + "unicode_decimal": 58966 + }, + { + "icon_id": "24855826", + "name": "refresh", + "font_class": "refresh", + "unicode": "e657", + "unicode_decimal": 58967 + }, + { + "icon_id": "24855808", + "name": "cloud-upload", + "font_class": "cloud-upload", + "unicode": "e645", + "unicode_decimal": 58949 + }, + { + "icon_id": "24855809", + "name": "cloud-download-filled", + "font_class": "cloud-download-filled", + "unicode": "e646", + "unicode_decimal": 58950 + }, + { + "icon_id": "24855810", + "name": "cloud-download", + "font_class": "cloud-download", + "unicode": "e647", + "unicode_decimal": 58951 + }, + { + "icon_id": "24855811", + "name": "cloud-upload-filled", + "font_class": "cloud-upload-filled", + "unicode": "e648", + "unicode_decimal": 58952 + }, + { + "icon_id": "24855813", + "name": "redo", + "font_class": "redo", + "unicode": "e64a", + "unicode_decimal": 58954 + }, + { + "icon_id": "24855814", + "name": "images-filled", + "font_class": "images-filled", + "unicode": "e64b", + "unicode_decimal": 58955 + }, + { + "icon_id": "24855815", + "name": "undo-filled", + "font_class": "undo-filled", + "unicode": "e64c", + "unicode_decimal": 58956 + }, + { + "icon_id": "24855816", + "name": "more", + "font_class": "more", + "unicode": "e64d", + "unicode_decimal": 58957 + }, + { + "icon_id": "24855817", + "name": "more-filled", + "font_class": "more-filled", + "unicode": "e64e", + "unicode_decimal": 58958 + }, + { + "icon_id": "24855818", + "name": "undo", + "font_class": "undo", + "unicode": "e64f", + "unicode_decimal": 58959 + }, + { + "icon_id": "24855819", + "name": "images", + "font_class": "images", + "unicode": "e650", + "unicode_decimal": 58960 + }, + { + "icon_id": "24855821", + "name": "paperclip", + "font_class": "paperclip", + "unicode": "e652", + "unicode_decimal": 58962 + }, + { + "icon_id": "24855822", + "name": "settings", + "font_class": "settings", + "unicode": "e653", + "unicode_decimal": 58963 + }, + { + "icon_id": "24855823", + "name": "search", + "font_class": "search", + "unicode": "e654", + "unicode_decimal": 58964 + }, + { + "icon_id": "24855824", + "name": "redo-filled", + "font_class": "redo-filled", + "unicode": "e655", + "unicode_decimal": 58965 + }, + { + "icon_id": "24841702", + "name": "list", + "font_class": "list", + "unicode": "e644", + "unicode_decimal": 58948 + }, + { + "icon_id": "24841489", + "name": "mail-open-filled", + "font_class": "mail-open-filled", + "unicode": "e63a", + "unicode_decimal": 58938 + }, + { + "icon_id": "24841491", + "name": "hand-thumbsdown-filled", + "font_class": "hand-down-filled", + "unicode": "e63c", + "unicode_decimal": 58940 + }, + { + "icon_id": "24841492", + "name": "hand-thumbsdown", + "font_class": "hand-down", + "unicode": "e63d", + "unicode_decimal": 58941 + }, + { + "icon_id": "24841493", + "name": "hand-thumbsup-filled", + "font_class": "hand-up-filled", + "unicode": "e63e", + "unicode_decimal": 58942 + }, + { + "icon_id": "24841494", + "name": "hand-thumbsup", + "font_class": "hand-up", + "unicode": "e63f", + "unicode_decimal": 58943 + }, + { + "icon_id": "24841496", + "name": "heart-filled", + "font_class": "heart-filled", + "unicode": "e641", + "unicode_decimal": 58945 + }, + { + "icon_id": "24841498", + "name": "mail-open", + "font_class": "mail-open", + "unicode": "e643", + "unicode_decimal": 58947 + }, + { + "icon_id": "24841488", + "name": "heart", + "font_class": "heart", + "unicode": "e639", + "unicode_decimal": 58937 + }, + { + "icon_id": "24839963", + "name": "loop", + "font_class": "loop", + "unicode": "e633", + "unicode_decimal": 58931 + }, + { + "icon_id": "24839866", + "name": "pulldown", + "font_class": "pulldown", + "unicode": "e632", + "unicode_decimal": 58930 + }, + { + "icon_id": "24813798", + "name": "scan", + "font_class": "scan", + "unicode": "e62a", + "unicode_decimal": 58922 + }, + { + "icon_id": "24813786", + "name": "bars", + "font_class": "bars", + "unicode": "e627", + "unicode_decimal": 58919 + }, + { + "icon_id": "24813788", + "name": "cart-filled", + "font_class": "cart-filled", + "unicode": "e629", + "unicode_decimal": 58921 + }, + { + "icon_id": "24813790", + "name": "checkbox", + "font_class": "checkbox", + "unicode": "e62b", + "unicode_decimal": 58923 + }, + { + "icon_id": "24813791", + "name": "checkbox-filled", + "font_class": "checkbox-filled", + "unicode": "e62c", + "unicode_decimal": 58924 + }, + { + "icon_id": "24813794", + "name": "shop", + "font_class": "shop", + "unicode": "e62f", + "unicode_decimal": 58927 + }, + { + "icon_id": "24813795", + "name": "headphones", + "font_class": "headphones", + "unicode": "e630", + "unicode_decimal": 58928 + }, + { + "icon_id": "24813796", + "name": "cart", + "font_class": "cart", + "unicode": "e631", + "unicode_decimal": 58929 + } + ] +} diff --git a/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue b/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue new file mode 100644 index 0000000..8740559 --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue @@ -0,0 +1,91 @@ + + + + + diff --git a/uni_modules/uni-icons/components/uni-icons/uni-icons.vue b/uni_modules/uni-icons/components/uni-icons/uni-icons.vue new file mode 100644 index 0000000..7da5356 --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/uni-icons.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/uni_modules/uni-icons/components/uni-icons/uni.ttf b/uni_modules/uni-icons/components/uni-icons/uni.ttf new file mode 100644 index 0000000000000000000000000000000000000000..60a1968d08cc6056c70b5402b2effac43c6f96a3 GIT binary patch literal 26164 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 literal 0 HcmV?d00001 diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons.css b/uni_modules/uni-icons/components/uni-icons/uniicons.css new file mode 100644 index 0000000..0a6b6fe --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/uniicons.css @@ -0,0 +1,664 @@ + +.uniui-cart-filled:before { + content: "\e6d0"; +} + +.uniui-gift-filled:before { + content: "\e6c4"; +} + +.uniui-color:before { + content: "\e6cf"; +} + +.uniui-wallet:before { + content: "\e6b1"; +} + +.uniui-settings-filled:before { + content: "\e6ce"; +} + +.uniui-auth-filled:before { + content: "\e6cc"; +} + +.uniui-shop-filled:before { + content: "\e6cd"; +} + +.uniui-staff-filled:before { + content: "\e6cb"; +} + +.uniui-vip-filled:before { + content: "\e6c6"; +} + +.uniui-plus-filled:before { + content: "\e6c7"; +} + +.uniui-folder-add-filled:before { + content: "\e6c8"; +} + +.uniui-color-filled:before { + content: "\e6c9"; +} + +.uniui-tune-filled:before { + content: "\e6ca"; +} + +.uniui-calendar-filled:before { + content: "\e6c0"; +} + +.uniui-notification-filled:before { + content: "\e6c1"; +} + +.uniui-wallet-filled:before { + content: "\e6c2"; +} + +.uniui-medal-filled:before { + content: "\e6c3"; +} + +.uniui-fire-filled:before { + content: "\e6c5"; +} + +.uniui-refreshempty:before { + content: "\e6bf"; +} + +.uniui-location-filled:before { + content: "\e6af"; +} + +.uniui-person-filled:before { + content: "\e69d"; +} + +.uniui-personadd-filled:before { + content: "\e698"; +} + +.uniui-arrowthinleft:before { + content: "\e6d2"; +} + +.uniui-arrowthinup:before { + content: "\e6d3"; +} + +.uniui-arrowthindown:before { + content: "\e6d4"; +} + +.uniui-back:before { + content: "\e6b9"; +} + +.uniui-forward:before { + content: "\e6ba"; +} + +.uniui-arrow-right:before { + content: "\e6bb"; +} + +.uniui-arrow-left:before { + content: "\e6bc"; +} + +.uniui-arrow-up:before { + content: "\e6bd"; +} + +.uniui-arrow-down:before { + content: "\e6be"; +} + +.uniui-arrowthinright:before { + content: "\e6d1"; +} + +.uniui-down:before { + content: "\e6b8"; +} + +.uniui-bottom:before { + content: "\e6b8"; +} + +.uniui-arrowright:before { + content: "\e6d5"; +} + +.uniui-right:before { + content: "\e6b5"; +} + +.uniui-up:before { + content: "\e6b6"; +} + +.uniui-top:before { + content: "\e6b6"; +} + +.uniui-left:before { + content: "\e6b7"; +} + +.uniui-arrowup:before { + content: "\e6d6"; +} + +.uniui-eye:before { + content: "\e651"; +} + +.uniui-eye-filled:before { + content: "\e66a"; +} + +.uniui-eye-slash:before { + content: "\e6b3"; +} + +.uniui-eye-slash-filled:before { + content: "\e6b4"; +} + +.uniui-info-filled:before { + content: "\e649"; +} + +.uniui-reload:before { + content: "\e6b2"; +} + +.uniui-micoff-filled:before { + content: "\e6b0"; +} + +.uniui-map-pin-ellipse:before { + content: "\e6ac"; +} + +.uniui-map-pin:before { + content: "\e6ad"; +} + +.uniui-location:before { + content: "\e6ae"; +} + +.uniui-starhalf:before { + content: "\e683"; +} + +.uniui-star:before { + content: "\e688"; +} + +.uniui-star-filled:before { + content: "\e68f"; +} + +.uniui-calendar:before { + content: "\e6a0"; +} + +.uniui-fire:before { + content: "\e6a1"; +} + +.uniui-medal:before { + content: "\e6a2"; +} + +.uniui-font:before { + content: "\e6a3"; +} + +.uniui-gift:before { + content: "\e6a4"; +} + +.uniui-link:before { + content: "\e6a5"; +} + +.uniui-notification:before { + content: "\e6a6"; +} + +.uniui-staff:before { + content: "\e6a7"; +} + +.uniui-vip:before { + content: "\e6a8"; +} + +.uniui-folder-add:before { + content: "\e6a9"; +} + +.uniui-tune:before { + content: "\e6aa"; +} + +.uniui-auth:before { + content: "\e6ab"; +} + +.uniui-person:before { + content: "\e699"; +} + +.uniui-email-filled:before { + content: "\e69a"; +} + +.uniui-phone-filled:before { + content: "\e69b"; +} + +.uniui-phone:before { + content: "\e69c"; +} + +.uniui-email:before { + content: "\e69e"; +} + +.uniui-personadd:before { + content: "\e69f"; +} + +.uniui-chatboxes-filled:before { + content: "\e692"; +} + +.uniui-contact:before { + content: "\e693"; +} + +.uniui-chatbubble-filled:before { + content: "\e694"; +} + +.uniui-contact-filled:before { + content: "\e695"; +} + +.uniui-chatboxes:before { + content: "\e696"; +} + +.uniui-chatbubble:before { + content: "\e697"; +} + +.uniui-upload-filled:before { + content: "\e68e"; +} + +.uniui-upload:before { + content: "\e690"; +} + +.uniui-weixin:before { + content: "\e691"; +} + +.uniui-compose:before { + content: "\e67f"; +} + +.uniui-qq:before { + content: "\e680"; +} + +.uniui-download-filled:before { + content: "\e681"; +} + +.uniui-pyq:before { + content: "\e682"; +} + +.uniui-sound:before { + content: "\e684"; +} + +.uniui-trash-filled:before { + content: "\e685"; +} + +.uniui-sound-filled:before { + content: "\e686"; +} + +.uniui-trash:before { + content: "\e687"; +} + +.uniui-videocam-filled:before { + content: "\e689"; +} + +.uniui-spinner-cycle:before { + content: "\e68a"; +} + +.uniui-weibo:before { + content: "\e68b"; +} + +.uniui-videocam:before { + content: "\e68c"; +} + +.uniui-download:before { + content: "\e68d"; +} + +.uniui-help:before { + content: "\e679"; +} + +.uniui-navigate-filled:before { + content: "\e67a"; +} + +.uniui-plusempty:before { + content: "\e67b"; +} + +.uniui-smallcircle:before { + content: "\e67c"; +} + +.uniui-minus-filled:before { + content: "\e67d"; +} + +.uniui-micoff:before { + content: "\e67e"; +} + +.uniui-closeempty:before { + content: "\e66c"; +} + +.uniui-clear:before { + content: "\e66d"; +} + +.uniui-navigate:before { + content: "\e66e"; +} + +.uniui-minus:before { + content: "\e66f"; +} + +.uniui-image:before { + content: "\e670"; +} + +.uniui-mic:before { + content: "\e671"; +} + +.uniui-paperplane:before { + content: "\e672"; +} + +.uniui-close:before { + content: "\e673"; +} + +.uniui-help-filled:before { + content: "\e674"; +} + +.uniui-paperplane-filled:before { + content: "\e675"; +} + +.uniui-plus:before { + content: "\e676"; +} + +.uniui-mic-filled:before { + content: "\e677"; +} + +.uniui-image-filled:before { + content: "\e678"; +} + +.uniui-locked-filled:before { + content: "\e668"; +} + +.uniui-info:before { + content: "\e669"; +} + +.uniui-locked:before { + content: "\e66b"; +} + +.uniui-camera-filled:before { + content: "\e658"; +} + +.uniui-chat-filled:before { + content: "\e659"; +} + +.uniui-camera:before { + content: "\e65a"; +} + +.uniui-circle:before { + content: "\e65b"; +} + +.uniui-checkmarkempty:before { + content: "\e65c"; +} + +.uniui-chat:before { + content: "\e65d"; +} + +.uniui-circle-filled:before { + content: "\e65e"; +} + +.uniui-flag:before { + content: "\e65f"; +} + +.uniui-flag-filled:before { + content: "\e660"; +} + +.uniui-gear-filled:before { + content: "\e661"; +} + +.uniui-home:before { + content: "\e662"; +} + +.uniui-home-filled:before { + content: "\e663"; +} + +.uniui-gear:before { + content: "\e664"; +} + +.uniui-smallcircle-filled:before { + content: "\e665"; +} + +.uniui-map-filled:before { + content: "\e666"; +} + +.uniui-map:before { + content: "\e667"; +} + +.uniui-refresh-filled:before { + content: "\e656"; +} + +.uniui-refresh:before { + content: "\e657"; +} + +.uniui-cloud-upload:before { + content: "\e645"; +} + +.uniui-cloud-download-filled:before { + content: "\e646"; +} + +.uniui-cloud-download:before { + content: "\e647"; +} + +.uniui-cloud-upload-filled:before { + content: "\e648"; +} + +.uniui-redo:before { + content: "\e64a"; +} + +.uniui-images-filled:before { + content: "\e64b"; +} + +.uniui-undo-filled:before { + content: "\e64c"; +} + +.uniui-more:before { + content: "\e64d"; +} + +.uniui-more-filled:before { + content: "\e64e"; +} + +.uniui-undo:before { + content: "\e64f"; +} + +.uniui-images:before { + content: "\e650"; +} + +.uniui-paperclip:before { + content: "\e652"; +} + +.uniui-settings:before { + content: "\e653"; +} + +.uniui-search:before { + content: "\e654"; +} + +.uniui-redo-filled:before { + content: "\e655"; +} + +.uniui-list:before { + content: "\e644"; +} + +.uniui-mail-open-filled:before { + content: "\e63a"; +} + +.uniui-hand-down-filled:before { + content: "\e63c"; +} + +.uniui-hand-down:before { + content: "\e63d"; +} + +.uniui-hand-up-filled:before { + content: "\e63e"; +} + +.uniui-hand-up:before { + content: "\e63f"; +} + +.uniui-heart-filled:before { + content: "\e641"; +} + +.uniui-mail-open:before { + content: "\e643"; +} + +.uniui-heart:before { + content: "\e639"; +} + +.uniui-loop:before { + content: "\e633"; +} + +.uniui-pulldown:before { + content: "\e632"; +} + +.uniui-scan:before { + content: "\e62a"; +} + +.uniui-bars:before { + content: "\e627"; +} + +.uniui-checkbox:before { + content: "\e62b"; +} + +.uniui-checkbox-filled:before { + content: "\e62c"; +} + +.uniui-shop:before { + content: "\e62f"; +} + +.uniui-headphones:before { + content: "\e630"; +} + +.uniui-cart:before { + content: "\e631"; +} diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons.ttf b/uni_modules/uni-icons/components/uni-icons/uniicons.ttf new file mode 100644 index 0000000000000000000000000000000000000000..14696d038d828073edac09ea4e5ba1dec2f58115 GIT binary patch literal 35824 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 F{2S@rCxHL} literal 0 HcmV?d00001 diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts b/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts new file mode 100644 index 0000000..98e93aa --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts @@ -0,0 +1,664 @@ + +export type IconsData = { + id : string + name : string + font_family : string + css_prefix_text : string + description : string + glyphs : Array +} + +export type IconsDataItem = { + font_class : string + unicode : string +} + + +export const fontData = [ + { + "font_class": "arrow-down", + "unicode": "\ue6be" + }, + { + "font_class": "arrow-left", + "unicode": "\ue6bc" + }, + { + "font_class": "arrow-right", + "unicode": "\ue6bb" + }, + { + "font_class": "arrow-up", + "unicode": "\ue6bd" + }, + { + "font_class": "auth", + "unicode": "\ue6ab" + }, + { + "font_class": "auth-filled", + "unicode": "\ue6cc" + }, + { + "font_class": "back", + "unicode": "\ue6b9" + }, + { + "font_class": "bars", + "unicode": "\ue627" + }, + { + "font_class": "calendar", + "unicode": "\ue6a0" + }, + { + "font_class": "calendar-filled", + "unicode": "\ue6c0" + }, + { + "font_class": "camera", + "unicode": "\ue65a" + }, + { + "font_class": "camera-filled", + "unicode": "\ue658" + }, + { + "font_class": "cart", + "unicode": "\ue631" + }, + { + "font_class": "cart-filled", + "unicode": "\ue6d0" + }, + { + "font_class": "chat", + "unicode": "\ue65d" + }, + { + "font_class": "chat-filled", + "unicode": "\ue659" + }, + { + "font_class": "chatboxes", + "unicode": "\ue696" + }, + { + "font_class": "chatboxes-filled", + "unicode": "\ue692" + }, + { + "font_class": "chatbubble", + "unicode": "\ue697" + }, + { + "font_class": "chatbubble-filled", + "unicode": "\ue694" + }, + { + "font_class": "checkbox", + "unicode": "\ue62b" + }, + { + "font_class": "checkbox-filled", + "unicode": "\ue62c" + }, + { + "font_class": "checkmarkempty", + "unicode": "\ue65c" + }, + { + "font_class": "circle", + "unicode": "\ue65b" + }, + { + "font_class": "circle-filled", + "unicode": "\ue65e" + }, + { + "font_class": "clear", + "unicode": "\ue66d" + }, + { + "font_class": "close", + "unicode": "\ue673" + }, + { + "font_class": "closeempty", + "unicode": "\ue66c" + }, + { + "font_class": "cloud-download", + "unicode": "\ue647" + }, + { + "font_class": "cloud-download-filled", + "unicode": "\ue646" + }, + { + "font_class": "cloud-upload", + "unicode": "\ue645" + }, + { + "font_class": "cloud-upload-filled", + "unicode": "\ue648" + }, + { + "font_class": "color", + "unicode": "\ue6cf" + }, + { + "font_class": "color-filled", + "unicode": "\ue6c9" + }, + { + "font_class": "compose", + "unicode": "\ue67f" + }, + { + "font_class": "contact", + "unicode": "\ue693" + }, + { + "font_class": "contact-filled", + "unicode": "\ue695" + }, + { + "font_class": "down", + "unicode": "\ue6b8" + }, + { + "font_class": "bottom", + "unicode": "\ue6b8" + }, + { + "font_class": "download", + "unicode": "\ue68d" + }, + { + "font_class": "download-filled", + "unicode": "\ue681" + }, + { + "font_class": "email", + "unicode": "\ue69e" + }, + { + "font_class": "email-filled", + "unicode": "\ue69a" + }, + { + "font_class": "eye", + "unicode": "\ue651" + }, + { + "font_class": "eye-filled", + "unicode": "\ue66a" + }, + { + "font_class": "eye-slash", + "unicode": "\ue6b3" + }, + { + "font_class": "eye-slash-filled", + "unicode": "\ue6b4" + }, + { + "font_class": "fire", + "unicode": "\ue6a1" + }, + { + "font_class": "fire-filled", + "unicode": "\ue6c5" + }, + { + "font_class": "flag", + "unicode": "\ue65f" + }, + { + "font_class": "flag-filled", + "unicode": "\ue660" + }, + { + "font_class": "folder-add", + "unicode": "\ue6a9" + }, + { + "font_class": "folder-add-filled", + "unicode": "\ue6c8" + }, + { + "font_class": "font", + "unicode": "\ue6a3" + }, + { + "font_class": "forward", + "unicode": "\ue6ba" + }, + { + "font_class": "gear", + "unicode": "\ue664" + }, + { + "font_class": "gear-filled", + "unicode": "\ue661" + }, + { + "font_class": "gift", + "unicode": "\ue6a4" + }, + { + "font_class": "gift-filled", + "unicode": "\ue6c4" + }, + { + "font_class": "hand-down", + "unicode": "\ue63d" + }, + { + "font_class": "hand-down-filled", + "unicode": "\ue63c" + }, + { + "font_class": "hand-up", + "unicode": "\ue63f" + }, + { + "font_class": "hand-up-filled", + "unicode": "\ue63e" + }, + { + "font_class": "headphones", + "unicode": "\ue630" + }, + { + "font_class": "heart", + "unicode": "\ue639" + }, + { + "font_class": "heart-filled", + "unicode": "\ue641" + }, + { + "font_class": "help", + "unicode": "\ue679" + }, + { + "font_class": "help-filled", + "unicode": "\ue674" + }, + { + "font_class": "home", + "unicode": "\ue662" + }, + { + "font_class": "home-filled", + "unicode": "\ue663" + }, + { + "font_class": "image", + "unicode": "\ue670" + }, + { + "font_class": "image-filled", + "unicode": "\ue678" + }, + { + "font_class": "images", + "unicode": "\ue650" + }, + { + "font_class": "images-filled", + "unicode": "\ue64b" + }, + { + "font_class": "info", + "unicode": "\ue669" + }, + { + "font_class": "info-filled", + "unicode": "\ue649" + }, + { + "font_class": "left", + "unicode": "\ue6b7" + }, + { + "font_class": "link", + "unicode": "\ue6a5" + }, + { + "font_class": "list", + "unicode": "\ue644" + }, + { + "font_class": "location", + "unicode": "\ue6ae" + }, + { + "font_class": "location-filled", + "unicode": "\ue6af" + }, + { + "font_class": "locked", + "unicode": "\ue66b" + }, + { + "font_class": "locked-filled", + "unicode": "\ue668" + }, + { + "font_class": "loop", + "unicode": "\ue633" + }, + { + "font_class": "mail-open", + "unicode": "\ue643" + }, + { + "font_class": "mail-open-filled", + "unicode": "\ue63a" + }, + { + "font_class": "map", + "unicode": "\ue667" + }, + { + "font_class": "map-filled", + "unicode": "\ue666" + }, + { + "font_class": "map-pin", + "unicode": "\ue6ad" + }, + { + "font_class": "map-pin-ellipse", + "unicode": "\ue6ac" + }, + { + "font_class": "medal", + "unicode": "\ue6a2" + }, + { + "font_class": "medal-filled", + "unicode": "\ue6c3" + }, + { + "font_class": "mic", + "unicode": "\ue671" + }, + { + "font_class": "mic-filled", + "unicode": "\ue677" + }, + { + "font_class": "micoff", + "unicode": "\ue67e" + }, + { + "font_class": "micoff-filled", + "unicode": "\ue6b0" + }, + { + "font_class": "minus", + "unicode": "\ue66f" + }, + { + "font_class": "minus-filled", + "unicode": "\ue67d" + }, + { + "font_class": "more", + "unicode": "\ue64d" + }, + { + "font_class": "more-filled", + "unicode": "\ue64e" + }, + { + "font_class": "navigate", + "unicode": "\ue66e" + }, + { + "font_class": "navigate-filled", + "unicode": "\ue67a" + }, + { + "font_class": "notification", + "unicode": "\ue6a6" + }, + { + "font_class": "notification-filled", + "unicode": "\ue6c1" + }, + { + "font_class": "paperclip", + "unicode": "\ue652" + }, + { + "font_class": "paperplane", + "unicode": "\ue672" + }, + { + "font_class": "paperplane-filled", + "unicode": "\ue675" + }, + { + "font_class": "person", + "unicode": "\ue699" + }, + { + "font_class": "person-filled", + "unicode": "\ue69d" + }, + { + "font_class": "personadd", + "unicode": "\ue69f" + }, + { + "font_class": "personadd-filled", + "unicode": "\ue698" + }, + { + "font_class": "personadd-filled-copy", + "unicode": "\ue6d1" + }, + { + "font_class": "phone", + "unicode": "\ue69c" + }, + { + "font_class": "phone-filled", + "unicode": "\ue69b" + }, + { + "font_class": "plus", + "unicode": "\ue676" + }, + { + "font_class": "plus-filled", + "unicode": "\ue6c7" + }, + { + "font_class": "plusempty", + "unicode": "\ue67b" + }, + { + "font_class": "pulldown", + "unicode": "\ue632" + }, + { + "font_class": "pyq", + "unicode": "\ue682" + }, + { + "font_class": "qq", + "unicode": "\ue680" + }, + { + "font_class": "redo", + "unicode": "\ue64a" + }, + { + "font_class": "redo-filled", + "unicode": "\ue655" + }, + { + "font_class": "refresh", + "unicode": "\ue657" + }, + { + "font_class": "refresh-filled", + "unicode": "\ue656" + }, + { + "font_class": "refreshempty", + "unicode": "\ue6bf" + }, + { + "font_class": "reload", + "unicode": "\ue6b2" + }, + { + "font_class": "right", + "unicode": "\ue6b5" + }, + { + "font_class": "scan", + "unicode": "\ue62a" + }, + { + "font_class": "search", + "unicode": "\ue654" + }, + { + "font_class": "settings", + "unicode": "\ue653" + }, + { + "font_class": "settings-filled", + "unicode": "\ue6ce" + }, + { + "font_class": "shop", + "unicode": "\ue62f" + }, + { + "font_class": "shop-filled", + "unicode": "\ue6cd" + }, + { + "font_class": "smallcircle", + "unicode": "\ue67c" + }, + { + "font_class": "smallcircle-filled", + "unicode": "\ue665" + }, + { + "font_class": "sound", + "unicode": "\ue684" + }, + { + "font_class": "sound-filled", + "unicode": "\ue686" + }, + { + "font_class": "spinner-cycle", + "unicode": "\ue68a" + }, + { + "font_class": "staff", + "unicode": "\ue6a7" + }, + { + "font_class": "staff-filled", + "unicode": "\ue6cb" + }, + { + "font_class": "star", + "unicode": "\ue688" + }, + { + "font_class": "star-filled", + "unicode": "\ue68f" + }, + { + "font_class": "starhalf", + "unicode": "\ue683" + }, + { + "font_class": "trash", + "unicode": "\ue687" + }, + { + "font_class": "trash-filled", + "unicode": "\ue685" + }, + { + "font_class": "tune", + "unicode": "\ue6aa" + }, + { + "font_class": "tune-filled", + "unicode": "\ue6ca" + }, + { + "font_class": "undo", + "unicode": "\ue64f" + }, + { + "font_class": "undo-filled", + "unicode": "\ue64c" + }, + { + "font_class": "up", + "unicode": "\ue6b6" + }, + { + "font_class": "top", + "unicode": "\ue6b6" + }, + { + "font_class": "upload", + "unicode": "\ue690" + }, + { + "font_class": "upload-filled", + "unicode": "\ue68e" + }, + { + "font_class": "videocam", + "unicode": "\ue68c" + }, + { + "font_class": "videocam-filled", + "unicode": "\ue689" + }, + { + "font_class": "vip", + "unicode": "\ue6a8" + }, + { + "font_class": "vip-filled", + "unicode": "\ue6c6" + }, + { + "font_class": "wallet", + "unicode": "\ue6b1" + }, + { + "font_class": "wallet-filled", + "unicode": "\ue6c2" + }, + { + "font_class": "weibo", + "unicode": "\ue68b" + }, + { + "font_class": "weixin", + "unicode": "\ue691" + } +] as IconsDataItem[] + +// export const fontData = JSON.parse(fontDataJson) diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js b/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js new file mode 100644 index 0000000..1cd11e1 --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js @@ -0,0 +1,649 @@ + +export const fontData = [ + { + "font_class": "arrow-down", + "unicode": "\ue6be" + }, + { + "font_class": "arrow-left", + "unicode": "\ue6bc" + }, + { + "font_class": "arrow-right", + "unicode": "\ue6bb" + }, + { + "font_class": "arrow-up", + "unicode": "\ue6bd" + }, + { + "font_class": "auth", + "unicode": "\ue6ab" + }, + { + "font_class": "auth-filled", + "unicode": "\ue6cc" + }, + { + "font_class": "back", + "unicode": "\ue6b9" + }, + { + "font_class": "bars", + "unicode": "\ue627" + }, + { + "font_class": "calendar", + "unicode": "\ue6a0" + }, + { + "font_class": "calendar-filled", + "unicode": "\ue6c0" + }, + { + "font_class": "camera", + "unicode": "\ue65a" + }, + { + "font_class": "camera-filled", + "unicode": "\ue658" + }, + { + "font_class": "cart", + "unicode": "\ue631" + }, + { + "font_class": "cart-filled", + "unicode": "\ue6d0" + }, + { + "font_class": "chat", + "unicode": "\ue65d" + }, + { + "font_class": "chat-filled", + "unicode": "\ue659" + }, + { + "font_class": "chatboxes", + "unicode": "\ue696" + }, + { + "font_class": "chatboxes-filled", + "unicode": "\ue692" + }, + { + "font_class": "chatbubble", + "unicode": "\ue697" + }, + { + "font_class": "chatbubble-filled", + "unicode": "\ue694" + }, + { + "font_class": "checkbox", + "unicode": "\ue62b" + }, + { + "font_class": "checkbox-filled", + "unicode": "\ue62c" + }, + { + "font_class": "checkmarkempty", + "unicode": "\ue65c" + }, + { + "font_class": "circle", + "unicode": "\ue65b" + }, + { + "font_class": "circle-filled", + "unicode": "\ue65e" + }, + { + "font_class": "clear", + "unicode": "\ue66d" + }, + { + "font_class": "close", + "unicode": "\ue673" + }, + { + "font_class": "closeempty", + "unicode": "\ue66c" + }, + { + "font_class": "cloud-download", + "unicode": "\ue647" + }, + { + "font_class": "cloud-download-filled", + "unicode": "\ue646" + }, + { + "font_class": "cloud-upload", + "unicode": "\ue645" + }, + { + "font_class": "cloud-upload-filled", + "unicode": "\ue648" + }, + { + "font_class": "color", + "unicode": "\ue6cf" + }, + { + "font_class": "color-filled", + "unicode": "\ue6c9" + }, + { + "font_class": "compose", + "unicode": "\ue67f" + }, + { + "font_class": "contact", + "unicode": "\ue693" + }, + { + "font_class": "contact-filled", + "unicode": "\ue695" + }, + { + "font_class": "down", + "unicode": "\ue6b8" + }, + { + "font_class": "bottom", + "unicode": "\ue6b8" + }, + { + "font_class": "download", + "unicode": "\ue68d" + }, + { + "font_class": "download-filled", + "unicode": "\ue681" + }, + { + "font_class": "email", + "unicode": "\ue69e" + }, + { + "font_class": "email-filled", + "unicode": "\ue69a" + }, + { + "font_class": "eye", + "unicode": "\ue651" + }, + { + "font_class": "eye-filled", + "unicode": "\ue66a" + }, + { + "font_class": "eye-slash", + "unicode": "\ue6b3" + }, + { + "font_class": "eye-slash-filled", + "unicode": "\ue6b4" + }, + { + "font_class": "fire", + "unicode": "\ue6a1" + }, + { + "font_class": "fire-filled", + "unicode": "\ue6c5" + }, + { + "font_class": "flag", + "unicode": "\ue65f" + }, + { + "font_class": "flag-filled", + "unicode": "\ue660" + }, + { + "font_class": "folder-add", + "unicode": "\ue6a9" + }, + { + "font_class": "folder-add-filled", + "unicode": "\ue6c8" + }, + { + "font_class": "font", + "unicode": "\ue6a3" + }, + { + "font_class": "forward", + "unicode": "\ue6ba" + }, + { + "font_class": "gear", + "unicode": "\ue664" + }, + { + "font_class": "gear-filled", + "unicode": "\ue661" + }, + { + "font_class": "gift", + "unicode": "\ue6a4" + }, + { + "font_class": "gift-filled", + "unicode": "\ue6c4" + }, + { + "font_class": "hand-down", + "unicode": "\ue63d" + }, + { + "font_class": "hand-down-filled", + "unicode": "\ue63c" + }, + { + "font_class": "hand-up", + "unicode": "\ue63f" + }, + { + "font_class": "hand-up-filled", + "unicode": "\ue63e" + }, + { + "font_class": "headphones", + "unicode": "\ue630" + }, + { + "font_class": "heart", + "unicode": "\ue639" + }, + { + "font_class": "heart-filled", + "unicode": "\ue641" + }, + { + "font_class": "help", + "unicode": "\ue679" + }, + { + "font_class": "help-filled", + "unicode": "\ue674" + }, + { + "font_class": "home", + "unicode": "\ue662" + }, + { + "font_class": "home-filled", + "unicode": "\ue663" + }, + { + "font_class": "image", + "unicode": "\ue670" + }, + { + "font_class": "image-filled", + "unicode": "\ue678" + }, + { + "font_class": "images", + "unicode": "\ue650" + }, + { + "font_class": "images-filled", + "unicode": "\ue64b" + }, + { + "font_class": "info", + "unicode": "\ue669" + }, + { + "font_class": "info-filled", + "unicode": "\ue649" + }, + { + "font_class": "left", + "unicode": "\ue6b7" + }, + { + "font_class": "link", + "unicode": "\ue6a5" + }, + { + "font_class": "list", + "unicode": "\ue644" + }, + { + "font_class": "location", + "unicode": "\ue6ae" + }, + { + "font_class": "location-filled", + "unicode": "\ue6af" + }, + { + "font_class": "locked", + "unicode": "\ue66b" + }, + { + "font_class": "locked-filled", + "unicode": "\ue668" + }, + { + "font_class": "loop", + "unicode": "\ue633" + }, + { + "font_class": "mail-open", + "unicode": "\ue643" + }, + { + "font_class": "mail-open-filled", + "unicode": "\ue63a" + }, + { + "font_class": "map", + "unicode": "\ue667" + }, + { + "font_class": "map-filled", + "unicode": "\ue666" + }, + { + "font_class": "map-pin", + "unicode": "\ue6ad" + }, + { + "font_class": "map-pin-ellipse", + "unicode": "\ue6ac" + }, + { + "font_class": "medal", + "unicode": "\ue6a2" + }, + { + "font_class": "medal-filled", + "unicode": "\ue6c3" + }, + { + "font_class": "mic", + "unicode": "\ue671" + }, + { + "font_class": "mic-filled", + "unicode": "\ue677" + }, + { + "font_class": "micoff", + "unicode": "\ue67e" + }, + { + "font_class": "micoff-filled", + "unicode": "\ue6b0" + }, + { + "font_class": "minus", + "unicode": "\ue66f" + }, + { + "font_class": "minus-filled", + "unicode": "\ue67d" + }, + { + "font_class": "more", + "unicode": "\ue64d" + }, + { + "font_class": "more-filled", + "unicode": "\ue64e" + }, + { + "font_class": "navigate", + "unicode": "\ue66e" + }, + { + "font_class": "navigate-filled", + "unicode": "\ue67a" + }, + { + "font_class": "notification", + "unicode": "\ue6a6" + }, + { + "font_class": "notification-filled", + "unicode": "\ue6c1" + }, + { + "font_class": "paperclip", + "unicode": "\ue652" + }, + { + "font_class": "paperplane", + "unicode": "\ue672" + }, + { + "font_class": "paperplane-filled", + "unicode": "\ue675" + }, + { + "font_class": "person", + "unicode": "\ue699" + }, + { + "font_class": "person-filled", + "unicode": "\ue69d" + }, + { + "font_class": "personadd", + "unicode": "\ue69f" + }, + { + "font_class": "personadd-filled", + "unicode": "\ue698" + }, + { + "font_class": "personadd-filled-copy", + "unicode": "\ue6d1" + }, + { + "font_class": "phone", + "unicode": "\ue69c" + }, + { + "font_class": "phone-filled", + "unicode": "\ue69b" + }, + { + "font_class": "plus", + "unicode": "\ue676" + }, + { + "font_class": "plus-filled", + "unicode": "\ue6c7" + }, + { + "font_class": "plusempty", + "unicode": "\ue67b" + }, + { + "font_class": "pulldown", + "unicode": "\ue632" + }, + { + "font_class": "pyq", + "unicode": "\ue682" + }, + { + "font_class": "qq", + "unicode": "\ue680" + }, + { + "font_class": "redo", + "unicode": "\ue64a" + }, + { + "font_class": "redo-filled", + "unicode": "\ue655" + }, + { + "font_class": "refresh", + "unicode": "\ue657" + }, + { + "font_class": "refresh-filled", + "unicode": "\ue656" + }, + { + "font_class": "refreshempty", + "unicode": "\ue6bf" + }, + { + "font_class": "reload", + "unicode": "\ue6b2" + }, + { + "font_class": "right", + "unicode": "\ue6b5" + }, + { + "font_class": "scan", + "unicode": "\ue62a" + }, + { + "font_class": "search", + "unicode": "\ue654" + }, + { + "font_class": "settings", + "unicode": "\ue653" + }, + { + "font_class": "settings-filled", + "unicode": "\ue6ce" + }, + { + "font_class": "shop", + "unicode": "\ue62f" + }, + { + "font_class": "shop-filled", + "unicode": "\ue6cd" + }, + { + "font_class": "smallcircle", + "unicode": "\ue67c" + }, + { + "font_class": "smallcircle-filled", + "unicode": "\ue665" + }, + { + "font_class": "sound", + "unicode": "\ue684" + }, + { + "font_class": "sound-filled", + "unicode": "\ue686" + }, + { + "font_class": "spinner-cycle", + "unicode": "\ue68a" + }, + { + "font_class": "staff", + "unicode": "\ue6a7" + }, + { + "font_class": "staff-filled", + "unicode": "\ue6cb" + }, + { + "font_class": "star", + "unicode": "\ue688" + }, + { + "font_class": "star-filled", + "unicode": "\ue68f" + }, + { + "font_class": "starhalf", + "unicode": "\ue683" + }, + { + "font_class": "trash", + "unicode": "\ue687" + }, + { + "font_class": "trash-filled", + "unicode": "\ue685" + }, + { + "font_class": "tune", + "unicode": "\ue6aa" + }, + { + "font_class": "tune-filled", + "unicode": "\ue6ca" + }, + { + "font_class": "undo", + "unicode": "\ue64f" + }, + { + "font_class": "undo-filled", + "unicode": "\ue64c" + }, + { + "font_class": "up", + "unicode": "\ue6b6" + }, + { + "font_class": "top", + "unicode": "\ue6b6" + }, + { + "font_class": "upload", + "unicode": "\ue690" + }, + { + "font_class": "upload-filled", + "unicode": "\ue68e" + }, + { + "font_class": "videocam", + "unicode": "\ue68c" + }, + { + "font_class": "videocam-filled", + "unicode": "\ue689" + }, + { + "font_class": "vip", + "unicode": "\ue6a8" + }, + { + "font_class": "vip-filled", + "unicode": "\ue6c6" + }, + { + "font_class": "wallet", + "unicode": "\ue6b1" + }, + { + "font_class": "wallet-filled", + "unicode": "\ue6c2" + }, + { + "font_class": "weibo", + "unicode": "\ue68b" + }, + { + "font_class": "weixin", + "unicode": "\ue691" + } +] + +// export const fontData = JSON.parse(fontDataJson) diff --git a/uni_modules/uni-icons/package.json b/uni_modules/uni-icons/package.json new file mode 100644 index 0000000..6b681b4 --- /dev/null +++ b/uni_modules/uni-icons/package.json @@ -0,0 +1,89 @@ +{ + "id": "uni-icons", + "displayName": "uni-icons 图标", + "version": "2.0.10", + "description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。", + "keywords": [ + "uni-ui", + "uniui", + "icon", + "图标" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.2.14" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y", + "app-uvue": "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", + "钉钉": "y", + "快手": "y", + "飞书": "y", + "京东": "y" + }, + "快应用": { + "华为": "y", + "联盟": "y" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-icons/readme.md b/uni_modules/uni-icons/readme.md new file mode 100644 index 0000000..86234ba --- /dev/null +++ b/uni_modules/uni-icons/readme.md @@ -0,0 +1,8 @@ +## Icons 图标 +> **组件名:uni-icons** +> 代码块: `uIcons` + +用于展示 icons 图标 。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-icons) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 diff --git a/uni_modules/uni-id-common/changelog.md b/uni_modules/uni-id-common/changelog.md new file mode 100644 index 0000000..e76f197 --- /dev/null +++ b/uni_modules/uni-id-common/changelog.md @@ -0,0 +1,34 @@ +## 1.0.17(2024-04-26) +- 兼容uni-app-x对客户端uniPlatform的调整(uni-app-x内uniPlatform区分app-android、app-ios) +## 1.0.16(2023-04-25) +- 新增maxTokenLength配置,用于限制数据库用户记录token数组的最大长度 +## 1.0.15(2023-04-06) +- 修复部分语言国际化出错的Bug +## 1.0.14(2023-03-07) +- 修复 admin用户包含其他角色时未包含在token的Bug +## 1.0.13(2022-07-21) +- 修复 创建token时未传角色权限信息生成的token不正确的bug +## 1.0.12(2022-07-15) +- 提升与旧版本uni-id的兼容性(补充读取配置文件时回退平台app-plus、h5),但是仍推荐使用新平台名进行配置(app、web) +## 1.0.11(2022-07-14) +- 修复 部分情况下报`read property 'reduce' of undefined`的错误 +## 1.0.10(2022-07-11) +- 将token存储在用户表的token字段内,与旧版本uni-id保持一致 +## 1.0.9(2022-07-01) +- checkToken兼容token内未缓存角色权限的情况,此时将查库获取角色权限 +## 1.0.8(2022-07-01) +- 修复clientDB默认依赖时部分情况下获取不到uni-id配置的Bug +## 1.0.7(2022-06-30) +- 修复config文件不合法时未抛出具体错误的Bug +## 1.0.6(2022-06-28) +- 移除插件内的数据表schema +## 1.0.5(2022-06-27) +- 修复使用多应用配置时报`Cannot read property 'appId' of undefined`的Bug +## 1.0.4(2022-06-27) +- 修复使用自定义token内容功能报错的Bug [详情](https://ask.dcloud.net.cn/question/147945) +## 1.0.2(2022-06-23) +- 对齐旧版本uni-id默认配置 +## 1.0.1(2022-06-22) +- 补充对uni-config-center的依赖 +## 1.0.0(2022-06-21) +- 提供uni-id token创建、校验、刷新接口,简化旧版uni-id公共模块 diff --git a/uni_modules/uni-id-common/package.json b/uni_modules/uni-id-common/package.json new file mode 100644 index 0000000..3ddc6e4 --- /dev/null +++ b/uni_modules/uni-id-common/package.json @@ -0,0 +1,84 @@ +{ + "id": "uni-id-common", + "displayName": "uni-id-common", + "version": "1.0.17", + "description": "包含uni-id token生成、校验、刷新功能的云函数公共模块", + "keywords": [ + "uni-id-common", + "uniCloud", + "token", + "权限" + ], + "repository": "https://gitcode.net/dcloud/uni-id-common", + "engines": { + }, + "dcloudext": { + "sale": { + "regular": { + "price": 0 + }, + "sourcecode": { + "price": 0 + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "", + "type": "unicloud-template-function" + }, + "uni_modules": { + "dependencies": ["uni-config-center"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "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", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} diff --git a/uni_modules/uni-id-common/readme.md b/uni_modules/uni-id-common/readme.md new file mode 100644 index 0000000..5f6a37a --- /dev/null +++ b/uni_modules/uni-id-common/readme.md @@ -0,0 +1,3 @@ +# uni-id-common + +文档请参考:[uni-id-common](https://uniapp.dcloud.net.cn/uniCloud/uni-id-common.html) \ No newline at end of file diff --git a/uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/index.js b/uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/index.js new file mode 100644 index 0000000..2078958 --- /dev/null +++ b/uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/index.js @@ -0,0 +1 @@ +"use strict";var e,t=(e=require("crypto"))&&"object"==typeof e&&"default"in e?e.default:e;const n={TOKEN_EXPIRED:"uni-id-token-expired",CHECK_TOKEN_FAILED:"uni-id-check-token-failed",PARAM_REQUIRED:"uni-id-param-required",ACCOUNT_EXISTS:"uni-id-account-exists",ACCOUNT_NOT_EXISTS:"uni-id-account-not-exists",ACCOUNT_CONFLICT:"uni-id-account-conflict",ACCOUNT_BANNED:"uni-id-account-banned",ACCOUNT_AUDITING:"uni-id-account-auditing",ACCOUNT_AUDIT_FAILED:"uni-id-account-audit-failed",ACCOUNT_CLOSED:"uni-id-account-closed"};function i(e){return!!e&&("object"==typeof e||"function"==typeof e)&&"function"==typeof e.then}function r(e){if(!e)return;const t=e.match(/^(\d+).(\d+).(\d+)/);return t?t.slice(1,4).map(e=>parseInt(e)):void 0}function o(e,t){const n=r(e),i=r(t);return n?i?function(e,t){const n=Math.max(e.length,t.length);for(let i=0;ir)return 1;if(n=e)throw new Error("Config error, tokenExpiresThreshold should be less than tokenExpiresIn");t>e/2&&console.warn(`Please check whether the tokenExpiresThreshold configuration is set too large, tokenExpiresThreshold: ${t}, tokenExpiresIn: ${e}`)}get customToken(){return this.uniId.interceptorMap.get("customToken")}isTokenInDb(e){return o(e,"1.0.10")>=0}async getUserRecord(){if(this.userRecord)return this.userRecord;const e=await C.doc(this.uid).get();if(this.userRecord=e.data[0],!this.userRecord)throw{errCode:n.ACCOUNT_NOT_EXISTS};switch(this.userRecord.status){case void 0:case 0:break;case 1:throw{errCode:n.ACCOUNT_BANNED};case 2:throw{errCode:n.ACCOUNT_AUDITING};case 3:throw{errCode:n.ACCOUNT_AUDIT_FAILED};case 4:throw{errCode:n.ACCOUNT_CLOSED}}if(this.oldTokenPayload){if(this.isTokenInDb(this.oldTokenPayload.uniIdVersion)){if(-1===(this.userRecord.token||[]).indexOf(this.oldToken))throw{errCode:n.CHECK_TOKEN_FAILED}}if(this.userRecord.valid_token_date&&this.userRecord.valid_token_date>1e3*this.oldTokenPayload.iat)throw{errCode:n.TOKEN_EXPIRED}}return this.userRecord}async updateUserRecord(e){await C.doc(this.uid).update(e)}async getUserPermission(){if(this.userPermission)return this.userPermission;const e=(await this.getUserRecord()).role||[];if(0===e.length)return this.userPermission={role:[],permission:[]},this.userPermission;if(e.includes("admin"))return this.userPermission={role:e,permission:[]},this.userPermission;const t=await T.where({role_id:_.in(e)}).get(),n=(i=t.data.reduce((e,t)=>(t.permission&&e.push(...t.permission),e),[]),Array.from(new Set(i)));var i;return this.userPermission={role:e,permission:n},this.userPermission}async _createToken({uid:e,role:t,permission:i}={}){if(!t||!i){const e=await this.getUserPermission();t=e.role,i=e.permission}let r={uid:e,role:t,permission:i};if(this.uniId.interceptorMap.has("customToken")){const n=this.uniId.interceptorMap.get("customToken");if("function"!=typeof n)throw new Error("Invalid custom token file");r=await n({uid:e,role:t,permission:i})}const o=Date.now(),{tokenSecret:s,tokenExpiresIn:c,maxTokenLength:a=10}=this.config,u=g({...r,uniIdVersion:"1.0.17"},s,{expiresIn:c}),d=await this.getUserRecord(),l=(d.token||[]).filter(e=>{try{const t=this._checkToken(e);if(d.valid_token_date&&d.valid_token_date>1e3*t.iat)return!1}catch(e){if(e.errCode===n.TOKEN_EXPIRED)return!1}return!0});return l.push(u),l.length>a&&l.splice(0,l.length-a),await this.updateUserRecord({last_login_ip:this.clientInfo.clientIP,last_login_date:o,token:l}),{token:u,tokenExpired:o+1e3*c}}async createToken({uid:e,role:t,permission:i}={}){if(!e)throw{errCode:n.PARAM_REQUIRED,errMsgValue:{param:"uid"}};this.uid=e;const{token:r,tokenExpired:o}=await this._createToken({uid:e,role:t,permission:i});return{errCode:0,token:r,tokenExpired:o}}async refreshToken({token:e}={}){if(!e)throw{errCode:n.PARAM_REQUIRED,errMsgValue:{param:"token"}};this.oldToken=e;const t=this._checkToken(e);this.uid=t.uid,this.oldTokenPayload=t;const{uid:i}=t,{role:r,permission:o}=await this.getUserPermission(),{token:s,tokenExpired:c}=await this._createToken({uid:i,role:r,permission:o});return{errCode:0,token:s,tokenExpired:c}}_checkToken(e){const{tokenSecret:t}=this.config;let i;try{i=k(e,t)}catch(e){if("TokenExpiredError"===e.name)throw{errCode:n.TOKEN_EXPIRED};throw{errCode:n.CHECK_TOKEN_FAILED}}return i}async checkToken(e,{autoRefresh:t=!0}={}){if(!e)throw{errCode:n.PARAM_REQUIRED,errMsgValue:{param:"token"}};this.oldToken=e;const i=this._checkToken(e);this.uid=i.uid,this.oldTokenPayload=i;const{tokenExpiresThreshold:r}=this.config,{uid:o,role:s,permission:c}=i,a={role:s,permission:c};if(!s&&!c){const{role:e,permission:t}=await this.getUserPermission();a.role=e,a.permission=t}if(!r||!t){const e={code:0,errCode:0,...i,...a};return delete e.uniIdVersion,e}const u=Date.now();let d={};1e3*i.exp-u<1e3*r&&(d=await this._createToken({uid:o}));const l={code:0,errCode:0,...i,...a,...d};return delete l.uniIdVersion,l}}var E=Object.freeze({__proto__:null,checkToken:async function(e,{autoRefresh:t=!0}={}){return new m({uniId:this}).checkToken(e,{autoRefresh:t})},createToken:async function({uid:e,role:t,permission:n}={}){return new m({uniId:this}).createToken({uid:e,role:t,permission:n})},refreshToken:async function({token:e}={}){return new m({uniId:this}).refreshToken({token:e})}});const w=require("uni-config-center")({pluginId:"uni-id"});class x{constructor({context:e,clientInfo:t,config:n}={}){this._clientInfo=e?function(e){return{appId:e.APPID,platform:e.PLATFORM,locale:e.LOCALE,clientIP:e.CLIENTIP,deviceId:e.DEVICEID}}(e):t,this._config=n,this.config=this._getOriginConfig(),this.interceptorMap=new Map,w.hasFile("custom-token.js")&&this.setInterceptor("customToken",require(w.resolve("custom-token.js")));this._i18n=uniCloud.initI18n({locale:this._clientInfo.locale,fallbackLocale:"zh-Hans",messages:JSON.parse(JSON.stringify(d))}),d[this._i18n.locale]||this._i18n.setLocale("zh-Hans")}setInterceptor(e,t){this.interceptorMap.set(e,t)}_t(...e){return this._i18n.t(...e)}_parseOriginConfig(e){return Array.isArray(e)?e:e[0]?Object.values(e):e}_getOriginConfig(){if(this._config)return this._config;if(w.hasFile("config.json")){let e;try{e=w.config()}catch(e){throw new Error("Invalid uni-id config file\n"+e.message)}return this._parseOriginConfig(e)}try{return this._parseOriginConfig(require("uni-id/config.json"))}catch(e){throw new Error("Invalid uni-id config file")}}_getAppConfig(){const e=this._getOriginConfig();return Array.isArray(e)?e.find(e=>e.dcloudAppid===this._clientInfo.appId)||e.find(e=>e.isDefaultConfig):e}_getPlatformConfig(){const e=this._getAppConfig();if(!e)throw new Error(`Config for current app (${this._clientInfo.appId}) was not found, please check your config file or client appId`);let t;switch(["app-plus","app-android","app-ios"].indexOf(this._clientInfo.platform)>-1&&(this._clientInfo.platform="app"),"h5"===this._clientInfo.platform&&(this._clientInfo.platform="web"),this._clientInfo.platform){case"web":t="h5";break;case"app":t="app-plus"}const n=[{tokenExpiresIn:7200,tokenExpiresThreshold:1200,passwordErrorLimit:6,passwordErrorRetryTime:3600},e];t&&e[t]&&n.push(e[t]),n.push(e[this._clientInfo.platform]);const i=Object.assign(...n);return["tokenSecret","tokenExpiresIn"].forEach(e=>{if(!i||!i[e])throw new Error(`Config parameter missing, ${e} is required`)}),i}_getConfig(){return this._getPlatformConfig()}}for(const e in E)x.prototype[e]=E[e];function y(e){const t=new x(e);return new Proxy(t,{get(e,t){if(t in e&&0!==t.indexOf("_")){if("function"==typeof e[t])return(n=e[t],function(){let e;try{e=n.apply(this,arguments)}catch(e){if(a(e))return c.call(this,e),e;throw e}return i(e)?e.then(e=>(a(e)&&c.call(this,e),e),e=>{if(a(e))return c.call(this,e),e;throw e}):(a(e)&&c.call(this,e),e)}).bind(e);if("context"!==t&&"config"!==t)return e[t]}var n}})}x.prototype.createInstance=y;const A={createInstance:y};module.exports=A; diff --git a/uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/package.json b/uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/package.json new file mode 100644 index 0000000..3cf41f3 --- /dev/null +++ b/uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/package.json @@ -0,0 +1,16 @@ +{ + "name": "uni-id-common", + "version": "1.0.17", + "description": "uni-id token生成、校验、刷新", + "main": "index.js", + "homepage": "https://uniapp.dcloud.io/uniCloud/uni-id-common.html", + "repository": { + "type": "git", + "url": "git+https://gitee.com/dcloud/uni-id-common.git" + }, + "author": "DCloud", + "license": "Apache-2.0", + "dependencies": { + "uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } +} \ No newline at end of file diff --git a/uni_modules/uni-id-pages/changelog.md b/uni_modules/uni-id-pages/changelog.md new file mode 100644 index 0000000..8a4d606 --- /dev/null +++ b/uni_modules/uni-id-pages/changelog.md @@ -0,0 +1,174 @@ +## 1.1.17(2023-12-14) +- uni-id-co 移除一键登录、短信的调用凭据 +## 1.1.16(2023-10-18) +- 修复 当不满足一键登录时页面回退无法继续登录的问题 +## 1.1.15(2023-07-13) +- uni-id-co 修复 QQ登录时不存在头像时报错的问题 +## 1.1.14(2023-05-19) +- 修复 退出登录不会跳转至登录页的问题 +## 1.1.13(2023-05-10) +- 修复 启用摇树优化 报错的问题 +## 1.1.12(2023-05-05) +- uni-id-co 新增 调用 add-user 接口创建用户时允许触发 beforeRegister 钩子方法,beforeRegister 钩子[详见](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html#before-register) +- uni-id-co 新增 自无 unionid 到有 unionid 状态进行登录时为用户补充 unionid 字段 +- uni-id-co 修复 i18n 在特定场景下报错的 bug +- uni-id-co 修复 跨平台解绑微信/QQ时无法解绑的 bug +- uni-id-co 修复 微信小程序等平台创建验证码时无法展示的 bug +- uni-id-co 修复 更新 push_clientid 时因 device_id 没有变化导致无法更新 +## 1.1.11(2023-03-24) +- 修复 tabbar页面因为token无效而强制跳转至登录页面(url参数包含`uniIdRedirectUrl`)后无法返回的问题 +## 1.1.10(2023-03-24) +- 修复 PC微信扫码登录跳转地址错误 +- uni-id-co 新增 请求鉴权支持 uni-cloud-s2s 模块验证签名 [uni-cloud-s2s文档](https://uniapp.dcloud.net.cn/uniCloud/uni-cloud-s2s.html) +## 1.1.9(2023-03-24) +- 修复 跳转至登录页面的url参数包含`uniIdRedirectUrl`后无法返回的问题 +## 1.1.8(2023-03-02) +- 修复 调试模式下没有对微信授权手机号登录方式进行配置检测 +## 1.1.7(2023-02-27) +- 【重要】新增 实名认证功能 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html#frv) +## 1.1.6(2023-02-24) +- uni-id-co 新增 注册用户时允许配置默认角色 [文档](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html#config-defult-role) +- uni-id-co 优化 `updateUserInfoByExternal`接口,允许修改头像、性别 +- uni-id-co 修复 请求签名密钥字段 `requestAuthSecret` 缺少为空判断 +- uni-id-co 修复 `externalRegister`接口头像未使用`avatar_file`字段保存 +- 修复 web微信登录回调地址不正确 +## 1.1.5(2023-02-23) +- 更新 微信小程序端 更新头像信息,如果是使用微信的头像则不再调用裁剪接口 +## 1.1.4(2023-02-21) +- 修复 部分情况下 `uniIdRedirectUrl` 参数无效的问题 +## 1.1.3(2023-02-20) +- 修复 非微信小程序端报`TypeError: uni.hideHomeButton is not a function`的问题 +## 1.1.2(2023-02-10) +- 新增 微信小程序端 首页需强制登录时,隐藏返回首页按钮 +- uni-id-co 新增 外部联登后修改用户信息接口(updateUserInfoByExternal) [文档](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#external-update-userinfo) +- uni-id-co 优化外部联登接口(登录、注册)逻辑 +## 1.1.1(2023-02-02) +- 新增 微信小程序端 支持选择使用微信资料的“头像”和“昵称” 设置用户资料 [详情参考](https://wdoc-76491.picgzc.qpic.cn/MTY4ODg1MDUyNzQyMDUxNw_21263_rTNhg68FTngQGdvQ_1647431233?w=1280&h=695.7176470588236) +## 1.1.0(2023-01-31) +- 【重要】优化 小程序端资源包大小(运行时大小为:731KB,发行后为:583KB;注:可以直接将本插件作为分包使用) +- 更新 微信小程序端 上传头像功能 用`wx.cropImage`实现图片裁剪 +- 修复 选择一键登录时会先显示 非密码登录页面的问题 +- 修复 一键登录 点击右上角的关闭按钮没有返回上一页的问题 +## 1.0.41(2023-01-16) +- 优化 压缩依赖的文件资源大小 +## 1.0.40(2023-01-16) +- 更新依赖的 验证码插件`uni-captcha`版本的版本为 0.6.4 修复 部分情况下APP端无法获取验证码的问题 [详情参考](https://ext.dcloud.net.cn/plugin?id=4048) +- 修复 客户端token过期后,点击退出登录按钮报错的问题 +- uni-id-co 修复 updateUser 接口`手机号`和`邮箱`参数值为空字符串时,修改无效的问题 +## 1.0.39(2022-12-28) +- uni-id-co 修复 URL化时第三方登录无法获取 uniPlatform 参数 +- uni-id-co 修复 validator error +## 1.0.38(2022-12-26) +- uni-id-co 优化 手机号与邮箱验证规则为空字符串时不校验 +## 1.0.37(2022-12-09) +- 优化admin端样式 +## 1.0.36(2022-12-08) +- uni-id-co 修复 `updateUser` 接口部分参数为空时数据修改异常 +## 1.0.35(2022-11-30) +- uni-id-co 新增 匹配到的用户不可在当前应用登录时的错误码 `uni-id-account-not-exists-in-current-app` [错误码说明](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html#errcode) +## 1.0.34(2022-11-29) +- 优化 toast 错误提示时间为3秒 +- uni-id-co 修复 无法从 clientInfo 中获取 uniIdToken +## 1.0.33(2022-11-25) +- uni-id-co 新增 外部系统联登接口,可为外部系统创建与uni-id相对应的账号,使该账号可以使用依赖uniId的系统及功能 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#external) +- uni-id-co 新增 URL化请求时鉴权签名验证 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#http-reqeust-auth) +- uni-id-co 修复 微信登录时用户未设置头像的报错问题 +## 1.0.32(2022-11-21) +- 新增 设置密码页面 +- 新增 登录后跳转设置密码页面配置项`setPasswordAfterLogin` [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-pwd-after-login) +- uni-id-co 新增 设置密码接口 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-pwd) +## 1.0.31(2022-11-16) +- uni-id-co 修复 验证码可能无法收到的bug +## 1.0.30(2022-11-11) +- uni-id-co 修复 用户只有openid时绑定微信/QQ报错 +## 1.0.29(2022-11-10) +- uni-id-co 支持URL化方式请求 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#adapter-http) +## 1.0.28(2022-11-09) +- uni-id-co 升级密码加密算法,支持hmac-sha256加密 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html#password-safe) +- uni-id-co 新增 开发者可以自定义密码加密规则 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html#custom-password-encrypt) +- uni-id-co 新增 支持将其他系统用户迁移至uni-id [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html#move-users-to-uni-id) +## 1.0.27(2022-10-26) +- uni-id-co 新增 secureNetworkHandshakeByWeixin 接口,用于建立和微信小程序的安全网络连接 +## 1.0.26(2022-10-18) +- 修复 uni-id-pages 导入时异常的Bug +## 1.0.25(2022-10-14) +- uni-id-co 增加 微信授权手机号登录方式 [文档](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-weixin-mobile) +- uni-id-co 增加 解绑第三方平台账号 [文档](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-third-account) +- uni-id-co 微信绑定手机号支持通过`getPhoneNumber`事件回调的`code`绑定 [文档](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-mp-weixin) +- 修复 sendSmsCode 接口未在参数内传递 templateId 时 未能从配置文件读取 templateId 的Bug +## 1.0.24(2022-10-08) +- 修复 报uni-id-users表schema内错误的bug +## 1.0.23(2022-10-08) +- 修复 vue3下vite编译发行打包失败 +- 修复 某些情况下注册账号,报TypeErroe:Cannot read properties of undefined (reading ’showToast‘)的错误 +## 1.0.22(2022-09-23) +- 修复 某些情况下,修改密码报“两次输入密码不一致”的bug +## 1.0.21(2022-09-21) +- 修复 store.hasLogin的值在某些情况下会出错的bug +## 1.0.20(2022-09-21) +- 新增 store 账号信息状态管理,详情:用户中心页面 路径:`/uni_modules/uni-id-pages/pages/userinfo/userinfo` +## 1.0.19(2022-09-20) +- 修复 小程序端,使用将自定义节点设置成[虚拟节点](https://uniapp.dcloud.net.cn/tutorial/vue-api.html#%E5%85%B6%E4%BB%96%E9%85%8D%E7%BD%AE)的uni-ui组件,样式错乱的问题 +## 1.0.18(2022-09-20) +- 修复 微信小程序端 WXSS 编译报错的bug +## 1.0.17(2022.09-19) +- 修复 无法退出登录的bug +## 1.0.16(2022-09-19) +- 修复 在 Edge 浏览器下 input[type="password"] 会出现浏览器自带的密码查看按钮 +- 优化 退出登录重定向页面为 uniIdRouter.loginPage +- 新增 注册账号页面支持返回登录页面 +## 1.0.15(2022-09-19) +- 更新表结构,解决在uni-admin中部分clientDB操作没有权限的问题 +## 1.0.14(2022-09-16) +- 修改 配置项`isAdmin`默认值为`false` +## 1.0.13(2022-09-16) +- 新增 管理员注册页面 +- 新增 配置项`isAdmin`区分是否为管理端 +- 新增 登录成功后自动跳转;跳转优先级:路由携带(`uniIdRedirectUrl`参数) > 返回上一路由 > 跳转首页 +- uni-id-co 优化 注册管理员时管理员存在提示文案 +## 1.0.12(2022-09-07) +- 修复 getSupportedLoginType判断是否支持微信公众号、PC网页微信扫码登录方式报错的Bug +- 优化 适配pc端样式 +- 新增 邮箱验证码注册 +- 新增 邮箱验证码找回密码 +- 新增 退出登录(全局)回调事件:`uni-id-pages-logout`,支持通过[uni.$on](https://uniapp.dcloud.net.cn/api/window/communication.html#on)监听; +- 调整 抽离退出登录方法至`/uni_modules/uni-id-pages/common/common.js`中,方便在项目其他页面中调用 +- 调整 用户中心(路径:`/uni_modules/uni-id-pages/pages/userinfo/userinfo`)默认不再显示退出登录按钮。支持页面传参数`showLoginManage=true`恢复显示 +## 1.0.11(2022-09-01) +- 修复 iOS端,一键登录功能卡在showLoading的问题 +- 更新 合并密码强度与长度配置 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#config) +- uni-id-co 修复 调用 removeAuthorizedApp 接口报错的Bug +- uni-id-co 新增 管理端接口 updateUser [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#update-user) +- uni-id-co 调整 为兼容旧版本,未配置密码强度时提供最简单的密码规则校验(长度大于6即可) +- uni-id-co 调整 注册、登录时如果携带了token则尝试对此token进行登出操作 +- uni-id-co 调整 管理端接口 addUser 增加 mobile、email等参数 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#add-user) +## 1.0.10(2022-08-25) +- 修复 导入uni-id-pages插件时未自动导入uni-open-bridge-common的Bug +## 1.0.9(2022-08-23) +- 修复 uni-id-co 缺失uni-open-bridge-common依赖的Bug +## 1.0.8(2022-08-23) +- 新增 H5端支持微信登录(含微信公众号内的网页授权登录 和 普通浏览器内网页生成二维码,实现手机微信扫码登录)[详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#weixinlogin) +- 新增 登录成功(全局)回调事件:`uni-id-pages-login-success`,支持通过[uni.$on](https://uniapp.dcloud.net.cn/api/window/communication.html#on)监听; +- 新增 密码强度(是否必须包含大小写字母、数字和特殊符号以及长度)配置 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#config) +- 调整 uni-id-co 密码规则调整,废除之前的简单校验,允许配置密码强度 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html#password-strength) +- 调整 uni-id-co 存储用户 openid 时同时以客户端 AppId 为 Key 的副本,参考:[微信登录](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-weixin)、[QQ登录](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-qq) +- 调整 uni-id-co 依赖 uni-open-bridge-common 存储用户 session_key、access_token 等信息 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html#save-user-token) +- 新增 uni-id-co 增加 beforeRegister 钩子用户在注册前向用户记录内添加一些数据 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html#before-register) +## 1.0.7(2022-07-19) +- 修复 uni-id-co接口 logout时没有删除token的Bug +## 1.0.6(2022-07-13) +- 新增 允许覆盖内置校验规则 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#custom-validator) +- 修复 app端clientInfo.appVersionCode为数字导致校验无法通过的Bug +## 1.0.5(2022-07-11) +修复 微信小程序调用uni-id-co接口报错的Bug [详情](https://ask.dcloud.net.cn/question/148877) +## 1.0.4(2022-07-06) +- uni-id-co增加clientInfo字段类型校验 +- 监听token更新时机,同步客户端push_clientid至uni-id-device表,改为:同步客户端push_clientid至uni-id-device表和opendb-device表 +## 1.0.3(2022-07-05) +新增监听token更新时机,同步客户端push_clientid至uni-id-device表 +## 1.0.2(2022-07-04) +修复微信小程序登录时无unionid报错的Bug [详情](https://ask.dcloud.net.cn/question/148016) +## 1.0.1(2022-06-28) +添加相关uni-id表 +## 1.0.0(2022-06-23) +正式版 diff --git a/uni_modules/uni-id-pages/common/check-id-card.js b/uni_modules/uni-id-pages/common/check-id-card.js new file mode 100644 index 0000000..b3ca0c3 --- /dev/null +++ b/uni_modules/uni-id-pages/common/check-id-card.js @@ -0,0 +1,16 @@ +function checkIdCard (idCardNumber) { + if (!idCardNumber || typeof idCardNumber !== 'string' || idCardNumber.length !== 18) return false + + const coefficient = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] + const checkCode = [1, 0, 'x', 9, 8, 7, 6, 5, 4, 3, 2] + const code = idCardNumber.substring(17) + + let sum = 0 + for (let i = 0; i < 17; i++) { + sum += Number(idCardNumber.charAt(i)) * coefficient[i] + } + + return checkCode[sum % 11].toString() === code.toLowerCase() +} + +export default checkIdCard diff --git a/uni_modules/uni-id-pages/common/login-page.mixin.js b/uni_modules/uni-id-pages/common/login-page.mixin.js new file mode 100644 index 0000000..3f04454 --- /dev/null +++ b/uni_modules/uni-id-pages/common/login-page.mixin.js @@ -0,0 +1,96 @@ +import { + mutations +} from '@/uni_modules/uni-id-pages/common/store.js' +import config from '@/uni_modules/uni-id-pages/config.js' +const mixin = { + data() { + return { + config, + uniIdRedirectUrl: '', + isMounted: false + } + }, + onUnload() { + // #ifdef H5 + document.onkeydown = false + // #endif + }, + mounted() { + this.isMounted = true + }, + onLoad(e) { + if (e.is_weixin_redirect) { + uni.showLoading({ + mask: true + }) + + if (window.location.href.includes('#')) { + // 将url通过 ? 分割获取后面的参数字符串 再通过 & 将每一个参数单独分割出来 + const paramsArr = window.location.href.split('?')[1].split('&') + paramsArr.forEach(item => { + const arr = item.split('=') + if (arr[0] == 'code') { + e.code = arr[1] + } + }) + } + this.$nextTick(n => { + // console.log(this.$refs.uniFabLogin); + this.$refs.uniFabLogin.login({ + code: e.code + }, 'weixin') + }) + } + + if (e.uniIdRedirectUrl) { + this.uniIdRedirectUrl = decodeURIComponent(e.uniIdRedirectUrl) + } + + // #ifdef MP-WEIXIN + if (getCurrentPages().length === 1) { + uni.hideHomeButton() + console.log('已隐藏:返回首页按钮'); + } + // #endif + }, + computed: { + needAgreements() { + if (this.isMounted) { + if (this.$refs.agreements) { + return this.$refs.agreements.needAgreements + } else { + return false + } + } + }, + agree: { + get() { + if (this.isMounted) { + if (this.$refs.agreements) { + return this.$refs.agreements.isAgree + } else { + return true + } + } + }, + set(agree) { + if (this.$refs.agreements) { + this.$refs.agreements.isAgree = agree + } else { + console.log('不存在 隐私政策协议组件'); + } + } + } + }, + methods: { + loginSuccess(e) { + console.log("登录成功"+JSON.stringify(e)) + mutations.loginSuccess({ + ...e, + uniIdRedirectUrl: this.uniIdRedirectUrl + }) + } + } +} + +export default mixin diff --git a/uni_modules/uni-id-pages/common/login-page.scss b/uni_modules/uni-id-pages/common/login-page.scss new file mode 100644 index 0000000..5de6899 --- /dev/null +++ b/uni_modules/uni-id-pages/common/login-page.scss @@ -0,0 +1,126 @@ +// 隐藏 edge 浏览器的密码查看按钮 + +/* #ifdef H5 */ +.input-box ::v-deep{ + .uni-input-input[type="password"] { + &::-ms-reveal { + display: none; + } + } +} +/* #endif */ + +.uni-content { + padding: 0 60rpx; +} + +.login-logo { + display: none; +} + +/* #ifndef APP-NVUE */ +@media screen and (min-width: 690px) { + .uni-content { + /* #ifndef H5 */ + padding: 0; + max-width: 300px; + margin-left: calc(50% - 200px); + /* #endif */ + /* #ifdef H5 */ + margin: 0 auto; + position: relative; + top: 100px; + padding: 30px 40px 80px 40px; + max-width: 450px; + max-height: 450px; + border-radius: 10px; + box-shadow: 0 0 20px #efefef; + background-color: #FFF; + /* #endif */ + } + /* #ifdef H5 */ + .login-logo { + display: flex; + justify-content: center; + } + + .login-logo image { + width: 60px; + height: 60px; + } + + .register-back{ + display: none; + } + + uni-button{ + padding-bottom: 1px; + } + + /* #endif */ +} + +.uni-content view { + box-sizing: border-box; +} +/* #endif */ + + + +.title { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + padding: 18px 0; + font-weight: 800; + flex-direction: column; +} + +.tip { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + color: #BDBDC0; + font-size: 11px; + margin: 6px 0; +} + + +/* #ifndef APP-NVUE */ +// 解决小程序端开启虚拟节点virtualHost引起的 class = input-box丢失的问题 [详情参考](https://uniapp.dcloud.net.cn/matter.html#%E5%90%84%E5%AE%B6%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%AE%9E%E7%8E%B0%E6%9C%BA%E5%88%B6%E4%B8%8D%E5%90%8C-%E5%8F%AF%E8%83%BD%E5%AD%98%E5%9C%A8%E7%9A%84%E5%B9%B3%E5%8F%B0%E5%85%BC%E5%AE%B9%E9%97%AE%E9%A2%98) +.uni-content ::v-deep .uni-easyinput__content, +/* #endif */ + +.input-box { + height: 44px; + background-color: #F8F8F8 !important; + border-radius: 0; + font-size: 14px; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex: 1; +} + +.link { + color: #04498c; + cursor: pointer; +} + +.uni-content ::v-deep .uni-forms-item__inner { + padding-bottom: 8px; +} + +.uni-btn { + text-align: center; + height: 40px; + line-height: 40px; + margin: 15px 0 10px 0; + color: #FFF !important; + border-radius: 5px; + font-size: 16px; +} + +.uni-body.uni_modules-uni-id-pages-pages-login-login-withoutpwd{ + height: auto !important; +} diff --git a/uni_modules/uni-id-pages/common/password.js b/uni_modules/uni-id-pages/common/password.js new file mode 100644 index 0000000..196c240 --- /dev/null +++ b/uni_modules/uni-id-pages/common/password.js @@ -0,0 +1,85 @@ +// 导入配置 +import config from '@/uni_modules/uni-id-pages/config.js' + +const {passwordStrength} = config + +// 密码强度表达式 +const passwordRules = { + // 密码必须包含大小写字母、数字和特殊符号 + super: /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/, + // 密码必须包含字母、数字和特殊符号 + strong: /^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/, + // 密码必须为字母、数字和特殊符号任意两种的组合 + medium: /^(?![0-9]+$)(?![a-zA-Z]+$)(?![~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]+$)[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/, + // 密码必须包含字母和数字 + weak: /^(?=.*[0-9])(?=.*[a-zA-Z])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{6,16}$/ +} + +const ERROR = { + normal: { + noPwd: '请输入密码', + noRePwd: '再次输入密码', + rePwdErr: '两次输入密码不一致' + }, + passwordStrengthError: { + super: '密码必须包含大小写字母、数字和特殊符号,密码长度必须在8-16位之间', + strong: '密码必须包含字母、数字和特殊符号,密码长度必须在8-16位之间', + medium: '密码必须为字母、数字和特殊符号任意两种的组合,密码长度必须在8-16位之间', + weak: '密码必须包含字母,密码长度必须在6-16位之间' + } +} + +function validPwd(password) { + //强度校验 + if (passwordStrength && passwordRules[passwordStrength]) { + if (!new RegExp(passwordRules[passwordStrength]).test(password)) { + return ERROR.passwordStrengthError[passwordStrength] + } + } + return true +} + +function getPwdRules(pwdName = 'password', rePwdName = 'password2') { + const rules = {} + rules[pwdName] = { + rules: [{ + required: true, + errorMessage: ERROR.normal.noPwd, + }, + { + validateFunction: function(rule, value, data, callback) { + const checkRes = validPwd(value) + if (checkRes !== true) { + callback(checkRes) + } + return true + } + } + ] + } + + if (rePwdName) { + rules[rePwdName] = { + rules: [{ + required: true, + errorMessage: ERROR.normal.noRePwd, + }, + { + validateFunction: function(rule, value, data, callback) { + if (value != data[pwdName]) { + callback(ERROR.normal.rePwdErr) + } + return true + } + } + ] + } + } + return rules +} + +export default { + ERROR, + validPwd, + getPwdRules +} diff --git a/uni_modules/uni-id-pages/common/store.js b/uni_modules/uni-id-pages/common/store.js new file mode 100644 index 0000000..83fdd1e --- /dev/null +++ b/uni_modules/uni-id-pages/common/store.js @@ -0,0 +1,174 @@ +import pagesJson from '@/pages.json' +import config from '@/uni_modules/uni-id-pages/config.js' + +const uniIdCo = uniCloud.importObject("uni-id-co") +const db = uniCloud.database(); +const usersTable = db.collection('uni-id-users') + +let hostUserInfo = uni.getStorageSync('uni-id-pages-userInfo')||{} +// console.log( hostUserInfo); +const data = { + userInfo: hostUserInfo, + hasLogin: Object.keys(hostUserInfo).length != 0 +} + +// console.log('data', data); +// 定义 mutations, 修改属性 +export const mutations = { + // data不为空,表示传递要更新的值(注意不是覆盖是合并),什么也不传时,直接查库获取更新 + async updateUserInfo(data = false) { + if (data) { + usersTable.where('_id==$env.uid').update(data).then(e => { + // console.log(e); + if (e.result.updated) { + uni.showToast({ + title: "更新成功", + icon: 'none', + duration: 3000 + }); + this.setUserInfo(data) + } else { + uni.showToast({ + title: "没有改变", + icon: 'none', + duration: 3000 + }); + } + }) + + } else { + const uniIdCo = uniCloud.importObject("uni-id-co", { + customUI: true + }) + try { + let res = await usersTable.where("'_id' == $cloudEnv_uid") + .field('mobile,nickname,username,email,avatar_file') + .get() + + const realNameRes = await uniIdCo.getRealNameInfo() + + // console.log('fromDbData',res.result.data); + this.setUserInfo({ + ...res.result.data[0], + realNameAuth: realNameRes + }) + } catch (e) { + this.setUserInfo({},{cover:true}) + console.error(e.message, e.errCode); + } + } + }, + async setUserInfo(data, {cover}={cover:false}) { + // console.log('set-userInfo', data); + let userInfo = cover?data:Object.assign(store.userInfo,data) + store.userInfo = Object.assign({},userInfo) + store.hasLogin = Object.keys(store.userInfo).length != 0 + // console.log('store.userInfo', store.userInfo); + uni.setStorageSync('uni-id-pages-userInfo', store.userInfo) + return data + }, + async logout() { + // 1. 已经过期就不需要调用服务端的注销接口 2.即使调用注销接口失败,不能阻塞客户端 + if(uniCloud.getCurrentUserInfo().tokenExpired > Date.now()){ + try{ + await uniIdCo.logout() + }catch(e){ + console.error(e); + } + } + uni.removeStorageSync('uni_id_token'); + uni.setStorageSync('uni_id_token_expired', 0) + uni.redirectTo({ + url: `/${pagesJson.uniIdRouter && pagesJson.uniIdRouter.loginPage ? pagesJson.uniIdRouter.loginPage: 'uni_modules/uni-id-pages/pages/login/login-withoutpwd'}`, + }); + uni.$emit('uni-id-pages-logout') + this.setUserInfo({},{cover:true}) + }, + + loginBack (e = {}) { + const {uniIdRedirectUrl = ''} = e + let delta = 0; //判断需要返回几层 + let pages = getCurrentPages(); + // console.log(pages); + pages.forEach((page, index) => { + if (pages[pages.length - index - 1].route.split('/')[3] == 'login') { + delta++ + } + }) + // console.log('判断需要返回几层:', delta); + if (uniIdRedirectUrl) { + return uni.redirectTo({ + url: uniIdRedirectUrl, + fail: (err1) => { + uni.switchTab({ + url:uniIdRedirectUrl, + fail: (err2) => { + console.log(err1,err2) + } + }) + } + }) + } + // #ifdef H5 + if (e.loginType == 'weixin') { + // console.log('window.history', window.history); + return window.history.go(-3) + } + // #endif + + if (delta) { + const page = pagesJson.pages[0] + return uni.reLaunch({ + url: `/${page.path}` + }) + } + + uni.navigateBack({ + delta + }) + }, + loginSuccess(e = {}){ + const { + showToast = true, toastText = '登录成功', autoBack = true, uniIdRedirectUrl = '', passwordConfirmed + } = e + // console.log({toastText,autoBack}); + if (showToast) { + uni.showToast({ + title: toastText, + icon: 'none', + duration: 3000 + }); + } + this.updateUserInfo() + + uni.$emit('uni-id-pages-login-success') + + if (config.setPasswordAfterLogin && !passwordConfirmed) { + return uni.redirectTo({ + url: uniIdRedirectUrl ? `/uni_modules/uni-id-pages/pages/userinfo/set-pwd/set-pwd?uniIdRedirectUrl=${uniIdRedirectUrl}&loginType=${e.loginType}`: `/uni_modules/uni-id-pages/pages/userinfo/set-pwd/set-pwd?loginType=${e.loginType}`, + fail: (err) => { + console.log(err) + } + }) + } + + if (autoBack) { + this.loginBack({uniIdRedirectUrl}) + } + } + +} + +// #ifdef VUE2 +import Vue from 'vue' +// 通过Vue.observable创建一个可响应的对象 +export const store = Vue.observable(data) +// #endif + +// #ifdef VUE3 +import { + reactive +} from 'vue' +// 通过Vue.observable创建一个可响应的对象 +export const store = reactive(data) +// #endif diff --git a/uni_modules/uni-id-pages/components/cloud-image/cloud-image.vue b/uni_modules/uni-id-pages/components/cloud-image/cloud-image.vue new file mode 100644 index 0000000..d714a3a --- /dev/null +++ b/uni_modules/uni-id-pages/components/cloud-image/cloud-image.vue @@ -0,0 +1,73 @@ + + + \ No newline at end of file diff --git a/uni_modules/uni-id-pages/components/uni-id-pages-agreements/uni-id-pages-agreements.vue b/uni_modules/uni-id-pages/components/uni-id-pages-agreements/uni-id-pages-agreements.vue new file mode 100644 index 0000000..31ab0b7 --- /dev/null +++ b/uni_modules/uni-id-pages/components/uni-id-pages-agreements/uni-id-pages-agreements.vue @@ -0,0 +1,167 @@ + + + + + diff --git a/uni_modules/uni-id-pages/components/uni-id-pages-avatar/uni-id-pages-avatar.vue b/uni_modules/uni-id-pages/components/uni-id-pages-avatar/uni-id-pages-avatar.vue new file mode 100644 index 0000000..7aa6062 --- /dev/null +++ b/uni_modules/uni-id-pages/components/uni-id-pages-avatar/uni-id-pages-avatar.vue @@ -0,0 +1,200 @@ + + + + + diff --git a/uni_modules/uni-id-pages/components/uni-id-pages-bind-mobile/uni-id-pages-bind-mobile.vue b/uni_modules/uni-id-pages/components/uni-id-pages-bind-mobile/uni-id-pages-bind-mobile.vue new file mode 100644 index 0000000..56edaec --- /dev/null +++ b/uni_modules/uni-id-pages/components/uni-id-pages-bind-mobile/uni-id-pages-bind-mobile.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/uni_modules/uni-id-pages/components/uni-id-pages-email-form/uni-id-pages-email-form.vue b/uni_modules/uni-id-pages/components/uni-id-pages-email-form/uni-id-pages-email-form.vue new file mode 100644 index 0000000..b10d7dc --- /dev/null +++ b/uni_modules/uni-id-pages/components/uni-id-pages-email-form/uni-id-pages-email-form.vue @@ -0,0 +1,248 @@ + + + + + diff --git a/uni_modules/uni-id-pages/components/uni-id-pages-fab-login/uni-id-pages-fab-login.vue b/uni_modules/uni-id-pages/components/uni-id-pages-fab-login/uni-id-pages-fab-login.vue new file mode 100644 index 0000000..9688abf --- /dev/null +++ b/uni_modules/uni-id-pages/components/uni-id-pages-fab-login/uni-id-pages-fab-login.vue @@ -0,0 +1,568 @@ + + + + diff --git a/uni_modules/uni-id-pages/components/uni-id-pages-sms-form/uni-id-pages-sms-form.vue b/uni_modules/uni-id-pages/components/uni-id-pages-sms-form/uni-id-pages-sms-form.vue new file mode 100644 index 0000000..1d38b87 --- /dev/null +++ b/uni_modules/uni-id-pages/components/uni-id-pages-sms-form/uni-id-pages-sms-form.vue @@ -0,0 +1,242 @@ + + + + + diff --git a/uni_modules/uni-id-pages/components/uni-id-pages-user-profile/uni-id-pages-user-profile.vue b/uni_modules/uni-id-pages/components/uni-id-pages-user-profile/uni-id-pages-user-profile.vue new file mode 100644 index 0000000..7b78f9b --- /dev/null +++ b/uni_modules/uni-id-pages/components/uni-id-pages-user-profile/uni-id-pages-user-profile.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/uni_modules/uni-id-pages/config.js b/uni_modules/uni-id-pages/config.js new file mode 100644 index 0000000..618bcf7 --- /dev/null +++ b/uni_modules/uni-id-pages/config.js @@ -0,0 +1,67 @@ +export default { + // 调试模式 + debug: false, + /* + 登录类型 未列举到的或运行环境不支持的,将被自动隐藏。 + 如果需要在不同平台有不同的配置,直接用条件编译即可 + */ + isAdmin: false, // 区分管理端与用户端 + loginTypes: [ + // "qq", + // "xiaomi", + // "sinaweibo", + // "taobao", + // "facebook", + // "google", + // "alipay", + // "douyin", + + // #ifdef APP + 'univerify', + // #endif + 'weixin', + 'username', + // #ifdef APP + 'apple', + // #endif + 'smsCode' + ], + // 政策协议 + agreements: { + serviceUrl: 'https://xxx', // 用户服务协议链接 + privacyUrl: 'https://xxx', // 隐私政策条款链接 + // 哪些场景下显示,1.注册(包括登录并注册,如:微信登录、苹果登录、短信验证码登录)、2.登录(如:用户名密码登录) + scope: [ + 'register', 'login', 'realNameVerify' + ] + }, + // 提供各类服务接入(如微信登录服务)的应用id + appid: { + weixin: { + // 微信公众号的appid,来源:登录微信公众号(https://mp.weixin.qq.com)-> 设置与开发 -> 基本配置 -> 公众号开发信息 -> AppID + h5: 'xxxxxx', + // 微信开放平台的appid,来源:登录微信开放平台(https://open.weixin.qq.com) -> 管理中心 -> 网站应用 -> 选择对应的应用名称,点击查看 -> AppID + web: 'xxxxxx' + } + }, + /** + * 密码强度 + * super(超强:密码必须包含大小写字母、数字和特殊符号,长度范围:8-16位之间) + * strong(强: 密密码必须包含字母、数字和特殊符号,长度范围:8-16位之间) + * medium (中:密码必须为字母、数字和特殊符号任意两种的组合,长度范围:8-16位之间) + * weak(弱:密码必须包含字母和数字,长度范围:6-16位之间) + * 为空或false则不验证密码强度 + */ + passwordStrength: 'medium', + /** + * 登录后允许用户设置密码(只针对未设置密码得用户) + * 开启此功能将 setPasswordAfterLogin 设置为 true 即可 + * "setPasswordAfterLogin": false + * + * 如果允许用户跳过设置密码 将 allowSkip 设置为 true + * "setPasswordAfterLogin": { + * "allowSkip": true + * } + * */ + setPasswordAfterLogin: false +} diff --git a/uni_modules/uni-id-pages/init.js b/uni_modules/uni-id-pages/init.js new file mode 100644 index 0000000..1d9b29d --- /dev/null +++ b/uni_modules/uni-id-pages/init.js @@ -0,0 +1,95 @@ +// 导入配置 +import config from '@/uni_modules/uni-id-pages/config.js' +// uni-id的云对象 +const uniIdCo = uniCloud.importObject('uni-id-co', { + customUI: true +}) +// 用户配置的登录方式、是否打开调试模式 +const { + loginTypes, + debug +} = config + +export default async function () { + // 有打开调试模式的情况下 + if (debug) { + // 1. 检查本地uni-id-pages中配置的登录方式,服务器端是否已经配置正确。否则提醒并引导去配置 + // 调用云对象,获取服务端已正确配置的登录方式 + const { + supportedLoginType + } = await uniIdCo.getSupportedLoginType() + console.log('supportedLoginType: ' + JSON.stringify(supportedLoginType)) + // 登录方式,服务端和客户端的映射关系 + const data = { + smsCode: 'mobile-code', + univerify: 'univerify', + username: 'username-password', + weixin: 'weixin', + qq: 'qq', + xiaomi: 'xiaomi', + sinaweibo: 'sinaweibo', + taobao: 'taobao', + facebook: 'facebook', + google: 'google', + alipay: 'alipay', + apple: 'apple', + weixinMobile: 'weixin' + } + // 遍历客户端配置的登录方式,与服务端比对。并在错误时抛出错误提示 + const list = loginTypes.filter(type => !supportedLoginType.includes(data[type])) + if (list.length) { + console.error( + `错误:前端启用的登录方式:${list.join(',')};没有在服务端完成配置。配置文件路径:"/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json"` + ) + } + } + + // #ifdef APP-PLUS + // 如果uni-id-pages配置的登录功能有一键登录,有则执行预登录(异步) + if (loginTypes.includes('univerify')) { + uni.preLogin({ + provider: 'univerify', + complete: e => { + // console.log(e); + } + }) + } + // #endif + + // 3. 绑定clientDB错误事件 + // clientDB对象 + const db = uniCloud.database() + db.on('error', onDBError) + // clientDB的错误提示 + function onDBError ({ + code, // 错误码详见https://uniapp.dcloud.net.cn/uniCloud/clientdb?id=returnvalue + message + }) { + // console.error('onDBError', {code,message}); + } + // 解绑clientDB错误事件 + // db.off('error', onDBError) + + // 4. 同步客户端push_clientid至device表 + if (uniCloud.onRefreshToken) { + uniCloud.onRefreshToken(() => { + // console.log('onRefreshToken'); + if (uni.getPushClientId) { + uni.getPushClientId({ + success: async function (e) { + // console.log(e) + const pushClientId = e.cid + // console.log(pushClientId); + const res = await uniIdCo.setPushCid({ + pushClientId + }) + // console.log('getPushClientId', res); + }, + fail (e) { + // console.log(e) + } + }) + } + }) + } +} diff --git a/uni_modules/uni-id-pages/package.json b/uni_modules/uni-id-pages/package.json new file mode 100644 index 0000000..2f46dc6 --- /dev/null +++ b/uni_modules/uni-id-pages/package.json @@ -0,0 +1,102 @@ +{ + "id": "uni-id-pages", + "displayName": "uni-id-pages", + "version": "1.1.17", + "description": "云端一体简单、统一、可扩展的用户中心页面模版", + "keywords": [ + "用户管理", + "用户中心", + "短信验证码", + "login", + "登录" + ], + "repository": "https://gitcode.net/dcloud/hello_uni-id-pages", + "engines": { + "HBuilderX": "^3.4.17" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "", + "type": "unicloud-template-page" + }, + "uni_modules": { + "dependencies": [ + "uni-captcha", + "uni-config-center", + "uni-data-checkbox", + "uni-easyinput", + "uni-forms", + "uni-icons", + "uni-id-common", + "uni-list", + "uni-load-more", + "uni-popup", + "uni-scss", + "uni-transition", + "uni-open-bridge-common", + "uni-cloud-s2s" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "u", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + }, + "dependencies": { + } +} diff --git a/uni_modules/uni-id-pages/pages/common/webview/webview.vue b/uni_modules/uni-id-pages/pages/common/webview/webview.vue new file mode 100644 index 0000000..71ff55c --- /dev/null +++ b/uni_modules/uni-id-pages/pages/common/webview/webview.vue @@ -0,0 +1,35 @@ + + + + diff --git a/uni_modules/uni-id-pages/pages/login/login-smscode.vue b/uni_modules/uni-id-pages/pages/login/login-smscode.vue new file mode 100644 index 0000000..f847cc5 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/login/login-smscode.vue @@ -0,0 +1,120 @@ + + + + diff --git a/uni_modules/uni-id-pages/pages/login/login-withoutpwd.vue b/uni_modules/uni-id-pages/pages/login/login-withoutpwd.vue new file mode 100644 index 0000000..26f963f --- /dev/null +++ b/uni_modules/uni-id-pages/pages/login/login-withoutpwd.vue @@ -0,0 +1,257 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/login/login-withpwd.vue b/uni_modules/uni-id-pages/pages/login/login-withpwd.vue new file mode 100644 index 0000000..3fe053b --- /dev/null +++ b/uni_modules/uni-id-pages/pages/login/login-withpwd.vue @@ -0,0 +1,177 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/register/register-admin.vue b/uni_modules/uni-id-pages/pages/register/register-admin.vue new file mode 100644 index 0000000..be2c1d3 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/register/register-admin.vue @@ -0,0 +1,178 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/register/register-by-email.vue b/uni_modules/uni-id-pages/pages/register/register-by-email.vue new file mode 100644 index 0000000..6f05c8a --- /dev/null +++ b/uni_modules/uni-id-pages/pages/register/register-by-email.vue @@ -0,0 +1,216 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/register/register.vue b/uni_modules/uni-id-pages/pages/register/register.vue new file mode 100644 index 0000000..20de1ad --- /dev/null +++ b/uni_modules/uni-id-pages/pages/register/register.vue @@ -0,0 +1,181 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/register/validator.js b/uni_modules/uni-id-pages/pages/register/validator.js new file mode 100644 index 0000000..9173e3c --- /dev/null +++ b/uni_modules/uni-id-pages/pages/register/validator.js @@ -0,0 +1,56 @@ +import passwordMod from '@/uni_modules/uni-id-pages/common/password.js' +export default { + "username": { + "rules": [{ + required: true, + errorMessage: '请输入用户名', + }, + { + minLength: 3, + maxLength: 32, + errorMessage: '用户名长度在 {minLength} 到 {maxLength} 个字符', + }, + { + validateFunction: function(rule, value, data, callback) { + // console.log(value); + if (/^1\d{10}$/.test(value) || /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/.test(value)) { + callback('用户名不能是:手机号或邮箱') + }; + if (/^\d+$/.test(value)) { + callback('用户名不能为纯数字') + }; + if(/[\u4E00-\u9FA5\uF900-\uFA2D]{1,}/.test(value)){ + callback('用户名不能包含中文') + } + return true + } + } + ], + "label": "用户名" + }, + "nickname": { + "rules": [{ + minLength: 3, + maxLength: 32, + errorMessage: '昵称长度在 {minLength} 到 {maxLength} 个字符', + }, + { + validateFunction: function(rule, value, data, callback) { + // console.log(value); + if (/^1\d{10}$/.test(value) || /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/.test(value)) { + callback('昵称不能是:手机号或邮箱') + }; + if (/^\d+$/.test(value)) { + callback('昵称不能为纯数字') + }; + if(/[\u4E00-\u9FA5\uF900-\uFA2D]{1,}/.test(value)){ + callback('昵称不能包含中文') + } + return true + } + } + ], + "label": "昵称" + }, + ...passwordMod.getPwdRules() +} diff --git a/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email.vue b/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email.vue new file mode 100644 index 0000000..b6e7704 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email.vue @@ -0,0 +1,218 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/retrieve/retrieve.vue b/uni_modules/uni-id-pages/pages/retrieve/retrieve.vue new file mode 100644 index 0000000..6e1976b --- /dev/null +++ b/uni_modules/uni-id-pages/pages/retrieve/retrieve.vue @@ -0,0 +1,241 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile.vue b/uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile.vue new file mode 100644 index 0000000..a6b2b1f --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile.vue @@ -0,0 +1,131 @@ + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/change_pwd/change_pwd.vue b/uni_modules/uni-id-pages/pages/userinfo/change_pwd/change_pwd.vue new file mode 100644 index 0000000..2992623 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/change_pwd/change_pwd.vue @@ -0,0 +1,130 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage.vue b/uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage.vue new file mode 100644 index 0000000..2317b9b --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage.vue @@ -0,0 +1,39 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/README.md b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/README.md new file mode 100644 index 0000000..9219f81 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/README.md @@ -0,0 +1,227 @@ +> 插件来源:[https://ext.dcloud.net.cn/plugin?id=3594](https://ext.dcloud.net.cn/plugin?id=3594) +##### 以下是作者写的插件介绍: + +# Clipper 图片裁剪 +> uniapp 图片裁剪,可用于图片头像等裁剪处理 +> [查看更多](http://liangei.gitee.io/limeui/#/clipper)
+> Q群:458377637 + + +## 平台兼容 + +| H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App | +| --- | ---------- | ------------ | ---------- | ---------- | --------- | --- | +| √ | √ | √ | 未测 | √ | √ | √ | + + +## 代码演示 +### 基本用法 +`@success` 事件点击 👉 **确定** 后会返回生成的图片信息,包含 `url`、`width`、`height` + +```html + + + +``` + +```js +// 非uni_modules引入 +import lClipper from '@/components/lime-clipper/' +// uni_modules引入 +import lClipper from '@/uni_modules/lime-clipper/components/lime-clipper/' +export default { + components: {lClipper}, + data() { + return { + show: false, + url: '', + } + } +} +``` + + +### 传入图片 +`image-url`可传入**相对路径**、**临时路径**、**本地路径**、**网络图片**
+ +* **当为网络地址时** +* H5:👉 需要解决跨域问题。
+* 小程序:👉 需要配置 downloadFile 域名
+ + +```html + + + +``` + +```js +export default { + components: {lClipper}, + data() { + return { + imageUrl: 'https://img12.360buyimg.com/pop/s1180x940_jfs/t1/97205/26/1142/87801/5dbac55aEf795d962/48a4d7a63ff80b8b.jpg', + show: false, + url: '', + } + } +} +``` + + +### 确定按钮颜色 +样式变量名:`--l-clipper-confirm-color` +可放到全局样式的 `page` 里或节点的 `style` +```html + +``` +```css +// css 中为组件设置 CSS 变量 +.clipper { + --l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24) +} +// 全局 +page { + --l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24) +} +``` + + +### 使用插槽 +共五个插槽 `cancel` 取消按钮、 `photo` 选择图片按钮、 `rotate` 旋转按钮、 `confirm` 确定按钮和默认插槽。 + +```html + + + + 取消 + 选择图片 + 旋转 + 确定 + + + 显示取消按钮 + + + 显示选择图片按钮 + + + 显示旋转按钮 + + + 显示确定按钮 + + + 锁定裁剪框宽度 + + + 锁定裁剪框高度 + + + 锁定裁剪框比例 + + + 限制移动范围 + + + 禁止缩放 + + + 禁止旋转 + + + + + +``` + +```js +export default { + components: {lClipper}, + data() { + return { + show: false, + url: '', + isLockWidth: false, + isLockHeight: false, + isLockRatio: true, + isLimitMove: false, + isDisableScale: false, + isDisableRotate: false, + isShowCancelBtn: true, + isShowPhotoBtn: true, + isShowRotateBtn: true, + isShowConfirmBtn: true + } + } +} +``` + + +## API + +### Props + +| 参数 | 说明 | 类型 | 默认值 | +| ------------- | ------------ | ---------------- | ------------ | +| image-url | 图片路径 | string | | +| quality | 图片的质量,取值范围为 [0, 1],不在范围内时当作1处理 | number | `1` | +| source | `{album: '从相册中选择'}`key为图片来源类型,value为选项说明 | Object | | +| width | 裁剪框宽度,单位为 `rpx` | number | `400` | +| height | 裁剪框高度 | number | `400` | +| min-width | 裁剪框最小宽度 | number | `200` | +| min-height |裁剪框最小高度 | number | `200` | +| max-width | 裁剪框最大宽度 | number | `600` | +| max-height | 裁剪框最大宽度 | number | `600` | +| min-ratio | 图片最小缩放比 | number | `0.5` | +| max-ratio | 图片最大缩放比 | number | `2` | +| rotate-angle | 旋转按钮每次旋转的角度 | number | `90` | +| scale-ratio | 生成图片相对于裁剪框的比例, **比例越高生成图片越清晰** | number | `1` | +| is-lock-width | 是否锁定裁剪框宽度 | boolean | `false` | +| is-lock-height | 是否锁定裁剪框高度上 | boolean | `false` | +| is-lock-ratio | 是否锁定裁剪框比例 | boolean | `true` | +| is-disable-scale | 是否禁止缩放 | boolean | `false` | +| is-disable-rotate | 是否禁止旋转 | boolean | `false` | +| is-limit-move | 是否限制移动范围 | boolean | `false` | +| is-show-photo-btn | 是否显示选择图片按钮 | boolean | `true` | +| is-show-rotate-btn | 是否显示转按钮 | boolean | `true` | +| is-show-confirm-btn | 是否显示确定按钮 | boolean | `true` | +| is-show-cancel-btn | 是否显示关闭按钮 | boolean | `true` | + + + +### 事件 Events + +| 事件名 | 说明 | 回调 | +| ------- | ------------ | -------------- | +| success | 生成图片成功 | {`width`, `height`, `url`} | +| fail | 生成图片失败 | `error` | +| cancel | 关闭 | `false` | +| ready | 图片加载完成 | {`width`, `height`, `path`, `orientation`, `type`} | +| change | 图片大小改变时触发 | {`width`, `height`} | +| rotate | 图片旋转时触发 | `angle` | + +## 常见问题 +> 1、H5端使用网络图片需要解决跨域问题。
+> 2、小程序使用网络图片需要去公众平台增加下载白名单!二级域名也需要配!
+> 3、H5端生成图片是base64,有时显示只有一半可以使用原生标签``
+> 4、IOS APP 请勿使用HBX2.9.3.20201014的版本!这个版本无法生成图片。
+> 5、APP端无成功反馈、也无失败反馈时,请更新基座和HBX。
+ + +## 打赏 +如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
+![输入图片说明](https://images.gitee.com/uploads/images/2020/1122/222521_bb543f96_518581.jpeg "微信图片编辑_20201122220352.jpg") \ No newline at end of file diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/photo.svg b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/photo.svg new file mode 100644 index 0000000..7b4b590 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/photo.svg @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/rotate.svg b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/rotate.svg new file mode 100644 index 0000000..0143706 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/images/rotate.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/index.css b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/index.css new file mode 100644 index 0000000..ce542bf --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/index.css @@ -0,0 +1,160 @@ +.flex-auto { + flex: auto; +} +.bg-transparent { + background-color: rgba(0,0,0,0.9); + transition-duration: 0.35s; +} +.l-clipper { + width: 100vw; + height: calc(100vh - var(--window-top)); + background-color: rgba(0,0,0,0.9); + position: fixed; + top: var(--window-top); + left: 0; + z-index: 1; +} +.l-clipper-mask { + position: relative; + z-index: 2; + pointer-events: none; +} +.l-clipper__content { + pointer-events: none; + position: absolute; + border: 1rpx solid rgba(255,255,255,0.3); + box-sizing: border-box; + box-shadow: rgba(0,0,0,0.5) 0 0 0 80vh; + background: transparent; +} +.l-clipper__content::before, +.l-clipper__content::after { + content: ''; + position: absolute; + border: 1rpx dashed rgba(255,255,255,0.3); +} +.l-clipper__content::before { + width: 100%; + top: 33.33%; + height: 33.33%; + border-left: none; + border-right: none; +} +.l-clipper__content::after { + width: 33.33%; + left: 33.33%; + height: 100%; + border-top: none; + border-bottom: none; +} +.l-clipper__edge { + position: absolute; + width: 34rpx; + height: 34rpx; + border: 6rpx solid #fff; + pointer-events: auto; +} +.l-clipper__edge::before { + content: ''; + position: absolute; + width: 40rpx; + height: 40rpx; + background-color: transparent; +} +.l-clipper__edge:nth-child(1) { + left: -6rpx; + top: -6rpx; + border-bottom-width: 0 !important; + border-right-width: 0 !important; +} +.l-clipper__edge:nth-child(1):before { + top: -50%; + left: -50%; +} +.l-clipper__edge:nth-child(2) { + right: -6rpx; + top: -6rpx; + border-bottom-width: 0 !important; + border-left-width: 0 !important; +} +.l-clipper__edge:nth-child(2):before { + top: -50%; + left: 50%; +} +.l-clipper__edge:nth-child(3) { + left: -6rpx; + bottom: -6rpx; + border-top-width: 0 !important; + border-right-width: 0 !important; +} +.l-clipper__edge:nth-child(3):before { + bottom: -50%; + left: -50%; +} +.l-clipper__edge:nth-child(4) { + right: -6rpx; + bottom: -6rpx; + border-top-width: 0 !important; + border-left-width: 0 !important; +} +.l-clipper__edge:nth-child(4):before { + bottom: -50%; + left: 50%; +} +.l-clipper-image { + width: 100%; + border-style: none; + position: absolute; + top: 0; + left: 0; + z-index: 1; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + transform-origin: center; +} +.l-clipper-canvas { + position: fixed; + z-index: 10; + left: -200vw; + top: -200vw; + pointer-events: none; +} +.l-clipper-tools { + position: fixed; + left: 0; + bottom: 10px; + width: 100%; + z-index: 99; + color: #fff; +} +.l-clipper-tools__btns { + font-weight: bold; + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: 20rpx 40rpx; + box-sizing: border-box; +} +.l-clipper-tools__btns .cancel { + width: 112rpx; + height: 60rpx; + text-align: center; + line-height: 60rpx; +} +.l-clipper-tools__btns .confirm { + width: 112rpx; + height: 60rpx; + line-height: 60rpx; + background-color: #07c160; + border-radius: 6rpx; + text-align: center; +} +.l-clipper-tools__btns image { + display: block; + width: 60rpx; + height: 60rpx; +} +.l-clipper-tools__btns { + flex-direction: row; +} diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/limeClipper.vue b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/limeClipper.vue new file mode 100644 index 0000000..4fc62b3 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/limeClipper.vue @@ -0,0 +1,820 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/utils.js b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/utils.js new file mode 100644 index 0000000..980c439 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/cropImage/limeClipper/utils.js @@ -0,0 +1,244 @@ +/** + * 判断手指触摸位置 + */ +export function determineDirection(clipX, clipY, clipWidth, clipHeight, currentX, currentY) { + /* + * (右下>>1 右上>>2 左上>>3 左下>>4) + */ + let corner; + /** + * 思路:(利用直角坐标系) + * 1.找出裁剪框中心点 + * 2.如点击坐标在上方点与左方点区域内,则点击为左上角 + * 3.如点击坐标在下方点与右方点区域内,则点击为右下角 + * 4.其他角同理 + */ + const mainPoint = [clipX + clipWidth / 2, clipY + clipHeight / 2]; // 中心点 + const currentPoint = [currentX, currentY]; // 触摸点 + + if (currentPoint[0] <= mainPoint[0] && currentPoint[1] <= mainPoint[1]) { + corner = 3; // 左上 + } else if (currentPoint[0] >= mainPoint[0] && currentPoint[1] <= mainPoint[1]) { + corner = 2; // 右上 + } else if (currentPoint[0] <= mainPoint[0] && currentPoint[1] >= mainPoint[1]) { + corner = 4; // 左下 + } else if (currentPoint[0] >= mainPoint[0] && currentPoint[1] >= mainPoint[1]) { + corner = 1; // 右下 + } + + return corner; +} + +/** + * 图片边缘检测检测时,计算图片偏移量 + */ +export function calcImageOffset(data, scale) { + let left = data.imageLeft; + let top = data.imageTop; + scale = scale || data.scale; + + let imageWidth = data.imageWidth; + let imageHeight = data.imageHeight; + if ((data.angle / 90) % 2) { + imageWidth = data.imageHeight; + imageHeight = data.imageWidth; + } + const { + clipX, + clipWidth, + clipY, + clipHeight + } = data; + + // 当前图片宽度/高度 + const currentImageSize = (size) => (size * scale) / 2; + const currentImageWidth = currentImageSize(imageWidth); + const currentImageHeight = currentImageSize(imageHeight); + + left = clipX + currentImageWidth >= left ? left : clipX + currentImageWidth; + left = clipX + clipWidth - currentImageWidth <= left ? left : clipX + clipWidth - currentImageWidth; + top = clipY + currentImageHeight >= top ? top : clipY + currentImageHeight; + top = clipY + clipHeight - currentImageHeight <= top ? top : clipY + clipHeight - currentImageHeight; + return { + left, + top, + scale + }; +} + +/** + * 图片边缘检测时,计算图片缩放比例 + */ +export function calcImageScale(data, scale) { + scale = scale || data.scale; + let { + imageWidth, + imageHeight, + clipWidth, + clipHeight, + angle + } = data + if ((angle / 90) % 2) { + imageWidth = imageHeight; + imageHeight = imageWidth; + } + if (imageWidth * scale < clipWidth) { + scale = clipWidth / imageWidth; + } + if (imageHeight * scale < clipHeight) { + scale = Math.max(scale, clipHeight / imageHeight); + } + return scale; +} + +/** + * 计算图片尺寸 + */ +export function calcImageSize(width, height, data) { + let imageWidth = width, + imageHeight = height; + let { + clipWidth, + clipHeight, + sysinfo, + width: originWidth, + height: originHeight + } = data + if (imageWidth && imageHeight) { + if (imageWidth / imageHeight > (clipWidth || originWidth) / (clipWidth || originHeight)) { + imageHeight = clipHeight || originHeight; + imageWidth = (width / height) * imageHeight; + } else { + imageWidth = clipWidth || originWidth; + imageHeight = (height / width) * imageWidth; + } + } else { + let sys = sysinfo || uni.getSystemInfoSync(); + imageWidth = sys.windowWidth; + imageHeight = 0; + } + return { + imageWidth, + imageHeight + }; +} + +/** + * 勾股定理求斜边 + */ +export function calcPythagoreanTheorem(width, height) { + return Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); +} + +/** + * 拖动裁剪框时计算 + */ +export function clipTouchMoveOfCalculate(data, event) { + const clientX = event.touches[0].clientX; + const clientY = event.touches[0].clientY; + + let { + clipWidth, + clipHeight, + clipY: oldClipY, + clipX: oldClipX, + clipStart, + isLockRatio, + maxWidth, + minWidth, + maxHeight, + minHeight + } = data; + maxWidth = maxWidth / 2; + minWidth = minWidth / 2; + minHeight = minHeight / 2; + maxHeight = maxHeight / 2; + + let width = clipWidth, + height = clipHeight, + clipY = oldClipY, + clipX = oldClipX, + // 获取裁剪框实际宽度/高度 + // 如果大于最大值则使用最大值 + // 如果小于最小值则使用最小值 + sizecorrect = () => { + width = width <= maxWidth ? (width >= minWidth ? width : minWidth) : maxWidth; + height = height <= maxHeight ? (height >= minHeight ? height : minHeight) : maxHeight; + }, + sizeinspect = () => { + sizecorrect(); + if ((width > maxWidth || width < minWidth || height > maxHeight || height < minHeight) && isLockRatio) { + return false; + } else { + return true; + } + }; + //if (clipStart.corner) { + height = clipStart.height + (clipStart.corner > 1 && clipStart.corner < 4 ? 1 : -1) * (clipStart.y - clientY); + //} + switch (clipStart.corner) { + case 1: + width = clipStart.width - clipStart.x + clientX; + if (isLockRatio) { + height = width / (clipWidth / clipHeight); + } + if (!sizeinspect()) return; + break; + case 2: + width = clipStart.width - clipStart.x + clientX; + if (isLockRatio) { + height = width / (clipWidth / clipHeight); + } + if (!sizeinspect()) { + return; + } else { + clipY = clipStart.clipY - (height - clipStart.height); + } + + break; + case 3: + width = clipStart.width + clipStart.x - clientX; + if (isLockRatio) { + height = width / (clipWidth / clipHeight); + } + if (!sizeinspect()) { + return; + } else { + clipY = clipStart.clipY - (height - clipStart.height); + clipX = clipStart.clipX - (width - clipStart.width); + } + + break; + case 4: + width = clipStart.width + clipStart.x - clientX; + if (isLockRatio) { + height = width / (clipWidth / clipHeight); + } + if (!sizeinspect()) { + return; + } else { + clipX = clipStart.clipX - (width - clipStart.width); + } + break; + default: + break; + } + return { + width, + height, + clipX, + clipY + }; +} + +/** + * 单指拖动图片计算偏移 + */ +export function imageTouchMoveOfCalcOffset(data, clientXForLeft, clientYForLeft) { + let left = clientXForLeft - data.touchRelative[0].x, + top = clientYForLeft - data.touchRelative[0].y; + return { + left, + top + }; +} diff --git a/uni_modules/uni-id-pages/pages/userinfo/deactivate/deactivate.vue b/uni_modules/uni-id-pages/pages/userinfo/deactivate/deactivate.vue new file mode 100644 index 0000000..1b666de --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/deactivate/deactivate.vue @@ -0,0 +1,117 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/realname-verify/face-verify-icon.svg b/uni_modules/uni-id-pages/pages/userinfo/realname-verify/face-verify-icon.svg new file mode 100644 index 0000000..df30eb4 --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/realname-verify/face-verify-icon.svg @@ -0,0 +1 @@ + diff --git a/uni_modules/uni-id-pages/pages/userinfo/realname-verify/realname-verify.vue b/uni_modules/uni-id-pages/pages/userinfo/realname-verify/realname-verify.vue new file mode 100644 index 0000000..001fa5a --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/realname-verify/realname-verify.vue @@ -0,0 +1,315 @@ + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/set-pwd/set-pwd.vue b/uni_modules/uni-id-pages/pages/userinfo/set-pwd/set-pwd.vue new file mode 100644 index 0000000..94ed02a --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/set-pwd/set-pwd.vue @@ -0,0 +1,171 @@ + + + + + + diff --git a/uni_modules/uni-id-pages/pages/userinfo/userinfo.vue b/uni_modules/uni-id-pages/pages/userinfo/userinfo.vue new file mode 100644 index 0000000..729484a --- /dev/null +++ b/uni_modules/uni-id-pages/pages/userinfo/userinfo.vue @@ -0,0 +1,272 @@ + + + + diff --git a/uni_modules/uni-id-pages/readme.md b/uni_modules/uni-id-pages/readme.md new file mode 100644 index 0000000..1650e45 --- /dev/null +++ b/uni_modules/uni-id-pages/readme.md @@ -0,0 +1,15 @@ +# 文档已移至uni-id-pages文档[https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html) + + + +关于插件更新的说明: + +所有uni_modules,在HBuilderX里点右键都可以直接升级。或者在插件市场导入覆盖。 + +覆盖时HBuilderX会弹出代码差异比对,可以决定接受哪些更改、拒绝哪些更改。 + +当拒绝局部修改时,注意可能产生兼容性问题。 + +你需要二次开发uni-id-pages的前端页面, +- 如果改动不大,那么每次更新uni-id-pages时,在HBuilderX的对比界面对比一下就好 +- 如果改动较大,建议复制一套前端页面到自己工程的pages目录下,pages.json里只引用根目录pages下的页面,不引用uni_modules下的页面。然后每次uni-id-pages更新,你对比下比上一版uni-id-pages改了什么,看你是否需要再合并到你自己的pages里。pages.json里不引用uni_modules里的页面的话,打包时不会把这些页面打包进去,不影响发行后的包体积 \ No newline at end of file diff --git a/uni_modules/uni-id-pages/static/app-plus/apple.png b/uni_modules/uni-id-pages/static/app-plus/apple.png new file mode 100644 index 0000000000000000000000000000000000000000..556f68666ecdb2a0414fb7f2a5a0d7fa484d6df8 GIT binary patch literal 10282 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 Z5FW-2!fSWBq{tqLd+-?8> literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/alipay.png b/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/alipay.png new file mode 100644 index 0000000000000000000000000000000000000000..5256d7a60afcb882681f6a681ae0e10f977d1a4a GIT binary patch literal 3978 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 EU-sXgSpWb4 literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/douyin.png b/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/douyin.png new file mode 100644 index 0000000000000000000000000000000000000000..f218f68d952a8e4753792b0529132b4522f5e8a1 GIT binary patch literal 3163 zcmb_e3s4mI89$#vL?wudNX*VjP|>~H-P^sr-GB~oAUJ@Crx4W9eI0jlce~!LaQJA0 zlu|-{h1gaKwG>eqtByeflv0hRwSd}CS_vXD1d*l;8pa1>4buMschSU0C)1nR+uiT~ zJ$~Qs`@a8w3z8C7O!E%(RwxwH;$rp5;BIqWUK7CoK;HERg~DsL*^nxyCdAX6XjL)1 z$O4cL)wlNl#$b1ZOs&yDWi;7CJi$=2rEI5)^L_%@VQCgJJYGF);j=)Vwp!FiR%~irUy}O%vku&r3x9%}Y zLm&)Gz>FX;Fpl61tV4}Bti_EiW+W*s$>`kP;%p9?v2lXS8=zWc2A(Jm({PA@!5STb z!90nRFpE(bENDs0Xe4zgfot9NtL$blkc{Q^s3;WU5sV{XQosyxjqoIkGKj0r8Xb&t3 zZDd`9;}io^It>Yf^jMY?5RNzUFSjNLLZdO_Mi`@jA&v?ttm6SO6bOs!z$>ezp0OUu zVUz;(tGODPP&(G^;x2nE=QYAsPxjErP|^(N+HAs=oNLMiUO6TaboXw6QZxbf4y}7P_#x28Xyr_dEnNU7 zmsWyS4rQk{M~u(GF98xA{iao;ln=AxA{u#B@D+j%x7YIqU@+ z;K>e-a>YBl?}E>ODN^iv4uxXsOxHC|QCt$BP>h3;;tkQm!^1mw?rdvo>*?v~?(VLr zsHm^62SQ*papJ`BDGG=A{&5-&f7Tiv3fpkpDc*;=Q-NF#L5hyP+z7 zbFh&On$%I>u=T-vPvzgP8n+_jZADVhhm-e)&N!WW!5}ri`OUynA~JsJiU;_noBtTj zKXFB>3~4lG4c)qUA#Jg$`JXKr7n>A=Lw!vh?`nRX0`I+5e5n)tI{n7r-3K%79qE_e zeUtC*{(E7_uDCg^KZb7n>%gUr#@O=dyJ9Z%o=T}YyIRL*toHe!Z+X_)AgO6e+M}A> z;618ooplD`lbhzFX(x-FSkLOXS%azCYPuagTJ_<;-J^4>g-u5`tX)*t0UPF~oW1t( zXK!iXfrgTI5*wusTjEMN1UvR+$J*`FQ*Q5j6miwZl(d%FP}S!*r%jx_uW@Pb-o4dl zwW~@SCSH%KYwx|eL)A;KidN_EpWGE#vZLAfC;O7$+_1GRHYvKUSnq@vm1Kl%-4t?R z{-shW^FQ*BW>2qZ{5-*T0TW=0ZuD+`P+yy!)3Pxx_ff#L-><*8Ja?D>g00ZC;AL+G zeO=1u?C@WB9@ouowoUy@EcAhZt7^vSxju?(w!o%r$73A?(~QS$nlCmnyFK`Sfbq7(I}A~)~;FArsm AbN~PV literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/facebook.png b/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/facebook.png new file mode 100644 index 0000000000000000000000000000000000000000..1331b61ffef8e169b1a11974a5749a89427bdcce GIT binary patch literal 3065 zcmb_e4Nz3q6<%Xf&5!6*o0=bWT`5t++kNltd%N##zyP}-C`%BiA~ZJd=Pvt{-M86Y ze#bPK*hZsi{h@{;VrmH(Ley%bpu{-Vj>KeQ5T_aiM;)|k0%aIPWC%IE57>=K{pqyb znY;Vmz2|)A`_4V*-hDGYZT^Huo_s{7(@jW8c4XjRuQtYy#os-@IelEG8~?bHl^x7> zrrIRcV-#dnM8;x|53lQVG0zwK1Zf2d>P3{Ncw-ISO@|G7MUFKrVV$JYXGd-&xzvv` zOVhHX(iIXf8=jx1k14ic01pZZ`eIMMH()D{H4Nk0@Uu2;GU$g*f-7PT@mfHAwliIC zSN%xO8ZCrGF`VAY8z~Dznk~_KnxuFW$(blKK~gr-Vq>lP(T@Q~^UE$4*f6FAVDqjHU@E%v3D+Oq7w-Bn=zNQrON{;LjfpE=wkqk37g53}9O-Z0mEY zK{eo3?*biO{$2o_TBkD{tpiylK4i*30kyy{p~ON=bC#yY zXS4f}5LEqHs+u3#sPqtJJ&jfCXD?B_vRV|FbDINl2tgEUph=n{D4HPoEQ+;JRvXDY zOL8`n95HpOvf?TUn`&E2P*fI8VhbB-{+=l=8CeJl_cfL!n@jb31T0wb2zkil^X3`! z;WXOpYQE~nfiXMt?ei&id%9nBDfxIIkTE|&pOR>|P`t%L&_-&QuG49As8WHpg(;3u zHOs1`$hPm`8It5UGbIrcDI-Fl8Ij;wi;J*G0-_{=wu%fLLQC-mf`V5<8X8WuQNc)* zBqKy3D`BR1nvi*hB1D-c35t<8QX&P)%!ncX7yJrtNFo3Jtayr+Nm^nFE5cZ;RYSE} zF-cAm1l}dMc!ANH;5!{5%y`T%fcHNz+GGhr-sn@lGEXBdW74E-6)Az#_Swu4j3n@c z$jKH0Su8v&Q!K;ELX1i4DC{)SthafaNr4f~G$I(8wGxb#Jd0fph@u_ z-m+QXSsdFXB7tBSULbhRY$dQfQIrrV$u9Zs-YmTcj}?jfZ}Z|K07R-)8N0MKAKj^ zEqL<~zPU_>|3S=u)S)9R!}|~t^TVU<|0ia+G)F4T^uyvCUc2pb!y7p~g>OvlF??0y zm+)neyf{yOe3jo=$n3>`10MDzFAeB)k51Oc7~PhwQ+2vA5$UN}i2!iD4=PVWObs~d zz*Y@&EAbp8)xm;#NZ0`vdcd+BqN{+}4)bcDcL3VD!LbAS2Vr0klIx)GFwCxmjNQ;T z2swLT@gCr+A!|2~?|`=n=yxEd8m{(1`4?cU0=WS$^}yf|9J&O(gK)kZ8qPynJ*+$m z%l5$#KvV_9?SQx%$ZvwQoe)_8sr9h#I7}}G{~RG)&OA*k+Y$;as$6U<1<99s3&;%1%h0Wrl9pXGk2YfJ76ZRC{Kno=J1d=+)% z#We@tUv54(A%5I@YjUm2kHpQ&Z0PxOF2IbX%40`2uD>F^?M`T(xOrvgR@1jD-<0<) zuHXN`&vTY)`oCB@e?9p0j3}$J?8M-?kK$S$ zD(dqX|G99**iSx~@Z81yX|1=mMSXg#YTASuEeo1GKl`TpOUL!bj-k@ut$W2Xax*HZr2&(&gvA>26H3pLp>){nJHL_L-V9{&BInvJX|HUDy&;-}1)B zvrqIaYiQfBdO_7-8TnY*`NWwub!(68YrY!&(l4gZE!bAOu)Vx>UR>9b_>ad;|F*Qb z_T-ed^y*U=8~f}2(3yFKz&daCk%wXef|?DDS3hKRApvR9C7jcNaO zUvf1|X{*}S?W!)!+*Z-vw(>yx%`=VbC;h0Qw5!Sf)-#8l zM|I~~8kb3tN2)yPZsX&XU%ywG$QR$Z*7|149@~Y`GD>gi_`qt#~rCrZo16{d(`{vbO Tf3E$d*QF$;Id&zy^!mR5pSY!V literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/google.png b/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/google.png new file mode 100644 index 0000000000000000000000000000000000000000..9155046e524adfada43323cdf81d8817b881edce GIT binary patch literal 4333 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 U;eq}@^S=~+Ucubc9x<8!1nf~DE&u=k literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/qq.png b/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/qq.png new file mode 100644 index 0000000000000000000000000000000000000000..f170691dc4d52d65bc604720d56a5a498170f1a4 GIT binary patch literal 3449 zcmb_f3se(V8jf0Bq>7dzQruz;^@U6_Gnq+df>;p{sA6f%B5m2)c?AOGVG^DmA5^JQ zMP-$yky0O&x`?ivgBF##F2*!PL`o5U) z6K1G&;5m=C{P_$W#Uyh^KFuYlG{J(Ns>=etiVYTQz@y=4T_~5Rip$BD=n5<-m zWChQ!;4jaR0RS~;r1%-?6pcZa5iA(Nm4R#LvPi%mF)=0w3qqU$`Ek)P{7|i)5K0ri+DIeS!!fNq~WhP!s|dkRelJq%t6l!G9bfj59ELmCmTrYWPk>iq@tYg9U); zs06jn1*EQEN!l z{tC3~@y`N))J8|UV*DZ(wb~WJU<^+KGR6|}i`E83rj8TIIfFJ;&v4;sfTq7wjZPM- z=P09Auh42!#tRiQPMMDa)%+zJR2o*BZdf|OfeWLIT(AIzQ3OIz2qqN>E<>a;7+VGt zG8i5;jn=X%Wv0v2Sy~7|6bLE9Ntqb=nJH))mNHVmY0NS*rB<(|fMAuHO5j8~O@e^$ zN~0`Po1)c&z<`~2;(AnQXpCN~RHc9i26@CPepGm<1R*672o)kDbfcqXVOl2DS;DBW z@or|djEa^01dp&%mV}iAM9?q|ku=6Z6iSm22GazGqa4FZv2nC0jloE17|w|XQY};g zBpQQRnq_c^V+bXLV;BjMh(rvbm;|F(6vH{h<^Q5y1qPBz`E6Dtg0e6QP^BCSL%0+} zAX+MAAckNlid0fclER!r@RN>l%n-oO0P1fT8?seY!q`=cYK4zqiKeN8CJ>ux;KvFVzClaLMRCwF@!@Pf(3~o zL0F6cx3q+u;60*YGzFr^=W1j^Wsxdp?lQ+Tuje+o)bmG%QbsY(%_dmDIH!zb1!K#q zU+4^6%(7B3%|QgG1Y^Qt63||#5|WUhu{cDD(Nb>QKRuBHppTip(dY)P(wI)^xsU|V z)4w_0qF*C#pwb>s9RWSYk)R=@1cpH@@o4Q^*(>ydhEI3&6+`*c`p<&sPdH~VZ(_c{A z-rhS9Th=)K1Zn`_f9wPjb^GcL82HFafOYID!AtUA`t)QS%FupU%qW}cJ->_hLXlkk6eqq ztf{H1Pf^xX*4%ZZzGIige!0z&XS-M3=HTbsEcYC@yZim}Yi8$KChw@;VX^Bjw3=$$ z8#?=zAE|c?3{Bfn-Pt!dEvMQe*BUW<_hwM6Nk;j)^+P-E$J%(jDQr|&h$3-n_u-*6 zEh~L&Go#PXmj5OB*i1Ea?VG7xYf@=*@fSw|?}t6J&cVT6`PmlI;x@14&bGfRnrqJ? zrk;@4N0xTe3R8!D;H$y9Ki~LxUtZoLI3jCr-XUc`{F_^si3`j}rzD-+zIp+7ZSB>C z<*UupeRB>i6+dPAhcCA%(M$fp^|1KK$%o8H@uF=VqTVyiiR`DpRlc2M^$sSM1kO!f z$b;hqd4=B;Zz3z>Z}Hs-vqcXAhjXV2ZCg8#Aqcsn2J()+aqtp_(BSWd{Y$^1VI3 zVAh4LOBd{WRT?m*@%eUqpC{4@JIpK<@l>=k+F%}sL) zix#-gOOx2G9``(;TPwWd$_wF#70(uzKmAC>nus?xS+Bktv3rA8=<&e4^P1mzC+=uo z#7t|$@LNH4$$M1hkEi0+9|~`3@4K41GBRQAmbJy_tzVZvxAji^-Y4ArXK&c(oe{OW z?c|e71E=5h-g(zeB`n`}g?F`x_$b}+xp|H}&ePI*`vO6KIb+EzOWlLTDJy1_o_lBV zOFVn5-1?L}=b_)uW=r1z z{{9=6@VYY{^CxXWhl}n+eNHV)aQj#3GVaK_Nvlv+Hbz3sliO{5wBHB)5>o6CYJ1!HO99l&bhKd zYwK>YnYNTzKd#rk+fw!Yq(+^1Gqm_bZ|0BIyJvJnaIWS3n>A;nPv)F>K|bX|ulwQ- zQ~4|ArDr3ArPmMju8BK+-Rlc~lR|lIVBx7)rF(b&ngDV851z5h#5s>XSy*7!Z=GHi iq5e8?TgdPqlKkKA`|8urK5_nIiV9yB_P159zwvLfty_Tr literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/sinaweibo.png b/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/sinaweibo.png new file mode 100644 index 0000000000000000000000000000000000000000..12cd03812cf81febc94a44c5591ae5b27229dfe9 GIT binary patch literal 4081 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 Tshq94|0>)zZ*#fi6maw(JX>;f literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/univerify.png b/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/univerify.png new file mode 100644 index 0000000000000000000000000000000000000000..aa0b9f5b56d36120c07016585195093aedf3ba59 GIT binary patch literal 3365 zcmb_f2~-nj9*k`kiK;fc2CxoqYgEcM5ocbaYE0Ona+)zynIzabC9c*% z41(#E1gS=J7_8O3szhOg)WCWTqJ?0@0P74mq3pO+z?+@r4U>|`b@&2ri7J!RX)|av z1qB7_0FsZEe&y5wy0?D=iZSw_RI>@vj_!&>D?hJ|2q2V(D_>aHhBbjgEjkRN9d}-^OVsaSmago#9ek0Orsz8=E1? z&QVUmo-GLZor%iqgsemXYvmuNnysu*;CQ8*0+&oVxkMETqX>kc5KLwxxB(#yFg6m_ z8(_Fy)F`lKetwr|IJFRhWFw>j2SVhpL_x{0l#_a*Fv}Qt!ET`dVY7wGHu1eVz zMnjU2FW7-&fKJp8Jr~d19GiXRE|H-IG1Z82A!6AY}VF)KM z1fmIoffzkQQ6x|CB!z{W;1?d9Hpc*b4v>FGN0W`EaywS}=22nLEC8*ADU8;l9E7nr zpi1C+h$L7&L^B}&lpdi_m`>1yI|?YZH*0roR!fmMj6yukQ4ofa6h!K^1Ox!mG{eCR z%d?Nx#&KM$>Q7)?!m+B3ZSzBNi)&ey(9#^F=Xg-)ET)4<8s#A!spoJG;W0X# z+jg@BCJq>VO#iftIRxHWK-sx5xu7ba*q@q5fp<`@$3sUzm2f1hg9tsSNEF6kh{g#V zVi=NS^f*T|{C`95-p`=>b)EhEd!ToOg)vdqTn@}0jq3N4`QLi%H+kqzru)a~|3{{+ zG}|jo^V{NUJL@){KqA|=z|0FTyM`@z=^EFZ6~xI7hH>(a>7Ri?9%)OR?ocTDMu+bn zijTI&C=@;NGSjnDLZOf(hu*3MkC3xkJh3-VRo^2G{$feNBNSb<&DDiS_u)ngVvO z=x&v>-Tno&(&5{|P$+1v7Ed$>ci#$>H3e(^a)Tt#1b}66S)G*Q_AjoLifScM4mAhl zYQJ3C7$~Zd=6L+?`=pANV6jiS+!DMc$#s6YQIc!?@-(;KFNb`R>=Whvw*&i|0>_$z zrMCc{K(Q}yFA(y!%FTh$TAx%@Bc5*wUTl#!Hw3Ev!OYA4;s)t(b8usWwB8rUsq$B~ z$`$v5+ZqC=?gf|COT1U~w92%{UsNl;RSNB>R7`lb1Q z!gE|RBITXuYMqTkMj|5#&t9M&w2jlwewX;iBJbNc~ z$Ea3@oN{4!^`)FxxJ#u4mu-|hJW|j?o@!HVy152c_f&1@OUY_N< zapdP6DUn9aklM(tS;kOYi?Moq#lRo<*f>kwA&-swc-xrKrL&q&)SfxBdhE64575M` ztDO&qTbk`Jo*EqAIHaO};sh0Wuk78L(p5*#*zJMyQ|IiC!79X)z1^v&E;3)W#A=Fj z&zp*0;SS>u8bxnto%;Rw)9EGV1tTWJxhs#KIJO}6j&**`>x#kYvK9QPn+f#`Sbb=~jRn!M=H)P~RcG!6X1=-{%5 zqMy&yCM?IJRcE(d^;Han4#zDWIrJ>9_3o>2&O8_TG2+0h9~gt1U-@D4f#VS7A+9~w5O z5^Li5^Oam<3}IMZSwIh;z^NO0zD=AnmgT!*;*mAcyT)z!Zt|+=U4u7duIZ^xKbXBi z`{DMMo{>wP<8Q3pJ?~|2SdmW-ZiPhW~SzX}K=?PJd;_mPj~q&<^*z zhF;6Pe9!bnOHJBOGkV-yDGxYg{&1xnDGR~!E62Z!kXDEP-K3>tB<~$NXVHHEmZfmT literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/limeClipper/photo.svg b/uni_modules/uni-id-pages/static/limeClipper/photo.svg new file mode 100644 index 0000000..7b4b590 --- /dev/null +++ b/uni_modules/uni-id-pages/static/limeClipper/photo.svg @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/uni_modules/uni-id-pages/static/limeClipper/rotate.svg b/uni_modules/uni-id-pages/static/limeClipper/rotate.svg new file mode 100644 index 0000000..0143706 --- /dev/null +++ b/uni_modules/uni-id-pages/static/limeClipper/rotate.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/uni_modules/uni-id-pages/static/login/uni-fab-login/sms.png b/uni_modules/uni-id-pages/static/login/uni-fab-login/sms.png new file mode 100644 index 0000000000000000000000000000000000000000..5533743a21e39f8a89ae2faee1d89ab9581bf29a GIT binary patch literal 4285 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 F^iP+OC9nVh literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/login/uni-fab-login/user.png b/uni_modules/uni-id-pages/static/login/uni-fab-login/user.png new file mode 100644 index 0000000000000000000000000000000000000000..268420b7343d9b2c7c58233e024927363928dc5f GIT binary patch literal 2997 zcmbVO2~ZSg79Q7Q5j7HTFL4?sjZKC!yFv1+pG=~_>DjuLo zfDl(ij7fx8u6Tt-Nzi4Hu!xAt5{5EB6j>Gtmy{wZ(YHMuqe*$BwyXMj|M!3Id++_P z|4t1FUOvg$)mb1AObQI}3+3-d`{^{AzxM91Rr0s-=70#RKrmsd{TwC8&Y2|;jH}jb z!?|!xkeW6bL?mOPSW$w(%%cSY&m{?Fl8$CMgkmH0MlWGcafuMoGhV`X38Og9tQL#omj$(bx#lPPATP$46d5eXkPvhW?fkuk+v7dgfODMr4IEqV9 zjL_n8HLg@+vOi%eHHHmAH6}){+vI@SON-*T7AMql9j%9L^yN+=l>O3{4%Nfk~?Fv?SG?-NPb+&NKlJuT#}324IQA&k$WvSR9cU7wB?W>}9w9+mf8dWYcc@wn z<$r|IH=rdGs(kFms-=ThPbd>Y`2whvLA4*0AyDcHAYcl+A;V0;r>)ArW8zYJ%W#AKa~hrmb)_0P5C4ZxuXj zgXT0C=z{j+aNPnWQ=qpJ>NmjEx1pyLn%;*>3A7!ChB#U zU1y=I82TEZ{Uo#>h1UI0uYY^g_u*n>Z?k z{|Rv7LW9G4?a2aYoumIIM<5t24fONYMvd*tj$hfb)TO*-N=vqC@3c^4N8-J;X=_jP z|JczFV`hH0ziIm^X>!K=+`c6Pmp%VmaV~#_J2m>WQ`*+7>FuxY`Luq#c3 zy*B@=T-nL{os(}kA8s#d4sttKu)5(&?)$N0%5Hix?-r&jF5kT7N{fqhr*d!2n<@EF z=X$?pa#kskQuH9Vy5`C*&qtN9qvuaLd*FEgwVa$F?Bs2y)Z^)Y2MX>Ge4<`<-ox2=Km@qdoqV;Ioq17IzT@JN* zd~r`>KKL(dajWy+K1gfdS@fCccCE+OIr*PfO}}uy!;<(Dx7WsPiOD--%J4SnH!ff6&$@*jp4v-KynP|LBB|0x|-1ceXu&G~~YZsmGKV~%$NYig$?XqEcA?1`DPvM!3srsetOS7NCzHfQWw^oTZ=%-C~( c-EA0EajwApWc_(h`;T>?f3V*PpY_}R2U3RH`~Uy| literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/login/uni-fab-login/weixin.png b/uni_modules/uni-id-pages/static/login/uni-fab-login/weixin.png new file mode 100644 index 0000000000000000000000000000000000000000..af7175b6fed8670ce6e6d1a7a64a4812a4db8cfe GIT binary patch literal 3934 zcmb_f3piA1AD`XavZ1Vm#5Bn#b!O&_xt&=fF}bvENg>ucGjry`m>DyZTUw} z@bqACBoTO+D`6w}mxV-ZleR%K8Aq;L?8+n8xtWC%Na3D+%zr&9jm7aIPA2EBAkiaq;`l6 z@btktOJoR^f~Nu;kW9zYAUsGV6YZ!Qup}Y~5r}jGXa^8M29e63(6F-?4)rGE@)*7> zmswxv8xto`D5MMmAv!u5A8m)1$oK>hf=~<+fkXmO3qT$#R=_cUSiWWsfrZF9GNDu< zl!&ovM3^nvrC{PvrZXW#Natb2^4T<@2_wY7QUZu4szaJK;=jo}TkQewRx`#Jmf+VsjK4#%w}<*IMouD@6#t zh+MKu#z8hmp)}X1qmeS4WeBX0$owP{(OjW?<|t!HXw+C6f1#KwiI%ThumNGg3WSLx z5lJ8bk^my)2T~XyjX@-@C(;>2;*6=Mge&C5&YP-B3xJ>>2%*(wkchuBMO%goE8xF0 z=5iQ3i7Wy}0~SWWe1sqs^KsbuG%}neB8d!jjIy&^IPdQ4>?4!#gd%i7?(6D=b>Hkv z1tBUGAmPDjx}Kg4mV~oQT|#%(TsLzi93hwS3p|lbVpFITDnN%|4gj;sWB?+PxB!WY zKolNCBe6mH9GbgWu7JfHM2&`~8ZShV?1&(RLV-8{n~ksmHcX}i5Qq=~7zD{w3dkdK z*wnfG-ZCL7NLcjOtRRrYC6YK4fQFEW0EI>d0XB`s0XTFH3`0Da2f<{u2!4rU4s#RA zPmb1KJ}WXOm_Iub2_4j=xznU!GTV-X0AwzO29RkKlr)V?2iP36{xBVcNkq0iL9Hls z(~MXb>_+3Yv*VF@011L%fD9raKgLEqEr5qwaKsi<_Mm{!Vo$c3dvaj*S3xgom~&mrMm9Hi-vNAv!`q z(CV;h$lU&D0fK`5i2`Q4%OyNTG%Q0l@zK8eON9~sh`bz*`g7_aT4w~}QUMwr?MV`m zOa#~z8U^5RAc#Y!AZ!lrx6~IZ64fttPLY3y`fOS`0$9vP(9?r}`}@KCZz`E#IbVl` z!7TiG`Tqqo-I_BUM)>dMn_gRRz@UYkoF^UL|^6)TttlKNroP$Kk$9LF_?Gt zd_4R%Pfbm2sb=8I%!y?dZb~{!Np`9tp_Az4qNF-j5p7D1Hz4uu(7_srfsODVW2LcZcB1oJhx#-VfQ&fV{m+n)I~|I>#r6!v1|LQgX=uP z8befLy$u7kaV=t>8mG~Tk=lOcr|tWD$9j_5;$%&{bC0s>2Wn4srT30?r?h{P(V0@x zQ#d&_v9C3%|MfFs8MeH)=J4V`!i!{PC5~=&?YEadyqKJ?3*Ww^>$)O${c^$K z(e@9P2<;8tSbgk|Ygy9Ky1u~aT?ZT6uEZTxH?qoipEWb2S0va)bc_BPrY`Bfca zN9l%ehtm;mv8#`z&AvysaS;Iz+a;@PtO?Zc9xW5@?o>Bju$++QVfxJH_j6C5z33c6u#ukA zOwZ0y{Ak5mO*6lgX%OC6xY3u5{rZd7ma2RMy<5FkUJmr6r-gO-e|Q#-Y{!4ZT&{id ztDqJ=(~C|mNqBN$PDM}K8cFqi&tQkh&Q+nZ0h#sIv0U8`R<_4o8G2*0CgqH#`wN5S zW6L71iUWhvpW zPMSX{(nv{%b{#Pc{5d7HzSc4)$@@@rlyk^>!at5P3xi<77Q4qaC$7EEs?;)j6)LOq zU#?TcfsODNpohaDe(MR%%P7NcK0buQ1&2d2(odbTXc!sptX)~$mFCLd(w43HG&b?c z(SzUbp^@`neYy5{$W8g@OUy-=TD)6EuVyY5aNiOr&)qeV70UBbdyYl%UwEq?@4WZ2 z?>TRWg|g66VQ-o1kf89~z4ocK|E=fw;fV=Gm7Sj79FX>BS+)*rxwiPuAT1}(^15rA zEbo=cCdd2!`Ehv-rTg4ljI`n8MT_%kS<$aE?b1uHOdRe05ll?%iqoJ!IHWJGE*|$+ ze%FZ{)cv=nDm1pU{rZE3{Wk*E?p$m>85mX&TG}^yJvbuvYP#mqus3~iPKFoqpZb@4 zC7ghA)5{%2%be@Z^!3NKwL-AUIiRw0X!o}<+@Z+}wW62jEd&pOEG_~6N?7Y{`SG5& zd3lHOjKPyPZ`?YCKk=$~TP#thWjk-<3f+{OKMR9peQf;lgr`57w%^NjIv%$FzQJX( zJg4<#_j~JwCztFrC|^0wZ}6yZzSj5BYmexkmZ2H^%LZP0p?caYGe$&6Q-N9Q#KvsNnmiFN*>&$HovQ`wE1=A+K@7iR3 zAd8?H(L1uLzIHs3iqk|-zL*0@0g0=j(iUE?;l<*A&C&y17oPV!QPUmUIn zgFI4intGPilYQ%-dRziT?qQ CN=BRj literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/static/login/weixin.png b/uni_modules/uni-id-pages/static/login/weixin.png new file mode 100644 index 0000000000000000000000000000000000000000..df70aac5092588d7ccb87d75f024d0c9dc804607 GIT binary patch literal 11483 zcmb_?2RK~cyDp=P9zpcz-58^c9(D9CNR%-~H+rvwsL?x#UZU3!qIVIUgalE8AfiV| zobhY-f9~@?=bq=@JI|E0zx}TFd%tgeYwi8aUNJgaD#V1egcukY#Hvt5Jq!#iJ9N7M z9}E4hmD{b3{vmLMns{Jf+_`)E!NkaUPJ@AgJ7aHP>}jm2Apv)B7Jym1SRn*_on6sr z3=An*Uso915#h;fg|M|pO0yik>1JWJx0YskB%%q_bX7pu*+c!^5&HgG25^5zIK-Mo zR)$&1R{~AojPQgp`#L)zJtTakS^nUaK(}wrf-KB`Ks+6#SsvaxWH#2+VODT)M=*;B zi1NdQz#`0I5CI`kVK4;3#|#1ri3S^zSWWHsDS-E(5O0%Gq{uzR^>p!$ekH6A{PMDxC%vDfG0C*eHA3$sPKR8z}cc(v` zTf+qrP6%fN($fQt75WG3YUkqV;$i3VUr_&Z`ad~9r&d$*A0Pi#i?j1TE<8MyywPF& zm5_gn_Au~sMF{F4JY2lo;Rq#fv`p69Xj~-}+z~KO7k2{}7pK1mO6PCM%nAy(0|Q~^ z(uBe7k+*Sh|4T1~BFqyZ%>n{~g!qAC{6J9yAt4E2hy)1C3lx_C0{?_+x>(!W`27O~ z@e2X@f#L=rVF{3sgplZef}-oj8s-W6KZ32{5;iXG&MIfhJ+(j z6{T6w84|F!x0V1ytc9&@gvI%-fe;u!*cu4pw-SZf@I%BQ2vIOZ94;&-`geat7r57L z9o+W+b4pmdz|kE4OCC@JE@WdPD#9-Whr{^cHeefmaj>-rKLiGb!L4oJAQ2GaZ#Hdr zd-SY?IsGf^ttx9Yqm3vKfe;ge@QaCxi|~Wt2qAtL1P(#ZAQ&7bA}$Vw2#eg-{vYKe z0k!u)547K3vq>M}_E*cvp81aol7PW)XNEKj{I(hEKRK$HGA zRr05I4;LFxADBDhp)ERh|FcpQ{I4SLfO-G-`oY#9YmktzFh9b^N(eok=p0&szz}|r zFa!()!$n{~E3v=h|9ARDL?wWrzf1T3TK``Og4@B6wg~isE6DQy5YhjrLjRQdPelLK zWc>dek>KrO`)9!k{_nN;$GLx5n9)P}hY7vf-!}ib%%BhcxlkdH=w!L0FGD}PUe91) zVD9Q@7$~W@YREUqL(8G^NO@=}6dDJWcq1XxCMDM@qgDu2^jCydDJ%LaD%UA0ddjQi zLZMN&NVR0BqPL=2A`}{~j5exes-cbYuJX#^%E~BZwHLRC%E8KtO}EC|?!n5?3T1hB zdGs3^rL2smjZs!BhNAr{HYlp4s;T8e)SBE;2S}gs{lSkt;y);fAoLm=Of8G3I>t;E)I*4D3 zpFf$6`5Z;jO*VNl>Ho?9#nua+Zm!vro>*HZfr`|Up1D2~Z*U2ZXU({~=cq3@*yb_4Ub@)gJBvp2HGj>bUUK+{=M(NWQc z-G=Ft$tGw=HmBDbS5uPlhMS4eU@}<6LSC$G~95P*r?r;EQ=+c9Bmn(wLv<27m)2 zS;Gm2m)!>L9QFk)OTv6aC-!SSS}^J8=u$lEfvydtA3&-g0ptO0`OL_=Kwo81bqxLjeIy9gB3Lg#;mu zBGKtt;%b%(>Xv(x^5mQ8zhe*ROdT5BbpgE;3&BsRJ>@Bun=kEvbV3Sfy3C&Gak0pP zm*NL?pO;oC;^yNhxY$vN!Di1G4=LT=8&?urmBl2U!XM2G;!BgtlUA4ix~NTK?!qiqGP?&yf_4rY3+W?|YR3j$wO| z>2V3zMc5orfQrv!lmVHq7dTu)hbhLeMgcJPfjaapMUWo@jtZ?VAe9{zz^~(uW7gu) zxOvx+j$J1a+xy9vK0^+qhjghj4;sON8ov*O0FYVW-GQIV1aoYt^eToPP?7hrWUWJr zKbx>0h4FcdH1fVyo~KoOG4|J#9@osm*X|vy13_Qg6&ZImO0dn(Bv{=KSnqN_H{Rt! zePsLoOt{IbhvTD)kem z)i_;J4=T4B8kdoTYt5jl)rehvo@7Umy(vJxw-RxC@Z&``1NyoZkQ64D9k!0DIxLl~oxY0S#OF{G&nC>Zg+Dela$A)}ee8F&i zx@}{V%B~Vdv&D*eaBqrk@`rVdy_&kEMDOQ7=BK~+oAcnvw}4J|YV*_U$U13B+d>rz zezK(L&(+C=$V1CoWUOQS3X1Mty7#i_2D0<}tOfm#22&E-U5y#DDZ(8x`4;Gd>PgADiB=R}gD))zkH$U8>TJr4*}Y?UY+jLXN(^c~AGT<+CF%L&fL3+%OBR z@H6|(=PnzqZ@Q$(uWAI%CZ6Qm&~fdTQ`%*N9`I$moH+f~?vwpBZetTIO_hqR?HxyW z*h(GKI3S@pt7kL!^WIkE56H(z8SX+M_2|K<7M~nxz2aq$Imt(<1dp_2{Cc26K-`77445_rcE{U>ogDzaHFY_fN^Eh~ui|NL^vo5mr49)zLWjU&Y52996tz6jp^iWA6JEyb)ps{I* zqxyO%Q0_c1w_2{iTEkW;ZZvYu*0OPe#4SZar>sW#3w@nJpE%WOiD%AQHLool1iPsh zCUK4gqmF($znT7@gel6M#BwHqj^@vA!pF*Cyd*tGxAUW;UEhY34{;8L%I|xH0TlcZ>6h zUbvf%8K$%9p=WNqYSSzia)d+@6`n#U(5 z!Ql$^USUo1`D-dbpCtoXSV-*T$hk+mxyezveMy9tTJ(vx&9rq${B;%q>T!>}nD*r~ zkND@+>QM4g6`$}&YY6e#j0{gZT*V!^eseyF8fM)c8fI;v3@;fvrle+h?nO>zd_+#>Kim9xsyLOhVn8+h{euWEdVqzSb4a)J4#J# zp9-U%8|K?SJlUufV8YE>40CtJq{Sv^;?dl^R4^pX=`tx;)8X_I(6jfeoFvJ81~@*y^(kDxFf7_8rhkd_W>wc7 zfP4sa!BjCgDd@0pYtF5I`oj9v!WO`k^aEAQfC*u>UZiKi!_oqvm-*6#F@QpkXk15= z0Bl44@Ke-roxy0;o|c#EL$wjsqWLFIzF`Cdp}HBnDAo(6^dw7U!J=6S9xvCuid^gB z2G8V{ifM}H1A;>LQ-`Uubf)dKvpjU@lN2|ZK!G$^N%R*N*TA| z3L#b9X?#Pzoq;OzgvvPzC2IQsheCtc5d!Y=?guDa#SywHvg1a4Xv((QJ$d0pbL_&k zeKInB);S{irhXUGtaDY{NxCQ5Lp?9@2eoY9$49V-QGc&{kDJ`+MRf)o}+)o^A3Q zYU?Rg{L4fls7%XTfoT$u_U(&V2W$@yxJZY}hh2eBMpkdOr%ZNB@cn64)4vkLaw6)J z8jmq(ckZXKW^NIZYt&*edFBq~bOA%js6b=eeMMNIMo>peg7dotH3>z`j`s;GQ#QSF zHY-jV>pE^|h%b$B*+yBxB_Ca4Ufh8hEY#O_aey>!Rn(mmFLm)bjfq_fN_}IKYsXhd zuph}*f}?X+V_ejBg$CvBazrPY`j#V%^z|%S;dnvtzW;Y4(CHR!((w$_PhAm#DXd_RkEa&J8^rF|yD_7r_50&}OwW3YTR%`0i?l{~C)>RX=3 zXh3d6YWe9H4`*uejP{4wr=Oz>uf=Uoa{>>O`)vhZNL`%j+g6@@z0(Y`T{ByPZONmC z=H{JNe#m{t4$Vd(aS@>&qsHV2$X!BBjPV5HCf&xg{Ri)A#pTBG&#vj3{CQdoB`X>W zxugyY3!Q|5FN5dWKMKOID(2X87V~0n5+~`4pXU30J)Hb?HKV?5RO!}d`l!&whw6Mz zPP9Hvr{F=Wb!u(6puYPj7MbnQIdbQO*&gDwwZ(=Ac}IM^>v4?L(covv`9s{LGg1SI zMHO!zNE5cOx51vh|MlU(>G5TR)-JfRM6#ng<}9};bHr3_r| zoP&hPxkGl#A&*)VYxkUTWPXVa%7+n<%37G#!F=>g8MrD1pR8^+_E62JFtD)I1(e%> z9NDa;>gRO}+a{hqpj;%xfBT(B{?+A?#2hg=IE&8l+wa5U8t8-ugLd^)PW`v?-Mshb z5?>8shdv?KQWq`~OKoLZ%lx-4^^_WkEriTi6hk{cN;U)$j?5~q6XCe=_Iypw1b{fR z)bA^hDQPtk$tU+p>8CHLz2r5_dx?5DxfU@YLLGJ(pXI+m2(e9VRSgZx6gmyf#8s%geKl}vXY=Z+15T*SS zVZB9EoQ=?LKms@pB)oEwxhI;1I6=|J9 z4>8fH&CB%ai3}~Per9~5C(o5X@{E*Fv4%{kfEN>sCCo`Hd1aPkEO1W4sWUMyB#|Wv zNS!F(qQxn_Bp)K|>p&#^MYdu|jv$x6y--p0@zCyrTnVLu8UJQ4owJ0wpm+RL{ks8& zuk}~$N1o)Jy&DH;ny3i%x54`4Y{E=w%MI&|=c@Vw8AKr)!|UXBZR=#@?~e0;nyh_$ zp5IxYoeqpsn95U{DMS$*=k88vQi|fN8hTbTe0?e{9@oO*2-l<|V6 zh0+XSmryqr_-xPjjH9l|&q#gaDJRb*5qY-}(rdC;D6dEDz?+0)0KVHaxPI+9_y8a+ zsUE$YnNYruSJ7ysf@el6B4+t0Zmda}1yA4p=e_O`4LS9bONOL*bYz}-sw>%)xxKzG zRqK3-yu|57p8}A zhL(+uf4?^`XD9q~J$Z{l(mW^d{9*FC4^b@gr_TX$J!yD*I;G1q{=_k<-%X2QHuITL z+DcPw?-9P4a`4E;%IDm&DhqduVz?1eE}yy6C@sSp6&y#3-j{`=A;H^>uoaMN&%((jOn}ro|?ki$$Zep7c6jb9py*pvlJgU1Y z|I_pNdc}39kxe`F8^7>jUQZuovVwEWk+-Em0N;wrurGF;k?$5?OUqG+yArYQb^k19 z$<2UpzQ=(wR@`<19K)1p!LXY&{yG3N-u|fo58iwJvXN1>HiGG7i;D;YPv7B$p_BmW zB+j}L%ovH|PdM?I#P2)vDzOnFAyO0dD zpv(}#Ezrf%P{|#H5nqSmLie;BN7g<$JfW~MA|#)~lk}fBFxS_EjuF*-&Ce)%SdA*4 z>3R5C8GfQ4bQOxJsc*mEH{niAV014cBjk!k`%qX}>!^!0e|xsBq`c>>$cQP|mR>G5 zSLlne@g0@?S#eHj`(7R0NE+;^9$NV;9=?48g>vQTFAq~%vU2)p0Xe>-DglLQn3}K3 zfzOlu)!gO{Ug>}WOeN);=JI~0NZgGWl1-7ZKdlNpyp#_f!fYneH^#ImC>6HGjgXGg z2eB~+kkl|rf5UG%eijpI+bW%0!e3Ta9~qi)eko8K3nl@(>2ch{>xC)}cj|l+8mb~v zbj%AF+))xN%Y2p;cxW4@k=G9ZZ+*woiA)q|l9R$tR(VHcJN`JDxmpeeO7GyD>QPfe zvOJ|AlCDe{Yft86)LOw`o#?R5Umj1Vc8L_j0lOVk{=}gr0T*`40h<%dJp5tD5Wvkm zyyLlw(IHT@?OIz~%?Gs?#+JI#h*1;D5i?PkPQb`LwcrrxE+|6l3XGzn3{H~mFB8Ei z?I~WkztM4kXhz{`YG!MBuTqQSTNIOL43b3CnAWp%<&v?jFya4PWuR6*n9P56(hf1o zO)qa4Ouy--H||euF9#~f6nR6Qy~H3UhCAegg>63;XUGSgwQWs&|%W5igN`Cw%T?|zzc*Q+~yN;MeE{v=`Xm(c}!Ks9=G?WE) zYd=1zX-cg5{p*Z0zti{k(Pn%|Nrow32D&YBEX$7P&(v6DCh*alROF0995M~>5@ z5*lf1nC$xKQLiR11qqs)Nw>L2OLr7wl5>O$jv(yZd^-v{Tp!DR@2UuhiYYB+e%sw_ zYO2Z}DEQ)@ql_#2P3Xw%j$HWiW)F1{xB%rog?dj1Oq*JyxDIoDo-I-I++eGg>$fOR zOg%*o4z2fnLgC|#9BkUph}`tCR*h|1Ka5{avx&;)mFBBmA$esV-(3gA29>Yg;0fmr zGU0>y+nzpWjIbM-wcD>=rO?{1#324zjSF624{KxHz?3TYpvJf_@x)AmP1#U!Ec9 zd{SyQ4Zy3^r=iNxlj2fFY$~D_=B4v?lyejgj>pwOM747@C@nQ9ZD4=uCT8eM<~FAf za1l%#1j&U}4UN<+wg#*>`Wy*vaC1M`5}W$&+OR2W=Uj_P+|odko5J|!^}Tx>uN?4xB_)ik zN2W*`krBAA9t>;_jf6@$=xrgsMLgLFT`&4>#aVY+oa8W({ALY)R5PYxUTc90xzyOz z72PIC#G&O@!^-(m7>EIz!U;m+7C#K;J5GPNGMAh_o=y5m+XxkD8$11yYkF*Aw8?E* zeBAsAmbH3`hr%cWZ}bAa$2*6@VSYBVn-7zx)pK|k4~2Wf<`n?(-ISbNe$U6H*U8!y z>26r~TW7Xc)}`lucKmQhYVphWXMA}uT93B@Rxo?xNJ-D=wDP0?wQJ_eB$}&>5-kAJ zXkCU0!s0%twhdX0~{9)YSg8MJjvlmkb|J!4i;r5~f(ukj*qhYZ>)*9iZ^x)N8|}UK9}$t?Dz$BpwEo?F%!iB}Z?t^TX$xbtt{^^Fv+FfiYF zXnMCP8nmqAK1|4Bf|r0@COXW6ILaKad-^WMPZ(j2x=)?SrE)*CoiTrMO0D9P2k$%j z$2Gj2=?csAKc=oOhO0?;6Ay!q%Z_cdQgSg069ei&f+W>}#1G?k_>M^U^-at;CZH>W z? zb`Ff0<{7A}&9=|0p6ER!@9h#)m9^W8&n)Fqc$O%vbA0;2o_eKP)84n^BYWtO5h6uI zlya*0!S`Ze<=|3nmb(39 z+hUU0hdzopAqEOOs0z*6*Kt0KK1Nac&{Hdq-HhyI6Kzj z+t_KYLH&@9pa+dWS{!~gf!%2z-?ack?)?P=+Bwx}ci;;Dt2@cVoEI6H??7^_Q4i)b zv{T%vv>xQoBwV%0J1#fXfs=(0ftQ}gTDsFqEKp_Hv+&W;YmI;hObXZ}>YMl>QABOo zwKZwc<7%`N{6XtnNh{4H`Q9eSSvCL;d`ePSW zp|@Q)_Kzp7D`NA@dgv@33z+HkqZ_1>uJUQrZi-X3C~;F?&fFZ zZg?+mlyS3OHvB<{kWx|b!u_=;iHq#3GynaFH`Hzy+c5<;0J}{d$TCv4+*1C)1n~Q* zKF~Cj!7g3pxXc zSwHX;^2GQsein5=opjCY;i9hC$dfBi8T1ov0(h-3Q*1Q_pB)&Xt|E2V<=x zUrnk{sj)oO%A1XtksC!yQ-;=jqZK`gtz^H}6xVsz+hQ~+X;jJMDLK#l@L3R+%&Gl2 z{Oom<-0QSHC(pibr!z(E#SWz!fXm3R;xN1VR(7(xMb8+B_hpB`v&yK*2A@sEW;!*R zy$pgR2jgM_?=}UHa29WiTG zYRP5|2LBZ2d^^KnnT(TL&G>CwKe(!EZfPiU2j#SjQRhs_ovYee-evrC1m&W9) z%htAIFiD$N&CA5o(?NOj@zD!Ae%a*~*mzv~2U?sDHQ5$^mfX}*Y3ytamdi?*J6>4M zPckHXO9p$Z%hQ5_xE)m`e->y;Oqf0*R+;R_SMv8KlaqXgjK2E=ypi9gbd>{r1Rk;F8(Y6XZ>F@l-3xHP zNrm8<3ZV0qq&U&xI}B%Oq-kQg8N5Ol&_$smRt4FtUD(c*EQ_Ovrud%R)5R;^KDTX? zUoE7WCYKgkhb>z5gW_AR%<(wWtP+7D0j2utswUt`&PMxswUE-EklNYRQs0)JdeOT@ z=tt7AY|Iuv41l;3k0X`*;DNW0eC$Xgb$lyi6jMwVj~essv;Hq@yoNPqCv`_qT8{!C#1Pq~H(lDk0UB3G5>ibIRRBZTOw`?pb<6n7`B;v4O)Oz5D1bDt?nr`?GwQJs0XVG*`62WsD0N}?Xr6`(R?%EzT< zSq!yQ>dq7o=Xu<7HhunDH%In8T#;hoDv4NC3HBy2A-dC8BdsSgsb_lWQRTAnr+bOV zF45@I**%}XW#q(lp+RPqQzDe(0N?+TKh}t9XSe$AX z0{U(qd_72vVBGBR*)lQ9#kiW~<#FY#azY1hi`bZb33|ImFnj&4OnOccsSt+4EsJjH z2kt8c*d+d4o4a@V=){ISScpX*v31I@*B>6!1(9#Q5SU>4U~3WmM2r)4(0vlA4ec}g zv{7d25l_WkCrq#(; zLWMQ_=fAyaWq2~S9@C*jV366<>+JJcwg{1ZH>_3a^d#!y=B!wZw7Tn2r(UvrT90W` sPe2vk%Joj&71Pr7l-b0@;r+`S#*Z>7MDG?nZ?_+-DrqU!%3Fs02OG_@1^@s6 literal 0 HcmV?d00001 diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/constants.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/constants.js new file mode 100644 index 0000000..afce8b8 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/constants.js @@ -0,0 +1,108 @@ +const db = uniCloud.database() +const dbCmd = db.command +const userCollectionName = 'uni-id-users' +const userCollection = db.collection(userCollectionName) +const verifyCollectionName = 'opendb-verify-codes' +const verifyCollection = db.collection(verifyCollectionName) +const deviceCollectionName = 'uni-id-device' +const deviceCollection = db.collection(deviceCollectionName) +const openDataCollectionName = 'opendb-open-data' +const openDataCollection = db.collection(openDataCollectionName) +const frvLogsCollectionName = 'opendb-frv-logs' +const frvLogsCollection = db.collection(frvLogsCollectionName) + +const USER_IDENTIFIER = { + _id: 'uid', + username: 'username', + mobile: 'mobile', + email: 'email', + wx_unionid: 'wechat-account', + 'wx_openid.app': 'wechat-account', + 'wx_openid.mp': 'wechat-account', + 'wx_openid.h5': 'wechat-account', + 'wx_openid.web': 'wechat-account', + qq_unionid: 'qq-account', + 'qq_openid.app': 'qq-account', + 'qq_openid.mp': 'qq-account', + ali_openid: 'alipay-account', + apple_openid: 'alipay-account', + identities: 'idp' +} + +const USER_STATUS = { + NORMAL: 0, + BANNED: 1, + AUDITING: 2, + AUDIT_FAILED: 3, + CLOSED: 4 +} + +const CAPTCHA_SCENE = { + REGISTER: 'register', + LOGIN_BY_PWD: 'login-by-pwd', + LOGIN_BY_SMS: 'login-by-sms', + RESET_PWD_BY_SMS: 'reset-pwd-by-sms', + RESET_PWD_BY_EMAIL: 'reset-pwd-by-email', + SEND_SMS_CODE: 'send-sms-code', + SEND_EMAIL_CODE: 'send-email-code', + BIND_MOBILE_BY_SMS: 'bind-mobile-by-sms', + SET_PWD_BY_SMS: 'set-pwd-by-sms' +} + +const LOG_TYPE = { + LOGOUT: 'logout', + LOGIN: 'login', + REGISTER: 'register', + RESET_PWD_BY_SMS: 'reset-pwd', + RESET_PWD_BY_EMAIL: 'reset-pwd', + BIND_MOBILE: 'bind-mobile', + BIND_WEIXIN: 'bind-weixin', + BIND_QQ: 'bind-qq', + BIND_APPLE: 'bind-apple', + BIND_ALIPAY: 'bind-alipay', + UNBIND_WEIXIN: 'unbind-weixin', + UNBIND_QQ: 'unbind-qq', + UNBIND_ALIPAY: 'unbind-alipay', + UNBIND_APPLE: 'unbind-apple' +} + +const SMS_SCENE = { + LOGIN_BY_SMS: 'login-by-sms', + RESET_PWD_BY_SMS: 'reset-pwd-by-sms', + BIND_MOBILE_BY_SMS: 'bind-mobile-by-sms', + SET_PWD_BY_SMS: 'set-pwd-by-sms' +} + +const EMAIL_SCENE = { + REGISTER: 'register', + LOGIN_BY_EMAIL: 'login-by-email', + RESET_PWD_BY_EMAIL: 'reset-pwd-by-email', + BIND_EMAIL: 'bind-email' +} + +const REAL_NAME_STATUS = { + NOT_CERTIFIED: 0, + WAITING_CERTIFIED: 1, + CERTIFIED: 2, + CERTIFY_FAILED: 3 +} + +const EXTERNAL_DIRECT_CONNECT_PROVIDER = 'externalDirectConnect' + +module.exports = { + db, + dbCmd, + userCollection, + verifyCollection, + deviceCollection, + openDataCollection, + frvLogsCollection, + USER_IDENTIFIER, + USER_STATUS, + CAPTCHA_SCENE, + LOG_TYPE, + SMS_SCENE, + EMAIL_SCENE, + REAL_NAME_STATUS, + EXTERNAL_DIRECT_CONNECT_PROVIDER +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/error.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/error.js new file mode 100644 index 0000000..1e33845 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/error.js @@ -0,0 +1,70 @@ +const ERROR = { + ACCOUNT_EXISTS: 'uni-id-account-exists', + ACCOUNT_NOT_EXISTS: 'uni-id-account-not-exists', + ACCOUNT_NOT_EXISTS_IN_CURRENT_APP: 'uni-id-account-not-exists-in-current-app', + ACCOUNT_CONFLICT: 'uni-id-account-conflict', + ACCOUNT_BANNED: 'uni-id-account-banned', + ACCOUNT_AUDITING: 'uni-id-account-auditing', + ACCOUNT_AUDIT_FAILED: 'uni-id-account-audit-failed', + ACCOUNT_CLOSED: 'uni-id-account-closed', + CAPTCHA_REQUIRED: 'uni-id-captcha-required', + PASSWORD_ERROR: 'uni-id-password-error', + PASSWORD_ERROR_EXCEED_LIMIT: 'uni-id-password-error-exceed-limit', + INVALID_USERNAME: 'uni-id-invalid-username', + INVALID_PASSWORD: 'uni-id-invalid-password', + INVALID_PASSWORD_SUPER: 'uni-id-invalid-password-super', + INVALID_PASSWORD_STRONG: 'uni-id-invalid-password-strong', + INVALID_PASSWORD_MEDIUM: 'uni-id-invalid-password-medium', + INVALID_PASSWORD_WEAK: 'uni-id-invalid-password-weak', + INVALID_MOBILE: 'uni-id-invalid-mobile', + INVALID_EMAIL: 'uni-id-invalid-email', + INVALID_NICKNAME: 'uni-id-invalid-nickname', + INVALID_PARAM: 'uni-id-invalid-param', + PARAM_REQUIRED: 'uni-id-param-required', + GET_THIRD_PARTY_ACCOUNT_FAILED: 'uni-id-get-third-party-account-failed', + GET_THIRD_PARTY_USER_INFO_FAILED: 'uni-id-get-third-party-user-info-failed', + MOBILE_VERIFY_CODE_ERROR: 'uni-id-mobile-verify-code-error', + EMAIL_VERIFY_CODE_ERROR: 'uni-id-email-verify-code-error', + ADMIN_EXISTS: 'uni-id-admin-exists', + PERMISSION_ERROR: 'uni-id-permission-error', + SYSTEM_ERROR: 'uni-id-system-error', + SET_INVITE_CODE_FAILED: 'uni-id-set-invite-code-failed', + INVALID_INVITE_CODE: 'uni-id-invalid-invite-code', + CHANGE_INVITER_FORBIDDEN: 'uni-id-change-inviter-forbidden', + BIND_CONFLICT: 'uni-id-bind-conflict', + UNBIND_FAIL: 'uni-id-unbind-failed', + UNBIND_NOT_SUPPORTED: 'uni-id-unbind-not-supported', + UNBIND_UNIQUE_LOGIN: 'uni-id-unbind-unique-login', + UNBIND_PASSWORD_NOT_EXISTS: 'uni-id-unbind-password-not-exists', + UNBIND_MOBILE_NOT_EXISTS: 'uni-id-unbind-mobile-not-exists', + UNSUPPORTED_REQUEST: 'uni-id-unsupported-request', + ILLEGAL_REQUEST: 'uni-id-illegal-request', + CONFIG_FIELD_REQUIRED: 'uni-id-config-field-required', + CONFIG_FIELD_INVALID: 'uni-id-config-field-invalid', + FRV_FAIL: 'uni-id-frv-fail', + FRV_PROCESSING: 'uni-id-frv-processing', + REAL_NAME_VERIFIED: 'uni-id-realname-verified', + ID_CARD_EXISTS: 'uni-id-idcard-exists', + INVALID_ID_CARD: 'uni-id-invalid-idcard', + INVALID_REAL_NAME: 'uni-id-invalid-realname', + UNKNOWN_ERROR: 'uni-id-unknown-error', + REAL_NAME_VERIFY_UPPER_LIMIT: 'uni-id-realname-verify-upper-limit' +} + +function isUniIdError (errCode) { + return Object.values(ERROR).includes(errCode) +} + +class UniCloudError extends Error { + constructor (options) { + super(options.message) + this.errMsg = options.message || '' + this.errCode = options.code + } +} + +module.exports = { + ERROR, + isUniIdError, + UniCloudError +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/sensitive-aes-cipher.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/sensitive-aes-cipher.js new file mode 100644 index 0000000..b2d6d95 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/sensitive-aes-cipher.js @@ -0,0 +1,64 @@ +const crypto = require('crypto') +const { ERROR } = require('./error') + +function checkSecret (secret) { + if (!secret) { + throw { + errCode: ERROR.CONFIG_FIELD_REQUIRED, + errMsgValue: { + field: 'sensitiveInfoEncryptSecret' + } + } + } + + if (secret.length !== 32) { + throw { + errCode: ERROR.CONFIG_FIELD_INVALID, + errMsgValue: { + field: 'sensitiveInfoEncryptSecret' + } + } + } +} +function encryptData (text = '') { + if (!text) return text + + const encryptSecret = this.config.sensitiveInfoEncryptSecret + + checkSecret(encryptSecret) + + const iv = encryptSecret.slice(-16) + + const cipher = crypto.createCipheriv('aes-256-cbc', encryptSecret, iv) + + const encrypted = Buffer.concat([ + cipher.update(Buffer.from(text, 'utf-8')), + cipher.final() + ]) + + return encrypted.toString('base64') +} + +function decryptData (text = '') { + if (!text) return text + + const encryptSecret = this.config.sensitiveInfoEncryptSecret + + checkSecret(encryptSecret) + + const iv = encryptSecret.slice(-16) + + const cipher = crypto.createDecipheriv('aes-256-cbc', encryptSecret, iv) + + const decrypted = Buffer.concat([ + cipher.update(Buffer.from(text, 'base64')), + cipher.final() + ]) + + return decrypted.toString('utf-8') +} + +module.exports = { + encryptData, + decryptData +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/universal.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/universal.js new file mode 100644 index 0000000..4bf46a0 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/universal.js @@ -0,0 +1,47 @@ +const { ERROR } = require('./error') + +function getHttpClientInfo () { + const requestId = this.getUniCloudRequestId() + const { clientIP, userAgent, source, secretType = 'none' } = this.getClientInfo() + const { clientInfo = {} } = JSON.parse(this.getHttpInfo().body) + + return { + ...clientInfo, + clientIP, + userAgent, + source, + secretType, + requestId + } +} + +function getHttpUniIdToken () { + const { uniIdToken = '' } = JSON.parse(this.getHttpInfo().body) + + return uniIdToken +} + +function verifyHttpMethod () { + const { headers, httpMethod } = this.getHttpInfo() + + if (!/^application\/json/.test(headers['content-type']) || httpMethod.toUpperCase() !== 'POST') { + throw { + errCode: ERROR.UNSUPPORTED_REQUEST, + errMsg: 'unsupported request' + } + } +} + +function universal () { + if (this.getClientInfo().source === 'http') { + verifyHttpMethod.call(this) + this.getParams()[0] = JSON.parse(this.getHttpInfo().body).params + this.getUniversalClientInfo = getHttpClientInfo.bind(this) + this.getUniversalUniIdToken = getHttpUniIdToken.bind(this) + } else { + this.getUniversalClientInfo = this.getClientInfo + this.getUniversalUniIdToken = this.getUniIdToken + } +} + +module.exports = universal diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/utils.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/utils.js new file mode 100644 index 0000000..11dc6e7 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/utils.js @@ -0,0 +1,270 @@ +function batchFindObjctValue (obj = {}, keys = []) { + const values = {} + for (let i = 0; i < keys.length; i++) { + const key = keys[i] + const keyPath = key.split('.') + let currentKey = keyPath.shift() + let result = obj + while (currentKey) { + if (!result) { + break + } + result = result[currentKey] + currentKey = keyPath.shift() + } + values[key] = result + } + return values +} + +function getType (val) { + return Object.prototype.toString.call(val).slice(8, -1).toLowerCase() +} + +function hasOwn (obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key) +} + +function isValidString (val) { + return val && getType(val) === 'string' +} + +function isPlainObject (obj) { + return getType(obj) === 'object' +} + +function isFn (fn) { + // 务必注意AsyncFunction + return typeof fn === 'function' +} + +// 获取文件后缀,只添加几种图片类型供客服消息接口使用 +const mime2ext = { + 'image/png': 'png', + 'image/jpeg': 'jpg', + 'image/gif': 'gif', + 'image/svg+xml': 'svg', + 'image/bmp': 'bmp', + 'image/webp': 'webp' +} + +function getExtension (contentType) { + return mime2ext[contentType] +} + +const isSnakeCase = /_(\w)/g +const isCamelCase = /[A-Z]/g + +function snake2camel (value) { + return value.replace(isSnakeCase, (_, c) => (c ? c.toUpperCase() : '')) +} + +function camel2snake (value) { + return value.replace(isCamelCase, str => '_' + str.toLowerCase()) +} + +function parseObjectKeys (obj, type) { + let parserReg, parser + switch (type) { + case 'snake2camel': + parser = snake2camel + parserReg = isSnakeCase + break + case 'camel2snake': + parser = camel2snake + parserReg = isCamelCase + break + } + for (const key in obj) { + if (hasOwn(obj, key)) { + if (parserReg.test(key)) { + const keyCopy = parser(key) + obj[keyCopy] = obj[key] + delete obj[key] + if (isPlainObject(obj[keyCopy])) { + obj[keyCopy] = parseObjectKeys(obj[keyCopy], type) + } else if (Array.isArray(obj[keyCopy])) { + obj[keyCopy] = obj[keyCopy].map((item) => { + return parseObjectKeys(item, type) + }) + } + } + } + } + return obj +} + +function snake2camelJson (obj) { + return parseObjectKeys(obj, 'snake2camel') +} + +function camel2snakeJson (obj) { + return parseObjectKeys(obj, 'camel2snake') +} + +function getOffsetDate (offset) { + return new Date( + Date.now() + (new Date().getTimezoneOffset() + (offset || 0) * 60) * 60000 + ) +} + +function getDateStr (date, separator = '-') { + date = date || new Date() + const dateArr = [] + dateArr.push(date.getFullYear()) + dateArr.push(('00' + (date.getMonth() + 1)).substr(-2)) + dateArr.push(('00' + date.getDate()).substr(-2)) + return dateArr.join(separator) +} + +function getTimeStr (date, separator = ':') { + date = date || new Date() + const timeArr = [] + timeArr.push(('00' + date.getHours()).substr(-2)) + timeArr.push(('00' + date.getMinutes()).substr(-2)) + timeArr.push(('00' + date.getSeconds()).substr(-2)) + return timeArr.join(separator) +} + +function getFullTimeStr (date) { + date = date || new Date() + return getDateStr(date) + ' ' + getTimeStr(date) +} + +function getDistinctArray (arr) { + return Array.from(new Set(arr)) +} + +/** + * 拼接url + * @param {string} base 基础路径 + * @param {string} path 在基础路径上拼接的路径 + * @returns + */ +function resolveUrl (base, path) { + if (/^https?:/.test(path)) { + return path + } + return base + path +} + +function getVerifyCode (len = 6) { + let code = '' + for (let i = 0; i < len; i++) { + code += Math.floor(Math.random() * 10) + } + return code +} + +function coverMobile (mobile) { + if (typeof mobile !== 'string') { + return mobile + } + return mobile.slice(0, 3) + '****' + mobile.slice(7) +} + +function getNonceStr (length = 16) { + let str = '' + while (str.length < length) { + str += Math.random().toString(32).substring(2) + } + return str.substring(0, length) +} + +try { + require('lodash.merge') +} catch (error) { + console.error('uni-id-co缺少依赖,请在uniCloud/cloudfunctions/uni-id-co目录执行 npm install 安装依赖') + throw error +} + +function isMatchUserApp (userAppList, matchAppList) { + if (userAppList === undefined || userAppList === null) { + return true + } + if (getType(userAppList) !== 'array') { + return false + } + if (userAppList.includes('*')) { + return true + } + if (getType(matchAppList) === 'string') { + matchAppList = [matchAppList] + } + return userAppList.some(item => matchAppList.includes(item)) +} + +function checkIdCard (idCardNumber) { + if (!idCardNumber || typeof idCardNumber !== 'string' || idCardNumber.length !== 18) return false + + const coefficient = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] + const checkCode = [1, 0, 'x', 9, 8, 7, 6, 5, 4, 3, 2] + const code = idCardNumber.substring(17) + + let sum = 0 + for (let i = 0; i < 17; i++) { + sum += Number(idCardNumber.charAt(i)) * coefficient[i] + } + + return checkCode[sum % 11].toString() === code.toLowerCase() +} + +function catchAwait (fn, finallyFn) { + if (!fn) return [new Error('no function')] + + if (Promise.prototype.finally === undefined) { + // eslint-disable-next-line no-extend-native + Promise.prototype.finally = function (finallyFn) { + return this.then( + res => Promise.resolve(finallyFn()).then(() => res), + error => Promise.resolve(finallyFn()).then(() => { throw error }) + ) + } + } + + return fn + .then((data) => [undefined, data]) + .catch((error) => [error]) + .finally(() => typeof finallyFn === 'function' && finallyFn()) +} + +function dataDesensitization (value = '', options = {}) { + const { onlyLast = false } = options + const [firstIndex, middleIndex, lastIndex] = onlyLast ? [0, 0, -1] : [0, 1, -1] + + if (!value) return value + const first = value.slice(firstIndex, middleIndex) + const middle = value.slice(middleIndex, lastIndex) + const last = value.slice(lastIndex) + const star = Array.from(new Array(middle.length), (v) => '*').join('') + + return first + star + last +} + +function getCurrentDateTimestamp (date = Date.now(), targetTimezone = 8) { + const oneHour = 60 * 60 * 1000 + return parseInt((date + targetTimezone * oneHour) / (24 * oneHour)) * (24 * oneHour) - targetTimezone * oneHour +} + +module.exports = { + getType, + isValidString, + batchFindObjctValue, + isPlainObject, + isFn, + getDistinctArray, + getFullTimeStr, + resolveUrl, + getOffsetDate, + camel2snakeJson, + snake2camelJson, + getExtension, + getVerifyCode, + coverMobile, + getNonceStr, + isMatchUserApp, + checkIdCard, + catchAwait, + dataDesensitization, + getCurrentDateTimestamp +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/validator.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/validator.js new file mode 100644 index 0000000..4b02104 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/validator.js @@ -0,0 +1,443 @@ +const { + isValidString, + getType +} = require('./utils.js') +const { + ERROR +} = require('./error') + +const baseValidator = Object.create(null) + +baseValidator.username = function (username) { + const errCode = ERROR.INVALID_USERNAME + if (!isValidString(username)) { + return { + errCode + } + } + if (/^\d+$/.test(username)) { + // 用户名不能为纯数字 + return { + errCode + } + }; + if (!/^[a-zA-Z0-9_-]+$/.test(username)) { + // 用户名仅能使用数字、字母、“_”及“-” + return { + errCode + } + } +} + +baseValidator.password = function (password) { + const errCode = ERROR.INVALID_PASSWORD + if (!isValidString(password)) { + return { + errCode + } + } + if (password.length < 6) { + // 密码长度不能小于6 + return { + errCode + } + } +} + +baseValidator.mobile = function (mobile) { + const errCode = ERROR.INVALID_MOBILE + if (getType(mobile) !== 'string') { + return { + errCode + } + } + if (mobile && !/^1\d{10}$/.test(mobile)) { + return { + errCode + } + } +} + +baseValidator.email = function (email) { + const errCode = ERROR.INVALID_EMAIL + if (getType(email) !== 'string') { + return { + errCode + } + } + if (email && !/@/.test(email)) { + return { + errCode + } + } +} + +baseValidator.nickname = function (nickname) { + const errCode = ERROR.INVALID_NICKNAME + if (nickname.indexOf('@') !== -1) { + // 昵称不允许含@ + return { + errCode + } + }; + if (/^\d+$/.test(nickname)) { + // 昵称不能为纯数字 + return { + errCode + } + }; + if (nickname.length > 100) { + // 昵称不可超过100字符 + return { + errCode + } + } +} + +const baseType = ['string', 'boolean', 'number', 'null'] // undefined不会由客户端提交上来 + +baseType.forEach((type) => { + baseValidator[type] = function (val) { + if (getType(val) === type) { + return + } + return { + errCode: ERROR.INVALID_PARAM + } + } +}) + +function tokenize(name) { + let i = 0 + const result = [] + let token = '' + while (i < name.length) { + const char = name[i] + switch (char) { + case '|': + case '<': + case '>': + token && result.push(token) + result.push(char) + token = '' + break + default: + token += char + break + } + i++ + if (i === name.length && token) { + result.push(token) + } + } + return result +} + +/** + * 处理validator名 + * @param {string} name + */ +function parseValidatorName(name) { + const tokenList = tokenize(name) + let i = 0 + let currentToken = tokenList[i] + const result = { + type: 'root', + children: [], + parent: null + } + let lastRealm = result + while (currentToken) { + switch (currentToken) { + case 'array': { + const currentRealm = { + type: 'array', + children: [], + parent: lastRealm + } + lastRealm.children.push(currentRealm) + lastRealm = currentRealm + break + } + case '<': + if (lastRealm.type !== 'array') { + throw new Error('Invalid validator token "<"') + } + break + case '>': + if (lastRealm.type !== 'array') { + throw new Error('Invalid validator token ">"') + } + lastRealm = lastRealm.parent + break + case '|': + if (lastRealm.type !== 'array' && lastRealm.type !== 'root') { + throw new Error('Invalid validator token "|"') + } + break + default: + lastRealm.children.push({ + type: currentToken + }) + break + } + i++ + currentToken = tokenList[i] + } + return result +} + +function getRuleCategory(rule) { + switch (rule.type) { + case 'array': + return 'array' + case 'root': + return 'root' + default: + return 'base' + } +} + + +// 特殊符号 https://www.ibm.com/support/pages/password-strength-rules ~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/ +// const specialChar = '~!@#$%^&*_-+=`|\(){}[]:;"\'<>,.?/' +// const specialCharRegExp = /^[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]$/ +// for (let i = 0, arr = specialChar.split(''); i < arr.length; i++) { +// const char = arr[i] +// if (!specialCharRegExp.test(char)) { +// throw new Error('check special character error: ' + char) +// } +// } + +// 密码强度表达式 +const passwordRules = { + // 密码必须包含大小写字母、数字和特殊符号 + super: /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/, + // 密码必须包含字母、数字和特殊符号 + strong: /^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/, + // 密码必须为字母、数字和特殊符号任意两种的组合 + medium: /^(?![0-9]+$)(?![a-zA-Z]+$)(?![~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]+$)[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/, + // 密码必须包含字母和数字 + weak: /^(?=.*[0-9])(?=.*[a-zA-Z])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{6,16}$/, + +} + +function createPasswordVerifier({ + passwordStrength = '' +} = {}) { + return function (password) { + const passwordRegExp = passwordRules[passwordStrength] + if (!passwordRegExp) { + throw new Error('Invalid password strength config: ' + passwordStrength) + } + const errCode = ERROR.INVALID_PASSWORD + if (!isValidString(password)) { + return { + errCode + } + } + if (!passwordRegExp.test(password)) { + return { + errCode: errCode + '-' + passwordStrength + } + } + } +} + +function isEmpty(value) { + return value === undefined || + value === null || + (typeof value === 'string' && value.trim() === '') +} + +class Validator { + constructor({ + passwordStrength = '' + } = {}) { + this.baseValidator = baseValidator + this.customValidator = Object.create(null) + if (passwordStrength) { + this.mixin( + 'password', + createPasswordVerifier({ + passwordStrength + }) + ) + } + } + + mixin(type, handler) { + this.customValidator[type] = handler + } + + getRealBaseValidator(type) { + return this.customValidator[type] || this.baseValidator[type] + } + + + _isMatchUnionType(val, rule) { + if (!rule.children || rule.children.length === 0) { + return true + } + const children = rule.children + for (let i = 0; i < children.length; i++) { + const child = children[i] + const category = getRuleCategory(child) + let pass = false + switch (category) { + case 'base': + pass = this._isMatchBaseType(val, child) + break + case 'array': + pass = this._isMatchArrayType(val, child) + break + default: + break + } + if (pass) { + return true + } + } + return false + } + + _isMatchBaseType(val, rule) { + const method = this.getRealBaseValidator(rule.type) + if (typeof method !== 'function') { + throw new Error(`invalid schema type: ${rule.type}`) + } + const validateRes = method(val) + if (validateRes && validateRes.errCode) { + return false + } + return true + } + + _isMatchArrayType(arr, rule) { + if (getType(arr) !== 'array') { + return false + } + if (rule.children && rule.children.length && arr.some(item => !this._isMatchUnionType(item, rule))) { + return false + } + return true + } + + get validator() { + const _this = this + return new Proxy({}, { + get: (_, prop) => { + if (typeof prop !== 'string') { + return + } + const realBaseValidator = this.getRealBaseValidator(prop) + if (realBaseValidator) { + return realBaseValidator + } + const rule = parseValidatorName(prop) + return function (val) { + if (!_this._isMatchUnionType(val, rule)) { + return { + errCode: ERROR.INVALID_PARAM + } + } + } + } + }) + } + + validate(value = {}, schema = {}) { + for (const schemaKey in schema) { + let schemaValue = schema[schemaKey] + if (getType(schemaValue) === 'string') { + schemaValue = { + required: true, + type: schemaValue + } + } + const { + required, + type + } = schemaValue + // value内未传入了schemaKey或对应值为undefined + if (isEmpty(value[schemaKey])) { + if (required) { + return { + errCode: ERROR.PARAM_REQUIRED, + errMsgValue: { + param: schemaKey + }, + schemaKey + } + } else { + //delete value[schemaKey] + continue + } + } + const validateMethod = this.validator[type] + if (!validateMethod) { + throw new Error(`invalid schema type: ${type}`) + } + const validateRes = validateMethod(value[schemaKey]) + if (validateRes) { + validateRes.schemaKey = schemaKey + return validateRes + } + } + } +} + +function checkClientInfo(clientInfo) { + const stringNotRequired = { + required: false, + type: 'string' + } + const numberNotRequired = { + required: false, + type: 'number' + } + const numberOrStringNotRequired = { + required: false, + type: 'number|string' + } + const schema = { + uniPlatform: 'string', + appId: 'string', + deviceId: stringNotRequired, + osName: stringNotRequired, + locale: stringNotRequired, + clientIP: stringNotRequired, + appName: stringNotRequired, + appVersion: stringNotRequired, + appVersionCode: numberOrStringNotRequired, + channel: numberOrStringNotRequired, + userAgent: stringNotRequired, + uniIdToken: stringNotRequired, + deviceBrand: stringNotRequired, + deviceModel: stringNotRequired, + osVersion: stringNotRequired, + osLanguage: stringNotRequired, + osTheme: stringNotRequired, + romName: stringNotRequired, + romVersion: stringNotRequired, + devicePixelRatio: numberNotRequired, + windowWidth: numberNotRequired, + windowHeight: numberNotRequired, + screenWidth: numberNotRequired, + screenHeight: numberNotRequired + } + const validateRes = new Validator().validate(clientInfo, schema) + if (validateRes) { + if (validateRes.errCode === ERROR.PARAM_REQUIRED) { + console.warn('- 如果使用HBuilderX运行本地云函数/云对象功能时出现此提示,请改为使用客户端调用本地云函数方式调试,或更新HBuilderX到3.4.12及以上版本。\n- 如果是缺少clientInfo.appId,请检查项目manifest.json内是否配置了DCloud AppId') + throw new Error(`"clientInfo.${validateRes.schemaKey}" is required.`) + } else { + throw new Error(`Invalid client info: clienInfo.${validateRes.schemaKey}`) + } + } +} + +module.exports = { + Validator, + checkClientInfo +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/config/permission.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/config/permission.js new file mode 100644 index 0000000..229a264 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/config/permission.js @@ -0,0 +1,90 @@ +// 各接口权限配置,未配置接口表示允许任何用户访问(包括未登录用户) +module.exports = { + // 管理接口 + addUser: { + // auth: true // 已登录用户方可操作,配置角色或权限时此项可不写 + role: ['admin'] // 允许进行此操作的角色,包含任一角色均可操作。 + // permission: [] // 允许进行此操作的权限,包含任一权限均可操作。 + // 权限角色均配置时,用户拥有任一权限或任一角色均可操作 + }, + updateUser: { + role: ['admin'] + }, + authorizeAppLogin: { + role: ['admin'] + }, + removeAuthorizedApp: { + role: ['admin'] + }, + setAuthorizedApp: { + role: ['admin'] + }, + + // 用户接口 + closeAccount: { + auth: true + }, + updatePwd: { + auth: true + }, + logout: { + auth: true + }, + bindMobileBySms: { + auth: true + }, + bindMobileByUniverify: { + auth: true + }, + bindMobileByMpWeixin: { + auth: true + }, + bindAlipay: { + auth: true + }, + bindApple: { + auth: true + }, + bindQQ: { + auth: true + }, + bindWeixin: { + auth: true + }, + acceptInvite: { + auth: true + }, + getInvitedUser: { + auth: true + }, + setPushCid: { + auth: true + }, + getAccountInfo: { + auth: true + }, + unbindWeixin: { + auth: true + }, + unbindAlipay: { + auth: true + }, + unbindQQ: { + auth: true + }, + unbindApple: { + auth: true + }, + setPwd: { + auth: true + }, + getFrvCertifyId: { + auth: true + }, + getFrvAuthResult: { + auth: true + }, + getRealNameInfo: { + auth: true + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/index.obj.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/index.obj.js new file mode 100644 index 0000000..348d416 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/index.obj.js @@ -0,0 +1,694 @@ +const uniIdCommon = require('uni-id-common') +const uniCaptcha = require('uni-captcha') +const { + getType, + checkIdCard +} = require('./common/utils') +const { + checkClientInfo, + Validator +} = require('./common/validator') +const ConfigUtils = require('./lib/utils/config') +const { + isUniIdError, + ERROR +} = require('./common/error') +const middleware = require('./middleware/index') +const universal = require('./common/universal') + +const { + registerAdmin, + registerUser, + registerUserByEmail +} = require('./module/register/index') +const { + addUser, + updateUser +} = require('./module/admin/index') +const { + login, + loginBySms, + loginByUniverify, + loginByWeixin, + loginByAlipay, + loginByQQ, + loginByApple, + loginByWeixinMobile +} = require('./module/login/index') +const { + logout +} = require('./module/logout/index') +const { + bindMobileBySms, + bindMobileByUniverify, + bindMobileByMpWeixin, + bindAlipay, + bindApple, + bindQQ, + bindWeixin, + unbindWeixin, + unbindAlipay, + unbindQQ, + unbindApple +} = require('./module/relate/index') +const { + setPwd, + updatePwd, + resetPwdBySms, + resetPwdByEmail, + closeAccount, + getAccountInfo, + getRealNameInfo +} = require('./module/account/index') +const { + createCaptcha, + refreshCaptcha, + sendSmsCode, + sendEmailCode +} = require('./module/verify/index') +const { + refreshToken, + setPushCid, + secureNetworkHandshakeByWeixin +} = require('./module/utils/index') +const { + getInvitedUser, + acceptInvite +} = require('./module/fission') +const { + authorizeAppLogin, + removeAuthorizedApp, + setAuthorizedApp +} = require('./module/multi-end') +const { + getSupportedLoginType +} = require('./module/dev/index') +const { + externalRegister, + externalLogin, + updateUserInfoByExternal +} = require('./module/external') +const { + getFrvCertifyId, + getFrvAuthResult +} = require('./module/facial-recognition-verify') + +module.exports = { + async _before () { + // 支持 callFunction 与 URL化 + universal.call(this) + + const clientInfo = this.getUniversalClientInfo() + /** + * 检查clientInfo,无appId和uniPlatform时本云对象无法正常运行 + * 此外需要保证用到的clientInfo字段均经过类型检查 + * clientInfo由客户端上传并非完全可信,clientInfo内除clientIP、userAgent、source外均为客户端上传参数 + * 否则可能会出现一些意料外的情况 + */ + checkClientInfo(clientInfo) + let clientPlatform = clientInfo.uniPlatform + // 统一platform名称 + switch (clientPlatform) { + case 'app': + case 'app-plus': + clientPlatform = 'app' + break + case 'web': + case 'h5': + clientPlatform = 'web' + break + default: + break + } + + this.clientPlatform = clientPlatform + + // 挂载uni-id实例到this上,方便后续调用 + this.uniIdCommon = uniIdCommon.createInstance({ + clientInfo + }) + + // 包含uni-id配置合并等功能的工具集 + this.configUtils = new ConfigUtils({ + context: this + }) + this.config = this.configUtils.getPlatformConfig() + this.hooks = this.configUtils.getHooks() + + this.validator = new Validator({ + passwordStrength: this.config.passwordStrength + }) + + // 扩展 validator 增加 验证身份证号码合法性 + this.validator.mixin('idCard', function (idCard) { + if (!checkIdCard(idCard)) { + return { + errCode: ERROR.INVALID_ID_CARD + } + } + }) + this.validator.mixin('realName', function (realName) { + if ( + typeof realName !== 'string' || + realName.length < 2 || + !/^[\u4e00-\u9fa5]{1,10}(·?[\u4e00-\u9fa5]{1,10}){0,5}$/.test(realName) + ) { + return { + errCode: ERROR.INVALID_REAL_NAME + } + } + }) + /** + * 示例:覆盖密码验证规则 + */ + // this.validator.mixin('password', function (password) { + // if (typeof password !== 'string' || password.length < 10) { + // // 调整为密码长度不能小于10 + // return { + // errCode: ERROR.INVALID_PASSWORD + // } + // } + // }) + /** + * 示例:新增验证规则 + */ + // this.validator.mixin('timestamp', function (timestamp) { + // if (typeof timestamp !== 'number' || timestamp > Date.now()) { + // return { + // errCode: ERROR.INVALID_PARAM + // } + // } + // }) + // // 新增规则同样可以在数组验证规则中使用 + // this.validator.validate({ + // timestamp: 123456789 + // }, { + // timestamp: 'timestamp' + // }) + // this.validator.validate({ + // timestampList: [123456789, 123123123123] + // }, { + // timestampList: 'array' + // }) + // // 甚至更复杂的写法 + // this.validator.validate({ + // timestamp: [123456789123123123, 123123123123] + // }, { + // timestamp: 'timestamp|array' + // }) + + // 挂载uni-captcha到this上,方便后续调用 + this.uniCaptcha = uniCaptcha + Object.defineProperty(this, 'uniOpenBridge', { + get () { + return require('uni-open-bridge-common') + } + }) + + // 挂载中间件 + this.middleware = {} + for (const mwName in middleware) { + this.middleware[mwName] = middleware[mwName].bind(this) + } + + // 国际化 + const messages = require('./lang/index') + const fallbackLocale = 'zh-Hans' + const i18n = uniCloud.initI18n({ + locale: clientInfo.locale, + fallbackLocale, + messages: JSON.parse(JSON.stringify(messages)) + }) + if (!messages[i18n.locale]) { + i18n.setLocale(fallbackLocale) + } + this.t = i18n.t.bind(i18n) + + this.response = {} + + // 请求鉴权验证 + await this.middleware.verifyRequestSign() + + // 通用权限校验模块 + await this.middleware.accessControl() + }, + _after (error, result) { + if (error) { + // 处理中间件内抛出的标准响应对象 + if (error.errCode && getType(error) === 'object') { + const errCode = error.errCode + if (!isUniIdError(errCode)) { + return error + } + return { + errCode, + errMsg: error.errMsg || this.t(errCode, error.errMsgValue) + } + } + throw error + } + return Object.assign(this.response, result) + }, + /** + * 注册管理员 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#register-admin + * @param {Object} params + * @param {String} params.username 用户名 + * @param {String} params.password 密码 + * @param {String} params.nickname 昵称 + * @returns + */ + registerAdmin, + /** + * 新增用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#add-user + * @param {Object} params + * @param {String} params.username 用户名 + * @param {String} params.password 密码 + * @param {String} params.nickname 昵称 + * @param {Array} params.authorizedApp 允许登录的AppID列表 + * @param {Array} params.role 用户角色列表 + * @param {String} params.mobile 手机号 + * @param {String} params.email 邮箱 + * @param {Array} params.tags 用户标签 + * @param {Number} params.status 用户状态 + * @returns + */ + addUser, + /** + * 修改用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#update-user + * @param {Object} params + * @param {String} params.id 要更新的用户id + * @param {String} params.username 用户名 + * @param {String} params.password 密码 + * @param {String} params.nickname 昵称 + * @param {Array} params.authorizedApp 允许登录的AppID列表 + * @param {Array} params.role 用户角色列表 + * @param {String} params.mobile 手机号 + * @param {String} params.email 邮箱 + * @param {Array} params.tags 用户标签 + * @param {Number} params.status 用户状态 + * @returns + */ + updateUser, + /** + * 授权用户登录应用 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#authorize-app-login + * @param {Object} params + * @param {String} params.uid 用户id + * @param {String} params.appId 授权的应用的AppId + * @returns + */ + authorizeAppLogin, + /** + * 移除用户登录授权 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#remove-authorized-app + * @param {Object} params + * @param {String} params.uid 用户id + * @param {String} params.appId 取消授权的应用的AppId + * @returns + */ + removeAuthorizedApp, + /** + * 设置用户允许登录的应用列表 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-authorized-app + * @param {Object} params + * @param {String} params.uid 用户id + * @param {Array} params.appIdList 允许登录的应用AppId列表 + * @returns + */ + setAuthorizedApp, + /** + * 注册普通用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#register-user + * @param {Object} params + * @param {String} params.username 用户名 + * @param {String} params.password 密码 + * @param {String} params.captcha 图形验证码 + * @param {String} params.nickname 昵称 + * @param {String} params.inviteCode 邀请码 + * @returns + */ + registerUser, + /** + * 通过邮箱+验证码注册用户 + * @param {Object} params + * @param {String} params.email 邮箱 + * @param {String} params.password 密码 + * @param {String} params.nickname 昵称 + * @param {String} params.code 邮箱验证码 + * @param {String} params.inviteCode 邀请码 + * @returns + */ + registerUserByEmail, + /** + * 用户名密码登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login + * @param {Object} params + * @param {String} params.username 用户名 + * @param {String} params.mobile 手机号 + * @param {String} params.email 邮箱 + * @param {String} params.password 密码 + * @param {String} params.captcha 图形验证码 + * @returns + */ + login, + /** + * 短信验证码登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-sms + * @param {Object} params + * @param {String} params.mobile 手机号 + * @param {String} params.code 短信验证码 + * @param {String} params.captcha 图形验证码 + * @param {String} params.inviteCode 邀请码 + * @returns + */ + loginBySms, + /** + * App端一键登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-univerify + * @param {Object} params + * @param {String} params.access_token APP端一键登录返回的access_token + * @param {String} params.openid APP端一键登录返回的openid + * @param {String} params.inviteCode 邀请码 + * @returns + */ + loginByUniverify, + /** + * 微信登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-weixin + * @param {Object} params + * @param {String} params.code 微信登录返回的code + * @param {String} params.inviteCode 邀请码 + * @returns + */ + loginByWeixin, + /** + * 支付宝登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-alipay + * @param {Object} params + * @param {String} params.code 支付宝小程序客户端登录返回的code + * @param {String} params.inviteCode 邀请码 + * @returns + */ + loginByAlipay, + /** + * QQ登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-qq + * @param {Object} params + * @param {String} params.code QQ小程序登录返回的code参数 + * @param {String} params.accessToken App端QQ登录返回的accessToken参数 + * @param {String} params.accessTokenExpired accessToken过期时间,由App端QQ登录返回的expires_in参数计算而来,单位:毫秒 + * @param {String} params.inviteCode 邀请码 + * @returns + */ + loginByQQ, + /** + * 苹果登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-apple + * @param {Object} params + * @param {String} params.identityToken 苹果登录返回的identityToken + * @param {String} params.nickname 用户昵称 + * @param {String} params.inviteCode 邀请码 + * @returns + */ + loginByApple, + loginByWeixinMobile, + /** + * 用户退出登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#logout + * @returns + */ + logout, + /** + * 通过短信验证码绑定手机号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-sms + * @param {Object} params + * @param {String} params.mobile 手机号 + * @param {String} params.code 短信验证码 + * @param {String} params.captcha 图形验证码 + * @returns + */ + bindMobileBySms, + /** + * 通过一键登录绑定手机号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-univerify + * @param {Object} params + * @param {String} params.openid APP端一键登录返回的openid + * @param {String} params.access_token APP端一键登录返回的access_token + * @returns + */ + bindMobileByUniverify, + /** + * 通过微信绑定手机号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-mp-weixin + * @param {Object} params + * @param {String} params.encryptedData 微信获取手机号返回的加密信息 + * @param {String} params.iv 微信获取手机号返回的初始向量 + * @returns + */ + bindMobileByMpWeixin, + /** + * 绑定微信 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-weixin + * @param {Object} params + * @param {String} params.code 微信登录返回的code + * @returns + */ + bindWeixin, + /** + * 绑定QQ + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-qq + * @param {Object} params + * @param {String} params.code 小程序端QQ登录返回的code + * @param {String} params.accessToken APP端QQ登录返回的accessToken + * @param {String} params.accessTokenExpired accessToken过期时间,由App端QQ登录返回的expires_in参数计算而来,单位:毫秒 + * @returns + */ + bindQQ, + /** + * 绑定支付宝账号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-alipay + * @param {Object} params + * @param {String} params.code 支付宝小程序登录返回的code参数 + * @returns + */ + bindAlipay, + /** + * 绑定苹果账号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-apple + * @param {Object} params + * @param {String} params.identityToken 苹果登录返回identityToken + * @returns + */ + bindApple, + /** + * 更新密码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#update-pwd + * @param {object} params + * @param {string} params.oldPassword 旧密码 + * @param {string} params.newPassword 新密码 + * @returns {object} + */ + updatePwd, + /** + * 通过短信验证码重置密码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#reset-pwd-by-sms + * @param {object} params + * @param {string} params.mobile 手机号 + * @param {string} params.mobile 短信验证码 + * @param {string} params.password 密码 + * @param {string} params.captcha 图形验证码 + * @returns {object} + */ + resetPwdBySms, + /** + * 通过邮箱验证码重置密码 + * @param {object} params + * @param {string} params.email 邮箱 + * @param {string} params.code 邮箱验证码 + * @param {string} params.password 密码 + * @param {string} params.captcha 图形验证码 + * @returns {object} + */ + resetPwdByEmail, + /** + * 注销账户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#close-account + * @returns + */ + closeAccount, + /** + * 获取账户账户简略信息 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-account-info + */ + getAccountInfo, + /** + * 创建图形验证码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#create-captcha + * @param {Object} params + * @param {String} params.scene 图形验证码使用场景 + * @returns + */ + createCaptcha, + /** + * 刷新图形验证码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#refresh-captcha + * @param {Object} params + * @param {String} params.scene 图形验证码使用场景 + * @returns + */ + refreshCaptcha, + /** + * 发送短信验证码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#send-sms-code + * @param {Object} params + * @param {String} params.mobile 手机号 + * @param {String} params.captcha 图形验证码 + * @param {String} params.scene 短信验证码使用场景 + * @returns + */ + sendSmsCode, + /** + * 发送邮箱验证码 + * @tutorial 需自行实现功能 + * @param {Object} params + * @param {String} params.email 邮箱 + * @param {String} params.captcha 图形验证码 + * @param {String} params.scene 短信验证码使用场景 + * @returns + */ + sendEmailCode, + /** + * 刷新token + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#refresh-token + */ + refreshToken, + /** + * 接受邀请 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#accept-invite + * @param {Object} params + * @param {String} params.inviteCode 邀请码 + * @returns + */ + acceptInvite, + /** + * 获取受邀用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-invited-user + * @param {Object} params + * @param {Number} params.level 获取受邀用户的级数,1表示直接邀请的用户 + * @param {Number} params.limit 返回数据大小 + * @param {Number} params.offset 返回数据偏移 + * @param {Boolean} params.needTotal 是否需要返回总数 + * @returns + */ + getInvitedUser, + /** + * 更新device表的push_clien_id + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-push-cid + * @param {object} params + * @param {string} params.pushClientId 客户端pushClientId + * @returns + */ + setPushCid, + /** + * 获取支持的登录方式 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-supported-login-type + * @returns + */ + getSupportedLoginType, + + /** + * 解绑微信 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-weixin + * @returns + */ + unbindWeixin, + /** + * 解绑支付宝 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-alipay + * @returns + */ + unbindAlipay, + /** + * 解绑QQ + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-qq + * @returns + */ + unbindQQ, + /** + * 解绑Apple + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-apple + * @returns + */ + unbindApple, + /** + * 安全网络握手,目前仅处理微信小程序安全网络握手 + */ + secureNetworkHandshakeByWeixin, + /** + * 设置密码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-pwd + * @returns + */ + setPwd, + /** + * 外部注册用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#external-register + * @param {object} params + * @param {string} params.externalUid 业务系统的用户id + * @param {string} params.nickname 昵称 + * @param {string} params.gender 性别 + * @param {string} params.avatar 头像 + * @returns {object} + */ + externalRegister, + /** + * 外部用户登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#external-login + * @param {object} params + * @param {string} params.userId uni-id体系用户id + * @param {string} params.externalUid 业务系统的用户id + * @returns {object} + */ + externalLogin, + /** + * 使用 userId 或 externalUid 获取用户信息 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#external-update-userinfo + * @param {object} params + * @param {string} params.userId uni-id体系的用户id + * @param {string} params.externalUid 业务系统的用户id + * @param {string} params.nickname 昵称 + * @param {string} params.gender 性别 + * @param {string} params.avatar 头像 + * @returns {object} + */ + updateUserInfoByExternal, + /** + * 获取认证ID + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-frv-certify-id + * @param {Object} params + * @param {String} params.realName 真实姓名 + * @param {String} params.idCard 身份证号码 + * @returns + */ + getFrvCertifyId, + /** + * 查询认证结果 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-frv-auth-result + * @param {Object} params + * @param {String} params.certifyId 认证ID + * @param {String} params.needAlivePhoto 是否获取认证照片,Y_O (原始图片)、Y_M(虚化,背景马赛克)、N(不返图) + * @returns + */ + getFrvAuthResult, + /** + * 获取实名信息 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-realname-info + * @param {Object} params + * @param {Boolean} params.decryptData 是否解密数据 + * @returns + */ + getRealNameInfo +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/en.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/en.js new file mode 100644 index 0000000..6825461 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/en.js @@ -0,0 +1,62 @@ +const word = { + login: 'login', + 'verify-mobile': 'verify phone number' +} + +const sentence = { + 'uni-id-account-exists': 'Account exists', + 'uni-id-account-not-exists': 'Account does not exists', + 'uni-id-account-not-exists-in-current-app': 'Account does not exists in current app', + 'uni-id-account-conflict': 'User account conflict', + 'uni-id-account-banned': 'Account has been banned', + 'uni-id-account-auditing': 'Account audit in progress', + 'uni-id-account-audit-failed': 'Account audit failed', + 'uni-id-account-closed': 'Account has been closed', + 'uni-id-captcha-required': 'Captcha required', + 'uni-id-password-error': 'Password error', + 'uni-id-password-error-exceed-limit': 'The number of password errors is excessive', + 'uni-id-invalid-username': 'Invalid username', + 'uni-id-invalid-password': 'invalid password', + 'uni-id-invalid-password-super': 'Passwords must have 8-16 characters and contain uppercase letters, lowercase letters, numbers, and symbols.', + 'uni-id-invalid-password-strong': 'Passwords must have 8-16 characters and contain letters, numbers and symbols.', + 'uni-id-invalid-password-medium': 'Passwords must have 8-16 characters and contain at least two of the following: letters, numbers, and symbols.', + 'uni-id-invalid-password-weak': 'Passwords must have 6-16 characters and contain letters and numbers.', + 'uni-id-invalid-mobile': 'Invalid mobile phone number', + 'uni-id-invalid-email': 'Invalid email address', + 'uni-id-invalid-nickname': 'Invalid nickname', + 'uni-id-invalid-param': 'Invalid parameter', + 'uni-id-param-required': 'Parameter required: {param}', + 'uni-id-get-third-party-account-failed': 'Get third party account failed', + 'uni-id-get-third-party-user-info-failed': 'Get third party user info failed', + 'uni-id-mobile-verify-code-error': 'Verify code error or expired', + 'uni-id-email-verify-code-error': 'Verify code error or expired', + 'uni-id-admin-exists': 'Administrator exists', + 'uni-id-permission-error': 'Permission denied', + 'uni-id-system-error': 'System error', + 'uni-id-set-invite-code-failed': 'Set invite code failed', + 'uni-id-invalid-invite-code': 'Invalid invite code', + 'uni-id-change-inviter-forbidden': 'Change inviter is not allowed', + 'uni-id-bind-conflict': 'This account has been bound', + 'uni-id-admin-exist-in-other-apps': 'Administrator is registered in other consoles', + 'uni-id-unbind-failed': 'Please bind first and then unbind', + 'uni-id-unbind-not-supported': 'Unbinding is not supported', + 'uni-id-unbind-mobile-not-exists': 'This is the only way to login at the moment, please bind your phone number and then try to unbind', + 'uni-id-unbind-password-not-exists': 'Please set a password first', + 'uni-id-unsupported-request': 'Unsupported request', + 'uni-id-illegal-request': 'Illegal request', + 'uni-id-config-field-required': 'Config field required: {field}', + 'uni-id-config-field-invalid': 'Config field: {field} is invalid', + 'uni-id-frv-fail': 'Real name certify failed', + 'uni-id-frv-processing': 'Waiting for face recognition', + 'uni-id-realname-verified': 'This account has been verified', + 'uni-id-idcard-exists': 'The ID number has been bound to the account', + 'uni-id-invalid-idcard': 'ID number is invalid', + 'uni-id-invalid-realname': 'The name can only be Chinese characters', + 'uni-id-unknown-error': 'unknown error', + 'uni-id-realname-verify-upper-limit': 'The number of real-name certify on the day has reached the upper limit' +} + +module.exports = { + ...word, + ...sentence +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/index.js new file mode 100644 index 0000000..1f22998 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/index.js @@ -0,0 +1,22 @@ +let lang = { + 'zh-Hans': require('./zh-hans'), + en: require('./en') +} + +function mergeLanguage (lang1, lang2) { + const localeList = Object.keys(lang1) + localeList.push(...Object.keys(lang2)) + const result = {} + for (let i = 0; i < localeList.length; i++) { + const locale = localeList[i] + result[locale] = Object.assign({}, lang1[locale], lang2[locale]) + } + return result +} + +try { + const langPath = require.resolve('uni-config-center/uni-id/lang/index.js') + lang = mergeLanguage(lang, require(langPath)) +} catch (error) { } + +module.exports = lang diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/zh-hans.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/zh-hans.js new file mode 100644 index 0000000..911ce20 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lang/zh-hans.js @@ -0,0 +1,64 @@ +const word = { + login: '登录', + 'verify-mobile': '验证手机号' +} + +const sentence = { + 'uni-id-token-expired': '登录状态失效,token已过期', + 'uni-id-check-token-failed': 'token校验未通过', + 'uni-id-account-exists': '此账号已注册', + 'uni-id-account-not-exists': '此账号未注册', + 'uni-id-account-not-exists-in-current-app': '此账号未在该应用注册', + 'uni-id-account-conflict': '用户账号冲突', + 'uni-id-account-banned': '此账号已封禁', + 'uni-id-account-auditing': '此账号正在审核中', + 'uni-id-account-audit-failed': '此账号审核失败', + 'uni-id-account-closed': '此账号已注销', + 'uni-id-captcha-required': '请输入图形验证码', + 'uni-id-password-error': '密码错误', + 'uni-id-password-error-exceed-limit': '密码错误次数过多,请稍后再试', + 'uni-id-invalid-username': '用户名不合法', + 'uni-id-invalid-password': '密码不合法', + 'uni-id-invalid-password-super': '密码必须包含大小写字母、数字和特殊符号,长度8-16位', + 'uni-id-invalid-password-strong': '密码必须包含字母、数字和特殊符号,长度8-16位不合法', + 'uni-id-invalid-password-medium': '密码必须为字母、数字和特殊符号任意两种的组合,长度8-16位', + 'uni-id-invalid-password-weak': '密码必须包含字母和数字,长度6-16位', + 'uni-id-invalid-mobile': '手机号码不合法', + 'uni-id-invalid-email': '邮箱不合法', + 'uni-id-invalid-nickname': '昵称不合法', + 'uni-id-invalid-param': '参数错误', + 'uni-id-param-required': '缺少参数: {param}', + 'uni-id-get-third-party-account-failed': '获取第三方账号失败', + 'uni-id-get-third-party-user-info-failed': '获取用户信息失败', + 'uni-id-mobile-verify-code-error': '手机验证码错误或已过期', + 'uni-id-email-verify-code-error': '邮箱验证码错误或已过期', + 'uni-id-admin-exists': '超级管理员已存在', + 'uni-id-permission-error': '权限错误', + 'uni-id-system-error': '系统错误', + 'uni-id-set-invite-code-failed': '设置邀请码失败', + 'uni-id-invalid-invite-code': '邀请码不可用', + 'uni-id-change-inviter-forbidden': '禁止修改邀请人', + 'uni-id-bind-conflict': '此账号已被绑定', + 'uni-id-admin-exist-in-other-apps': '超级管理员已在其他控制台注册', + 'uni-id-unbind-failed': '请先绑定后再解绑', + 'uni-id-unbind-not-supported': '不支持解绑', + 'uni-id-unbind-mobile-not-exists': '这是当前唯一登录方式,请绑定手机号后再尝试解绑', + 'uni-id-unbind-password-not-exists': '请先设置密码在尝试解绑', + 'uni-id-unsupported-request': '不支持的请求方式', + 'uni-id-illegal-request': '非法请求', + 'uni-id-frv-fail': '实名认证失败', + 'uni-id-frv-processing': '等待人脸识别', + 'uni-id-realname-verified': '该账号已实名认证', + 'uni-id-idcard-exists': '该证件号码已绑定账号', + 'uni-id-invalid-idcard': '身份证号码不合法', + 'uni-id-invalid-realname': '姓名只能是汉字', + 'uni-id-unknown-error': '未知错误', + 'uni-id-realname-verify-upper-limit': '当日实名认证次数已达上限', + 'uni-id-config-field-required': '缺少配置项: {field}', + 'uni-id-config-field-invalid': '配置项: {field}无效' +} + +module.exports = { + ...word, + ...sentence +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/README.md b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/README.md new file mode 100644 index 0000000..47d8c4c --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/README.md @@ -0,0 +1,3 @@ +# 说明 + +此目录内为uni-id-co基础能力,不建议直接修改。如果你发现有些逻辑加入会更好,或者此部分代码有Bug可以向我们提交PR,仓库地址:[]()。如果有特殊的需求也可以在[论坛](https://ask.dcloud.net.cn/)提出,我们可以讨论下如何实现。 \ No newline at end of file diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/index.js new file mode 100644 index 0000000..dbec081 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/index.js @@ -0,0 +1,16 @@ +const AlipayBase = require('../alipayBase') +const protocols = require('./protocols') +module.exports = class Auth extends AlipayBase { + constructor (options) { + super(options) + this._protocols = protocols + } + + async code2Session (code) { + const result = await this._exec('alipay.system.oauth.token', { + grantType: 'authorization_code', + code + }) + return result + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/protocols.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/protocols.js new file mode 100644 index 0000000..cff351d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/account/protocols.js @@ -0,0 +1,10 @@ +module.exports = { + code2Session: { + // args (fromArgs) { + // return fromArgs + // }, + returnValue: { + openid: 'userId' + } + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/alipayBase.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/alipayBase.js new file mode 100644 index 0000000..1462b04 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/alipay/alipayBase.js @@ -0,0 +1,231 @@ +const { + camel2snakeJson, + snake2camelJson, + getOffsetDate, + getFullTimeStr +} = require('../../../common/utils') +const crypto = require('crypto') + +const ALIPAY_ALGORITHM_MAPPING = { + RSA: 'RSA-SHA1', + RSA2: 'RSA-SHA256' +} + +module.exports = class AlipayBase { + constructor (options = {}) { + if (!options.appId) throw new Error('appId required') + if (!options.privateKey) throw new Error('privateKey required') + const defaultOptions = { + gateway: 'https://openapi.alipay.com/gateway.do', + timeout: 5000, + charset: 'utf-8', + version: '1.0', + signType: 'RSA2', + timeOffset: -new Date().getTimezoneOffset() / 60, + keyType: 'PKCS8' + } + + if (options.sandbox) { + options.gateway = 'https://openapi.alipaydev.com/gateway.do' + } + + this.options = Object.assign({}, defaultOptions, options) + + const privateKeyType = + this.options.keyType === 'PKCS8' ? 'PRIVATE KEY' : 'RSA PRIVATE KEY' + + this.options.privateKey = this._formatKey( + this.options.privateKey, + privateKeyType + ) + if (this.options.alipayPublicKey) { + this.options.alipayPublicKey = this._formatKey( + this.options.alipayPublicKey, + 'PUBLIC KEY' + ) + } + } + + _formatKey (key, type) { + return `-----BEGIN ${type}-----\n${key}\n-----END ${type}-----` + } + + _formatUrl (url, params) { + let requestUrl = url + // 需要放在 url 中的参数列表 + const urlArgs = [ + 'app_id', + 'method', + 'format', + 'charset', + 'sign_type', + 'sign', + 'timestamp', + 'version', + 'notify_url', + 'return_url', + 'auth_token', + 'app_auth_token' + ] + + for (const key in params) { + if (urlArgs.indexOf(key) > -1) { + const val = encodeURIComponent(params[key]) + requestUrl = `${requestUrl}${requestUrl.includes('?') ? '&' : '?' + }${key}=${val}` + // 删除 postData 中对应的数据 + delete params[key] + } + } + + return { execParams: params, url: requestUrl } + } + + _getSign (method, params) { + const bizContent = params.bizContent || null + delete params.bizContent + + const signParams = Object.assign({ + method, + appId: this.options.appId, + charset: this.options.charset, + version: this.options.version, + signType: this.options.signType, + timestamp: getFullTimeStr(getOffsetDate(this.options.timeOffset)) + }, params) + + if (bizContent) { + signParams.bizContent = JSON.stringify(camel2snakeJson(bizContent)) + } + + // params key 驼峰转下划线 + const decamelizeParams = camel2snakeJson(signParams) + + // 排序 + const signStr = Object.keys(decamelizeParams) + .sort() + .map((key) => { + let data = decamelizeParams[key] + if (Array.prototype.toString.call(data) !== '[object String]') { + data = JSON.stringify(data) + } + return `${key}=${data}` + }) + .join('&') + + // 计算签名 + const sign = crypto + .createSign(ALIPAY_ALGORITHM_MAPPING[this.options.signType]) + .update(signStr, 'utf8') + .sign(this.options.privateKey, 'base64') + + return Object.assign(decamelizeParams, { sign }) + } + + async _exec (method, params = {}, option = {}) { + // 计算签名 + const signData = this._getSign(method, params) + const { url, execParams } = this._formatUrl(this.options.gateway, signData) + const { status, data } = await uniCloud.httpclient.request(url, { + method: 'POST', + data: execParams, + // 按 text 返回(为了验签) + dataType: 'text', + timeout: this.options.timeout + }) + if (status !== 200) throw new Error('request fail') + /** + * 示例响应格式 + * {"alipay_trade_precreate_response": + * {"code": "10000","msg": "Success","out_trade_no": "111111","qr_code": "https:\/\/"}, + * "sign": "abcde=" + * } + * 或者 + * {"error_response": + * {"code":"40002","msg":"Invalid Arguments","sub_code":"isv.code-invalid","sub_msg":"授权码code无效"}, + * } + */ + const result = JSON.parse(data) + const responseKey = `${method.replace(/\./g, '_')}_response` + const response = result[responseKey] + const errorResponse = result.error_response + if (response) { + // 按字符串验签 + const validateSuccess = option.validateSign ? this._checkResponseSign(data, responseKey) : true + if (validateSuccess) { + if (!response.code || response.code === '10000') { + const errCode = 0 + const errMsg = response.msg || '' + return { + errCode, + errMsg, + ...snake2camelJson(response) + } + } + const msg = response.sub_code ? `${response.sub_code} ${response.sub_msg}` : `${response.msg || 'unkonwn error'}` + throw new Error(msg) + } else { + throw new Error('check sign error') + } + } else if (errorResponse) { + throw new Error(errorResponse.sub_msg || errorResponse.msg || 'request fail') + } + + throw new Error('request fail') + } + + _checkResponseSign (signStr, responseKey) { + if (!this.options.alipayPublicKey || this.options.alipayPublicKey === '') { + console.warn('options.alipayPublicKey is empty') + // 支付宝公钥不存在时不做验签 + return true + } + + // 带验签的参数不存在时返回失败 + if (!signStr) { return false } + + // 根据服务端返回的结果截取需要验签的目标字符串 + const validateStr = this._getSignStr(signStr, responseKey) + // 服务端返回的签名 + const serverSign = JSON.parse(signStr).sign + + // 参数存在,并且是正常的结果(不包含 sub_code)时才验签 + const verifier = crypto.createVerify(ALIPAY_ALGORITHM_MAPPING[this.options.signType]) + verifier.update(validateStr, 'utf8') + return verifier.verify(this.options.alipayPublicKey, serverSign, 'base64') + } + + _getSignStr (originStr, responseKey) { + // 待签名的字符串 + let validateStr = originStr.trim() + // 找到 xxx_response 开始的位置 + const startIndex = originStr.indexOf(`${responseKey}"`) + // 找到最后一个 “"sign"” 字符串的位置(避免) + const lastIndex = originStr.lastIndexOf('"sign"') + + /** + * 删除 xxx_response 及之前的字符串 + * 假设原始字符串为 + * {"xxx_response":{"code":"10000"},"sign":"jumSvxTKwn24G5sAIN"} + * 删除后变为 + * :{"code":"10000"},"sign":"jumSvxTKwn24G5sAIN"} + */ + validateStr = validateStr.substr(startIndex + responseKey.length + 1) + + /** + * 删除最后一个 "sign" 及之后的字符串 + * 删除后变为 + * :{"code":"10000"}, + * {} 之间就是待验签的字符串 + */ + validateStr = validateStr.substr(0, lastIndex) + + // 删除第一个 { 之前的任何字符 + validateStr = validateStr.replace(/^[^{]*{/g, '{') + + // 删除最后一个 } 之后的任何字符 + validateStr = validateStr.replace(/\}([^}]*)$/g, '}') + + return validateStr + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/account/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/account/index.js new file mode 100644 index 0000000..0e51b4d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/account/index.js @@ -0,0 +1,76 @@ +const rsaPublicKeyPem = require('../rsa-public-key-pem') +let authKeysCache = null + +module.exports = class Auth { + constructor (options) { + this.options = Object.assign({ + baseUrl: 'https://appleid.apple.com', + timeout: 10000 + }, options) + } + + async _fetch (url, options) { + const { baseUrl } = this.options + return uniCloud.httpclient.request(baseUrl + url, options) + } + + async verifyIdentityToken (identityToken) { + // 解密出kid,拿取key + const jwtHeader = identityToken.split('.')[0] + const { kid } = JSON.parse(Buffer.from(jwtHeader, 'base64').toString()) + let authKeys + if (authKeysCache) { + authKeys = authKeysCache + } else { + authKeys = await this.getAuthKeys() + authKeysCache = authKeys + } + const usedKey = authKeys.find(item => item.kid === kid) + + /** + * identityToken 格式 + * + * { + * iss: 'https://appleid.apple.com', + * aud: 'io.dcloud.hellouniapp', + * exp: 1610626724, + * iat: 1610540324, + * sub: '000628.30119d332d9b45a3be4a297f9391fd5c.0403', + * c_hash: 'oFfgewoG36cJX00KUbj45A', + * email: 'x2awmap99s@privaterelay.appleid.com', + * email_verified: 'true', + * is_private_email: 'true', + * auth_time: 1610540324, + * nonce_supported: true + * } + */ + const payload = require('jsonwebtoken').verify( + identityToken, + rsaPublicKeyPem(usedKey.n, usedKey.e), + { + algorithms: usedKey.alg + } + ) + + if (payload.iss !== 'https://appleid.apple.com' || payload.aud !== this.options.bundleId) { + throw new Error('Invalid identity token') + } + + return { + openid: payload.sub, + email: payload.email, + emailVerified: payload.email_verified === 'true', + isPrivateEmail: payload.is_private_email === 'true' + } + } + + async getAuthKeys () { + const { status, data } = await this._fetch('/auth/keys', { + method: 'GET', + dataType: 'json', + timeout: this.options.timeout + }) + if (status !== 200) throw new Error('request https://appleid.apple.com/auth/keys fail') + return data.keys + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/rsa-public-key-pem.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/rsa-public-key-pem.js new file mode 100644 index 0000000..e1dbb31 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/apple/rsa-public-key-pem.js @@ -0,0 +1,64 @@ +// http://stackoverflow.com/questions/18835132/xml-to-pem-in-node-js +/* eslint-disable camelcase */ +function rsaPublicKeyPem (modulus_b64, exponent_b64) { + const modulus = Buffer.from(modulus_b64, 'base64') + const exponent = Buffer.from(exponent_b64, 'base64') + + let modulus_hex = modulus.toString('hex') + let exponent_hex = exponent.toString('hex') + + modulus_hex = prepadSigned(modulus_hex) + exponent_hex = prepadSigned(exponent_hex) + + const modlen = modulus_hex.length / 2 + const explen = exponent_hex.length / 2 + + const encoded_modlen = encodeLengthHex(modlen) + const encoded_explen = encodeLengthHex(explen) + const encoded_pubkey = '30' + + encodeLengthHex( + modlen + + explen + + encoded_modlen.length / 2 + + encoded_explen.length / 2 + 2 + ) + + '02' + encoded_modlen + modulus_hex + + '02' + encoded_explen + exponent_hex + + const der_b64 = Buffer.from(encoded_pubkey, 'hex').toString('base64') + + const pem = '-----BEGIN RSA PUBLIC KEY-----\n' + + der_b64.match(/.{1,64}/g).join('\n') + + '\n-----END RSA PUBLIC KEY-----\n' + + return pem +} + +function prepadSigned (hexStr) { + const msb = hexStr[0] + if (msb < '0' || msb > '7') { + return '00' + hexStr + } else { + return hexStr + } +} + +function toHex (number) { + const nstr = number.toString(16) + if (nstr.length % 2) return '0' + nstr + return nstr +} + +// encode ASN.1 DER length field +// if <=127, short form +// if >=128, long form +function encodeLengthHex (n) { + if (n <= 127) return toHex(n) + else { + const n_hex = toHex(n) + const length_of_length_byte = 128 + n_hex.length / 2 // 0x80+numbytes + return toHex(length_of_length_byte) + n_hex + } +} + +module.exports = rsaPublicKeyPem diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/index.js new file mode 100644 index 0000000..149c7de --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/index.js @@ -0,0 +1,36 @@ +const WxAccount = require('./weixin/account/index') +const QQAccount = require('./qq/account/index') +const AliAccount = require('./alipay/account/index') +const AppleAccount = require('./apple/account/index') + +const createApi = require('./share/create-api') + +module.exports = { + initWeixin: function () { + const oauthConfig = this.configUtils.getOauthConfig({ provider: 'weixin' }) + return createApi(WxAccount, { + appId: oauthConfig.appid, + secret: oauthConfig.appsecret + }) + }, + initQQ: function () { + const oauthConfig = this.configUtils.getOauthConfig({ provider: 'qq' }) + return createApi(QQAccount, { + appId: oauthConfig.appid, + secret: oauthConfig.appsecret + }) + }, + initAlipay: function () { + const oauthConfig = this.configUtils.getOauthConfig({ provider: 'alipay' }) + return createApi(AliAccount, { + appId: oauthConfig.appid, + privateKey: oauthConfig.privateKey + }) + }, + initApple: function () { + const oauthConfig = this.configUtils.getOauthConfig({ provider: 'apple' }) + return createApi(AppleAccount, { + bundleId: oauthConfig.bundleId + }) + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/account/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/account/index.js new file mode 100644 index 0000000..9b4879a --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/account/index.js @@ -0,0 +1,97 @@ +const { + UniCloudError +} = require('../../../../common/error') +const { + resolveUrl +} = require('../../../../common/utils') +const { + callQQOpenApi +} = require('../normalize') + +module.exports = class Auth { + constructor (options) { + this.options = Object.assign({ + baseUrl: 'https://graph.qq.com', + timeout: 5000 + }, options) + } + + async _requestQQOpenapi ({ name, url, data, options }) { + const defaultOptions = { + method: 'GET', + dataType: 'json', + dataAsQueryString: true, + timeout: this.options.timeout + } + const result = await callQQOpenApi({ + name: `auth.${name}`, + url: resolveUrl(this.options.baseUrl, url), + data, + options, + defaultOptions + }) + return result + } + + async getUserInfo ({ + accessToken, + openid + } = {}) { + const url = '/user/get_user_info' + const result = await this._requestQQOpenapi({ + name: 'getUserInfo', + url, + data: { + oauthConsumerKey: this.options.appId, + accessToken, + openid + } + }) + return { + nickname: result.nickname, + avatar: result.figureurl_qq_1 + } + } + + async getOpenidByToken ({ + accessToken + } = {}) { + const url = '/oauth2.0/me' + const result = await this._requestQQOpenapi({ + name: 'getOpenidByToken', + url, + data: { + accessToken, + unionid: 1, + fmt: 'json' + } + }) + if (result.clientId !== this.options.appId) { + throw new UniCloudError({ + code: 'APPID_NOT_MATCH', + message: 'appid not match' + }) + } + return { + openid: result.openid, + unionid: result.unionid + } + } + + async code2Session ({ + code + } = {}) { + const url = 'https://api.q.qq.com/sns/jscode2session' + const result = await this._requestQQOpenapi({ + name: 'getOpenidByToken', + url, + data: { + grant_type: 'authorization_code', + appid: this.options.appId, + secret: this.options.secret, + js_code: code + } + }) + return result + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/account/protocol.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/account/protocol.js new file mode 100644 index 0000000..e69de29 diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/normalize.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/normalize.js new file mode 100644 index 0000000..fcfdc1e --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/qq/normalize.js @@ -0,0 +1,85 @@ +const { + UniCloudError +} = require('../../../common/error') +const { + camel2snakeJson, + snake2camelJson +} = require('../../../common/utils') + +function generateApiResult (apiName, data) { + if (data.ret || data.error) { + // 这三种都是qq的错误码规范 + const code = data.ret || data.error || data.errcode || -2 + const message = data.msg || data.error_description || data.errmsg || `${apiName} fail` + throw new UniCloudError({ + code, + message + }) + } else { + delete data.ret + delete data.msg + delete data.error + delete data.error_description + delete data.errcode + delete data.errmsg + return { + ...data, + errMsg: `${apiName} ok`, + errCode: 0 + } + } +} + +function nomalizeError (apiName, error) { + throw new UniCloudError({ + code: error.code || -2, + message: error.message || `${apiName} fail` + }) +} + +async function callQQOpenApi ({ + name, + url, + data, + options, + defaultOptions +}) { + options = Object.assign({}, defaultOptions, options, { data: camel2snakeJson(Object.assign({}, data)) }) + let result + try { + result = await uniCloud.httpclient.request(url, options) + } catch (e) { + return nomalizeError(name, e) + } + let resData = result.data + const contentType = result.headers['content-type'] + if ( + Buffer.isBuffer(resData) && + (contentType.indexOf('text/plain') === 0 || + contentType.indexOf('application/json') === 0) + ) { + try { + resData = JSON.parse(resData.toString()) + } catch (e) { + resData = resData.toString() + } + } else if (Buffer.isBuffer(resData)) { + resData = { + buffer: resData, + contentType + } + } + return snake2camelJson( + generateApiResult( + name, + resData || { + errCode: -2, + errMsg: 'Request failed' + } + ) + ) +} + +module.exports = { + callQQOpenApi +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/share/create-api.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/share/create-api.js new file mode 100644 index 0000000..c58f1e8 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/share/create-api.js @@ -0,0 +1,73 @@ +const { + isFn, + isPlainObject +} = require('../../../common/utils') + +// 注意:不进行递归处理 +function parseParams (params = {}, rule) { + if (!rule || !params) { + return params + } + const internalKeys = ['_pre', '_purify', '_post'] + // 转换之前的处理 + if (rule._pre) { + params = rule._pre(params) + } + // 净化参数 + let purify = { shouldDelete: new Set([]) } + if (rule._purify) { + const _purify = rule._purify + for (const purifyKey in _purify) { + _purify[purifyKey] = new Set(_purify[purifyKey]) + } + purify = Object.assign(purify, _purify) + } + if (isPlainObject(rule)) { + for (const key in rule) { + const parser = rule[key] + if (isFn(parser) && internalKeys.indexOf(key) === -1) { + params[key] = parser(params) + } else if (typeof parser === 'string' && internalKeys.indexOf(key) === -1) { + // 直接转换属性名称的删除旧属性名 + params[key] = params[parser] + purify.shouldDelete.add(parser) + } + } + } else if (isFn(rule)) { + params = rule(params) + } + + if (purify.shouldDelete) { + for (const item of purify.shouldDelete) { + delete params[item] + } + } + + // 转换之后的处理 + if (rule._post) { + params = rule._post(params) + } + + return params +} + +function createApi (ApiClass, options) { + const apiInstance = new ApiClass(options) + return new Proxy(apiInstance, { + get: function (obj, prop) { + if (typeof obj[prop] === 'function' && prop.indexOf('_') !== 0 && obj._protocols && obj._protocols[prop]) { + const protocol = obj._protocols[prop] + return async function (params) { + params = parseParams(params, protocol.args) + let result = await obj[prop](params) + result = parseParams(result, protocol.returnValue) + return result + } + } else { + return obj[prop] + } + } + }) +} + +module.exports = createApi diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/account/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/account/index.js new file mode 100644 index 0000000..7ecea84 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/account/index.js @@ -0,0 +1,111 @@ +const { + callWxOpenApi, + buildUrl +} = require('../normalize') + +module.exports = class Auth { + constructor (options) { + this.options = Object.assign({ + baseUrl: 'https://api.weixin.qq.com', + timeout: 5000 + }, options) + } + + async _requestWxOpenapi ({ name, url, data, options }) { + const defaultOptions = { + method: 'GET', + dataType: 'json', + dataAsQueryString: true, + timeout: this.options.timeout + } + const result = await callWxOpenApi({ + name: `auth.${name}`, + url: `${this.options.baseUrl}${buildUrl(url, data)}`, + data, + options, + defaultOptions + }) + return result + } + + async code2Session (code) { + const url = '/sns/jscode2session' + const result = await this._requestWxOpenapi({ + name: 'code2Session', + url, + data: { + grant_type: 'authorization_code', + appid: this.options.appId, + secret: this.options.secret, + js_code: code + } + }) + return result + } + + async getOauthAccessToken (code) { + const url = '/sns/oauth2/access_token' + const result = await this._requestWxOpenapi({ + name: 'getOauthAccessToken', + url, + data: { + grant_type: 'authorization_code', + appid: this.options.appId, + secret: this.options.secret, + code + } + }) + if (result.expiresIn) { + result.expired = Date.now() + result.expiresIn * 1000 + // delete result.expiresIn + } + return result + } + + async getUserInfo ({ + accessToken, + openid + } = {}) { + const url = '/sns/userinfo' + const { + nickname, + headimgurl: avatar + } = await this._requestWxOpenapi({ + name: 'getUserInfo', + url, + data: { + accessToken, + openid, + appid: this.options.appId, + secret: this.options.secret, + scope: 'snsapi_userinfo' + } + }) + return { + nickname, + avatar + } + } + + async getPhoneNumber (accessToken, code) { + const url = `/wxa/business/getuserphonenumber?access_token=${accessToken}` + const { phoneInfo } = await this._requestWxOpenapi({ + name: 'getPhoneNumber', + url, + data: { + code + }, + options: { + method: 'POST', + dataAsQueryString: false, + headers: { + 'content-type': 'application/json' + } + } + }) + + return { + purePhoneNumber: phoneInfo.purePhoneNumber + } + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/normalize.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/normalize.js new file mode 100644 index 0000000..908d916 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/normalize.js @@ -0,0 +1,95 @@ +const { + UniCloudError +} = require('../../../common/error') +const { + camel2snakeJson, snake2camelJson +} = require('../../../common/utils') + +function generateApiResult (apiName, data) { + if (data.errcode) { + throw new UniCloudError({ + code: data.errcode || -2, + message: data.errmsg || `${apiName} fail` + }) + } else { + delete data.errcode + delete data.errmsg + return { + ...data, + errMsg: `${apiName} ok`, + errCode: 0 + } + } +} + +function nomalizeError (apiName, error) { + throw new UniCloudError({ + code: error.code || -2, + message: error.message || `${apiName} fail` + }) +} + +// 微信openapi接口接收蛇形(snake case)参数返回蛇形参数,这里进行转化,如果是formdata里面的参数需要在对应api实现时就转为蛇形 +async function callWxOpenApi ({ + name, + url, + data, + options, + defaultOptions +}) { + let result = {} + // 获取二维码的接口wxacode.get和wxacode.getUnlimited不可以传入access_token(可能有其他接口也不可以),否则会返回data format error + const dataCopy = camel2snakeJson(Object.assign({}, data)) + if (dataCopy && dataCopy.access_token) { + delete dataCopy.access_token + } + try { + options = Object.assign({}, defaultOptions, options, { data: dataCopy }) + result = await uniCloud.httpclient.request(url, options) + } catch (e) { + return nomalizeError(name, e) + } + + // 有几个接口成功返回buffer失败返回json,对这些接口统一成返回buffer,然后分别解析 + let resData = result.data + const contentType = result.headers['content-type'] + if ( + Buffer.isBuffer(resData) && + (contentType.indexOf('text/plain') === 0 || + contentType.indexOf('application/json') === 0) + ) { + try { + resData = JSON.parse(resData.toString()) + } catch (e) { + resData = resData.toString() + } + } else if (Buffer.isBuffer(resData)) { + resData = { + buffer: resData, + contentType + } + } + return snake2camelJson( + generateApiResult( + name, + resData || { + errCode: -2, + errMsg: 'Request failed' + } + ) + ) +} + +function buildUrl (url, data) { + let query = '' + if (data && data.accessToken) { + const divider = url.indexOf('?') > -1 ? '&' : '?' + query = `${divider}access_token=${data.accessToken}` + } + return `${url}${query}` +} + +module.exports = { + callWxOpenApi, + buildUrl +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/utils.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/utils.js new file mode 100644 index 0000000..c141016 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/third-party/weixin/utils.js @@ -0,0 +1,87 @@ +const crypto = require('crypto') +const { + isPlainObject +} = require('../../../common/utils') + +// 退款通知解密key=md5(key) +function decryptData (encryptedData, key, iv = '') { + // 解密 + const decipher = crypto.createDecipheriv('aes-128-cbc', key, iv) + // 设置自动 padding 为 true,删除填充补位 + decipher.setAutoPadding(true) + let decoded = decipher.update(encryptedData, 'base64', 'utf8') + decoded += decipher.final('utf8') + return decoded +} + +function md5 (str, encoding = 'utf8') { + return crypto + .createHash('md5') + .update(str, encoding) + .digest('hex') +} + +function sha256 (str, key, encoding = 'utf8') { + return crypto + .createHmac('sha256', key) + .update(str, encoding) + .digest('hex') +} + +function getSignStr (obj) { + return Object.keys(obj) + .filter(key => key !== 'sign' && obj[key] !== undefined && obj[key] !== '') + .sort() + .map(key => key + '=' + obj[key]) + .join('&') +} + +function getNonceStr (length = 16) { + let str = '' + while (str.length < length) { + str += Math.random().toString(32).substring(2) + } + return str.substring(0, length) +} + +// 简易版Object转XML,只可在微信支付时使用,不支持嵌套 +function buildXML (obj, rootName = 'xml') { + const content = Object.keys(obj).map(item => { + if (isPlainObject(obj[item])) { + return `<${item}>` + } else { + return `<${item}>` + } + }) + return `<${rootName}>${content.join('')}` +} + +function isXML (str) { + const reg = /^(<\?xml.*\?>)?(\r?\n)*(.|\r?\n)*<\/xml>$/i + return reg.test(str.trim()) +}; + +// 简易版XML转Object,只可在微信支付时使用,不支持嵌套 +function parseXML (xml) { + const xmlReg = /<(?:xml|root).*?>([\s|\S]*)<\/(?:xml|root)>/ + const str = xmlReg.exec(xml)[1] + const obj = {} + const nodeReg = /<(.*?)>(?:){0,1}<\/.*?>/g + let matches = null + // eslint-disable-next-line no-cond-assign + while ((matches = nodeReg.exec(str))) { + obj[matches[1]] = matches[2] + } + return obj +} + +module.exports = { + decryptData, + md5, + sha256, + getSignStr, + getNonceStr, + buildXML, + parseXML, + isXML +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/account.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/account.js new file mode 100644 index 0000000..1fd25f0 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/account.js @@ -0,0 +1,98 @@ +const { + dbCmd, + userCollection +} = require('../../common/constants') +const { + USER_IDENTIFIER +} = require('../../common/constants') +const { + batchFindObjctValue, + getType, + isMatchUserApp +} = require('../../common/utils') + +/** + * 查询满足条件的用户 + * @param {Object} params + * @param {Object} params.userQuery 用户唯一标识组成的查询条件 + * @param {Object} params.authorizedApp 用户允许登录的应用 + * @returns userMatched 满足条件的用户列表 + */ +async function findUser (params = {}) { + const { + userQuery, + authorizedApp = [] + } = params + const condition = getUserQueryCondition(userQuery) + if (condition.length === 0) { + throw new Error('Invalid user query') + } + const authorizedAppType = getType(authorizedApp) + if (authorizedAppType !== 'string' && authorizedAppType !== 'array') { + throw new Error('Invalid authorized app') + } + + let finalQuery + + if (condition.length === 1) { + finalQuery = condition[0] + } else { + finalQuery = dbCmd.or(condition) + } + const userQueryRes = await userCollection.where(finalQuery).get() + return { + total: userQueryRes.data.length, + userMatched: userQueryRes.data.filter(item => { + return isMatchUserApp(item.dcloud_appid, authorizedApp) + }) + } +} + +function getUserIdentifier (userRecord = {}) { + const keys = Object.keys(USER_IDENTIFIER) + return batchFindObjctValue(userRecord, keys) +} + +function getUserQueryCondition (userRecord = {}) { + const userIdentifier = getUserIdentifier(userRecord) + const condition = [] + for (const key in userIdentifier) { + const value = userIdentifier[key] + if (!value) { + // 过滤所有value为假值的条件,在查询用户时没有意义 + continue + } + const queryItem = { + [key]: value + } + // 为兼容用户老数据用户名及邮箱需要同时查小写及原始大小写数据 + if (key === 'mobile') { + queryItem.mobile_confirmed = 1 + } else if (key === 'email') { + queryItem.email_confirmed = 1 + const email = userIdentifier.email + if (email.toLowerCase() !== email) { + condition.push({ + email: email.toLowerCase(), + email_confirmed: 1 + }) + } + } else if (key === 'username') { + const username = userIdentifier.username + if (username.toLowerCase() !== username) { + condition.push({ + username: username.toLowerCase() + }) + } + } else if (key === 'identities') { + queryItem.identities = dbCmd.elemMatch(value) + } + condition.push(queryItem) + } + return condition +} + +module.exports = { + findUser, + getUserIdentifier +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/captcha.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/captcha.js new file mode 100644 index 0000000..0dd620e --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/captcha.js @@ -0,0 +1,76 @@ +const { + ERROR +} = require('../../common/error') + +async function getNeedCaptcha ({ + uid, + username, + mobile, + email, + type = 'login', + limitDuration = 7200000, // 两小时 + limitTimes = 3 // 记录次数 +} = {}) { + const db = uniCloud.database() + const dbCmd = db.command + // 当用户最近“2小时内(limitDuration)”登录失败达到3次(limitTimes)时。要求用户提交验证码 + const now = Date.now() + const uniIdLogCollection = db.collection('uni-id-log') + const userIdentifier = { + user_id: uid, + username, + mobile, + email + } + + let totalKey = 0; let deleteKey = 0 + for (const key in userIdentifier) { + totalKey++ + if (!userIdentifier[key] || typeof userIdentifier[key] !== 'string') { + deleteKey++ + delete userIdentifier[key] + } + } + + if (deleteKey === totalKey) { + throw new Error('System error') // 正常情况下不会进入此条件,但是考虑到后续会有其他开发者修改此云对象,在此处做一个判断 + } + + const { + data: recentRecord + } = await uniIdLogCollection.where({ + ip: this.getUniversalClientInfo().clientIP, + ...userIdentifier, + type, + create_date: dbCmd.gt(now - limitDuration) + }) + .orderBy('create_date', 'desc') + .limit(limitTimes) + .get() + return recentRecord.length === limitTimes && recentRecord.every(item => item.state === 0) +} + +async function verifyCaptcha (params = {}) { + const { + captcha, + scene + } = params + if (!captcha) { + throw { + errCode: ERROR.CAPTCHA_REQUIRED + } + } + const payload = await this.uniCaptcha.verify({ + deviceId: this.getUniversalClientInfo().deviceId, + captcha, + scene + }) + if (payload.errCode) { + throw payload + } +} + +module.exports = { + getNeedCaptcha, + verifyCaptcha +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/config.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/config.js new file mode 100644 index 0000000..48d5688 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/config.js @@ -0,0 +1,135 @@ +const { + getWeixinPlatform +} = require('./weixin') +const createConfig = require('uni-config-center') + +const requiredConfig = { + 'web.weixin-h5': ['appid', 'appsecret'], + 'web.weixin-web': ['appid', 'appsecret'], + 'app.weixin': ['appid', 'appsecret'], + 'mp-weixin.weixin': ['appid', 'appsecret'], + 'app.qq': ['appid', 'appsecret'], + 'mp-alipay.alipay': ['appid', 'privateKey'], + 'app.apple': ['bundleId'] +} + +const uniIdConfig = createConfig({ + pluginId: 'uni-id' +}) + +class ConfigUtils { + constructor ({ + context + } = {}) { + this.context = context + this.clientInfo = context.getUniversalClientInfo() + const { + appId, + uniPlatform + } = this.clientInfo + this.appId = appId + switch (uniPlatform) { + case 'app': + case 'app-plus': + this.platform = 'app' + break + case 'web': + case 'h5': + this.platform = 'web' + break + default: + this.platform = uniPlatform + break + } + } + + getConfigArray () { + let configContent + try { + configContent = require('uni-config-center/uni-id/config.json') + } catch (error) { + throw new Error('Invalid config file\n' + error.message) + } + if (configContent[0]) { + return Object.values(configContent) + } + configContent.isDefaultConfig = true + return [configContent] + } + + getAppConfig () { + const configArray = this.getConfigArray() + return configArray.find(item => item.dcloudAppid === this.appId) || configArray.find(item => item.isDefaultConfig) + } + + getPlatformConfig () { + const appConfig = this.getAppConfig() + if (!appConfig) { + throw new Error( + `Config for current app (${this.appId}) was not found, please check your config file or client appId`) + } + const platform = this.platform + if ( + (this.platform === 'app' && appConfig['app-plus']) || + (this.platform === 'web' && appConfig.h5) + ) { + throw new Error( + `Client platform is ${this.platform}, but ${this.platform === 'web' ? 'h5' : 'app-plus'} was found in config. Please refer to: https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary?id=m-to-co` + ) + } + + const defaultConfig = { + tokenExpiresIn: 7200, + tokenExpiresThreshold: 1200, + passwordErrorLimit: 6, + passwordErrorRetryTime: 3600 + } + return Object.assign(defaultConfig, appConfig, appConfig[platform]) + } + + getOauthProvider ({ + provider + } = {}) { + const clientPlatform = this.platform + let oatuhProivder = provider + if (provider === 'weixin' && clientPlatform === 'web') { + const weixinPlatform = getWeixinPlatform.call(this.context) + if (weixinPlatform === 'h5' || weixinPlatform === 'web') { + oatuhProivder = 'weixin-' + weixinPlatform // weixin-h5 公众号,weixin-web pc端 + } + } + return oatuhProivder + } + + getOauthConfig ({ + provider + } = {}) { + const config = this.getPlatformConfig() + const clientPlatform = this.platform + const oatuhProivder = this.getOauthProvider({ + provider + }) + const requireConfigKey = requiredConfig[`${clientPlatform}.${oatuhProivder}`] || [] + if (!config.oauth || !config.oauth[oatuhProivder]) { + throw new Error(`Config param required: ${clientPlatform}.oauth.${oatuhProivder}`) + } + const oauthConfig = config.oauth[oatuhProivder] + requireConfigKey.forEach((item) => { + if (!oauthConfig[item]) { + throw new Error(`Config param required: ${clientPlatform}.oauth.${oatuhProivder}.${item}`) + } + }) + return oauthConfig + } + + getHooks () { + if (uniIdConfig.hasFile('hooks/index.js')) { + return require( + uniIdConfig.resolve('hooks/index.js') + ) + } + return {} + } +} + +module.exports = ConfigUtils diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/fission.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/fission.js new file mode 100644 index 0000000..84233c3 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/fission.js @@ -0,0 +1,192 @@ +const { + dbCmd, + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +/** + * 获取随机邀请码,邀请码由大写字母加数字组成,由于存在手动输入邀请码的场景,从可选字符中去除 0、1、I、O + * @param {number} len 邀请码长度,默认6位 + * @returns {string} 随机邀请码 + */ +function getRandomInviteCode (len = 6) { + const charArr = ['2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] + let code = '' + for (let i = 0; i < len; i++) { + code += charArr[Math.floor(Math.random() * charArr.length)] + } + return code +} + +/** + * 获取可用的邀请码,至多尝试十次以获取可用邀请码。从10亿可选值中随机,碰撞概率较低 + * 也有其他方案可以尝试,比如在数据库内设置一个从0开始计数的数字,每次调用此方法时使用updateAndReturn使数字加1并返回加1后的值,根据这个值生成对应的邀请码,比如(22222A + 1 == 22222B),此方式性能理论更好,但是不适用于旧项目 + * @param {object} param + * @param {string} param.inviteCode 初始随机邀请码 + */ +async function getValidInviteCode () { + let retry = 10 + let code + let codeValid = false + while (retry > 0 && !codeValid) { + retry-- + code = getRandomInviteCode() + const getUserRes = await userCollection.where({ + my_invite_code: code + }).limit(1).get() + if (getUserRes.data.length === 0) { + codeValid = true + break + } + } + if (!codeValid) { + throw { + errCode: ERROR.SET_INVITE_CODE_FAILED + } + } + return code +} + +/** + * 根据邀请码查询邀请人 + * @param {object} param + * @param {string} param.inviteCode 邀请码 + * @param {string} param.queryUid 受邀人id,非空时校验不可被下家或自己邀请 + * @returns + */ +async function findUserByInviteCode ({ + inviteCode, + queryUid +} = {}) { + if (typeof inviteCode !== 'string') { + throw { + errCode: ERROR.SYSTEM_ERROR + } + } + // 根据邀请码查询邀请人 + let getInviterRes + if (queryUid) { + getInviterRes = await userCollection.where({ + _id: dbCmd.neq(queryUid), + inviter_uid: dbCmd.not(dbCmd.all([queryUid])), + my_invite_code: inviteCode + }).get() + } else { + getInviterRes = await userCollection.where({ + my_invite_code: inviteCode + }).get() + } + if (getInviterRes.data.length > 1) { + // 正常情况下不可能进入此条件,以防用户自行修改数据库出错,在此做出判断 + throw { + errCode: ERROR.SYSTEM_ERROR + } + } + const inviterRecord = getInviterRes.data[0] + if (!inviterRecord) { + throw { + errCode: ERROR.INVALID_INVITE_CODE + } + } + return inviterRecord +} + +/** + * 根据邀请码生成邀请信息 + * @param {object} param + * @param {string} param.inviteCode 邀请码 + * @param {string} param.queryUid 受邀人id,非空时校验不可被下家或自己邀请 + * @returns + */ +async function generateInviteInfo ({ + inviteCode, + queryUid +} = {}) { + const inviterRecord = await findUserByInviteCode({ + inviteCode, + queryUid + }) + // 倒叙拼接当前用户邀请链 + const inviterUid = inviterRecord.inviter_uid || [] + inviterUid.unshift(inviterRecord._id) + return { + inviterUid, + inviteTime: Date.now() + } +} + +/** + * 检查当前用户是否可以接受邀请,如果可以返回用户记录 + * @param {string} uid + */ +async function checkInviteInfo (uid) { + // 检查当前用户是否已有邀请人 + const getUserRes = await userCollection.doc(uid).field({ + my_invite_code: true, + inviter_uid: true + }).get() + const userRecord = getUserRes.data[0] + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + if (userRecord.inviter_uid && userRecord.inviter_uid.length > 0) { + throw { + errCode: ERROR.CHANGE_INVITER_FORBIDDEN + } + } + return userRecord +} + +/** + * 指定用户接受邀请码邀请 + * @param {object} param + * @param {string} param.uid 用户uid + * @param {string} param.inviteCode 邀请人的邀请码 + * @returns + */ +async function acceptInvite ({ + uid, + inviteCode +} = {}) { + await checkInviteInfo(uid) + const { + inviterUid, + inviteTime + } = await generateInviteInfo({ + inviteCode, + queryUid: uid + }) + + if (inviterUid === uid) { + throw { + errCode: ERROR.INVALID_INVITE_CODE + } + } + + // 更新当前用户的邀请人信息 + await userCollection.doc(uid).update({ + inviter_uid: inviterUid, + invite_time: inviteTime + }) + + // 更新当前用户邀请的用户的邀请人信息,这步可能较为耗时 + await userCollection.where({ + inviter_uid: uid + }).update({ + inviter_uid: dbCmd.push(inviterUid) + }) + + return { + errCode: 0, + errMsg: '' + } +} + +module.exports = { + acceptInvite, + generateInviteInfo, + getValidInviteCode +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js new file mode 100644 index 0000000..ea8532d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js @@ -0,0 +1,246 @@ +const { + findUser +} = require('./account') +const { + userCollection, + LOG_TYPE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + logout +} = require('./logout') +const PasswordUtils = require('./password') + +async function realPreLogin (params = {}) { + const { + user + } = params + const appId = this.getUniversalClientInfo().appId + const { + total, + userMatched + } = await findUser({ + userQuery: user, + authorizedApp: appId + }) + if (userMatched.length === 0) { + if (total > 0) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS_IN_CURRENT_APP + } + } + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } else if (userMatched.length > 1) { + throw { + errCode: ERROR.ACCOUNT_CONFLICT + } + } + const userRecord = userMatched[0] + checkLoginUserRecord(userRecord) + return userRecord +} + +async function preLogin (params = {}) { + const { + user + } = params + try { + const user = await realPreLogin.call(this, params) + return user + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + data: user, + type: LOG_TYPE.LOGIN + }) + throw error + } +} + +async function preLoginWithPassword (params = {}) { + const { + user, + password + } = params + try { + const userRecord = await realPreLogin.call(this, params) + const { + passwordErrorLimit, + passwordErrorRetryTime + } = this.config + const { + clientIP + } = this.getUniversalClientInfo() + // 根据ip地址,密码错误次数过多,锁定登录 + let loginIPLimit = userRecord.login_ip_limit || [] + // 清理无用记录 + loginIPLimit = loginIPLimit.filter(item => item.last_error_time > Date.now() - passwordErrorRetryTime * 1000) + let currentIPLimit = loginIPLimit.find(item => item.ip === clientIP) + if (currentIPLimit && currentIPLimit.error_times >= passwordErrorLimit) { + throw { + errCode: ERROR.PASSWORD_ERROR_EXCEED_LIMIT + } + } + const passwordUtils = new PasswordUtils({ + userRecord, + clientInfo: this.getUniversalClientInfo(), + passwordSecret: this.config.passwordSecret + }) + + const { + success: checkPasswordSuccess, + refreshPasswordInfo + } = passwordUtils.checkUserPassword({ + password + }) + if (!checkPasswordSuccess) { + // 更新用户ip对应的密码错误记录 + if (!currentIPLimit) { + currentIPLimit = { + ip: clientIP, + error_times: 1, + last_error_time: Date.now() + } + loginIPLimit.push(currentIPLimit) + } else { + currentIPLimit.error_times++ + currentIPLimit.last_error_time = Date.now() + } + await userCollection.doc(userRecord._id).update({ + login_ip_limit: loginIPLimit + }) + throw { + errCode: ERROR.PASSWORD_ERROR + } + } + const extraData = {} + if (refreshPasswordInfo) { + extraData.password = refreshPasswordInfo.passwordHash + extraData.password_secret_version = refreshPasswordInfo.version + } + + const currentIPLimitIndex = loginIPLimit.indexOf(currentIPLimit) + if (currentIPLimitIndex > -1) { + loginIPLimit.splice(currentIPLimitIndex, 1) + } + extraData.login_ip_limit = loginIPLimit + return { + user: userRecord, + extraData + } + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + data: user, + type: LOG_TYPE.LOGIN + }) + throw error + } +} + +function checkLoginUserRecord (user) { + switch (user.status) { + case undefined: + case 0: + break + case 1: + throw { + errCode: ERROR.ACCOUNT_BANNED + } + case 2: + throw { + errCode: ERROR.ACCOUNT_AUDITING + } + case 3: + throw { + errCode: ERROR.ACCOUNT_AUDIT_FAILED + } + case 4: + throw { + errCode: ERROR.ACCOUNT_CLOSED + } + default: + break + } +} + +async function thirdPartyLogin (params = {}) { + const { + user + } = params + return { + mobileConfirmed: !!user.mobile_confirmed, + emailConfirmed: !!user.email_confirmed + } +} + +async function postLogin (params = {}) { + const { + user, + extraData, + isThirdParty = false + } = params + const { + clientIP + } = this.getUniversalClientInfo() + const uniIdToken = this.getUniversalUniIdToken() + const uid = user._id + const updateData = { + last_login_date: Date.now(), + last_login_ip: clientIP, + ...extraData + } + const createTokenRes = await this.uniIdCommon.createToken({ + uid + }) + + const { + errCode, + token, + tokenExpired + } = createTokenRes + if (errCode) { + throw createTokenRes + } + + if (uniIdToken) { + try { + await logout.call(this) + } catch (error) {} + } + + await userCollection.doc(uid).update(updateData) + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: LOG_TYPE.LOGIN + }) + return { + errCode: 0, + newToken: { + token, + tokenExpired + }, + uid, + ...( + isThirdParty + ? thirdPartyLogin({ + user + }) + : {} + ), + passwordConfirmed: !!user.password + } +} + +module.exports = { + preLogin, + postLogin, + checkLoginUserRecord, + preLoginWithPassword +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/logout.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/logout.js new file mode 100644 index 0000000..ddcbb97 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/logout.js @@ -0,0 +1,49 @@ +const { + dbCmd, + LOG_TYPE, + deviceCollection, + userCollection +} = require('../../common/constants') + +async function logout () { + const { + deviceId + } = this.getUniversalClientInfo() + const uniIdToken = this.getUniversalUniIdToken() + const payload = await this.uniIdCommon.checkToken( + uniIdToken, + { + autoRefresh: false + } + ) + if (payload.errCode) { + throw payload + } + const uid = payload.uid + + // 删除token + await userCollection.doc(uid).update({ + token: dbCmd.pull(uniIdToken) + }) + + // 仅当device表的device_id和user_id均对应时才进行更新 + await deviceCollection.where({ + device_id: deviceId, + user_id: uid + }).update({ + token_expired: 0 + }) + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: LOG_TYPE.LOGOUT + }) + return { + errCode: 0 + } +} + +module.exports = { + logout +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js new file mode 100644 index 0000000..0e46757 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js @@ -0,0 +1,261 @@ +const { + getType +} = require('../../common/utils') +const crypto = require('crypto') +const createConfig = require('uni-config-center') +const shareConfig = createConfig({ + pluginId: 'uni-id' +}) +let customPassword = {} +if (shareConfig.hasFile('custom-password.js')) { + customPassword = shareConfig.requireFile('custom-password.js') || {} +} + +const passwordAlgorithmMap = { + UNI_ID_HMAC_SHA1: 'hmac-sha1', + UNI_ID_HMAC_SHA256: 'hmac-sha256', + UNI_ID_CUSTOM: 'custom' +} + +const passwordAlgorithmKeyMap = Object.keys(passwordAlgorithmMap).reduce((res, item) => { + res[passwordAlgorithmMap[item]] = item + return res +}, {}) + +const passwordExtMethod = { + [passwordAlgorithmMap.UNI_ID_HMAC_SHA1]: { + verify ({ password }) { + const { password_secret_version: passwordSecretVersion } = this.userRecord + + const passwordSecret = this._getSecretByVersion({ + version: passwordSecretVersion + }) + + const { passwordHash } = this.encrypt({ + password, + passwordSecret + }) + + return passwordHash === this.userRecord.password + }, + encrypt ({ password, passwordSecret }) { + const { value: secret, version } = passwordSecret + const hmac = crypto.createHmac('sha1', secret.toString('ascii')) + + hmac.update(password) + + return { + passwordHash: hmac.digest('hex'), + version + } + } + }, + [passwordAlgorithmMap.UNI_ID_HMAC_SHA256]: { + verify ({ password }) { + const parse = this._parsePassword() + const passwordHash = crypto.createHmac(parse.algorithm, parse.salt).update(password).digest('hex') + + return passwordHash === parse.hash + }, + encrypt ({ password, passwordSecret }) { + const { version } = passwordSecret + + // 默认使用 sha256 加密算法 + const salt = crypto.randomBytes(10).toString('hex') + const sha256Hash = crypto.createHmac(passwordAlgorithmMap.UNI_ID_HMAC_SHA256.substring(5), salt).update(password).digest('hex') + const algorithm = passwordAlgorithmKeyMap[passwordAlgorithmMap.UNI_ID_HMAC_SHA256] + // B 为固定值,对应 PasswordMethodMaps 中的 sha256算法 + // hash 格式 $[PasswordMethodFlagMapsKey]$[salt size]$[salt][Hash] + const passwordHash = `$${algorithm}$${salt.length}$${salt}${sha256Hash}` + + return { + passwordHash, + version + } + } + }, + [passwordAlgorithmMap.UNI_ID_CUSTOM]: { + verify ({ password, passwordSecret }) { + if (!customPassword.verifyPassword) throw new Error('verifyPassword method not found in custom password file') + + // return true or false + return customPassword.verifyPassword({ + password, + passwordSecret, + userRecord: this.userRecord, + clientInfo: this.clientInfo + }) + }, + encrypt ({ password, passwordSecret }) { + if (!customPassword.encryptPassword) throw new Error('encryptPassword method not found in custom password file') + + // return object<{passwordHash: string, version: number}> + return customPassword.encryptPassword({ + password, + passwordSecret, + clientInfo: this.clientInfo + }) + } + } +} + +class PasswordUtils { + constructor ({ + userRecord = {}, + clientInfo, + passwordSecret + } = {}) { + if (!clientInfo) throw new Error('Invalid clientInfo') + if (!passwordSecret) throw new Error('Invalid password secret') + + this.clientInfo = clientInfo + this.userRecord = userRecord + this.passwordSecret = this.prePasswordSecret(passwordSecret) + } + + /** + * passwordSecret 预处理 + * @param passwordSecret + * @return {*[]} + */ + prePasswordSecret (passwordSecret) { + const newPasswordSecret = [] + if (getType(passwordSecret) === 'string') { + newPasswordSecret.push({ + value: passwordSecret, + type: passwordAlgorithmMap.UNI_ID_HMAC_SHA1 + }) + } else if (getType(passwordSecret) === 'array') { + for (const secret of passwordSecret.sort((a, b) => a.version - b.version)) { + newPasswordSecret.push({ + ...secret, + // 没有 type 设置默认 type hmac-sha1 + type: secret.type || passwordAlgorithmMap.UNI_ID_HMAC_SHA1 + }) + } + } else { + throw new Error('Invalid password secret') + } + + return newPasswordSecret + } + + /** + * 获取最新加密密钥 + * @return {*} + * @private + */ + _getLastestSecret () { + return this.passwordSecret[this.passwordSecret.length - 1] + } + + _getOldestSecret () { + return this.passwordSecret[0] + } + + _getSecretByVersion ({ version } = {}) { + if (!version && version !== 0) { + return this._getOldestSecret() + } + if (this.passwordSecret.length === 1) { + return this.passwordSecret[0] + } + return this.passwordSecret.find(item => item.version === version) + } + + /** + * 获取密码的验证/加密方法 + * @param passwordSecret + * @return {*[]} + * @private + */ + _getPasswordExt (passwordSecret) { + const ext = passwordExtMethod[passwordSecret.type] + if (!ext) { + throw new Error(`暂不支持 ${passwordSecret.type} 类型的加密算法`) + } + + const passwordExt = Object.create(null) + + for (const key in ext) { + passwordExt[key] = ext[key].bind(Object.assign(this, Object.keys(ext).reduce((res, item) => { + if (item !== key) { + res[item] = ext[item].bind(this) + } + return res + }, {}))) + } + + return passwordExt + } + + _parsePassword () { + const [algorithmKey = '', cost = 0, hashStr = ''] = this.userRecord.password.split('$').filter(key => key) + const algorithm = passwordAlgorithmMap[algorithmKey] ? passwordAlgorithmMap[algorithmKey].substring(5) : null + const salt = hashStr.substring(0, Number(cost)) + const hash = hashStr.substring(Number(cost)) + + return { + algorithm, + salt, + hash + } + } + + /** + * 生成加密后的密码 + * @param {String} password 密码 + */ + generatePasswordHash ({ password }) { + if (!password) throw new Error('Invalid password') + + const passwordSecret = this._getLastestSecret() + const ext = this._getPasswordExt(passwordSecret) + + const { passwordHash, version } = ext.encrypt({ + password, + passwordSecret + }) + + return { + passwordHash, + version + } + } + + /** + * 密码校验 + * @param {String} password + * @param {Boolean} autoRefresh + * @return {{refreshPasswordInfo: {version: *, passwordHash: *}, success: boolean}|{success: boolean}} + */ + checkUserPassword ({ password, autoRefresh = true }) { + if (!password) throw new Error('Invalid password') + + const { password_secret_version: passwordSecretVersion } = this.userRecord + const passwordSecret = this._getSecretByVersion({ + version: passwordSecretVersion + }) + const ext = this._getPasswordExt(passwordSecret) + + const success = ext.verify({ password, passwordSecret }) + + if (!success) { + return { + success: false + } + } + + let refreshPasswordInfo + if (autoRefresh && passwordSecretVersion !== this._getLastestSecret().version) { + refreshPasswordInfo = this.generatePasswordHash({ password }) + } + + return { + success: true, + refreshPasswordInfo + } + } +} + +module.exports = PasswordUtils diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/qq.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/qq.js new file mode 100644 index 0000000..7ea612d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/qq.js @@ -0,0 +1,152 @@ +const { + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +function getQQPlatform () { + const platform = this.clientPlatform + switch (platform) { + case 'app': + case 'app-plus': + return 'app' + case 'mp-qq': + return 'mp' + default: + throw new Error('Unsupported qq platform') + } +} + +async function saveQQUserKey ({ + openid, + sessionKey, // QQ小程序用户sessionKey + accessToken, // App端QQ用户accessToken + accessTokenExpired // App端QQ用户accessToken过期时间 +} = {}) { + // 微信公众平台、开放平台refreshToken有效期均为30天(微信没有在网络请求里面返回30天这个值,务必注意未来可能出现调整,需及时更新此处逻辑)。 + // 此前QQ开放平台有调整过accessToken的过期时间:[access_token有效期由90天缩短至30天](https://wiki.connect.qq.com/%E3%80%90qq%E4%BA%92%E8%81%94%E3%80%91access_token%E6%9C%89%E6%95%88%E6%9C%9F%E8%B0%83%E6%95%B4) + const appId = this.getUniversalClientInfo().appId + const qqPlatform = getQQPlatform.call(this) + const keyObj = { + dcloudAppid: appId, + openid, + platform: 'qq-' + qqPlatform + } + switch (qqPlatform) { + case 'mp': + await this.uniOpenBridge.setSessionKey(keyObj, { + session_key: sessionKey + }, 30 * 24 * 60 * 60) + break + case 'app': + case 'h5': + case 'web': + await this.uniOpenBridge.setUserAccessToken(keyObj, { + access_token: accessToken, + access_token_expired: accessTokenExpired + }, accessTokenExpired + ? Math.floor((accessTokenExpired - Date.now()) / 1000) + : 30 * 24 * 60 * 60 + ) + break + default: + break + } +} + +function generateQQCache ({ + sessionKey, // QQ小程序用户sessionKey + accessToken, // App端QQ用户accessToken + accessTokenExpired // App端QQ用户accessToken过期时间 +} = {}) { + const platform = getQQPlatform.call(this) + let cache + switch (platform) { + case 'app': + cache = { + access_token: accessToken, + access_token_expired: accessTokenExpired + } + break + case 'mp': + cache = { + session_key: sessionKey + } + break + default: + throw new Error('Unsupported qq platform') + } + return { + third_party: { + [`${platform}_qq`]: cache + } + } +} + +function getQQOpenid ({ + userRecord +} = {}) { + const qqPlatform = getQQPlatform.call(this) + const appId = this.getUniversalClientInfo().appId + const qqOpenidObj = userRecord.qq_openid + if (!qqOpenidObj) { + return + } + return qqOpenidObj[`${qqPlatform}_${appId}`] || qqOpenidObj[qqPlatform] +} + +async function getQQCacheFallback ({ + userRecord, + key +} = {}) { + const platform = getQQPlatform.call(this) + const thirdParty = userRecord && userRecord.third_party + if (!thirdParty) { + return + } + const qqCache = thirdParty[`${platform}_qq`] + return qqCache && qqCache[key] +} + +async function getQQCache ({ + uid, + userRecord, + key +} = {}) { + const qqPlatform = getQQPlatform.call(this) + const appId = this.getUniversalClientInfo().appId + + if (!userRecord) { + const getUserRes = await userCollection.doc(uid).get() + userRecord = getUserRes.data[0] + } + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + const openid = getQQOpenid.call(this, { + userRecord + }) + const getCacheMethod = qqPlatform === 'mp' ? 'getSessionKey' : 'getUserAccessToken' + const userKey = await this.uniOpenBridge[getCacheMethod]({ + dcloudAppid: appId, + platform: 'qq-' + qqPlatform, + openid + }) + if (userKey) { + return userKey[key] + } + return getQQCacheFallback({ + userRecord, + key + }) +} + +module.exports = { + getQQPlatform, + generateQQCache, + getQQCache, + saveQQUserKey +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js new file mode 100644 index 0000000..d937610 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js @@ -0,0 +1,229 @@ +const { + userCollection, + LOG_TYPE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + findUser +} = require('./account') +const { + getValidInviteCode, + generateInviteInfo +} = require('./fission') +const { + logout +} = require('./logout') +const PasswordUtils = require('./password') +const merge = require('lodash.merge') + +async function realPreRegister (params = {}) { + const { + user + } = params + const { + userMatched + } = await findUser({ + userQuery: user, + authorizedApp: this.getUniversalClientInfo().appId + }) + if (userMatched.length > 0) { + throw { + errCode: ERROR.ACCOUNT_EXISTS + } + } +} + +async function preRegister (params = {}) { + try { + await realPreRegister.call(this, params) + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.REGISTER + }) + throw error + } +} + +async function preRegisterWithPassword (params = {}) { + const { + user, + password + } = params + await preRegister.call(this, { + user + }) + const passwordUtils = new PasswordUtils({ + clientInfo: this.getUniversalClientInfo(), + passwordSecret: this.config.passwordSecret + }) + const { + passwordHash, + version + } = passwordUtils.generatePasswordHash({ + password + }) + const extraData = { + password: passwordHash, + password_secret_version: version + } + return { + user, + extraData + } +} + +async function thirdPartyRegister ({ + user = {} +} = {}) { + return { + mobileConfirmed: !!(user.mobile && user.mobile_confirmed) || false, + emailConfirmed: !!(user.email && user.email_confirmed) || false + } +} + +async function postRegister (params = {}) { + const { + user, + extraData = {}, + isThirdParty = false, + inviteCode + } = params + const { + appId, + appName, + appVersion, + appVersionCode, + channel, + scene, + clientIP, + osName + } = this.getUniversalClientInfo() + const uniIdToken = this.getUniversalUniIdToken() + + merge(user, extraData) + + const registerChannel = channel || scene + user.register_env = { + appid: appId || '', + uni_platform: this.clientPlatform || '', + os_name: osName || '', + app_name: appName || '', + app_version: appVersion || '', + app_version_code: appVersionCode || '', + channel: registerChannel ? registerChannel + '' : '', // channel可能为数字,统一存为字符串 + client_ip: clientIP || '' + } + + user.register_date = Date.now() + user.dcloud_appid = [appId] + + if (user.username) { + user.username = user.username.toLowerCase() + } + if (user.email) { + user.email = user.email.toLowerCase() + } + + const { + autoSetInviteCode, // 注册时自动设置邀请码 + forceInviteCode, // 必须有邀请码才允许注册,注意此逻辑不可对admin生效 + userRegisterDefaultRole // 用户注册时配置的默认角色 + } = this.config + if (autoSetInviteCode) { + user.my_invite_code = await getValidInviteCode() + } + + // 如果用户注册默认角色配置存在且不为空数组 + if (userRegisterDefaultRole && userRegisterDefaultRole.length) { + // 将用户已有的角色和配置的默认角色合并成一个数组,并去重 + user.role = Array.from(new Set([...(user.role || []), ...userRegisterDefaultRole])) + } + + const isAdmin = user.role && user.role.includes('admin') + + if (forceInviteCode && !isAdmin && !inviteCode) { + throw { + errCode: ERROR.INVALID_INVITE_CODE + } + } + + if (inviteCode) { + const { + inviterUid, + inviteTime + } = await generateInviteInfo({ + inviteCode + }) + user.inviter_uid = inviterUid + user.invite_time = inviteTime + } + + if (uniIdToken) { + try { + await logout.call(this) + } catch (error) { } + } + + const beforeRegister = this.hooks.beforeRegister + let userRecord = user + if (beforeRegister) { + userRecord = await beforeRegister({ + userRecord, + clientInfo: this.getUniversalClientInfo() + }) + } + + const { + id: uid + } = await userCollection.add(userRecord) + + const createTokenRes = await this.uniIdCommon.createToken({ + uid + }) + + const { + errCode, + token, + tokenExpired + } = createTokenRes + + if (errCode) { + throw createTokenRes + } + + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: LOG_TYPE.REGISTER + }) + + return { + errCode: 0, + uid, + newToken: { + token, + tokenExpired + }, + ...( + isThirdParty + ? thirdPartyRegister({ + user: { + ...userRecord, + _id: uid + } + }) + : {} + ), + passwordConfirmed: !!userRecord.password + } +} + +module.exports = { + preRegister, + preRegisterWithPassword, + postRegister +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/relate.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/relate.js new file mode 100644 index 0000000..8431551 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/relate.js @@ -0,0 +1,164 @@ +const { + findUser +} = require('./account') +const { + ERROR +} = require('../../common/error') +const { + userCollection, dbCmd, USER_IDENTIFIER +} = require('../../common/constants') +const { + getUserIdentifier +} = require('../../lib/utils/account') + +const { + batchFindObjctValue +} = require('../../common/utils') +const merge = require('lodash.merge') + +/** + * + * @param {object} param + * @param {string} param.uid 用户id + * @param {string} param.bindAccount 要绑定的三方账户、手机号或邮箱 + */ +async function preBind ({ + uid, + bindAccount, + logType +} = {}) { + const { + userMatched + } = await findUser({ + userQuery: bindAccount, + authorizedApp: this.getUniversalClientInfo().appId + }) + if (userMatched.length > 0) { + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: logType, + success: false + }) + throw { + errCode: ERROR.BIND_CONFLICT + } + } +} + +async function postBind ({ + uid, + extraData = {}, + bindAccount, + logType +} = {}) { + await userCollection.doc(uid).update(merge(bindAccount, extraData)) + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: logType + }) + return { + errCode: 0 + } +} + +async function preUnBind ({ + uid, + unBindAccount, + logType +}) { + const notUnBind = ['username', 'mobile', 'email'] + const userIdentifier = getUserIdentifier(unBindAccount) + const condition = Object.keys(userIdentifier).reduce((res, key) => { + if (userIdentifier[key]) { + if (notUnBind.includes(key)) { + throw { + errCode: ERROR.UNBIND_NOT_SUPPORTED + } + } + + res.push({ + [key]: userIdentifier[key] + }) + } + + return res + }, []) + const currentUnBindAccount = Object.keys(userIdentifier).reduce((res, key) => { + if (userIdentifier[key]) { + res.push(key) + } + return res + }, []) + const { data: users } = await userCollection.where(dbCmd.and( + { _id: uid }, + dbCmd.or(condition) + )).get() + + if (users.length <= 0) { + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: logType, + success: false + }) + throw { + errCode: ERROR.UNBIND_FAIL + } + } + + const [user] = users + const otherAccounts = batchFindObjctValue(user, Object.keys(USER_IDENTIFIER).filter(key => !notUnBind.includes(key) && !currentUnBindAccount.includes(key))) + let hasOtherAccountBind = false + + for (const key in otherAccounts) { + if (otherAccounts[key]) { + hasOtherAccountBind = true + break + } + } + + // 如果没有其他第三方登录方式 + if (!hasOtherAccountBind) { + // 存在用户名或者邮箱但是没有设置过没密码就提示设置密码 + if ((user.username || user.email) && !user.password) { + throw { + errCode: ERROR.UNBIND_PASSWORD_NOT_EXISTS + } + } + // 账号任何登录方式都没有就优先绑定手机号 + if (!user.mobile) { + throw { + errCode: ERROR.UNBIND_MOBILE_NOT_EXISTS + } + } + } +} + +async function postUnBind ({ + uid, + unBindAccount, + logType +}) { + await userCollection.doc(uid).update(unBindAccount) + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: logType + }) + return { + errCode: 0 + } +} + +module.exports = { + preBind, + postBind, + preUnBind, + postUnBind +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/sms.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/sms.js new file mode 100644 index 0000000..ae9b7af --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/sms.js @@ -0,0 +1,79 @@ +const { + setMobileVerifyCode +} = require('./verify-code') +const { + getVerifyCode +} = require('../../common/utils') + +/** + * 发送短信 + * @param {object} param + * @param {string} param.mobile 手机号 + * @param {object} param.code 可选,验证码 + * @param {object} param.scene 短信场景 + * @param {object} param.templateId 可选,短信模板id + * @returns + */ +async function sendSmsCode ({ + mobile, + code, + scene, + templateId +} = {}) { + const requiredParams = [ + 'name', + 'codeExpiresIn' + ] + const smsConfig = (this.config.service && this.config.service.sms) || {} + for (let i = 0; i < requiredParams.length; i++) { + const key = requiredParams[i] + if (!smsConfig[key]) { + throw new Error(`Missing config param: service.sms.${key}`) + } + } + if (!code) { + code = getVerifyCode() + } + let action + switch (scene) { + case 'login-by-sms': + action = this.t('login') + break + default: + action = this.t('verify-mobile') + break + } + const sceneConfig = (smsConfig.scene || {})[scene] || {} + if (!templateId) { + templateId = sceneConfig.templateId + } + if (!templateId) { + throw new Error('"templateId" is required') + } + const codeExpiresIn = sceneConfig.codeExpiresIn || smsConfig.codeExpiresIn + await setMobileVerifyCode.call(this, { + mobile, + code, + expiresIn: codeExpiresIn, + scene + }) + await uniCloud.sendSms({ + smsKey: smsConfig.smsKey, + smsSecret: smsConfig.smsSecret, + phone: mobile, + templateId, + data: { + name: smsConfig.name, + code, + action, + expMinute: '' + Math.round(codeExpiresIn / 60) + } + }) + return { + errCode: 0 + } +} + +module.exports = { + sendSmsCode +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/unified-login.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/unified-login.js new file mode 100644 index 0000000..eac7a51 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/unified-login.js @@ -0,0 +1,106 @@ +const { + checkLoginUserRecord, + postLogin +} = require('./login') +const { + postRegister +} = require('./register') +const { + findUser +} = require('./account') +const { + ERROR +} = require('../../common/error') + +async function realPreUnifiedLogin (params = {}) { + const { + user, + type + } = params + const appId = this.getUniversalClientInfo().appId + const { + total, + userMatched + } = await findUser({ + userQuery: user, + authorizedApp: appId + }) + if (userMatched.length === 0) { + if (type === 'login') { + if (total > 0) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS_IN_CURRENT_APP + } + } + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + return { + type: 'register', + user + } + } if (userMatched.length === 1) { + if (type === 'register') { + throw { + errCode: ERROR.ACCOUNT_EXISTS + } + } + const userRecord = userMatched[0] + checkLoginUserRecord(userRecord) + return { + type: 'login', + user: userRecord + } + } else if (userMatched.length > 1) { + throw { + errCode: ERROR.ACCOUNT_CONFLICT + } + } +} + +async function preUnifiedLogin (params = {}) { + try { + const result = await realPreUnifiedLogin.call(this, params) + return result + } catch (error) { + await this.middleware.uniIdLog({ + success: false + }) + throw error + } +} + +async function postUnifiedLogin (params = {}) { + const { + user, + extraData = {}, + isThirdParty = false, + type, + inviteCode + } = params + let result + if (type === 'login') { + result = await postLogin.call(this, { + user, + extraData, + isThirdParty + }) + } else if (type === 'register') { + result = await postRegister.call(this, { + user, + extraData, + isThirdParty, + inviteCode + }) + } + return { + ...result, + type + } +} + +module.exports = { + preUnifiedLogin, + postUnifiedLogin +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/univerify.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/univerify.js new file mode 100644 index 0000000..b64bef9 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/univerify.js @@ -0,0 +1,27 @@ +async function getPhoneNumber ({ + // eslint-disable-next-line camelcase + access_token, + openid +} = {}) { + const requiredParams = [] + const univerifyConfig = (this.config.service && this.config.service.univerify) || {} + for (let i = 0; i < requiredParams.length; i++) { + const key = requiredParams[i] + if (!univerifyConfig[key]) { + throw new Error(`Missing config param: service.univerify.${key}`) + } + } + return uniCloud.getPhoneNumber({ + provider: 'univerify', + appid: this.getUniversalClientInfo().appId, + apiKey: univerifyConfig.apiKey, + apiSecret: univerifyConfig.apiSecret, + // eslint-disable-next-line camelcase + access_token, + openid + }) +} + +module.exports = { + getPhoneNumber +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/update-user-info.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/update-user-info.js new file mode 100644 index 0000000..ced33b9 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/update-user-info.js @@ -0,0 +1,25 @@ +const { + userCollection +} = require('../../common/constants') +const { + USER_STATUS +} = require('../../common/constants') +async function setUserStatus (uid, status) { + const updateData = { + status + } + if (status !== USER_STATUS.NORMAL) { + updateData.valid_token_date = Date.now() + } + await userCollection.doc(uid).update({ + status + }) + // TODO 此接口尚不完善,例如注销后其他客户端可能存在有效token,支持Redis后此处会补充额外逻辑 + return { + errCode: 0 + } +} + +module.exports = { + setUserStatus +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/utils.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/utils.js new file mode 100644 index 0000000..7d3e0f3 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/utils.js @@ -0,0 +1,18 @@ +let redisEnable = null +function getRedisEnable() { + // 未用到的时候不调用redis接口,节省一些连接数 + if (redisEnable !== null) { + return redisEnable + } + try { + uniCloud.redis() + redisEnable = true + } catch (error) { + redisEnable = false + } + return redisEnable +} + +module.exports = { + getRedisEnable +} \ No newline at end of file diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/verify-code.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/verify-code.js new file mode 100644 index 0000000..b11bc02 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/verify-code.js @@ -0,0 +1,152 @@ +const { + dbCmd, + verifyCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + getVerifyCode +} = require('../../common/utils') + +async function setVerifyCode ({ + mobile, + email, + code, + expiresIn, + scene +} = {}) { + const now = Date.now() + const record = { + mobile, + email, + scene, + code: code || getVerifyCode(), + state: 0, + ip: this.getUniversalClientInfo().clientIP, + created_date: now, + expired_date: now + expiresIn * 1000 + } + await verifyCollection.add(record) + return { + errCode: 0 + } +} + +async function setEmailVerifyCode ({ + email, + code, + expiresIn, + scene +} = {}) { + email = email && email.trim() + if (!email) { + throw { + errCode: ERROR.INVALID_EMAIL + } + } + email = email.toLowerCase() + return setVerifyCode.call(this, { + email, + code, + expiresIn, + scene + }) +} + +async function setMobileVerifyCode ({ + mobile, + code, + expiresIn, + scene +} = {}) { + mobile = mobile && mobile.trim() + if (!mobile) { + throw { + errCode: ERROR.INVALID_MOBILE + } + } + return setVerifyCode.call(this, { + mobile, + code, + expiresIn, + scene + }) +} + +async function verifyEmailCode ({ + email, + code, + scene +} = {}) { + email = email && email.trim() + if (!email) { + throw { + errCode: ERROR.INVALID_EMAIL + } + } + email = email.toLowerCase() + const { + data: codeRecord + } = await verifyCollection.where({ + email, + scene, + code, + state: 0, + expired_date: dbCmd.gt(Date.now()) + }).limit(1).get() + + if (codeRecord.length === 0) { + throw { + errCode: ERROR.EMAIL_VERIFY_CODE_ERROR + } + } + await verifyCollection.doc(codeRecord[0]._id).update({ + state: 1 + }) + return { + errCode: 0 + } +} + +async function verifyMobileCode ({ + mobile, + code, + scene +} = {}) { + mobile = mobile && mobile.trim() + if (!mobile) { + throw { + errCode: ERROR.INVALID_MOBILE + } + } + const { + data: codeRecord + } = await verifyCollection.where({ + mobile, + scene, + code, + state: 0, + expired_date: dbCmd.gt(Date.now()) + }).limit(1).get() + + if (codeRecord.length === 0) { + throw { + errCode: ERROR.MOBILE_VERIFY_CODE_ERROR + } + } + + await verifyCollection.doc(codeRecord[0]._id).update({ + state: 1 + }) + return { + errCode: 0 + } +} + +module.exports = { + verifyEmailCode, + verifyMobileCode, + setEmailVerifyCode, + setMobileVerifyCode +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/weixin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/weixin.js new file mode 100644 index 0000000..98eb370 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/weixin.js @@ -0,0 +1,234 @@ +const crypto = require('crypto') +const { + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + getRedisEnable +} = require('./utils') +const { + openDataCollection +} = require('../../common/constants') + +function decryptWeixinData ({ + encryptedData, + sessionKey, + iv +} = {}) { + const oauthConfig = this.configUtils.getOauthConfig({ + provider: 'weixin' + }) + const decipher = crypto.createDecipheriv( + 'aes-128-cbc', + Buffer.from(sessionKey, 'base64'), + Buffer.from(iv, 'base64') + ) + // 设置自动 padding 为 true,删除填充补位 + decipher.setAutoPadding(true) + let decoded + decoded = decipher.update(encryptedData, 'base64', 'utf8') + decoded += decipher.final('utf8') + decoded = JSON.parse(decoded) + if (decoded.watermark.appid !== oauthConfig.appid) { + throw new Error('Invalid wechat appid in decode content') + } + return decoded +} + +function getWeixinPlatform () { + const platform = this.clientPlatform + const userAgent = this.getUniversalClientInfo().userAgent + switch (platform) { + case 'app': + case 'app-plus': + return 'app' + case 'mp-weixin': + return 'mp' + case 'h5': + case 'web': + return userAgent.indexOf('MicroMessenger') > -1 ? 'h5' : 'web' + default: + throw new Error('Unsupported weixin platform') + } +} + +async function saveWeixinUserKey ({ + openid, + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + accessTokenExpired // App端微信用户accessToken过期时间 +} = {}) { + // 微信公众平台、开放平台refreshToken有效期均为30天(微信没有在网络请求里面返回30天这个值,务必注意未来可能出现调整,需及时更新此处逻辑)。 + // 此前QQ开放平台有调整过accessToken的过期时间:[access_token有效期由90天缩短至30天](https://wiki.connect.qq.com/%E3%80%90qq%E4%BA%92%E8%81%94%E3%80%91access_token%E6%9C%89%E6%95%88%E6%9C%9F%E8%B0%83%E6%95%B4) + + const appId = this.getUniversalClientInfo().appId + const weixinPlatform = getWeixinPlatform.call(this) + const keyObj = { + dcloudAppid: appId, + openid, + platform: 'weixin-' + weixinPlatform + } + switch (weixinPlatform) { + case 'mp': + await this.uniOpenBridge.setSessionKey(keyObj, { + session_key: sessionKey + }, 30 * 24 * 60 * 60) + break + case 'app': + case 'h5': + case 'web': + await this.uniOpenBridge.setUserAccessToken(keyObj, { + access_token: accessToken, + refresh_token: refreshToken, + access_token_expired: accessTokenExpired + }, 30 * 24 * 60 * 60) + break + default: + break + } +} + +async function saveSecureNetworkCache ({ + code, + openid, + unionid, + sessionKey +}) { + const { + appId + } = this.getUniversalClientInfo() + const key = `uni-id:${appId}:weixin-mp:code:${code}:secure-network-cache` + const value = JSON.stringify({ + openid, + unionid, + session_key: sessionKey + }) + // 此处存储的是code的缓存,设置有效期和token一致 + const expiredSeconds = this.config.tokenExpiresIn || 3 * 24 * 60 * 60 + + await openDataCollection.doc(key).set({ + value, + expired: Date.now() + expiredSeconds * 1000 + }) + const isRedisEnable = getRedisEnable() + if (isRedisEnable) { + const redis = uniCloud.redis() + await redis.set(key, value, 'EX', expiredSeconds) + } +} + +function generateWeixinCache ({ + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + accessTokenExpired // App端微信用户accessToken过期时间 +} = {}) { + const platform = getWeixinPlatform.call(this) + let cache + switch (platform) { + case 'app': + case 'h5': + case 'web': + cache = { + access_token: accessToken, + refresh_token: refreshToken, + access_token_expired: accessTokenExpired + } + break + case 'mp': + cache = { + session_key: sessionKey + } + break + default: + throw new Error('Unsupported weixin platform') + } + return { + third_party: { + [`${platform}_weixin`]: cache + } + } +} + +function getWeixinOpenid ({ + userRecord +} = {}) { + const weixinPlatform = getWeixinPlatform.call(this) + const appId = this.getUniversalClientInfo().appId + const wxOpenidObj = userRecord.wx_openid + if (!wxOpenidObj) { + return + } + return wxOpenidObj[`${weixinPlatform}_${appId}`] || wxOpenidObj[weixinPlatform] +} + +async function getWeixinCacheFallback ({ + userRecord, + key +} = {}) { + const platform = getWeixinPlatform.call(this) + const thirdParty = userRecord && userRecord.third_party + if (!thirdParty) { + return + } + const weixinCache = thirdParty[`${platform}_weixin`] + return weixinCache && weixinCache[key] +} + +async function getWeixinCache ({ + uid, + userRecord, + key +} = {}) { + const weixinPlatform = getWeixinPlatform.call(this) + const appId = this.getUniversalClientInfo().appId + if (!userRecord) { + const getUserRes = await userCollection.doc(uid).get() + userRecord = getUserRes.data[0] + } + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + const openid = getWeixinOpenid.call(this, { + userRecord + }) + const getCacheMethod = weixinPlatform === 'mp' ? 'getSessionKey' : 'getUserAccessToken' + const userKey = await this.uniOpenBridge[getCacheMethod]({ + dcloudAppid: appId, + platform: 'weixin-' + weixinPlatform, + openid + }) + if (userKey) { + return userKey[key] + } + return getWeixinCacheFallback({ + userRecord, + key + }) +} + +async function getWeixinAccessToken () { + const weixinPlatform = getWeixinPlatform.call(this) + const appId = this.getUniversalClientInfo().appId + + const cache = await this.uniOpenBridge.getAccessToken({ + dcloudAppid: appId, + platform: 'weixin-' + weixinPlatform + }) + + return cache.access_token +} +module.exports = { + decryptWeixinData, + getWeixinPlatform, + generateWeixinCache, + getWeixinCache, + saveWeixinUserKey, + getWeixinAccessToken, + saveSecureNetworkCache +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/access-control.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/access-control.js new file mode 100644 index 0000000..e333fe0 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/access-control.js @@ -0,0 +1,59 @@ +const methodPermission = require('../config/permission') +const { + ERROR +} = require('../common/error') + +function isAccessAllowed (user, setting) { + const { + role: userRole = [], + permission: userPermission = [] + } = user + const { + role: settingRole = [], + permission: settingPermission = [] + } = setting + if (userRole.includes('admin')) { + return + } + if ( + settingRole.length > 0 && + settingRole.every(item => !userRole.includes(item)) + ) { + throw { + errCode: ERROR.PERMISSION_ERROR + } + } + if ( + settingPermission.length > 0 && + settingPermission.every(item => !userPermission.includes(item)) + ) { + throw { + errCode: ERROR.PERMISSION_ERROR + } + } +} + +module.exports = async function () { + const methodName = this.getMethodName() + if (!(methodName in methodPermission)) { + return + } + const { + auth, + role, + permission + } = methodPermission[methodName] + if (auth || role || permission) { + await this.middleware.auth() + } + if (role && role.length === 0) { + throw new Error('[AccessControl]Empty role array is not supported') + } + if (permission && permission.length === 0) { + throw new Error('[AccessControl]Empty permission array is not supported') + } + return isAccessAllowed(this.authInfo, { + role, + permission + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/auth.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/auth.js new file mode 100644 index 0000000..1915335 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/auth.js @@ -0,0 +1,17 @@ +module.exports = async function () { + if (this.authInfo) { // 多次执行auth时如果第一次成功后续不再执行 + return + } + const token = this.getUniversalUniIdToken() + const payload = await this.uniIdCommon.checkToken(token) + if (payload.errCode) { + throw payload + } + this.authInfo = payload + if (payload.token) { + this.response.newToken = { + token: payload.token, + tokenExpired: payload.tokenExpired + } + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/index.js new file mode 100644 index 0000000..9f7c958 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/index.js @@ -0,0 +1,8 @@ +module.exports = { + auth: require('./auth'), + uniIdLog: require('./uni-id-log'), + validate: require('./validate'), + accessControl: require('./access-control'), + verifyRequestSign: require('./verify-request-sign'), + ...require('./rbac') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/rbac.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/rbac.js new file mode 100644 index 0000000..f42ef8d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/rbac.js @@ -0,0 +1,39 @@ +const { + ERROR +} = require('../common/error') + +function hasRole (...roleList) { + const userRole = this.authInfo.role || [] + if (userRole.includes('admin')) { + return + } + const isMatch = roleList.every(roleItem => { + return userRole.includes(roleItem) + }) + if (!isMatch) { + throw { + errCode: ERROR.PERMISSION_ERROR + } + } +} + +function hasPermission (...permissionList) { + const userRole = this.authInfo.role || [] + const userPermission = this.authInfo.permission || [] + if (userRole.includes('admin')) { + return + } + const isMatch = permissionList.every(permissionItem => { + return userPermission.includes(permissionItem) + }) + if (!isMatch) { + throw { + errCode: ERROR.PERMISSION_ERROR + } + } +} + +module.exports = { + hasRole, + hasPermission +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/uni-id-log.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/uni-id-log.js new file mode 100644 index 0000000..ca6927d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/uni-id-log.js @@ -0,0 +1,39 @@ +const db = uniCloud.database() +module.exports = async function ({ + data = {}, + success = true, + type = 'login' +} = {}) { + const now = Date.now() + const uniIdLogCollection = db.collection('uni-id-log') + const requiredDataKeyList = ['user_id', 'username', 'email', 'mobile'] + const dataCopy = {} + for (let i = 0; i < requiredDataKeyList.length; i++) { + const key = requiredDataKeyList[i] + if (key in data && typeof data[key] === 'string') { + dataCopy[key] = data[key] + } + } + const { + appId, + clientIP, + deviceId, + userAgent + } = this.getUniversalClientInfo() + const logData = { + appid: appId, + device_id: deviceId, + ip: clientIP, + type, + ua: userAgent, + create_date: now, + ...dataCopy + } + + if (success) { + logData.state = 1 + } else { + logData.state = 0 + } + return uniIdLogCollection.add(logData) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/validate.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/validate.js new file mode 100644 index 0000000..52ff047 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/validate.js @@ -0,0 +1,7 @@ +module.exports = function (value = {}, schema = {}) { + const validateRes = this.validator.validate(value, schema) + if (validateRes) { + delete validateRes.schemaKey + throw validateRes + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/verify-request-sign.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/verify-request-sign.js new file mode 100644 index 0000000..56e421a --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/middleware/verify-request-sign.js @@ -0,0 +1,85 @@ +const crypto = require('crypto') +const createConfig = require('uni-config-center') +const { verifyHttpInfo } = require('uni-cloud-s2s') + +const { ERROR } = require('../common/error') +const s2sConfig = createConfig({ + pluginId: 'uni-cloud-s2s' +}) +const needSignFunctions = new Set([ + 'externalRegister', + 'externalLogin', + 'updateUserInfoByExternal' +]) + +module.exports = function () { + const methodName = this.getMethodName() + const { source } = this.getUniversalClientInfo() + + // 指定接口需要鉴权 + if (!needSignFunctions.has(methodName)) return + + // 非 HTTP 方式请求拒绝访问 + if (source !== 'http') { + throw { + errCode: ERROR.ILLEGAL_REQUEST + } + } + + // 支持 uni-cloud-s2s 验证请求 + if (s2sConfig.hasFile('config.json')) { + try { + if (!verifyHttpInfo(this.getHttpInfo())) { + throw { + errCode: ERROR.ILLEGAL_REQUEST + } + } + } catch (e) { + if (e.errSubject === 'uni-cloud-s2s') { + throw { + errCode: ERROR.ILLEGAL_REQUEST, + errMsg: e.errMsg + } + } + throw e + } + + return + } + + if (!this.config.requestAuthSecret || typeof this.config.requestAuthSecret !== 'string') { + throw { + errCode: ERROR.CONFIG_FIELD_REQUIRED, + errMsgValue: { + field: 'requestAuthSecret' + } + } + } + + const timeout = 20 * 1000 // 请求超过20秒不能再请求,防止重放攻击 + const { headers, body: _body } = this.getHttpInfo() + const { 'uni-id-nonce': nonce, 'uni-id-timestamp': timestamp, 'uni-id-signature': signature } = headers + const body = JSON.parse(_body).params || {} + const bodyStr = Object.keys(body) + .sort() + .filter(item => typeof body[item] !== 'object') + .map(item => `${item}=${body[item]}`) + .join('&') + + if (isNaN(Number(timestamp)) || (Number(timestamp) + timeout) < Date.now()) { + console.error('[timestamp error], timestamp:', timestamp, 'timeout:', timeout) + + throw { + errCode: ERROR.ILLEGAL_REQUEST + } + } + + const reSignature = crypto.createHmac('sha256', `${this.config.requestAuthSecret + nonce}`).update(`${timestamp}${bodyStr}`).digest('hex') + + if (signature !== reSignature.toUpperCase()) { + console.error('[signature error], signature:', signature, 'reSignature:', reSignature.toUpperCase(), 'requestAuthSecret:', this.config.requestAuthSecret) + throw { + errCode: ERROR.ILLEGAL_REQUEST + } + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/close-account.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/close-account.js new file mode 100644 index 0000000..f1bdf96 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/close-account.js @@ -0,0 +1,16 @@ +const { + setUserStatus +} = require('../../lib/utils/update-user-info') +const { + USER_STATUS +} = require('../../common/constants') + +/** + * 注销账户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#close-account + * @returns + */ +module.exports = async function () { + const { uid } = this.authInfo + return setUserStatus(uid, USER_STATUS.CLOSED) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/get-account-info.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/get-account-info.js new file mode 100644 index 0000000..7b8599a --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/get-account-info.js @@ -0,0 +1,69 @@ +const { + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +function isUsernameSet (userRecord) { + return !!userRecord.username +} +function isNicknameSet (userRecord) { + return !!userRecord.nickname +} +function isPasswordSet (userRecord) { + return !!userRecord.password +} +function isMobileBound (userRecord) { + return !!(userRecord.mobile && userRecord.mobile_confirmed) +} +function isEmailBound (userRecord) { + return !!(userRecord.email && userRecord.email_confirmed) +} +function isWeixinBound (userRecord) { + return !!( + userRecord.wx_unionid || + Object.keys(userRecord.wx_openid || {}).length + ) +} +function isQQBound (userRecord) { + return !!( + userRecord.qq_unionid || + Object.keys(userRecord.qq_openid || {}).length + ) +} +function isAlipayBound (userRecord) { + return !!userRecord.ali_openid +} +function isAppleBound (userRecord) { + return !!userRecord.apple_openid +} + +/** + * 获取账户账户简略信息 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-account-info + */ +module.exports = async function () { + const { + uid + } = this.authInfo + const getUserRes = await userCollection.doc(uid).get() + const userRecord = getUserRes && getUserRes.data && getUserRes.data[0] + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + return { + errCode: 0, + isUsernameSet: isUsernameSet(userRecord), + isNicknameSet: isNicknameSet(userRecord), + isPasswordSet: isPasswordSet(userRecord), + isMobileBound: isMobileBound(userRecord), + isEmailBound: isEmailBound(userRecord), + isWeixinBound: isWeixinBound(userRecord), + isQQBound: isQQBound(userRecord), + isAlipayBound: isAlipayBound(userRecord), + isAppleBound: isAppleBound(userRecord) + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/get-realname-info.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/get-realname-info.js new file mode 100644 index 0000000..0ea8f05 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/get-realname-info.js @@ -0,0 +1,45 @@ +const { userCollection } = require('../../common/constants') +const { ERROR } = require('../../common/error') +const { decryptData } = require('../../common/sensitive-aes-cipher') +const { dataDesensitization } = require('../../common/utils') + +/** + * 获取实名信息 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-realname-info + * @param {Object} params + * @param {Boolean} params.decryptData 是否解密数据 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + decryptData: { + required: false, + type: 'boolean' + } + } + + this.middleware.validate(params, schema) + + const { decryptData: isDecryptData = true } = params + + const { + uid + } = this.authInfo + const getUserRes = await userCollection.doc(uid).get() + const userRecord = getUserRes && getUserRes.data && getUserRes.data[0] + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + + const { realname_auth: realNameAuth = {} } = userRecord + + return { + errCode: 0, + type: realNameAuth.type, + authStatus: realNameAuth.auth_status, + realName: isDecryptData ? dataDesensitization(decryptData.call(this, realNameAuth.real_name), { onlyLast: true }) : realNameAuth.real_name, + identity: isDecryptData ? dataDesensitization(decryptData.call(this, realNameAuth.identity)) : realNameAuth.identity + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/index.js new file mode 100644 index 0000000..0e55385 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/index.js @@ -0,0 +1,9 @@ +module.exports = { + setPwd: require('./set-pwd'), + updatePwd: require('./update-pwd'), + resetPwdBySms: require('./reset-pwd-by-sms'), + resetPwdByEmail: require('./reset-pwd-by-email'), + closeAccount: require('./close-account'), + getAccountInfo: require('./get-account-info'), + getRealNameInfo: require('./get-realname-info') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-email.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-email.js new file mode 100644 index 0000000..20c6219 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-email.js @@ -0,0 +1,128 @@ +const { + ERROR +} = require('../../common/error') +const { + getNeedCaptcha, + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + verifyEmailCode +} = require('../../lib/utils/verify-code') +const { + userCollection, + EMAIL_SCENE, + CAPTCHA_SCENE, + LOG_TYPE +} = require('../../common/constants') +const { + findUser +} = require('../../lib/utils/account') +const PasswordUtils = require('../../lib/utils/password') + +/** + * 通过邮箱验证码重置密码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#reset-pwd-by-email + * @param {object} params + * @param {string} params.email 邮箱 + * @param {string} params.code 邮箱验证码 + * @param {string} params.password 密码 + * @param {string} params.captcha 图形验证码 + * @returns {object} + */ +module.exports = async function (params = {}) { + const schema = { + email: 'email', + code: 'string', + password: 'password', + captcha: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + email, + code, + password, + captcha + } = params + + const needCaptcha = await getNeedCaptcha.call(this, { + email, + type: LOG_TYPE.RESET_PWD_BY_EMAIL + }) + if (needCaptcha) { + await verifyCaptcha.call(this, { + captcha, + scene: CAPTCHA_SCENE.RESET_PWD_BY_EMAIL + }) + } + try { + // 验证手机号验证码,验证不通过时写入失败日志 + await verifyEmailCode({ + email, + code, + scene: EMAIL_SCENE.RESET_PWD_BY_EMAIL + }) + } catch (error) { + await this.middleware.uniIdLog({ + data: { + email + }, + type: LOG_TYPE.RESET_PWD_BY_EMAIL, + success: false + }) + throw error + } + // 根据手机号查找匹配的用户 + const { + total, + userMatched + } = await findUser.call(this, { + userQuery: { + email + }, + authorizedApp: [this.getUniversalClientInfo().appId] + }) + if (userMatched.length === 0) { + if (total > 0) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS_IN_CURRENT_APP + } + } + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } else if (userMatched.length > 1) { + throw { + errCode: ERROR.ACCOUNT_CONFLICT + } + } + const { _id: uid } = userMatched[0] + const { + passwordHash, + version + } = new PasswordUtils({ + clientInfo: this.getUniversalClientInfo(), + passwordSecret: this.config.passwordSecret + }).generatePasswordHash({ + password + }) + // 更新用户密码 + await userCollection.doc(uid).update({ + password: passwordHash, + password_secret_version: version, + valid_token_date: Date.now() + }) + + // 写入成功日志 + await this.middleware.uniIdLog({ + data: { + email + }, + type: LOG_TYPE.RESET_PWD_BY_SMS + }) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-sms.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-sms.js new file mode 100644 index 0000000..bc10dc8 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-sms.js @@ -0,0 +1,128 @@ +const { + ERROR +} = require('../../common/error') +const { + getNeedCaptcha, + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + verifyMobileCode +} = require('../../lib/utils/verify-code') +const { + userCollection, + SMS_SCENE, + CAPTCHA_SCENE, + LOG_TYPE +} = require('../../common/constants') +const { + findUser +} = require('../../lib/utils/account') +const PasswordUtils = require('../../lib/utils/password') + +/** + * 通过短信验证码重置密码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#reset-pwd-by-sms + * @param {object} params + * @param {string} params.mobile 手机号 + * @param {string} params.mobile 短信验证码 + * @param {string} params.password 密码 + * @param {string} params.captcha 图形验证码 + * @returns {object} + */ +module.exports = async function (params = {}) { + const schema = { + mobile: 'mobile', + code: 'string', + password: 'password', + captcha: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + mobile, + code, + password, + captcha + } = params + + const needCaptcha = await getNeedCaptcha.call(this, { + mobile, + type: LOG_TYPE.RESET_PWD_BY_SMS + }) + if (needCaptcha) { + await verifyCaptcha.call(this, { + captcha, + scene: CAPTCHA_SCENE.RESET_PWD_BY_SMS + }) + } + try { + // 验证手机号验证码,验证不通过时写入失败日志 + await verifyMobileCode({ + mobile, + code, + scene: SMS_SCENE.RESET_PWD_BY_SMS + }) + } catch (error) { + await this.middleware.uniIdLog({ + data: { + mobile + }, + type: LOG_TYPE.RESET_PWD_BY_SMS, + success: false + }) + throw error + } + // 根据手机号查找匹配的用户 + const { + total, + userMatched + } = await findUser.call(this, { + userQuery: { + mobile + }, + authorizedApp: [this.getUniversalClientInfo().appId] + }) + if (userMatched.length === 0) { + if (total > 0) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS_IN_CURRENT_APP + } + } + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } else if (userMatched.length > 1) { + throw { + errCode: ERROR.ACCOUNT_CONFLICT + } + } + const { _id: uid } = userMatched[0] + const { + passwordHash, + version + } = new PasswordUtils({ + clientInfo: this.getUniversalClientInfo(), + passwordSecret: this.config.passwordSecret + }).generatePasswordHash({ + password + }) + // 更新用户密码 + await userCollection.doc(uid).update({ + password: passwordHash, + password_secret_version: version, + valid_token_date: Date.now() + }) + + // 写入成功日志 + await this.middleware.uniIdLog({ + data: { + mobile + }, + type: LOG_TYPE.RESET_PWD_BY_SMS + }) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/set-pwd.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/set-pwd.js new file mode 100644 index 0000000..f33c6f4 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/set-pwd.js @@ -0,0 +1,83 @@ +const { userCollection, SMS_SCENE, LOG_TYPE, CAPTCHA_SCENE } = require('../../common/constants') +const { ERROR } = require('../../common/error') +const { verifyMobileCode } = require('../../lib/utils/verify-code') +const PasswordUtils = require('../../lib/utils/password') +const { getNeedCaptcha, verifyCaptcha } = require('../../lib/utils/captcha') + +module.exports = async function (params = {}) { + const schema = { + password: 'password', + code: 'string', + captcha: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + + const { password, code, captcha } = params + const uid = this.authInfo.uid + const getUserRes = await userCollection.doc(uid).get() + const userRecord = getUserRes.data[0] + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + + const needCaptcha = await getNeedCaptcha.call(this, { + mobile: userRecord.mobile + }) + + if (needCaptcha) { + await verifyCaptcha.call(this, { + captcha, + scene: CAPTCHA_SCENE.SET_PWD_BY_SMS + }) + } + + try { + // 验证手机号验证码,验证不通过时写入失败日志 + await verifyMobileCode({ + mobile: userRecord.mobile, + code, + scene: SMS_SCENE.SET_PWD_BY_SMS + }) + } catch (error) { + await this.middleware.uniIdLog({ + data: { + mobile: userRecord.mobile + }, + type: LOG_TYPE.SET_PWD_BY_SMS, + success: false + }) + throw error + } + + const { + passwordHash, + version + } = new PasswordUtils({ + clientInfo: this.getUniversalClientInfo(), + passwordSecret: this.config.passwordSecret + }).generatePasswordHash({ + password + }) + + // 更新用户密码 + await userCollection.doc(uid).update({ + password: passwordHash, + password_secret_version: version + }) + + await this.middleware.uniIdLog({ + data: { + mobile: userRecord.mobile + }, + type: LOG_TYPE.SET_PWD_BY_SMS + }) + + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js new file mode 100644 index 0000000..97fd1be --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js @@ -0,0 +1,69 @@ +const { + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const PasswordUtils = require('../../lib/utils/password') +/** + * 更新密码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#update-pwd + * @param {object} params + * @param {string} params.oldPassword 旧密码 + * @param {string} params.newPassword 新密码 + * @returns {object} + */ +module.exports = async function (params = {}) { + const schema = { + oldPassword: 'string', // 防止密码规则调整导致旧密码无法更新 + newPassword: 'password' + } + this.middleware.validate(params, schema) + const uid = this.authInfo.uid + const getUserRes = await userCollection.doc(uid).get() + const userRecord = getUserRes.data[0] + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + const { + oldPassword, + newPassword + } = params + const passwordUtils = new PasswordUtils({ + userRecord, + clientInfo: this.getUniversalClientInfo(), + passwordSecret: this.config.passwordSecret + }) + + const { + success: checkPasswordSuccess + } = passwordUtils.checkUserPassword({ + password: oldPassword, + autoRefresh: false + }) + + if (!checkPasswordSuccess) { + throw { + errCode: ERROR.PASSWORD_ERROR + } + } + + const { + passwordHash, + version + } = passwordUtils.generatePasswordHash({ + password: newPassword + }) + + await userCollection.doc(uid).update({ + password: passwordHash, + password_secret_version: version, + valid_token_date: Date.now() // refreshToken时会校验,如果创建token时间在此时间点之前,则拒绝下发新token,返回token失效错误码 + }) + // 执行更新密码操作后客户端应将用户退出重新登录 + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/add-user.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/add-user.js new file mode 100644 index 0000000..330fd37 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/add-user.js @@ -0,0 +1,131 @@ +const { + findUser +} = require('../../lib/utils/account') +const { + ERROR +} = require('../../common/error') +const { + userCollection +} = require('../../common/constants') +const PasswordUtils = require('../../lib/utils/password') + +/** + * 新增用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#add-user + * @param {Object} params + * @param {String} params.username 用户名 + * @param {String} params.password 密码 + * @param {String} params.nickname 昵称 + * @param {Array} params.authorizedApp 允许登录的AppID列表 + * @param {Array} params.role 用户角色列表 + * @param {String} params.mobile 手机号 + * @param {String} params.email 邮箱 + * @param {Array} params.tags 用户标签 + * @param {Number} params.status 用户状态 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + username: 'username', + password: 'password', + authorizedApp: { + required: false, + type: 'array' + }, // 指定允许登录的app,传空数组或不传时表示可以不可以在任何端登录 + nickname: { + required: false, + type: 'nickname' + }, + role: { + require: false, + type: 'array' + }, + mobile: { + required: false, + type: 'mobile' + }, + email: { + required: false, + type: 'email' + }, + tags: { + required: false, + type: 'array' + }, + status: { + required: false, + type: 'number' + } + } + this.middleware.validate(params, schema) + const { + username, + password, + authorizedApp, + nickname, + role, + mobile, + email, + tags, + status + } = params + const { + userMatched + } = await findUser({ + userQuery: { + username, + mobile, + email + }, + authorizedApp + }) + if (userMatched.length) { + throw { + errCode: ERROR.ACCOUNT_EXISTS + } + } + const passwordUtils = new PasswordUtils({ + clientInfo: this.getUniversalClientInfo(), + passwordSecret: this.config.passwordSecret + }) + const { + passwordHash, + version + } = passwordUtils.generatePasswordHash({ + password + }) + const data = { + username, + password: passwordHash, + password_secret_version: version, + dcloud_appid: authorizedApp || [], + nickname, + role: role || [], + mobile, + email, + tags: tags || [], + status + } + if (email) { + data.email_confirmed = 1 + } + if (mobile) { + data.mobile_confirmed = 1 + } + + // 触发 beforeRegister 钩子 + const beforeRegister = this.hooks.beforeRegister + let userRecord = data + if (beforeRegister) { + userRecord = await beforeRegister({ + userRecord, + clientInfo: this.getUniversalClientInfo() + }) + } + + await userCollection.add(userRecord) + return { + errCode: 0, + errMsg: '' + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/index.js new file mode 100644 index 0000000..c8830f5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/index.js @@ -0,0 +1,4 @@ +module.exports = { + addUser: require('./add-user'), + updateUser: require('./update-user') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/update-user.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/update-user.js new file mode 100644 index 0000000..ed2f7b6 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/update-user.js @@ -0,0 +1,138 @@ +const { + findUser +} = require('../../lib/utils/account') +const { + ERROR +} = require('../../common/error') +const { + userCollection +} = require('../../common/constants') +const PasswordUtils = require('../../lib/utils/password') + +/** + * 修改用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#update-user + * @param {Object} params + * @param {String} params.uid 要更新的用户id + * @param {String} params.username 用户名 + * @param {String} params.password 密码 + * @param {String} params.nickname 昵称 + * @param {Array} params.authorizedApp 允许登录的AppID列表 + * @param {Array} params.role 用户角色列表 + * @param {String} params.mobile 手机号 + * @param {String} params.email 邮箱 + * @param {Array} params.tags 用户标签 + * @param {Number} params.status 用户状态 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + uid: 'string', + username: 'username', + password: { + required: false, + type: 'password' + }, + authorizedApp: { + required: false, + type: 'array' + }, // 指定允许登录的app,传空数组或不传时表示可以不可以在任何端登录 + nickname: { + required: false, + type: 'nickname' + }, + role: { + require: false, + type: 'array' + }, + mobile: { + required: false, + type: 'mobile' + }, + email: { + required: false, + type: 'email' + }, + tags: { + required: false, + type: 'array' + }, + status: { + required: false, + type: 'number' + } + } + + this.middleware.validate(params, schema) + + const { + uid, + username, + password, + authorizedApp, + nickname, + role, + mobile, + email, + tags, + status + } = params + + // 更新的用户数据字段 + const data = { + username, + dcloud_appid: authorizedApp, + nickname, + role, + mobile, + email, + tags, + status + } + + const realData = Object.keys(data).reduce((res, key) => { + const item = data[key] + if (item !== undefined) { + res[key] = item + } + return res + }, {}) + + // 更新用户名时验证用户名是否重新 + if (username) { + const { + userMatched + } = await findUser({ + userQuery: { + username + }, + authorizedApp + }) + if (userMatched.filter(user => user._id !== uid).length) { + throw { + errCode: ERROR.ACCOUNT_EXISTS + } + } + } + if (password) { + const passwordUtils = new PasswordUtils({ + clientInfo: this.getUniversalClientInfo(), + passwordSecret: this.config.passwordSecret + }) + const { + passwordHash, + version + } = passwordUtils.generatePasswordHash({ + password + }) + + realData.password = passwordHash + realData.password_secret_version = version + } + + await userCollection.doc(uid).update(realData) + + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/get-supported-login-type.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/get-supported-login-type.js new file mode 100644 index 0000000..c28f3bd --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/get-supported-login-type.js @@ -0,0 +1,70 @@ +function isMobileCodeSupported () { + const config = this.config + return !!(config.service && config.service.sms && config.service.sms.smsKey) +} + +function isUniverifySupport () { + return true +} + +function isWeixinSupported () { + this.configUtils.getOauthConfig({ + provider: 'weixin' + }) + return true +} + +function isQQSupported () { + this.configUtils.getOauthConfig({ + provider: 'qq' + }) + return true +} + +function isAppleSupported () { + this.configUtils.getOauthConfig({ + provider: 'apple' + }) + return true +} + +function isAlipaySupported () { + this.configUtils.getOauthConfig({ + provider: 'alipay' + }) + return true +} + +const loginTypeTester = { + 'mobile-code': isMobileCodeSupported, + univerify: isUniverifySupport, + weixin: isWeixinSupported, + qq: isQQSupported, + apple: isAppleSupported, + alipay: isAlipaySupported +} + +/** + * 获取支持的登录方式 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-supported-login-type + * @returns + */ +module.exports = async function () { + const supportedLoginType = [ + 'username-password', + 'mobile-password', + 'email-password' + ] + for (const type in loginTypeTester) { + try { + if (loginTypeTester[type].call(this)) { + supportedLoginType.push(type) + } + } catch (error) { } + } + return { + errCode: 0, + errMsg: '', + supportedLoginType + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/index.js new file mode 100644 index 0000000..e22f9f2 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/dev/index.js @@ -0,0 +1,3 @@ +module.exports = { + getSupportedLoginType: require('./get-supported-login-type') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/index.js new file mode 100644 index 0000000..6fa597f --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/index.js @@ -0,0 +1,5 @@ +module.exports = { + externalRegister: require('./register'), + externalLogin: require('./login'), + updateUserInfoByExternal: require('./update-user-info') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/login.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/login.js new file mode 100644 index 0000000..af13013 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/login.js @@ -0,0 +1,68 @@ +const { preLogin, postLogin } = require('../../lib/utils/login') +const { EXTERNAL_DIRECT_CONNECT_PROVIDER } = require('../../common/constants') +const { ERROR } = require('../../common/error') + +/** + * 外部用户登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#external-login + * @param {object} params + * @param {string} params.uid uni-id体系用户id + * @param {string} params.externalUid 业务系统的用户id + * @returns {object} + */ +module.exports = async function (params = {}) { + const schema = { + uid: { + required: false, + type: 'string' + }, + externalUid: { + required: false, + type: 'string' + } + } + + this.middleware.validate(params, schema) + + const { + uid, + externalUid + } = params + + if (!uid && !externalUid) { + throw { + errCode: ERROR.PARAM_REQUIRED, + errMsgValue: { + param: 'uid or externalUid' + } + } + } + + let query + if (uid) { + query = { + _id: uid + } + } else { + query = { + identities: { + provider: EXTERNAL_DIRECT_CONNECT_PROVIDER, + uid: externalUid + } + } + } + + const user = await preLogin.call(this, { + user: query + }) + + const result = await postLogin.call(this, { + user + }) + + return { + errCode: result.errCode, + newToken: result.newToken, + uid: result.uid + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/register.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/register.js new file mode 100644 index 0000000..1b2279c --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/register.js @@ -0,0 +1,93 @@ +const url = require('url') +const { preRegister, postRegister } = require('../../lib/utils/register') +const { EXTERNAL_DIRECT_CONNECT_PROVIDER } = require('../../common/constants') + +/** + * 外部注册用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#external-register + * @param {object} params + * @param {string} params.externalUid 业务系统的用户id + * @param {string} params.nickname 昵称 + * @param {number} params.gender 性别 + * @param {string} params.avatar 头像 + * @returns {object} + */ +module.exports = async function (params = {}) { + const schema = { + externalUid: 'string', + nickname: { + required: false, + type: 'nickname' + }, + gender: { + required: false, + type: 'number' + }, + avatar: { + required: false, + type: 'string' + } + } + + this.middleware.validate(params, schema) + + const { + externalUid, + avatar, + gender, + nickname + } = params + + await preRegister.call(this, { + user: { + identities: { + provider: EXTERNAL_DIRECT_CONNECT_PROVIDER, + uid: externalUid + } + } + }) + + const extraData = {} + + if (avatar) { + // eslint-disable-next-line n/no-deprecated-api + const avatarPath = url.parse(avatar).pathname + const extName = avatarPath.indexOf('.') > -1 ? avatarPath.split('.').pop() : '' + + extraData.avatar_file = { + name: avatarPath, + extname: extName, + url: avatar + } + } + + const result = await postRegister.call(this, { + user: { + avatar, + gender, + nickname, + identities: [ + { + provider: EXTERNAL_DIRECT_CONNECT_PROVIDER, + userInfo: { + avatar, + gender, + nickname + }, + uid: externalUid + } + ] + }, + extraData + }) + + return { + errCode: result.errCode, + newToken: result.newToken, + externalUid, + avatar, + gender, + nickname, + uid: result.uid + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/update-user-info.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/update-user-info.js new file mode 100644 index 0000000..a91fe9f --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/external/update-user-info.js @@ -0,0 +1,208 @@ +const url = require('url') +const { userCollection, EXTERNAL_DIRECT_CONNECT_PROVIDER } = require('../../common/constants') +const { ERROR } = require('../../common/error') +const { findUser } = require('../../lib/utils/account') +const PasswordUtils = require('../../lib/utils/password') + +/** + * 使用 uid 或 externalUid 获取用户信息 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#external-update-userinfo + * @param {object} params + * @param {string} params.uid uni-id体系的用户id + * @param {string} params.externalUid 业务系统的用户id + * @param {string} params.nickname 昵称 + * @param {string} params.gender 性别 + * @param {string} params.avatar 头像 + * @returns {object} + */ +module.exports = async function (params = {}) { + const schema = { + uid: { + required: false, + type: 'string' + }, + externalUid: { + required: false, + type: 'string' + }, + username: { + required: false, + type: 'string' + }, + password: { + required: false, + type: 'password' + }, + authorizedApp: { + required: false, + type: 'array' + }, // 指定允许登录的app,传空数组或不传时表示可以不可以在任何端登录 + nickname: { + required: false, + type: 'nickname' + }, + role: { + require: false, + type: 'array' + }, + mobile: { + required: false, + type: 'mobile' + }, + email: { + required: false, + type: 'email' + }, + tags: { + required: false, + type: 'array' + }, + status: { + required: false, + type: 'number' + }, + gender: { + required: false, + type: 'number' + }, + avatar: { + required: false, + type: 'string' + } + } + + this.middleware.validate(params, schema) + + const { + uid, + externalUid, + username, + password, + authorizedApp, + nickname, + role, + mobile, + email, + tags, + status, + avatar, + gender + } = params + + if (!uid && !externalUid) { + throw { + errCode: ERROR.PARAM_REQUIRED, + errMsgValue: { + param: 'uid or externalUid' + } + } + } + + let query + if (uid) { + query = { + _id: uid + } + } else { + query = { + identities: { + provider: EXTERNAL_DIRECT_CONNECT_PROVIDER, + uid: externalUid + } + } + } + + const users = await userCollection.where(query).get() + const user = users.data && users.data[0] + if (!user) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + + // 更新的用户数据字段 + const data = { + username, + dcloud_appid: authorizedApp, + nickname, + role, + mobile, + email, + tags, + status, + avatar, + gender + } + + const realData = Object.keys(data).reduce((res, key) => { + const item = data[key] + if (item !== undefined) { + res[key] = item + } + return res + }, {}) + + // 更新用户名时验证用户名是否重新 + if (username) { + const { + userMatched + } = await findUser({ + userQuery: { + username + }, + authorizedApp + }) + if (userMatched.filter(user => user._id !== uid).length) { + throw { + errCode: ERROR.ACCOUNT_EXISTS + } + } + } + if (password) { + const passwordUtils = new PasswordUtils({ + clientInfo: this.getUniversalClientInfo(), + passwordSecret: this.config.passwordSecret + }) + const { + passwordHash, + version + } = passwordUtils.generatePasswordHash({ + password + }) + + realData.password = passwordHash + realData.password_secret_version = version + } + + if (avatar) { + // eslint-disable-next-line n/no-deprecated-api + const avatarPath = url.parse(avatar).pathname + const extName = avatarPath.indexOf('.') > -1 ? avatarPath.split('.').pop() : '' + + realData.avatar_file = { + name: avatarPath, + extname: extName, + url: avatar + } + } + + if (user.identities.length) { + const identity = user.identities.find(item => item.provider === EXTERNAL_DIRECT_CONNECT_PROVIDER) + + if (identity) { + identity.userInfo = { + avatar, + gender, + nickname + } + } + + realData.identities = user.identities + } + + await userCollection.where(query).update(realData) + + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/facial-recognition-verify/get-auth-result.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/facial-recognition-verify/get-auth-result.js new file mode 100644 index 0000000..0b37b4e --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/facial-recognition-verify/get-auth-result.js @@ -0,0 +1,135 @@ +const { userCollection, REAL_NAME_STATUS, frvLogsCollection } = require('../../common/constants') +const { dataDesensitization, catchAwait } = require('../../common/utils') +const { encryptData, decryptData } = require('../../common/sensitive-aes-cipher') +const { ERROR } = require('../../common/error') + +/** + * 查询认证结果 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-frv-auth-result + * @param {Object} params + * @param {String} params.certifyId 认证ID + * @returns + */ +module.exports = async function (params) { + const schema = { + certifyId: 'string' + } + + this.middleware.validate(params, schema) + + const { uid } = this.authInfo // 从authInfo中取出uid属性 + const { certifyId } = params // 从params中取出certifyId属性 + + const user = await userCollection.doc(uid).get() // 根据uid查询用户信息 + const userInfo = user.data && user.data[0] // 从查询结果中获取userInfo对象 + + // 如果用户不存在,抛出账户不存在的错误 + if (!userInfo) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + + const { realname_auth: realNameAuth = {} } = userInfo + + // 如果用户已经实名认证,抛出已实名认证的错误 + if (realNameAuth.auth_status === REAL_NAME_STATUS.CERTIFIED) { + throw { + errCode: ERROR.REAL_NAME_VERIFIED + } + } + + // 初始化实人认证服务 + const frvManager = uniCloud.getFacialRecognitionVerifyManager({ + requestId: this.getUniCloudRequestId() + }) + + // 调用frvManager的getAuthResult方法,获取认证结果 + const [error, res] = await catchAwait(frvManager.getAuthResult({ + certifyId + })) + + // 如果出现错误,抛出未知错误并打印日志 + if (error) { + console.log(ERROR.UNKNOWN_ERROR, 'error: ', error) + throw error + } + + // 如果认证状态为“PROCESSING”,抛出认证正在处理中的错误 + if (res.authState === 'PROCESSING') { + throw { + errCode: ERROR.FRV_PROCESSING + } + } + + // 如果认证状态为“FAIL”,更新认证日志的状态并抛出认证失败的错误 + if (res.authState === 'FAIL') { + await frvLogsCollection.where({ + certify_id: certifyId + }).update({ + status: REAL_NAME_STATUS.CERTIFY_FAILED + }) + + console.log(ERROR.FRV_FAIL, 'error: ', res) + throw { + errCode: ERROR.FRV_FAIL + } + } + + // 如果认证状态不为“SUCCESS”,抛出未知错误并打印日志 + if (res.authState !== 'SUCCESS') { + console.log(ERROR.UNKNOWN_ERROR, 'source res: ', res) + throw { + errCode: ERROR.UNKNOWN_ERROR + } + } + + // 根据certifyId查询认证记录 + const frvLogs = await frvLogsCollection.where({ + certify_id: certifyId + }).get() + + const log = frvLogs.data && frvLogs.data[0] + + const updateData = { + realname_auth: { + auth_status: REAL_NAME_STATUS.CERTIFIED, + real_name: log.real_name, + identity: log.identity, + auth_date: Date.now(), + type: 0 + } + } + + // 如果获取到了认证照片的地址,则会对其进行下载,并使用uniCloud.uploadFile方法将其上传到云存储,并将上传后的fileID保存起来。 + if (res.pictureUrl) { + const pictureRes = await uniCloud.httpclient.request(res.pictureUrl) + if (pictureRes.status < 400) { + const { + fileID + } = await uniCloud.uploadFile({ + cloudPath: `user/id-card/${uid}.b64`, + fileContent: Buffer.from(encryptData.call(this, pictureRes.data.toString('base64'))) + }) + updateData.realname_auth.in_hand = fileID + } + } + + await Promise.all([ + // 更新用户认证状态 + userCollection.doc(uid).update(updateData), + // 更新实人认证记录状态 + frvLogsCollection.where({ + certify_id: certifyId + }).update({ + status: REAL_NAME_STATUS.CERTIFIED + }) + ]) + + return { + errCode: 0, + authStatus: REAL_NAME_STATUS.CERTIFIED, + realName: dataDesensitization(decryptData.call(this, log.real_name), { onlyLast: true }), // 对姓名进行脱敏处理 + identity: dataDesensitization(decryptData.call(this, log.identity)) // 对身份证号进行脱敏处理 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/facial-recognition-verify/get-certify-id.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/facial-recognition-verify/get-certify-id.js new file mode 100644 index 0000000..cb8b48b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/facial-recognition-verify/get-certify-id.js @@ -0,0 +1,99 @@ +const { userCollection, REAL_NAME_STATUS, frvLogsCollection, dbCmd } = require('../../common/constants') +const { ERROR } = require('../../common/error') +const { encryptData } = require('../../common/sensitive-aes-cipher') +const { getCurrentDateTimestamp } = require('../../common/utils') + +// const CertifyIdExpired = 25 * 60 * 1000 // certifyId 过期时间为30分钟,在25分时置为过期 + +/** + * 获取认证ID + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-frv-certify-id + * @param {Object} params + * @param {String} params.realName 真实姓名 + * @param {String} params.idCard 身份证号码 + * @param {String} params.metaInfo 客户端初始化时返回的metaInfo + * @returns + */ +module.exports = async function (params) { + const schema = { + realName: 'realName', + idCard: 'idCard', + metaInfo: 'string' + } + + this.middleware.validate(params, schema) + + const { realName: originalRealName, idCard: originalIdCard, metaInfo } = params // 解构出传入参数的真实姓名、身份证号码、其他元数据 + const realName = encryptData.call(this, originalRealName) // 对真实姓名进行加密处理 + const idCard = encryptData.call(this, originalIdCard) // 对身份证号码进行加密处理 + + const { uid } = this.authInfo // 获取当前用户的 ID + const idCardCertifyLimit = this.config.idCardCertifyLimit || 1 // 获取身份证认证限制次数,默认为1次 + const realNameCertifyLimit = this.config.realNameCertifyLimit || 5 // 获取实名认证限制次数,默认为5次 + const frvNeedAlivePhoto = this.config.frvNeedAlivePhoto || false // 是否需要拍摄活体照片,默认为 false + + const user = await userCollection.doc(uid).get() // 获取用户信息 + const userInfo = user.data && user.data[0] // 获取用户信息对象中的实名认证信息 + const { realname_auth: realNameAuth = {} } = userInfo // 解构出实名认证信息中的认证状态对象,默认为空对象 + + // 如果用户已经实名认证过,不能再次认证 + if (realNameAuth.auth_status === REAL_NAME_STATUS.CERTIFIED) { + throw { + errCode: ERROR.REAL_NAME_VERIFIED + } + } + + // 查询已经使用同一个身份证认证的账号数量,如果超过限制则不能认证 + const idCardAccount = await userCollection.where({ + realname_auth: { + type: 0, // 用户认证状态是个人 + auth_status: REAL_NAME_STATUS.CERTIFIED, // 认证状态为已认证 + identity: idCard // 身份证号码和传入参数的身份证号码相同 + } + }).get() + if (idCardAccount.data.length >= idCardCertifyLimit) { + throw { + errCode: ERROR.ID_CARD_EXISTS + } + } + + // 查询用户今天已经进行的实名认证次数,如果超过限制则不能认证 + const userFrvLogs = await frvLogsCollection.where({ + user_id: uid, + created_date: dbCmd.gt(getCurrentDateTimestamp()) // 查询今天的认证记录 + }).get() + + // 限制用户每日认证次数 + if (userFrvLogs.data && userFrvLogs.data.length >= realNameCertifyLimit) { + throw { + errCode: ERROR.REAL_NAME_VERIFY_UPPER_LIMIT + } + } + + // 初始化实人认证服务 + const frvManager = uniCloud.getFacialRecognitionVerifyManager({ + requestId: this.getUniCloudRequestId() // 获取当前 + }) + // 调用实人认证服务,获取认证 ID + const res = await frvManager.getCertifyId({ + realName: originalRealName, + idCard: originalIdCard, + needPicture: frvNeedAlivePhoto, + metaInfo + }) + + // 将认证记录插入到实名认证日志中 + await frvLogsCollection.add({ + user_id: uid, + certify_id: res.certifyId, + real_name: realName, + identity: idCard, + status: REAL_NAME_STATUS.WAITING_CERTIFIED, + created_date: Date.now() + }) + + // 返回认证ID + return { + certifyId: res.certifyId + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/facial-recognition-verify/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/facial-recognition-verify/index.js new file mode 100644 index 0000000..63f6b1f --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/facial-recognition-verify/index.js @@ -0,0 +1,4 @@ +module.exports = { + getFrvCertifyId: require('./get-certify-id'), + getFrvAuthResult: require('./get-auth-result') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/accept-invite.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/accept-invite.js new file mode 100644 index 0000000..2461e06 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/accept-invite.js @@ -0,0 +1,25 @@ +const { + acceptInvite +} = require('../../lib/utils/fission') + +/** + * 接受邀请 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#accept-invite + * @param {Object} params + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + inviteCode: 'string' + } + this.middleware.validate(params, schema) + const { + inviteCode + } = params + const uid = this.authInfo.uid + return acceptInvite({ + uid, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/get-invited-user.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/get-invited-user.js new file mode 100644 index 0000000..93d4671 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/get-invited-user.js @@ -0,0 +1,80 @@ +const { + userCollection +} = require('../../common/constants') +const { + coverMobile +} = require('../../common/utils') + +/** + * 获取受邀用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-invited-user + * @param {Object} params + * @param {Number} params.level 获取受邀用户的级数,1表示直接邀请的用户 + * @param {Number} params.limit 返回数据大小 + * @param {Number} params.offset 返回数据偏移 + * @param {Boolean} params.needTotal 是否需要返回总数 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + level: 'number', + limit: { + required: false, + type: 'number' + }, + offset: { + required: false, + type: 'number' + }, + needTotal: { + required: false, + type: 'boolean' + } + } + this.middleware.validate(params, schema) + const { + level, + limit = 20, + offset = 0, + needTotal = false + } = params + const uid = this.authInfo.uid + const query = { + [`inviter_uid.${level - 1}`]: uid + } + const getUserRes = await userCollection.where(query) + .field({ + _id: true, + avatar: true, + avatar_file: true, + username: true, + nickname: true, + mobile: true, + invite_time: true + }) + .orderBy('invite_time', 'desc') + .skip(offset) + .limit(limit) + .get() + + const invitedUser = getUserRes.data.map(item => { + return { + uid: item._id, + username: item.username, + nickname: item.nickname, + mobile: coverMobile(item.mobile), + inviteTime: item.invite_time, + avatar: item.avatar, + avatarFile: item.avatar_file + } + }) + const result = { + errCode: 0, + invitedUser + } + if (needTotal) { + const getTotalRes = await userCollection.where(query).count() + result.total = getTotalRes.total + } + return result +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/index.js new file mode 100644 index 0000000..4a9bee1 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/fission/index.js @@ -0,0 +1,4 @@ +module.exports = { + acceptInvite: require('./accept-invite'), + getInvitedUser: require('./get-invited-user') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/index.js new file mode 100644 index 0000000..f65f58b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/index.js @@ -0,0 +1,20 @@ +module.exports = { + login: require('./login'), + loginBySms: require('./login-by-sms'), + loginByUniverify: require('./login-by-univerify'), + loginByWeixin: require('./login-by-weixin'), + loginByAlipay: require('./login-by-alipay'), + loginByQQ: require('./login-by-qq'), + loginByApple: require('./login-by-apple'), + loginByBaidu: require('./login-by-baidu'), + loginByDingtalk: require('./login-by-dingtalk'), + loginByToutiao: require('./login-by-toutiao'), + loginByDouyin: require('./login-by-douyin'), + loginByWeibo: require('./login-by-weibo'), + loginByTaobao: require('./login-by-taobao'), + loginByEmailLink: require('./login-by-email-link'), + loginByEmailCode: require('./login-by-email-code'), + loginByFacebook: require('./login-by-facebook'), + loginByGoogle: require('./login-by-google'), + loginByWeixinMobile: require('./login-by-weixin-mobile') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-alipay.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-alipay.js new file mode 100644 index 0000000..d5d4631 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-alipay.js @@ -0,0 +1,70 @@ +const { + initAlipay +} = require('../../lib/third-party/index') +const { + ERROR +} = require('../../common/error') +const { + preUnifiedLogin, + postUnifiedLogin +} = require('../../lib/utils/unified-login') +const { + LOG_TYPE +} = require('../../common/constants') + +/** + * 支付宝登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-alipay + * @param {Object} params + * @param {String} params.code 支付宝小程序客户端登录返回的code + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: 'string', + inviteCode: { + type: 'string', + required: false + } + } + this.middleware.validate(params, schema) + const { + code, + inviteCode + } = params + const alipayApi = initAlipay.call(this) + let getAlipayAccountResult + try { + getAlipayAccountResult = await alipayApi.code2Session(code) + } catch (error) { + console.error(error) + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.LOGIN + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { + openid + } = getAlipayAccountResult + + const { + type, + user + } = await preUnifiedLogin.call(this, { + user: { + ali_openid: openid + } + }) + return postUnifiedLogin.call(this, { + user, + extraData: {}, + isThirdParty: true, + type, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-apple.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-apple.js new file mode 100644 index 0000000..5f39e62 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-apple.js @@ -0,0 +1,77 @@ +const { + initApple +} = require('../../lib/third-party/index') +const { + ERROR +} = require('../../common/error') +const { + preUnifiedLogin, + postUnifiedLogin +} = require('../../lib/utils/unified-login') +const { + LOG_TYPE +} = require('../../common/constants') + +/** + * 苹果登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-apple + * @param {Object} params + * @param {String} params.identityToken 苹果登录返回的identityToken + * @param {String} params.nickname 用户昵称 + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + identityToken: 'string', + nickname: { + required: false, + type: 'nickname' + }, + inviteCode: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + identityToken, + nickname, + inviteCode + } = params + const appleApi = initApple.call(this) + let verifyResult + try { + verifyResult = await appleApi.verifyIdentityToken(identityToken) + } catch (error) { + console.error(error) + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.LOGIN + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + const { + openid + } = verifyResult + + const { + type, + user + } = await preUnifiedLogin.call(this, { + user: { + apple_openid: openid + } + }) + return postUnifiedLogin.call(this, { + user, + extraData: { + nickname + }, + isThirdParty: true, + type, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-baidu.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-baidu.js new file mode 100644 index 0000000..856449d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-baidu.js @@ -0,0 +1,9 @@ +/** + * 百度登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByBaidu] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-dingtalk.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-dingtalk.js new file mode 100644 index 0000000..afe1f01 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-dingtalk.js @@ -0,0 +1,9 @@ +/** + * 钉钉登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByDingtalk] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-douyin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-douyin.js new file mode 100644 index 0000000..8cd4ab5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-douyin.js @@ -0,0 +1,9 @@ +/** + * 抖音登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByDouyin] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-code.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-code.js new file mode 100644 index 0000000..c3af08f --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-code.js @@ -0,0 +1,9 @@ +/** + * 邮箱验证码登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByEmailCode] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-link.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-link.js new file mode 100644 index 0000000..0ebbf3a --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-email-link.js @@ -0,0 +1,9 @@ +/** + * 邮箱点击链接登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByEmailLink] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-facebook.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-facebook.js new file mode 100644 index 0000000..5c93bd4 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-facebook.js @@ -0,0 +1,9 @@ +/** + * Facebook登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByFacebook] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-google.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-google.js new file mode 100644 index 0000000..8054ece --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-google.js @@ -0,0 +1,9 @@ +/** + * Google登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByGoogle] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-qq.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-qq.js new file mode 100644 index 0000000..1eaa7ba --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-qq.js @@ -0,0 +1,167 @@ +const { + initQQ +} = require('../../lib/third-party/index') +const { + ERROR +} = require('../../common/error') +const { + preUnifiedLogin, + postUnifiedLogin +} = require('../../lib/utils/unified-login') +const { + LOG_TYPE +} = require('../../common/constants') +const { + getQQPlatform, + generateQQCache, + saveQQUserKey +} = require('../../lib/utils/qq') +const url = require('url') + +/** + * QQ登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-qq + * @param {Object} params + * @param {String} params.code QQ小程序登录返回的code参数 + * @param {String} params.accessToken App端QQ登录返回的accessToken参数 + * @param {String} params.accessTokenExpired accessToken过期时间,由App端QQ登录返回的expires_in参数计算而来,单位:毫秒 + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: { + type: 'string', + required: false + }, + accessToken: { + type: 'string', + required: false + }, + accessTokenExpired: { + type: 'number', + required: false + }, + inviteCode: { + type: 'string', + required: false + } + } + this.middleware.validate(params, schema) + const { + code, + accessToken, + accessTokenExpired, + inviteCode + } = params + const { + appId + } = this.getUniversalClientInfo() + const qqApi = initQQ.call(this) + const qqPlatform = getQQPlatform.call(this) + let apiName + switch (qqPlatform) { + case 'mp': + apiName = 'code2Session' + break + case 'app': + apiName = 'getOpenidByToken' + break + default: + throw new Error('Unsupported qq platform') + } + let getQQAccountResult + try { + getQQAccountResult = await qqApi[apiName]({ + code, + accessToken + }) + } catch (error) { + console.error(error) + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.LOGIN + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { + openid, + unionid, + // 保存下面的字段 + sessionKey // QQ小程序用户sessionKey + } = getQQAccountResult + + const { + type, + user + } = await preUnifiedLogin.call(this, { + user: { + qq_openid: { + [qqPlatform]: openid + }, + qq_unionid: unionid + } + }) + const extraData = { + qq_openid: { + [`${qqPlatform}_${appId}`]: openid + }, + qq_unionid: unionid + } + if (type === 'register' && qqPlatform !== 'mp') { + const { + nickname, + avatar + } = await qqApi.getUserInfo({ + accessToken, + openid + }) + if (avatar) { + // eslint-disable-next-line n/no-deprecated-api + const extName = url.parse(avatar).pathname.split('.').pop() + const cloudPath = `user/avatar/${openid.slice(-8) + Date.now()}-avatar.${extName}` + const getAvatarRes = await uniCloud.httpclient.request(avatar) + if (getAvatarRes.status >= 400) { + throw { + errCode: ERROR.GET_THIRD_PARTY_USER_INFO_FAILED + } + } + const { + fileID + } = await uniCloud.uploadFile({ + cloudPath, + fileContent: getAvatarRes.data + }) + extraData.avatar_file = { + name: cloudPath, + extname: extName, + url: fileID + } + } + extraData.nickname = nickname + } + await saveQQUserKey.call(this, { + openid, + sessionKey, + accessToken, + accessTokenExpired + }) + return postUnifiedLogin.call(this, { + user, + extraData: { + ...extraData, + ...generateQQCache.call(this, { + openid, + sessionKey, // QQ小程序用户sessionKey + accessToken, // App端QQ用户accessToken + accessTokenExpired // App端QQ用户accessToken过期时间 + }) + }, + isThirdParty: true, + type, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-sms.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-sms.js new file mode 100644 index 0000000..915e9b6 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-sms.js @@ -0,0 +1,99 @@ +const { + getNeedCaptcha, + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + verifyMobileCode +} = require('../../lib/utils/verify-code') +const { + preUnifiedLogin, + postUnifiedLogin +} = require('../../lib/utils/unified-login') +const { + CAPTCHA_SCENE, + SMS_SCENE, + LOG_TYPE +} = require('../../common/constants') + +/** + * 短信验证码登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-sms + * @param {Object} params + * @param {String} params.mobile 手机号 + * @param {String} params.code 短信验证码 + * @param {String} params.captcha 图形验证码 + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + mobile: 'mobile', + code: 'string', + captcha: { + required: false, + type: 'string' + }, + inviteCode: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + mobile, + code, + captcha, + inviteCode + } = params + + const needCaptcha = await getNeedCaptcha.call(this, { + mobile + }) + + if (needCaptcha) { + await verifyCaptcha.call(this, { + captcha, + scene: CAPTCHA_SCENE.LOGIN_BY_SMS + }) + } + + try { + await verifyMobileCode({ + mobile, + code, + scene: SMS_SCENE.LOGIN_BY_SMS + }) + } catch (error) { + console.log(error, { + mobile, + code, + type: SMS_SCENE.LOGIN_BY_SMS + }) + await this.middleware.uniIdLog({ + success: false, + data: { + mobile + }, + type: LOG_TYPE.LOGIN + }) + throw error + } + + const { + type, + user + } = await preUnifiedLogin.call(this, { + user: { + mobile + } + }) + return postUnifiedLogin.call(this, { + user, + extraData: { + mobile_confirmed: 1 + }, + isThirdParty: false, + type, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-taobao.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-taobao.js new file mode 100644 index 0000000..6a6d599 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-taobao.js @@ -0,0 +1,9 @@ +/** + * 淘宝登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByTaobao] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-toutiao.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-toutiao.js new file mode 100644 index 0000000..133aadb --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-toutiao.js @@ -0,0 +1,9 @@ +/** + * 头条登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByToutiao] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-univerify.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-univerify.js new file mode 100644 index 0000000..53e681c --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-univerify.js @@ -0,0 +1,69 @@ +const { + getPhoneNumber +} = require('../../lib/utils/univerify') +const { + preUnifiedLogin, + postUnifiedLogin +} = require('../../lib/utils/unified-login') +const { + LOG_TYPE +} = require('../../common/constants') + +/** + * App端一键登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-univerify + * @param {Object} params + * @param {String} params.access_token APP端一键登录返回的access_token + * @param {String} params.openid APP端一键登录返回的openid + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + access_token: 'string', + openid: 'string', + inviteCode: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + // eslint-disable-next-line camelcase + access_token, + openid, + inviteCode + } = params + + let mobile + try { + const phoneInfo = await getPhoneNumber.call(this, { + // eslint-disable-next-line camelcase + access_token, + openid + }) + mobile = phoneInfo.phoneNumber + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.LOGIN + }) + throw error + } + const { + user, + type + } = await preUnifiedLogin.call(this, { + user: { + mobile + } + }) + return postUnifiedLogin.call(this, { + user, + extraData: { + mobile_confirmed: 1 + }, + type, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weibo.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weibo.js new file mode 100644 index 0000000..496cdb4 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weibo.js @@ -0,0 +1,9 @@ +/** + * 微博登录 + * @param {Object} params + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[loginByWeibo] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin-mobile.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin-mobile.js new file mode 100644 index 0000000..c27c2b2 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin-mobile.js @@ -0,0 +1,106 @@ +const { + initWeixin +} = require('../../lib/third-party/index') +const { + getWeixinAccessToken +} = require('../../lib/utils/weixin') +const { + ERROR +} = require('../../common/error') +const { + preUnifiedLogin, + postUnifiedLogin +} = require('../../lib/utils/unified-login') +const { + LOG_TYPE +} = require('../../common/constants') +const { + preBind, + postBind +} = require('../../lib/utils/relate') + +/** + * 微信授权手机号登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-weixin-mobile + * @param {Object} params + * @param {String} params.phoneCode 微信手机号返回的code + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + phoneCode: 'string', + inviteCode: { + type: 'string', + required: false + } + } + + this.middleware.validate(params, schema) + + const { phoneCode, inviteCode } = params + + const weixinApi = initWeixin.call(this) + let mobile + + try { + const accessToken = await getWeixinAccessToken.call(this) + const mobileRes = await weixinApi.getPhoneNumber(accessToken, phoneCode) + mobile = mobileRes.purePhoneNumber + } catch (error) { + console.error(error) + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.LOGIN + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { type, user } = await preUnifiedLogin.call(this, { + user: { + mobile + } + }) + + let extraData = { + mobile_confirmed: 1 + } + + if (type === 'login') { + // 绑定手机号 + if (!user.mobile_confirmed) { + const bindAccount = { + mobile + } + await preBind.call(this, { + uid: user._id, + bindAccount, + logType: LOG_TYPE.BIND_MOBILE + }) + await postBind.call(this, { + uid: user._id, + bindAccount, + extraData: { + mobile_confirmed: 1 + }, + logType: LOG_TYPE.BIND_MOBILE + }) + extraData = { + ...extraData, + ...bindAccount + } + } + } + + return postUnifiedLogin.call(this, { + user, + extraData: { + ...extraData + }, + isThirdParty: false, + type, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin.js new file mode 100644 index 0000000..b50f9a5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin.js @@ -0,0 +1,176 @@ +const { + initWeixin +} = require('../../lib/third-party/index') +const { + ERROR +} = require('../../common/error') +const { + preUnifiedLogin, + postUnifiedLogin +} = require('../../lib/utils/unified-login') +const { + generateWeixinCache, + getWeixinPlatform, + saveWeixinUserKey, + saveSecureNetworkCache +} = require('../../lib/utils/weixin') +const { + LOG_TYPE +} = require('../../common/constants') +const url = require('url') + +/** + * 微信登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-weixin + * @param {Object} params + * @param {String} params.code 微信登录返回的code + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: 'string', + inviteCode: { + type: 'string', + required: false + } + } + this.middleware.validate(params, schema) + const { + code, + inviteCode, + // 内部参数,暂不暴露 + secureNetworkCache = false + } = params + const { + appId + } = this.getUniversalClientInfo() + const weixinApi = initWeixin.call(this) + const weixinPlatform = getWeixinPlatform.call(this) + let apiName + switch (weixinPlatform) { + case 'mp': + apiName = 'code2Session' + break + case 'app': + case 'h5': + case 'web': + apiName = 'getOauthAccessToken' + break + default: + throw new Error('Unsupported weixin platform') + } + let getWeixinAccountResult + try { + getWeixinAccountResult = await weixinApi[apiName](code) + } catch (error) { + console.error(error) + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.LOGIN + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { + openid, + unionid, + // 保存下面四个字段 + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + expired: accessTokenExpired // App端微信用户accessToken过期时间 + } = getWeixinAccountResult + + if (secureNetworkCache) { + if (weixinPlatform !== 'mp') { + throw new Error('Unsupported weixin platform, expect mp-weixin') + } + await saveSecureNetworkCache.call(this, { + code, + openid, + unionid, + sessionKey + }) + } + + const { + type, + user + } = await preUnifiedLogin.call(this, { + user: { + wx_openid: { + [weixinPlatform]: openid + }, + wx_unionid: unionid + } + }) + const extraData = { + wx_openid: { + [`${weixinPlatform}_${appId}`]: openid + }, + wx_unionid: unionid + } + if (type === 'register' && weixinPlatform !== 'mp') { + const { + nickname, + avatar + } = await weixinApi.getUserInfo({ + accessToken, + openid + }) + + if (avatar) { + // eslint-disable-next-line n/no-deprecated-api + const avatarPath = url.parse(avatar).pathname + const extName = avatarPath.indexOf('.') > -1 ? url.parse(avatar).pathname.split('.').pop() : 'jpg' + const cloudPath = `user/avatar/${openid.slice(-8) + Date.now()}-avatar.${extName}` + const getAvatarRes = await uniCloud.httpclient.request(avatar) + if (getAvatarRes.status >= 400) { + throw { + errCode: ERROR.GET_THIRD_PARTY_USER_INFO_FAILED + } + } + + const { + fileID + } = await uniCloud.uploadFile({ + cloudPath, + fileContent: getAvatarRes.data + }) + + extraData.avatar_file = { + name: cloudPath, + extname: extName, + url: fileID + } + } + + extraData.nickname = nickname + } + await saveWeixinUserKey.call(this, { + openid, + sessionKey, + accessToken, + refreshToken, + accessTokenExpired + }) + return postUnifiedLogin.call(this, { + user, + extraData: { + ...extraData, + ...generateWeixinCache.call(this, { + openid, + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + accessTokenExpired // App端微信用户accessToken过期时间 + }) + }, + isThirdParty: true, + type, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login.js new file mode 100644 index 0000000..97e9cfe --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login.js @@ -0,0 +1,94 @@ +const { + preLoginWithPassword, + postLogin +} = require('../../lib/utils/login') +const { + getNeedCaptcha, + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + CAPTCHA_SCENE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +/** + * 用户名密码登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login + * @param {Object} params + * @param {String} params.username 用户名 + * @param {String} params.mobile 手机号 + * @param {String} params.email 邮箱 + * @param {String} params.password 密码 + * @param {String} params.captcha 图形验证码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + username: { + required: false, + type: 'username' + }, + mobile: { + required: false, + type: 'mobile' + }, + email: { + required: false, + type: 'email' + }, + password: 'password', + captcha: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + username, + mobile, + email, + password, + captcha + } = params + if (!username && !mobile && !email) { + throw { + errCode: ERROR.INVALID_USERNAME + } + } else if ( + (username && email) || + (username && mobile) || + (email && mobile) + ) { + throw { + errCode: ERROR.INVALID_PARAM + } + } + const needCaptcha = await getNeedCaptcha.call(this, { + username, + mobile, + email + }) + if (needCaptcha) { + await verifyCaptcha.call(this, { + captcha, + scene: CAPTCHA_SCENE.LOGIN_BY_PWD + }) + } + const { + user, + extraData + } = await preLoginWithPassword.call(this, { + user: { + username, + mobile, + email + }, + password + }) + return postLogin.call(this, { + user, + extraData + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/index.js new file mode 100644 index 0000000..544be2b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/index.js @@ -0,0 +1,3 @@ +module.exports = { + logout: require('./logout') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/logout.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/logout.js new file mode 100644 index 0000000..7d491c6 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/logout/logout.js @@ -0,0 +1,15 @@ +const { + logout +} = require('../../lib/utils/logout') + +/** + * 用户退出登录 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#logout + * @returns + */ +module.exports = async function () { + await logout.call(this) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/authorize-app-login.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/authorize-app-login.js new file mode 100644 index 0000000..8f8a167 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/authorize-app-login.js @@ -0,0 +1,37 @@ +const { + isAuthorizeApproved +} = require('./utils') +const { + dbCmd, + userCollection +} = require('../../common/constants') + +/** + * 授权用户登录应用 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#authorize-app-login + * @param {Object} params + * @param {String} params.uid 用户id + * @param {String} params.appId 授权的应用的AppId + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + uid: 'string', + appId: 'string' + } + this.middleware.validate(params, schema) + const { + uid, + appId + } = params + await isAuthorizeApproved({ + uid, + appIdList: [appId] + }) + await userCollection.doc(uid).update({ + dcloud_appid: dbCmd.push(appId) + }) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/index.js new file mode 100644 index 0000000..ce9cc7b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/index.js @@ -0,0 +1,5 @@ +module.exports = { + authorizeAppLogin: require('./authorize-app-login'), + removeAuthorizedApp: require('./remove-authorized-app'), + setAuthorizedApp: require('./set-authorized-app') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/remove-authorized-app.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/remove-authorized-app.js new file mode 100644 index 0000000..df82184 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/remove-authorized-app.js @@ -0,0 +1,30 @@ +const { + dbCmd, + userCollection +} = require('../../common/constants') + +/** + * 移除用户登录授权 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#remove-authorized-app + * @param {Object} params + * @param {String} params.uid 用户id + * @param {String} params.appId 取消授权的应用的AppId + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + uid: 'string', + appId: 'string' + } + this.middleware.validate(params, schema) + const { + uid, + appId + } = params + await userCollection.doc(uid).update({ + dcloud_appid: dbCmd.pull(appId) + }) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/set-authorized-app.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/set-authorized-app.js new file mode 100644 index 0000000..a438ef9 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/set-authorized-app.js @@ -0,0 +1,36 @@ +const { + isAuthorizeApproved +} = require('./utils') +const { + userCollection +} = require('../../common/constants') + +/** + * 设置用户允许登录的应用列表 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-authorized-app + * @param {Object} params + * @param {String} params.uid 用户id + * @param {Array} params.appIdList 允许登录的应用AppId列表 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + uid: 'string', + appIdList: 'array' + } + this.middleware.validate(params, schema) + const { + uid, + appIdList + } = params + await isAuthorizeApproved({ + uid, + appIdList + }) + await userCollection.doc(uid).update({ + dcloud_appid: appIdList + }) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/utils.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/utils.js new file mode 100644 index 0000000..4ee4e26 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/multi-end/utils.js @@ -0,0 +1,38 @@ +const { + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + findUser +} = require('../../lib/utils/account') + +async function isAuthorizeApproved ({ + uid, + appIdList +} = {}) { + const getUserRes = await userCollection.doc(uid).get() + const userRecord = getUserRes.data[0] + if (!userRecord) { + throw { + errCode: ERROR.ACCOUNT_NOT_EXISTS + } + } + const { + userMatched + } = await findUser({ + userQuery: userRecord, + authorizedApp: appIdList + }) + + if (userMatched.some(item => item._id !== uid)) { + throw { + errCode: ERROR.ACCOUNT_CONFLICT + } + } +} + +module.exports = { + isAuthorizeApproved +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/index.js new file mode 100644 index 0000000..64ff603 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/index.js @@ -0,0 +1,5 @@ +module.exports = { + registerUser: require('./register-user'), + registerAdmin: require('./register-admin'), + registerUserByEmail: require('./register-user-by-email') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-admin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-admin.js new file mode 100644 index 0000000..5e122ab --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-admin.js @@ -0,0 +1,72 @@ +const { + userCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + preRegisterWithPassword, + postRegister +} = require('../../lib/utils/register') + +/** + * 注册管理员 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#register-admin + * @param {Object} params + * @param {String} params.username 用户名 + * @param {String} params.password 密码 + * @param {String} params.nickname 昵称 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + username: 'username', + password: 'password', + nickname: { + type: 'nickname', + required: false + } + } + this.middleware.validate(params, schema) + const { + username, + password, + nickname + } = params + const getAdminRes = await userCollection.where({ + role: 'admin' + }).limit(1).get() + if (getAdminRes.data.length > 0) { + const [admin] = getAdminRes.data + const appId = this.getUniversalClientInfo().appId + + if (!admin.dcloud_appid || (admin.dcloud_appid && admin.dcloud_appid.includes(appId))) { + return { + errCode: ERROR.ADMIN_EXISTS, + errMsg: this.t('uni-id-admin-exists') + } + } else { + return { + errCode: ERROR.ADMIN_EXISTS, + errMsg: this.t('uni-id-admin-exist-in-other-apps') + } + } + } + const { + user, + extraData + } = await preRegisterWithPassword.call(this, { + user: { + username + }, + password + }) + return postRegister.call(this, { + user, + extraData: { + ...extraData, + nickname, + role: ['admin'] + } + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user-by-email.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user-by-email.js new file mode 100644 index 0000000..b52c1d2 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user-by-email.js @@ -0,0 +1,87 @@ +const { + postRegister, + preRegisterWithPassword +} = require('../../lib/utils/register') +const { + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + CAPTCHA_SCENE, + EMAIL_SCENE, + LOG_TYPE +} = require('../../common/constants') +const { + verifyEmailCode +} = require('../../lib/utils/verify-code') + +/** + * 通过邮箱+验证码注册普通用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#register-user-by-email + * @param {Object} params + * @param {String} params.email 邮箱 + * @param {String} params.password 密码 + * @param {String} params.nickname 昵称 + * @param {String} params.code 邮箱验证码 + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + email: 'email', + password: 'password', + nickname: { + required: false, + type: 'nickname' + }, + code: 'string', + inviteCode: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + email, + password, + nickname, + code, + inviteCode + } = params + + try { + // 验证邮箱验证码,验证不通过时写入失败日志 + await verifyEmailCode({ + email, + code, + scene: EMAIL_SCENE.REGISTER + }) + } catch (error) { + await this.middleware.uniIdLog({ + data: { + email + }, + type: LOG_TYPE.REGISTER, + success: false + }) + throw error + } + + const { + user, + extraData + } = await preRegisterWithPassword.call(this, { + user: { + email + }, + password + }) + return postRegister.call(this, { + user, + extraData: { + ...extraData, + nickname, + email_confirmed: 1 + }, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user.js new file mode 100644 index 0000000..130dece --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/register/register-user.js @@ -0,0 +1,68 @@ +const { + postRegister, + preRegisterWithPassword +} = require('../../lib/utils/register') +const { + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + CAPTCHA_SCENE +} = require('../../common/constants') + +/** + * 注册普通用户 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#register-user + * @param {Object} params + * @param {String} params.username 用户名 + * @param {String} params.password 密码 + * @param {String} params.captcha 图形验证码 + * @param {String} params.nickname 昵称 + * @param {String} params.inviteCode 邀请码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + username: 'username', + password: 'password', + captcha: 'string', + nickname: { + required: false, + type: 'nickname' + }, + inviteCode: { + required: false, + type: 'string' + } + } + this.middleware.validate(params, schema) + const { + username, + password, + nickname, + captcha, + inviteCode + } = params + + await verifyCaptcha.call(this, { + captcha, + scene: CAPTCHA_SCENE.REGISTER + }) + + const { + user, + extraData + } = await preRegisterWithPassword.call(this, { + user: { + username + }, + password + }) + return postRegister.call(this, { + user, + extraData: { + ...extraData, + nickname + }, + inviteCode + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-alipay.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-alipay.js new file mode 100644 index 0000000..bdb451b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-alipay.js @@ -0,0 +1,63 @@ +const { + preBind, + postBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + initAlipay +} = require('../../lib/third-party/index') + +/** + * 绑定支付宝账号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-alipay + * @param {Object} params + * @param {String} params.code 支付宝小程序登录返回的code参数 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: 'string' + } + this.middleware.validate(params, schema) + const uid = this.authInfo.uid + const { + code + } = params + const alipayApi = initAlipay.call(this) + let getAlipayAccountResult + try { + getAlipayAccountResult = await alipayApi().code2Session(code) + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.BIND_ALIPAY + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { + openid + } = getAlipayAccountResult + + const bindAccount = { + ali_openid: openid + } + await preBind.call(this, { + uid, + bindAccount, + logType: LOG_TYPE.BIND_APPLE + }) + return postBind.call(this, { + uid, + bindAccount, + extraData: {}, + logType: LOG_TYPE.BIND_APPLE + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-apple.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-apple.js new file mode 100644 index 0000000..eb87f8b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-apple.js @@ -0,0 +1,62 @@ +const { + preBind, + postBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + initApple +} = require('../../lib/third-party/index') + +/** + * 绑定苹果账号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-apple + * @param {Object} params + * @param {String} params.identityToken 苹果登录返回identityToken + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + identityToken: 'string' + } + this.middleware.validate(params, schema) + const uid = this.authInfo.uid + const { + identityToken + } = params + const appleApi = initApple.call(this) + let verifyResult + try { + verifyResult = await appleApi.verifyIdentityToken(identityToken) + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.BIND_APPLE + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + const { + openid + } = verifyResult + + const bindAccount = { + apple_openid: openid + } + await preBind.call(this, { + uid, + bindAccount, + logType: LOG_TYPE.BIND_APPLE + }) + return postBind.call(this, { + uid, + bindAccount, + extraData: {}, + logType: LOG_TYPE.BIND_APPLE + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-mp-weixin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-mp-weixin.js new file mode 100644 index 0000000..f4c2bd0 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-mp-weixin.js @@ -0,0 +1,104 @@ +const { + preBind, + postBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE +} = require('../../common/constants') +const { + decryptWeixinData, + getWeixinCache, getWeixinAccessToken +} = require('../../lib/utils/weixin') +const { initWeixin } = require('../../lib/third-party') +const { ERROR } = require('../../common/error') + +/** + * 通过微信绑定手机号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-mp-weixin + * @param {Object} params + * @param {String} params.encryptedData 微信获取手机号返回的加密信息 + * @param {String} params.iv 微信获取手机号返回的初始向量 + * @param {String} params.code 微信获取手机号返回的code + * @returns + */ +module.exports = async function (params = {}) { + /** + * 微信小程序的规则是客户端应先使用checkSession接口检测上次获取的sessionKey是否仍有效 + * 如果有效则直接使用上次存储的sessionKey即可 + * 如果无效应重新调用login接口再次刷新sessionKey + * 因此此接口不应直接使用客户端login获取的code,只能使用缓存的sessionKey + */ + const schema = { + encryptedData: { + required: false, + type: 'string' + }, + iv: { + required: false, + type: 'string' + }, + code: { + required: false, + type: 'string' + } + } + const { + encryptedData, + iv, + code + } = params + this.middleware.validate(params, schema) + + if ((!encryptedData && !iv) && !code) { + return { + errCode: ERROR.INVALID_PARAM + } + } + + const uid = this.authInfo.uid + + let mobile + if (code) { + // 区分客户端类型 小程序还是App + const accessToken = await getWeixinAccessToken.call(this) + const weixinApi = initWeixin.call(this) + const res = await weixinApi.getPhoneNumber(accessToken, code) + + mobile = res.purePhoneNumber + } else { + const sessionKey = await getWeixinCache.call(this, { + uid, + key: 'session_key' + }) + if (!sessionKey) { + throw new Error('Session key not found') + } + const res = decryptWeixinData.call(this, { + encryptedData, + sessionKey, + iv + }) + + mobile = res.purePhoneNumber + } + + const bindAccount = { + mobile + } + await preBind.call(this, { + uid, + bindAccount, + logType: LOG_TYPE.BIND_MOBILE + }) + await postBind.call(this, { + uid, + bindAccount, + extraData: { + mobile_confirmed: 1 + }, + logType: LOG_TYPE.BIND_MOBILE + }) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-sms.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-sms.js new file mode 100644 index 0000000..1640c2d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-sms.js @@ -0,0 +1,92 @@ +const { + getNeedCaptcha, + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + LOG_TYPE, + SMS_SCENE, + CAPTCHA_SCENE +} = require('../../common/constants') +const { + verifyMobileCode +} = require('../../lib/utils/verify-code') +const { + preBind, + postBind +} = require('../../lib/utils/relate') + +/** + * 通过短信验证码绑定手机号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-sms + * @param {Object} params + * @param {String} params.mobile 手机号 + * @param {String} params.code 短信验证码 + * @param {String} params.captcha 图形验证码 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + mobile: 'mobile', + code: 'string', + captcha: { + type: 'string', + required: false + } + } + const { + mobile, + code, + captcha + } = params + this.middleware.validate(params, schema) + const uid = this.authInfo.uid + + // 判断是否需要验证码 + const needCaptcha = await getNeedCaptcha.call(this, { + uid, + type: LOG_TYPE.BIND_MOBILE + }) + if (needCaptcha) { + await verifyCaptcha.call(this, { + captcha, + scene: CAPTCHA_SCENE.BIND_MOBILE_BY_SMS + }) + } + + try { + // 验证手机号验证码,验证不通过时写入失败日志 + await verifyMobileCode({ + mobile, + code, + scene: SMS_SCENE.BIND_MOBILE_BY_SMS + }) + } catch (error) { + await this.middleware.uniIdLog({ + data: { + user_id: uid + }, + type: LOG_TYPE.BIND_MOBILE, + success: false + }) + throw error + } + const bindAccount = { + mobile + } + await preBind.call(this, { + uid, + bindAccount, + logType: LOG_TYPE.BIND_MOBILE + }) + await postBind.call(this, { + uid, + bindAccount, + extraData: { + mobile_confirmed: 1 + }, + logType: LOG_TYPE.BIND_MOBILE + }) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-univerify.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-univerify.js new file mode 100644 index 0000000..2970c61 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-mobile-by-univerify.js @@ -0,0 +1,70 @@ +const { + getPhoneNumber +} = require('../../lib/utils/univerify') +const { + LOG_TYPE +} = require('../../common/constants') +const { + preBind, + postBind +} = require('../../lib/utils/relate') + +/** + * 通过一键登录绑定手机号 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-mobile-by-univerify + * @param {Object} params + * @param {String} params.openid APP端一键登录返回的openid + * @param {String} params.access_token APP端一键登录返回的access_token + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + openid: 'string', + access_token: 'string' + } + const { + openid, + // eslint-disable-next-line camelcase + access_token + } = params + this.middleware.validate(params, schema) + const uid = this.authInfo.uid + let mobile + try { + const phoneInfo = await getPhoneNumber.call(this, { + // eslint-disable-next-line camelcase + access_token, + openid + }) + mobile = phoneInfo.phoneNumber + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + data: { + user_id: uid + }, + type: LOG_TYPE.BIND_MOBILE + }) + throw error + } + + const bindAccount = { + mobile + } + await preBind.call(this, { + uid, + bindAccount, + logType: LOG_TYPE.BIND_MOBILE + }) + await postBind.call(this, { + uid, + bindAccount, + extraData: { + mobile_confirmed: 1 + }, + logType: LOG_TYPE.BIND_MOBILE + }) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-qq.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-qq.js new file mode 100644 index 0000000..574f917 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-qq.js @@ -0,0 +1,110 @@ +const { + preBind, + postBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +const { + initQQ +} = require('../../lib/third-party/index') +const { + generateQQCache, + getQQPlatform, + saveQQUserKey +} = require('../../lib/utils/qq') + +/** + * 绑定QQ + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-qq + * @param {Object} params + * @param {String} params.code 小程序端QQ登录返回的code + * @param {String} params.accessToken APP端QQ登录返回的accessToken + * @param {String} params.accessTokenExpired accessToken过期时间,由App端QQ登录返回的expires_in参数计算而来,单位:毫秒 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: { + type: 'string', + required: false + }, + accessToken: { + type: 'string', + required: false + }, + accessTokenExpired: { + type: 'number', + required: false + } + } + this.middleware.validate(params, schema) + const uid = this.authInfo.uid + const { + code, + accessToken, + accessTokenExpired + } = params + const qqPlatform = getQQPlatform.call(this) + const appId = this.getUniversalClientInfo().appId + const qqApi = initQQ.call(this) + const clientPlatform = this.clientPlatform + const apiName = clientPlatform === 'mp-qq' ? 'code2Session' : 'getOpenidByToken' + let getQQAccountResult + try { + getQQAccountResult = await qqApi[apiName]({ + code, + accessToken + }) + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.BIND_QQ + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { + openid, + unionid, + // 保存下面四个字段 + sessionKey // 微信小程序用户sessionKey + } = getQQAccountResult + + const bindAccount = { + qq_openid: { + [qqPlatform]: openid + }, + qq_unionid: unionid + } + await preBind.call(this, { + uid, + bindAccount, + logType: LOG_TYPE.BIND_QQ + }) + await saveQQUserKey.call(this, { + openid, + sessionKey, + accessToken, + accessTokenExpired + }) + return postBind.call(this, { + uid, + bindAccount, + extraData: { + qq_openid: { + [`${qqPlatform}_${appId}`]: openid + }, + ...generateQQCache.call(this, { + openid, + sessionKey + }) + }, + logType: LOG_TYPE.BIND_QQ + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-weixin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-weixin.js new file mode 100644 index 0000000..d649478 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/bind-weixin.js @@ -0,0 +1,100 @@ +const { + preBind, + postBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE +} = require('../../common/constants') +const { + generateWeixinCache, + saveWeixinUserKey, + getWeixinPlatform +} = require('../../lib/utils/weixin') +const { + initWeixin +} = require('../../lib/third-party/index') +const { + ERROR +} = require('../../common/error') + +/** + * 绑定微信 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#bind-weixin + * @param {Object} params + * @param {String} params.code 微信登录返回的code + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: 'string' + } + this.middleware.validate(params, schema) + const uid = this.authInfo.uid + const { + code + } = params + const weixinPlatform = getWeixinPlatform.call(this) + const appId = this.getUniversalClientInfo().appId + + const weixinApi = initWeixin.call(this) + const clientPlatform = this.clientPlatform + const apiName = clientPlatform === 'mp-weixin' ? 'code2Session' : 'getOauthAccessToken' + let getWeixinAccountResult + try { + getWeixinAccountResult = await weixinApi[apiName](code) + } catch (error) { + await this.middleware.uniIdLog({ + success: false, + type: LOG_TYPE.BIND_WEIXIN + }) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + + const { + openid, + unionid, + // 保存下面四个字段 + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + expired: accessTokenExpired // App端微信用户accessToken过期时间 + } = getWeixinAccountResult + + const bindAccount = { + wx_openid: { + [weixinPlatform]: openid + }, + wx_unionid: unionid + } + await preBind.call(this, { + uid, + bindAccount, + logType: LOG_TYPE.BIND_WEIXIN + }) + await saveWeixinUserKey.call(this, { + openid, + sessionKey, + accessToken, + refreshToken, + accessTokenExpired + }) + return postBind.call(this, { + uid, + bindAccount, + extraData: { + wx_openid: { + [`${weixinPlatform}_${appId}`]: openid + }, + ...generateWeixinCache.call(this, { + openid, + sessionKey, // 微信小程序用户sessionKey + accessToken, // App端微信用户accessToken + refreshToken, // App端微信用户refreshToken + accessTokenExpired // App端微信用户accessToken过期时间 + }) + }, + logType: LOG_TYPE.BIND_WEIXIN + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/index.js new file mode 100644 index 0000000..4d99c02 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/index.js @@ -0,0 +1,13 @@ +module.exports = { + bindMobileBySms: require('./bind-mobile-by-sms'), + bindMobileByUniverify: require('./bind-mobile-by-univerify'), + bindMobileByMpWeixin: require('./bind-mobile-by-mp-weixin'), + bindAlipay: require('./bind-alipay'), + bindApple: require('./bind-apple'), + bindQQ: require('./bind-qq'), + bindWeixin: require('./bind-weixin'), + unbindWeixin: require('./unbind-weixin'), + unbindAlipay: require('./unbind-alipay'), + unbindQQ: require('./unbind-qq'), + unbindApple: require('./unbind-apple') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-alipay.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-alipay.js new file mode 100644 index 0000000..67bb43b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-alipay.js @@ -0,0 +1,32 @@ +const { + preUnBind, + postUnBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE, dbCmd +} = require('../../common/constants') + +/** + * 解绑支付宝 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-alipay + * @returns + */ +module.exports = async function () { + const { uid } = this.authInfo + + await preUnBind.call(this, { + uid, + unBindAccount: { + ali_openid: dbCmd.exists(true) + }, + logType: LOG_TYPE.UNBIND_ALIPAY + }) + + return await postUnBind.call(this, { + uid, + unBindAccount: { + ali_openid: dbCmd.remove() + }, + logType: LOG_TYPE.UNBIND_ALIPAY + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-apple.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-apple.js new file mode 100644 index 0000000..111c1bf --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-apple.js @@ -0,0 +1,32 @@ +const { + preUnBind, + postUnBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE, dbCmd +} = require('../../common/constants') + +/** + * 解绑apple + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-apple + * @returns + */ +module.exports = async function () { + const { uid } = this.authInfo + + await preUnBind.call(this, { + uid, + unBindAccount: { + apple_openid: dbCmd.exists(true) + }, + logType: LOG_TYPE.UNBIND_APPLE + }) + + return await postUnBind.call(this, { + uid, + unBindAccount: { + apple_openid: dbCmd.remove() + }, + logType: LOG_TYPE.UNBIND_APPLE + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-qq.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-qq.js new file mode 100644 index 0000000..0c9704c --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-qq.js @@ -0,0 +1,33 @@ +const { + preUnBind, + postUnBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE, dbCmd +} = require('../../common/constants') +/** + * 解绑QQ + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-qq + * @returns + */ +module.exports = async function () { + const { uid } = this.authInfo + + await preUnBind.call(this, { + uid, + unBindAccount: { + qq_openid: dbCmd.exists(true), + qq_unionid: dbCmd.exists(true) + }, + logType: LOG_TYPE.UNBIND_QQ + }) + + return await postUnBind.call(this, { + uid, + unBindAccount: { + qq_openid: dbCmd.remove(), + qq_unionid: dbCmd.remove() + }, + logType: LOG_TYPE.UNBIND_QQ + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-weixin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-weixin.js new file mode 100644 index 0000000..2248327 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/relate/unbind-weixin.js @@ -0,0 +1,38 @@ +const { + preUnBind, + postUnBind +} = require('../../lib/utils/relate') +const { + LOG_TYPE, dbCmd +} = require('../../common/constants') +const { + getWeixinPlatform +} = require('../../lib/utils/weixin') + +/** + * 解绑微信 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-weixin + * @returns + */ +module.exports = async function () { + const { uid } = this.authInfo + // const weixinPlatform = getWeixinPlatform.call(this) + + await preUnBind.call(this, { + uid, + unBindAccount: { + wx_openid: dbCmd.exists(true), + wx_unionid: dbCmd.exists(true) + }, + logType: LOG_TYPE.UNBIND_WEIXIN + }) + + return await postUnBind.call(this, { + uid, + unBindAccount: { + wx_openid: dbCmd.remove(), + wx_unionid: dbCmd.remove() + }, + logType: LOG_TYPE.UNBIND_WEIXIN + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/index.js new file mode 100644 index 0000000..0ec67a5 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/index.js @@ -0,0 +1,5 @@ +module.exports = { + refreshToken: require('./refresh-token'), + setPushCid: require('./set-push-cid'), + secureNetworkHandshakeByWeixin: require('./secure-network-handshake-by-weixin') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/refresh-token.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/refresh-token.js new file mode 100644 index 0000000..b12f1f0 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/refresh-token.js @@ -0,0 +1,24 @@ +/** + * 刷新token + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#refresh-token + */ +module.exports = async function () { + const refreshTokenRes = await this.uniIdCommon.refreshToken({ + token: this.getUniversalUniIdToken() + }) + const { + errCode, + token, + tokenExpired + } = refreshTokenRes + if (errCode) { + throw refreshTokenRes + } + return { + errCode: 0, + newToken: { + token, + tokenExpired + } + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/secure-network-handshake-by-weixin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/secure-network-handshake-by-weixin.js new file mode 100644 index 0000000..82ea0b3 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/secure-network-handshake-by-weixin.js @@ -0,0 +1,73 @@ +const { + ERROR +} = require('../../common/error') +const { + initWeixin +} = require('../../lib/third-party/index') +const { + saveWeixinUserKey, + saveSecureNetworkCache +} = require('../../lib/utils/weixin') +const loginByWeixin = require('../login/login-by-weixin') +/** + * 微信安全网络握手 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-push-cid + * @param {object} params + * @param {string} params.code 微信登录返回的code + * @param {boolean} params.callLoginByWeixin 是否同时调用一次微信登录 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: 'string', + callLoginByWeixin: { + type: 'boolean', + required: false + } + } + this.middleware.validate(params, schema) + let platform = this.clientPlatform + if (platform !== 'mp-weixin') { + throw new Error(`[secureNetworkHandshake] platform ${platform} is not supported`) + } + const { + code, + callLoginByWeixin = false + } = params + if (callLoginByWeixin) { + return loginByWeixin.call(this, { + code, + secureNetworkCache: true + }) + } + + const weixinApi = initWeixin.call(this) + let getWeixinAccountResult + try { + getWeixinAccountResult = await weixinApi.code2Session(code) + } catch (error) { + console.error(error) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + const { + openid, + unionid, + sessionKey // 微信小程序用户sessionKey + } = getWeixinAccountResult + await saveSecureNetworkCache.call(this, { + code, + openid, + unionid, + sessionKey + }) + await saveWeixinUserKey.call(this, { + openid, + sessionKey + }) + + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/set-push-cid.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/set-push-cid.js new file mode 100644 index 0000000..9e08183 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/set-push-cid.js @@ -0,0 +1,132 @@ +const { + deviceCollection +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +async function setOpendbDevice ({ + pushClientId +} = {}) { + // 仅新增,如果存在进行更新操作 + const { + appId, + deviceId, + deviceBrand, + deviceModel, + osName, + osVersion, + osLanguage, + osTheme, + devicePixelRatio, + windowWidth, + windowHeight, + screenWidth, + screenHeight, + romName, + romVersion + } = this.getUniversalClientInfo() + const platform = this.clientPlatform + const now = Date.now() + + const db = uniCloud.database() + const opendbDeviceCollection = db.collection('opendb-device') + const getDeviceRes = await opendbDeviceCollection.where({ + device_id: deviceId + }).get() + const data = { + appid: appId, + device_id: deviceId, + vendor: deviceBrand, + model: deviceModel, + uni_platform: platform, + os_name: osName, + os_version: osVersion, + os_language: osLanguage, + os_theme: osTheme, + pixel_ratio: devicePixelRatio, + window_width: windowWidth, + window_height: windowHeight, + screen_width: screenWidth, + screen_height: screenHeight, + rom_name: romName, + rom_version: romVersion, + last_update_date: now, + push_clientid: pushClientId + } + if (getDeviceRes.data.length > 0) { + await opendbDeviceCollection.where({ + device_id: deviceId + }).update(data) + return + } + data.create_date = now + await opendbDeviceCollection.add(data) +} + +/** + * 更新device表的push_clien_id + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-push-cid + * @param {object} params + * @param {string} params.pushClientId 客户端pushClientId + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + pushClientId: 'string' + } + this.middleware.validate(params, schema) + const { + deviceId, + appId, + osName + } = this.getUniversalClientInfo() + let platform = this.clientPlatform + if (platform === 'app') { + platform += osName + } + + const { + uid, + exp + } = this.authInfo + const { pushClientId } = params + const tokenExpired = exp * 1000 + const getDeviceRes = await deviceCollection.where({ + device_id: deviceId + }).get() + // console.log(getDeviceRes) + if (getDeviceRes.data.length > 1) { + return { + errCode: ERROR.SYSTEM_ERROR + } + } + const deviceRecord = getDeviceRes.data[0] + await setOpendbDevice.call(this, { + pushClientId + }) + if (!deviceRecord) { + await deviceCollection.add({ + user_id: uid, + device_id: deviceId, + token_expired: tokenExpired, + push_clientid: pushClientId, + appid: appId + }) + return { + errCode: 0 + } + } + + await deviceCollection.where({ + device_id: deviceId + }).update({ + user_id: uid, + token_expired: tokenExpired, + push_clientid: pushClientId, + appid: appId + }) + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/create-captcha.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/create-captcha.js new file mode 100644 index 0000000..c3f7d81 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/create-captcha.js @@ -0,0 +1,35 @@ +const { + CAPTCHA_SCENE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +/** + * 创建图形验证码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#create-captcha + * @param {Object} params + * @param {String} params.scene 图形验证码使用场景 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + scene: 'string' + } + this.middleware.validate(params, schema) + + const { deviceId, platform } = this.getUniversalClientInfo() + const { + scene + } = params + if (!(Object.values(CAPTCHA_SCENE).includes(scene))) { + throw { + errCode: ERROR.INVALID_PARAM + } + } + return this.uniCaptcha.create({ + deviceId, + scene, + uniPlatform: platform + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/index.js new file mode 100644 index 0000000..fba3524 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/index.js @@ -0,0 +1,7 @@ +module.exports = { + createCaptcha: require('./create-captcha'), + refreshCaptcha: require('./refresh-captcha'), + sendSmsCode: require('./send-sms-code'), + sendEmailLink: require('./send-email-link'), + sendEmailCode: require('./send-email-code') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/refresh-captcha.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/refresh-captcha.js new file mode 100644 index 0000000..fafdc6b --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/refresh-captcha.js @@ -0,0 +1,36 @@ +const { + CAPTCHA_SCENE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +/** + * 刷新图形验证码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#refresh-captcha + * @param {Object} params + * @param {String} params.scene 图形验证码使用场景 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + scene: 'string' + } + this.middleware.validate(params, schema) + + const { deviceId, platform } = this.getUniversalClientInfo() + + const { + scene + } = params + if (!(Object.values(CAPTCHA_SCENE).includes(scene))) { + throw { + errCode: ERROR.INVALID_PARAM + } + } + return this.uniCaptcha.refresh({ + deviceId, + scene, + uniPlatform: platform + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-code.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-code.js new file mode 100644 index 0000000..1a6304d --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-code.js @@ -0,0 +1,60 @@ +const { + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + EMAIL_SCENE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') +/** + * 发送邮箱验证码,可用于登录、注册、绑定邮箱、修改密码等操作 + * @tutorial + * @param {Object} params + * @param {String} params.email 邮箱 + * @param {String} params.captcha 图形验证码 + * @param {String} params.scene 使用场景 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + email: 'email', + captcha: 'string', + scene: 'string' + } + this.middleware.validate(params, schema) + + const { + email, + captcha, + scene + } = params + + if (!(Object.values(EMAIL_SCENE).includes(scene))) { + throw { + errCode: ERROR.INVALID_PARAM + } + } + + await verifyCaptcha.call(this, { + scene: 'send-email-code', + captcha + }) + + // -- 测试代码 + await require('../../lib/utils/verify-code') + .setEmailVerifyCode.call(this, { + email, + code: '123456', + expiresIn: 180, + scene + }) + return { + errCode: 'uni-id-invalid-mail-template', + errMsg: `已启动测试模式,直接使用:123456作为邮箱验证码即可。\n如果是正式项目,需自行实现发送邮件的相关功能` + } + // -- 测试代码 + + + //发送邮件--需自行实现 +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-link.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-link.js new file mode 100644 index 0000000..f643434 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-link.js @@ -0,0 +1,12 @@ +/** + * 发送邮箱链接,可用于登录、注册、绑定邮箱、修改密码等操作 + * @tutorial + * @param {Object} params + * @param {String} params.email 邮箱 + * @param {String} params.scene 使用场景 + * @returns + */ +module.exports = async function (params = {}) { + // 此接口暂未实现,欢迎向我们提交pr + throw new Error('api[sendEmailLink] is not yet implemented') +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-sms-code.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-sms-code.js new file mode 100644 index 0000000..b392e7e --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-sms-code.js @@ -0,0 +1,71 @@ +const { + sendSmsCode +} = require('../../lib/utils/sms') +const { + verifyCaptcha +} = require('../../lib/utils/captcha') +const { + SMS_SCENE +} = require('../../common/constants') +const { + ERROR +} = require('../../common/error') + +/** + * 发送短信验证码 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#send-sms-code + * @param {Object} params + * @param {String} params.mobile 手机号 + * @param {String} params.captcha 图形验证码 + * @param {String} params.scene 短信验证码使用场景 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + mobile: 'mobile', + captcha: 'string', + scene: 'string' + } + this.middleware.validate(params, schema) + const { + mobile, + captcha, + scene + } = params + if (!(Object.values(SMS_SCENE).includes(scene))) { + throw { + errCode: ERROR.INVALID_PARAM + } + } + await verifyCaptcha.call(this, { + scene: 'send-sms-code', + captcha + }) + + // -- 测试代码 + const { + templateId + } = (this.config.service && + this.config.service.sms && + this.config.service.sms.scene && + this.config.service.sms.scene[scene]) || {} + if (!templateId) { + await require('../../lib/utils/verify-code') + .setMobileVerifyCode.call(this, { + mobile: params.mobile, + code: '123456', + expiresIn: 180, + scene + }) + return { + errCode: 'uni-id-invalid-sms-template-id', + errMsg: `未找到scene=${scene},的短信模版templateId。\n已启动测试模式,直接使用:123456作为短信验证码即可。\n如果是正式项目,请在路径:/common/uni-config-center/uni-id/config.json中service->sms中配置密钥等信息\n更多详情:https://uniapp.dcloud.io/uniCloud/uni-id.html#config` + } + } + // -- 测试代码 + + return sendSmsCode.call(this, { + mobile, + scene + }) +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package-lock.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package-lock.json new file mode 100644 index 0000000..48c8e83 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package-lock.json @@ -0,0 +1,2843 @@ +{ + "name": "uni-id-co", + "version": "1.1.17", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "uni-id-co", + "version": "1.1.17", + "dependencies": { + "jsonwebtoken": "8.5.1", + "lodash.merge": "^4.6.2", + "uni-captcha": "file:../../../../uni-captcha/uniCloud/cloudfunctions/common/uni-captcha", + "uni-cloud-s2s": "file:../../../../uni-cloud-s2s/uniCloud/cloudfunctions/common/uni-cloud-s2s", + "uni-config-center": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center", + "uni-id-common": "file:../../../../uni-id-common/uniCloud/cloudfunctions/common/uni-id-common", + "uni-open-bridge-common": "file:../../../../uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common" + }, + "devDependencies": { + "eslint": "^8.18.0", + "eslint-config-standard": "^17.0.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-n": "^15.2.3", + "eslint-plugin-promise": "^6.0.0" + } + }, + "../../../../uni-captcha/uniCloud/cloudfunctions/common/uni-captcha": { + "version": "0.7.0", + "license": "Apache-2.0", + "dependencies": { + "uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } + }, + "../../../../uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/node_modules/uni-config-center": { + "version": "0.0.3", + "license": "Apache-2.0" + }, + "../../../../uni-cloud-s2s/uniCloud/cloudfunctions/common/uni-cloud-s2s": { + "version": "1.0.1", + "dependencies": { + "uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } + }, + "../../../../uni-cloud-s2s/uniCloud/cloudfunctions/common/uni-cloud-s2s/node_modules/uni-config-center": { + "version": "0.0.3", + "license": "Apache-2.0" + }, + "../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center": { + "version": "0.0.3", + "license": "Apache-2.0" + }, + "../../../../uni-id-common/uniCloud/cloudfunctions/common/uni-id-common": { + "version": "1.0.16", + "license": "Apache-2.0", + "dependencies": { + "uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } + }, + "../../../../uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/node_modules/uni-config-center": { + "version": "0.0.3", + "license": "Apache-2.0" + }, + "../../../../uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common": { + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } + }, + "../../../../uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/node_modules/uni-config-center": { + "version": "0.0.3", + "license": "Apache-2.0" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.1", + "resolved": "https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", + "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmmirror.com/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmmirror.com/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "license": "BSD-3-Clause" + }, + "node_modules/builtins": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/builtins/-/builtins-5.1.0.tgz", + "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/builtins/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmmirror.com/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmmirror.com/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-standard": { + "version": "17.1.0", + "resolved": "https://registry.npmmirror.com/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", + "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", + "eslint-plugin-promise": "^6.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmmirror.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmmirror.com/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-es": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", + "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", + "dev": true, + "dependencies": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" + } + }, + "node_modules/eslint-plugin-es/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmmirror.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-n": { + "version": "15.7.0", + "resolved": "https://registry.npmmirror.com/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz", + "integrity": "sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==", + "dev": true, + "dependencies": { + "builtins": "^5.0.1", + "eslint-plugin-es": "^4.1.0", + "eslint-utils": "^3.0.0", + "ignore": "^5.1.1", + "is-core-module": "^2.11.0", + "minimatch": "^3.1.2", + "resolve": "^1.22.1", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-n/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-promise": { + "version": "6.2.0", + "resolved": "https://registry.npmmirror.com/eslint-plugin-promise/-/eslint-plugin-promise-6.2.0.tgz", + "integrity": "sha512-QmAqwizauvnKOlifxyDj2ObfULpHQawlg/zQdgEixur9vl0CvZGv/LCJV2rtj3210QCoeGBzVMfMXqGAOr/4fA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmmirror.com/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmmirror.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmmirror.com/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmmirror.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmmirror.com/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmmirror.com/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "5.7.2", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmmirror.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmmirror.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/uni-captcha": { + "resolved": "../../../../uni-captcha/uniCloud/cloudfunctions/common/uni-captcha", + "link": true + }, + "node_modules/uni-cloud-s2s": { + "resolved": "../../../../uni-cloud-s2s/uniCloud/cloudfunctions/common/uni-cloud-s2s", + "link": true + }, + "node_modules/uni-config-center": { + "resolved": "../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center", + "link": true + }, + "node_modules/uni-id-common": { + "resolved": "../../../../uni-id-common/uniCloud/cloudfunctions/common/uni-id-common", + "link": true + }, + "node_modules/uni-open-bridge-common": { + "resolved": "../../../../uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common", + "link": true + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package.json new file mode 100644 index 0000000..d7427b8 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package.json @@ -0,0 +1,32 @@ +{ + "name": "uni-id-co", + "version": "1.1.17", + "description": "", + "main": "index.js", + "keywords": [], + "author": "DCloud", + "dependencies": { + "jsonwebtoken": "8.5.1", + "lodash.merge": "^4.6.2", + "uni-captcha": "file:../../../../uni-captcha/uniCloud/cloudfunctions/common/uni-captcha", + "uni-config-center": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center", + "uni-id-common": "file:../../../../uni-id-common/uniCloud/cloudfunctions/common/uni-id-common", + "uni-open-bridge-common": "file:../../../../uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common", + "uni-cloud-s2s": "file:../../../../uni-cloud-s2s/uniCloud/cloudfunctions/common/uni-cloud-s2s" + }, + "extensions": { + "uni-cloud-redis": {}, + "uni-cloud-sms": {}, + "uni-cloud-verify": {} + }, + "cloudfunction-config": { + "keepRunningAfterReturn": false + }, + "devDependencies": { + "eslint": "^8.18.0", + "eslint-config-standard": "^17.0.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-n": "^15.2.3", + "eslint-plugin-promise": "^6.0.0" + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/database/opendb-frv-logs.schema.json b/uni_modules/uni-id-pages/uniCloud/database/opendb-frv-logs.schema.json new file mode 100644 index 0000000..ba36734 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/database/opendb-frv-logs.schema.json @@ -0,0 +1 @@ +{"bsonType":"object","permission":{"read":"doc._id == auth.uid || 'CREATE_UNI_ID_USERS' in auth.permission","create":"'CREATE_UNI_ID_USERS' in auth.permission","update":"doc._id == auth.uid || 'UPDATE_UNI_ID_USERS' in auth.permission","delete":"'DELETE_UNI_ID_USERS' in auth.permission"},"properties":{"_id":{"description":"存储文档 ID(用户 ID),系统自动生成"},"certify_id":{"bsonType":"string","description":"认证id"},"user_id":{"bsonType":"string","description":"用户id"},"real_name":{"bsonType":"string","description":"姓名"},"identity":{"bsonType":"string","description":"身份证号码"},"status":{"bsonType":"int","description":"认证状态:0 未认证 1 等待认证 2 认证通过 3 认证失败","maximum":3,"minimum":0},"created_date":{"bsonType":"timestamp","description":"创建时间","forceDefaultValue":{"$env":"now"}}},"required":[]} \ No newline at end of file diff --git a/uni_modules/uni-image-menu/changelog.md b/uni_modules/uni-image-menu/changelog.md new file mode 100644 index 0000000..e69de29 diff --git a/uni_modules/uni-image-menu/js_sdk/uni-image-menu.js b/uni_modules/uni-image-menu/js_sdk/uni-image-menu.js new file mode 100644 index 0000000..b482b83 --- /dev/null +++ b/uni_modules/uni-image-menu/js_sdk/uni-image-menu.js @@ -0,0 +1,169 @@ +var nvMask,nvImageMenu; +export default { + show({list,cancelText},callback){ + console.log(789789879); + if(!list){ + list = [{ + "img":"/static/sharemenu/wechatfriend.png", + "text":"图标文字" + }] + } + //以下为计算菜单的nview绘制布局,为固定算法,使用者无关关心 + var screenWidth = plus.screen.resolutionWidth + //以360px宽度屏幕为例,上下左右边距及2排按钮边距留25像素,图标宽度55像素,同行图标间的间距在360宽的屏幕是30px,但需要动态计算,以此原则计算4列图标分别的left位置 + //图标下的按钮文字距离图标5像素,文字大小12像素 + //底部取消按钮高度固定为44px + //TODO 未处理横屏和pad,这些情况6个图标应该一排即可 + var margin = 20, + iconWidth = 60, + icontextSpace = 5, + textHeight = 12 + var left1 = margin / 360 * screenWidth + var iconSpace = (screenWidth - (left1 * 2) - (iconWidth * 4)) / 3 //屏幕宽度减去左右留白间距,再减去4个图标的宽度,就是3个同行图标的间距 + if (iconSpace <= 5) { //屏幕过窄时,缩小边距和图标大小,再算一次 + margin = 15 + iconWidth = 40 + left1 = margin / 360 * screenWidth + iconSpace = (screenWidth - (left1 * 2) - (iconWidth * 4)) / 3 //屏幕宽度减去左右留白间距,再减去4个图标的宽度,就是3个同行图标的间距 + } + var left2 = left1 + iconWidth + iconSpace + var left3 = left1 + (iconWidth + iconSpace) * 2 + var left4 = left1 + (iconWidth + iconSpace) * 3 + var top1 = left1 + var top2 = top1 + iconWidth + icontextSpace + textHeight + left1 + + const TOP = {top1,top2}, LEFT = {left1,left2,left3,left4}; + + nvMask = new plus.nativeObj.View("nvMask", { //先创建遮罩层 + top: '0px', + left: '0px', + height: '100%', + width: '100%', + backgroundColor: 'rgba(0,0,0,0.2)' + }); + nvMask.addEventListener("click", function() { //处理遮罩层点击 + nvMask.hide(); + nvImageMenu.hide(); + }) + nvImageMenu = new plus.nativeObj.View("nvImageMenu", { //创建底部图标菜单 + bottom: '0px', + left: '0px', + height: (iconWidth + textHeight + 2 * margin)*Math.ceil(list.length/4) +44+'px',//'264px', + width: '100%', + backgroundColor: 'rgb(255,255,255)' + }); + + let myList = [] + list.forEach((item,i)=>{ + myList.push({ + tag: 'img', + src: item.img, + position: { + top: TOP['top'+( parseInt(i/4) +1)], + left: LEFT['left'+(1+i%4)], + width: iconWidth, + height: iconWidth + } + }) + myList.push({ + tag: 'font', + text: item.text, + textStyles: { + size: textHeight + }, + position: { + top: TOP['top'+(parseInt(i/4)+1)] + iconWidth + icontextSpace, + left: LEFT['left'+(1+i%4)], + width: iconWidth, + height: textHeight + } + }) + }) + + //绘制底部图标菜单的内容 + nvImageMenu.draw([ + { + tag: 'rect',//菜单顶部的分割灰线 + color: '#e7e7e7', + position: { + top: '0px', + height: '1px' + } + }, + { + tag: 'font', + text: cancelText,//底部取消按钮的文字 + textStyles: { + size: '14px' + }, + position: { + bottom: '0px', + height: '44px' + } + }, + { + tag: 'rect',//底部取消按钮的顶部边线 + color: '#e7e7e7', + position: { + bottom: '45px', + height: '1px' + } + }, + ...myList + ]) + nvMask.show() + nvImageMenu.show() //5+应支持从底部向上弹出的动画 + + + + nvImageMenu.addEventListener("click",e=>{ //处理底部图标菜单的点击事件,根据点击位置触发不同的逻辑 + // console.log("click menu"+JSON.stringify(e)); + if (e.screenY > plus.screen.resolutionHeight - 44) { //点击了底部取消按钮 + nvMask.hide(); + nvImageMenu.hide(); + } else if (e.clientX < 5 || e.clientX > screenWidth - 5 || e.clientY < 5) { + //屏幕左右边缘5像素及菜单顶部5像素不处理点击 + } else { //点击了图标按钮 + var iClickIndex = -1 //点击的图标按钮序号,第一个图标按钮的index为0 + var iRow = e.clientY < (top2 - (left1 / 2)) ? 0 : 1 + var iCol = -1 + if (e.clientX < (left2 - (iconSpace / 2))) { + iCol = 0 + } else if (e.clientX < (left3 - (iconSpace / 2))) { + iCol = 1 + } else if (e.clientX < (left4 - (iconSpace / 2))) { + iCol = 2 + } else { + iCol = 3 + } + if (iRow == 0) { + iClickIndex = iCol + } else { + iClickIndex = iCol + 4 + } + // console.log("点击按钮的序号: " + iClickIndex); + // if (iClickIndex >= 0 && iClickIndex <= 5) { //处理具体的点击逻辑,此处也可以自行定义逻辑。如果增减了按钮,此处也需要跟着修改 + // } + callback(iClickIndex) + this.hide() + } + }) + /* nvImageMenu.addEventListener("touchstart", function(e) { + if (e.screenY > (plus.screen.resolutionHeight - 44)) { + //TODO 这里可以处理按下背景变灰的效果 + } + }) + nvImageMenu.addEventListener("touchmove", function(e) { + //TODO 这里可以处理按下背景变灰的效果 + if (e.screenY > plus.screen.resolutionHeight - 44) {} + }) + nvImageMenu.addEventListener("touchend", function(e) { + //TODO 这里可以处理释放背景恢复的效果 + }) + */ + }, + hide(){ + nvMask.hide() + nvImageMenu.hide() + } +} \ No newline at end of file diff --git a/uni_modules/uni-image-menu/package.json b/uni_modules/uni-image-menu/package.json new file mode 100644 index 0000000..5938aa9 --- /dev/null +++ b/uni_modules/uni-image-menu/package.json @@ -0,0 +1,76 @@ +{ + "id": "uni-image-menu", + "displayName": "uni-image-menu", + "version": "1.0.0", + "description": "uni-image-menu", + "keywords": [ + "uni-image-menu" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "category": [ + "JS SDK", + "JS SDK" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "", + "data": "", + "permissions": "" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "u", + "aliyun": "u" + }, + "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" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-image-menu/readme.md b/uni_modules/uni-image-menu/readme.md new file mode 100644 index 0000000..ecca1b0 --- /dev/null +++ b/uni_modules/uni-image-menu/readme.md @@ -0,0 +1,19 @@ +# uni-image-menu + +使用示例: +``` +import uniImageMenu from 'uni_modules/uni-image-menu/js_sdk/uni-image-menu.js'; +uniImageMenu.show({ + list:[{ + "img": "/static/sharemenu/wechatfriend.png", + "text": "微信好友" + }, + { + "img": "/static/sharemenu/wechatmoments.png", + "text": "微信朋友圈" + }], + cancelText:param.cancelText +}, e => { + console.log(e) +}) +``` \ No newline at end of file diff --git a/uni_modules/uni-indexed-list/changelog.md b/uni_modules/uni-indexed-list/changelog.md new file mode 100644 index 0000000..08fa71c --- /dev/null +++ b/uni_modules/uni-indexed-list/changelog.md @@ -0,0 +1,17 @@ +## 1.2.1(2021-11-22) +- 修复 vue3中某些scss变量无法找到的问题 +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-indexed-list](https://uniapp.dcloud.io/component/uniui/uni-indexed-list) +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.11(2021-05-12) +- 新增 组件示例地址 +## 1.0.10(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 1.0.9(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.8(2021-02-05) +- 调整为uni_modules目录规范 +- 新增 支持 PC 端 diff --git a/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list-item.vue b/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list-item.vue new file mode 100644 index 0000000..19284bd --- /dev/null +++ b/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list-item.vue @@ -0,0 +1,144 @@ + + + + + diff --git a/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list.vue b/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list.vue new file mode 100644 index 0000000..ee3a7ec --- /dev/null +++ b/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list.vue @@ -0,0 +1,367 @@ + + + diff --git a/uni_modules/uni-indexed-list/package.json b/uni_modules/uni-indexed-list/package.json new file mode 100644 index 0000000..125c0e7 --- /dev/null +++ b/uni_modules/uni-indexed-list/package.json @@ -0,0 +1,89 @@ +{ + "id": "uni-indexed-list", + "displayName": "uni-indexed-list 索引列表", + "version": "1.2.1", + "description": "索引列表组件,右侧带索引的列表,方便快速定位到具体内容,通常用于城市/机场选择等场景", + "keywords": [ + "uni-ui", + "索引列表", + "索引", + "列表" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-icons" + ], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-indexed-list/readme.md b/uni_modules/uni-indexed-list/readme.md new file mode 100644 index 0000000..44ad84b --- /dev/null +++ b/uni_modules/uni-indexed-list/readme.md @@ -0,0 +1,11 @@ + + +## IndexedList 索引列表 +> **组件名:uni-indexed-list** +> 代码块: `uIndexedList` + + +用于展示索引列表。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-indexed-list) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 diff --git a/uni_modules/uni-link/changelog.md b/uni_modules/uni-link/changelog.md new file mode 100644 index 0000000..2cfbf59 --- /dev/null +++ b/uni_modules/uni-link/changelog.md @@ -0,0 +1,17 @@ +## 1.0.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-link](https://uniapp.dcloud.io/component/uniui/uni-link) +## 1.1.7(2021-11-08) +## 0.0.7(2021-09-03) +- 修复 在 nvue 下不显示的 bug +## 0.0.6(2021-07-30) +- 新增 支持自定义插槽 +## 0.0.5(2021-06-21) +- 新增 download 属性,H5平台下载文件名 +## 0.0.4(2021-05-12) +- 新增 组件示例地址 +## 0.0.3(2021-03-09) +- 新增 href 属性支持 tel:|mailto: + +## 0.0.2(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-link/components/uni-link/uni-link.vue b/uni_modules/uni-link/components/uni-link/uni-link.vue new file mode 100644 index 0000000..27c5468 --- /dev/null +++ b/uni_modules/uni-link/components/uni-link/uni-link.vue @@ -0,0 +1,128 @@ + + + + + diff --git a/uni_modules/uni-link/package.json b/uni_modules/uni-link/package.json new file mode 100644 index 0000000..77b1986 --- /dev/null +++ b/uni_modules/uni-link/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-link", + "displayName": "uni-link 超链接", + "version": "1.0.0", + "description": "uni-link是一个外部网页超链接组件,在小程序内复制url,在app内打开外部浏览器,在h5端打", + "keywords": [ + "uni-ui", + "uniui", + "link", + "超链接", + "" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "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" + }, + "快应用": { + "华为": "y", + "联盟": "y" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-link/readme.md b/uni_modules/uni-link/readme.md new file mode 100644 index 0000000..7f09e94 --- /dev/null +++ b/uni_modules/uni-link/readme.md @@ -0,0 +1,11 @@ + + +## Link 链接 +> **组件名:uni-link** +> 代码块: `uLink` + + +uni-link是一个外部网页超链接组件,在小程序内复制url,在app内打开外部浏览器,在h5端打开新网页。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-link) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-list/changelog.md b/uni_modules/uni-list/changelog.md new file mode 100644 index 0000000..8254a18 --- /dev/null +++ b/uni_modules/uni-list/changelog.md @@ -0,0 +1,46 @@ +## 1.2.14(2023-04-14) +- 优化 uni-list-chat 具名插槽`header` 非app端套一层元素,方便使用时通过外层元素定位实现样式修改 +## 1.2.13(2023-03-03) +- uni-list-chat 新增 支持具名插槽`header` +## 1.2.12(2023-02-01) +- 新增 列表图标新增 customPrefix 属性 ,用法 [详见](https://uniapp.dcloud.net.cn/component/uniui/uni-icons.html#icons-props) +## 1.2.11(2023-01-31) +- 修复 无反馈效果呈现的bug +## 1.2.9(2022-11-22) +- 修复 uni-list-chat 在vue3下跳转报错的bug +## 1.2.8(2022-11-21) +- 修复 uni-list-chat avatar属性 值为本地路径时错误的问题 +## 1.2.7(2022-11-21) +- 修复 uni-list-chat avatar属性 在腾讯云版uniCloud下错误的问题 +## 1.2.6(2022-11-18) +- 修复 uni-list-chat note属性 支持:“草稿”字样功能 文本少1位的问题 +## 1.2.5(2022-11-15) +- 修复 uni-list-item 的 customStyle 属性 padding值在 H5端 无效的bug +## 1.2.4(2022-11-15) +- 修复 uni-list-item 的 customStyle 属性 padding值在nvue(vue2)下无效的bug +## 1.2.3(2022-11-14) +- uni-list-chat 新增 avatar 支持 fileId +## 1.2.2(2022-11-11) +- uni-list 新增属性 render-reverse 详情参考:[https://uniapp.dcloud.net.cn/component/list.html](https://uniapp.dcloud.net.cn/component/list.html) +- uni-list-chat note属性 支持:“草稿”字样 加红显示 详情参考uni-im:[https://ext.dcloud.net.cn/plugin?name=uni-im](https://ext.dcloud.net.cn/plugin?name=uni-im) +- uni-list-item 新增属性 customStyle 支持设置padding、backgroundColor +## 1.2.1(2022-03-30) +- 删除无用文件 +## 1.2.0(2021-11-23) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-list](https://uniapp.dcloud.io/component/uniui/uni-list) +## 1.1.3(2021-08-30) +- 修复 在vue3中to属性在发行应用的时候报错的bug +## 1.1.2(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.1.1(2021-07-21) +- 修复 与其他组件嵌套使用时,点击失效的Bug +## 1.1.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.17(2021-05-12) +- 新增 组件示例地址 +## 1.0.16(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 +## 1.0.15(2021-02-05) +- 调整为uni_modules目录规范 +- 修复 uni-list-chat 角标显示不正常的问题 diff --git a/uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue b/uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue new file mode 100644 index 0000000..b9349c2 --- /dev/null +++ b/uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue @@ -0,0 +1,107 @@ + + + + + diff --git a/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss b/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss new file mode 100644 index 0000000..311f8d9 --- /dev/null +++ b/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss @@ -0,0 +1,58 @@ +/** + * 这里是 uni-list 组件内置的常用样式变量 + * 如果需要覆盖样式,这里提供了基本的组件样式变量,您可以尝试修改这里的变量,去完成样式替换,而不用去修改源码 + * + */ + +// 背景色 +$background-color : #fff; +// 分割线颜色 +$divide-line-color : #e5e5e5; + +// 默认头像大小,如需要修改此值,注意同步修改 js 中的值 const avatarWidth = xx ,目前只支持方形头像 +// nvue 页面不支持修改头像大小 +$avatar-width : 45px ; + +// 头像边框 +$avatar-border-radius: 5px; +$avatar-border-color: #eee; +$avatar-border-width: 1px; + +// 标题文字样式 +$title-size : 16px; +$title-color : #3b4144; +$title-weight : normal; + +// 描述文字样式 +$note-size : 12px; +$note-color : #999; +$note-weight : normal; + +// 右侧额外内容默认样式 +$right-text-size : 12px; +$right-text-color : #999; +$right-text-weight : normal; + +// 角标样式 +// nvue 页面不支持修改圆点位置以及大小 +// 角标在左侧时,角标的位置,默认为 0 ,负数左/下移动,正数右/上移动 +$badge-left: 0px; +$badge-top: 0px; + +// 显示圆点时,圆点大小 +$dot-width: 10px; +$dot-height: 10px; + +// 显示角标时,角标大小和字体大小 +$badge-size : 18px; +$badge-font : 12px; +// 显示角标时,角标前景色 +$badge-color : #fff; +// 显示角标时,角标背景色 +$badge-background-color : #ff5a5f; +// 显示角标时,角标左右间距 +$badge-space : 6px; + +// 状态样式 +// 选中颜色 +$hover : #f5f5f5; diff --git a/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue b/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue new file mode 100644 index 0000000..d49fd7c --- /dev/null +++ b/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue @@ -0,0 +1,593 @@ + + + + + diff --git a/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue b/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue new file mode 100644 index 0000000..a274ac8 --- /dev/null +++ b/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue @@ -0,0 +1,534 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-list/components/uni-list/uni-list - 副本.vue b/uni_modules/uni-list/components/uni-list/uni-list - 副本.vue new file mode 100644 index 0000000..1c85003 --- /dev/null +++ b/uni_modules/uni-list/components/uni-list/uni-list - 副本.vue @@ -0,0 +1,106 @@ + + + + diff --git a/uni_modules/uni-list/components/uni-list/uni-list.vue b/uni_modules/uni-list/components/uni-list/uni-list.vue new file mode 100644 index 0000000..6ef5972 --- /dev/null +++ b/uni_modules/uni-list/components/uni-list/uni-list.vue @@ -0,0 +1,123 @@ + + + + diff --git a/uni_modules/uni-list/components/uni-list/uni-refresh.vue b/uni_modules/uni-list/components/uni-list/uni-refresh.vue new file mode 100644 index 0000000..3b4c5a2 --- /dev/null +++ b/uni_modules/uni-list/components/uni-list/uni-refresh.vue @@ -0,0 +1,65 @@ + + + + + diff --git a/uni_modules/uni-list/components/uni-list/uni-refresh.wxs b/uni_modules/uni-list/components/uni-list/uni-refresh.wxs new file mode 100644 index 0000000..818a6b7 --- /dev/null +++ b/uni_modules/uni-list/components/uni-list/uni-refresh.wxs @@ -0,0 +1,87 @@ +var pullDown = { + threshold: 95, + maxHeight: 200, + callRefresh: 'onrefresh', + callPullingDown: 'onpullingdown', + refreshSelector: '.uni-refresh' +}; + +function ready(newValue, oldValue, ownerInstance, instance) { + var state = instance.getState() + state.canPullDown = newValue; + // console.log(newValue); +} + +function touchStart(e, instance) { + var state = instance.getState(); + state.refreshInstance = instance.selectComponent(pullDown.refreshSelector); + state.canPullDown = (state.refreshInstance != null && state.refreshInstance != undefined); + if (!state.canPullDown) { + return + } + + // console.log("touchStart"); + + state.height = 0; + state.touchStartY = e.touches[0].pageY || e.changedTouches[0].pageY; + state.refreshInstance.setStyle({ + 'height': 0 + }); + state.refreshInstance.callMethod("onchange", true); +} + +function touchMove(e, ownerInstance) { + var instance = e.instance; + var state = instance.getState(); + if (!state.canPullDown) { + return + } + + var oldHeight = state.height; + var endY = e.touches[0].pageY || e.changedTouches[0].pageY; + var height = endY - state.touchStartY; + if (height > pullDown.maxHeight) { + return; + } + + var refreshInstance = state.refreshInstance; + refreshInstance.setStyle({ + 'height': height + 'px' + }); + + height = height < pullDown.maxHeight ? height : pullDown.maxHeight; + state.height = height; + refreshInstance.callMethod(pullDown.callPullingDown, { + height: height + }); +} + +function touchEnd(e, ownerInstance) { + var state = e.instance.getState(); + if (!state.canPullDown) { + return + } + + state.refreshInstance.callMethod("onchange", false); + + var refreshInstance = state.refreshInstance; + if (state.height > pullDown.threshold) { + refreshInstance.callMethod(pullDown.callRefresh); + return; + } + + refreshInstance.setStyle({ + 'height': 0 + }); +} + +function propObserver(newValue, oldValue, instance) { + pullDown = newValue; +} + +module.exports = { + touchmove: touchMove, + touchstart: touchStart, + touchend: touchEnd, + propObserver: propObserver +} diff --git a/uni_modules/uni-list/package.json b/uni_modules/uni-list/package.json new file mode 100644 index 0000000..8350efc --- /dev/null +++ b/uni_modules/uni-list/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-list", + "displayName": "uni-list 列表", + "version": "1.2.14", + "description": "List 组件 ,帮助使用者快速构建列表。", + "keywords": [ + "", + "uni-ui", + "uniui", + "列表", + "", + "list" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [ + "uni-badge", + "uni-icons" + ], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-list/readme.md b/uni_modules/uni-list/readme.md new file mode 100644 index 0000000..32c2865 --- /dev/null +++ b/uni_modules/uni-list/readme.md @@ -0,0 +1,346 @@ +## List 列表 +> **组件名:uni-list** +> 代码块: `uList`、`uListItem` +> 关联组件:`uni-list-item`、`uni-badge`、`uni-icons`、`uni-list-chat`、`uni-list-ad` + + +List 列表组件,包含基本列表样式、可扩展插槽机制、长列表性能优化、多端兼容。 + +在vue页面里,它默认使用页面级滚动。在app-nvue页面里,它默认使用原生list组件滚动。这样的长列表,在滚动出屏幕外后,系统会回收不可见区域的渲染内存资源,不会造成滚动越长手机越卡的问题。 + +uni-list组件是父容器,里面的核心是uni-list-item子组件,它代表列表中的一个可重复行,子组件可以无限循环。 + +uni-list-item有很多风格,uni-list-item组件通过内置的属性,满足一些常用的场景。当内置属性不满足需求时,可以通过扩展插槽来自定义列表内容。 + +内置属性可以覆盖的场景包括:导航列表、设置列表、小图标列表、通信录列表、聊天记录列表。 + +涉及很多大图或丰富内容的列表,比如类今日头条的新闻列表、类淘宝的电商列表,需要通过扩展插槽实现。 + +下文均有样例给出。 + +uni-list不包含下拉刷新和上拉翻页。上拉翻页另见组件:[uni-load-more](https://ext.dcloud.net.cn/plugin?id=29) + + +### 安装方式 + +本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。 + +如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55) + +> **注意事项** +> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。 +> - 组件需要依赖 `sass` 插件 ,请自行手动安装 +> - 组件内部依赖 `'uni-icons'` 、`uni-badge` 组件 +> - `uni-list` 和 `uni-list-item` 需要配套使用,暂不支持单独使用 `uni-list-item` +> - 只有开启点击反馈后,会有点击选中效果 +> - 使用插槽时,可以完全自定义内容 +> - note 、rightText 属性暂时没做限制,不支持文字溢出隐藏,使用时应该控制长度显示或通过默认插槽自行扩展 +> - 支付宝小程序平台需要在支付宝小程序开发者工具里开启 component2 编译模式,开启方式: 详情 --> 项目配置 --> 启用 component2 编译 +> - 如果需要修改 `switch`、`badge` 样式,请使用插槽自定义 +> - 在 `HBuilderX` 低版本中,可能会出现组件显示 `undefined` 的问题,请升级最新的 `HBuilderX` 或者 `cli` +> - 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + +### 基本用法 + +- 设置 `title` 属性,可以显示列表标题 +- 设置 `disabled` 属性,可以禁用当前项 + +```html + + + + + +``` + +### 多行内容显示 + +- 设置 `note` 属性 ,可以在第二行显示描述文本信息 + +```html + + + + + +``` + +### 右侧显示角标、switch + +- 设置 `show-badge` 属性 ,可以显示角标内容 +- 设置 `show-switch` 属性,可以显示 switch 开关 + +```html + + + + + +``` + +### 左侧显示略缩图、图标 + +- 设置 `thumb` 属性 ,可以在列表左侧显示略缩图 +- 设置 `show-extra-icon` 属性,并指定 `extra-icon` 可以在左侧显示图标 + +```html + + + + +``` + +### 开启点击反馈和右侧箭头 +- 设置 `clickable` 为 `true` ,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 `click` 事件 +- 设置 `link` 属性,会自动开启点击反馈,并给列表右侧添加一个箭头 +- 设置 `to` 属性,可以跳转页面,`link` 的值表示跳转方式,如果不指定,默认为 `navigateTo` + +```html + + + + + + + +``` + + +### 聊天列表示例 +- 设置 `clickable` 为 `true` ,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 `click` 事件 +- 设置 `link` 属性,会自动开启点击反馈,`link` 的值表示跳转方式,如果不指定,默认为 `navigateTo` +- 设置 `to` 属性,可以跳转页面 +- `time` 属性,通常会设置成时间显示,但是这个属性不仅仅可以设置时间,你可以传入任何文本,注意文本长度可能会影响显示 +- `avatar` 和 `avatarList` 属性同时只会有一个生效,同时设置的话,`avatarList` 属性的长度大于1 ,`avatar` 属性将失效 +- 可以通过默认插槽自定义列表右侧内容 + +```html + + + + + + + + + + + + + + + + + 刚刚 + + + + + + + +``` + +```javascript + +export default { + components: {}, + data() { + return { + avatarList: [{ + url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png' + }, { + url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png' + }, { + url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png' + }] + } + } +} + +``` + + +```css + +.chat-custom-right { + flex: 1; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + justify-content: space-between; + align-items: flex-end; +} + +.chat-custom-text { + font-size: 12px; + color: #999; +} + +``` + +## API + +### List Props + +属性名 |类型 |默认值 | 说明 +:-: |:-: |:-: | :-: +border |Boolean |true | 是否显示边框 + + +### ListItem Props + +属性名 |类型 |默认值 | 说明 +:-: |:-: |:-: | :-: +title |String |- | 标题 +note |String |- | 描述 +ellipsis |Number |0 | title 是否溢出隐藏,可选值,0:默认; 1:显示一行; 2:显示两行;【nvue 暂不支持】 +thumb |String |- | 左侧缩略图,若thumb有值,则不会显示扩展图标 +thumbSize |String |medium | 略缩图尺寸,可选值,lg:大图; medium:一般; sm:小图; +showBadge |Boolean |false | 是否显示数字角标 +badgeText |String |- | 数字角标内容 +badgeType |String |- | 数字角标类型,参考[uni-icons](https://ext.dcloud.net.cn/plugin?id=21) +badgeStyle |Object |- | 数字角标样式,使用uni-badge的custom-style参数 +rightText |String |- | 右侧文字内容 +disabled |Boolean |false | 是否禁用 +showArrow |Boolean |true | 是否显示箭头图标 +link |String |navigateTo | 新页面跳转方式,可选值见下表 +to |String |- | 新页面跳转地址,如填写此属性,click 会返回页面是否跳转成功 +clickable |Boolean |false | 是否开启点击反馈 +showSwitch |Boolean |false | 是否显示Switch +switchChecked |Boolean |false | Switch是否被选中 +showExtraIcon |Boolean |false | 左侧是否显示扩展图标 +extraIcon |Object |- | 扩展图标参数,格式为 ``{color: '#4cd964',size: '22',type: 'spinner'}``,参考 [uni-icons](https://ext.dcloud.net.cn/plugin?id=28) +direction | String |row | 排版方向,可选值,row:水平排列; column:垂直排列; 3个插槽是水平排还是垂直排,也受此属性控制 + + +#### Link Options + +属性名 | 说明 +:-: | :-: +navigateTo | 同 uni.navigateTo() +redirectTo | 同 uni.reLaunch() +reLaunch | 同 uni.reLaunch() +switchTab | 同 uni.switchTab() + +### ListItem Events + +事件称名 |说明 |返回参数 +:-: |:-: |:-: +click |点击 uniListItem 触发事件,需开启点击反馈 |- +switchChange |点击切换 Switch 时触发,需显示 switch |e={value:checked} + + + +### ListItem Slots + +名称 | 说明 +:-: | :-: +header | 左/上内容插槽,可完全自定义默认显示 +body | 中间内容插槽,可完全自定义中间内容 +footer | 右/下内容插槽,可完全自定义右侧内容 + + +> **通过插槽扩展** +> 需要注意的是当使用插槽时,内置样式将会失效,只保留排版样式,此时的样式需要开发者自己实现 +> 如果 `uni-list-item` 组件内置属性样式无法满足需求,可以使用插槽来自定义uni-list-item里的内容。 +> uni-list-item提供了3个可扩展的插槽:`header`、`body`、`footer` +> - 当 `direction` 属性为 `row` 时表示水平排列,此时 `header` 表示列表的左边部分,`body` 表示列表的中间部分,`footer` 表示列表的右边部分 +> - 当 `direction` 属性为 `column` 时表示垂直排列,此时 `header` 表示列表的上边部分,`body` 表示列表的中间部分,`footer` 表示列表的下边部分 +> 开发者可以只用1个插槽,也可以3个一起使用。在插槽中可自主编写view标签,实现自己所需的效果。 + + +**示例** + +```html + + + + + + + + + 自定义插槽 + + + + +``` + + + + + +### ListItemChat Props + +属性名 |类型 |默认值 | 说明 +:-: |:-: |:-: | :-: +title |String |- | 标题 +note |String |- | 描述 +clickable |Boolean |false | 是否开启点击反馈 +badgeText |String |- | 数字角标内容,设置为 `dot` 将显示圆点 +badgePositon |String |right | 角标位置 +link |String |navigateTo | 是否展示右侧箭头并开启点击反馈,可选值见下表 +clickable |Boolean |false | 是否开启点击反馈 +to |String |- | 跳转页面地址,如填写此属性,click 会返回页面是否跳转成功 +time |String |- | 右侧时间显示 +avatarCircle |Boolean |false | 是否显示圆形头像 +avatar |String |- | 头像地址,avatarCircle 不填时生效 +avatarList |Array |- | 头像组,格式为 [{url:''}] + +#### Link Options + +属性名 | 说明 +:-: | :-: +navigateTo | 同 uni.navigateTo() +redirectTo | 同 uni.reLaunch() +reLaunch | 同 uni.reLaunch() +switchTab | 同 uni.switchTab() + +### ListItemChat Slots + +名称 | 说明 +:- | :- +default | 自定义列表右侧内容(包括时间和角标显示) + +### ListItemChat Events +事件称名 | 说明 | 返回参数 +:-: | :-: | :-: +@click | 点击 uniListChat 触发事件 | {data:{}} ,如有 to 属性,会返回页面跳转信息 + + + + + + +## 基于uni-list扩展的页面模板 + +通过扩展插槽,可实现多种常见样式的列表 + +**新闻列表类** + +1. 云端一体混合布局:[https://ext.dcloud.net.cn/plugin?id=2546](https://ext.dcloud.net.cn/plugin?id=2546) +2. 云端一体垂直布局,大图模式:[https://ext.dcloud.net.cn/plugin?id=2583](https://ext.dcloud.net.cn/plugin?id=2583) +3. 云端一体垂直布局,多行图文混排:[https://ext.dcloud.net.cn/plugin?id=2584](https://ext.dcloud.net.cn/plugin?id=2584) +4. 云端一体垂直布局,多图模式:[https://ext.dcloud.net.cn/plugin?id=2585](https://ext.dcloud.net.cn/plugin?id=2585) +5. 云端一体水平布局,左图右文:[https://ext.dcloud.net.cn/plugin?id=2586](https://ext.dcloud.net.cn/plugin?id=2586) +6. 云端一体水平布局,左文右图:[https://ext.dcloud.net.cn/plugin?id=2587](https://ext.dcloud.net.cn/plugin?id=2587) +7. 云端一体垂直布局,无图模式,主标题+副标题:[https://ext.dcloud.net.cn/plugin?id=2588](https://ext.dcloud.net.cn/plugin?id=2588) + +**商品列表类** + +1. 云端一体列表/宫格视图互切:[https://ext.dcloud.net.cn/plugin?id=2651](https://ext.dcloud.net.cn/plugin?id=2651) +2. 云端一体列表(宫格模式):[https://ext.dcloud.net.cn/plugin?id=2671](https://ext.dcloud.net.cn/plugin?id=2671) +3. 云端一体列表(列表模式):[https://ext.dcloud.net.cn/plugin?id=2672](https://ext.dcloud.net.cn/plugin?id=2672) + +## 组件示例 + +点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/list/list](https://hellouniapp.dcloud.net.cn/pages/extUI/list/list) \ No newline at end of file diff --git a/uni_modules/uni-load-more/changelog.md b/uni_modules/uni-load-more/changelog.md new file mode 100644 index 0000000..8f03f1d --- /dev/null +++ b/uni_modules/uni-load-more/changelog.md @@ -0,0 +1,19 @@ +## 1.3.3(2022-01-20) +- 新增 showText属性 ,是否显示文本 +## 1.3.2(2022-01-19) +- 修复 nvue 平台下不显示文本的bug +## 1.3.1(2022-01-19) +- 修复 微信小程序平台样式选择器报警告的问题 +## 1.3.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-load-more](https://uniapp.dcloud.io/component/uniui/uni-load-more) +## 1.2.1(2021-08-24) +- 新增 支持国际化 +## 1.2.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.8(2021-05-12) +- 新增 组件示例地址 +## 1.1.7(2021-03-30) +- 修复 uni-load-more 在首页使用时,h5 平台报 'uni is not defined' 的 bug +## 1.1.6(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json b/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json new file mode 100644 index 0000000..a4f14a5 --- /dev/null +++ b/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json @@ -0,0 +1,5 @@ +{ + "uni-load-more.contentdown": "Pull up to show more", + "uni-load-more.contentrefresh": "loading...", + "uni-load-more.contentnomore": "No more data" +} diff --git a/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js b/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js new file mode 100644 index 0000000..de7509c --- /dev/null +++ b/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json b/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json new file mode 100644 index 0000000..f15d510 --- /dev/null +++ b/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json @@ -0,0 +1,5 @@ +{ + "uni-load-more.contentdown": "上拉显示更多", + "uni-load-more.contentrefresh": "正在加载...", + "uni-load-more.contentnomore": "没有更多数据了" +} diff --git a/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json b/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json new file mode 100644 index 0000000..a255c6d --- /dev/null +++ b/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json @@ -0,0 +1,5 @@ +{ + "uni-load-more.contentdown": "上拉顯示更多", + "uni-load-more.contentrefresh": "正在加載...", + "uni-load-more.contentnomore": "沒有更多數據了" +} diff --git a/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue b/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue new file mode 100644 index 0000000..e5eff4d --- /dev/null +++ b/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue @@ -0,0 +1,399 @@ + + + + + diff --git a/uni_modules/uni-load-more/package.json b/uni_modules/uni-load-more/package.json new file mode 100644 index 0000000..2fa6f04 --- /dev/null +++ b/uni_modules/uni-load-more/package.json @@ -0,0 +1,86 @@ +{ + "id": "uni-load-more", + "displayName": "uni-load-more 加载更多", + "version": "1.3.3", + "description": "LoadMore 组件,常用在列表里面,做滚动加载使用。", + "keywords": [ + "uni-ui", + "uniui", + "加载更多", + "load-more" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-load-more/readme.md b/uni_modules/uni-load-more/readme.md new file mode 100644 index 0000000..54dc1fa --- /dev/null +++ b/uni_modules/uni-load-more/readme.md @@ -0,0 +1,14 @@ + + +### LoadMore 加载更多 +> **组件名:uni-load-more** +> 代码块: `uLoadMore` + + +用于列表中,做滚动加载使用,展示 loading 的各种状态。 + + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-load-more) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-nav-bar/changelog.md b/uni_modules/uni-nav-bar/changelog.md new file mode 100644 index 0000000..0f9a2f1 --- /dev/null +++ b/uni_modules/uni-nav-bar/changelog.md @@ -0,0 +1,51 @@ +## 1.3.11(2023-03-29) +- 修复 自定义状态栏高度闪动BUG +## 1.3.10(2023-03-29) +- 修复 暗黑模式下边线颜色错误的bug +## 1.3.9(2022-10-13) +- 修复 条件编译错误的bug +## 1.3.8(2022-10-12) +- 修复 nvue 环境 fixed 为 true 的情况下,无法置顶的 bug +## 1.3.7(2022-08-11) +- 修复 nvue 环境下 fixed 为 true 的情况下,无法置顶的 bug +## 1.3.6(2022-06-30) +- 修复 组件示例中插槽用法无法显示内容的bug +## 1.3.5(2022-05-24) +- 新增 stat 属性 ,可开启统计title 上报 ,仅使用了title 属性且项目开启了uni统计生效 +## 1.3.4(2022-01-24) +- 更新 组件示例 +## 1.3.3(2022-01-24) +- 新增 left-width/right-width属性 ,可修改左右两侧的宽度 +## 1.3.2(2022-01-18) +- 修复 在vue下,标题不垂直居中的bug +## 1.3.1(2022-01-18) +- 修复 height 属性类型错误 +## 1.3.0(2022-01-18) +- 新增 height 属性,可修改组件高度 +- 新增 dark 属性可可开启暗黑模式 +- 优化 标题字数过多显示省略号 +- 优化 插槽,插入内容可完全覆盖 +## 1.2.1(2022-01-10) +- 修复 color 属性不生效的bug +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-nav-bar](https://uniapp.dcloud.io/component/uniui/uni-nav-bar) +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.11(2021-05-12) +- 新增 组件示例地址 +## 1.0.10(2021-04-30) +- 修复 在nvue下fixed为true,宽度不能撑满的Bug +## 1.0.9(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 1.0.8(2021-04-14) +- uni-ui 修复 uni-nav-bar 当 fixed 属性为 true 时铺不满屏幕的 bug + +## 1.0.7(2021-02-25) +- 修复 easycom 下,找不到 uni-status-bar 的bug + +## 1.0.6(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.5(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue b/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue new file mode 100644 index 0000000..c890860 --- /dev/null +++ b/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue @@ -0,0 +1,357 @@ + + + + + diff --git a/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue b/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue new file mode 100644 index 0000000..4ac73ae --- /dev/null +++ b/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/uni_modules/uni-nav-bar/package.json b/uni_modules/uni-nav-bar/package.json new file mode 100644 index 0000000..240ae95 --- /dev/null +++ b/uni_modules/uni-nav-bar/package.json @@ -0,0 +1,86 @@ +{ + "id": "uni-nav-bar", + "displayName": "uni-nav-bar 自定义导航栏", + "version": "1.3.11", + "description": "自定义导航栏组件,主要用于头部导航。", + "keywords": [ + "uni-ui", + "导航", + "导航栏", + "自定义导航栏" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-nav-bar/readme.md b/uni_modules/uni-nav-bar/readme.md new file mode 100644 index 0000000..3934b32 --- /dev/null +++ b/uni_modules/uni-nav-bar/readme.md @@ -0,0 +1,15 @@ + + +## NavBar 导航栏 +> **组件名:uni-nav-bar** +> 代码块: `uNavBar` + +导航栏组件,主要用于头部导航。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-nav-bar) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + + + + diff --git a/uni_modules/uni-notice-bar/changelog.md b/uni_modules/uni-notice-bar/changelog.md new file mode 100644 index 0000000..d526811 --- /dev/null +++ b/uni_modules/uni-notice-bar/changelog.md @@ -0,0 +1,18 @@ +## 1.2.1(2022-09-05) +- 新增 属性 fontSize,可修改文字大小。 +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-notice-bar](https://uniapp.dcloud.io/component/uniui/uni-notice-bar) +## 1.1.1(2021-11-09) +- 新增 提供组件设计资源,组件样式调整 +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.9(2021-05-12) +- 新增 组件示例地址 +## 1.0.8(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 1.0.7(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.6(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue b/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue new file mode 100644 index 0000000..98d4720 --- /dev/null +++ b/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue @@ -0,0 +1,426 @@ + + + + + diff --git a/uni_modules/uni-notice-bar/package.json b/uni_modules/uni-notice-bar/package.json new file mode 100644 index 0000000..8d9b13c --- /dev/null +++ b/uni_modules/uni-notice-bar/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-notice-bar", + "displayName": "uni-notice-bar 通告栏", + "version": "1.2.1", + "description": "NoticeBar 通告栏组件,常用于展示公告信息,可设为滚动公告", + "keywords": [ + "uni-ui", + "uniui", + "通告栏", + "公告", + "跑马灯" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-notice-bar/readme.md b/uni_modules/uni-notice-bar/readme.md new file mode 100644 index 0000000..fb2ede2 --- /dev/null +++ b/uni_modules/uni-notice-bar/readme.md @@ -0,0 +1,13 @@ + + +## NoticeBar 通告栏 +> **组件名:uni-notice-bar** +> 代码块: `uNoticeBar` + + +通告栏组件 。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-notice-bar) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-number-box/changelog.md b/uni_modules/uni-number-box/changelog.md new file mode 100644 index 0000000..aab060d --- /dev/null +++ b/uni_modules/uni-number-box/changelog.md @@ -0,0 +1,29 @@ +## 1.2.3(2023-05-23) +更新示例工程 +## 1.2.2(2023-05-08) +- 修复 change 事件执行顺序错误的问题 +## 1.2.1(2021-11-22) +- 修复 vue3中某些scss变量无法找到的问题 +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-number-box](https://uniapp.dcloud.io/component/uniui/uni-number-box) +## 1.1.2(2021-11-09) +- 新增 提供组件设计资源,组件样式调整 +## 1.1.1(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.1.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.7(2021-05-12) +- 新增 组件示例地址 +## 1.0.6(2021-04-20) +- 修复 uni-number-box 浮点数运算不精确的 bug +- 修复 uni-number-box change 事件触发不正确的 bug +- 新增 uni-number-box v-model 双向绑定 +## 1.0.5(2021-02-05) +- 调整为uni_modules目录规范 + +## 1.0.7(2021-02-05) +- 调整为uni_modules目录规范 +- 新增 支持 v-model +- 新增 支持 focus、blur 事件 +- 新增 支持 PC 端 diff --git a/uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue b/uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue new file mode 100644 index 0000000..40786f5 --- /dev/null +++ b/uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue @@ -0,0 +1,221 @@ + + + diff --git a/uni_modules/uni-number-box/package.json b/uni_modules/uni-number-box/package.json new file mode 100644 index 0000000..743d2e4 --- /dev/null +++ b/uni_modules/uni-number-box/package.json @@ -0,0 +1,82 @@ +{ + "id": "uni-number-box", + "displayName": "uni-number-box 数字输入框", + "version": "1.2.3", + "description": "NumberBox 带加减按钮的数字输入框组件,用户可以控制每次点击增加的数值,支持小数。", + "keywords": [ + "uni-ui", + "uniui", + "数字输入框" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-number-box/readme.md b/uni_modules/uni-number-box/readme.md new file mode 100644 index 0000000..affc56f --- /dev/null +++ b/uni_modules/uni-number-box/readme.md @@ -0,0 +1,13 @@ + + +## NumberBox 数字输入框 +> **组件名:uni-number-box** +> 代码块: `uNumberBox` + + +带加减按钮的数字输入框。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-number-box) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-open-bridge-common/changelog.md b/uni_modules/uni-open-bridge-common/changelog.md new file mode 100644 index 0000000..e97c535 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/changelog.md @@ -0,0 +1,25 @@ +## 1.2.0(2023-04-27) +- 优化 微信小程序平台 使用微信新增 API getStableAccessToken 获取 access_token, access_token 有效期内重复调用该接口不会更新 access_token, [详情](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getStableAccessToken.html) +## 1.1.5(2023-03-27) +- 修复 微信小程序平台 某些情况下 encrypt_key 插入错误的问题 +## 1.1.4(2023-03-13) +- 修复 平台 weixin-web +## 1.1.3(2023-03-13) +- 新增 支持旧版本 uni-id 配置 +- 新增 支持平台 weixin-app|qq-mp|qq-app +## 1.1.2(2023-02-28) +- 新增 config 配置错误提示语 +## 1.1.1(2023-02-28) +- 新增 支持 provider 参数,和 platform 保持一致 +## 1.1.0(2023-02-27) +- 重要更新 调整数据库key格式,兼容旧版本API,如果开发者通过手动拼接key查询数据库需要修改现有逻辑 + + 原格式: uni-id:[dcloudAppid]:[platform]:[openid]:[access-token|user-access-token|session-key|encrypt-key-version|ticket] + + 新格式: uni-id:[provider]:[appid]:[openid]:[access-token|user-access-token|session-key|encrypt-key-version|ticket] +## 1.0.4(2022-09-21) +- 新增 支持使用阿里云固定IP获取微信公众号H5凭据 access_token、ticket,开发者需要在微信公众平台配置阿里云固定IP,[固定IP详情](https://uniapp.dcloud.net.cn/uniCloud/cf-functions.html#aliyun-eip) +## 1.0.3(2022-09-06) +- 修复 过期时间问题,容错 AccessToken 默认 fallback 逻辑,当微信服务器没有返回过期时间时设置为2小时后过期 +## 1.0.2(2022-09-02) +- 新增 依赖数据表schema opendb-open-data +## 1.0.0(2022-08-22) +- 首次发布 diff --git a/uni_modules/uni-open-bridge-common/package.json b/uni_modules/uni-open-bridge-common/package.json new file mode 100644 index 0000000..30f2620 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/package.json @@ -0,0 +1,84 @@ +{ + "id": "uni-open-bridge-common", + "displayName": "uni-open-bridge-common", + "version": "1.2.0", + "description": "统一接管微信等三方平台认证凭据", + "keywords": [ + "uni-open-bridge-common", + "access_token", + "session_key", + "ticket" +], + "repository": "", + "engines": { + "HBuilderX": "^3.5.2" + }, + "dcloudext": { + "type": "unicloud-template-function", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "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", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-open-bridge-common/readme.md b/uni_modules/uni-open-bridge-common/readme.md new file mode 100644 index 0000000..3892384 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/readme.md @@ -0,0 +1,5 @@ +# uni-open-bridge-common + +`uni-open-bridge-common` 是统一接管微信等三方平台认证凭据(包括但不限于`access_token`、`session_key`、`encrypt_key`、`ticket`)的开源库。 + +文档链接 [https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge#common](https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge#common) diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/bridge-error.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/bridge-error.js new file mode 100644 index 0000000..95160a4 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/bridge-error.js @@ -0,0 +1,26 @@ +'use strict'; + +class BridgeError extends Error { + + constructor(code, message) { + super(message) + + this._code = code + } + + get code() { + return this._code + } + + get errCode() { + return this._code + } + + get errMsg() { + return this.message + } +} + +module.exports = { + BridgeError +} diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/config.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/config.js new file mode 100644 index 0000000..d083f00 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/config.js @@ -0,0 +1,124 @@ +'use strict'; + +const { + ProviderType +} = require('./consts.js') + +const configCenter = require('uni-config-center') + +// 多维数据为兼容uni-id以前版本配置 +const OauthConfig = { + 'weixin-app': [ + ['app', 'oauth', 'weixin'], + ['app-plus', 'oauth', 'weixin'] + ], + 'weixin-mp': [ + ['mp-weixin', 'oauth', 'weixin'] + ], + 'weixin-h5': [ + ['web', 'oauth', 'weixin-h5'], + ['h5-weixin', 'oauth', 'weixin'], + ['h5', 'oauth', 'weixin'] + ], + 'weixin-web': [ + ['web', 'oauth', 'weixin-web'] + ], + 'qq-app': [ + ['app', 'oauth', 'qq'], + ['app-plus', 'oauth', 'qq'] + ], + 'qq-mp': [ + ['mp-qq', 'oauth', 'qq'] + ] +} + +const Support_Platforms = [ + ProviderType.WEIXIN_MP, + ProviderType.WEIXIN_H5, + ProviderType.WEIXIN_APP, + ProviderType.WEIXIN_WEB, + ProviderType.QQ_MP, + ProviderType.QQ_APP +] + +class ConfigBase { + + constructor() { + const uniIdConfigCenter = configCenter({ + pluginId: 'uni-id' + }) + + this._uniIdConfig = uniIdConfigCenter.config() + } + + getAppConfig(appid) { + if (Array.isArray(this._uniIdConfig)) { + return this._uniIdConfig.find((item) => { + return (item.dcloudAppid === appid) + }) + } + return this._uniIdConfig + } +} + +class AppConfig extends ConfigBase { + + constructor() { + super() + } + + get(appid, platform) { + if (!this.isSupport(platform)) { + return null + } + + let appConfig = this.getAppConfig(appid) + if (!appConfig) { + return null + } + + return this.getOauthConfig(appConfig, platform) + } + + isSupport(platformName) { + return (Support_Platforms.indexOf(platformName) >= 0) + } + + getOauthConfig(appConfig, platformName) { + let treePath = OauthConfig[platformName] + let node = this.findNode(appConfig, treePath) + if (node && node.appid && node.appsecret) { + return { + appid: node.appid, + secret: node.appsecret + } + } + return null + } + + findNode(treeNode, arrayPath) { + let node = treeNode + for (let treePath of arrayPath) { + for (let name of treePath) { + const currentNode = node[name] + if (currentNode) { + node = currentNode + } else { + node = null + break + } + } + if (node === null) { + node = treeNode + } else { + break + } + } + return node + } +} + + +module.exports = { + AppConfig +}; \ No newline at end of file diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/consts.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/consts.js new file mode 100644 index 0000000..4c666e9 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/consts.js @@ -0,0 +1,30 @@ +'use strict'; + +const TAG = "UNI_OPEN_BRIDGE" + +const HTTP_STATUS = { + SUCCESS: 200 +} + +const ProviderType = { + WEIXIN_MP: 'weixin-mp', + WEIXIN_H5: 'weixin-h5', + WEIXIN_APP: 'weixin-app', + WEIXIN_WEB: 'weixin-web', + QQ_MP: 'qq-mp', + QQ_APP: 'qq-app' +} + +// old +const PlatformType = ProviderType + +const ErrorCodeType = { + SYSTEM_ERROR: TAG + "_SYSTEM_ERROR" +} + +module.exports = { + HTTP_STATUS, + ProviderType, + PlatformType, + ErrorCodeType +} diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/index.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/index.js new file mode 100644 index 0000000..fc23cd9 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/index.js @@ -0,0 +1,317 @@ +'use strict'; + +const { + PlatformType, + ProviderType, + ErrorCodeType +} = require('./consts.js') + +const { + AppConfig +} = require('./config.js') + +const { + Storage +} = require('./storage.js') + +const { + BridgeError +} = require('./bridge-error.js') + +const { + WeixinServer +} = require('./weixin-server.js') + +const appConfig = new AppConfig() + +class AccessToken extends Storage { + + constructor() { + super('access-token', ['provider', 'appid']) + } + + async update(key) { + super.update(key) + + const result = await this.getByWeixinServer(key) + + return this.set(key, result.value, result.duration) + } + + async fallback(key) { + return this.getByWeixinServer(key) + } + + async getByWeixinServer(key) { + const oauthConfig = appConfig.get(key.dcloudAppid, key.provider) + let methodName + if (key.provider === ProviderType.WEIXIN_MP) { + methodName = 'GetMPAccessTokenData' + } else if (key.provider === ProviderType.WEIXIN_H5) { + methodName = 'GetH5AccessTokenData' + } else { + throw new BridgeError(ErrorCodeType.SYSTEM_ERROR, "provider invalid") + } + + const responseData = await WeixinServer[methodName](oauthConfig) + + const duration = responseData.expires_in || (60 * 60 * 2) + delete responseData.expires_in + + return { + value: responseData, + duration + } + } +} + +class UserAccessToken extends Storage { + + constructor() { + super('user-access-token', ['provider', 'appid', 'openid']) + } +} + +class SessionKey extends Storage { + + constructor() { + super('session-key', ['provider', 'appid', 'openid']) + } +} + +class Encryptkey extends Storage { + + constructor() { + super('encrypt-key', ['provider', 'appid', 'openid']) + } + + async update(key) { + super.update(key) + + const result = await this.getByWeixinServer(key) + + return this.set(key, result.value, result.duration) + } + + getKeyString(key) { + return `${super.getKeyString(key)}-${key.version}` + } + + getExpiresIn(value) { + if (value <= 0) { + return 60 + } + return value + } + + async fallback(key) { + return this.getByWeixinServer(key) + } + + async getByWeixinServer(key) { + const accessToken = await Factory.Get(AccessToken, key) + const userSession = await Factory.Get(SessionKey, key) + + const responseData = await WeixinServer.GetUserEncryptKeyData({ + openid: key.openid, + access_token: accessToken.access_token, + session_key: userSession.session_key + }) + + const keyInfo = responseData.key_info_list.find((item) => { + return item.version === key.version + }) + + if (!keyInfo) { + throw new BridgeError(ErrorCodeType.SYSTEM_ERROR, 'key version invalid') + } + + const value = { + encrypt_key: keyInfo.encrypt_key, + iv: keyInfo.iv + } + + return { + value, + duration: keyInfo.expire_in + } + } +} + +class Ticket extends Storage { + + constructor() { + super('ticket', ['provider', 'appid']) + } + + async update(key) { + super.update(key) + + const result = await this.getByWeixinServer(key) + + return this.set(key, result.value, result.duration) + } + + async fallback(key) { + return this.getByWeixinServer(key) + } + + async getByWeixinServer(key) { + const accessToken = await Factory.Get(AccessToken, { + dcloudAppid: key.dcloudAppid, + provider: ProviderType.WEIXIN_H5 + }) + + const responseData = await WeixinServer.GetH5TicketData(accessToken) + + const duration = responseData.expires_in || (60 * 60 * 2) + delete responseData.expires_in + delete responseData.errcode + delete responseData.errmsg + + return { + value: responseData, + duration + } + } +} + + +const Factory = { + + async Get(T, key, fallback) { + Factory.FixOldKey(key) + return Factory.MakeUnique(T).get(key, fallback) + }, + + async Set(T, key, value, expiresIn) { + Factory.FixOldKey(key) + return Factory.MakeUnique(T).set(key, value, expiresIn) + }, + + async Remove(T, key) { + Factory.FixOldKey(key) + return Factory.MakeUnique(T).remove(key) + }, + + async Update(T, key) { + Factory.FixOldKey(key) + return Factory.MakeUnique(T).update(key) + }, + + FixOldKey(key) { + if (!key.provider) { + key.provider = key.platform + } + + const configData = appConfig.get(key.dcloudAppid, key.provider) + if (!configData) { + throw new BridgeError(ErrorCodeType.SYSTEM_ERROR, 'appid or provider invalid') + } + key.appid = configData.appid + }, + + MakeUnique(T) { + return new T() + } +} + + +// exports + +async function getAccessToken(key, fallback) { + return Factory.Get(AccessToken, key, fallback) +} + +async function setAccessToken(key, value, expiresIn) { + return Factory.Set(AccessToken, key, value, expiresIn) +} + +async function removeAccessToken(key) { + return Factory.Remove(AccessToken, key) +} + +async function updateAccessToken(key) { + return Factory.Update(AccessToken, key) +} + +async function getUserAccessToken(key, fallback) { + return Factory.Get(UserAccessToken, key, fallback) +} + +async function setUserAccessToken(key, value, expiresIn) { + return Factory.Set(UserAccessToken, key, value, expiresIn) +} + +async function removeUserAccessToken(key) { + return Factory.Remove(UserAccessToken, key) +} + +async function getSessionKey(key, fallback) { + return Factory.Get(SessionKey, key, fallback) +} + +async function setSessionKey(key, value, expiresIn) { + return Factory.Set(SessionKey, key, value, expiresIn) +} + +async function removeSessionKey(key) { + return Factory.Remove(SessionKey, key) +} + +async function getEncryptKey(key, fallback) { + return Factory.Get(Encryptkey, key, fallback) +} + +async function setEncryptKey(key, value, expiresIn) { + return Factory.Set(Encryptkey, key, value, expiresIn) +} + +async function removeEncryptKey(key) { + return Factory.Remove(Encryptkey, key) +} + +async function updateEncryptKey(key) { + return Factory.Update(Encryptkey, key) +} + +async function getTicket(key, fallback) { + return Factory.Get(Ticket, key, fallback) +} + +async function setTicket(key, value, expiresIn) { + return Factory.Set(Ticket, key, value, expiresIn) +} + +async function removeTicket(key) { + return Factory.Remove(Ticket, key) +} + +async function updateTicket(key) { + return Factory.Update(Ticket, key) +} + +module.exports = { + getAccessToken, + setAccessToken, + removeAccessToken, + updateAccessToken, + getUserAccessToken, + setUserAccessToken, + removeUserAccessToken, + getSessionKey, + setSessionKey, + removeSessionKey, + getEncryptKey, + setEncryptKey, + removeEncryptKey, + updateEncryptKey, + getTicket, + setTicket, + removeTicket, + updateTicket, + ProviderType, + PlatformType, + WeixinServer, + ErrorCodeType +} diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/package.json b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/package.json new file mode 100644 index 0000000..a017b49 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/package.json @@ -0,0 +1,15 @@ +{ + "name": "uni-open-bridge-common", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } +} \ No newline at end of file diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/storage.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/storage.js new file mode 100644 index 0000000..bfb13a1 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/storage.js @@ -0,0 +1,111 @@ +'use strict'; + +const { + Validator +} = require('./validator.js') + +const { + CacheKeyCascade +} = require('./uni-cloud-cache.js') + +const { + BridgeError +} = require('./bridge-error.js') + +class Storage { + + constructor(type, keys) { + this._type = type || null + this._keys = keys || [] + } + + async get(key, fallback) { + this.validateKey(key) + const result = await this.create(key, fallback).get() + return result.value + } + + async set(key, value, expiresIn) { + this.validateKey(key) + this.validateValue(value) + const expires_in = this.getExpiresIn(expiresIn) + if (expires_in !== 0) { + await this.create(key).set(this.getValue(value), expires_in) + } + } + + async remove(key) { + this.validateKey(key) + await this.create(key).remove() + } + + // virtual + async update(key) { + this.validateKey(key) + } + + async ttl(key) { + this.validateKey(key) + // 后续考虑支持 + } + + async fallback(key) {} + + getKeyString(key) { + const keyArray = [Storage.Prefix] + this._keys.forEach((name) => { + keyArray.push(key[name]) + }) + keyArray.push(this._type) + return keyArray.join(':') + } + + getValue(value) { + return value + } + + getExpiresIn(value) { + if (value !== undefined) { + return value + } + return -1 + } + + validateKey(key) { + Validator.Key(this._keys, key) + } + + validateValue(value) { + Validator.Value(value) + } + + create(key, fallback) { + const keyString = this.getKeyString(key) + const options = { + layers: [{ + type: 'database', + key: keyString + }, { + type: 'redis', + key: keyString + }] + } + + const _this = this + return new CacheKeyCascade({ + ...options, + fallback: async function() { + if (fallback) { + return fallback(key) + } else if (_this.fallback) { + return _this.fallback(key) + } + } + }) + } +} +Storage.Prefix = "uni-id" + +module.exports = { + Storage +}; diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/uni-cloud-cache.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/uni-cloud-cache.js new file mode 100644 index 0000000..2e4286b --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/uni-cloud-cache.js @@ -0,0 +1,324 @@ +const db = uniCloud.database() + +function getType(value) { + return Object.prototype.toString.call(value).slice(8, -1).toLowerCase() +} + +const validator = { + key: function(value) { + const err = new Error('Invalid key') + if (typeof value !== 'string') { + throw err + } + const valueTrim = value.trim() + if (!valueTrim || valueTrim !== value) { + throw err + } + }, + value: function(value) { + // 仅作简单校验 + const type = getType(value) + const validValueType = ['null', 'number', 'string', 'array', 'object'] + if (validValueType.indexOf(type) === -1) { + throw new Error('Invalid value type') + } + }, + duration: function(value) { + const err = new Error('Invalid duration') + if (value === undefined) { + return + } + if (typeof value !== 'number' || value === 0) { + throw err + } + } +} + +/** + * 入库时 expired 为过期时间对应的时间戳,永不过期用-1表示 + * 返回结果时 与redis对齐,-1表示永不过期,-2表示已过期或不存在 + */ +class DatabaseCache { + constructor({ + collection = 'opendb-open-data' + } = {}) { + this.type = 'db' + this.collection = db.collection(collection) + } + + _serializeValue(value) { + return value === undefined ? null : JSON.stringify(value) + } + + _deserializeValue(value) { + return value ? JSON.parse(value) : value + } + + async set(key, value, duration) { + validator.key(key) + validator.value(value) + validator.duration(duration) + value = this._serializeValue(value) + await this.collection.doc(key).set({ + value, + expired: duration && duration !== -1 ? Date.now() + (duration * 1000) : -1 + }) + } + + async _getWithDuration(key) { + const getKeyRes = await this.collection.doc(key).get() + const record = getKeyRes.data[0] + if (!record) { + return { + value: null, + duration: -2 + } + } + const value = this._deserializeValue(record.value) + const expired = record.expired + if (expired === -1) { + return { + value, + duration: -1 + } + } + const duration = expired - Date.now() + if (duration <= 0) { + await this.remove(key) + return { + value: null, + duration: -2 + } + } + return { + value, + duration: Math.floor(duration / 1000) + } + } + + async get(key, { + withDuration = true + } = {}) { + const result = await this._getWithDuration(key) + if (!withDuration) { + delete result.duration + } + return result + } + + async remove(key) { + await this.collection.doc(key).remove() + } +} + +class RedisCache { + constructor() { + this.type = 'redis' + this.redis = uniCloud.redis() + } + + _serializeValue(value) { + return value === undefined ? null : JSON.stringify(value) + } + + _deserializeValue(value) { + return value ? JSON.parse(value) : value + } + + async set(key, value, duration) { + validator.key(key) + validator.value(value) + validator.duration(duration) + value = this._serializeValue(value) + if (!duration || duration === -1) { + await this.redis.set(key, value) + } else { + await this.redis.set(key, value, 'EX', duration) + } + } + + async get(key, { + withDuration = false + } = {}) { + let value = await this.redis.get(key) + value = this._deserializeValue(value) + if (!withDuration) { + return { + value + } + } + const durationSecond = await this.redis.ttl(key) + let duration + switch (durationSecond) { + case -1: + duration = -1 + break + case -2: + duration = -2 + break + default: + duration = durationSecond + break + } + return { + value, + duration + } + } + + async remove(key) { + await this.redis.del(key) + } +} + +class Cache { + constructor({ + type, + collection + } = {}) { + if (type === 'database') { + return new DatabaseCache({ + collection + }) + } else if (type === 'redis') { + return new RedisCache() + } else { + throw new Error('Invalid cache type') + } + } +} + +class CacheKey { + constructor({ + type, + collection, + cache, + key, + fallback + } = {}) { + this.cache = cache || new Cache({ + type, + collection + }) + this.key = key + this.fallback = fallback + } + + async set(value, duration) { + await this.cache.set(this.key, value, duration) + } + + async setWithSync(value, duration, syncMethod) { + await Promise.all([ + this.set(this.key, value, duration), + syncMethod(value, duration) + ]) + } + + async get() { + let { + value, + duration + } = await this.cache.get(this.key) + if (value !== null && value !== undefined) { + return { + value, + duration + } + } + if (!this.fallback) { + return { + value: null, + duration: -2 + } + } + const fallbackResult = await this.fallback() + value = fallbackResult.value + duration = fallbackResult.duration + if (value !== null && duration !== undefined) { + await this.cache.set(this.key, value, duration) + } + return { + value, + duration + } + } + + async remove() { + await this.cache.remove(this.key) + } +} + +class CacheKeyCascade { + constructor({ + layers, // [{cache, type, collection, key}] 从低级到高级排序,[DbCacheKey, RedisCacheKey] + fallback + } = {}) { + this.layers = layers + this.cacheLayers = [] + let lastCacheKey + for (let i = 0; i < layers.length; i++) { + const { + type, + cache, + collection, + key + } = layers[i] + const lastCacheKeyTemp = lastCacheKey + try { + const currentCacheKey = new CacheKey({ + type, + collection, + cache, + key, + fallback: i === 0 ? fallback : function() { + return lastCacheKeyTemp.get() + } + }) + this.cacheLayers.push(currentCacheKey) + lastCacheKey = currentCacheKey + } catch (e) {} + } + this.highLevelCache = lastCacheKey + } + + async set(value, duration) { + return Promise.all( + this.cacheLayers.map(item => { + return item.set(value, duration) + }) + ) + } + + async setWithSync(value, duration, syncMethod) { + const setPromise = this.cacheLayers.map(item => { + return item.set(value, duration) + }) + return Promise.all( + [ + ...setPromise, + syncMethod(value, duration) + ] + ) + } + + async get() { + return this.highLevelCache.get() + } + + async remove() { + await Promise.all( + this.cacheLayers.map(cacheKeyItem => { + return cacheKeyItem.remove() + }) + ) + } +} + +module.exports = { + Cache, + DatabaseCache, + RedisCache, + CacheKey, + CacheKeyCascade +} diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/validator.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/validator.js new file mode 100644 index 0000000..47a455b --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/validator.js @@ -0,0 +1,31 @@ +const Validator = { + + Key(keyArray, parameters) { + for (let i = 0; i < keyArray.length; i++) { + const keyName = keyArray[i] + if (typeof parameters[keyName] !== 'string') { + Validator.ThrowNewError(`Invalid ${keyName}`) + } + if (parameters[keyName].length < 1) { + Validator.ThrowNewError(`Invalid ${keyName}`) + } + } + }, + + Value(value) { + if (value === undefined) { + Validator.ThrowNewError('Invalid Value') + } + if (typeof value !== 'object') { + Validator.ThrowNewError('Invalid Value Type') + } + }, + + ThrowNewError(message) { + throw new Error(message) + } +} + +module.exports = { + Validator +} diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/weixin-server.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/weixin-server.js new file mode 100644 index 0000000..ef476f1 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/weixin-server.js @@ -0,0 +1,203 @@ +'use strict'; + +const crypto = require('crypto') + +const { + HTTP_STATUS +} = require('./consts.js') + +const { + BridgeError +} = require('./bridge-error.js') + +class WeixinServer { + + constructor(options = {}) { + this._appid = options.appid + this._secret = options.secret + } + + getAccessToken() { + return uniCloud.httpclient.request(WeixinServer.AccessToken_Url, { + dataType: 'json', + method: 'POST', + contentType: 'json', + data: { + appid: this._appid, + secret: this._secret, + grant_type: "client_credential" + } + }) + } + + // 使用客户端获取的 code 从微信服务器换取 openid,code 仅可使用一次 + codeToSession(code) { + return uniCloud.httpclient.request(WeixinServer.Code2Session_Url, { + dataType: 'json', + data: { + appid: this._appid, + secret: this._secret, + js_code: code, + grant_type: 'authorization_code' + } + }) + } + + getUserEncryptKey({ + access_token, + openid, + session_key + }) { + console.log(access_token, openid, session_key); + const signature = crypto.createHmac('sha256', session_key).update('').digest('hex') + return uniCloud.httpclient.request(WeixinServer.User_Encrypt_Key_Url, { + dataType: 'json', + method: 'POST', + dataAsQueryString: true, + data: { + access_token, + openid: openid, + signature: signature, + sig_method: 'hmac_sha256' + } + }) + } + + getH5AccessToken() { + return uniCloud.httpclient.request(WeixinServer.AccessToken_H5_Url, { + dataType: 'json', + method: 'GET', + data: { + appid: this._appid, + secret: this._secret, + grant_type: "client_credential" + } + }) + } + + getH5Ticket(access_token) { + return uniCloud.httpclient.request(WeixinServer.Ticket_Url, { + dataType: 'json', + dataAsQueryString: true, + method: 'POST', + data: { + access_token + } + }) + } + + getH5AccessTokenForEip() { + return uniCloud.httpProxyForEip.postForm(WeixinServer.AccessToken_H5_Url, { + appid: this._appid, + secret: this._secret, + grant_type: "client_credential" + }, { + dataType: 'json' + }) + } + + getH5TicketForEip(access_token) { + return uniCloud.httpProxyForEip.postForm(WeixinServer.Ticket_Url, { + access_token + }, { + dataType: 'json', + dataAsQueryString: true + }) + } +} + +WeixinServer.AccessToken_Url = 'https://api.weixin.qq.com/cgi-bin/stable_token' +WeixinServer.Code2Session_Url = 'https://api.weixin.qq.com/sns/jscode2session' +WeixinServer.User_Encrypt_Key_Url = 'https://api.weixin.qq.com/wxa/business/getuserencryptkey' +WeixinServer.AccessToken_H5_Url = 'https://api.weixin.qq.com/cgi-bin/token' +WeixinServer.Ticket_Url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi' + +WeixinServer.GetMPAccessToken = function(options) { + return new WeixinServer(options).getAccessToken() +} + +WeixinServer.GetCodeToSession = function(options) { + return new WeixinServer(options).codeToSession(options.code) +} + +WeixinServer.GetUserEncryptKey = function(options) { + return new WeixinServer(options).getUserEncryptKey(options) +} + +WeixinServer.GetH5AccessToken = function(options) { + return new WeixinServer(options).getH5AccessToken() +} + +WeixinServer.GetH5Ticket = function(options) { + return new WeixinServer(options).getH5Ticket(options.access_token) +} + +//////////////////////////////////////////////////////////////// + +function isAliyun() { + return (uniCloud.getCloudInfos()[0].provider === 'aliyun') +} + +WeixinServer.GetResponseData = function(response) { + console.log("WeixinServer::response", response) + + if (!(response.status === HTTP_STATUS.SUCCESS || response.statusCodeValue === HTTP_STATUS.SUCCESS)) { + throw new BridgeError(response.status || response.statusCodeValue, response.status || response.statusCodeValue) + } + + const responseData = response.data || response.body + + if (responseData.errcode !== undefined && responseData.errcode !== 0) { + throw new BridgeError(responseData.errcode, responseData.errmsg) + } + + return responseData +} + +WeixinServer.GetMPAccessTokenData = async function(options) { + const response = await new WeixinServer(options).getAccessToken() + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetCodeToSessionData = async function(options) { + const response = await new WeixinServer(options).codeToSession(options.code) + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetUserEncryptKeyData = async function(options) { + const response = await new WeixinServer(options).getUserEncryptKey(options) + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetH5AccessTokenData = async function(options) { + const ws = new WeixinServer(options) + let response + if (isAliyun()) { + response = await ws.getH5AccessTokenForEip() + if (typeof response === 'string') { + response = JSON.parse(response) + } + } else { + response = await ws.getH5AccessToken() + } + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetH5TicketData = async function(options) { + const ws = new WeixinServer(options) + let response + if (isAliyun()) { + response = await ws.getH5TicketForEip(options.access_token) + if (typeof response === 'string') { + response = JSON.parse(response) + } + } else { + response = await ws.getH5Ticket(options.access_token) + } + return WeixinServer.GetResponseData(response) +} + + +module.exports = { + WeixinServer +} diff --git a/uni_modules/uni-open-bridge/changelog.md b/uni_modules/uni-open-bridge/changelog.md new file mode 100644 index 0000000..e69de29 diff --git a/uni_modules/uni-open-bridge/package.json b/uni_modules/uni-open-bridge/package.json new file mode 100644 index 0000000..e88a0a7 --- /dev/null +++ b/uni_modules/uni-open-bridge/package.json @@ -0,0 +1,84 @@ +{ + "id": "uni-open-bridge", + "displayName": "uni-open-bridge", + "version": "1.0.0", + "description": "uni-open-bridge", + "keywords": [ + "uni-open-bridge" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "category": [ + "uniCloud", + "云函数模板" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "", + "data": "", + "permissions": "" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "u", + "aliyun": "u" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "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", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-open-bridge/readme.md b/uni_modules/uni-open-bridge/readme.md new file mode 100644 index 0000000..9f4f9f7 --- /dev/null +++ b/uni_modules/uni-open-bridge/readme.md @@ -0,0 +1,577 @@ +# uni-open-bridge + +`uni-open-bridge` + + +## config.json + +```json +{ + "schedule": { + "__UNI__xxxxxx": { + "enable": true, + "mp-weixin": { + "enable": true, + "tasks": ["accessToken"] + }, + "h5-weixin": { + "enable": false, + "tasks": ["ticket"] + } + } + }, + "ipWhitelist": ["0.0.0.0"] +} +``` + +## http 调用 + +请求类型 `POST`, 需要配置IP白名单字段 `ipWhitelist`,参见 `config.json` + +### getAccessToken + +Url + +``` +https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/getAccessToken +``` + +参数 + +```json +{ + "dcloudAppid": "__UNI__xxx", + "platform": "mp-weixin" +} +``` + +### setAccessToken + +Url + +``` +https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/setAccessToken +``` + +```json +{ + "dcloudAppid": "__UNI__xxx", + "platform": "mp-weixin", + "value": { + "access_token": "" + }, + "expiresIn": 7200 +} +``` + +### removeAccessToken + +Url + +``` +https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/removeAccessToken +``` + +参数 + +```json +{ + "dcloudAppid": "__UNI__xxx", + "platform": "mp-weixin" +} +``` + +### getUserKey + +Url + +``` +https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/getUserKey +``` + +参数 + +```json +{ + "dcloudAppid": "__UNI__xxx", + "platform": "mp-weixin", + "openid": "" +} +``` + +### setUserKey + +Url + +``` +https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/setUserKey +``` + +参数 + +```json +{ + "dcloudAppid": "__UNI__xxx", + "platform": "mp-weixin", + "openid": "", + "value": { + "session_key": "" + }, + "expiresIn": 7200 +} +``` + +### removeUserKey + +Url + +``` +https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/removeUserKey +``` + +参数 + +```json +{ + "dcloudAppid": "__UNI__xxx", + "platform": "mp-weixin", + "openid": "" +} +``` + +### getTicket + +Url + +``` +https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/getTicket +``` + +参数 + +```json +{ + "dcloudAppid": "__UNI__xxx", + "platform": "mp-weixin" +} +``` + + +### setTicket + +Url + +``` +https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/setTicket +``` + +参数 + +```json +{ + "dcloudAppid": "__UNI__xxx", + "platform": "mp-weixin", + "value": { + "ticket": "" + }, + "expiresIn": 7200 +} +``` + +### removeTicket + +Url + +``` +https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/removeTicket +``` + +参数 + +```json +{ + "dcloudAppid": "__UNI__xxx", + "platform": "mp-weixin" +} +``` + + + + + +# uni-open-bridge-common + +`uni-open-bridge-common` 是 `uni-id` 体系中用于 `开放平台数据` 管理的公共模块。 + +> `云函数公共模块`是不同云函数共享代码的一种方式。如果你不了解什么是`云函数公共模块`,请另读文档[公共模块](https://uniapp.dcloud.io/uniCloud/cf-common) + +`uni-open-bridge-common` 提供了 `access_token`、`session_key`、`encrypt_key`、`ticket` 的读取、写入、删除操作。 + +`uni-open-bridge-common` 支持多层 读取 / 写入 机制,`redis -> database -> fallback`,优先级如下: + +如果用户没有开通 `redis` 或者操作失败,透传到 `database`,`database` 失败后,如果用户配置了 `fallback`,继续调用 `fallback` 方法,否则抛出 `Error` + +`database` 对应的表为: `opendb-open-data` + + +## access_token + +`access_token` 是微信小程序全局唯一后台接口调用凭据,调用绝大多数后台接口时都需使用。开发者可以通过 getAccessToken 接口获取并进行妥善保存。[详情](https://developers.weixin.qq.com/miniprogram/dev/framework/server-ability/backend-api.html#access_token) + + +### getAccessToken(key: Object) + +读取 access_token + + +### setAccessToken(key: Object, value: Object, expiresIn: Number) + +写入 access_token + + +### removeAccessToken(key: Object) + +删除 access_token + + +### key 属性 + +|参数 |类型 |必填 |描述 | +|:-: |:-: |:-: |:-: | +|dcloudAppid|String |是 |DCloud应用appid。[详情](https://ask.dcloud.net.cn/article/35907) | +|platform |String |是 |[详情](#platform) | +|fallback |Function |否 |[详情](#fallback) | + +### value 属性 + +|参数 |类型 |描述 | +|:-: |:-: |:-: | +|access_token |String | | + +### expiresIn + +有效时间(秒) + + +### 示例代码 + +```js +'use strict'; + +const { + getAccessToken, + setAccessToken, + removeAccessToken +} = require('uni-open-bridge-common') + +exports.main = async (event, context) => { + const key = { + dcloudAppid: '', + platform: '' + } + const value = { + access_token: '' + } + const expiresIn = 7200 + + // 写入 (redis / 数据库) + await setAccessToken(key, value, expiresIn) + + // 读取 (redis / 数据库) + let result1 = await getAccessToken(key) + + // 删除 + await removeAccessToken(key) + + + // 删除后读取, 返回 null + let result2 = await getAccessToken(key) + console.log(result2) // null + + return null +}; +``` + + +## user_key + +平台对应的值 + +|平台 |值 |描述 | +|:-: |:-: |:-: | +|微信小程序 |session_key|微信小程序会话密钥。[详情](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html) | + + +### getUserKey(key: Object) + +读取 user_key + + +### setUserKey(key: Object, value: Object, expiresIn: Number) + +写入 user_key + + +### removeUserKey(key: Object) + +删除 user_key + + +### key 属性 + +|参数 |类型 |必填 |描述 | +|:-: |:-: |:-: |:-: | +|dcloudAppid|String |是 |DCloud应用appid。[详情](https://ask.dcloud.net.cn/article/35907) | +|platform |String |是 |[详情](#platform) | +|openid |String |是 | | +|fallback |Function |否 |[详情](#fallback) | + +### value 属性 + +|参数 |类型 |描述 | +|:-: |:-: |:-: | +|session_key|String |微信小程序会话密钥 | + +### expiresIn + +有效时间(秒) + + +### 示例代码 + +```js +'use strict'; + +const { + getUserKey, + setUserKey, + removeUserKey, +} = require('uni-open-bridge-common') + +exports.main = async (event, context) => { + const key = { + dcloudAppid: '', + platform: '', + openid: '' + } + const value = { + 'session_key': '' + } + const expiresIn = 7200 + + // 写入 (redis / 数据库) + await setUserKey(key, value, expiresIn) + + // 读取 (redis / 数据库) + let result1 = await getUserKey(key) + + // 删除 + await removeUserKey(key) + + + // 删除后读取, 返回 null + let result2 = await getUserKey(key) + console.log(result2) // null + + return null +}; +``` + + +## encrypt_key + +为了避免小程序与开发者后台通信时数据被截取和篡改,微信侧维护了一个用户维度的可靠key,用于小程序和后台通信时进行加密和签名。[详情](https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/user-encryptkey.html) + +开发者可以分别通过小程序前端和微信后台提供的接口,获取用户的加密 key。 + + +### getEncryptKey(key: Object) + +读取 encrypt_key + + +### setEncryptKey(key: Object, value: Object, expiresIn: Number) + +写入 encrypt_key + + +### removeEncryptKey(key: Object) + +删除 encrypt_key + + +### key 属性 + +|参数 |类型 |必填 |描述 | +|:-: |:-: |:-: |:-: | +|dcloudAppid|String |是 |DCloud应用appid。[详情](https://ask.dcloud.net.cn/article/35907) | +|platform |String |是 |[详情](#platform) | +|openid |String |是 | | +|version |Number |是 |版本 | +|fallback |Function |否 |[详情](#fallback) | + + +### value 属性 + +|参数 |类型 |描述 | +|:-: |:-: |:-: | +|encrypt_key|String |加密 key | +|iv |String |加密 iv | + +### expiresIn + +有效时间(秒) + + +### 示例代码 + +```js +'use strict'; + +const { + getEncryptKey, + setEncryptKey, + removeEncryptKey +} = require('uni-open-bridge-common') + +exports.main = async (event, context) => { + const key = { + dcloudAppid: '', + platform: '', + openid: '', + version: 1 + } + const value = { + encrypt_key: '', + iv: '' + } + const expiresIn = 7200 + + // 写入 (redis / 数据库) + await setEncryptKey(key, value, expiresIn) + + // 读取 (redis / 数据库) + let result1 = await getEncryptKey(key) + + // 删除 + await removeEncryptKey(key) + + // 删除后读取, 返回 null + let result2 = await getEncryptKey(key) + console.log(result2) // null + + return null +}; +``` + + +## ticket + +`ticket` 是公众号用于调用微信 JS 接口的临时票据。[详情](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#62) + + +### getTicket(key: Object) + +读取 ticket + + +### setTicket(key: Object, value: Object, expiresIn: Number) + +写入 ticket + + +### removeTicket(key: Object) + +删除 ticket + + +### key 属性 + +|参数 |类型 |必填 |描述 | +|:-: |:-: |:-: |:-: | +|dcloudAppid|String |是 |DCloud应用appid。[详情](https://ask.dcloud.net.cn/article/35907) | +|platform |String |是 |[详情](#platform) | +|fallback |Function |否 |[详情](#fallback) | + +### value 属性 + +|参数 |类型 |描述 | +|:-: |:-: |:-: | +|ticket |String | | + +### expiresIn + +有效时间(秒) + + +### 示例代码 + +```js +'use strict'; + +const { + getTicket, + setTicket, + removeTicket +} = require('uni-open-bridge-common') + +exports.main = async (event, context) => { + const key = { + dcloudAppid: '', + platform: '' + } + const value = { + ticket: '' + } + const expiresIn = 7200 + + // 写入 (redis / 数据库) + await setTicket(key, value, expiresIn) + + // 读取 (redis / 数据库) + let result1 = await getTicket(key) + + // 删除 + await removeTicket(key) + + + // 删除后读取, 返回 null + let result2 = await getTicket(key) + console.log(result2) // null + + return null +}; +``` + + +## Platform@platform + +平台对应的值 + +|值 |描述 | +|:-: |:-: | +|mp-weixin |微信小程序 | +|app-weixin |微信 App | +|h5-weixin |微信公众号 | +|web-weixin |微信pc网页 | +|mp-qq |QQ 小程序 | +|app-qq |QQ App | + + +## fallback@fallback + +可选 `async function fallback()`,当 `reids -> database` 都找不到对应 `key` 时,调用此方法,需要返回数据格式如下 + +```json +{ + value: null, + duration: 1 +} +``` + + + +注意事项 + +- 所有方法类型为 `async`,需要使用 `await` +- 所有方法校验 `key` 属性是否有效,无效则 `throw new Error()`,对 `value` 仅校验是否为 `undefined` diff --git a/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/basic.js b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/basic.js new file mode 100644 index 0000000..b59f040 --- /dev/null +++ b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/basic.js @@ -0,0 +1,131 @@ +'use strict'; + +class Command { + + constructor() { + this._registered = {} + } + + async execute(name, args) { + if (this._registered[name]) { + return await this._registered[name].execute(args) + } + } + + canExecute(name, args) { + if (this._registered[name] && this._registered[name].canExecute) { + this._registered[name].canExecute(args) + } + return false + } + + register(name, execute, canExecute) { + this._registered[name] = { + execute, + canExecute + } + } +} + +class Task { + + constructor(id) { + this._id = id || this._newTaskId() + + this._state = Task.TASK_STATE.WAITING + } + + async run() {} + + async cancel() {} + + async taskAction() {} + + _newTaskId() { + let guid = '' + const format = 'xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx' + for (let i = 0; i < format.length; i++) { + if (format[i] === 'x') { + guid += (Math.random() * 16 | 0).toString(16) + } else { + guid += format[i] + } + } + return guid.toUpperCase() + } + + get id() { + return this._id + } + set id(value) { + this._id = value + } + + get state() { + return this._state + } + set state(value) { + this._state = value + } +} + +Task.TASK_STATE = { + WAITING: "WAITING", + RESOLVING: "RESOLVING", + RESOLVED: "RESOLVED", + EXECUTING: "EXECUTING", + ERROR: "ERROR", + COMPLETED: "COMPLETED", + CANCELLING: "CANCELLING", + CANCELLED: "CANCELLED" +} + +class TaskManager { + + constructor() { + this._tasks = [] + } + + get tasks() { + return this._tasks + } + + clear() { + this._tasks.length = 0 + } + + getTask(id) { + return this._tasks.find((item) => { + return (item.id == id) + }) + } + + addTask(task) { + this._tasks.push(task) + } + + deleteTask(id) { + const index = this.findIndex(id) + if (index < 0) { + return + } + + this._tasks[index].cancel() + + if (index > -1) { + this._tasks.splice(index, 1) + } + } + + findIndex(id) { + return this._tasks.findIndex((item) => { + return (item.id == id) + }) + } +} + +module.exports = { + Command, + Task, + TaskManager +}; diff --git a/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/config.js b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/config.js new file mode 100644 index 0000000..83adffa --- /dev/null +++ b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/config.js @@ -0,0 +1,197 @@ +'use strict'; + +const { + PlatformType +} = require('./consts.js') + +const configCenter = require('uni-config-center') + +const OauthConfig = { + 'mp-weixin': ['oauth', 'weixin'], + 'h5-weixin': ['oauth', 'weixin'] +} + +class TaskConfig { + + constructor(options) { + this._dcloudAppid = options.dcloudAppid + this._appid = options.appid + this._secret = options.secret + this._platform = options.platform + this._tasks = options.tasks + this._timeout = 1000 * 10 + } + + get dcloudAppid() { + return this._dcloudAppid + } + + get appid() { + return this._appid + } + + get secret() { + return this._secret + } + + get platform() { + return this._platform + } + + get tasks() { + return this._tasks + } +} + +class ConfigBase { + + constructor() { + const uniIdConfig = configCenter({ + pluginId: 'uni-id' + }) + const openBridgeConfig = configCenter({ + pluginId: 'uni-open-bridge' + }) + + this._uniId = uniIdConfig.config() + this._openBridge = openBridgeConfig.config() + + this._ready = true + } + + getAppConfig(appid) { + if (Array.isArray(this._uniId)) { + return this._uniId.find((item) => { + return (item.dcloudAppid === appid) + }) + } + + if (this._uniId.dcloudAppid === appid) { + return this._uniId + } + + return null + } + + inWhitelist(ip) { + return (this.ipWhitelist.indexOf(ip) > -1) + } + + get openBridge() { + return this._openBridge + } + + get ipWhitelist() { + return this._openBridge.ipWhitelist + } + + get ready() { + return this._ready + } +} + +class OpenBridgeConfig extends ConfigBase { + + constructor() { + super() + + this._tasks = [] + + this.resolve() + } + + get tasks() { + return this._tasks + } + + resolve() { + this._tasks.length = 0 + + const appids = Object.keys(this.openBridge.schedule) + + for (let i = 0; i < appids.length; i++) { + const appid = appids[i] + let appConfig = this.getAppConfig(appid) + + if (appConfig != null) { + const schedule = this.openBridge.schedule[appid] + if (schedule) { + this.resolveSchedule(appid, appConfig, schedule) + } + } + } + } + + resolveSchedule(dcloudAppid, appConfig, schedule) { + if (schedule.enable !== true) { + return + } + + const schedulePlatforms = Object.keys(schedule) + + for (let i = 0; i < schedulePlatforms.length; i++) { + const platformName = schedulePlatforms[i] + const scheduleTask = schedule[platformName] + + if (!scheduleTask.enable) { + continue + } + + if (!this.isSupport(platformName)) { + continue + } + + const oauthConfig = this.getOauthConfig(appConfig, platformName) + if (!oauthConfig) { + continue + } + + this._tasks.push({ + platform: platformName, + tasks: scheduleTask.tasks, + dcloudAppid: dcloudAppid, + appid: oauthConfig.appid, + secret: oauthConfig.secret + }) + } + } + + isSupport(platformName) { + return (OpenBridgeConfig.Support_Platforms.indexOf(platformName) >= 0) + } + + getOauthConfig(appConfig, platformName) { + const platformConfig = appConfig[platformName] + if (!platformConfig) { + return null + } + + let tree = OauthConfig[platformName] + let node = platformConfig + for (let i = 0; i < tree.length; i++) { + let nodeName = tree[i] + if (node[nodeName]) { + node = node[nodeName] + } else { + node = null + break + } + } + + if (node && node.appid && node.appsecret) { + return { + appid: node.appid, + secret: node.appsecret + } + } + + return null + } +} + +OpenBridgeConfig.Support_Platforms = ['mp-weixin', 'h5-weixin'] + + +module.exports = { + OpenBridgeConfig +}; diff --git a/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/consts.js b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/consts.js new file mode 100644 index 0000000..c163e96 --- /dev/null +++ b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/consts.js @@ -0,0 +1,19 @@ +'use strict'; + +const HTTP_STATUS = { + SUCCESS: 200 +} + +const PlatformType = { + MP_WEIXIN: 'mp-weixin', + H5_WEIXIN: 'h5-weixin', + APP_WEIXIN: 'app-weixin', + WEB_WEIXIN: 'web-weixin', + MP_QQ: 'mp-qq', + APP_QQ: 'app-qq' +} + +module.exports = { + HTTP_STATUS, + PlatformType +} diff --git a/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/index.mp-weixin.js b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/index.mp-weixin.js new file mode 100644 index 0000000..25556ef --- /dev/null +++ b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/index.mp-weixin.js @@ -0,0 +1,93 @@ +'use strict'; + +const { + getAccessToken, + setAccessToken, + removeAccessToken, + getUserKey, + setUserKey, + removeUserKey, + getEncryptKey, + setEncryptKey, + removeEncryptKey, + getTicket, + setTicket, + removeTicket +} = require('uni-open-bridge-common') + +const { + Command +} = require('./basic.js'); + +const { + OpenBridgeConfig +} = require('./config.js') + +const openBridgeConfig = new OpenBridgeConfig() + +class MainFrame extends Command { + + constructor() { + super() + + MainFrame.Commands.forEach((name) => { + this.register(name, this[name].bind(this)) + }) + } + + async getAccessToken(parameters) { + return await getAccessToken(parameters) + } + + async setAccessToken(parameters) { + return await setAccessToken(parameters, parameters.value, parameters.expiresIn) + } + + async removeAccessToken(parameters) { + return await removeAccessToken(parameters) + } + + async getUserKey(parameters) { + return await getUserKey(parameters, null) + } + + async setUserKey(parameters) { + return await setUserKey(parameters, parameters.value, parameters.expiresIn) + } + + async removeUserKey(parameters) { + return await removeUserKey(parameters) + } + + async getTicket(parameters) { + return await getTicket(parameters, null) + } + + async setTicket(parameters) { + return await setTicket(parameters, parameters.value, parameters.expiresIn) + } + + async removeTicket(parameters) { + return await removeTicket(parameters) + } + + checkIP(ip) { + return openBridgeConfig.inWhitelist(ip) + } +} + +MainFrame.Commands = [ + 'getAccessToken', + 'setAccessToken', + 'removeAccessToken', + 'getUserKey', + 'setUserKey', + 'removeUserKey', + 'getTicket', + 'setTicket', + 'removeTicket' +]; + +const commands = new MainFrame(); + +module.exports = commands; diff --git a/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/index.obj.js b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/index.obj.js new file mode 100644 index 0000000..71d6ae9 --- /dev/null +++ b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/index.obj.js @@ -0,0 +1,62 @@ +'use strict'; + +const { + PlatformType +} = require('./consts.js') + +const runTask = require('./index.task.js') +const weixinCommand = require('./index.mp-weixin.js') + +async function executeCommand() { + const methodName = this.getMethodName() + const parameters = JSON.parse(this.getHttpInfo().body) + + if (parameters.platform === PlatformType.MP_WEIXIN) { + return await weixinCommand.execute(methodName, parameters) + } + + throw new Error('Invalid Platform') +} + +module.exports = { + async _timing() { + console.log('triggered by timing') + await runTask() + }, + async _before() { + const clientInfo = this.getClientInfo() + if (!weixinCommand.checkIP(clientInfo.clientIP)) { + throw new Error("Invalid IP:" + clientInfo.clientIP) + } + }, + // async runTask() { + // await runTask() + // }, + async getAccessToken() { + return await executeCommand.call(this) + }, + async setAccessToken() { + return await executeCommand.call(this) + }, + async removeAccessToken() { + return await executeCommand.call(this) + }, + async getUserKey() { + return await executeCommand.call(this) + }, + async setUserKey() { + return await executeCommand.call(this) + }, + async removeUserKey() { + return await executeCommand.call(this) + }, + async getTicket() { + return await executeCommand.call(this) + }, + async setTicket() { + return await executeCommand.call(this) + }, + async removeTicket() { + return await executeCommand.call(this) + } +} diff --git a/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/index.task.js b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/index.task.js new file mode 100644 index 0000000..017dc88 --- /dev/null +++ b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/index.task.js @@ -0,0 +1,86 @@ +'use strict'; + +const { + OpenBridgeConfig +} = require('./config.js') + +const { + TaskManager +} = require('./basic.js') + +const { + TaskAccessTokenMP +} = require('./task-mp-weixin.js') + +const { + TaskAccessTokenH5, + TaskTicket +} = require('./task-h5-weixin.js') + +const TaskMapping = { + 'mp-weixin': { + 'accessToken': TaskAccessTokenMP + }, + 'h5-weixin': { + 'accessToken': TaskAccessTokenH5, + 'ticket': TaskTicket + } +} + +class ScheduleManager extends TaskManager { + + constructor() { + super() + } + + async runAll() { + for (let i = 0; i < this.tasks.length; i++) { + const task = this.tasks[i] + + try { + await task.run() + } catch (e) { + console.log("task.run::", e) + } + } + } + + newTask(T, config) { + const newTask = new T(config) + + super.addTask(newTask) + + return newTask + } +} + +ScheduleManager.instance = function() { + if (!ScheduleManager._instance) { + ScheduleManager._instance = new ScheduleManager() + } + return ScheduleManager._instance +} + +async function main() { + const openBridgeConfig = new OpenBridgeConfig() + + ScheduleManager.instance().clear() + + for (let taskConfig of openBridgeConfig.tasks) { + let { + platform, + tasks + } = taskConfig + + for (let taskName of tasks) { + const platformTask = TaskMapping[platform] + if (platformTask) { + ScheduleManager.instance().newTask(platformTask[taskName], taskConfig) + } + } + } + + await ScheduleManager.instance().runAll() +} + +module.exports = main; diff --git a/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/package.json b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/package.json new file mode 100644 index 0000000..7aad3d9 --- /dev/null +++ b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/package.json @@ -0,0 +1,10 @@ +{ + "name": "uni-open-bridge", + "dependencies": { + "uni-open-bridge-common": "file:../common/uni-open-bridge-common", + "uni-config-center": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + }, + "extensions": { + "uni-cloud-jql": {} + } +} \ No newline at end of file diff --git a/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/task-h5-weixin.js b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/task-h5-weixin.js new file mode 100644 index 0000000..c5950ae --- /dev/null +++ b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/task-h5-weixin.js @@ -0,0 +1,67 @@ +'use strict'; + +const { + getAccessToken, + setAccessToken, + removeAccessToken, + getTicket, + setTicket, + removeTicket +} = require('uni-open-bridge-common') + +const { + Task +} = require('./basic.js') + +const { + PlatformType +} = require('./consts.js') + +class TaskAccessTokenH5 extends Task { + + constructor(config) { + super() + + this._config = config || null + } + + async run() { + const key = { + dcloudAppid: this._config.dcloudAppid, + platform: PlatformType.H5_WEIXIN + } + + const result = await getAccessToken(key) + + console.log("setAccessToken...", key, result) + } +} + +TaskAccessTokenH5.ID = 'TaskAccessTokenH5' + +class TaskTicket extends Task { + + constructor(config) { + super() + + this._config = config || null + } + + async run() { + const key = { + dcloudAppid: this._config.dcloudAppid, + platform: PlatformType.H5_WEIXIN + } + + const result = await getTicket(key) + + console.log("setTicket...", key, result) + } +} + +TaskTicket.ID = 'TaskTicket' + +module.exports = { + TaskAccessTokenH5, + TaskTicket +} diff --git a/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/task-mp-weixin.js b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/task-mp-weixin.js new file mode 100644 index 0000000..547aaa7 --- /dev/null +++ b/uni_modules/uni-open-bridge/uniCloud/cloudfunctions/uni-open-bridge/task-mp-weixin.js @@ -0,0 +1,41 @@ +'use strict'; + +const { + getAccessToken, + setAccessToken, + removeAccessToken +} = require('uni-open-bridge-common') + +const { + Task +} = require('./basic.js') + +const { + PlatformType +} = require('./consts.js') + +class TaskAccessTokenMP extends Task { + + constructor(config) { + super() + + this._config = config || null + } + + async run() { + const key = { + dcloudAppid: this._config.dcloudAppid, + platform: PlatformType.MP_WEIXIN + } + + const result = await getAccessToken(key) + + console.log("setAccessToken...", key, result) + } +} + +TaskAccessTokenMP.ID = 'TaskAccessTokenMP' + +module.exports = { + TaskAccessTokenMP +} diff --git a/uni_modules/uni-pagination/changelog.md b/uni_modules/uni-pagination/changelog.md new file mode 100644 index 0000000..2e94adc --- /dev/null +++ b/uni_modules/uni-pagination/changelog.md @@ -0,0 +1,27 @@ +## 1.2.4(2022-09-19) +- 修复,未对主题色设置默认色,导致未引入 uni-scss 变量文件报错。 +- 修复,未对移动端当前页文字做主题色适配。 +## 1.2.3(2022-09-15) +- 修复未使用 uni-scss 主题色的 bug。 +## 1.2.2(2022-07-06) +- 修复 es 语言 i18n 错误 +## 1.2.1(2021-11-22) +- 修复 vue3中某些scss变量无法找到的问题 +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-pagination](https://uniapp.dcloud.io/component/uniui/uni-pagination) +## 1.1.2(2021-10-08) +- 修复 current 、value 属性未监听,导致高亮样式失效的 bug +## 1.1.1(2021-08-20) +- 新增 支持国际化 +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.7(2021-05-12) +- 新增 组件示例地址 +## 1.0.6(2021-04-12) +- 新增 PC 和 移动端适配不同的 ui +## 1.0.5(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.4(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-pagination/components/uni-pagination/i18n/en.json b/uni_modules/uni-pagination/components/uni-pagination/i18n/en.json new file mode 100644 index 0000000..d6e2897 --- /dev/null +++ b/uni_modules/uni-pagination/components/uni-pagination/i18n/en.json @@ -0,0 +1,5 @@ +{ + "uni-pagination.prevText": "prev", + "uni-pagination.nextText": "next", + "uni-pagination.piecePerPage": "piece/page" +} diff --git a/uni_modules/uni-pagination/components/uni-pagination/i18n/es.json b/uni_modules/uni-pagination/components/uni-pagination/i18n/es.json new file mode 100644 index 0000000..604a113 --- /dev/null +++ b/uni_modules/uni-pagination/components/uni-pagination/i18n/es.json @@ -0,0 +1,5 @@ +{ + "uni-pagination.prevText": "anterior", + "uni-pagination.nextText": "prxima", + "uni-pagination.piecePerPage": "Artculo/Pgina" +} diff --git a/uni_modules/uni-pagination/components/uni-pagination/i18n/fr.json b/uni_modules/uni-pagination/components/uni-pagination/i18n/fr.json new file mode 100644 index 0000000..a7a0c77 --- /dev/null +++ b/uni_modules/uni-pagination/components/uni-pagination/i18n/fr.json @@ -0,0 +1,5 @@ +{ + "uni-pagination.prevText": "précédente", + "uni-pagination.nextText": "suivante", + "uni-pagination.piecePerPage": "Articles/Pages" +} diff --git a/uni_modules/uni-pagination/components/uni-pagination/i18n/index.js b/uni_modules/uni-pagination/components/uni-pagination/i18n/index.js new file mode 100644 index 0000000..2469dd0 --- /dev/null +++ b/uni_modules/uni-pagination/components/uni-pagination/i18n/index.js @@ -0,0 +1,12 @@ +import en from './en.json' +import es from './es.json' +import fr from './fr.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + es, + fr, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hans.json b/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hans.json new file mode 100644 index 0000000..782bbe4 --- /dev/null +++ b/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hans.json @@ -0,0 +1,5 @@ +{ + "uni-pagination.prevText": "上一页", + "uni-pagination.nextText": "下一页", + "uni-pagination.piecePerPage": "条/页" +} diff --git a/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hant.json b/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hant.json new file mode 100644 index 0000000..180fddb --- /dev/null +++ b/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hant.json @@ -0,0 +1,5 @@ +{ + "uni-pagination.prevText": "上一頁", + "uni-pagination.nextText": "下一頁", + "uni-pagination.piecePerPage": "條/頁" +} diff --git a/uni_modules/uni-pagination/components/uni-pagination/uni-pagination.vue b/uni_modules/uni-pagination/components/uni-pagination/uni-pagination.vue new file mode 100644 index 0000000..5305b5f --- /dev/null +++ b/uni_modules/uni-pagination/components/uni-pagination/uni-pagination.vue @@ -0,0 +1,465 @@ + + + + + diff --git a/uni_modules/uni-pagination/package.json b/uni_modules/uni-pagination/package.json new file mode 100644 index 0000000..862d5ab --- /dev/null +++ b/uni_modules/uni-pagination/package.json @@ -0,0 +1,83 @@ +{ + "id": "uni-pagination", + "displayName": "uni-pagination 分页器", + "version": "1.2.4", + "description": "Pagination 分页器组件,用于展示页码、请求数据等。", + "keywords": [ + "uni-ui", + "uniui", + "分页器", + "页码" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-scss","uni-icons"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-pagination/readme.md b/uni_modules/uni-pagination/readme.md new file mode 100644 index 0000000..97ea1d6 --- /dev/null +++ b/uni_modules/uni-pagination/readme.md @@ -0,0 +1,11 @@ + + +## Pagination 分页器 +> **组件名:uni-pagination** +> 代码块: `uPagination` + + +分页器组件,用于展示页码、请求数据等。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-pagination) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 diff --git a/uni_modules/uni-pay/changelog.md b/uni_modules/uni-pay/changelog.md new file mode 100644 index 0000000..c247bbc --- /dev/null +++ b/uni_modules/uni-pay/changelog.md @@ -0,0 +1,86 @@ +## 2.2.1(2024-06-06) +- 【优化】ios内购验证凭据失败时尝试使用相反的环境配置再次验证 +- 【优化】支付宝小程序获取openid报错的提示 +## 2.2.0(2024-03-11) +- 【重要】新增微信小程序虚拟支付 [配置参数](https://doc.dcloud.net.cn/uniCloud/uni-pay/uni-app.html#config-wxpay-virtual-mp) 、[代币充值](https://doc.dcloud.net.cn/uniCloud/uni-pay/uni-app.html#short-series-coin) 、[道具直购](https://doc.dcloud.net.cn/uniCloud/uni-pay/uni-app.html#short-series-goods) +## 2.1.5(2024-01-13) +- 【调整】删除 `db_init.json` 文件,使用新的数据库初始化方式(右键database目录-初始化云数据库) +- 【修复】解决了当未传 `out_trade_no` 时,可能会出现商户订单号重复的错误提示问题 +## 2.1.4(2023-09-04) +- 【修复】支付宝小程序支付一进入页面获取openid时报签名错误的问题 +## 2.1.3(2023-08-16) +- 【修复】ios内购`verifyReceiptFromAppleiap`接口pay_date变量值不是数字类型的bug +- 【优化】`createOrder`新增`fail`事件的触发 +- 【优化】示例中 `ref="uniPay"` 改成 `ref="pay"` 以兼容vue3(vue3的ref值不可以是组件名) +## 2.1.2(2023-06-05) +- 【优化】支付宝小程序支付的细节处理 +## 2.1.1(2023-05-31) +- 【修复】ios内购不支持自定义异步回调函数的问题 +- 【优化】ios内购在丢失username时自动尝试从本地缓存中找回username +## 2.1.0(2023-05-29) +- 【新增】`refund_date` 字段,表示最近一次退款时间(每一次的退款时间可在refund_list内查看) +- 【优化】与java和php服务端通信的加密解密示例 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-pay.html#service-outside) +- 【优化】云对象的`_before`函数中,若为回调通知时,不执行uniId的token校验逻辑(因回调跟uniId插件没有关系,故不执行token校验逻辑) +## 2.0.7(2023-04-13) +- 【优化】appleiap支付的订单调用getOrder接口时做兼容性处理 +## 2.0.6(2023-04-12) +- 【优化】当检测到证书错误时,则进行明确提示:支付证书错误 +## 2.0.5(2023-03-28) +- 【重要】回调通知时,original_data字段的数据内容调整为http原始请求参数,使之更加符合(原始数据)的含义(原先是处理过后的数据),如果开发者在自己业务中有用到该字段,可能需要进行代码调整。 +- 【修复】ios内购`verifyReceiptFromAppleiap`接口可能会报错的问题。 +- 【优化】支付回调时自动同步支付方式 +- 【调整】默认运行内存调整为512M +## 2.0.4(2023-02-22) +- 【修复】微信支付V3在使用腾讯云空间时会报错的问题 +## 2.0.3(2023-01-13) +- 【优化】兼容从阿里云公测版迁移到阿里云正式版空间后,发起支付时可能会提示"请先配置正确的异步回调URL"的问题。 +## 2.0.2(2022-12-12) +- 【修复】`createOrder`接口传了`other`参数后可能会报`snake2camelJson is not function`的问题。 +## 2.0.1(2022-12-12) +- 【优化】补全package.json内的uni_modules依赖 +## 2.0.0(2022-12-05) +- 【重要】uni-pay 2.0,从公共模块升级为包含前端页面、uni-pay-co云对象,让支付更加简单省心 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-pay.html) +## 1.1.1(2022-09-22) +- 修复 微信支付V3提示 appCert 不存在的bug +- 新增 微信支付V3可以通过证书字符串方式导入证书 +## 1.1.0(2022-09-22) +- 新增 微信支付V3接口 [详情](https://uniapp.dcloud.io/uniCloud/unipay?id=微信支付v3) +## 1.0.29(2022-06-14) +- 修复app平台PLATFORM变更引起的支付报错的Bug +## 1.0.28(2022-01-10) +- 支付宝下单接口返回详细错误信息 +- 优化发行包体积 +## 1.0.27(2021-11-02) +- 新增 苹果应用内购买凭证校验接口 [详情](https://uniapp.dcloud.io/uniCloud/unipay?id=verifyreceipt) +## 1.0.26(2021-11-01) +- 新增 苹果内购凭证校验接口 +## 1.0.25(2021-10-18) +- 修复微信子商户id参数错误的Bug +## 1.0.24(2021-09-23) +- 新增 微信外部浏览器支付(H5支付) +## 1.0.23(2021-09-22) +- 修复微信支付部分值被转化为NaN导致无法直接入库的错误 +## 1.0.22(2021-08-26) +- 修复 支付宝用户未支付状态下查询订单状态(orderQuery)报错的Bug +## 1.0.21(2021-08-19) +- 修复1.0.18版本引出的微信退款通知验签失败的bug +## 1.0.20(2021-08-04) +- 修复1.0.19版本引出的微信支付签名错误问题 +## 1.0.19(2021-08-03) +- 修复timeStamp大小写导致的微信公众号支付失败 +## 1.0.18(2021-07-16) +- 通知类型不匹配时返回校验未通过 +## 1.0.17(2021-07-16) +- 新增 支付宝退款通知回调 [详情](https://uniapp.dcloud.io/uniCloud/unipay?id=verify-refund-notify) +- 新增 判断通知类型接口 [详情](https://uniapp.dcloud.io/uniCloud/unipay?id=check-notify-type) +## 1.0.16(2021-07-14) +- 修复APP微信支付报签名错误的Bug +## 1.0.15(2021-07-13) +- 修复1.0.14版本引出的微信支付使用pfx时报错的Bug +## 1.0.14(2021-07-12) +- 支持使用微信子商户号,[详情](https://uniapp.dcloud.net.cn/uniCloud/unipay?id=init),感谢[studytime](https://gitee.com/studytime) +- 修复支付宝支付传入encode后的passbackParams参数导致验签无法通过的Bug +## 1.0.13(2021-03-25) +- 修复 微信退款通知解析报错的Bug +## 1.0.12(2021-02-03) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-pay/components/uni-pay/uni-pay.vue b/uni_modules/uni-pay/components/uni-pay/uni-pay.vue new file mode 100644 index 0000000..016211a --- /dev/null +++ b/uni_modules/uni-pay/components/uni-pay/uni-pay.vue @@ -0,0 +1,927 @@ + + + + diff --git a/uni_modules/uni-pay/js_sdk/appleiap.js b/uni_modules/uni-pay/js_sdk/appleiap.js new file mode 100644 index 0000000..ba33391 --- /dev/null +++ b/uni_modules/uni-pay/js_sdk/appleiap.js @@ -0,0 +1,123 @@ +// uni iap +const IapTransactionState = { + purchasing: "0", // A transaction that is being processed by the App Store. + purchased: "1", // A successfully processed transaction. + failed: "2", // A failed transaction. + restored: "3", // A transaction that restores content previously purchased by the user. + deferred: "4" // A transaction that is in the queue, but its final status is pending external action such as Ask to Buy. +}; + +class Iap { + + constructor(data={}) { + this._productIds = data.products || []; + this._channel = null; + this._channelError = null; + this.ready = false; + } + + init() { + return new Promise((resolve, reject) => { + this.getChannels((channel) => { + this.ready = true; + resolve(channel); + }, (err) => { + reject(err); + }) + }) + } + + getProduct(productIds) { + return new Promise((resolve, reject) => { + this._channel.requestProduct(productIds || this._productIds, (res) => { + resolve(res); + }, (err) => { + reject(err); + }) + }); + } + + requestPayment(orderInfo) { + return new Promise((resolve, reject) => { + uni.requestPayment({ + provider: "appleiap", + orderInfo: { + quantity: 1, + manualFinishTransaction: true, + ...orderInfo + }, + success: (res) => { + resolve(res); + }, + fail: (err) => { + //console.log('requestPayment-err: ', err) + reject(err); + } + }); + }); + + } + + restoreCompletedTransactions(username) { + return new Promise((resolve, reject) => { + this._channel.restoreCompletedTransactions({ + manualFinishTransaction: true, + username + }, (res) => { + resolve(res); + }, (err) => { + console.log('restoreCompletedTransactions-err: ', err) + reject(err); + }) + }); + } + + finishTransaction(transaction) { + return new Promise((resolve, reject) => { + this._channel.finishTransaction(transaction, (res) => { + resolve(res); + }, (err) => { + reject(err); + }); + }); + } + + getChannels(success, fail) { + if (this._channel !== null) { + success(this._channel) + return + } + + if (this._channelError !== null) { + fail(this._channelError) + return + } + + uni.getProvider({ + service: 'payment', + success: (res) => { + this._channel = res.providers.find((channel) => { + return (channel.id === 'appleiap') + }) + + if (this._channel) { + success(this._channel) + } else { + this._channelError = { + errMsg: 'paymentContext:fail iap service not found' + } + fail(this._channelError) + } + } + }); + } + + get channel() { + return this._channel; + } +} + +export default { + Iap, + IapTransactionState +}; \ No newline at end of file diff --git a/uni_modules/uni-pay/js_sdk/js_sdk.js b/uni_modules/uni-pay/js_sdk/js_sdk.js new file mode 100644 index 0000000..652a35e --- /dev/null +++ b/uni_modules/uni-pay/js_sdk/js_sdk.js @@ -0,0 +1,158 @@ +var util = {}; +/* + * 此方法不支持微信公众号 +util.getWeixinCode().then((code) => { + +}); +*/ +util.getWeixinCode = function() { + return new Promise((resolve, reject) => { + // #ifdef MP-WEIXIN + uni.login({ + provider: 'weixin', + success(res) { + resolve(res.code) + }, + fail(err) { + reject(new Error('获取微信code失败')) + } + }) + // #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('获取微信code失败')); + }); + } + }); + // #endif + }) +}; + +util.getAlipayCode = function() { + // #ifdef APP-PLUS || MP-ALIPAY + return new Promise((resolve, reject) => { + uni.login({ + provider: 'alipay', + success(res) { + resolve(res.code); + }, + fail(err) { + reject(new Error('获取支付宝code失败,可能是没有关联appid或你的支付宝开发者工具还没有登录')); + } + }); + }); + // #endif +}; + +util.checkPlatform = function() { + // #ifdef H5 + let system = { + win: false, + mac: false, + xll: false + }; + let p = navigator.platform; + system.win = p.indexOf("Win") == 0; + system.mac = p.indexOf("Mac") == 0; + system.x11 = p == "X11" || p.indexOf("Linux") == 0; + if (system.win || system.mac || system.xll) { + let ua = navigator.userAgent.toLowerCase(); + if (ua.indexOf("micromessenger") > -1) { + // 微信开发者工具下访问(注意微信开发者工具下无法唤起微信公众号支付) + return "pc-weixin"; + } else { + return "pc"; + } + } else { + if (p.indexOf("iPhone") > -1 || p.indexOf("iPad") > -1) { + return "ios"; + } else { + return "android"; + } + } + // #endif +}; + +/** + * 获取当前H5所在的环境 + */ +util.getH5Env = 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"; +}; + + +/** + * 日期格式化 + * @params {Date || Number} date 需要格式化的时间 + * timeFormat(new Date(),"yyyy-MM-dd hh:mm:ss"); + */ +util.timeFormat = function(time, fmt = 'yyyy-MM-dd hh:mm:ss', targetTimezone = 8) { + try { + if (!time) { + return ""; + } + if (typeof time === "string" && !isNaN(time)) time = Number(time); + // 其他更多是格式化有如下: + // yyyy-MM-dd hh:mm:ss|yyyy年MM月dd日 hh时MM分等,可自定义组合 + let date; + if (typeof time === "number") { + if (time.toString().length == 10) time *= 1000; + date = new Date(time); + } else { + date = time; + } + + const dif = date.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + const east8time = date.getTime() + timeDif; + + date = new Date(east8time); + let opt = { + "M+": date.getMonth() + 1, //月份 + "d+": date.getDate(), //日 + "h+": date.getHours(), //小时 + "m+": date.getMinutes(), //分 + "s+": date.getSeconds(), //秒 + "q+": Math.floor((date.getMonth() + 3) / 3), //季度 + "S": date.getMilliseconds() //毫秒 + }; + if (/(y+)/.test(fmt)) { + fmt = fmt.replace(RegExp.$1, (date.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; + } +}; + +export default util; \ No newline at end of file diff --git a/uni_modules/uni-pay/package.json b/uni_modules/uni-pay/package.json new file mode 100644 index 0000000..9af29c3 --- /dev/null +++ b/uni_modules/uni-pay/package.json @@ -0,0 +1,83 @@ +{ + "id": "uni-pay", + "displayName": "uni-pay", + "version": "2.2.1", + "description": "更简单的支付接口调用方式、拉齐不同支付平台", + "keywords": [ + "unipay", + "uni-pay", + "微信支付", + "支付宝", + "ios内购" +], + "repository": "https://gitcode.net/dcloud/uni-pay.git", + "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-page" + }, + "uni_modules": { + "dependencies": ["uni-config-center","uni-id-common","uni-popup","uni-list"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y", + "app-uvue": "n" + }, + "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", + "百度": "u", + "字节跳动": "u", + "QQ": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-pay/pages/ad-interactive-webview/ad-interactive-webview.vue b/uni_modules/uni-pay/pages/ad-interactive-webview/ad-interactive-webview.vue new file mode 100644 index 0000000..f030465 --- /dev/null +++ b/uni_modules/uni-pay/pages/ad-interactive-webview/ad-interactive-webview.vue @@ -0,0 +1,18 @@ + + + diff --git a/uni_modules/uni-pay/pages/pay-desk/pay-desk.vue b/uni_modules/uni-pay/pages/pay-desk/pay-desk.vue new file mode 100644 index 0000000..46cd36b --- /dev/null +++ b/uni_modules/uni-pay/pages/pay-desk/pay-desk.vue @@ -0,0 +1,116 @@ + + + + \ No newline at end of file diff --git a/uni_modules/uni-pay/pages/success/success.vue b/uni_modules/uni-pay/pages/success/success.vue new file mode 100644 index 0000000..7d00b3a --- /dev/null +++ b/uni_modules/uni-pay/pages/success/success.vue @@ -0,0 +1,233 @@ + + + + \ No newline at end of file diff --git a/uni_modules/uni-pay/readme.md b/uni_modules/uni-pay/readme.md new file mode 100644 index 0000000..5010501 --- /dev/null +++ b/uni_modules/uni-pay/readme.md @@ -0,0 +1,31 @@ +`uni-pay`已升级为`uni-pay 2.x`,从公共模块升级为包含前端页面、uni-pay-co云对象,让支付更加简单省心 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-pay.html) + +## 简介 + +支付,重要的变现手段,但开发复杂。在不同端,对接微信支付、支付宝等渠道,前端后端都要写不少代码。 + +涉及金额可不是小事,生成业务订单、获取收银台、发起支付、支付状态查询、支付异步回调、失败处理、发起退款、退款状态查询、支付统计...众多环节,代码量多,出错率高。 + +为什么不能有一个开源的、高质量的项目?即可以避免大家重复开发,又可以安心使用,不担心自己从头写产生Bug。 + +`uni-pay`应需而生。 + +之前`uni-pay 1.x`版本,仅是一个公共模块,它让开发者无需研究支付宝、微信等支付平台的后端开发、无需为它们编写不同代码,拿来即用,屏蔽差异。 + +但开发者还是需要自己编写前端页面和云函数,还是有一定的开发难度和工作量的,特别对于新手来说,门槛高、易出错。 + +`uni-pay 2.0` 起,补充了前端页面和云对象,让开发者开箱即用。 + +**注意:`uni-pay 2` 仍内置了uni-pay公共模块,向下兼容`uni-pay 1.x`,即从`uni-pay 1.x`可以一键升级到`uni-pay 2.x`,且不会对你的老项目造成影响。** + +开发者在项目中引入 `uni-pay` 后,微信支付、支付宝支付等功能无需自己再开发。由于源码的开放性和层次结构清晰,有二次开发需求也很方便调整。 + +> 下载地址:[https://ext.dcloud.net.cn/plugin?name=uni-pay](https://ext.dcloud.net.cn/plugin?name=uni-pay) + +> 开发文档:[https://uniapp.dcloud.io/uniCloud/uni-pay](https://uniapp.dcloud.io/uniCloud/uni-pay) + +**线上体验地址** + +注意:线上体验地址用的是阿里云免费版,免费版请求次数有限,如请求失败为正常现象,可直接导入示例项目绑定自己的空间体验。 + +![](https://f184e7c3-1912-41b2-b81f-435d1b37c7b4.cdn.bspapp.com/VKCEYUGU-f184e7c3-1912-41b2-b81f-435d1b37c7b4/a9489bd6-37d6-4664-9e0b-346f8859534c.png) diff --git a/uni_modules/uni-pay/static/alipay.png b/uni_modules/uni-pay/static/alipay.png new file mode 100644 index 0000000000000000000000000000000000000000..cc15e39b6cc6ad5ff37fa6c8200f20f3ad927410 GIT binary patch literal 935 zcmV;Y16cftP)Px&VM#ucv5o62cO4h=fA~mXMPKPSN*Z5oh1h z9so3bG8NCJ`WRbsLXEtYENOoF&xa(03;*!K?S}{;D&WEiL>IVl0mL8}T_C!^g%gM_ z@D>92F#Fz3sQsdwYdh|}>n6O(H1g70-eXr1DFg7u`1UX1e5Ju@4?lL(_RUHOlvLCVk>|EyCz^rG~_Ha z-v<*+-&Fx+7aZ$=SO+w;4v^ArL%Zv82@=#L#JR3tf^g&dU$yUGm;N4oO}YI!{VD}P zHE?IPo&(`6XQB{&B&<-uPp!ubz^BLcZ5H7}ehGciL#1>(?q7wRN{;0PAoOD7cps;m zX9P`=6)^V~QfeJW_>9?^Zb)0P5e=t<#o$2}obSbq)`IiD01CMo zX@LS(HaV*jSzekD!nXq)9+ZL?)x7&G0LnMzZV~Q=RfCZXm;!N7CUywi-&CECo2s3a z;K4TmLY1M}bsEqBNLG7pRY>rz0LnGCbRl$%%r!`{d^Q271BO)r3P2rsI8y?_bJg7o z1;Y;D?{PQu`<<`xr_fBPl>^rbKt=zM3a}ebDG)vZ(tr~m^ad6SFWJWyNLel*Z*D`J z#9YSb1MQ*i-~~$SP9rV0qrUOx*$O}{SW4{IxW~S_(k;mTmO!Z~<#~hf0U!-ImZ%jo zfh*c`;bsS~>@mijItv@%3m`9Bx!4xMgmcQ{6h2(z^9Gd$;R_&Bf#xYJi@ZoF2z)&* zFuTv=`K|8-CmTcv00mdzABxmK(7D)0TCL2YXRrdegr|VvOT3cPlM-TP}OzFyNSw`VAVPx(FG)l}RCr$PT1{HpKn#^k@6oX9*Khz}1DvF=fpUtFQ&89tPJ-D02O#~rt9uVT z>ZgfKoMgr$`6q_N-eeJZX7uLijifQcmOr@V{zDHy&wwpQpbvp9CqOTPeF(G_0^hFp z2VVdNJpLO%!oPnmU+nKkdKzKC_uKu`h@t@@9Ra~{se=eH5zD763>{yMw^ zq|+KZnjql)n=zBFfKUU#)ZW2pRMYWQ%m^nbnen=TPyw)ay?;y*KGfLp;H!jm_WS&0 z5;SbcKn%d}_TV8H-wiDa*2o4C0BdzV2N5AoQ#xxqB!U2R;{2RRNowe%O%O@}*tby+^oigDAiN_2bSs)9Ko~QqQ3^?3FmZS_?Yw32@**X1T+y+>fr8^=QN$IdWmQB2 zpaL6lR$4bzQLX?WQSv4MD2iLAA>xoIhGEr0s!IS8G<3!yDiTi#>J`%Gu0p`(5Srvk z;(u71y3Ou<%lOSOk{c{%CS^$vvf~A~&tQ7_mQ4!_|gCGEwinG?3K1I!3V!A>U z9k<+G3xy#}FP>NY6#*a;nzEzlg8<;t0WkpVUsX-uiCei%3hw!$K`jR4L#di2x+75O zj@o>shdIj@6^}%1UBd};0L4lwm@XZ$`3NcioF@X|1j*c6k(*tQ=gK`-@NDub?5W_Y z^A%r(r~+WY0m1zpGbUdRx3faYN>k1{#&ObL6$0<{7dY;7WZm7SInDi5p_l=@_$I#S zXdTes{f(Y zA|?vwRi}Um`HDuthK6F?Pz!8%sLmNsTu`A+&iR9^5i@I_&A(0jj0|vXFoVI_CI3eR zU+oo{!2}Whac{w-5a)M=%M8+7qJAg_D46avwfBjHBSIQWKegK^0CH5A5ykHo%7EQS z05nYM0nnheiMBlhHgQ)qKJ^UHptXs%Jp(pzS2aFuJp=v&?EZ{jaX}m;00000NkvXX Hu0mjfq!RB@ literal 0 HcmV?d00001 diff --git a/uni_modules/uni-pay/uniCloud/cloudfunctions/common/uni-pay/LICENSE.md b/uni_modules/uni-pay/uniCloud/cloudfunctions/common/uni-pay/LICENSE.md new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/uni_modules/uni-pay/uniCloud/cloudfunctions/common/uni-pay/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-pay/uniCloud/cloudfunctions/common/uni-pay/index.js b/uni_modules/uni-pay/uniCloud/cloudfunctions/common/uni-pay/index.js new file mode 100644 index 0000000..d8e0a9d --- /dev/null +++ b/uni_modules/uni-pay/uniCloud/cloudfunctions/common/uni-pay/index.js @@ -0,0 +1,12698 @@ +! function(e, t) { + for (var r in t) e[r] = t[r] +}(exports, function(e) { + var t = {}; + + function r(n) { + if (t[n]) return t[n].exports; + var i = t[n] = { + i: n, + l: !1, + exports: {} + }; + return e[n].call(i.exports, i, i.exports, r), i.l = !0, i.exports + } + return r.m = e, r.c = t, r.d = function(e, t, n) { + r.o(e, t) || Object.defineProperty(e, t, { + enumerable: !0, + get: n + }) + }, r.r = function(e) { + "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, { + value: "Module" + }), Object.defineProperty(e, "__esModule", { + value: !0 + }) + }, r.t = function(e, t) { + if (1 & t && (e = r(e)), 8 & t) return e; + if (4 & t && "object" == typeof e && e && e.__esModule) return e; + var n = Object.create(null); + if (r.r(n), Object.defineProperty(n, "default", { + enumerable: !0, + value: e + }), 2 & t && "string" != typeof e) + for (var i in e) r.d(n, i, function(t) { + return e[t] + }.bind(null, i)); + return n + }, r.n = function(e) { + var t = e && e.__esModule ? function() { + return e.default + } : function() { + return e + }; + return r.d(t, "a", t), t + }, r.o = function(e, t) { + return Object.prototype.hasOwnProperty.call(e, t) + }, r.p = "", r(r.s = 23) +}([function(e, t, r) { + var n; + e.exports = (n = n || function(e, t) { + var n; + if ("undefined" != typeof window && window.crypto && (n = window.crypto), "undefined" != + typeof self && self.crypto && (n = self.crypto), "undefined" != typeof globalThis && + globalThis.crypto && (n = globalThis.crypto), !n && "undefined" != typeof window && + window.msCrypto && (n = window.msCrypto), !n && "undefined" != typeof global && global + .crypto && (n = global.crypto), !n) try { + n = r(2) + } catch (e) {} + var i = function() { + if (n) { + if ("function" == typeof n.getRandomValues) try { + return n.getRandomValues(new Uint32Array(1))[0] + } catch (e) {} + if ("function" == typeof n.randomBytes) try { + return n.randomBytes(4).readInt32LE() + } catch (e) {} + } + throw new Error( + "Native crypto module could not be used to get secure random number.") + }, + o = Object.create || function() { + function e() {} + return function(t) { + var r; + return e.prototype = t, r = new e, e.prototype = null, r + } + }(), + a = {}, + s = a.lib = {}, + u = s.Base = { + extend: function(e) { + var t = o(this); + return e && t.mixIn(e), t.hasOwnProperty("init") && this.init !== t.init || + (t.init = function() { + t.$super.init.apply(this, arguments) + }), t.init.prototype = t, t.$super = this, t + }, + create: function() { + var e = this.extend(); + return e.init.apply(e, arguments), e + }, + init: function() {}, + mixIn: function(e) { + for (var t in e) e.hasOwnProperty(t) && (this[t] = e[t]); + e.hasOwnProperty("toString") && (this.toString = e.toString) + }, + clone: function() { + return this.init.prototype.extend(this) + } + }, + c = s.WordArray = u.extend({ + init: function(e, t) { + e = this.words = e || [], this.sigBytes = null != t ? t : 4 * e.length + }, + toString: function(e) { + return (e || l).stringify(this) + }, + concat: function(e) { + var t = this.words, + r = e.words, + n = this.sigBytes, + i = e.sigBytes; + if (this.clamp(), n % 4) + for (var o = 0; o < i; o++) { + var a = r[o >>> 2] >>> 24 - o % 4 * 8 & 255; + t[n + o >>> 2] |= a << 24 - (n + o) % 4 * 8 + } else + for (var s = 0; s < i; s += 4) t[n + s >>> 2] = r[s >>> 2]; + return this.sigBytes += i, this + }, + clamp: function() { + var t = this.words, + r = this.sigBytes; + t[r >>> 2] &= 4294967295 << 32 - r % 4 * 8, t.length = e.ceil(r / 4) + }, + clone: function() { + var e = u.clone.call(this); + return e.words = this.words.slice(0), e + }, + random: function(e) { + for (var t = [], r = 0; r < e; r += 4) t.push(i()); + return new c.init(t, e) + } + }), + f = a.enc = {}, + l = f.Hex = { + stringify: function(e) { + for (var t = e.words, r = e.sigBytes, n = [], i = 0; i < r; i++) { + var o = t[i >>> 2] >>> 24 - i % 4 * 8 & 255; + n.push((o >>> 4).toString(16)), n.push((15 & o).toString(16)) + } + return n.join("") + }, + parse: function(e) { + for (var t = e.length, r = [], n = 0; n < t; n += 2) r[n >>> 3] |= parseInt( + e.substr(n, 2), 16) << 24 - n % 8 * 4; + return new c.init(r, t / 2) + } + }, + h = f.Latin1 = { + stringify: function(e) { + for (var t = e.words, r = e.sigBytes, n = [], i = 0; i < r; i++) { + var o = t[i >>> 2] >>> 24 - i % 4 * 8 & 255; + n.push(String.fromCharCode(o)) + } + return n.join("") + }, + parse: function(e) { + for (var t = e.length, r = [], n = 0; n < t; n++) r[n >>> 2] |= (255 & e + .charCodeAt(n)) << 24 - n % 4 * 8; + return new c.init(r, t) + } + }, + p = f.Utf8 = { + stringify: function(e) { + try { + return decodeURIComponent(escape(h.stringify(e))) + } catch (e) { + throw new Error("Malformed UTF-8 data") + } + }, + parse: function(e) { + return h.parse(unescape(encodeURIComponent(e))) + } + }, + d = s.BufferedBlockAlgorithm = u.extend({ + reset: function() { + this._data = new c.init, this._nDataBytes = 0 + }, + _append: function(e) { + "string" == typeof e && (e = p.parse(e)), this._data.concat(e), this + ._nDataBytes += e.sigBytes + }, + _process: function(t) { + var r, n = this._data, + i = n.words, + o = n.sigBytes, + a = this.blockSize, + s = o / (4 * a), + u = (s = t ? e.ceil(s) : e.max((0 | s) - this._minBufferSize, 0)) * + a, + f = e.min(4 * u, o); + if (u) { + for (var l = 0; l < u; l += a) this._doProcessBlock(i, l); + r = i.splice(0, u), n.sigBytes -= f + } + return new c.init(r, f) + }, + clone: function() { + var e = u.clone.call(this); + return e._data = this._data.clone(), e + }, + _minBufferSize: 0 + }), + y = (s.Hasher = d.extend({ + cfg: u.extend(), + init: function(e) { + this.cfg = this.cfg.extend(e), this.reset() + }, + reset: function() { + d.reset.call(this), this._doReset() + }, + update: function(e) { + return this._append(e), this._process(), this + }, + finalize: function(e) { + return e && this._append(e), this._doFinalize() + }, + blockSize: 16, + _createHelper: function(e) { + return function(t, r) { + return new e.init(r).finalize(t) + } + }, + _createHmacHelper: function(e) { + return function(t, r) { + return new y.HMAC.init(e, r).finalize(t) + } + } + }), a.algo = {}); + return a + }(Math), n) +}, function(e, t, r) { + var n, i, o, a, s, u, c, f, l, h, p, d, y, g, v, _, m, b, w; + e.exports = (n = r(0), r(4), void(n.lib.Cipher || (i = n, o = i.lib, a = o.Base, s = o.WordArray, u = o + .BufferedBlockAlgorithm, c = i.enc, c.Utf8, f = c.Base64, l = i.algo.EvpKDF, h = o + .Cipher = u.extend({ + cfg: a.extend(), + createEncryptor: function(e, t) { + return this.create(this._ENC_XFORM_MODE, e, t) + }, + createDecryptor: function(e, t) { + return this.create(this._DEC_XFORM_MODE, e, t) + }, + init: function(e, t, r) { + this.cfg = this.cfg.extend(r), this._xformMode = e, this._key = t, this + .reset() + }, + reset: function() { + u.reset.call(this), this._doReset() + }, + process: function(e) { + return this._append(e), this._process() + }, + finalize: function(e) { + return e && this._append(e), this._doFinalize() + }, + keySize: 4, + ivSize: 4, + _ENC_XFORM_MODE: 1, + _DEC_XFORM_MODE: 2, + _createHelper: function() { + function e(e) { + return "string" == typeof e ? w : m + } + return function(t) { + return { + encrypt: function(r, n, i) { + return e(n).encrypt(t, r, n, i) + }, + decrypt: function(r, n, i) { + return e(n).decrypt(t, r, n, i) + } + } + } + }() + }), o.StreamCipher = h.extend({ + _doFinalize: function() { + return this._process(!0) + }, + blockSize: 1 + }), p = i.mode = {}, d = o.BlockCipherMode = a.extend({ + createEncryptor: function(e, t) { + return this.Encryptor.create(e, t) + }, + createDecryptor: function(e, t) { + return this.Decryptor.create(e, t) + }, + init: function(e, t) { + this._cipher = e, this._iv = t + } + }), y = p.CBC = function() { + var e = d.extend(); + + function t(e, t, r) { + var n, i = this._iv; + i ? (n = i, this._iv = void 0) : n = this._prevBlock; + for (var o = 0; o < r; o++) e[t + o] ^= n[o] + } + return e.Encryptor = e.extend({ + processBlock: function(e, r) { + var n = this._cipher, + i = n.blockSize; + t.call(this, e, r, i), n.encryptBlock(e, r), this._prevBlock = e + .slice(r, r + i) + } + }), e.Decryptor = e.extend({ + processBlock: function(e, r) { + var n = this._cipher, + i = n.blockSize, + o = e.slice(r, r + i); + n.decryptBlock(e, r), t.call(this, e, r, i), this._prevBlock = o + } + }), e + }(), g = (i.pad = {}).Pkcs7 = { + pad: function(e, t) { + for (var r = 4 * t, n = r - e.sigBytes % r, i = n << 24 | n << 16 | n << 8 | + n, o = [], a = 0; a < n; a += 4) o.push(i); + var u = s.create(o, n); + e.concat(u) + }, + unpad: function(e) { + var t = 255 & e.words[e.sigBytes - 1 >>> 2]; + e.sigBytes -= t + } + }, o.BlockCipher = h.extend({ + cfg: h.cfg.extend({ + mode: y, + padding: g + }), + reset: function() { + var e; + h.reset.call(this); + var t = this.cfg, + r = t.iv, + n = t.mode; + this._xformMode == this._ENC_XFORM_MODE ? e = n.createEncryptor : (e = n + .createDecryptor, this._minBufferSize = 1), this._mode && this + ._mode.__creator == e ? this._mode.init(this, r && r.words) : (this + ._mode = e.call(n, this, r && r.words), this._mode.__creator = e + ) + }, + _doProcessBlock: function(e, t) { + this._mode.processBlock(e, t) + }, + _doFinalize: function() { + var e, t = this.cfg.padding; + return this._xformMode == this._ENC_XFORM_MODE ? (t.pad(this._data, this + .blockSize), e = this._process(!0)) : (e = this._process(!0), t + .unpad(e)), e + }, + blockSize: 4 + }), v = o.CipherParams = a.extend({ + init: function(e) { + this.mixIn(e) + }, + toString: function(e) { + return (e || this.formatter).stringify(this) + } + }), _ = (i.format = {}).OpenSSL = { + stringify: function(e) { + var t = e.ciphertext, + r = e.salt; + return (r ? s.create([1398893684, 1701076831]).concat(r).concat(t) : t) + .toString(f) + }, + parse: function(e) { + var t, r = f.parse(e), + n = r.words; + return 1398893684 == n[0] && 1701076831 == n[1] && (t = s.create(n.slice(2, + 4)), n.splice(0, 4), r.sigBytes -= 16), v.create({ + ciphertext: r, + salt: t + }) + } + }, m = o.SerializableCipher = a.extend({ + cfg: a.extend({ + format: _ + }), + encrypt: function(e, t, r, n) { + n = this.cfg.extend(n); + var i = e.createEncryptor(r, n), + o = i.finalize(t), + a = i.cfg; + return v.create({ + ciphertext: o, + key: r, + iv: a.iv, + algorithm: e, + mode: a.mode, + padding: a.padding, + blockSize: e.blockSize, + formatter: n.format + }) + }, + decrypt: function(e, t, r, n) { + return n = this.cfg.extend(n), t = this._parse(t, n.format), e + .createDecryptor(r, n).finalize(t.ciphertext) + }, + _parse: function(e, t) { + return "string" == typeof e ? t.parse(e, this) : e + } + }), b = (i.kdf = {}).OpenSSL = { + execute: function(e, t, r, n) { + n || (n = s.random(8)); + var i = l.create({ + keySize: t + r + }).compute(e, n), + o = s.create(i.words.slice(t), 4 * r); + return i.sigBytes = 4 * t, v.create({ + key: i, + iv: o, + salt: n + }) + } + }, w = o.PasswordBasedCipher = m.extend({ + cfg: m.cfg.extend({ + kdf: b + }), + encrypt: function(e, t, r, n) { + var i = (n = this.cfg.extend(n)).kdf.execute(r, e.keySize, e.ivSize); + n.iv = i.iv; + var o = m.encrypt.call(this, e, t, i.key, n); + return o.mixIn(i), o + }, + decrypt: function(e, t, r, n) { + n = this.cfg.extend(n), t = this._parse(t, n.format); + var i = n.kdf.execute(r, e.keySize, e.ivSize, t.salt); + return n.iv = i.iv, m.decrypt.call(this, e, t, i.key, n) + } + })))) +}, function(e, t) { + e.exports = require("crypto") +}, function(e, t, r) { + "use strict"; + Object.defineProperty(t, "__esModule", { + value: !0 + }); + var n = { + FormData: !0, + UniCloudError: !0 + }; + Object.defineProperty(t, "FormData", { + enumerable: !0, + get: function() { + return i.default + } + }), Object.defineProperty(t, "UniCloudError", { + enumerable: !0, + get: function() { + return o.default + } + }); + var i = u(r(26)), + o = u(r(27)), + a = r(28); + Object.keys(a).forEach((function(e) { + "default" !== e && "__esModule" !== e && (Object.prototype.hasOwnProperty.call(n, e) || + e in t && t[e] === a[e] || Object.defineProperty(t, e, { + enumerable: !0, + get: function() { + return a[e] + } + })) + })); + var s = r(7); + + function u(e) { + return e && e.__esModule ? e : { + default: e + } + } + Object.keys(s).forEach((function(e) { + "default" !== e && "__esModule" !== e && (Object.prototype.hasOwnProperty.call(n, e) || + e in t && t[e] === s[e] || Object.defineProperty(t, e, { + enumerable: !0, + get: function() { + return s[e] + } + })) + })) +}, function(e, t, r) { + var n, i, o, a, s, u, c, f; + e.exports = (f = r(0), r(11), r(12), i = (n = f).lib, o = i.Base, a = i.WordArray, s = n.algo, u = s + .MD5, c = s.EvpKDF = o.extend({ + cfg: o.extend({ + keySize: 4, + hasher: u, + iterations: 1 + }), + init: function(e) { + this.cfg = this.cfg.extend(e) + }, + compute: function(e, t) { + for (var r, n = this.cfg, i = n.hasher.create(), o = a.create(), s = o.words, + u = n.keySize, c = n.iterations; s.length < u;) { + r && i.update(r), r = i.update(e).finalize(t), i.reset(); + for (var f = 1; f < c; f++) r = i.finalize(r), i.reset(); + o.concat(r) + } + return o.sigBytes = 4 * u, o + } + }), n.EvpKDF = function(e, t, r) { + return c.create(r).compute(e, t) + }, f.EvpKDF) +}, function(e, t, r) { + var n, i, o; + e.exports = (o = r(0), i = (n = o).lib.WordArray, n.enc.Base64 = { + stringify: function(e) { + var t = e.words, + r = e.sigBytes, + n = this._map; + e.clamp(); + for (var i = [], o = 0; o < r; o += 3) + for (var a = (t[o >>> 2] >>> 24 - o % 4 * 8 & 255) << 16 | (t[o + 1 >>> 2] >>> + 24 - (o + 1) % 4 * 8 & 255) << 8 | t[o + 2 >>> 2] >>> 24 - (o + 2) % + 4 * 8 & 255, s = 0; s < 4 && o + .75 * s < r; s++) i.push(n.charAt(a >>> + 6 * (3 - s) & 63)); + var u = n.charAt(64); + if (u) + for (; i.length % 4;) i.push(u); + return i.join("") + }, + parse: function(e) { + var t = e.length, + r = this._map, + n = this._reverseMap; + if (!n) { + n = this._reverseMap = []; + for (var o = 0; o < r.length; o++) n[r.charCodeAt(o)] = o + } + var a = r.charAt(64); + if (a) { + var s = e.indexOf(a); - 1 !== s && (t = s) + } + return function(e, t, r) { + for (var n = [], o = 0, a = 0; a < t; a++) + if (a % 4) { + var s = r[e.charCodeAt(a - 1)] << a % 4 * 2, + u = r[e.charCodeAt(a)] >>> 6 - a % 4 * 2, + c = s | u; + n[o >>> 2] |= c << 24 - o % 4 * 8, o++ + } return i.create(n, o) + }(e, t, n) + }, + _map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" + }, o.enc.Base64) +}, function(e, t, r) { + var n; + e.exports = (n = r(0), function(e) { + var t = n, + r = t.lib, + i = r.WordArray, + o = r.Hasher, + a = t.algo, + s = []; + ! function() { + for (var t = 0; t < 64; t++) s[t] = 4294967296 * e.abs(e.sin(t + 1)) | 0 + }(); + var u = a.MD5 = o.extend({ + _doReset: function() { + this._hash = new i.init([1732584193, 4023233417, 2562383102, 271733878]) + }, + _doProcessBlock: function(e, t) { + for (var r = 0; r < 16; r++) { + var n = t + r, + i = e[n]; + e[n] = 16711935 & (i << 8 | i >>> 24) | 4278255360 & (i << 24 | + i >>> 8) + } + var o = this._hash.words, + a = e[t + 0], + u = e[t + 1], + p = e[t + 2], + d = e[t + 3], + y = e[t + 4], + g = e[t + 5], + v = e[t + 6], + _ = e[t + 7], + m = e[t + 8], + b = e[t + 9], + w = e[t + 10], + S = e[t + 11], + E = e[t + 12], + A = e[t + 13], + I = e[t + 14], + N = e[t + 15], + C = o[0], + T = o[1], + R = o[2], + x = o[3]; + C = c(C, T, R, x, a, 7, s[0]), x = c(x, C, T, R, u, 12, s[1]), R = c(R, + x, C, T, p, 17, s[2]), T = c(T, R, x, C, d, 22, s[3]), C = c(C, + T, R, x, y, 7, s[4]), x = c(x, C, T, R, g, 12, s[5]), R = c(R, + x, C, T, v, 17, s[6]), T = c(T, R, x, C, _, 22, s[7]), C = c(C, + T, R, x, m, 7, s[8]), x = c(x, C, T, R, b, 12, s[9]), R = c(R, + x, C, T, w, 17, s[10]), T = c(T, R, x, C, S, 22, s[11]), C = c( + C, T, R, x, E, 7, s[12]), x = c(x, C, T, R, A, 12, s[13]), R = + c(R, x, C, T, I, 17, s[14]), C = f(C, T = c(T, R, x, C, N, 22, s[ + 15]), R, x, u, 5, s[16]), x = f(x, C, T, R, v, 9, s[17]), R = f( + R, x, C, T, S, 14, s[18]), T = f(T, R, x, C, a, 20, s[19]), C = + f(C, T, R, x, g, 5, s[20]), x = f(x, C, T, R, w, 9, s[21]), R = f(R, + x, C, T, N, 14, s[22]), T = f(T, R, x, C, y, 20, s[23]), C = f( + C, T, R, x, b, 5, s[24]), x = f(x, C, T, R, I, 9, s[25]), R = f( + R, x, C, T, d, 14, s[26]), T = f(T, R, x, C, m, 20, s[27]), C = + f(C, T, R, x, A, 5, s[28]), x = f(x, C, T, R, p, 9, s[29]), R = f(R, + x, C, T, _, 14, s[30]), C = l(C, T = f(T, R, x, C, E, 20, s[ + 31]), R, x, g, 4, s[32]), x = l(x, C, T, R, m, 11, s[33]), R = + l(R, x, C, T, S, 16, s[34]), T = l(T, R, x, C, I, 23, s[35]), C = l( + C, T, R, x, u, 4, s[36]), x = l(x, C, T, R, y, 11, s[37]), R = + l(R, x, C, T, _, 16, s[38]), T = l(T, R, x, C, w, 23, s[39]), C = l( + C, T, R, x, A, 4, s[40]), x = l(x, C, T, R, a, 11, s[41]), R = + l(R, x, C, T, d, 16, s[42]), T = l(T, R, x, C, v, 23, s[43]), C = l( + C, T, R, x, b, 4, s[44]), x = l(x, C, T, R, E, 11, s[45]), R = + l(R, x, C, T, N, 16, s[46]), C = h(C, T = l(T, R, x, C, p, 23, s[ + 47]), R, x, a, 6, s[48]), x = h(x, C, T, R, _, 10, s[49]), R = + h(R, x, C, T, I, 15, s[50]), T = h(T, R, x, C, g, 21, s[51]), C = h( + C, T, R, x, E, 6, s[52]), x = h(x, C, T, R, d, 10, s[53]), R = + h(R, x, C, T, w, 15, s[54]), T = h(T, R, x, C, u, 21, s[55]), C = h( + C, T, R, x, m, 6, s[56]), x = h(x, C, T, R, N, 10, s[57]), R = + h(R, x, C, T, v, 15, s[58]), T = h(T, R, x, C, A, 21, s[59]), C = h( + C, T, R, x, y, 6, s[60]), x = h(x, C, T, R, S, 10, s[61]), R = + h(R, x, C, T, p, 15, s[62]), T = h(T, R, x, C, b, 21, s[63]), o[0] = + o[0] + C | 0, o[1] = o[1] + T | 0, o[2] = o[2] + R | 0, o[3] = o[ + 3] + x | 0 + }, + _doFinalize: function() { + var t = this._data, + r = t.words, + n = 8 * this._nDataBytes, + i = 8 * t.sigBytes; + r[i >>> 5] |= 128 << 24 - i % 32; + var o = e.floor(n / 4294967296), + a = n; + r[15 + (i + 64 >>> 9 << 4)] = 16711935 & (o << 8 | o >>> 24) | + 4278255360 & (o << 24 | o >>> 8), r[14 + (i + 64 >>> 9 << 4)] = + 16711935 & (a << 8 | a >>> 24) | 4278255360 & (a << 24 | a >>> 8), t + .sigBytes = 4 * (r.length + 1), this._process(); + for (var s = this._hash, u = s.words, c = 0; c < 4; c++) { + var f = u[c]; + u[c] = 16711935 & (f << 8 | f >>> 24) | 4278255360 & (f << 24 | + f >>> 8) + } + return s + }, + clone: function() { + var e = o.clone.call(this); + return e._hash = this._hash.clone(), e + } + }); + + function c(e, t, r, n, i, o, a) { + var s = e + (t & r | ~t & n) + i + a; + return (s << o | s >>> 32 - o) + t + } + + function f(e, t, r, n, i, o, a) { + var s = e + (t & n | r & ~n) + i + a; + return (s << o | s >>> 32 - o) + t + } + + function l(e, t, r, n, i, o, a) { + var s = e + (t ^ r ^ n) + i + a; + return (s << o | s >>> 32 - o) + t + } + + function h(e, t, r, n, i, o, a) { + var s = e + (r ^ (t | ~n)) + i + a; + return (s << o | s >>> 32 - o) + t + } + t.MD5 = o._createHelper(u), t.HmacMD5 = o._createHmacHelper(u) + }(Math), n.MD5) +}, function(e, t, r) { + "use strict"; + Object.defineProperty(t, "__esModule", { + value: !0 + }), t.accMul = function(e, t) { + if (isNaN(e) || isNaN(t)) return NaN; + const { + value: r, + power: n + } = y(e), { + value: i, + power: o + } = y(t); + return r * i / Math.pow(10, n + o) + }, t.camel2snake = l, t.camel2snakeJson = function(e) { + return h(e, "camel2snake") + }, t.deepClone = function(e) { + return JSON.parse(JSON.stringify(e)) + }, t.deleteObjectKey = function e(t, r) { + const n = t.shift(); + if (!n) return; + e(t, r[n]), r[n] && (Object.keys(r[n]).length <= 0 || "string" == typeof r[n]) && delete r[n] + }, t.getDateStr = p, t.getExtension = function(e) { + return s[e] + }, t.getFullTimeStr = function(e) { + return p(e = e || new Date) + " " + d(e) + }, t.getOffsetDate = function(e) { + return new Date(Date.now() + 6e4 * ((new Date).getTimezoneOffset() + 60 * (e || 0))) + }, t.getTimeStr = d, t.hasOwn = o, t.isFn = function(e) { + return "function" == typeof e + }, t.isPlainObject = a, t.log = function() { + 0 + }, t.mime2ext = void 0, t.snake2camel = f, t.snake2camelJson = function(e) { + return h(e, "snake2camel") + }; + const n = Object.prototype.toString, + i = Object.prototype.hasOwnProperty; + + function o(e, t) { + return i.call(e, t) + } + + function a(e) { + return "[object Object]" === n.call(e) + } + const s = { + "image/png": "png", + "image/jpeg": "jpg", + "image/gif": "gif", + "image/svg+xml": "svg", + "image/bmp": "bmp", + "image/webp": "webp" + }; + t.mime2ext = s; + const u = /_(\w)/g, + c = /[A-Z]/g; + + function f(e) { + return e.replace(u, (e, t) => t ? t.toUpperCase() : "") + } + + function l(e) { + return e.replace(c, e => "_" + e.toLowerCase()) + } + + function h(e, t) { + let r, n; + switch (t) { + case "snake2camel": + n = f, r = u; + break; + case "camel2snake": + n = l, r = c + } + for (const i in e) + if (o(e, i) && r.test(i)) { + const r = n(i); + e[r] = e[i], delete e[i], a(e[r]) ? e[r] = h(e[r], t) : Array.isArray(e[r]) && (e[r] = e[r] + .map(e => h(e, t))) + } return e + } + + function p(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) + } + + function d(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) + } + + function y(e) { + const t = e.toString().split("."), + r = t[1] ? t[1].length : 0; + return { + value: Number(t.join("")), + power: r + } + } +}, function(e, t, r) { + var n, i, o, a, s, u; + e.exports = (u = r(0), i = (n = u).lib, o = i.Base, a = i.WordArray, (s = n.x64 = {}).Word = o.extend({ + init: function(e, t) { + this.high = e, this.low = t + } + }), s.WordArray = o.extend({ + init: function(e, t) { + e = this.words = e || [], this.sigBytes = null != t ? t : 8 * e.length + }, + toX32: function() { + for (var e = this.words, t = e.length, r = [], n = 0; n < t; n++) { + var i = e[n]; + r.push(i.high), r.push(i.low) + } + return a.create(r, this.sigBytes) + }, + clone: function() { + for (var e = o.clone.call(this), t = e.words = this.words.slice(0), r = t + .length, n = 0; n < r; n++) t[n] = t[n].clone(); + return e + } + }), u) +}, function(e, t) { + e.exports = require("util") +}, function(e, t) { + e.exports = require("fs") +}, function(e, t, r) { + var n, i, o, a, s, u, c, f; + e.exports = (f = r(0), i = (n = f).lib, o = i.WordArray, a = i.Hasher, s = n.algo, u = [], c = s.SHA1 = + a.extend({ + _doReset: function() { + this._hash = new o.init([1732584193, 4023233417, 2562383102, 271733878, + 3285377520 + ]) + }, + _doProcessBlock: function(e, t) { + for (var r = this._hash.words, n = r[0], i = r[1], o = r[2], a = r[3], s = r[4], + c = 0; c < 80; c++) { + if (c < 16) u[c] = 0 | e[t + c]; + else { + var f = u[c - 3] ^ u[c - 8] ^ u[c - 14] ^ u[c - 16]; + u[c] = f << 1 | f >>> 31 + } + var l = (n << 5 | n >>> 27) + s + u[c]; + l += c < 20 ? 1518500249 + (i & o | ~i & a) : c < 40 ? 1859775393 + (i ^ o ^ + a) : c < 60 ? (i & o | i & a | o & a) - 1894007588 : (i ^ o ^ a) - + 899497514, s = a, a = o, o = i << 30 | i >>> 2, i = n, n = l + } + r[0] = r[0] + n | 0, r[1] = r[1] + i | 0, r[2] = r[2] + o | 0, r[3] = r[3] + a | + 0, r[4] = r[4] + s | 0 + }, + _doFinalize: function() { + var e = this._data, + t = e.words, + r = 8 * this._nDataBytes, + n = 8 * e.sigBytes; + return t[n >>> 5] |= 128 << 24 - n % 32, t[14 + (n + 64 >>> 9 << 4)] = Math + .floor(r / 4294967296), t[15 + (n + 64 >>> 9 << 4)] = r, e.sigBytes = 4 * t + .length, this._process(), this._hash + }, + clone: function() { + var e = a.clone.call(this); + return e._hash = this._hash.clone(), e + } + }), n.SHA1 = a._createHelper(c), n.HmacSHA1 = a._createHmacHelper(c), f.SHA1) +}, function(e, t, r) { + var n, i, o, a; + e.exports = (n = r(0), o = (i = n).lib.Base, a = i.enc.Utf8, void(i.algo.HMAC = o.extend({ + init: function(e, t) { + e = this._hasher = new e.init, "string" == typeof t && (t = a.parse(t)); + var r = e.blockSize, + n = 4 * r; + t.sigBytes > n && (t = e.finalize(t)), t.clamp(); + for (var i = this._oKey = t.clone(), o = this._iKey = t.clone(), s = i + .words, u = o.words, c = 0; c < r; c++) s[c] ^= 1549556828, u[c] ^= + 909522486; + i.sigBytes = o.sigBytes = n, this.reset() + }, + reset: function() { + var e = this._hasher; + e.reset(), e.update(this._iKey) + }, + update: function(e) { + return this._hasher.update(e), this + }, + finalize: function(e) { + var t = this._hasher, + r = t.finalize(e); + return t.reset(), t.finalize(this._oKey.clone().concat(r)) + } + }))) +}, function(e, t, r) { + "use strict"; + Object.defineProperty(t, "__esModule", { + value: !0 + }); + const n = r(76); + t.bytesFromIP = function(e) { + switch (n.isIP(e)) { + case 4: + return Buffer.from(e.split(".").map(e => parseInt(e, 10))); + case 6: + const t = e.split(":"), + r = Buffer.alloc(16); + let n = 0; + "" === t[t.length - 1] && (t[t.length - 1] = "0"); + for (let e = 0; e < t.length; e++) "" !== t[e] ? (r.writeUInt16BE(parseInt(t[e], 16), + n), n += 2) : e + 1 < t.length && "" !== t[e + 1] && (n = 16 - 2 * (t.length - + e - 1)); + return r; + default: + return null + } + }, t.bytesToIP = function(e) { + switch (e.length) { + case 4: + return [e[0], e[1], e[2], e[3]].join("."); + case 16: + const t = []; + let r = -1, + n = 0, + i = -1, + o = 0; + for (let a = 0; a < e.length; a += 2) { + const s = e[a] << 8 | e[a + 1]; + 0 === s ? (n++, -1 === r && (r = t.length), n > o && (o = n, i = r)) : (r = -1, n = + 0), t.push(s.toString(16)) + } + if (o > 0) { + let e = ""; + const r = t.slice(i + o); + t.length = i, 0 === t.length && (e += ":"), 0 === r.length && (e += ":"), t.push(e, + ...r) + } + return t.join(":"); + default: + return "" + } + }; + const i = Object.create(null), + o = /^[0-9.]+$/; + + function a(e, t) { + i[e] = t, i[t] = e + } + t.getOID = function(e) { + return o.test(e) && "" !== i[e] ? e : null == i[e] ? "" : i[e] + }, t.getOIDName = function(e) { + return o.test(e) || "" === i[e] ? null == i[e] ? e : i[e] : e + }, a("1.2.840.113549.1.1.1", "rsaEncryption"), a("1.2.840.113549.1.1.4", "md5WithRsaEncryption"), a( + "1.2.840.113549.1.1.5", "sha1WithRsaEncryption"), a("1.2.840.113549.1.1.8", "mgf1"), a( + "1.2.840.113549.1.1.10", "RSASSA-PSS"), a("1.2.840.113549.1.1.11", "sha256WithRsaEncryption"), + a("1.2.840.113549.1.1.12", "sha384WithRsaEncryption"), a("1.2.840.113549.1.1.13", + "sha512WithRsaEncryption"), a("1.2.840.10045.2.1", "ecEncryption"), a("1.2.840.10045.4.1", + "ecdsaWithSha1"), a("1.2.840.10045.4.3.2", "ecdsaWithSha256"), a("1.2.840.10045.4.3.3", + "ecdsaWithSha384"), a("1.2.840.10045.4.3.4", "ecdsaWithSha512"), a("1.2.840.10040.4.3", + "dsaWithSha1"), a("2.16.840.1.101.3.4.3.2", "dsaWithSha256"), a("1.3.14.3.2.7", "desCBC"), a( + "1.3.14.3.2.26", "sha1"), a("2.16.840.1.101.3.4.2.1", "sha256"), a("2.16.840.1.101.3.4.2.2", + "sha384"), a("2.16.840.1.101.3.4.2.3", "sha512"), a("1.2.840.113549.2.5", "md5"), a( + "1.3.101.110", "X25519"), a("1.3.101.111", "X448"), a("1.3.101.112", "Ed25519"), a( + "1.3.101.113", "Ed448"), a("1.2.840.113549.1.7.1", "data"), a("1.2.840.113549.1.7.2", + "signedData"), a("1.2.840.113549.1.7.3", "envelopedData"), a("1.2.840.113549.1.7.4", + "signedAndEnvelopedData"), a("1.2.840.113549.1.7.5", "digestedData"), a("1.2.840.113549.1.7.6", + "encryptedData"), a("1.2.840.113549.1.9.1", "emailAddress"), a("1.2.840.113549.1.9.2", + "unstructuredName"), a("1.2.840.113549.1.9.3", "contentType"), a("1.2.840.113549.1.9.4", + "messageDigest"), a("1.2.840.113549.1.9.5", "signingTime"), a("1.2.840.113549.1.9.6", + "counterSignature"), a("1.2.840.113549.1.9.7", "challengePassword"), a("1.2.840.113549.1.9.8", + "unstructuredAddress"), a("1.2.840.113549.1.9.14", "extensionRequest"), a( + "1.2.840.113549.1.9.20", "friendlyName"), a("1.2.840.113549.1.9.21", "localKeyId"), a( + "1.2.840.113549.1.9.22.1", "x509Certificate"), a("1.2.840.113549.1.12.10.1.1", "keyBag"), a( + "1.2.840.113549.1.12.10.1.2", "pkcs8ShroudedKeyBag"), a("1.2.840.113549.1.12.10.1.3", + "certBag"), a("1.2.840.113549.1.12.10.1.4", "crlBag"), a("1.2.840.113549.1.12.10.1.5", "secretBag"), + a("1.2.840.113549.1.12.10.1.6", "safeContentsBag"), a("1.2.840.113549.1.5.13", "pkcs5PBES2"), a( + "1.2.840.113549.1.5.12", "pkcs5PBKDF2"), a("1.2.840.113549.2.7", "hmacWithSha1"), a( + "1.2.840.113549.2.9", "hmacWithSha256"), a("1.2.840.113549.2.10", "hmacWithSha384"), a( + "1.2.840.113549.2.11", "hmacWithSha512"), a("1.2.840.113549.3.7", "3desCBC"), a( + "2.16.840.1.101.3.4.1.2", "aesCBC128"), a("2.16.840.1.101.3.4.1.42", "aesCBC256"), a("2.5.4.3", + "commonName"), a("2.5.4.5", "serialName"), a("2.5.4.6", "countryName"), a("2.5.4.7", + "localityName"), a("2.5.4.8", "stateOrProvinceName"), a("2.5.4.10", "organizationName"), a( + "2.5.4.11", "organizationalUnitName"), a("2.5.4.15", "businessCategory"), a( + "2.16.840.1.113730.1.1", "nsCertType"), a("2.5.29.2", "keyAttributes"), a("2.5.29.4", + "keyUsageRestriction"), a("2.5.29.6", "subtreesConstraint"), a("2.5.29.9", + "subjectDirectoryAttributes"), a("2.5.29.14", "subjectKeyIdentifier"), a("2.5.29.15", + "keyUsage"), a("2.5.29.16", "privateKeyUsagePeriod"), a("2.5.29.17", "subjectAltName"), a( + "2.5.29.18", "issuerAltName"), a("2.5.29.19", "basicConstraints"), a("2.5.29.20", "cRLNumber"), + a("2.5.29.21", "cRLReason"), a("2.5.29.22", "expirationDate"), a("2.5.29.23", "instructionCode"), a( + "2.5.29.24", "invalidityDate"), a("2.5.29.27", "deltaCRLIndicator"), a("2.5.29.28", + "issuingDistributionPoint"), a("2.5.29.29", "certificateIssuer"), a("2.5.29.30", + "nameConstraints"), a("2.5.29.31", "cRLDistributionPoints"), a("2.5.29.32", + "certificatePolicies"), a("2.5.29.33", "policyMappings"), a("2.5.29.35", + "authorityKeyIdentifier"), a("2.5.29.36", "policyConstraints"), a("2.5.29.37", "extKeyUsage"), + a("2.5.29.46", "freshestCRL"), a("2.5.29.54", "inhibitAnyPolicy"), a("1.3.6.1.4.1.311.60.2.1.2", + "jurisdictionST"), a("1.3.6.1.4.1.311.60.2.1.3", "jurisdictionC"), a("1.3.6.1.4.1.11129.2.4.2", + "timestampList"), a("1.3.6.1.5.5.7.1.1", "authorityInfoAccess"), a("1.3.6.1.5.5.7.3.1", + "serverAuth"), a("1.3.6.1.5.5.7.3.2", "clientAuth"), a("1.3.6.1.5.5.7.3.3", "codeSigning"), a( + "1.3.6.1.5.5.7.3.4", "emailProtection"), a("1.3.6.1.5.5.7.3.8", "timeStamping"), a( + "1.3.6.1.5.5.7.48.1", "authorityInfoAccessOcsp"), a("1.3.6.1.5.5.7.48.2", + "authorityInfoAccessIssuers") +}, function(e, t, r) { + "use strict"; + const n = e => !("object" != typeof e || null === e || e instanceof RegExp || e instanceof Error || + e instanceof Date); + e.exports = function e(t, r, i, o) { + if (i = Object.assign({ + deep: !1, + target: {} + }, i), (o = o || new WeakMap).has(t)) return o.get(t); + o.set(t, i.target); + const a = i.target; + delete i.target; + for (const s of Object.keys(t)) { + const u = t[s], + c = r(s, u, t); + let f = c[1]; + i.deep && n(f) && (f = Array.isArray(f) ? f.map(t => n(t) ? e(t, r, i, o) : t) : e(f, r, i, + o)), a[c[0]] = f + } + return a + } +}, function(e, t, r) { + "use strict"; + var n = r(14), + i = r(42); + e.exports = function(e, t) { + return t = Object.assign({ + deep: !0 + }, t), n(e, (function(e, t) { + return [i(e), t] + }), t) + } +}, function(e, t, r) { + "use strict"; + Object.defineProperty(t, "__esModule", { + value: !0 + }); + const n = r(2), + i = r(45), + o = r(46), + a = r(15), + s = r(47), + u = r(72), + c = { + RSA: "RSA-SHA1", + RSA2: "RSA-SHA256" + }; + + function f(e) { + return { + iv: s.enc.Hex.parse(u.padEnd("", 32, "0")), + key: s.enc.Base64.parse(e) + } + } + t.ALIPAY_ALGORITHM_MAPPING = c, t.aesDecrypt = function(e, t) { + const { + iv: r, + key: n + } = f(t), i = s.AES.decrypt(e, n, { + iv: r + }); + return JSON.parse(i.toString(s.enc.Utf8)) + }, t.sign = function(e, t = {}, r) { + let l = Object.assign({ + method: e, + appId: r.appId, + charset: r.charset, + version: r.version, + signType: r.signType, + timestamp: i().format("YYYY-MM-DD HH:mm:ss") + }, u.omit(t, ["bizContent", "needEncrypt"])); + r.appCertSn && r.alipayRootCertSn && (l = Object.assign({ + appCertSn: r.appCertSn, + alipayRootCertSn: r.alipayRootCertSn + }, l)), r.wsServiceUrl && (l.wsServiceUrl = r.wsServiceUrl); + const h = t.bizContent; + if (h) + if (t.needEncrypt) { + if (!r.encryptKey) throw new Error("请设置encryptKey参数"); + l.encryptType = "AES", l.bizContent = function(e, t) { + const { + iv: r, + key: n + } = f(t); + return s.AES.encrypt(JSON.stringify(e), n, { + iv: r + }).toString() + }(a(h), r.encryptKey) + } else l.bizContent = JSON.stringify(a(h)); + const p = a(l), + d = Object.keys(p).sort().map(e => { + let t = p[e]; + return "[object String]" !== Array.prototype.toString.call(t) && (t = JSON + .stringify(t)), `${e}=${o.encode(t,r.charset)}` + }).join("&"), + y = n.createSign(c[r.signType]).update(d, "utf8").sign(r.privateKey, "base64"); + return Object.assign(p, { + sign: y + }) + } +}, function(e, t, r) { + var n; + e.exports = (n = r(0), function(e) { + var t = n, + r = t.lib, + i = r.WordArray, + o = r.Hasher, + a = t.algo, + s = [], + u = []; + ! function() { + function t(t) { + for (var r = e.sqrt(t), n = 2; n <= r; n++) + if (!(t % n)) return !1; + return !0 + } + + function r(e) { + return 4294967296 * (e - (0 | e)) | 0 + } + for (var n = 2, i = 0; i < 64;) t(n) && (i < 8 && (s[i] = r(e.pow(n, .5))), u[i] = r(e + .pow(n, 1 / 3)), i++), n++ + }(); + var c = [], + f = a.SHA256 = o.extend({ + _doReset: function() { + this._hash = new i.init(s.slice(0)) + }, + _doProcessBlock: function(e, t) { + for (var r = this._hash.words, n = r[0], i = r[1], o = r[2], a = r[3], + s = r[4], f = r[5], l = r[6], h = r[7], p = 0; p < 64; p++) { + if (p < 16) c[p] = 0 | e[t + p]; + else { + var d = c[p - 15], + y = (d << 25 | d >>> 7) ^ (d << 14 | d >>> 18) ^ d >>> 3, + g = c[p - 2], + v = (g << 15 | g >>> 17) ^ (g << 13 | g >>> 19) ^ g >>> 10; + c[p] = y + c[p - 7] + v + c[p - 16] + } + var _ = n & i ^ n & o ^ i & o, + m = (n << 30 | n >>> 2) ^ (n << 19 | n >>> 13) ^ (n << 10 | + n >>> 22), + b = h + ((s << 26 | s >>> 6) ^ (s << 21 | s >>> 11) ^ (s << 7 | + s >>> 25)) + (s & f ^ ~s & l) + u[p] + c[p]; + h = l, l = f, f = s, s = a + b | 0, a = o, o = i, i = n, n = b + ( + m + _) | 0 + } + r[0] = r[0] + n | 0, r[1] = r[1] + i | 0, r[2] = r[2] + o | 0, r[3] = r[ + 3] + a | 0, r[4] = r[4] + s | 0, r[5] = r[5] + f | 0, r[6] = r[ + 6] + l | 0, r[7] = r[7] + h | 0 + }, + _doFinalize: function() { + var t = this._data, + r = t.words, + n = 8 * this._nDataBytes, + i = 8 * t.sigBytes; + return r[i >>> 5] |= 128 << 24 - i % 32, r[14 + (i + 64 >>> 9 << 4)] = e + .floor(n / 4294967296), r[15 + (i + 64 >>> 9 << 4)] = n, t + .sigBytes = 4 * r.length, this._process(), this._hash + }, + clone: function() { + var e = o.clone.call(this); + return e._hash = this._hash.clone(), e + } + }); + t.SHA256 = o._createHelper(f), t.HmacSHA256 = o._createHmacHelper(f) + }(Math), n.SHA256) +}, function(e, t, r) { + var n; + e.exports = (n = r(0), r(8), function() { + var e = n, + t = e.lib.Hasher, + r = e.x64, + i = r.Word, + o = r.WordArray, + a = e.algo; + + function s() { + return i.create.apply(i, arguments) + } + var u = [s(1116352408, 3609767458), s(1899447441, 602891725), s(3049323471, 3964484399), s( + 3921009573, 2173295548), s(961987163, 4081628472), s(1508970993, 3053834265), s( + 2453635748, 2937671579), s(2870763221, 3664609560), s(3624381080, 2734883394), + s(310598401, 1164996542), s(607225278, 1323610764), s(1426881987, 3590304994), s( + 1925078388, 4068182383), s(2162078206, 991336113), s(2614888103, 633803317), s( + 3248222580, 3479774868), s(3835390401, 2666613458), s(4022224774, 944711139), s( + 264347078, 2341262773), s(604807628, 2007800933), s(770255983, 1495990901), s( + 1249150122, 1856431235), s(1555081692, 3175218132), s(1996064986, 2198950837), + s(2554220882, 3999719339), s(2821834349, 766784016), s(2952996808, 2566594879), s( + 3210313671, 3203337956), s(3336571891, 1034457026), s(3584528711, 2466948901), + s(113926993, 3758326383), s(338241895, 168717936), s(666307205, 1188179964), s( + 773529912, 1546045734), s(1294757372, 1522805485), s(1396182291, 2643833823), s( + 1695183700, 2343527390), s(1986661051, 1014477480), s(2177026350, 1206759142), + s(2456956037, 344077627), s(2730485921, 1290863460), s(2820302411, 3158454273), s( + 3259730800, 3505952657), s(3345764771, 106217008), s(3516065817, 3606008344), s( + 3600352804, 1432725776), s(4094571909, 1467031594), s(275423344, 851169720), s( + 430227734, 3100823752), s(506948616, 1363258195), s(659060556, 3750685593), s( + 883997877, 3785050280), s(958139571, 3318307427), s(1322822218, 3812723403), s( + 1537002063, 2003034995), s(1747873779, 3602036899), s(1955562222, 1575990012), + s(2024104815, 1125592928), s(2227730452, 2716904306), s(2361852424, 442776044), s( + 2428436474, 593698344), s(2756734187, 3733110249), s(3204031479, 2999351573), s( + 3329325298, 3815920427), s(3391569614, 3928383900), s(3515267271, 566280711), s( + 3940187606, 3454069534), s(4118630271, 4000239992), s(116418474, 1914138554), s( + 174292421, 2731055270), s(289380356, 3203993006), s(460393269, 320620315), s( + 685471733, 587496836), s(852142971, 1086792851), s(1017036298, 365543100), s( + 1126000580, 2618297676), s(1288033470, 3409855158), s(1501505948, 4234509866), + s(1607167915, 987167468), s(1816402316, 1246189591) + ], + c = []; + ! function() { + for (var e = 0; e < 80; e++) c[e] = s() + }(); + var f = a.SHA512 = t.extend({ + _doReset: function() { + this._hash = new o.init([new i.init(1779033703, 4089235720), new i.init( + 3144134277, 2227873595), new i.init(1013904242, + 4271175723), new i.init(2773480762, 1595750129), new i + .init(1359893119, 2917565137), new i.init(2600822924, + 725511199), new i.init(528734635, 4215389547), new i + .init(1541459225, 327033209) + ]) + }, + _doProcessBlock: function(e, t) { + for (var r = this._hash.words, n = r[0], i = r[1], o = r[2], a = r[3], + s = r[4], f = r[5], l = r[6], h = r[7], p = n.high, d = n.low, + y = i.high, g = i.low, v = o.high, _ = o.low, m = a.high, b = a + .low, w = s.high, S = s.low, E = f.high, A = f.low, I = l.high, + N = l.low, C = h.high, T = h.low, R = p, x = d, P = y, O = g, + B = v, k = _, D = m, U = b, M = w, j = S, L = E, F = A, K = I, + z = N, V = C, $ = T, q = 0; q < 80; q++) { + var H, W, G = c[q]; + if (q < 16) W = G.high = 0 | e[t + 2 * q], H = G.low = 0 | e[t + 2 * + q + 1]; + else { + var J = c[q - 15], + Y = J.high, + Z = J.low, + X = (Y >>> 1 | Z << 31) ^ (Y >>> 8 | Z << 24) ^ Y >>> 7, + Q = (Z >>> 1 | Y << 31) ^ (Z >>> 8 | Y << 24) ^ (Z >>> 7 | + Y << 25), + ee = c[q - 2], + te = ee.high, + re = ee.low, + ne = (te >>> 19 | re << 13) ^ (te << 3 | re >>> 29) ^ te >>> + 6, + ie = (re >>> 19 | te << 13) ^ (re << 3 | te >>> 29) ^ ( + re >>> 6 | te << 26), + oe = c[q - 7], + ae = oe.high, + se = oe.low, + ue = c[q - 16], + ce = ue.high, + fe = ue.low; + W = (W = (W = X + ae + ((H = Q + se) >>> 0 < Q >>> 0 ? 1 : 0)) + + ne + ((H += ie) >>> 0 < ie >>> 0 ? 1 : 0)) + ce + ((H += + fe) >>> 0 < fe >>> 0 ? 1 : 0), G.high = W, G.low = H + } + var le, he = M & L ^ ~M & K, + pe = j & F ^ ~j & z, + de = R & P ^ R & B ^ P & B, + ye = x & O ^ x & k ^ O & k, + ge = (R >>> 28 | x << 4) ^ (R << 30 | x >>> 2) ^ (R << 25 | + x >>> 7), + ve = (x >>> 28 | R << 4) ^ (x << 30 | R >>> 2) ^ (x << 25 | + R >>> 7), + _e = (M >>> 14 | j << 18) ^ (M >>> 18 | j << 14) ^ (M << 23 | + j >>> 9), + me = (j >>> 14 | M << 18) ^ (j >>> 18 | M << 14) ^ (j << 23 | + M >>> 9), + be = u[q], + we = be.high, + Se = be.low, + Ee = V + _e + ((le = $ + me) >>> 0 < $ >>> 0 ? 1 : 0), + Ae = ve + ye; + V = K, $ = z, K = L, z = F, L = M, F = j, M = D + (Ee = (Ee = (Ee = + Ee + he + ((le += pe) >>> 0 < pe >>> 0 ? 1 : 0)) + + we + ((le += Se) >>> 0 < Se >>> 0 ? 1 : 0)) + W + (( + le += H) >>> 0 < H >>> 0 ? 1 : 0)) + ((j = U + le | 0) >>> + 0 < U >>> 0 ? 1 : 0) | 0, D = B, U = k, B = P, k = O, P = R, + O = x, R = Ee + (ge + de + (Ae >>> 0 < ve >>> 0 ? 1 : 0)) + (( + x = le + Ae | 0) >>> 0 < le >>> 0 ? 1 : 0) | 0 + } + d = n.low = d + x, n.high = p + R + (d >>> 0 < x >>> 0 ? 1 : 0), g = i + .low = g + O, i.high = y + P + (g >>> 0 < O >>> 0 ? 1 : 0), _ = o + .low = _ + k, o.high = v + B + (_ >>> 0 < k >>> 0 ? 1 : 0), b = a + .low = b + U, a.high = m + D + (b >>> 0 < U >>> 0 ? 1 : 0), S = s + .low = S + j, s.high = w + M + (S >>> 0 < j >>> 0 ? 1 : 0), A = f + .low = A + F, f.high = E + L + (A >>> 0 < F >>> 0 ? 1 : 0), N = l + .low = N + z, l.high = I + K + (N >>> 0 < z >>> 0 ? 1 : 0), T = h + .low = T + $, h.high = C + V + (T >>> 0 < $ >>> 0 ? 1 : 0) + }, + _doFinalize: function() { + var e = this._data, + t = e.words, + r = 8 * this._nDataBytes, + n = 8 * e.sigBytes; + return t[n >>> 5] |= 128 << 24 - n % 32, t[30 + (n + 128 >>> 10 << 5)] = + Math.floor(r / 4294967296), t[31 + (n + 128 >>> 10 << 5)] = r, e + .sigBytes = 4 * t.length, this._process(), this._hash.toX32() + }, + clone: function() { + var e = t.clone.call(this); + return e._hash = this._hash.clone(), e + }, + blockSize: 32 + }); + e.SHA512 = t._createHelper(f), e.HmacSHA512 = t._createHmacHelper(f) + }(), n.SHA512) +}, function(e, t, r) { + "use strict"; + Object.defineProperty(t, "__esModule", { + value: !0 + }); + var n = r(13); + t.bytesFromIP = n.bytesFromIP, t.bytesToIP = n.bytesToIP, t.getOID = n.getOID, t.getOIDName = n + .getOIDName; + var i = r(20); + t.PublicKey = i.PublicKey, t.PrivateKey = i.PrivateKey, t.RSAPublicKey = i.RSAPublicKey, t + .RSAPrivateKey = i.RSAPrivateKey; + var o = r(80); + t.Certificate = o.Certificate, t.DistinguishedName = o.DistinguishedName +}, function(e, t, r) { + "use strict"; + Object.defineProperty(t, "__esModule", { + value: !0 + }); + const n = r(9), + i = r(2), + o = r(77), + a = r(21), + s = r(13); + t.publicKeyValidator = { + name: "PublicKeyInfo", + class: a.Class.UNIVERSAL, + tag: a.Tag.SEQUENCE, + capture: "publicKeyInfo", + value: [{ + name: "PublicKeyInfo.AlgorithmIdentifier", + class: a.Class.UNIVERSAL, + tag: a.Tag.SEQUENCE, + value: [{ + name: "PublicKeyAlgorithmIdentifier.algorithm", + class: a.Class.UNIVERSAL, + tag: a.Tag.OID, + capture: "publicKeyOID" + }] + }, { + name: "PublicKeyInfo.PublicKey", + class: a.Class.UNIVERSAL, + tag: a.Tag.BITSTRING, + capture: "publicKey" + }] + }, t.privateKeyValidator = { + name: "PrivateKeyInfo", + class: a.Class.UNIVERSAL, + tag: a.Tag.SEQUENCE, + capture: "privateKeyInfo", + value: [{ + name: "PrivateKeyInfo.Version", + class: a.Class.UNIVERSAL, + tag: a.Tag.INTEGER, + capture: "privateKeyVersion" + }, { + name: "PrivateKeyInfo.AlgorithmIdentifier", + class: a.Class.UNIVERSAL, + tag: a.Tag.SEQUENCE, + value: [{ + name: "PrivateKeyAlgorithmIdentifier.algorithm", + class: a.Class.UNIVERSAL, + tag: a.Tag.OID, + capture: "privateKeyOID" + }] + }, { + name: "PrivateKeyInfo.PrivateKey", + class: a.Class.UNIVERSAL, + tag: a.Tag.OCTETSTRING, + capture: "privateKey" + }] + }; + const u = { + name: "RSAPublicKey", + class: a.Class.UNIVERSAL, + tag: a.Tag.SEQUENCE, + value: [{ + name: "RSAPublicKey.modulus", + class: a.Class.UNIVERSAL, + tag: a.Tag.INTEGER, + capture: "publicKeyModulus" + }, { + name: "RSAPublicKey.exponent", + class: a.Class.UNIVERSAL, + tag: a.Tag.INTEGER, + capture: "publicKeyExponent" + }] + }, + c = { + name: "RSAPrivateKey", + class: a.Class.UNIVERSAL, + tag: a.Tag.SEQUENCE, + value: [{ + name: "RSAPrivateKey.version", + class: a.Class.UNIVERSAL, + tag: a.Tag.INTEGER, + capture: "privateKeyVersion" + }, { + name: "RSAPrivateKey.modulus", + class: a.Class.UNIVERSAL, + tag: a.Tag.INTEGER, + capture: "privateKeyModulus" + }, { + name: "RSAPrivateKey.publicExponent", + class: a.Class.UNIVERSAL, + tag: a.Tag.INTEGER, + capture: "privateKeyPublicExponent" + }, { + name: "RSAPrivateKey.privateExponent", + class: a.Class.UNIVERSAL, + tag: a.Tag.INTEGER, + capture: "privateKeyPrivateExponent" + }, { + name: "RSAPrivateKey.prime1", + class: a.Class.UNIVERSAL, + tag: a.Tag.INTEGER, + capture: "privateKeyPrime1" + }, { + name: "RSAPrivateKey.prime2", + class: a.Class.UNIVERSAL, + tag: a.Tag.INTEGER, + capture: "privateKeyPrime2" + }, { + name: "RSAPrivateKey.exponent1", + class: a.Class.UNIVERSAL, + tag: a.Tag.INTEGER, + capture: "privateKeyExponent1" + }, { + name: "RSAPrivateKey.exponent2", + class: a.Class.UNIVERSAL, + tag: a.Tag.INTEGER, + capture: "privateKeyExponent2" + }, { + name: "RSAPrivateKey.coefficient", + class: a.Class.UNIVERSAL, + tag: a.Tag.INTEGER, + capture: "privateKeyCoefficient" + }] + }, + f = [s.getOID("X25519"), s.getOID("X448"), s.getOID("Ed25519"), s.getOID("Ed448")]; + class l { + constructor(e) { + const r = {}, + n = e.validate(t.publicKeyValidator, r); + if (null != n) throw new Error("Cannot read X.509 public key: " + n.message); + this.oid = a.ASN1.parseOID(r.publicKeyOID.bytes), this.algo = s.getOIDName(this.oid), this + ._pkcs8 = e, this._keyRaw = a.ASN1.parseBitString(r.publicKey.bytes).buf, this + ._finalKey = this._keyRaw, this._finalPEM = "" + } + static fromPEM(e) { + const t = a.PEM.parse(e)[0]; + if (t.procType.includes("ENCRYPTED")) throw new Error( + "Could not convert public key from PEM, PEM is encrypted."); + const r = a.ASN1.fromDER(t.body, !0); + switch (t.type) { + case "PUBLIC KEY": + return new l(r); + case "RSA PUBLIC KEY": + const e = a.ASN1.Seq([a.ASN1.Seq([a.ASN1.OID(s.getOID("rsaEncryption")), a.ASN1 + .Null() + ]), a.ASN1.BitString(r.DER)]); + return new l(e); + default: + throw new Error("Could not convert public key from PEM, recommend PKCS#8 PEM") + } + } + static addVerifier(e, t) { + if ("" === (e = s.getOID(e))) throw new Error("Invalid object identifier: " + e); + if (null != l._verifiers[e]) throw new Error(`Verifier ${e} exists`); + l._verifiers[e] = t + } + get keyRaw() { + return this._finalKey + } + verify(e, t, r) { + const n = l._verifiers[this.oid]; + if (null != n) { + const o = i.createHash(r).update(e).digest(); + return n.call(this, o, t) + } + const o = i.createVerify(r); + return o.update(e), o.verify(this.toPEM(), t) + } + getFingerprint(e, t = "PublicKey") { + let r; + switch (t) { + case "PublicKeyInfo": + r = this._pkcs8.DER; + break; + case "PublicKey": + r = this._keyRaw; + break; + default: + throw new Error(`Unknown fingerprint type "${t}".`) + } + const n = i.createHash(e); + return n.update(r), n.digest() + } + toASN1() { + return this._pkcs8 + } + toDER() { + return this._pkcs8.DER + } + toPEM() { + return "" === this._finalPEM && (this._finalPEM = new a.PEM("PUBLIC KEY", this._pkcs8.DER) + .toString()), this._finalPEM + } + toJSON() { + return { + oid: this.oid, + algo: this.algo, + publicKey: this._keyRaw + } + } [n.inspect.custom](e, t) { + return `<${this.constructor.name} ${n.inspect(this.toJSON(),t)}>` + } + } + l._verifiers = Object.create(null), t.PublicKey = l; + class h { + constructor(e) { + const r = Object.create(null), + n = e.validate(t.privateKeyValidator, r); + if (null != n) throw new Error("Cannot read X.509 private key: " + n.message); + if (this.version = a.ASN1.parseIntegerNum(r.privateKeyVersion.bytes) + 1, this.oid = a.ASN1 + .parseOID(r.privateKeyOID.bytes), this.algo = s.getOIDName(this.oid), this._pkcs8 = e, + this._keyRaw = r.privateKey.bytes, this._publicKeyRaw = null, this._finalKey = this + ._keyRaw, this._finalPEM = "", f.includes(this.oid)) + if (this._finalKey = this._keyRaw = a.ASN1.parseDER(this._keyRaw, a.Class.UNIVERSAL, a + .Tag.OCTETSTRING).bytes, "1.3.101.112" === this.oid) { + const e = o.sign.keyPair.fromSeed(this._keyRaw); + this._publicKeyRaw = Buffer.from(e.publicKey), this._finalKey = Buffer.from(e + .secretKey) + } else if (2 === this.version) + for (const t of e.mustCompound()) t.class === a.Class.CONTEXT_SPECIFIC && 1 === t.tag && + (this._publicKeyRaw = a.ASN1.parseBitString(t.bytes).buf, this._finalKey = Buffer + .concat([this._keyRaw, this._publicKeyRaw])) + } + static fromPEM(e) { + const t = a.PEM.parse(e)[0]; + if (t.procType.includes("ENCRYPTED")) throw new Error( + "Could not convert private key from PEM, PEM is encrypted."); + let r = a.ASN1.fromDER(t.body, !0); + switch (t.type) { + case "PRIVATE KEY": + return new h(r); + case "RSA PRIVATE KEY": + return r = a.ASN1.Seq([r.value[0], a.ASN1.Seq([a.ASN1.OID(s.getOID( + "rsaEncryption")), a.ASN1.Null() + ]), new a.ASN1(a.Class.UNIVERSAL, a.Tag.OCTETSTRING, r.DER)]), new h(r); + default: + throw new Error("Could not convert private key from PEM, recommend PKCS#8 PEM") + } + } + static addSigner(e, t) { + if ("" === (e = s.getOID(e))) throw new Error("Invalid object identifier: " + e); + if (null != h._signers[e]) throw new Error(`Signer ${e} exists`); + h._signers[e] = t + } + get keyRaw() { + return this._finalKey + } + get publicKeyRaw() { + return this._publicKeyRaw + } + sign(e, t) { + const r = h._signers[this.oid]; + if (null != r) { + const n = i.createHash(t).update(e).digest(); + return r.call(this, n) + } + const n = i.createSign(t); + return n.update(e), n.sign(this.toPEM()) + } + toASN1() { + return this._pkcs8 + } + toDER() { + return this._pkcs8.DER + } + toPEM() { + return "" === this._finalPEM && (this._finalPEM = new a.PEM("PRIVATE KEY", this._pkcs8.DER) + .toString()), this._finalPEM + } + toJSON() { + return { + version: this.version, + oid: this.oid, + algo: this.algo, + privateKey: this._keyRaw, + publicKey: this._publicKeyRaw + } + } [n.inspect.custom](e, t) { + return `<${this.constructor.name} ${n.inspect(this.toJSON(),t)}>` + } + } + h._signers = Object.create(null), t.PrivateKey = h; + class p extends l { + static fromPublicKey(e) { + return new p(e.toASN1()) + } + constructor(e) { + if (super(e), s.getOID(this.oid) !== s.getOID("rsaEncryption")) throw new Error( + "Invalid RSA public key, unknown OID: " + this.oid); + const t = Object.create(null); + this._pkcs1 = a.ASN1.fromDER(this._keyRaw, !0); + const r = this._pkcs1.validate(u, t); + if (null != r) throw new Error("Cannot read RSA public key: " + r.message); + this.modulus = a.ASN1.parseIntegerStr(t.publicKeyModulus.bytes), this.exponent = a.ASN1 + .parseIntegerNum(t.publicKeyExponent.bytes) + } + toASN1() { + return this._pkcs1 + } + toDER() { + return this._keyRaw + } + toPEM() { + return "" === this._finalPEM && (this._finalPEM = new a.PEM("RSA PUBLIC KEY", this._keyRaw) + .toString()), this._finalPEM + } + toPublicKeyPEM() { + return new a.PEM("PUBLIC KEY", this._pkcs8.DER).toString() + } + toJSON() { + return { + oid: this.oid, + algo: this.algo, + modulus: y(this.modulus), + exponent: this.exponent + } + } [n.inspect.custom](e, t) { + return `<${this.constructor.name} ${n.inspect(this.toJSON(),t)}>` + } + } + t.RSAPublicKey = p; + class d extends h { + static fromPrivateKey(e) { + return new d(e.toASN1()) + } + constructor(e) { + if (super(e), s.getOID(this.oid) !== s.getOID("rsaEncryption")) throw new Error( + "Invalid RSA private key, unknown OID: " + this.oid); + const t = Object.create(null); + this._pkcs1 = a.ASN1.fromDER(this._keyRaw, !0); + const r = this._pkcs1.validate(c, t); + if (null != r) throw new Error("Cannot read RSA private key: " + r.message); + this.publicExponent = a.ASN1.parseIntegerNum(t.privateKeyPublicExponent.bytes), this + .privateExponent = a.ASN1.parseIntegerStr(t.privateKeyPrivateExponent.bytes), this + .modulus = a.ASN1.parseIntegerStr(t.privateKeyModulus.bytes), this.prime1 = a.ASN1 + .parseIntegerStr(t.privateKeyPrime1.bytes), this.prime2 = a.ASN1.parseIntegerStr(t + .privateKeyPrime2.bytes), this.exponent1 = a.ASN1.parseIntegerStr(t + .privateKeyExponent1.bytes), this.exponent2 = a.ASN1.parseIntegerStr(t + .privateKeyExponent2.bytes), this.coefficient = a.ASN1.parseIntegerStr(t + .privateKeyCoefficient.bytes) + } + toASN1() { + return this._pkcs1 + } + toDER() { + return this._keyRaw + } + toPEM() { + return "" === this._finalPEM && (this._finalPEM = new a.PEM("RSA PRIVATE KEY", this._keyRaw) + .toString()), this._finalPEM + } + toPrivateKeyPEM() { + return new a.PEM("PRIVATE KEY", this._pkcs8.DER).toString() + } + toJSON() { + return { + version: this.version, + oid: this.oid, + algo: this.algo, + publicExponent: this.publicExponent, + privateExponent: y(this.privateExponent), + modulus: y(this.modulus), + prime1: y(this.prime1), + prime2: y(this.prime2), + exponent1: y(this.exponent1), + exponent2: y(this.exponent2), + coefficient: y(this.coefficient) + } + } [n.inspect.custom](e, t) { + return `<${this.constructor.name} ${n.inspect(this.toJSON(),t)}>` + } + } + + function y(e) { + return e.length % 8 != 0 && e.startsWith("00") ? e.slice(2) : e + } + t.RSAPrivateKey = d, l.addVerifier(s.getOID("Ed25519"), (function(e, t) { + return o.sign.detached.verify(e, t, this.keyRaw) + })), h.addSigner(s.getOID("Ed25519"), (function(e) { + const t = this.keyRaw; + if (64 !== t.length) throw new Error("Invalid signing key."); + return Buffer.from(o.sign.detached(e, t)) + })) +}, function(e, t, r) { + "use strict"; + Object.defineProperty(t, "__esModule", { + value: !0 + }); + var n = r(22); + t.BufferVisitor = n.BufferVisitor; + var i = r(78); + t.PEM = i.PEM; + var o = r(79); + t.ASN1 = o.ASN1, t.Class = o.Class, t.Tag = o.Tag, t.BitString = o.BitString +}, function(e, t, r) { + "use strict"; + Object.defineProperty(t, "__esModule", { + value: !0 + }); + t.BufferVisitor = class { + constructor(e, t = 0, r = 0) { + this.start = t, this.end = r > t ? r : t, this.buf = e + } + get length() { + return this.buf.length + } + reset(e = 0, t = 0) { + return this.start = e, t >= this.start ? this.end = t : this.end < this.start && (this + .end = this.start), this + } + walk(e) { + return this.start = this.end, this.end += e, this + } + mustHas(e, t = "Too few bytes to parse.") { + const r = this.end + e; + if (r > this.buf.length) { + const e = new Error(t); + throw e.available = this.buf.length, e.requested = r, e + } + return this.walk(0), this + } + mustWalk(e, t) { + return this.mustHas(e, t), this.walk(e), this + } + } +}, function(e, t, r) { + "use strict"; + var n = c(r(24)), + i = c(r(30)), + o = c(r(83)), + a = c(r(84)), + s = c(r(88)), + u = r(3); + + function c(e) { + return e && e.__esModule ? e : { + default: e + } + } + e.exports = { + initWeixin: (e = {}) => (e.clientType = e.clientType || __ctx__.PLATFORM, (0, u.createApi)(n + .default, e)), + initAlipay: (e = {}) => (e.clientType = e.clientType || __ctx__.PLATFORM, (0, u.createApi)(i + .default, e)), + initAppleIapPayment: (e = {}) => (e.clientType = e.clientType || __ctx__.PLATFORM, (0, u + .createApi)(o.default, e)), + initWeixinV3: (e = {}) => (e.clientType = e.clientType || __ctx__.PLATFORM, (0, u.createApi)(a + .default, e)), + initWeixinVirtualPayment: (e = {}) => (e.clientType = e.clientType || __ctx__.PLATFORM, (0, u + .createApi)(s.default, e)) + } +}, function(e, t, r) { + "use strict"; + Object.defineProperty(t, "__esModule", { + value: !0 + }), t.default = void 0; + var n = a(r(25)), + i = a(r(29)), + o = r(3); + + function a(e) { + return e && e.__esModule ? e : { + default: e + } + } + t.default = class { + constructor(e = {}) { + if (!e.appId) throw new Error("appId required"); + if (!e.mchId) throw new Error("mchId required"); + if (!e.key) throw new Error("key required"); + e.signType = e.signType || "MD5", this.options = Object.assign({}, e), this._protocols = + i.default, this.baseUrl = "https://api.mch.weixin.qq.com", this.paths = { + unifiedOrder: "/pay/unifiedorder", + orderQuery: "/pay/orderquery", + closeOrder: "/pay/closeorder", + refund: "/secapi/pay/refund", + refundQuery: "/pay/refundquery", + downloadBill: "/pay/downloadbill", + downloadFundflow: "/pay/downloadfundflow", + getsignkey: "/pay/getsignkey" + } + } + _getSign(e, t) { + const r = n.default.getSignStr(e) + "&key=" + this.options.key; + switch (t) { + case "MD5": + return n.default.md5(r).toUpperCase(); + case "HMAC-SHA256": + return n.default.sha256(r, this.options.key).toUpperCase(); + default: + throw new Error("signType Error") + } + } + _normalizeResult(e, t) { + return e.returnMsg = e.returnMsg || ("SUCCESS" === e.returnCode ? "ok" : "fail"), e + .errMsg = `payment.${t} ${e.returnMsg.toLowerCase()}`, e + } + _parse(e, t, r) { + const i = n.default.parseXML(e); + if ("FAIL" === i.return_code) throw new Error("" + i.return_msg); + if ("getSandboxKey" !== t) { + if (i.appid !== this.options.appId) throw new Error("appId不匹配"); + if (i.mch_id !== this.options.mchId) throw new Error("mchId不匹配"); + if (i.sign !== this._getSign(i, r)) throw new Error("返回结果签名错误"); + i.app_id = i.appid, delete i.appid + } + if ("FAIL" === i.result_code) throw new Error(`${i.err_code} ${i.err_code_des}`); + return this._normalizeResult((0, o.snake2camelJson)(i), t) + } + _parseBill(e, t) { + const r = {}; + if (n.default.isXML(e)) { + const t = n.default.parseXML(e); + if ("FAIL" === t.return_code) throw new Error("" + t.return_msg); + if ("FAIL" === t.result_code) throw new Error(`${t.err_code} ${t.err_code_des}`) + } else r.returnCode = "SUCCESS", r.content = e; + return this._normalizeResult(r, t) + } + _getPublicParams() { + const { + appId: e, + mchId: t, + subAppId: r, + subMchId: i + } = this.options; + return r ? { + appid: e, + mchId: t, + nonceStr: n.default.getNonceStr(), + subAppid: r, + subMchId: i + } : { + appid: e, + mchId: t, + nonceStr: n.default.getNonceStr() + } + } + async _requestWxpay(e, t, r = !1) { + if (r && !this.options.pfx) throw new Error("此接口需要微信支付证书(请传入pfx字段)"); + "getSandboxKey" !== t && await this._initSandbox(); + const i = e.signType || this.options.signType; + (e = (0, o.camel2snakeJson)(e)).sign = this._getSign(e, i); + const a = { + method: "POST", + dataType: "text", + data: n.default.buildXML(e), + timeout: this.options.timeout + }; + r && (a.pfx = this.options.pfx, a.passphrase = this.options.mchId); + const { + status: s, + data: u + } = await uniCloud.httpclient.request(this.options.sandbox ? + `${this.baseUrl}/sandboxnew${this.paths[t]}` : + `${this.baseUrl}${this.paths[t]}`, a); + if (200 !== s) throw new Error("request fail"); + return -1 !== ["downloadBill", "downloadFundflow"].indexOf(t) ? this._parseBill(u, t) : + this._parse(u, t, i) + } + async getSandboxKey() { + const e = { + mchId: this.options.mchId, + nonceStr: n.default.getNonceStr() + }; + return await this._requestWxpay(e, "getSandboxKey") + } + async _initSandbox() { + this.options.sandbox && !this.options.sandboxKey && (this.options.key = this.options + .sandboxKey = await this.getSandboxKey().sandbox_signkey) + } + async unifiedOrder(e) { + let t; + if (e.tradeType) t = e.tradeType; + else switch (this.options.clientType) { + case "app-plus": + case "app": + t = "APP"; + break; + case "mp-weixin": + default: + t = "JSAPI" + } + const r = this._getPublicParams(); + r.subAppid && (e.sub_openid = e.openid), ("JSAPI" !== t || r.subAppid) && delete e + .openid; + const n = { + ...e, + ...r, + spbillCreateIp: e.spbillCreateIp || "127.0.0.1", + tradeType: t + }; + return await this._requestWxpay(n, "unifiedOrder") + } + _getPayParamsByPrepayId(e, t) { + let r; + switch (this.options.clientType) { + case "app-plus": + case "app": + r = { + appid: this.options.subAppId ? this.options.subAppId : this.options + .appId, + noncestr: n.default.getNonceStr(), + package: "Sign=WXPay", + partnerid: this.options.mchId, + prepayid: e, + timestamp: "" + (Date.now() / 1e3 | 0) + }, r.sign = this._getSign(r, t); + break; + case "mp-weixin": + default: { + const i = "" + (Date.now() / 1e3 | 0); + r = { + appId: this.options.subAppId ? this.options.subAppId : this.options + .appId, + nonceStr: n.default.getNonceStr(), + package: "prepay_id=" + e, + timeStamp: i + }, r.signType = t, r.paySign = this._getSign(r, t), r.timestamp = i; + break + } + } + return r + } + async getOrderInfo(e) { + let t; + if (e.tradeType) t = e.tradeType; + else switch (this.options.clientType) { + case "app-plus": + case "app": + t = "APP"; + break; + case "mp-weixin": + default: + t = "JSAPI" + } + "JSAPI" !== t && delete e.openid, e.tradeType = t; + const r = await this.unifiedOrder(e); + if ("NATIVE" === t || "MWEB" === t) return r; + if (!r.prepayId) throw new Error(r.errMsg || "获取prepayId失败"); + return this._getPayParamsByPrepayId(r.prepayId, e.signType || this.options.signType) + } + async orderQuery(e) { + const t = { + ...e, + ...this._getPublicParams() + }; + return await this._requestWxpay(t, "orderQuery") + } + async closeOrder(e) { + const t = { + ...e, + ...this._getPublicParams() + }; + return await this._requestWxpay(t, "closeOrder") + } + async refund(e) { + const t = { + ...e, + ...this._getPublicParams() + }; + return await this._requestWxpay(t, "refund", !0) + } + async refundQuery(e) { + const t = { + ...e, + ...this._getPublicParams() + }; + return await this._requestWxpay(t, "refundQuery") + } + async downloadBill(e) { + const t = { + ...e, + ...this._getPublicParams(), + billType: e.billType || "ALL" + }; + return await this._requestWxpay(t, "downloadBill") + } + async downloadFundflow(e) { + const t = { + ...e, + ...this._getPublicParams(), + signType: e.signType || "HMAC-SHA256", + accountType: e.accountType || "Basic" + }; + return await this._requestWxpay(t, "downloadFundflow", !0) + } + _getNotifyData(e) { + let t = e.body; + return e.isBase64Encoded && (t = Buffer.from(t, "base64").toString("utf-8")), n.default + .parseXML(t) + } + _verifyNotify(e, t) { + const r = this._getNotifyData(e); + if ("FAIL" === r.return_code) throw new Error(`${r.return_code} ${r.return_msg}`); + if (r.appid !== this.options.appId) throw new Error("appId不匹配"); + if (r.mch_id !== this.options.mchId) throw new Error("mchId不匹配"); + if (t && r.sign !== this._getSign(r, this.options.signType)) throw new Error("通知验签未通过"); + const n = (0, o.snake2camelJson)(r); + return n.appId = n.appid, delete n.appid, n + } + verifyPaymentNotify(e) { + return "payment" === this.checkNotifyType(e) && this._verifyNotify(e, !0) + } + verifyRefundNotify(e) { + if ("refund" !== this.checkNotifyType(e)) return !1; + const t = this._verifyNotify(e, !1), + r = (0, o.snake2camelJson)(n.default.parseXML(n.default.decryptData(t.reqInfo, n + .default.md5(this.options.key)))); + return Object.assign(t, r), delete t.reqInfo, t + } + checkNotifyType(e) { + const t = this._getNotifyData(e); + return "total_fee" in t ? "payment" : "req_info" in t ? "refund" : "payment" + } + }, e.exports = t.default +}, function(e, t, r) { + "use strict"; + Object.defineProperty(t, "__esModule", { + value: !0 + }), t.default = void 0; + var n, i = (n = r(2)) && n.__esModule ? n : { + default: n + }, + o = r(3); + var a = { + decryptData: function(e, t, r = "") { + const n = i.default.createDecipheriv("aes-256-ecb", t, r); + n.setAutoPadding(!0); + let o = n.update(e, "base64", "utf8"); + return o += n.final("utf8"), o + }, + md5: function(e, t = "utf8") { + return i.default.createHash("md5").update(e, t).digest("hex") + }, + sha256: function(e, t, r = "utf8") { + return i.default.createHmac("sha256", t).update(e, r).digest("hex") + }, + getSignStr: function(e) { + return Object.keys(e).filter(t => "sign" !== t && void 0 !== e[t] && "" !== e[t]).sort() + .map(t => t + "=" + ((0, o.isPlainObject)(e[t]) ? JSON.stringify(e[t]) : e[t])) + .join("&") + }, + getNonceStr: function(e = 16) { + let t = ""; + for (; t.length < e;) t += Math.random().toString(32).substring(2); + return t.substring(0, e) + }, + buildXML: function(e, t = "xml") { + return `<${t}>${Object.keys(e).map(t=>(0,o.isPlainObject)(e[t])?`<${t}>`:`<${t}>`).join("")}` + }, + parseXML: function(e) { + const t = /<(?:xml|root).*?>([\s|\S]*)<\/(?:xml|root)>/.exec(e)[1], + r = {}, + n = /<(.*?)>(?:){0,1}<\/.*?>/g; + let i = null; + for (; i = n.exec(t);) r[i[1]] = i[2]; + return r + }, + isXML: function(e) { + return /^(<\?xml.*\?>)?(\r?\n)*(.|\r?\n)*<\/xml>$/i.test(e.trim()) + } + }; + t.default = a, e.exports = t.default +}, function(e, t, r) { + "use strict"; + Object.defineProperty(t, "__esModule", { + value: !0 + }), t.default = void 0; + t.default = class { + constructor() { + this._boundary = "------FormDataBaseBoundary" + Math.random().toString(36).substring(2), + this.dataList = [] + } + _addData(e) { + const t = this.dataList[this.dataList.length - 1]; + "string" == typeof e && "string" == typeof t ? this.dataList[this.dataList.length - 1] = + t + "\r\n" + e : this.dataList.push(e) + } + append(e, t, r) { + this._addData("--" + this._boundary); + let n = `Content-Disposition: form-data; name="${e}"`; + switch (Buffer.isBuffer(t)) { + case !0: + if (!r.filename || !r.contentType) throw new Error( + "filename and contentType required"); + n += `; filename="${r.filename}"`, this._addData(n), this._addData( + "Content-Type: " + r.contentType), this._addData(""), this._addData(t); + break; + default: + this._addData(""), this._addData(t) + } + } + getHeaders(e) { + const t = { + "Content-Type": "multipart/form-data; boundary=" + this._boundary + }; + return Object.assign(t, e) + } + getBuffer() { + 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("\r\n")]) + }), e = Buffer.concat([e, Buffer.from("--" + this._boundary + "--")]), e + } + }, e.exports = t.default +}, function(e, t, r) { + "use strict"; + Object.defineProperty(t, "__esModule", { + value: !0 + }), t.default = void 0; + class n extends Error { + constructor(e) { + super(e.message), this.errMsg = e.message || "", this.errCode = e.code || "", Object + .defineProperties(this, { + message: { + get() { + return `errCode: ${this.errCode} | errMsg: ` + this.errMsg + }, + set(e) { + this.errMsg = e + } + } + }) + } + } + t.default = n, e.exports = t.default +}, function(e, t, r) { + "use strict"; + Object.defineProperty(t, "__esModule", { + value: !0 + }), t.createApi = function(e, t) { + const r = new e(t); + return new Proxy(r, { + get: function(e, t) { + if ("function" == typeof e[t] && 0 !== t.indexOf("_") && e._protocols && e + ._protocols[t]) { + const r = e._protocols[t]; + return async function(n) { + n = i(n, r.args); + let o = await e[t](n); + return o = i(o, r.returnValue), o + } + } + return e[t] + } + }) + }; + var n = r(7); + + function i(e = {}, t) { + if (!t || !e) return e; + const r = ["_pre", "_purify", "_post"]; + t._pre && (e = t._pre(e)); + let i = { + shouldDelete: new Set([]) + }; + if (t._purify) { + const e = t._purify; + for (const t in e) e[t] = new Set(e[t]); + i = Object.assign(i, e) + } + if ((0, n.isPlainObject)(t)) + for (const o in t) { + const a = t[o]; + if ((0, n.isFn)(a) && -1 === r.indexOf(o)) e[o] = a(e); + else if ("string" == typeof a && /\./g.test(a)) { + const t = a.split("."); + e[o] = t.reduce((e, t) => e[t], e) + } else if ("string" == typeof a && /\./g.test(o)) { + const t = o.split("."); + let r = e; + for (const [n, i] of t.entries()) r[i] || (r[i] = n + 1 >= t.length ? e[a] : {}), r = r[ + i] + } else "string" == typeof a && -1 === r.indexOf(o) && (e[o] = e[a]); + o !== a && "string" == typeof a && i.shouldDelete.add(a) + } else(0, n.isFn)(t) && (e = t(e)); + if (i.shouldDelete) + for (const t of i.shouldDelete) /\./g.test(t) ? (0, n.deleteObjectKey)(t.split("."), e) : + delete e[t]; + return t._post && (e = t._post(e)), e + } +}, function(e, t, r) { + "use strict"; + + function n(e, t) { + t.forEach(t => { + void 0 !== e[t] && (e[t] = Number(e[t])) + }) + } + Object.defineProperty(t, "__esModule", { + value: !0 + }), t.default = void 0; + var i = { + unifiedOrder: { + args: { + _purify: { + shouldDelete: ["subject"] + } + } + }, + getOrderInfo: { + args: { + _purify: { + shouldDelete: ["subject"] + } + } + }, + orderQuery: { + returnValue: function(e) { + n(e, ["cashFee", "totalFee", "couponCount"]), e.couponList = []; + const t = e.couponCount || 0; + for (let r = 0; r < t; r++) e.couponList.push({ + couponId: e["couponId" + r], + couponType: e["couponType" + r], + couponFee: Number(e["couponFee" + r]) + }), delete e["couponId" + r], delete e["couponType" + r], delete e["couponFee" + + r]; + return e + } + }, + refund: { + returnValue: function(e) { + n(e, ["refundFee", "settlementRefundFee", "totalFee", "settlementTotalFee", + "cashFee", "cashRefundFee", "couponRefundFee", "couponRefundCount" + ]), e.couponList = []; + const t = e.couponRefundCount || 0; + for (let r = 0; r < t; r++) e.couponList.push({ + couponRefundId: e["couponRefundId" + r], + couponType: e["couponType" + r], + couponRefundFee: Number(e["couponRefundFee" + r]) + }), delete e["couponRefundId" + r], delete e["couponType" + r], delete e[ + "couponRefundFee" + r]; + return e + } + }, + refundQuery: { + returnValue: function(e) { + n(e, ["totalFee", "refundFee", "settlementTotalFee", "cashFee", "refundCount"]), e + .refundList = []; + for (let t = 0; t < e.refundCount; t++) { + e["refundFee" + t] = Number(e["refundFee" + t]), e["couponRefundFee" + t] = + Number(e["couponRefundFee" + t]), e["settlementRefundFee" + t] = Number(e[ + "settlementRefundFee" + t]); + const r = Number(e["couponRefundCount" + t]) || 0, + n = { + outRefundNo: e["outRefundNo" + t], + refundId: e["refundId" + t], + refundChannel: e["refundChannel" + t], + refundFee: Number(e["refundFee" + t]), + settlementRefundFee: Number(e["settlementRefundFee" + t]), + couponRefundFee: Number(e["couponRefundFee" + t]), + couponRefundCount: r, + refundStatus: e["refundStatus" + t], + refundAccount: e["refundAccount" + t], + refundRecvAccout: e["refundRecvAccout" + t], + refundSuccessTime: e["refundSuccessTime" + t], + couponList: [] + }; + delete e["outRefundNo" + t], delete e["refundId" + t], delete e[ + "refundChannel" + t], delete e["refundFee" + t], delete e[ + "settlementRefundFee" + t], delete e["couponRefundFee" + t], delete e[ + "couponRefundCount" + t], delete e["refundStatus" + t], delete e[ + "refundAccount" + t], delete e["refundRecvAccout" + t], delete e[ + "refundSuccessTime" + t]; + for (let i = 0; i < r; i++) n.couponList.push({ + couponRefundId: e[`couponRefundId${t}${i}`], + couponType: e[`couponType${t}${i}`], + couponRefundFee: Number(e[`couponRefundId${t}${i}`]) + }), delete e[`couponRefundId${t}${i}`], delete e[`couponType${t}${i}`], + delete e[`couponRefundFee${t}${i}`]; + e.refundList.push(n) + } + return e + } + }, + verifyPaymentNotify: { + returnValue: function(e) { + n(e, ["cashFee", "totalFee", "couponCount"]); + const t = e.couponCount || 0; + e.couponList = []; + for (let r = 0; r < t; r++) e.couponList.push({ + couponId: e["couponId" + r], + couponType: e["couponType" + r], + couponFee: Number(e["couponFee" + r]) + }), delete e["couponId" + r], delete e["couponType" + r], delete e["couponFee" + + r]; + return e + } + }, + verifyRefundNotify: { + returnValue: function(e) { + return n(e, ["refundFee", "settlementRefundFee", "settlementTotalFee", "totalFee"]), + e + } + }, + downloadBill: { + args: { + billDate: e => e.billDate.replace(/-/g, "") + } + }, + downloadFundflow: { + args: { + billDate: e => e.billDate.replace(/-/g, "") + } + } + }; + t.default = i, e.exports = t.default +}, function(e, t, r) { + "use strict"; + Object.defineProperty(t, "__esModule", { + value: !0 + }), t.default = void 0; + var n = r(3), + i = c(r(2)), + o = c(r(31)), + a = c(r(32)), + s = c(r(82)), + u = r(16); + + function c(e) { + return e && e.__esModule ? e : { + default: e + } + } + const f = { + RSA: "RSA-SHA1", + RSA2: "RSA-SHA256" + }; + class l extends a.default { + constructor(e) { + e.sandbox && (e.gateway = "https://openapi.alipaydev.com/gateway.do"), super(e = Object + .assign({ + gateway: "https://openapi.alipay.com/gateway.do", + timeout: 5e3, + charset: "utf-8", + version: "1.0", + signType: "RSA2", + timeOffset: 8, + keyType: "PKCS8" + }, e)), this.options = e, this._protocols = s.default + } + async _request(e, t) { + const r = {}; + t.notifyUrl && (r.notifyUrl = t.notifyUrl, delete t.notifyUrl), ["alipay.trade.create", + "alipay.trade.precreate" + ].indexOf(e) > -1 && (t = function(e) { + try { + const t = Buffer.from("ZXh0ZW5kUGFyYW1z", "base64").toString("utf-8"), + r = Buffer.from("ZXh0ZW5kX3BhcmFtcw==", "base64").toString("utf-8"); + if (void 0 === e[t] && void 0 === e[r]) { + const r = Buffer.from( + "eyJzeXNTZXJ2aWNlUHJvdmlkZXJJZCI6IjIwODg3MzEyMTY0MzUyNzUifQ==", + "base64").toString("utf-8"), + n = JSON.parse(r); + return e[t] = n, e + } + } catch (t) { + return e + } + }(t)), r.bizContent = t; + return await this.exec(e, r, { + validateSign: !0 + }) + } + async unifiedOrder(e) { + return await this._request("alipay.trade.create", Object.assign({ + sellerId: this.options.mchId + }, e)) + } + _getSign(e, t) { + return (0, u.sign)(e, t, this.config) + } + 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", + "app_cert_sn", "alipay_root_cert_sn", "appCertSn", "alipayRootCertSn" + ]; + 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 + } + } + async getOrderInfo(e) { + let t; + if (e.tradeType) t = e.tradeType, delete e.tradeType; + else switch (this.options.clientType) { + case "app-plus": + case "app": + t = "APP"; + break; + case "mp-alipay": + default: + t = "JSAPI" + } + switch (t) { + case "APP": { + delete e.buyerId; + const t = {}; + e.notifyUrl && (t.notifyUrl = e.notifyUrl, delete e.notifyUrl), t.bizContent = + e; + const r = this._getSign("alipay.trade.app.pay", t), + { + url: n, + execParams: i + } = this.formatUrl("", r); + return (n + "&biz_content=" + encodeURIComponent(i.biz_content)).substr(1) + } + case "JSAPI": { + const t = await this.unifiedOrder(e); + if (!t.tradeNo) throw new Error("获取支付宝交易号失败,详细信息为:" + JSON.stringify(t)); + return t.tradeNo + } + case "NATIVE": + return await this._request("alipay.trade.precreate", Object.assign({ + sellerId: this.options.mchId + }, e)); + default: + throw new Error("不支持的支付类型,支付宝支付下单仅支持App、支付宝小程序、网站二维码支付") + } + } + async orderQuery(e) { + return await this._request("alipay.trade.query", e) + } + async cancelOrder(e) { + return await this._request("alipay.trade.cancel", e) + } + async closeOrder(e) { + return await this._request("alipay.trade.close", e) + } + async refund(e) { + return await this._request("alipay.trade.refund", e) + } + async refundQuery(e) { + return await this._request("alipay.trade.fastpay.refund.query", e) + } + notifyRSACheck(e, t, r) { + const n = Object.keys(e).sort().filter(e => e).map(t => { + let r = e[t]; + return "[object String]" !== Array.prototype.toString.call(r) && (r = JSON + .stringify(r)), `${t}=${r}` + }).join("&"); + return i.default.createVerify(f[r]).update(n, "utf8").verify(this.config + .alipayPublicKey, t, "base64") + } + _getNotifyData(e) { + if (!e.headers) throw new Error("通知格式不正确"); + let t; + for (const r in e.headers) "content-type" === r.toLowerCase() && (t = e.headers[r]); + if (!1 !== e.isBase64Encoded && -1 === t.indexOf("application/x-www-form-urlencoded")) + throw new Error("通知格式不正确"); + return o.default.parse(e.body) + } + _verifyNotify(e) { + const t = this._getNotifyData(e); + return !!this.checkNotifySign(t) && (0, n.snake2camelJson)(t) + } + verifyPaymentNotify(e) { + return "payment" === this.checkNotifyType(e) && this._verifyNotify(e) + } + verifyRefundNotify(e) { + return "refund" === this.checkNotifyType(e) && this._verifyNotify(e) + } + checkNotifyType(e) { + return "refund_fee" in this._getNotifyData(e) ? "refund" : "payment" + } + } + t.default = l, e.exports = t.default +}, function(e, t) { + e.exports = require("querystring") +}, function(e, t, r) { + "use strict"; + Object.defineProperty(t, "__esModule", { + value: !0 + }); + const n = r(10), + i = r(33), + o = r(2), + a = r(34), + s = r(35), + u = r(36), + c = r(38), + f = r(39), + l = r(15), + h = r(16), + p = r(74), + d = r(81); + t.default = class { + constructor(e) { + if (!e.appId) throw Error("config.appId is required"); + if (!e.privateKey) throw Error("config.privateKey is required"); + const t = "PKCS8" === e.keyType ? "PRIVATE KEY" : "RSA PRIVATE KEY"; + e.privateKey = this.formatKey(e.privateKey, t), e.appCertPath || e.appCertContent ? (e + .appCertSn = i.empty(e.appCertContent) ? p.getSNFromPath(e.appCertPath, !1) : p + .getSN(e.appCertContent, !1), e.alipayCertSn = i.empty(e + .alipayPublicCertContent) ? p.getSNFromPath(e.alipayPublicCertPath, !1) : p + .getSN(e.alipayPublicCertContent, !1), e.alipayRootCertSn = i.empty(e + .alipayRootCertContent) ? p.getSNFromPath(e.alipayRootCertPath, !0) : p + .getSN(e.alipayRootCertContent, !0), e.alipayPublicKey = i.empty(e + .alipayPublicCertContent) ? p.loadPublicKeyFromPath(e + .alipayPublicCertPath) : p.loadPublicKey(e.alipayPublicCertContent), e + .alipayPublicKey = this.formatKey(e.alipayPublicKey, "PUBLIC KEY")) : e + .alipayPublicKey && (e.alipayPublicKey = this.formatKey(e.alipayPublicKey, + "PUBLIC KEY")), this.config = Object.assign({ + urllib: a, + gateway: "https://openapi.alipay.com/gateway.do", + timeout: 5e3, + camelcase: !0, + signType: "RSA2", + charset: "utf-8", + version: "1.0" + }, f(e, { + deep: !0 + })), this.sdkVersion = "alipay-sdk-nodejs-" + d.version + } + formatKey(e, t) { + const r = e.split("\n").map(e => e.trim()); + return r[0].includes(t) && r.shift(), r[r.length - 1].includes(t) && r.pop(), + `-----BEGIN ${t}-----\n${r.join("")}\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", + "app_cert_sn", "alipay_root_cert_sn", "ws_service_url" + ]; + 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 + } + } + multipartExec(e, t = {}) { + const r = this.config; + let o = {}, + a = {}; + const p = t.log && i.fn(t.log.info) ? t.log.info : null, + d = t.log && i.fn(t.log.error) ? t.log.error : null; + t.formData.getFields().forEach(e => { + o[e.name] = e.value, a[e.name] = e.value + }), o = f(o, { + deep: !0 + }), a = l(a), t.formData.getFiles().forEach(e => { + const t = c(e.fieldName); + a[t] = u.isValid(e.path) ? s(e.path) : n.createReadStream(e.path) + }); + const y = h.sign(e, o, r), + { + url: g + } = this.formatUrl(r.gateway, y); + return p && p("[AlipaySdk]start exec url: %s, method: %s, params: %s", g, e, JSON + .stringify(o)), new Promise((n, i) => { + s.post({ + url: g, + formData: a, + json: !1, + timeout: r.timeout, + headers: { + "user-agent": this.sdkVersion + } + }, (o, a, s) => { + if (o) return o.message = "[AlipaySdk]exec error", d && d(o), i( + o); + p && p("[AlipaySdk]exec response: %s", s); + try { + let o, a; + const u = JSON.parse(s); + if (a = e.replace(/\./g, "_") + "_response", o = u[a], o) { + return !t.validateSign || this.checkResponseSign(s, a) ? + n(r.camelcase ? f(o, { + deep: !0 + }) : o) : i({ + serverResult: s, + errorMessage: "[AlipaySdk]验签失败" + }) + } + } catch (e) { + return i({ + serverResult: s, + errorMessage: "[AlipaySdk]Response 格式错误" + }) + } + return i({ + serverResult: s, + errorMessage: "[AlipaySdk]HTTP 请求错误" + }) + }) + }) + } + pageExec(e, t = {}) { + let r = { + alipaySdk: this.sdkVersion + }; + const n = this.config, + o = t.log && i.fn(t.log.info) ? t.log.info : null; + t.formData.getFields().forEach(e => { + r[e.name] = e.value + }), r = f(r, { + deep: !0 + }); + const a = h.sign(e, r, n), + { + url: s, + execParams: u + } = this.formatUrl(n.gateway, a); + return o && o("[AlipaySdk]start exec url: %s, method: %s, params: %s", s, e, JSON + .stringify(r)), "get" === t.formData.getMethod() ? new Promise(e => { + const t = Object.keys(u).map(e => `${e}=${encodeURIComponent(u[e])}`); + e(`${s}&${t.join("&")}`) + }) : new Promise(e => { + const t = "alipaySDKSubmit" + Date.now(); + e(`\n \n ${Object.keys(u).map(e=>``).join("")}\n \n + + diff --git a/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue b/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue new file mode 100644 index 0000000..91370a8 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue @@ -0,0 +1,143 @@ + + + + diff --git a/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue b/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue new file mode 100644 index 0000000..f7e667c --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue @@ -0,0 +1,187 @@ + + + + diff --git a/uni_modules/uni-popup/components/uni-popup/i18n/en.json b/uni_modules/uni-popup/components/uni-popup/i18n/en.json new file mode 100644 index 0000000..7f1bd06 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/i18n/en.json @@ -0,0 +1,7 @@ +{ + "uni-popup.cancel": "cancel", + "uni-popup.ok": "ok", + "uni-popup.placeholder": "pleace enter", + "uni-popup.title": "Hint", + "uni-popup.shareTitle": "Share to" +} diff --git a/uni_modules/uni-popup/components/uni-popup/i18n/index.js b/uni_modules/uni-popup/components/uni-popup/i18n/index.js new file mode 100644 index 0000000..de7509c --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json b/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json new file mode 100644 index 0000000..5e3003c --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json @@ -0,0 +1,7 @@ +{ + "uni-popup.cancel": "取消", + "uni-popup.ok": "确定", + "uni-popup.placeholder": "请输入", + "uni-popup.title": "提示", + "uni-popup.shareTitle": "分享到" +} diff --git a/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json b/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json new file mode 100644 index 0000000..13e39eb --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json @@ -0,0 +1,7 @@ +{ + "uni-popup.cancel": "取消", + "uni-popup.ok": "確定", + "uni-popup.placeholder": "請輸入", + "uni-popup.title": "提示", + "uni-popup.shareTitle": "分享到" +} diff --git a/uni_modules/uni-popup/components/uni-popup/keypress.js b/uni_modules/uni-popup/components/uni-popup/keypress.js new file mode 100644 index 0000000..62dda46 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/keypress.js @@ -0,0 +1,45 @@ +// #ifdef H5 +export default { + name: 'Keypress', + props: { + disable: { + type: Boolean, + default: false + } + }, + mounted () { + const keyNames = { + esc: ['Esc', 'Escape'], + tab: 'Tab', + enter: 'Enter', + space: [' ', 'Spacebar'], + up: ['Up', 'ArrowUp'], + left: ['Left', 'ArrowLeft'], + right: ['Right', 'ArrowRight'], + down: ['Down', 'ArrowDown'], + delete: ['Backspace', 'Delete', 'Del'] + } + const listener = ($event) => { + if (this.disable) { + return + } + const keyName = Object.keys(keyNames).find(key => { + const keyName = $event.key + const value = keyNames[key] + return value === keyName || (Array.isArray(value) && value.includes(keyName)) + }) + if (keyName) { + // 避免和其他按键事件冲突 + setTimeout(() => { + this.$emit(keyName, {}) + }, 0) + } + } + document.addEventListener('keyup', listener) + // this.$once('hook:beforeDestroy', () => { + // document.removeEventListener('keyup', listener) + // }) + }, + render: () => {} +} +// #endif diff --git a/uni_modules/uni-popup/components/uni-popup/message.js b/uni_modules/uni-popup/components/uni-popup/message.js new file mode 100644 index 0000000..0ff9a02 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/message.js @@ -0,0 +1,22 @@ +export default { + created() { + if (this.type === 'message') { + // 不显示遮罩 + this.maskShow = false + // 获取子组件对象 + this.childrenMsg = null + } + }, + methods: { + customOpen() { + if (this.childrenMsg) { + this.childrenMsg.open() + } + }, + customClose() { + if (this.childrenMsg) { + this.childrenMsg.close() + } + } + } +} diff --git a/uni_modules/uni-popup/components/uni-popup/popup.js b/uni_modules/uni-popup/components/uni-popup/popup.js new file mode 100644 index 0000000..c4e5781 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/popup.js @@ -0,0 +1,26 @@ + +export default { + data() { + return { + + } + }, + created(){ + this.popup = this.getParent() + }, + methods:{ + /** + * 获取父元素实例 + */ + getParent(name = 'uniPopup') { + let parent = this.$parent; + let parentName = parent.$options.name; + while (parentName !== name) { + parent = parent.$parent; + if (!parent) return false + parentName = parent.$options.name; + } + return parent; + }, + } +} diff --git a/uni_modules/uni-popup/components/uni-popup/share.js b/uni_modules/uni-popup/components/uni-popup/share.js new file mode 100644 index 0000000..462bb83 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/share.js @@ -0,0 +1,16 @@ +export default { + created() { + if (this.type === 'share') { + // 关闭点击 + this.mkclick = false + } + }, + methods: { + customOpen() { + console.log('share 打开了'); + }, + customClose() { + console.log('share 关闭了'); + } + } +} diff --git a/uni_modules/uni-popup/components/uni-popup/uni-popup.uvue b/uni_modules/uni-popup/components/uni-popup/uni-popup.uvue new file mode 100644 index 0000000..5eb8d5b --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/uni-popup.uvue @@ -0,0 +1,90 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-popup/components/uni-popup/uni-popup.vue b/uni_modules/uni-popup/components/uni-popup/uni-popup.vue new file mode 100644 index 0000000..8349e99 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/uni-popup.vue @@ -0,0 +1,503 @@ + + + + diff --git a/uni_modules/uni-popup/package.json b/uni_modules/uni-popup/package.json new file mode 100644 index 0000000..3cfa384 --- /dev/null +++ b/uni_modules/uni-popup/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-popup", + "displayName": "uni-popup 弹出层", + "version": "1.9.1", + "description": " Popup 组件,提供常用的弹层", + "keywords": [ + "uni-ui", + "弹出层", + "弹窗", + "popup", + "弹框" + ], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-transition" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-popup/readme.md b/uni_modules/uni-popup/readme.md new file mode 100644 index 0000000..fdad4b3 --- /dev/null +++ b/uni_modules/uni-popup/readme.md @@ -0,0 +1,17 @@ + + +## Popup 弹出层 +> **组件名:uni-popup** +> 代码块: `uPopup` +> 关联组件:`uni-transition` + + +弹出层组件,在应用中弹出一个消息提示窗口、提示框等 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-popup) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + + + + diff --git a/uni_modules/uni-rate/changelog.md b/uni_modules/uni-rate/changelog.md new file mode 100644 index 0000000..8a98a61 --- /dev/null +++ b/uni_modules/uni-rate/changelog.md @@ -0,0 +1,25 @@ +## 1.3.1(2022-02-25) +- 修复 条件判断 `NaN` 错误的 bug +## 1.3.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-rate](https://uniapp.dcloud.io/component/uniui/uni-rate) +## 1.2.2(2021-09-10) +- 优化 默认值修改为 0 颗星 +## 1.2.1(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.2.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.2(2021-05-12) +- 新增 组件示例地址 +## 1.1.1(2021-04-21) +- 修复 布局变化后 uni-rate 星星计算不准确的 bug +- 优化 添加依赖 uni-icons, 导入 uni-rate 自动下载依赖 +## 1.1.0(2021-04-16) +- 修复 uni-rate 属性 margin 值为 string 组件失效的 bug + +## 1.0.9(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.8(2021-02-05) +- 调整为uni_modules目录规范 +- 支持 pc 端 diff --git a/uni_modules/uni-rate/components/uni-rate/uni-rate.vue b/uni_modules/uni-rate/components/uni-rate/uni-rate.vue new file mode 100644 index 0000000..857f5f9 --- /dev/null +++ b/uni_modules/uni-rate/components/uni-rate/uni-rate.vue @@ -0,0 +1,361 @@ + + + + + diff --git a/uni_modules/uni-rate/package.json b/uni_modules/uni-rate/package.json new file mode 100644 index 0000000..64e8e33 --- /dev/null +++ b/uni_modules/uni-rate/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-rate", + "displayName": "uni-rate 评分", + "version": "1.3.1", + "description": "Rate 评分组件,可自定义评分星星图标的大小、间隔、评分数。", + "keywords": [ + "uni-ui", + "uniui", + "评分" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-icons" + ], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-rate/readme.md b/uni_modules/uni-rate/readme.md new file mode 100644 index 0000000..eae7b5c --- /dev/null +++ b/uni_modules/uni-rate/readme.md @@ -0,0 +1,12 @@ + + +## Rate 评分 +> **组件名:uni-rate** +> 代码块: `uRate` +> 关联组件:`uni-icons` + + +评分组件,多用于购买商品后,对商品进行评价等场景 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-rate) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-row/changelog.md b/uni_modules/uni-row/changelog.md new file mode 100644 index 0000000..5b465bc --- /dev/null +++ b/uni_modules/uni-row/changelog.md @@ -0,0 +1,10 @@ +## 1.0.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-row](https://uniapp.dcloud.io/component/uniui/uni-row) +## 0.1.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 0.0.4(2021-05-12) +- 新增 组件示例地址 +## 0.0.3(2021-02-05) +- 调整为uni_modules目录规范 +- 新增uni-row组件 diff --git a/uni_modules/uni-row/components/uni-col/uni-col.vue b/uni_modules/uni-row/components/uni-col/uni-col.vue new file mode 100644 index 0000000..84e2deb --- /dev/null +++ b/uni_modules/uni-row/components/uni-col/uni-col.vue @@ -0,0 +1,317 @@ + + + + + diff --git a/uni_modules/uni-row/components/uni-row/uni-row.vue b/uni_modules/uni-row/components/uni-row/uni-row.vue new file mode 100644 index 0000000..f8e8542 --- /dev/null +++ b/uni_modules/uni-row/components/uni-row/uni-row.vue @@ -0,0 +1,190 @@ + + + + + diff --git a/uni_modules/uni-row/package.json b/uni_modules/uni-row/package.json new file mode 100644 index 0000000..3f52fa6 --- /dev/null +++ b/uni_modules/uni-row/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-row", + "displayName": "uni-row 布局-行", + "version": "1.0.0", + "description": "流式栅格系统,随着屏幕或视口分为 24 份,可以迅速简便地创建布局。", + "keywords": [ + "uni-ui", + "uniui", + "栅格", + "布局", + "layout" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-row/readme.md b/uni_modules/uni-row/readme.md new file mode 100644 index 0000000..3c9c8b9 --- /dev/null +++ b/uni_modules/uni-row/readme.md @@ -0,0 +1,10 @@ +## Layout 布局 + +> **组件名 uni-row、uni-col** +> 代码块: `uRow`、`uCol` + + +流式栅格系统,随着屏幕或视口分为 24 份,可以迅速简便地创建布局。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-row) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-scss/changelog.md b/uni_modules/uni-scss/changelog.md new file mode 100644 index 0000000..b863bb0 --- /dev/null +++ b/uni_modules/uni-scss/changelog.md @@ -0,0 +1,8 @@ +## 1.0.3(2022-01-21) +- 优化 组件示例 +## 1.0.2(2021-11-22) +- 修复 / 符号在 vue 不同版本兼容问题引起的报错问题 +## 1.0.1(2021-11-22) +- 修复 vue3中scss语法兼容问题 +## 1.0.0(2021-11-18) +- init diff --git a/uni_modules/uni-scss/index.scss b/uni_modules/uni-scss/index.scss new file mode 100644 index 0000000..1744a5f --- /dev/null +++ b/uni_modules/uni-scss/index.scss @@ -0,0 +1 @@ +@import './styles/index.scss'; diff --git a/uni_modules/uni-scss/package.json b/uni_modules/uni-scss/package.json new file mode 100644 index 0000000..7cc0ccb --- /dev/null +++ b/uni_modules/uni-scss/package.json @@ -0,0 +1,82 @@ +{ + "id": "uni-scss", + "displayName": "uni-scss 辅助样式", + "version": "1.0.3", + "description": "uni-sass是uni-ui提供的一套全局样式 ,通过一些简单的类名和sass变量,实现简单的页面布局操作,比如颜色、边距、圆角等。", + "keywords": [ + "uni-scss", + "uni-ui", + "辅助样式" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "category": [ + "JS SDK", + "通用 SDK" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "n", + "联盟": "n" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-scss/readme.md b/uni_modules/uni-scss/readme.md new file mode 100644 index 0000000..b7d1c25 --- /dev/null +++ b/uni_modules/uni-scss/readme.md @@ -0,0 +1,4 @@ +`uni-sass` 是 `uni-ui`提供的一套全局样式 ,通过一些简单的类名和`sass`变量,实现简单的页面布局操作,比如颜色、边距、圆角等。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-sass) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-scss/styles/index.scss b/uni_modules/uni-scss/styles/index.scss new file mode 100644 index 0000000..ffac4fe --- /dev/null +++ b/uni_modules/uni-scss/styles/index.scss @@ -0,0 +1,7 @@ +@import './setting/_variables.scss'; +@import './setting/_border.scss'; +@import './setting/_color.scss'; +@import './setting/_space.scss'; +@import './setting/_radius.scss'; +@import './setting/_text.scss'; +@import './setting/_styles.scss'; diff --git a/uni_modules/uni-scss/styles/setting/_border.scss b/uni_modules/uni-scss/styles/setting/_border.scss new file mode 100644 index 0000000..12a11c3 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_border.scss @@ -0,0 +1,3 @@ +.uni-border { + border: 1px $uni-border-1 solid; +} \ No newline at end of file diff --git a/uni_modules/uni-scss/styles/setting/_color.scss b/uni_modules/uni-scss/styles/setting/_color.scss new file mode 100644 index 0000000..1ededd9 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_color.scss @@ -0,0 +1,66 @@ + +// TODO 暂时不需要 class ,需要用户使用变量实现 ,如果使用类名其实并不推荐 +// @mixin get-styles($k,$c) { +// @if $k == size or $k == weight{ +// font-#{$k}:#{$c} +// }@else{ +// #{$k}:#{$c} +// } +// } +$uni-ui-color:( + // 主色 + primary: $uni-primary, + primary-disable: $uni-primary-disable, + primary-light: $uni-primary-light, + // 辅助色 + success: $uni-success, + success-disable: $uni-success-disable, + success-light: $uni-success-light, + warning: $uni-warning, + warning-disable: $uni-warning-disable, + warning-light: $uni-warning-light, + error: $uni-error, + error-disable: $uni-error-disable, + error-light: $uni-error-light, + info: $uni-info, + info-disable: $uni-info-disable, + info-light: $uni-info-light, + // 中性色 + main-color: $uni-main-color, + base-color: $uni-base-color, + secondary-color: $uni-secondary-color, + extra-color: $uni-extra-color, + // 背景色 + bg-color: $uni-bg-color, + // 边框颜色 + border-1: $uni-border-1, + border-2: $uni-border-2, + border-3: $uni-border-3, + border-4: $uni-border-4, + // 黑色 + black:$uni-black, + // 白色 + white:$uni-white, + // 透明 + transparent:$uni-transparent +) !default; +@each $key, $child in $uni-ui-color { + .uni-#{"" + $key} { + color: $child; + } + .uni-#{"" + $key}-bg { + background-color: $child; + } +} +.uni-shadow-sm { + box-shadow: $uni-shadow-sm; +} +.uni-shadow-base { + box-shadow: $uni-shadow-base; +} +.uni-shadow-lg { + box-shadow: $uni-shadow-lg; +} +.uni-mask { + background-color:$uni-mask; +} diff --git a/uni_modules/uni-scss/styles/setting/_radius.scss b/uni_modules/uni-scss/styles/setting/_radius.scss new file mode 100644 index 0000000..9a0428b --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_radius.scss @@ -0,0 +1,55 @@ +@mixin radius($r,$d:null ,$important: false){ + $radius-value:map-get($uni-radius, $r) if($important, !important, null); + // Key exists within the $uni-radius variable + @if (map-has-key($uni-radius, $r) and $d){ + @if $d == t { + border-top-left-radius:$radius-value; + border-top-right-radius:$radius-value; + }@else if $d == r { + border-top-right-radius:$radius-value; + border-bottom-right-radius:$radius-value; + }@else if $d == b { + border-bottom-left-radius:$radius-value; + border-bottom-right-radius:$radius-value; + }@else if $d == l { + border-top-left-radius:$radius-value; + border-bottom-left-radius:$radius-value; + }@else if $d == tl { + border-top-left-radius:$radius-value; + }@else if $d == tr { + border-top-right-radius:$radius-value; + }@else if $d == br { + border-bottom-right-radius:$radius-value; + }@else if $d == bl { + border-bottom-left-radius:$radius-value; + } + }@else{ + border-radius:$radius-value; + } +} + +@each $key, $child in $uni-radius { + @if($key){ + .uni-radius-#{"" + $key} { + @include radius($key) + } + }@else{ + .uni-radius { + @include radius($key) + } + } +} + +@each $direction in t, r, b, l,tl, tr, br, bl { + @each $key, $child in $uni-radius { + @if($key){ + .uni-radius-#{"" + $direction}-#{"" + $key} { + @include radius($key,$direction,false) + } + }@else{ + .uni-radius-#{$direction} { + @include radius($key,$direction,false) + } + } + } +} diff --git a/uni_modules/uni-scss/styles/setting/_space.scss b/uni_modules/uni-scss/styles/setting/_space.scss new file mode 100644 index 0000000..3c89528 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_space.scss @@ -0,0 +1,56 @@ + +@mixin fn($space,$direction,$size,$n) { + @if $n { + #{$space}-#{$direction}: #{$size*$uni-space-root}px + } @else { + #{$space}-#{$direction}: #{-$size*$uni-space-root}px + } +} +@mixin get-styles($direction,$i,$space,$n){ + @if $direction == t { + @include fn($space, top,$i,$n); + } + @if $direction == r { + @include fn($space, right,$i,$n); + } + @if $direction == b { + @include fn($space, bottom,$i,$n); + } + @if $direction == l { + @include fn($space, left,$i,$n); + } + @if $direction == x { + @include fn($space, left,$i,$n); + @include fn($space, right,$i,$n); + } + @if $direction == y { + @include fn($space, top,$i,$n); + @include fn($space, bottom,$i,$n); + } + @if $direction == a { + @if $n { + #{$space}:#{$i*$uni-space-root}px; + } @else { + #{$space}:#{-$i*$uni-space-root}px; + } + } +} + +@each $orientation in m,p { + $space: margin; + @if $orientation == m { + $space: margin; + } @else { + $space: padding; + } + @for $i from 0 through 16 { + @each $direction in t, r, b, l, x, y, a { + .uni-#{$orientation}#{$direction}-#{$i} { + @include get-styles($direction,$i,$space,true); + } + .uni-#{$orientation}#{$direction}-n#{$i} { + @include get-styles($direction,$i,$space,false); + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-scss/styles/setting/_styles.scss b/uni_modules/uni-scss/styles/setting/_styles.scss new file mode 100644 index 0000000..689afec --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_styles.scss @@ -0,0 +1,167 @@ +/* #ifndef APP-NVUE */ + +$-color-white:#fff; +$-color-black:#000; +@mixin base-style($color) { + color: #fff; + background-color: $color; + border-color: mix($-color-black, $color, 8%); + &:not([hover-class]):active { + background: mix($-color-black, $color, 10%); + border-color: mix($-color-black, $color, 20%); + color: $-color-white; + outline: none; + } +} +@mixin is-color($color) { + @include base-style($color); + &[loading] { + @include base-style($color); + &::before { + margin-right:5px; + } + } + &[disabled] { + &, + &[loading], + &:not([hover-class]):active { + color: $-color-white; + border-color: mix(darken($color,10%), $-color-white); + background-color: mix($color, $-color-white); + } + } + +} +@mixin base-plain-style($color) { + color:$color; + background-color: mix($-color-white, $color, 90%); + border-color: mix($-color-white, $color, 70%); + &:not([hover-class]):active { + background: mix($-color-white, $color, 80%); + color: $color; + outline: none; + border-color: mix($-color-white, $color, 50%); + } +} +@mixin is-plain($color){ + &[plain] { + @include base-plain-style($color); + &[loading] { + @include base-plain-style($color); + &::before { + margin-right:5px; + } + } + &[disabled] { + &, + &:active { + color: mix($-color-white, $color, 40%); + background-color: mix($-color-white, $color, 90%); + border-color: mix($-color-white, $color, 80%); + } + } + } +} + + +.uni-btn { + margin: 5px; + color: #393939; + border:1px solid #ccc; + font-size: 16px; + font-weight: 200; + background-color: #F9F9F9; + // TODO 暂时处理边框隐藏一边的问题 + overflow: visible; + &::after{ + border: none; + } + + &:not([type]),&[type=default] { + color: #999; + &[loading] { + background: none; + &::before { + margin-right:5px; + } + } + + + + &[disabled]{ + color: mix($-color-white, #999, 60%); + &, + &[loading], + &:active { + color: mix($-color-white, #999, 60%); + background-color: mix($-color-white,$-color-black , 98%); + border-color: mix($-color-white, #999, 85%); + } + } + + &[plain] { + color: #999; + background: none; + border-color: $uni-border-1; + &:not([hover-class]):active { + background: none; + color: mix($-color-white, $-color-black, 80%); + border-color: mix($-color-white, $-color-black, 90%); + outline: none; + } + &[disabled]{ + &, + &[loading], + &:active { + background: none; + color: mix($-color-white, #999, 60%); + border-color: mix($-color-white, #999, 85%); + } + } + } + } + + &:not([hover-class]):active { + color: mix($-color-white, $-color-black, 50%); + } + + &[size=mini] { + font-size: 16px; + font-weight: 200; + border-radius: 8px; + } + + + + &.uni-btn-small { + font-size: 14px; + } + &.uni-btn-mini { + font-size: 12px; + } + + &.uni-btn-radius { + border-radius: 999px; + } + &[type=primary] { + @include is-color($uni-primary); + @include is-plain($uni-primary) + } + &[type=success] { + @include is-color($uni-success); + @include is-plain($uni-success) + } + &[type=error] { + @include is-color($uni-error); + @include is-plain($uni-error) + } + &[type=warning] { + @include is-color($uni-warning); + @include is-plain($uni-warning) + } + &[type=info] { + @include is-color($uni-info); + @include is-plain($uni-info) + } +} +/* #endif */ diff --git a/uni_modules/uni-scss/styles/setting/_text.scss b/uni_modules/uni-scss/styles/setting/_text.scss new file mode 100644 index 0000000..a34d08f --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_text.scss @@ -0,0 +1,24 @@ +@mixin get-styles($k,$c) { + @if $k == size or $k == weight{ + font-#{$k}:#{$c} + }@else{ + #{$k}:#{$c} + } +} + +@each $key, $child in $uni-headings { + /* #ifndef APP-NVUE */ + .uni-#{$key} { + @each $k, $c in $child { + @include get-styles($k,$c) + } + } + /* #endif */ + /* #ifdef APP-NVUE */ + .container .uni-#{$key} { + @each $k, $c in $child { + @include get-styles($k,$c) + } + } + /* #endif */ +} diff --git a/uni_modules/uni-scss/styles/setting/_variables.scss b/uni_modules/uni-scss/styles/setting/_variables.scss new file mode 100644 index 0000000..557d3d7 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_variables.scss @@ -0,0 +1,146 @@ +// @use "sass:math"; +@import '../tools/functions.scss'; +// 间距基础倍数 +$uni-space-root: 2 !default; +// 边框半径默认值 +$uni-radius-root:5px !default; +$uni-radius: () !default; +// 边框半径断点 +$uni-radius: map-deep-merge( + ( + 0: 0, + // TODO 当前版本暂时不支持 sm 属性 + // 'sm': math.div($uni-radius-root, 2), + null: $uni-radius-root, + 'lg': $uni-radius-root * 2, + 'xl': $uni-radius-root * 6, + 'pill': 9999px, + 'circle': 50% + ), + $uni-radius +); +// 字体家族 +$body-font-family: 'Roboto', sans-serif !default; +// 文本 +$heading-font-family: $body-font-family !default; +$uni-headings: () !default; +$letterSpacing: -0.01562em; +$uni-headings: map-deep-merge( + ( + 'h1': ( + size: 32px, + weight: 300, + line-height: 50px, + // letter-spacing:-0.01562em + ), + 'h2': ( + size: 28px, + weight: 300, + line-height: 40px, + // letter-spacing: -0.00833em + ), + 'h3': ( + size: 24px, + weight: 400, + line-height: 32px, + // letter-spacing: normal + ), + 'h4': ( + size: 20px, + weight: 400, + line-height: 30px, + // letter-spacing: 0.00735em + ), + 'h5': ( + size: 16px, + weight: 400, + line-height: 24px, + // letter-spacing: normal + ), + 'h6': ( + size: 14px, + weight: 500, + line-height: 18px, + // letter-spacing: 0.0125em + ), + 'subtitle': ( + size: 12px, + weight: 400, + line-height: 20px, + // letter-spacing: 0.00937em + ), + 'body': ( + font-size: 14px, + font-weight: 400, + line-height: 22px, + // letter-spacing: 0.03125em + ), + 'caption': ( + 'size': 12px, + 'weight': 400, + 'line-height': 20px, + // 'letter-spacing': 0.03333em, + // 'text-transform': false + ) + ), + $uni-headings +); + + + +// 主色 +$uni-primary: #2979ff !default; +$uni-primary-disable:lighten($uni-primary,20%) !default; +$uni-primary-light: lighten($uni-primary,25%) !default; + +// 辅助色 +// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。 +$uni-success: #18bc37 !default; +$uni-success-disable:lighten($uni-success,20%) !default; +$uni-success-light: lighten($uni-success,25%) !default; + +$uni-warning: #f3a73f !default; +$uni-warning-disable:lighten($uni-warning,20%) !default; +$uni-warning-light: lighten($uni-warning,25%) !default; + +$uni-error: #e43d33 !default; +$uni-error-disable:lighten($uni-error,20%) !default; +$uni-error-light: lighten($uni-error,25%) !default; + +$uni-info: #8f939c !default; +$uni-info-disable:lighten($uni-info,20%) !default; +$uni-info-light: lighten($uni-info,25%) !default; + +// 中性色 +// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。 +$uni-main-color: #3a3a3a !default; // 主要文字 +$uni-base-color: #6a6a6a !default; // 常规文字 +$uni-secondary-color: #909399 !default; // 次要文字 +$uni-extra-color: #c7c7c7 !default; // 辅助说明 + +// 边框颜色 +$uni-border-1: #F0F0F0 !default; +$uni-border-2: #EDEDED !default; +$uni-border-3: #DCDCDC !default; +$uni-border-4: #B9B9B9 !default; + +// 常规色 +$uni-black: #000000 !default; +$uni-white: #ffffff !default; +$uni-transparent: rgba($color: #000000, $alpha: 0) !default; + +// 背景色 +$uni-bg-color: #f7f7f7 !default; + +/* 水平间距 */ +$uni-spacing-sm: 8px !default; +$uni-spacing-base: 15px !default; +$uni-spacing-lg: 30px !default; + +// 阴影 +$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5) !default; +$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default; +$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5) !default; + +// 蒙版 +$uni-mask: rgba($color: #000000, $alpha: 0.4) !default; diff --git a/uni_modules/uni-scss/styles/tools/functions.scss b/uni_modules/uni-scss/styles/tools/functions.scss new file mode 100644 index 0000000..ac6f63e --- /dev/null +++ b/uni_modules/uni-scss/styles/tools/functions.scss @@ -0,0 +1,19 @@ +// 合并 map +@function map-deep-merge($parent-map, $child-map){ + $result: $parent-map; + @each $key, $child in $child-map { + $parent-has-key: map-has-key($result, $key); + $parent-value: map-get($result, $key); + $parent-type: type-of($parent-value); + $child-type: type-of($child); + $parent-is-map: $parent-type == map; + $child-is-map: $child-type == map; + + @if (not $parent-has-key) or ($parent-type != $child-type) or (not ($parent-is-map and $child-is-map)){ + $result: map-merge($result, ( $key: $child )); + }@else { + $result: map-merge($result, ( $key: map-deep-merge($parent-value, $child) )); + } + } + @return $result; +}; diff --git a/uni_modules/uni-scss/theme.scss b/uni_modules/uni-scss/theme.scss new file mode 100644 index 0000000..80ee62f --- /dev/null +++ b/uni_modules/uni-scss/theme.scss @@ -0,0 +1,31 @@ +// 间距基础倍数 +$uni-space-root: 2; +// 边框半径默认值 +$uni-radius-root:5px; +// 主色 +$uni-primary: #2979ff; +// 辅助色 +$uni-success: #4cd964; +// 警告色 +$uni-warning: #f0ad4e; +// 错误色 +$uni-error: #dd524d; +// 描述色 +$uni-info: #909399; +// 中性色 +$uni-main-color: #303133; +$uni-base-color: #606266; +$uni-secondary-color: #909399; +$uni-extra-color: #C0C4CC; +// 背景色 +$uni-bg-color: #f5f5f5; +// 边框颜色 +$uni-border-1: #DCDFE6; +$uni-border-2: #E4E7ED; +$uni-border-3: #EBEEF5; +$uni-border-4: #F2F6FC; + +// 常规色 +$uni-black: #000000; +$uni-white: #ffffff; +$uni-transparent: rgba($color: #000000, $alpha: 0); diff --git a/uni_modules/uni-scss/variables.scss b/uni_modules/uni-scss/variables.scss new file mode 100644 index 0000000..1c062d4 --- /dev/null +++ b/uni_modules/uni-scss/variables.scss @@ -0,0 +1,62 @@ +@import './styles/setting/_variables.scss'; +// 间距基础倍数 +$uni-space-root: 2; +// 边框半径默认值 +$uni-radius-root:5px; + +// 主色 +$uni-primary: #2979ff; +$uni-primary-disable:mix(#fff,$uni-primary,50%); +$uni-primary-light: mix(#fff,$uni-primary,80%); + +// 辅助色 +// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。 +$uni-success: #18bc37; +$uni-success-disable:mix(#fff,$uni-success,50%); +$uni-success-light: mix(#fff,$uni-success,80%); + +$uni-warning: #f3a73f; +$uni-warning-disable:mix(#fff,$uni-warning,50%); +$uni-warning-light: mix(#fff,$uni-warning,80%); + +$uni-error: #e43d33; +$uni-error-disable:mix(#fff,$uni-error,50%); +$uni-error-light: mix(#fff,$uni-error,80%); + +$uni-info: #8f939c; +$uni-info-disable:mix(#fff,$uni-info,50%); +$uni-info-light: mix(#fff,$uni-info,80%); + +// 中性色 +// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。 +$uni-main-color: #3a3a3a; // 主要文字 +$uni-base-color: #6a6a6a; // 常规文字 +$uni-secondary-color: #909399; // 次要文字 +$uni-extra-color: #c7c7c7; // 辅助说明 + +// 边框颜色 +$uni-border-1: #F0F0F0; +$uni-border-2: #EDEDED; +$uni-border-3: #DCDCDC; +$uni-border-4: #B9B9B9; + +// 常规色 +$uni-black: #000000; +$uni-white: #ffffff; +$uni-transparent: rgba($color: #000000, $alpha: 0); + +// 背景色 +$uni-bg-color: #f7f7f7; + +/* 水平间距 */ +$uni-spacing-sm: 8px; +$uni-spacing-base: 15px; +$uni-spacing-lg: 30px; + +// 阴影 +$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5); +$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2); +$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5); + +// 蒙版 +$uni-mask: rgba($color: #000000, $alpha: 0.4); diff --git a/uni_modules/uni-search-bar/changelog.md b/uni_modules/uni-search-bar/changelog.md new file mode 100644 index 0000000..a01fcf2 --- /dev/null +++ b/uni_modules/uni-search-bar/changelog.md @@ -0,0 +1,35 @@ +## 1.2.4(2023-05-09) +- 修复 i18n 国际化不正确的 Bug +## 1.2.3(2022-05-24) +- 新增 readonly 属性,组件只读 +## 1.2.2(2022-05-06) +- 修复 vue3 input 事件不生效的bug +## 1.2.1(2022-05-06) +- 修复 多余代码导致的bug +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-search-bar](https://uniapp.dcloud.io/component/uniui/uni-search-bar) +## 1.1.2(2021-08-30) +- 修复 value 属性与 modelValue 属性不兼容的Bug +## 1.1.1(2021-08-24) +- 新增 支持国际化 +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.9(2021-05-12) +- 新增 项目示例地址 +## 1.0.8(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 1.0.7(2021-04-15) +- uni-ui 新增 uni-search-bar 的 focus 事件 + +## 1.0.6(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.5(2021-02-05) +- 调整为uni_modules目录规范 +- 新增 支持双向绑定 +- 更改 input 事件的返回值,e={value:Number} --> e=value +- 新增 支持图标插槽 +- 新增 支持 clear、blur 事件 +- 新增 支持 focus 属性 +- 去掉组件背景色 diff --git a/uni_modules/uni-search-bar/components/uni-search-bar/i18n/en.json b/uni_modules/uni-search-bar/components/uni-search-bar/i18n/en.json new file mode 100644 index 0000000..dd083a5 --- /dev/null +++ b/uni_modules/uni-search-bar/components/uni-search-bar/i18n/en.json @@ -0,0 +1,4 @@ +{ + "uni-search-bar.cancel": "cancel", + "uni-search-bar.placeholder": "Search enter content" +} \ No newline at end of file diff --git a/uni_modules/uni-search-bar/components/uni-search-bar/i18n/index.js b/uni_modules/uni-search-bar/components/uni-search-bar/i18n/index.js new file mode 100644 index 0000000..de7509c --- /dev/null +++ b/uni_modules/uni-search-bar/components/uni-search-bar/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hans.json b/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hans.json new file mode 100644 index 0000000..d2a1ced --- /dev/null +++ b/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hans.json @@ -0,0 +1,4 @@ +{ + "uni-search-bar.cancel": "取消", + "uni-search-bar.placeholder": "请输入搜索内容" +} diff --git a/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hant.json b/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hant.json new file mode 100644 index 0000000..f1c96bc --- /dev/null +++ b/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hant.json @@ -0,0 +1,4 @@ +{ + "uni-search-bar.cancel": "取消", + "uni-search-bar.placeholder": "請輸入搜索內容" +} diff --git a/uni_modules/uni-search-bar/components/uni-search-bar/uni-search-bar.vue b/uni_modules/uni-search-bar/components/uni-search-bar/uni-search-bar.vue new file mode 100644 index 0000000..e0a7372 --- /dev/null +++ b/uni_modules/uni-search-bar/components/uni-search-bar/uni-search-bar.vue @@ -0,0 +1,298 @@ + + + + + diff --git a/uni_modules/uni-search-bar/package.json b/uni_modules/uni-search-bar/package.json new file mode 100644 index 0000000..ede02ef --- /dev/null +++ b/uni_modules/uni-search-bar/package.json @@ -0,0 +1,86 @@ +{ + "id": "uni-search-bar", + "displayName": "uni-search-bar 搜索栏", + "version": "1.2.4", + "description": "搜索栏组件,通常用于搜索商品、文章等", + "keywords": [ + "uni-ui", + "uniui", + "搜索框", + "搜索栏" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-search-bar/readme.md b/uni_modules/uni-search-bar/readme.md new file mode 100644 index 0000000..253092f --- /dev/null +++ b/uni_modules/uni-search-bar/readme.md @@ -0,0 +1,14 @@ + + +## SearchBar 搜索栏 + +> **组件名:uni-search-bar** +> 代码块: `uSearchBar` + + +搜索栏组件 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-search-bar) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-section/changelog.md b/uni_modules/uni-section/changelog.md new file mode 100644 index 0000000..738f2b3 --- /dev/null +++ b/uni_modules/uni-section/changelog.md @@ -0,0 +1,2 @@ +## 0.0.1(2022-07-22) +- 初始化 diff --git a/uni_modules/uni-section/components/uni-section/uni-section.vue b/uni_modules/uni-section/components/uni-section/uni-section.vue new file mode 100644 index 0000000..9a52e0b --- /dev/null +++ b/uni_modules/uni-section/components/uni-section/uni-section.vue @@ -0,0 +1,167 @@ + + + + diff --git a/uni_modules/uni-section/package.json b/uni_modules/uni-section/package.json new file mode 100644 index 0000000..0a31fb5 --- /dev/null +++ b/uni_modules/uni-section/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-section", + "displayName": "uni-section 标题栏", + "version": "0.0.1", + "description": "标题栏组件", + "keywords": [ + "uni-ui", + "uniui", + "标题栏" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": [ + "uni-scss" + ], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-section/readme.md b/uni_modules/uni-section/readme.md new file mode 100644 index 0000000..d47faab --- /dev/null +++ b/uni_modules/uni-section/readme.md @@ -0,0 +1,8 @@ +## Section 标题栏 +> **组件名:uni-section** +> 代码块: `uSection` + +uni-section 组件主要用于文章、列表详情等标题展示 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-section) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 diff --git a/uni_modules/uni-segmented-control/changelog.md b/uni_modules/uni-segmented-control/changelog.md new file mode 100644 index 0000000..a44385d --- /dev/null +++ b/uni_modules/uni-segmented-control/changelog.md @@ -0,0 +1,9 @@ +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-segmented-control](https://uniapp.dcloud.io/component/uniui/uni-segmented-control) +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.5(2021-05-12) +- 新增 项目示例地址 +## 1.0.4(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue b/uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue new file mode 100644 index 0000000..044a495 --- /dev/null +++ b/uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue @@ -0,0 +1,145 @@ + + + + + diff --git a/uni_modules/uni-segmented-control/package.json b/uni_modules/uni-segmented-control/package.json new file mode 100644 index 0000000..6cae41d --- /dev/null +++ b/uni_modules/uni-segmented-control/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-segmented-control", + "displayName": "uni-segmented-control 分段器", + "version": "1.2.0", + "description": "分段器由至少 2 个分段控件组成,用作不同视图的显示", + "keywords": [ + "uni-ui", + "uniui", + "分段器", + "segement", + "顶部选择" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-segmented-control/readme.md b/uni_modules/uni-segmented-control/readme.md new file mode 100644 index 0000000..3527b03 --- /dev/null +++ b/uni_modules/uni-segmented-control/readme.md @@ -0,0 +1,13 @@ + + +## SegmentedControl 分段器 +> **组件名:uni-segmented-control** +> 代码块: `uSegmentedControl` + + +用作不同视图的显示 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-segmented-control) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-share/changelog.md b/uni_modules/uni-share/changelog.md new file mode 100644 index 0000000..c858c67 --- /dev/null +++ b/uni_modules/uni-share/changelog.md @@ -0,0 +1,18 @@ +## 2.0.2(2021-12-16) +修复在某些情况下报:`Cannot read property 'hide' of undefined`的问题 +## 2.0.1(2021-11-29) +修改错误的scene值WXSenceTimeline(分享到朋友圈)更正为WXSceneTimeline +## 2.0.0(2021-10-14) +支持监听返回操作(如:物理返回,全面屏手机侧滑)关闭分享弹窗 +## 1.0.6(2021-08-25) +兼容vue3 +## 1.0.5(2021-08-05) +优化代码实现,修改原来用`eval()`函数实现的逻辑 +## 1.0.4(2021-06-07) +为符合苹果应用市场的审核,只显示存在对应的分享客户端的选项。如:配置包含微信分享,但是用户手机上并没有安装微信,就不显示微信分享。 +## 1.0.2(2021-05-06) +修复错误的提示:“打包时未添加oauth模块” +## 1.0.1(2021-04-30) +新增完整示例 +## 1.0.0(2021-04-28) +第1版发布 diff --git a/uni_modules/uni-share/js_sdk/uni-image-menu.js b/uni_modules/uni-share/js_sdk/uni-image-menu.js new file mode 100644 index 0000000..c03e51b --- /dev/null +++ b/uni_modules/uni-share/js_sdk/uni-image-menu.js @@ -0,0 +1,204 @@ +var nvMask, nvImageMenu; +class NvImageMenu { + constructor(arg) { + this.isShow = false + } + show({ + list, + cancelText + }, callback) { + if (!list) { + list = [{ + "img": "/static/sharemenu/wechatfriend.png", + "text": "图标文字" + }] + } + //以下为计算菜单的nview绘制布局,为固定算法,使用者无关关心 + var screenWidth = plus.screen.resolutionWidth + //以360px宽度屏幕为例,上下左右边距及2排按钮边距留25像素,图标宽度55像素,同行图标间的间距在360宽的屏幕是30px,但需要动态计算,以此原则计算4列图标分别的left位置 + //图标下的按钮文字距离图标5像素,文字大小12像素 + //底部取消按钮高度固定为44px + //TODO 未处理横屏和pad,这些情况6个图标应该一排即可 + var margin = 20, + iconWidth = 60, + icontextSpace = 5, + textHeight = 12 + var left1 = margin / 360 * screenWidth + var iconSpace = (screenWidth - (left1 * 2) - (iconWidth * 4)) / 3 //屏幕宽度减去左右留白间距,再减去4个图标的宽度,就是3个同行图标的间距 + if (iconSpace <= 5) { //屏幕过窄时,缩小边距和图标大小,再算一次 + margin = 15 + iconWidth = 40 + left1 = margin / 360 * screenWidth + iconSpace = (screenWidth - (left1 * 2) - (iconWidth * 4)) / 3 //屏幕宽度减去左右留白间距,再减去4个图标的宽度,就是3个同行图标的间距 + } + var left2 = left1 + iconWidth + iconSpace + var left3 = left1 + (iconWidth + iconSpace) * 2 + var left4 = left1 + (iconWidth + iconSpace) * 3 + var top1 = left1 + var top2 = top1 + iconWidth + icontextSpace + textHeight + left1 + + const TOP = { + top1, + top2 + }, + LEFT = { + left1, + left2, + left3, + left4 + }; + + nvMask = new plus.nativeObj.View("nvMask", { //先创建遮罩层 + top: '0px', + left: '0px', + height: '100%', + width: '100%', + backgroundColor: 'rgba(0,0,0,0.2)' + }); + nvImageMenu = new plus.nativeObj.View("nvImageMenu", { //创建底部图标菜单 + bottom: '0px', + left: '0px', + height: (iconWidth + textHeight + 2 * margin) * Math.ceil(list.length / 4) + 44 + + 'px', //'264px', + width: '100%', + backgroundColor: 'rgb(255,255,255)' + }); + nvMask.addEventListener("click", () => { //处理遮罩层点击 + // console.log('处理遮罩层点击'); + this.hide() + callback({ + event: "clickMask" + }) + }) + let myList = [] + list.forEach((item, i) => { + myList.push({ + tag: 'img', + src: item.img, + position: { + top: TOP['top' + (parseInt(i / 4) + 1)], + left: LEFT['left' + (1 + i % 4)], + width: iconWidth, + height: iconWidth + } + }) + myList.push({ + tag: 'font', + text: item.text, + textStyles: { + size: textHeight + }, + position: { + top: TOP['top' + (parseInt(i / 4) + 1)] + iconWidth + icontextSpace, + left: LEFT['left' + (1 + i % 4)], + width: iconWidth, + height: textHeight + } + }) + }) + + //绘制底部图标菜单的内容 + nvImageMenu.draw([{ + tag: 'rect', //菜单顶部的分割灰线 + color: '#e7e7e7', + position: { + top: '0px', + height: '1px' + } + }, + { + tag: 'font', + text: cancelText, //底部取消按钮的文字 + textStyles: { + size: '14px' + }, + position: { + bottom: '0px', + height: '44px' + } + }, + { + tag: 'rect', //底部取消按钮的顶部边线 + color: '#e7e7e7', + position: { + bottom: '45px', + height: '1px' + } + }, + ...myList + ]) + nvMask.show() + nvImageMenu.show() + // 开始动画 + /* + plus.nativeObj.View.startAnimation({ + type: 'slide-in-bottom', + duration: 300 + }, nvImageMenu, {}, function() { + console.log('plus.nativeObj.View.startAnimation动画结束'); + // 关闭原生动画 + plus.nativeObj.View.clearAnimation(); + nvImageMenu.show() + }); + */ + + + this.isShow = true + nvImageMenu.addEventListener("click", e => { //处理底部图标菜单的点击事件,根据点击位置触发不同的逻辑 + // console.log("click menu"+JSON.stringify(e)); + if (e.screenY > plus.screen.resolutionHeight - 44) { //点击了底部取消按钮 + // callback({event:"clickCancelButton"}) + this.hide() + } else if (e.clientX < 5 || e.clientX > screenWidth - 5 || e.clientY < 5) { + //屏幕左右边缘5像素及菜单顶部5像素不处理点击 + } else { //点击了图标按钮 + var iClickIndex = -1 //点击的图标按钮序号,第一个图标按钮的index为0 + var iRow = e.clientY < (top2 - (left1 / 2)) ? 0 : 1 + var iCol = -1 + if (e.clientX < (left2 - (iconSpace / 2))) { + iCol = 0 + } else if (e.clientX < (left3 - (iconSpace / 2))) { + iCol = 1 + } else if (e.clientX < (left4 - (iconSpace / 2))) { + iCol = 2 + } else { + iCol = 3 + } + if (iRow == 0) { + iClickIndex = iCol + } else { + iClickIndex = iCol + 4 + } + // console.log("点击按钮的序号: " + iClickIndex); + // if (iClickIndex >= 0 && iClickIndex <= 5) { //处理具体的点击逻辑,此处也可以自行定义逻辑。如果增减了按钮,此处也需要跟着修改 + // } + callback({ + event: "clickMenu", + index: iClickIndex + }) + } + }) + /* nvImageMenu.addEventListener("touchstart", function(e) { + if (e.screenY > (plus.screen.resolutionHeight - 44)) { + //TODO 这里可以处理按下背景变灰的效果 + } + }) + nvImageMenu.addEventListener("touchmove", function(e) { + //TODO 这里可以处理按下背景变灰的效果 + if (e.screenY > plus.screen.resolutionHeight - 44) {} + }) + nvImageMenu.addEventListener("touchend", function(e) { + //TODO 这里可以处理释放背景恢复的效果 + }) + */ + } + + hide() { + if (this.isShow) { + nvMask.hide() + nvImageMenu.hide() + this.isShow = false + } + } +} +export default NvImageMenu \ No newline at end of file diff --git a/uni_modules/uni-share/js_sdk/uni-share.js b/uni_modules/uni-share/js_sdk/uni-share.js new file mode 100644 index 0000000..8af8631 --- /dev/null +++ b/uni_modules/uni-share/js_sdk/uni-share.js @@ -0,0 +1,98 @@ +import UniImageMenu from './uni-image-menu.js'; +class UniShare extends UniImageMenu{ + constructor(arg) { + super() + this.isShow = super.isShow + } + async show(param, callback){ + var menus = [] + plus.share.getServices(services => { //只显示有服务的项目 + services = services.filter(item => item.nativeClient) + let servicesList = services.map(e => e.id) + param.menus.forEach(item => { + if (servicesList.includes(item.share.provider) || typeof(item.share) == 'string') { + menus.push(item) + } + }) + super.show({ + list: menus, + cancelText: param.cancelText + }, e => { + callback(e) + if(e.event == 'clickMenu'){ + if (typeof(menus[e.index]['share']) == 'string') { + this[menus[e.index]['share']](param) + } else { + uni.share({ + ...param.content, + ...menus[e.index].share, + success: res=> { + console.log("success:" + JSON.stringify(res)); + super.hide() + }, + fail: function(err) { + console.log("fail:" + JSON.stringify(err)); + uni.showModal({ + content: JSON.stringify(err), + showCancel: false, + confirmText: "知道了" + }); + } + }) + } + } + }) + }, err => { + uni.showModal({ + title: '获取服务供应商失败:' + JSON.stringify(err), + showCancel: false, + confirmText: '知道了' + }); + console.error('获取服务供应商失败:' + JSON.stringify(err)); + }) + } + hide(){ + super.hide() + } + copyurl(param) { + console.log('copyurl',param); + uni.setClipboardData({ + data: param.content.href, + success: ()=>{ + console.log('success'); + uni.hideToast() //关闭自带的toast + uni.showToast({ + title: '复制成功', + icon: 'none' + }); + super.hide(); + }, + fail: (err) => { + uni.showModal({ + content: JSON.stringify(err), + showCancel: false + }); + } + }); + } + // 使用系统分享发送分享消息 + shareSystem(param) { + console.log('shareSystem',param); + plus.share.sendWithSystem({ + type: 'text', + content: param.content.title + param.content.summary || '', + href: param.content.href, + }, (e)=> { + console.log('分享成功'); + super.hide() + }, (err)=> { + console.log('分享失败:' + JSON.stringify(err)); + uni.showModal({ + title: '获取服务供应商失败:' + JSON.stringify(err), + showCancel: false, + confirmText: '知道了' + }); + }); + } +} +export default UniShare \ No newline at end of file diff --git a/uni_modules/uni-share/package.json b/uni_modules/uni-share/package.json new file mode 100644 index 0000000..fa43a0e --- /dev/null +++ b/uni_modules/uni-share/package.json @@ -0,0 +1,80 @@ +{ + "id": "uni-share", + "displayName": "uni-share", + "version": "2.0.2", + "description": "底部弹出宫格图标式的分享菜单,可覆盖原生组件。", + "keywords": [ + "分享菜单" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "category": [ + "JS SDK", + "通用 SDK" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "H5-mobile": { + "Safari": "n", + "Android Browser": "n", + "微信浏览器(Android)": "n", + "QQ浏览器(Android)": "n" + }, + "H5-pc": { + "Chrome": "n", + "IE": "n", + "Edge": "n", + "Firefox": "n", + "Safari": "n" + }, + "小程序": { + "微信": "n", + "阿里": "n", + "百度": "n", + "字节跳动": "n", + "QQ": "n" + }, + "快应用": { + "华为": "n", + "联盟": "n" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-share/readme.md b/uni_modules/uni-share/readme.md new file mode 100644 index 0000000..dced6d6 --- /dev/null +++ b/uni_modules/uni-share/readme.md @@ -0,0 +1,95 @@ +#### 本功能基于[底部图标菜单](https://ext.dcloud.net.cn/plugin?id=4858)封装而成。 +### 示例代码 +``` + + + +``` \ No newline at end of file diff --git a/uni_modules/uni-sign-in/changelog.md b/uni_modules/uni-sign-in/changelog.md new file mode 100644 index 0000000..e44cc46 --- /dev/null +++ b/uni_modules/uni-sign-in/changelog.md @@ -0,0 +1,12 @@ +## 1.0.5(2021-12-09) +修复插件没自动安装依赖的`uni-popup`和`uni-icons`组件的问题 +## 1.0.4(2021-11-29) +修复在某些情况下,签到不连续7天,也获得60积分的问题 +## 1.0.3(2021-11-20) +新增支持看激励视频广告签到 +## 1.0.2(2021-08-25) +修复时区问题 +## 1.0.1(2021-08-23) +调整签到逻辑,支持查出积分的收入支出历史记录 +## 1.0.0(2021-08-05) +1.0.0版本发布 diff --git a/uni_modules/uni-sign-in/components/uni-sign-in/uni-sign-in.vue b/uni_modules/uni-sign-in/components/uni-sign-in/uni-sign-in.vue new file mode 100644 index 0000000..677ef9b --- /dev/null +++ b/uni_modules/uni-sign-in/components/uni-sign-in/uni-sign-in.vue @@ -0,0 +1,307 @@ + + + + + diff --git a/uni_modules/uni-sign-in/package.json b/uni_modules/uni-sign-in/package.json new file mode 100644 index 0000000..e951059 --- /dev/null +++ b/uni_modules/uni-sign-in/package.json @@ -0,0 +1,84 @@ +{ + "id": "uni-sign-in", + "displayName": "uni-starter签到插件 提升留存,激励视频变现", + "version": "1.0.5", + "description": "培养用户习惯,提升用户粘性,支持广告流量变现的签到得积分功能", + "keywords": [ + "uni-sign-in", + "签到", + "营销", + "变现", + "积分" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "category": [ + "uniCloud", + "云端一体页面模板" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": ["uni-popup","uni-icons"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "y", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "y", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-sign-in/pages/demo/demo.vue b/uni_modules/uni-sign-in/pages/demo/demo.vue new file mode 100644 index 0000000..1131d3c --- /dev/null +++ b/uni_modules/uni-sign-in/pages/demo/demo.vue @@ -0,0 +1,15 @@ + + \ No newline at end of file diff --git a/uni_modules/uni-sign-in/readme.md b/uni_modules/uni-sign-in/readme.md new file mode 100644 index 0000000..88dd9c2 --- /dev/null +++ b/uni_modules/uni-sign-in/readme.md @@ -0,0 +1,86 @@ +#### 简介:培养用户习惯,提升用户粘性,支持广告流量变现的签到得积分功能。 +#### 功能支持: +1. 每日签到奖励 (支持:普通签到、看广告签到) +2. 周期性连续7日签到,奖励翻倍 + +### 使用看广告签到功能必读 +1.`普通签到`是通过clientDb实现,如果你要使用`看广告签到`的方式, + 为了防止刷量需要修改`opendb-sign-in.schema`中`permission` -> `create` 的值设置为`false` + +> 文件路径 :`uni_modules/uni-sign-in/uniCloud/database/opendb-sign-in.schema.json` + +示例: + +```javascript +{ + "bsonType": "object", + "required": [], + "permission": { + "read": "auth.uid == doc.user_id", + "create": false, + "update": false, + "delete": false + } +} +``` + +2. 你需要看激励视频广告相关文档 +详情:[https://uniapp.dcloud.net.cn/api/a-d/rewarded-video](https://uniapp.dcloud.net.cn/api/a-d/rewarded-video) + +##### 使用方式 + +```js + + +``` + +> 详情参考[uni-starter](https://ext.dcloud.net.cn/plugin?id=5057) + + +##### 插件组成 +1. 前端组件 + + + +2. `DB Schema`表结构, + - 描述签到表字段及含义以及读写权限。 + - 路径:`/uniCloud/database/opendb-sign-in.schema.json` +> 更多表结构说明详情:[https://uniapp.dcloud.io/uniCloud/schema](https://uniapp.dcloud.io/uniCloud/schema) + +3. `uni-clientDB-actions` 一个可编程的 `clientDB` 前置后置操作 + - 前置操作,添加操作时检查今日是否未签到,否则拦截 + - 后置操作,判断是否已经连续签到7天,决定本次签到用户可得积分 + - 后置操作,输出本轮已签到几天,当前积分,已签到的日期数组,本轮签到可得多少分 +4. 两个api接口 + 普通签到`this.$refs.signIn.open()` + 看激励视频广告签到`this.$refs.signIn.showRewardedVideoAd()` + +#### 常见问题 +1. 是否支持配置积分数 + + 答:暂不支持,今后的版本有计划支持 + +2. 有没有更多玩法 + + 答:计划今后推出 + + (2.1)需要看广告才能签到 --- 已支持 + + (2.2)补签的玩法 \ No newline at end of file diff --git a/uni_modules/uni-sign-in/static/background.png b/uni_modules/uni-sign-in/static/background.png new file mode 100644 index 0000000000000000000000000000000000000000..c17b7ee15b8cadd798efbc1aa306a716ded4a06b GIT binary patch literal 30068 zcmd3Nby!sGz9=D~ga}BZgdjCc&oG2Yhkytw9Rmy@F#`-RAV_xz(gG?VDw5JMw1g6( zD5Z2rN(qRl>yF?4zJ2z&XYX_NeeV6^4$qort#|#p-&u=TLjx_AQ+%hWsHj+UwAGEM zsHm+ehYKSuWo03*Qi-zO>vG+cXsWL#Z;yAE#X8{aaIz$K0_8pxm7+3N+KpmeTY6m4d?8l9pHsC4luZGAK+?_aS&0yB&0}^rx0+*5wSuf zcQ+4jd6JUIA9Up@=f9W1B0_(F5M7l-RDLrQGSxQ}Qp0=Ugpjf*kUbP3CxphxLQx0^ z93>+JgFrE0h#VLS2SK3n5R^O;E%fI{gu>0s!BO5wUGq;~lq)3>XCjdx4+i`B`N{gh zW$|84U?>Jdp#cNKU?2(v$lKq8h$VqMyhZ<_ppNsl_i`Z+UGN@4zbRtv@IFK(5sIXL zQ^B3^cd{Pdf0~J6Ffa*A07GRVzg7AJ(82!ia0DMOw?CLW*n@FyICq=}(VGGb{W~nd z8BfG}JLCTa>A&CpPYfug)z|+!kAEtQyZhf+coQ{zDQf&_kbes8echjc0~_JI@jhPm zI1OKln4*7a<4rWe{f9mO4Ri|lAIJoGH7^{Ni1)gV$GiRIWy8Pp6;f0C!>d9P`dE7x zkKaa+{LS)DESx%)h*J`w_+1VJg@T}{>rj|HTuvT>k%mydA%6qa$2+(<`u_zA`yCu0 z80I=uP9BPsha>(IC?)6|uteH53$sLV;ki&_Bf0*O%Av@FrqC>~T8kN+J|p zWnEkx>~k@of=I08#?fg=J1!rD8+K#n*Z1_#B#F-WMx@5K2J&VNx+q3GvLal7}Q ziK&Wp`t!`qqBJ0Ka5)tiMqL#FRe`F&P!Kp;T@#}DUokLnmr{314s^Ij|SnO2pmWbhqMDhP%uY(IR_-l-U0Kkv0~(sfvWCX~?0V zFens?Qu`-<_)A|55@%=ch^B=-yc0|6Xu8EW#d(l|z7_7)l;N z?I=lrh1yfn3Qmb+I1YsA z0>{CyI1CI5qNs$SRC{|AC7+QxQLdjYX41FC2k%yw>q5sFK z{2rwKbIbjk5&j*G?C~DHIIn+*ECSXGOBv>HUfxO~j$U|oAuNI5=33hy4D>pu=GyNCy-a20}YRu^_+}tqHJ+~pZ>p~%0D)3K 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 EADV1ZBme*a literal 0 HcmV?d00001 diff --git a/uni_modules/uni-sign-in/uniCloud/cloudfunctions/common/sign-in/index.js b/uni_modules/uni-sign-in/uniCloud/cloudfunctions/common/sign-in/index.js new file mode 100644 index 0000000..1cd87bd --- /dev/null +++ b/uni_modules/uni-sign-in/uniCloud/cloudfunctions/common/sign-in/index.js @@ -0,0 +1,106 @@ +// 开发文档:https://uniapp.dcloud.io/uniCloud/clientdb?id=action +const db = uniCloud.database(); +const dbCmd = db.command +const signInTable = db.collection('opendb-sign-in'); +const scoresTable = db.collection('uni-id-scores'); +module.exports = async function({user_id,ip}) { + let date = todayTimestamp() + let { + total + } = await signInTable.where({ + user_id, + date, + isDelete: false + }).count() + console.log(total); + if (total) { + throw new Error("今天已经签到") + } + // state.newData.date = date + // state.newData.isDelete = false + + await signInTable.add({ + ip, + date, + user_id, + create_date:Date.now(), + isDelete:false, + }) + + + // after ------------------------- + //查最近7天的签到情况 + let { + data: signInData + } = await signInTable.where({ + user_id, + date: dbCmd.gte(date - 3600 * 24 * 6 * 1000), + isDelete: false + }).get() + + let allDate = signInData.map(item => item.date) + + //今天是本轮签到的第几天 + const n = (date - Math.min(...allDate)) / 3600 / 24 / 1000 + 1; + //换成数字--第几天 + let days = signInData.map(item => { + return (n * 10000 - (date - item.date) / 3600 / 24 / 1000 * 10000) / 10000 - 1 + }) + + //查出来用户当前有多少积分 + let { + data: [userScore] + } = await scoresTable + .where({ + user_id + }) + .orderBy("create_date", "desc") + .limit(1) + .get() + let balance = 0 + if (userScore) { + balance = userScore.balance + } + + if (n == 7) { //如果已经满一轮就软删除之前的内容 + let setIsDeleteRes = await signInTable.where({ + user_id, + date: dbCmd.neq(date) + }).update({ + isDelete: true + }) + console.log({ + setIsDeleteRes + }); + } + //给加积分 + let score = n+days.length==14?60:10 //如果连续签到7天就多加50分,也就是60分 + balance += score + let addScores = await scoresTable.add({ + user_id, + balance, + score, + type: 1, + create_date: Date.now() + }) + console.log({ + addScores + }); + return { + score: balance, + signInData, + n, + days + } +} + +function todayTimestamp() { + //时区 + let timeZone = new Date().getTimezoneOffset() / 60 + //获得相对于北京时间的时间戳 + let timestamp = Date.now() + 3600 * 1000 * (8 + timeZone) + //一天一共多少毫秒 + const D = 3600 * 24 * 1000 + //去掉余数,再减去东8区的8小时 得到当天凌晨的时间戳 + return parseInt(timestamp / D) * D - 3600 * 1000 * 8 +} diff --git a/uni_modules/uni-sign-in/uniCloud/cloudfunctions/common/sign-in/package.json b/uni_modules/uni-sign-in/uniCloud/cloudfunctions/common/sign-in/package.json new file mode 100644 index 0000000..7cdbf1d --- /dev/null +++ b/uni_modules/uni-sign-in/uniCloud/cloudfunctions/common/sign-in/package.json @@ -0,0 +1,12 @@ +{ + "name": "sign-in", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/uni_modules/uni-sign-in/uniCloud/cloudfunctions/rewarded-video-ad-notify-url/index.js b/uni_modules/uni-sign-in/uniCloud/cloudfunctions/rewarded-video-ad-notify-url/index.js new file mode 100644 index 0000000..969eef5 --- /dev/null +++ b/uni_modules/uni-sign-in/uniCloud/cloudfunctions/rewarded-video-ad-notify-url/index.js @@ -0,0 +1,64 @@ +'use strict'; +const uniADConfig = require('uni-config-center')({ + pluginId: 'uni-ad' +}).config() +const signIn = require('sign-in') +let ip = null +async function nextFn(data) { + //写自己的业务逻辑 + switch (data.extra) { + case "uniSignIn": //签到 + let { + user_id + } = data; + await signIn({ + user_id, + ip + }) + break; + default: + break; + } + return { + "isValid": true //如果不返回,广点通会2次调用本云函数 + } +} + +const crypto = require('crypto'); +const db = uniCloud.database(); +exports.main = async (event, context) => { + ip = context.CLIENTIP; + //event为客户端上传的参数 + console.log('event : ', event); + const { + path, + queryStringParameters + } = event; + const data = { + adpid: event.adpid, + platform: event.platform, + provider: event.provider, + trans_id: event.trans_id, + sign: event.sign, + user_id: event.user_id, + extra: event.extra, + } + // 注意::必须验签请求来源 + const trans_id = event.trans_id; + //去uni-config-center通过adpid获取secret + const secret = uniADConfig[event.adpid] + const sign2 = crypto.createHash('sha256').update(`${secret}:${trans_id}`).digest('hex'); + if (event.sign !== sign2) { + console.log('验签失败'); + return null; + } + //自己的逻辑 + try { + return await nextFn(data) + } catch (e) { + console.error(e) + return { + "isValid": false + } + } +}; \ No newline at end of file diff --git a/uni_modules/uni-sign-in/uniCloud/cloudfunctions/rewarded-video-ad-notify-url/package.json b/uni_modules/uni-sign-in/uniCloud/cloudfunctions/rewarded-video-ad-notify-url/package.json new file mode 100644 index 0000000..faa915a --- /dev/null +++ b/uni_modules/uni-sign-in/uniCloud/cloudfunctions/rewarded-video-ad-notify-url/package.json @@ -0,0 +1,15 @@ +{ + "name": "rewarded-video-ad-notify-url", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "sign-in": "file:../common/sign-in", + "uni-config-center": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } +} diff --git a/uni_modules/uni-sign-in/uniCloud/cloudfunctions/uni-clientDB-actions/signIn.js b/uni_modules/uni-sign-in/uniCloud/cloudfunctions/uni-clientDB-actions/signIn.js new file mode 100644 index 0000000..adf56bc --- /dev/null +++ b/uni_modules/uni-sign-in/uniCloud/cloudfunctions/uni-clientDB-actions/signIn.js @@ -0,0 +1,90 @@ +// 开发文档:https://uniapp.dcloud.io/uniCloud/clientdb?id=action +const db = uniCloud.database(); +const dbCmd = db.command +const signInTable = db.collection('opendb-sign-in'); +const scoresTable = db.collection('uni-id-scores'); +module.exports = { + before: async (state, event) => { + // console.log({state}); + if(state.type == 'create'){ + let date = todayTimestamp() + let {total} = await signInTable.where({ + user_id:state.auth.uid, + date, + isDelete:false + }).count() + console.log(total); + if(total){ + throw new Error("今天已经签到") + } + state.newData.date = date + state.newData.isDelete = false + } + }, + after: async (state, event, error, result) => { + if (error) { + throw error + } + let date = todayTimestamp() + //查最近7天的签到情况 + let {data:signInData} = await signInTable.where({ + user_id:state.auth.uid, + date:dbCmd.gte(date-3600*24*6*1000), + isDelete:false + }).get() + + let allDate = signInData.map(item=>item.date) + + //今天是本轮签到的第几天 + const n = ( date - Math.min(...allDate) )/3600/24/1000+1; + //换成数字--第几天 + let days = signInData.map(item=>{ + return (n*10000 - (date - item.date)/3600/24/1000*10000)/10000 -1 + }) + + //查出来用户当前有多少积分 + let {data: [userScore]} = await scoresTable + .where({user_id:state.auth.uid}) + .orderBy("create_date", "desc") + .limit(1) + .get() + let balance = 0 + if(userScore){ + balance = userScore.balance + } + + if(state.type == 'create'){ + if(n == 7){ //如果已经满一轮就软删除之前的内容 + let setIsDeleteRes = await signInTable.where({ + user_id:state.auth.uid, + date:dbCmd.neq(date) + }).update({isDelete:true}) + console.log({setIsDeleteRes}); + } + //给加积分 + let score = n+days.length==14?60:10 //如果连续签到7天就多加50分,也就是60分 + balance += score + let addScores = await scoresTable.add({ + user_id:state.auth.uid, + balance, + score, + type:1, + create_date:Date.now() + }) + console.log({addScores}); + } + return {...result,score:balance,signInData,n,days} + } +} + + +function todayTimestamp(){ + //时区 + let timeZone = new Date().getTimezoneOffset()/60 + //获得相对于北京时间的时间戳 + let timestamp = Date.now()+3600*1000*(8+timeZone) + //一天一共多少毫秒 + const D = 3600*24*1000 + //去掉余数,再减去东8区的8小时 得到当天凌晨的时间戳 + return parseInt(timestamp/D)*D - 3600*1000*8 +} \ No newline at end of file diff --git a/uni_modules/uni-sign-in/utils/ad.js b/uni_modules/uni-sign-in/utils/ad.js new file mode 100644 index 0000000..7a77ca5 --- /dev/null +++ b/uni_modules/uni-sign-in/utils/ad.js @@ -0,0 +1,253 @@ +// ad.js +const ADType = { + RewardedVideo: "RewardedVideo", + FullScreenVideo: "FullScreenVideo" +} + +class AdHelper { + + constructor() { + this._ads = {} + } + + load(options, onload, onerror) { + let ops = this._fixOldOptions(options) + let { + adpid + } = ops + + if (!adpid || this.isBusy(adpid)) { + return + } + + this.get(ops).load(onload, onerror) + } + + show(options, onsuccess, onfail) { + let ops = this._fixOldOptions(options) + let { + adpid + } = ops + + if (!adpid) { + return + } + + uni.showLoading({ + mask: true + }) + + var ad = this.get(ops) + + ad.load(() => { + uni.hideLoading() + ad.show((e) => { + onsuccess && onsuccess(e) + }) + }, (err) => { + uni.hideLoading() + onfail && onfail(err) + }) + } + + isBusy(adpid) { + return (this._ads[adpid] && this._ads[adpid].isLoading) + } + + get(options) { + const { + adpid, + singleton = true + } = options + if (singleton === false) { + if (this._ads[adpid]) { + this._ads[adpid].destroy() + delete this._ads[adpid] + } + } + delete options.singleton + if (!this._ads[adpid]) { + this._ads[adpid] = this._createAdInstance(options) + } + + return this._ads[adpid] + } + + _createAdInstance(options) { + const adType = options.adType || ADType.RewardedVideo + delete options.adType + + let ad = null; + if (adType === ADType.RewardedVideo) { + ad = new RewardedVideo(options) + } else if (adType === ADType.FullScreenVideo) { + ad = new FullScreenVideo(options) + } + + return ad + } + + _fixOldOptions(options) { + return (typeof options === "string") ? { + adpid: options + } : options + } +} + +const EXPIRED_TIME = 1000 * 60 * 30 +const ProviderType = { + CSJ: 'csj', + GDT: 'gdt' +} + +const RETRY_COUNT = 1 + +class AdBase { + constructor(adInstance, options = {}) { + this._isLoad = false + this._isLoading = false + this._lastLoadTime = 0 + this._lastError = null + this._retryCount = 0 + + this._loadCallback = null + this._closeCallback = null + this._errorCallback = null + + const ad = this._ad = adInstance + ad.onLoad((e) => { + this._isLoading = false + this._isLoad = true + this._lastLoadTime = Date.now() + + this.onLoad() + }) + ad.onClose((e) => { + this._isLoad = false + this.onClose(e) + }) + ad.onVerify && ad.onVerify((e) => { + // e.isValid + }) + ad.onError(({ + code, + message + }) => { + this._isLoading = false + const data = { + code: code, + errMsg: message + } + + if (code === -5008) { + this._loadAd() + return + } + + if (this._retryCount < RETRY_COUNT) { + this._retryCount += 1 + this._loadAd() + return + } + + this._lastError = data + this.onError(data) + }) + } + + get isExpired() { + return (this._lastLoadTime !== 0 && (Math.abs(Date.now() - this._lastLoadTime) > EXPIRED_TIME)) + } + + get isLoading() { + return this._isLoading + } + + getProvider() { + return this._ad.getProvider() + } + + load(onload, onerror) { + this._loadCallback = onload + this._errorCallback = onerror + + if (this._isLoading) { + return + } + + if (this._isLoad) { + this.onLoad() + return + } + + this._retryCount = 0 + + this._loadAd() + } + + show(onclose) { + this._closeCallback = onclose + + if (this._isLoading || !this._isLoad) { + return + } + + if (this._lastError !== null) { + this.onError(this._lastError) + return + } + + const provider = this.getProvider() + if (provider === ProviderType.CSJ && this.isExpired) { + this._loadAd() + return + } + + this._ad.show() + } + + onLoad(e) { + if (this._loadCallback != null) { + this._loadCallback() + } + } + + onClose(e) { + if (this._closeCallback != null) { + this._closeCallback({ + isEnded: e.isEnded + }) + } + } + + onError(e) { + if (this._errorCallback != null) { + this._errorCallback(e) + } + } + + destroy() { + this._ad.destroy() + } + + _loadAd() { + this._isLoad = false + this._isLoading = true + this._lastError = null + this._ad.load() + } +} + +class RewardedVideo extends AdBase { + constructor(options = {}) { + super(plus.ad.createRewardedVideoAd(options), options) + } +} + +class FullScreenVideo extends AdBase { + constructor(options = {}) { + super(plus.ad.createFullScreenVideoAd(options), options) + } +} + +export default new AdHelper() \ No newline at end of file diff --git a/uni_modules/uni-steps/changelog.md b/uni_modules/uni-steps/changelog.md new file mode 100644 index 0000000..cb9d367 --- /dev/null +++ b/uni_modules/uni-steps/changelog.md @@ -0,0 +1,16 @@ +## 1.1.1(2021-11-22) +- 修复 vue3中某些scss变量无法找到的问题 +## 1.1.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-steps](https://uniapp.dcloud.io/component/uniui/uni-steps) +## 1.0.8(2021-05-12) +- 新增 项目示例地址 +## 1.0.7(2021-05-06) +- 修复 uni-steps 横向布局时,多行文字高度不合理的 bug +## 1.0.6(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 1.0.5(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.4(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-steps/components/uni-steps/uni-steps.vue b/uni_modules/uni-steps/components/uni-steps/uni-steps.vue new file mode 100644 index 0000000..a6c8f28 --- /dev/null +++ b/uni_modules/uni-steps/components/uni-steps/uni-steps.vue @@ -0,0 +1,269 @@ + + + + + diff --git a/uni_modules/uni-steps/package.json b/uni_modules/uni-steps/package.json new file mode 100644 index 0000000..c687b40 --- /dev/null +++ b/uni_modules/uni-steps/package.json @@ -0,0 +1,89 @@ +{ + "id": "uni-steps", + "displayName": "uni-steps 步骤条", + "version": "1.1.1", + "description": "步骤条组件,提供横向和纵向两种布局格式。", + "keywords": [ + "uni-ui", + "uniui", + "步骤条", + "时间轴" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-icons" + ], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-steps/readme.md b/uni_modules/uni-steps/readme.md new file mode 100644 index 0000000..da7a4bf --- /dev/null +++ b/uni_modules/uni-steps/readme.md @@ -0,0 +1,13 @@ + + +## Steps 步骤条 +> **组件名:uni-steps** +> 代码块: `uSteps` + + +步骤条,常用于显示进度 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-steps) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-swipe-action/changelog.md b/uni_modules/uni-swipe-action/changelog.md new file mode 100644 index 0000000..c916427 --- /dev/null +++ b/uni_modules/uni-swipe-action/changelog.md @@ -0,0 +1,43 @@ +## 1.3.8(2023-04-13) +- 修复`uni-swipe-action`和`uni-swipe-action-item`不同时使用导致 closeOther 方法报错的 bug +## 1.3.7(2022-06-06) +- 修复 vue3 下使用组件不能正常运行的Bug +## 1.3.6(2022-05-31) +- 修复 h5端点击click触发两次的Bug +## 1.3.5(2022-05-23) +- 修复 isPC 找不到的Bug +## 1.3.4(2022-05-19) +- 修复 在 nvue 下 disabled 失效的bug +## 1.3.3(2022-03-31) +- 修复 按钮字体大小不能设置的bug +## 1.3.2(2022-03-16) +- 修复 h5和app端下报el错误的bug +## 1.3.1(2022-03-07) +- 修复 HBuilderX 1.4.X 版本中,h5和app端下报错的bug +## 1.3.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-swipe-action](https://uniapp.dcloud.io/component/uniui/uni-swipe-action) +## 1.2.4(2021-08-20) +- 优化 close-all 方法 +## 1.2.3(2021-08-20) +- 新增 close-all 方法,关闭所有已打开的组件 +## 1.2.2(2021-08-17) +- 新增 resize() 方法,在非微信小程序、h5、app-vue端出现不能滑动的问题的时候,重置组件 +- 修复 app 端偶尔出现类似 Page[x][-x,xx;-x,xx,x,x-x] 的问题 +- 优化 微信小程序、h5、app-vue 滑动逻辑,避免出现动态新增组件后不能滑动的问题 +## 1.2.1(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +- 修复 跨页面修改组件数据 ,导致不能滑动的问题 +## 1.1.10(2021-06-17) +- 修复 按钮点击执行两次的bug +## 1.1.9(2021-05-12) +- 新增 项目示例地址 +## 1.1.8(2021-03-26) +- 修复 微信小程序 nv_navigator is not defined 报错的bug +## 1.1.7(2021-02-05) +- 调整为uni_modules目录规范 +- 新增 左侧滑动 +- 新增 插槽使用方式 +- 新增 threshold 属性,可以控制滑动缺省值 +- 优化 长列表滚动性能 +- 修复 滚动页面时触发组件滑动的Bug diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/bindingx.js b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/bindingx.js new file mode 100644 index 0000000..707e432 --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/bindingx.js @@ -0,0 +1,302 @@ +let bindIngXMixins = {} + +// #ifdef APP-NVUE +const BindingX = uni.requireNativePlugin('bindingx'); +const dom = uni.requireNativePlugin('dom'); +const animation = uni.requireNativePlugin('animation'); + +bindIngXMixins = { + data() { + return {} + }, + + watch: { + show(newVal) { + if (this.autoClose) return + if (this.stop) return + this.stop = true + if (newVal) { + this.open(newVal) + } else { + this.close() + } + }, + leftOptions() { + this.getSelectorQuery() + this.init() + }, + rightOptions(newVal) { + this.init() + } + }, + created() { + this.swipeaction = this.getSwipeAction() + if (this.swipeaction && Array.isArray(this.swipeaction.children)) { + this.swipeaction.children.push(this) + } + }, + mounted() { + this.box = this.getEl(this.$refs['selector-box--hock']) + this.selector = this.getEl(this.$refs['selector-content--hock']); + this.leftButton = this.getEl(this.$refs['selector-left-button--hock']); + this.rightButton = this.getEl(this.$refs['selector-right-button--hock']); + this.init() + }, + // beforeDestroy() { + // this.swipeaction.children.forEach((item, index) => { + // if (item === this) { + // this.swipeaction.children.splice(index, 1) + // } + // }) + // }, + methods: { + init() { + this.$nextTick(() => { + this.x = 0 + this.button = { + show: false + } + setTimeout(() => { + this.getSelectorQuery() + }, 200) + }) + }, + onClick(index, item, position) { + this.$emit('click', { + content: item, + index, + position + }) + }, + touchstart(e) { + // fix by mehaotian 禁止滑动 + if (this.disabled) return + // 每次只触发一次,避免多次监听造成闪烁 + if (this.stop) return + this.stop = true + if (this.autoClose && this.swipeaction) { + this.swipeaction.closeOther(this) + } + + const leftWidth = this.button.left.width + const rightWidth = this.button.right.width + let expression = this.range(this.x, -rightWidth, leftWidth) + let leftExpression = this.range(this.x - leftWidth, -leftWidth, 0) + let rightExpression = this.range(this.x + rightWidth, 0, rightWidth) + + this.eventpan = BindingX.bind({ + anchor: this.box, + eventType: 'pan', + props: [{ + element: this.selector, + property: 'transform.translateX', + expression + }, { + element: this.leftButton, + property: 'transform.translateX', + expression: leftExpression + }, { + element: this.rightButton, + property: 'transform.translateX', + expression: rightExpression + }, ] + }, (e) => { + // nope + if (e.state === 'end') { + this.x = e.deltaX + this.x; + this.isclick = true + this.bindTiming(e.deltaX) + } + }); + }, + touchend(e) { + if (this.isopen !== 'none' && !this.isclick) { + this.open('none') + } + }, + bindTiming(x) { + const left = this.x + const leftWidth = this.button.left.width + const rightWidth = this.button.right.width + const threshold = this.threshold + if (!this.isopen || this.isopen === 'none') { + if (left > threshold) { + this.open('left') + } else if (left < -threshold) { + this.open('right') + } else { + this.open('none') + } + } else { + if ((x > -leftWidth && x < 0) || x > rightWidth) { + if ((x > -threshold && x < 0) || (x - rightWidth > threshold)) { + this.open('left') + } else { + this.open('none') + } + } else { + if ((x < threshold && x > 0) || (x + leftWidth < -threshold)) { + this.open('right') + } else { + this.open('none') + } + } + } + }, + + /** + * 移动范围 + * @param {Object} num + * @param {Object} mix + * @param {Object} max + */ + range(num, mix, max) { + return `min(max(x+${num}, ${mix}), ${max})` + }, + + /** + * 开启swipe + */ + open(type) { + this.animation(type) + }, + + /** + * 关闭swipe + */ + close() { + this.animation('none') + }, + + /** + * 开启关闭动画 + * @param {Object} type + */ + animation(type) { + const time = 300 + const leftWidth = this.button.left.width + const rightWidth = this.button.right.width + if (this.eventpan && this.eventpan.token) { + BindingX.unbind({ + token: this.eventpan.token, + eventType: 'pan' + }) + } + + switch (type) { + case 'left': + Promise.all([ + this.move(this.selector, leftWidth), + this.move(this.leftButton, 0), + this.move(this.rightButton, rightWidth * 2) + ]).then(() => { + this.setEmit(leftWidth, type) + }) + break + case 'right': + Promise.all([ + this.move(this.selector, -rightWidth), + this.move(this.leftButton, -leftWidth * 2), + this.move(this.rightButton, 0) + ]).then(() => { + this.setEmit(-rightWidth, type) + }) + break + default: + Promise.all([ + this.move(this.selector, 0), + this.move(this.leftButton, -leftWidth), + this.move(this.rightButton, rightWidth) + ]).then(() => { + this.setEmit(0, type) + }) + + } + }, + setEmit(x, type) { + const leftWidth = this.button.left.width + const rightWidth = this.button.right.width + this.isopen = this.isopen || 'none' + this.stop = false + this.isclick = false + // 只有状态不一致才会返回结果 + if (this.isopen !== type && this.x !== x) { + if (type === 'left' && leftWidth > 0) { + this.$emit('change', 'left') + } + if (type === 'right' && rightWidth > 0) { + this.$emit('change', 'right') + } + if (type === 'none') { + this.$emit('change', 'none') + } + } + this.x = x + this.isopen = type + }, + move(ref, value) { + return new Promise((resolve, reject) => { + animation.transition(ref, { + styles: { + transform: `translateX(${value})`, + }, + duration: 150, //ms + timingFunction: 'linear', + needLayout: false, + delay: 0 //ms + }, function(res) { + resolve(res) + }) + }) + + }, + + /** + * 获取ref + * @param {Object} el + */ + getEl(el) { + return el.ref + }, + /** + * 获取节点信息 + */ + getSelectorQuery() { + Promise.all([ + this.getDom('left'), + this.getDom('right'), + ]).then((data) => { + let show = 'none' + if (this.autoClose) { + show = 'none' + } else { + show = this.show + } + + if (show === 'none') { + // this.close() + } else { + this.open(show) + } + + }) + + }, + getDom(str) { + return new Promise((resolve, reject) => { + dom.getComponentRect(this.$refs[`selector-${str}-button--hock`], (data) => { + if (data) { + this.button[str] = data.size + resolve(data) + } else { + reject() + } + }) + }) + } + } +} + +// #endif + +export default bindIngXMixins diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/index.wxs b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/index.wxs new file mode 100644 index 0000000..10ddb56 --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/index.wxs @@ -0,0 +1,323 @@ +var MIN_DISTANCE = 10; + +/** + * 判断当前是否为H5、app-vue + */ +var IS_HTML5 = false +if (typeof window === 'object') IS_HTML5 = true + +/** + * 监听页面内值的变化,主要用于动态开关swipe-action + * @param {Object} newValue + * @param {Object} oldValue + * @param {Object} ownerInstance + * @param {Object} instance + */ +function sizeReady(newValue, oldValue, ownerInstance, instance) { + var state = instance.getState() + var buttonPositions = JSON.parse(newValue) + if (!buttonPositions || !buttonPositions.data || buttonPositions.data.length === 0) return + state.leftWidth = buttonPositions.data[0].width + state.rightWidth = buttonPositions.data[1].width + state.threshold = instance.getDataset().threshold + + if (buttonPositions.show && buttonPositions.show !== 'none') { + openState(buttonPositions.show, instance, ownerInstance) + return + } + + if (state.left) { + openState('none', instance, ownerInstance) + } + resetTouchStatus(instance) +} + +/** + * 开始触摸操作 + * @param {Object} e + * @param {Object} ins + */ +function touchstart(e, ins) { + var instance = e.instance; + var disabled = instance.getDataset().disabled + var state = instance.getState(); + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false; + if (disabled) return + // 开始触摸时移除动画类 + instance.requestAnimationFrame(function() { + instance.removeClass('ani'); + ins.callMethod('closeSwipe'); + }) + + // 记录上次的位置 + state.x = state.left || 0 + // 计算滑动开始位置 + stopTouchStart(e, ins) +} + +/** + * 开始滑动操作 + * @param {Object} e + * @param {Object} ownerInstance + */ +function touchmove(e, ownerInstance) { + var instance = e.instance; + var disabled = instance.getDataset().disabled + var state = instance.getState() + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false; + if (disabled) return + // 是否可以滑动页面 + stopTouchMove(e); + if (state.direction !== 'horizontal') { + return; + } + + if (e.preventDefault) { + // 阻止页面滚动 + e.preventDefault() + } + + move(state.x + state.deltaX, instance, ownerInstance) +} + +/** + * 结束触摸操作 + * @param {Object} e + * @param {Object} ownerInstance + */ +function touchend(e, ownerInstance) { + var instance = e.instance; + var disabled = instance.getDataset().disabled + var state = instance.getState() + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false; + + if (disabled) return + // 滑动过程中触摸结束,通过阙值判断是开启还是关闭 + // fixed by mehaotian 定时器解决点击按钮,touchend 触发比 click 事件时机早的问题 ,主要是 ios13 + moveDirection(state.left, instance, ownerInstance) + +} + +/** + * 设置移动距离 + * @param {Object} value + * @param {Object} instance + * @param {Object} ownerInstance + */ +function move(value, instance, ownerInstance) { + value = value || 0 + var state = instance.getState() + var leftWidth = state.leftWidth + var rightWidth = state.rightWidth + // 获取可滑动范围 + state.left = range(value, -rightWidth, leftWidth); + instance.requestAnimationFrame(function() { + instance.setStyle({ + transform: 'translateX(' + state.left + 'px)', + '-webkit-transform': 'translateX(' + state.left + 'px)' + }) + }) + +} + +/** + * 获取范围 + * @param {Object} num + * @param {Object} min + * @param {Object} max + */ +function range(num, min, max) { + return Math.min(Math.max(num, min), max); +} + + +/** + * 移动方向判断 + * @param {Object} left + * @param {Object} value + * @param {Object} ownerInstance + * @param {Object} ins + */ +function moveDirection(left, ins, ownerInstance) { + var state = ins.getState() + var threshold = state.threshold + var position = state.position + var isopen = state.isopen || 'none' + var leftWidth = state.leftWidth + var rightWidth = state.rightWidth + if (state.deltaX === 0) { + openState('none', ins, ownerInstance) + return + } + if ((isopen === 'none' && rightWidth > 0 && -left > threshold) || (isopen !== 'none' && rightWidth > 0 && + rightWidth + + left < threshold)) { + // right + openState('right', ins, ownerInstance) + } else if ((isopen === 'none' && leftWidth > 0 && left > threshold) || (isopen !== 'none' && leftWidth > 0 && + leftWidth - left < threshold)) { + // left + openState('left', ins, ownerInstance) + } else { + // default + openState('none', ins, ownerInstance) + } +} + + +/** + * 开启状态 + * @param {Boolean} type + * @param {Object} ins + * @param {Object} ownerInstance + */ +function openState(type, ins, ownerInstance) { + var state = ins.getState() + var position = state.position + var leftWidth = state.leftWidth + var rightWidth = state.rightWidth + var left = '' + state.isopen = state.isopen ? state.isopen : 'none' + switch (type) { + case "left": + left = leftWidth + break + case "right": + left = -rightWidth + break + default: + left = 0 + } + + // && !state.throttle + + if (state.isopen !== type) { + state.throttle = true + ownerInstance.callMethod('change', { + open: type + }) + + } + + state.isopen = type + // 添加动画类 + ins.requestAnimationFrame(function() { + ins.addClass('ani'); + move(left, ins, ownerInstance) + }) + // 设置最终移动位置,理论上只要进入到这个函数,肯定是要打开的 +} + + +function getDirection(x, y) { + if (x > y && x > MIN_DISTANCE) { + return 'horizontal'; + } + if (y > x && y > MIN_DISTANCE) { + return 'vertical'; + } + return ''; +} + +/** + * 重置滑动状态 + * @param {Object} event + */ +function resetTouchStatus(instance) { + var state = instance.getState(); + state.direction = ''; + state.deltaX = 0; + state.deltaY = 0; + state.offsetX = 0; + state.offsetY = 0; +} + +/** + * 设置滑动开始位置 + * @param {Object} event + */ +function stopTouchStart(event) { + var instance = event.instance; + var state = instance.getState(); + resetTouchStatus(instance); + var touch = event.touches[0]; + if (IS_HTML5 && isPC()) { + touch = event; + } + state.startX = touch.clientX; + state.startY = touch.clientY; +} + +/** + * 滑动中,是否禁止打开 + * @param {Object} event + */ +function stopTouchMove(event) { + var instance = event.instance; + var state = instance.getState(); + var touch = event.touches[0]; + if (IS_HTML5 && isPC()) { + touch = event; + } + state.deltaX = touch.clientX - state.startX; + state.deltaY = touch.clientY - state.startY; + state.offsetY = Math.abs(state.deltaY); + state.offsetX = Math.abs(state.deltaX); + state.direction = state.direction || getDirection(state.offsetX, state.offsetY); +} + +function isPC() { + var userAgentInfo = navigator.userAgent; + var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"]; + var flag = true; + for (var v = 0; v < Agents.length - 1; v++) { + if (userAgentInfo.indexOf(Agents[v]) > 0) { + flag = false; + break; + } + } + return flag; +} + +var movable = false + +function mousedown(e, ins) { + if (!IS_HTML5) return + if (!isPC()) return + touchstart(e, ins) + movable = true +} + +function mousemove(e, ins) { + if (!IS_HTML5) return + if (!isPC()) return + if (!movable) return + touchmove(e, ins) +} + +function mouseup(e, ins) { + if (!IS_HTML5) return + if (!isPC()) return + touchend(e, ins) + movable = false +} + +function mouseleave(e, ins) { + if (!IS_HTML5) return + if (!isPC()) return + movable = false +} + +module.exports = { + sizeReady: sizeReady, + touchstart: touchstart, + touchmove: touchmove, + touchend: touchend, + mousedown: mousedown, + mousemove: mousemove, + mouseup: mouseup, + mouseleave: mouseleave +} diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/isPC.js b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/isPC.js new file mode 100644 index 0000000..917cb48 --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/isPC.js @@ -0,0 +1,12 @@ +export function isPC() { + var userAgentInfo = navigator.userAgent; + var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"]; + var flag = true; + for (let v = 0; v < Agents.length - 1; v++) { + if (userAgentInfo.indexOf(Agents[v]) > 0) { + flag = false; + break; + } + } + return flag; +} diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js new file mode 100644 index 0000000..35c796b --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js @@ -0,0 +1,195 @@ +export default { + data() { + return { + x: 0, + transition: false, + width: 0, + viewWidth: 0, + swipeShow: 0 + } + }, + watch: { + show(newVal) { + if (this.autoClose) return + if (newVal && newVal !== 'none') { + this.transition = true + this.open(newVal) + } else { + this.close() + } + } + }, + created() { + this.swipeaction = this.getSwipeAction() + if (this.swipeaction && Array.isArray(this.swipeaction.children)) { + this.swipeaction.children.push(this) + } + }, + mounted() { + this.isopen = false + setTimeout(() => { + this.getQuerySelect() + }, 50) + }, + methods: { + appTouchStart(e) { + const { + clientX + } = e.changedTouches[0] + this.clientX = clientX + this.timestamp = new Date().getTime() + }, + appTouchEnd(e, index, item, position) { + const { + clientX + } = e.changedTouches[0] + // fixed by xxxx 模拟点击事件,解决 ios 13 点击区域错位的问题 + let diff = Math.abs(this.clientX - clientX) + let time = (new Date().getTime()) - this.timestamp + if (diff < 40 && time < 300) { + this.$emit('click', { + content: item, + index, + position + }) + } + }, + /** + * 移动触发 + * @param {Object} e + */ + onChange(e) { + this.moveX = e.detail.x + this.isclose = false + }, + touchstart(e) { + this.transition = false + this.isclose = true + if (this.autoClose && this.swipeaction) { + this.swipeaction.closeOther(this) + } + }, + touchmove(e) {}, + touchend(e) { + // 0的位置什么都不执行 + if (this.isclose && this.isopen === 'none') return + if (this.isclose && this.isopen !== 'none') { + this.transition = true + this.close() + } else { + this.move(this.moveX + this.leftWidth) + } + }, + + /** + * 移动 + * @param {Object} moveX + */ + move(moveX) { + // 打开关闭的处理逻辑不太一样 + this.transition = true + // 未打开状态 + if (!this.isopen || this.isopen === 'none') { + if (moveX > this.threshold) { + this.open('left') + } else if (moveX < -this.threshold) { + this.open('right') + } else { + this.close() + } + } else { + if (moveX < 0 && moveX < this.rightWidth) { + const rightX = this.rightWidth + moveX + if (rightX < this.threshold) { + this.open('right') + } else { + this.close() + } + } else if (moveX > 0 && moveX < this.leftWidth) { + const leftX = this.leftWidth - moveX + if (leftX < this.threshold) { + this.open('left') + } else { + this.close() + } + } + + } + + }, + + /** + * 打开 + */ + open(type) { + this.x = this.moveX + this.animation(type) + }, + + /** + * 关闭 + */ + close() { + this.x = this.moveX + // TODO 解决 x 值不更新的问题,所以会多触发一次 nextTick ,待优化 + this.$nextTick(() => { + this.x = -this.leftWidth + if (this.isopen !== 'none') { + this.$emit('change', 'none') + } + this.isopen = 'none' + }) + }, + + /** + * 执行结束动画 + * @param {Object} type + */ + animation(type) { + this.$nextTick(() => { + if (type === 'left') { + this.x = 0 + } else { + this.x = -this.rightWidth - this.leftWidth + } + + if (this.isopen !== type) { + this.$emit('change', type) + } + this.isopen = type + }) + + }, + getSlide(x) {}, + getQuerySelect() { + const query = uni.createSelectorQuery().in(this); + query.selectAll('.movable-view--hock').boundingClientRect(data => { + this.leftWidth = data[1].width + this.rightWidth = data[2].width + this.width = data[0].width + this.viewWidth = this.width + this.rightWidth + this.leftWidth + if (this.leftWidth === 0) { + // TODO 疑似bug ,初始化的时候如果x 是0,会导致移动位置错误,所以让元素超出一点 + this.x = -0.1 + } else { + this.x = -this.leftWidth + } + this.moveX = this.x + this.$nextTick(() => { + this.swipeShow = 1 + }) + + if (!this.buttonWidth) { + this.disabledView = true + } + + if (this.autoClose) return + if (this.show !== 'none') { + this.transition = true + this.open(this.shows) + } + }).exec(); + + } + } +} diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js new file mode 100644 index 0000000..d389bce --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js @@ -0,0 +1,260 @@ +let otherMixins = {} + +// #ifndef APP-PLUS|| MP-WEIXIN || H5 +const MIN_DISTANCE = 10; +otherMixins = { + data() { + // TODO 随机生生元素ID,解决百度小程序获取同一个元素位置信息的bug + const elClass = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}` + return { + uniShow: false, + left: 0, + buttonShow: 'none', + ani: false, + moveLeft: '', + elClass + } + }, + watch: { + show(newVal) { + if (this.autoClose) return + this.openState(newVal) + }, + left() { + this.moveLeft = `translateX(${this.left}px)` + }, + buttonShow(newVal) { + if (this.autoClose) return + this.openState(newVal) + }, + leftOptions() { + this.init() + }, + rightOptions() { + this.init() + } + }, + mounted() { + this.swipeaction = this.getSwipeAction() + if (this.swipeaction && Array.isArray(this.swipeaction.children)) { + this.swipeaction.children.push(this) + } + this.init() + }, + methods: { + init() { + clearTimeout(this.timer) + this.timer = setTimeout(() => { + this.getSelectorQuery() + }, 100) + // 移动距离 + this.left = 0 + this.x = 0 + }, + + closeSwipe(e) { + if (this.autoClose && this.swipeaction) { + this.swipeaction.closeOther(this) + } + }, + appTouchStart(e) { + const { + clientX + } = e.changedTouches[0] + this.clientX = clientX + this.timestamp = new Date().getTime() + }, + appTouchEnd(e, index, item, position) { + const { + clientX + } = e.changedTouches[0] + // fixed by xxxx 模拟点击事件,解决 ios 13 点击区域错位的问题 + let diff = Math.abs(this.clientX - clientX) + let time = (new Date().getTime()) - this.timestamp + if (diff < 40 && time < 300) { + this.$emit('click', { + content: item, + index, + position + }) + } + }, + touchstart(e) { + if (this.disabled) return + this.ani = false + this.x = this.left || 0 + this.stopTouchStart(e) + this.autoClose && this.closeSwipe() + }, + touchmove(e) { + if (this.disabled) return + // 是否可以滑动页面 + this.stopTouchMove(e); + if (this.direction !== 'horizontal') { + return; + } + this.move(this.x + this.deltaX) + return false + }, + touchend() { + if (this.disabled) return + this.moveDirection(this.left) + }, + /** + * 设置移动距离 + * @param {Object} value + */ + move(value) { + value = value || 0 + const leftWidth = this.leftWidth + const rightWidth = this.rightWidth + // 获取可滑动范围 + this.left = this.range(value, -rightWidth, leftWidth); + }, + + /** + * 获取范围 + * @param {Object} num + * @param {Object} min + * @param {Object} max + */ + range(num, min, max) { + return Math.min(Math.max(num, min), max); + }, + /** + * 移动方向判断 + * @param {Object} left + * @param {Object} value + */ + moveDirection(left) { + const threshold = this.threshold + const isopen = this.isopen || 'none' + const leftWidth = this.leftWidth + const rightWidth = this.rightWidth + if (this.deltaX === 0) { + this.openState('none') + return + } + if ((isopen === 'none' && rightWidth > 0 && -left > threshold) || (isopen !== 'none' && rightWidth > + 0 && rightWidth + + left < threshold)) { + // right + this.openState('right') + } else if ((isopen === 'none' && leftWidth > 0 && left > threshold) || (isopen !== 'none' && leftWidth > + 0 && + leftWidth - left < threshold)) { + // left + this.openState('left') + } else { + // default + this.openState('none') + } + }, + + /** + * 开启状态 + * @param {Boolean} type + */ + openState(type) { + const leftWidth = this.leftWidth + const rightWidth = this.rightWidth + let left = '' + this.isopen = this.isopen ? this.isopen : 'none' + switch (type) { + case "left": + left = leftWidth + break + case "right": + left = -rightWidth + break + default: + left = 0 + } + + + if (this.isopen !== type) { + this.throttle = true + this.$emit('change', type) + } + + this.isopen = type + // 添加动画类 + this.ani = true + this.$nextTick(() => { + this.move(left) + }) + // 设置最终移动位置,理论上只要进入到这个函数,肯定是要打开的 + }, + close() { + this.openState('none') + }, + getDirection(x, y) { + if (x > y && x > MIN_DISTANCE) { + return 'horizontal'; + } + if (y > x && y > MIN_DISTANCE) { + return 'vertical'; + } + return ''; + }, + + /** + * 重置滑动状态 + * @param {Object} event + */ + resetTouchStatus() { + this.direction = ''; + this.deltaX = 0; + this.deltaY = 0; + this.offsetX = 0; + this.offsetY = 0; + }, + + /** + * 设置滑动开始位置 + * @param {Object} event + */ + stopTouchStart(event) { + this.resetTouchStatus(); + const touch = event.touches[0]; + this.startX = touch.clientX; + this.startY = touch.clientY; + }, + + /** + * 滑动中,是否禁止打开 + * @param {Object} event + */ + stopTouchMove(event) { + const touch = event.touches[0]; + this.deltaX = touch.clientX - this.startX; + this.deltaY = touch.clientY - this.startY; + this.offsetX = Math.abs(this.deltaX); + this.offsetY = Math.abs(this.deltaY); + this.direction = this.direction || this.getDirection(this.offsetX, this.offsetY); + }, + + getSelectorQuery() { + const views = uni.createSelectorQuery().in(this) + views + .selectAll('.' + this.elClass) + .boundingClientRect(data => { + if (data.length === 0) return + let show = 'none' + if (this.autoClose) { + show = 'none' + } else { + show = this.show + } + this.leftWidth = data[0].width || 0 + this.rightWidth = data[1].width || 0 + this.buttonShow = show + }) + .exec() + } + } +} + +// #endif + +export default otherMixins diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js new file mode 100644 index 0000000..08de1c9 --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js @@ -0,0 +1,84 @@ +let mpMixins = {} +let is_pc = null +// #ifdef H5 +import { + isPC +} from "./isPC" +is_pc = isPC() +// #endif +// #ifdef APP-VUE|| MP-WEIXIN || H5 + +mpMixins = { + data() { + return { + is_show: 'none' + } + }, + watch: { + show(newVal) { + this.is_show = this.show + } + }, + created() { + this.swipeaction = this.getSwipeAction() + if (this.swipeaction && Array.isArray(this.swipeaction.children)) { + this.swipeaction.children.push(this) + } + }, + mounted() { + this.is_show = this.show + }, + methods: { + // wxs 中调用 + closeSwipe(e) { + if (this.autoClose && this.swipeaction) { + this.swipeaction.closeOther(this) + } + }, + + change(e) { + this.$emit('change', e.open) + if (this.is_show !== e.open) { + this.is_show = e.open + } + }, + + appTouchStart(e) { + if (is_pc) return + const { + clientX + } = e.changedTouches[0] + this.clientX = clientX + this.timestamp = new Date().getTime() + }, + appTouchEnd(e, index, item, position) { + if (is_pc) return + const { + clientX + } = e.changedTouches[0] + // fixed by xxxx 模拟点击事件,解决 ios 13 点击区域错位的问题 + let diff = Math.abs(this.clientX - clientX) + let time = (new Date().getTime()) - this.timestamp + if (diff < 40 && time < 300) { + this.$emit('click', { + content: item, + index, + position + }) + } + }, + onClickForPC(index, item, position) { + if (!is_pc) return + // #ifdef H5 + this.$emit('click', { + content: item, + index, + position + }) + // #endif + } + } +} + +// #endif +export default mpMixins diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/render.js b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/render.js new file mode 100644 index 0000000..78f0ec6 --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/render.js @@ -0,0 +1,270 @@ +const MIN_DISTANCE = 10; +export default { + showWatch(newVal, oldVal, ownerInstance, instance, self) { + var state = self.state + var $el = ownerInstance.$el || ownerInstance.$vm && ownerInstance.$vm.$el + if (!$el) return + this.getDom(instance, ownerInstance, self) + if (newVal && newVal !== 'none') { + this.openState(newVal, instance, ownerInstance, self) + return + } + + if (state.left) { + this.openState('none', instance, ownerInstance, self) + } + this.resetTouchStatus(instance, self) + }, + + /** + * 开始触摸操作 + * @param {Object} e + * @param {Object} ins + */ + touchstart(e, ownerInstance, self) { + let instance = e.instance; + let disabled = instance.getDataset().disabled + let state = self.state; + this.getDom(instance, ownerInstance, self) + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = this.getDisabledType(disabled) + if (disabled) return + // 开始触摸时移除动画类 + instance.requestAnimationFrame(function() { + instance.removeClass('ani'); + ownerInstance.callMethod('closeSwipe'); + }) + + // 记录上次的位置 + state.x = state.left || 0 + // 计算滑动开始位置 + this.stopTouchStart(e, ownerInstance, self) + }, + + /** + * 开始滑动操作 + * @param {Object} e + * @param {Object} ownerInstance + */ + touchmove(e, ownerInstance, self) { + let instance = e.instance; + // 删除之后已经那不到实例了 + if (!instance) return; + let disabled = instance.getDataset().disabled + let state = self.state + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = this.getDisabledType(disabled) + if (disabled) return + // 是否可以滑动页面 + this.stopTouchMove(e, self); + if (state.direction !== 'horizontal') { + return; + } + if (e.preventDefault) { + // 阻止页面滚动 + e.preventDefault() + } + let x = state.x + state.deltaX + this.move(x, instance, ownerInstance, self) + }, + + /** + * 结束触摸操作 + * @param {Object} e + * @param {Object} ownerInstance + */ + touchend(e, ownerInstance, self) { + let instance = e.instance; + let disabled = instance.getDataset().disabled + let state = self.state + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = this.getDisabledType(disabled) + + if (disabled) return + // 滑动过程中触摸结束,通过阙值判断是开启还是关闭 + // fixed by mehaotian 定时器解决点击按钮,touchend 触发比 click 事件时机早的问题 ,主要是 ios13 + this.moveDirection(state.left, instance, ownerInstance, self) + + }, + + /** + * 设置移动距离 + * @param {Object} value + * @param {Object} instance + * @param {Object} ownerInstance + */ + move(value, instance, ownerInstance, self) { + value = value || 0 + let state = self.state + let leftWidth = state.leftWidth + let rightWidth = state.rightWidth + // 获取可滑动范围 + state.left = this.range(value, -rightWidth, leftWidth); + instance.requestAnimationFrame(function() { + instance.setStyle({ + transform: 'translateX(' + state.left + 'px)', + '-webkit-transform': 'translateX(' + state.left + 'px)' + }) + }) + + }, + + /** + * 获取元素信息 + * @param {Object} instance + * @param {Object} ownerInstance + */ + getDom(instance, ownerInstance, self) { + var state = self.state + var $el = ownerInstance.$el || ownerInstance.$vm && ownerInstance.$vm.$el + var leftDom = $el.querySelector('.button-group--left') + var rightDom = $el.querySelector('.button-group--right') + + state.leftWidth = leftDom.offsetWidth || 0 + state.rightWidth = rightDom.offsetWidth || 0 + state.threshold = instance.getDataset().threshold + }, + + getDisabledType(value) { + return (typeof(value) === 'string' ? JSON.parse(value) : value) || false; + }, + + /** + * 获取范围 + * @param {Object} num + * @param {Object} min + * @param {Object} max + */ + range(num, min, max) { + return Math.min(Math.max(num, min), max); + }, + + + /** + * 移动方向判断 + * @param {Object} left + * @param {Object} value + * @param {Object} ownerInstance + * @param {Object} ins + */ + moveDirection(left, ins, ownerInstance, self) { + var state = self.state + var threshold = state.threshold + var position = state.position + var isopen = state.isopen || 'none' + var leftWidth = state.leftWidth + var rightWidth = state.rightWidth + if (state.deltaX === 0) { + this.openState('none', ins, ownerInstance, self) + return + } + if ((isopen === 'none' && rightWidth > 0 && -left > threshold) || (isopen !== 'none' && rightWidth > 0 && + rightWidth + + left < threshold)) { + // right + this.openState('right', ins, ownerInstance, self) + } else if ((isopen === 'none' && leftWidth > 0 && left > threshold) || (isopen !== 'none' && leftWidth > 0 && + leftWidth - left < threshold)) { + // left + this.openState('left', ins, ownerInstance, self) + } else { + // default + this.openState('none', ins, ownerInstance, self) + } + }, + + + /** + * 开启状态 + * @param {Boolean} type + * @param {Object} ins + * @param {Object} ownerInstance + */ + openState(type, ins, ownerInstance, self) { + let state = self.state + let leftWidth = state.leftWidth + let rightWidth = state.rightWidth + let left = '' + state.isopen = state.isopen ? state.isopen : 'none' + switch (type) { + case "left": + left = leftWidth + break + case "right": + left = -rightWidth + break + default: + left = 0 + } + + // && !state.throttle + + if (state.isopen !== type) { + state.throttle = true + ownerInstance.callMethod('change', { + open: type + }) + + } + + state.isopen = type + // 添加动画类 + ins.requestAnimationFrame(() => { + ins.addClass('ani'); + this.move(left, ins, ownerInstance, self) + }) + }, + + + getDirection(x, y) { + if (x > y && x > MIN_DISTANCE) { + return 'horizontal'; + } + if (y > x && y > MIN_DISTANCE) { + return 'vertical'; + } + return ''; + }, + + /** + * 重置滑动状态 + * @param {Object} event + */ + resetTouchStatus(instance, self) { + let state = self.state; + state.direction = ''; + state.deltaX = 0; + state.deltaY = 0; + state.offsetX = 0; + state.offsetY = 0; + }, + + /** + * 设置滑动开始位置 + * @param {Object} event + */ + stopTouchStart(event, ownerInstance, self) { + let instance = event.instance; + let state = self.state + this.resetTouchStatus(instance, self); + var touch = event.touches[0]; + state.startX = touch.clientX; + state.startY = touch.clientY; + }, + + /** + * 滑动中,是否禁止打开 + * @param {Object} event + */ + stopTouchMove(event, self) { + let instance = event.instance; + let state = self.state; + let touch = event.touches[0]; + + state.deltaX = touch.clientX - state.startX; + state.deltaY = touch.clientY - state.startY; + state.offsetY = Math.abs(state.deltaY); + state.offsetX = Math.abs(state.deltaX); + state.direction = state.direction || this.getDirection(state.offsetX, state.offsetY); + } +} diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue new file mode 100644 index 0000000..d79c297 --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue @@ -0,0 +1,347 @@ + + + + + + diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/wx.wxs b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/wx.wxs new file mode 100644 index 0000000..b394244 --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/wx.wxs @@ -0,0 +1,341 @@ +var MIN_DISTANCE = 10; + +/** + * 判断当前是否为H5、app-vue + */ +var IS_HTML5 = false +if (typeof window === 'object') IS_HTML5 = true + +/** + * 监听页面内值的变化,主要用于动态开关swipe-action + * @param {Object} newValue + * @param {Object} oldValue + * @param {Object} ownerInstance + * @param {Object} instance + */ +function showWatch(newVal, oldVal, ownerInstance, instance) { + var state = instance.getState() + getDom(instance, ownerInstance) + if (newVal && newVal !== 'none') { + openState(newVal, instance, ownerInstance) + return + } + + if (state.left) { + openState('none', instance, ownerInstance) + } + resetTouchStatus(instance) +} + +/** + * 开始触摸操作 + * @param {Object} e + * @param {Object} ins + */ +function touchstart(e, ownerInstance) { + var instance = e.instance; + var disabled = instance.getDataset().disabled + var state = instance.getState(); + getDom(instance, ownerInstance) + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false; + if (disabled) return + // 开始触摸时移除动画类 + instance.requestAnimationFrame(function() { + instance.removeClass('ani'); + ownerInstance.callMethod('closeSwipe'); + }) + + // 记录上次的位置 + state.x = state.left || 0 + // 计算滑动开始位置 + stopTouchStart(e, ownerInstance) +} + +/** + * 开始滑动操作 + * @param {Object} e + * @param {Object} ownerInstance + */ +function touchmove(e, ownerInstance) { + var instance = e.instance; + var disabled = instance.getDataset().disabled + var state = instance.getState() + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false; + if (disabled) return + // 是否可以滑动页面 + stopTouchMove(e); + if (state.direction !== 'horizontal') { + return; + } + + if (e.preventDefault) { + // 阻止页面滚动 + e.preventDefault() + } + + move(state.x + state.deltaX, instance, ownerInstance) +} + +/** + * 结束触摸操作 + * @param {Object} e + * @param {Object} ownerInstance + */ +function touchend(e, ownerInstance) { + var instance = e.instance; + var disabled = instance.getDataset().disabled + var state = instance.getState() + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false; + + if (disabled) return + // 滑动过程中触摸结束,通过阙值判断是开启还是关闭 + // fixed by mehaotian 定时器解决点击按钮,touchend 触发比 click 事件时机早的问题 ,主要是 ios13 + moveDirection(state.left, instance, ownerInstance) + +} + +/** + * 设置移动距离 + * @param {Object} value + * @param {Object} instance + * @param {Object} ownerInstance + */ +function move(value, instance, ownerInstance) { + value = value || 0 + var state = instance.getState() + var leftWidth = state.leftWidth + var rightWidth = state.rightWidth + // 获取可滑动范围 + state.left = range(value, -rightWidth, leftWidth); + instance.requestAnimationFrame(function() { + instance.setStyle({ + transform: 'translateX(' + state.left + 'px)', + '-webkit-transform': 'translateX(' + state.left + 'px)' + }) + }) + +} + +/** + * 获取元素信息 + * @param {Object} instance + * @param {Object} ownerInstance + */ +function getDom(instance, ownerInstance) { + var state = instance.getState() + var leftDom = ownerInstance.selectComponent('.button-group--left') + var rightDom = ownerInstance.selectComponent('.button-group--right') + var leftStyles = { + width: 0 + } + var rightStyles = { + width: 0 + } + leftStyles = leftDom.getBoundingClientRect() + rightStyles = rightDom.getBoundingClientRect() + + state.leftWidth = leftStyles.width || 0 + state.rightWidth = rightStyles.width || 0 + state.threshold = instance.getDataset().threshold +} + +/** + * 获取范围 + * @param {Object} num + * @param {Object} min + * @param {Object} max + */ +function range(num, min, max) { + return Math.min(Math.max(num, min), max); +} + + +/** + * 移动方向判断 + * @param {Object} left + * @param {Object} value + * @param {Object} ownerInstance + * @param {Object} ins + */ +function moveDirection(left, ins, ownerInstance) { + var state = ins.getState() + var threshold = state.threshold + var position = state.position + var isopen = state.isopen || 'none' + var leftWidth = state.leftWidth + var rightWidth = state.rightWidth + if (state.deltaX === 0) { + openState('none', ins, ownerInstance) + return + } + if ((isopen === 'none' && rightWidth > 0 && -left > threshold) || (isopen !== 'none' && rightWidth > 0 && + rightWidth + + left < threshold)) { + // right + openState('right', ins, ownerInstance) + } else if ((isopen === 'none' && leftWidth > 0 && left > threshold) || (isopen !== 'none' && leftWidth > 0 && + leftWidth - left < threshold)) { + // left + openState('left', ins, ownerInstance) + } else { + // default + openState('none', ins, ownerInstance) + } +} + + +/** + * 开启状态 + * @param {Boolean} type + * @param {Object} ins + * @param {Object} ownerInstance + */ +function openState(type, ins, ownerInstance) { + var state = ins.getState() + var leftWidth = state.leftWidth + var rightWidth = state.rightWidth + var left = '' + state.isopen = state.isopen ? state.isopen : 'none' + switch (type) { + case "left": + left = leftWidth + break + case "right": + left = -rightWidth + break + default: + left = 0 + } + + // && !state.throttle + + if (state.isopen !== type) { + state.throttle = true + ownerInstance.callMethod('change', { + open: type + }) + + } + + state.isopen = type + // 添加动画类 + ins.requestAnimationFrame(function() { + ins.addClass('ani'); + move(left, ins, ownerInstance) + }) + // 设置最终移动位置,理论上只要进入到这个函数,肯定是要打开的 +} + + +function getDirection(x, y) { + if (x > y && x > MIN_DISTANCE) { + return 'horizontal'; + } + if (y > x && y > MIN_DISTANCE) { + return 'vertical'; + } + return ''; +} + +/** + * 重置滑动状态 + * @param {Object} event + */ +function resetTouchStatus(instance) { + var state = instance.getState(); + state.direction = ''; + state.deltaX = 0; + state.deltaY = 0; + state.offsetX = 0; + state.offsetY = 0; +} + +/** + * 设置滑动开始位置 + * @param {Object} event + */ +function stopTouchStart(event) { + var instance = event.instance; + var state = instance.getState(); + resetTouchStatus(instance); + var touch = event.touches[0]; + if (IS_HTML5 && isPC()) { + touch = event; + } + state.startX = touch.clientX; + state.startY = touch.clientY; +} + +/** + * 滑动中,是否禁止打开 + * @param {Object} event + */ +function stopTouchMove(event) { + var instance = event.instance; + var state = instance.getState(); + var touch = event.touches[0]; + if (IS_HTML5 && isPC()) { + touch = event; + } + state.deltaX = touch.clientX - state.startX; + state.deltaY = touch.clientY - state.startY; + state.offsetY = Math.abs(state.deltaY); + state.offsetX = Math.abs(state.deltaX); + state.direction = state.direction || getDirection(state.offsetX, state.offsetY); +} + +function isPC() { + var userAgentInfo = navigator.userAgent; + var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"]; + var flag = true; + for (var v = 0; v < Agents.length - 1; v++) { + if (userAgentInfo.indexOf(Agents[v]) > 0) { + flag = false; + break; + } + } + return flag; +} + +var movable = false + +function mousedown(e, ins) { + if (!IS_HTML5) return + if (!isPC()) return + touchstart(e, ins) + movable = true +} + +function mousemove(e, ins) { + if (!IS_HTML5) return + if (!isPC()) return + if (!movable) return + touchmove(e, ins) +} + +function mouseup(e, ins) { + if (!IS_HTML5) return + if (!isPC()) return + touchend(e, ins) + movable = false +} + +function mouseleave(e, ins) { + if (!IS_HTML5) return + if (!isPC()) return + movable = false +} + +module.exports = { + showWatch: showWatch, + touchstart: touchstart, + touchmove: touchmove, + touchend: touchend, + mousedown: mousedown, + mousemove: mousemove, + mouseup: mouseup, + mouseleave: mouseleave +} diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue b/uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue new file mode 100644 index 0000000..4971782 --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue @@ -0,0 +1,60 @@ + + + + + diff --git a/uni_modules/uni-swipe-action/package.json b/uni_modules/uni-swipe-action/package.json new file mode 100644 index 0000000..69135de --- /dev/null +++ b/uni_modules/uni-swipe-action/package.json @@ -0,0 +1,84 @@ +{ + "id": "uni-swipe-action", + "displayName": "uni-swipe-action 滑动操作", + "version": "1.3.8", + "description": "SwipeAction 滑动操作操作组件", + "keywords": [ + "", + "uni-ui", + "uniui", + "滑动删除", + "侧滑删除" + ], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "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" + }, + "快应用": { + "华为": "y", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-swipe-action/readme.md b/uni_modules/uni-swipe-action/readme.md new file mode 100644 index 0000000..93a5cac --- /dev/null +++ b/uni_modules/uni-swipe-action/readme.md @@ -0,0 +1,11 @@ + + +## SwipeAction 滑动操作 +> **组件名:uni-swipe-action** +> 代码块: `uSwipeAction`、`uSwipeActionItem` + + +通过滑动触发选项的容器 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-swipe-action) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-swiper-dot/changelog.md b/uni_modules/uni-swiper-dot/changelog.md new file mode 100644 index 0000000..85cf54d --- /dev/null +++ b/uni_modules/uni-swiper-dot/changelog.md @@ -0,0 +1,12 @@ +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-swiper-dot](https://uniapp.dcloud.io/component/uniui/uni-swiper-dot) +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.6(2021-05-12) +- 新增 示例地址 +- 修复 示例项目缺少组件的Bug +## 1.0.5(2021-02-05) +- 调整为uni_modules目录规范 +- 新增 clickItem 事件,支持指示点控制轮播 +- 新增 支持 pc 可用 diff --git a/uni_modules/uni-swiper-dot/components/uni-swiper-dot/uni-swiper-dot.vue b/uni_modules/uni-swiper-dot/components/uni-swiper-dot/uni-swiper-dot.vue new file mode 100644 index 0000000..e66b6c7 --- /dev/null +++ b/uni_modules/uni-swiper-dot/components/uni-swiper-dot/uni-swiper-dot.vue @@ -0,0 +1,218 @@ + + + + + diff --git a/uni_modules/uni-swiper-dot/package.json b/uni_modules/uni-swiper-dot/package.json new file mode 100644 index 0000000..f2dd8d2 --- /dev/null +++ b/uni_modules/uni-swiper-dot/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-swiper-dot", + "displayName": "uni-swiper-dot 轮播图指示点", + "version": "1.2.0", + "description": "自定义轮播图指示点组件", + "keywords": [ + "uni-ui", + "uniui", + "轮播图指示点", + "dot", + "swiper" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-swiper-dot/readme.md b/uni_modules/uni-swiper-dot/readme.md new file mode 100644 index 0000000..7d397e2 --- /dev/null +++ b/uni_modules/uni-swiper-dot/readme.md @@ -0,0 +1,11 @@ + + +## SwiperDot 轮播图指示点 +> **组件名:uni-swiper-dot** +> 代码块: `uSwiperDot` + + +自定义轮播图指示点 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-swiper-dot) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-table/changelog.md b/uni_modules/uni-table/changelog.md new file mode 100644 index 0000000..9f87c67 --- /dev/null +++ b/uni_modules/uni-table/changelog.md @@ -0,0 +1,27 @@ +## 1.2.3(2023-03-28) +- 修复 在vue3模式下可能会出现错误的问题 +## 1.2.2(2022-11-29) +- 优化 主题样式 +## 1.2.1(2022-06-06) +- 修复 微信小程序存在无使用组件的问题 +## 1.2.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-table](https://uniapp.dcloud.io/component/uniui/uni-table) +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.7(2021-07-08) +- 新增 uni-th 支持 date 日期筛选范围 +## 1.0.6(2021-07-05) +- 新增 uni-th 支持 range 筛选范围 +## 1.0.5(2021-06-28) +- 新增 uni-th 筛选功能 +## 1.0.4(2021-05-12) +- 新增 示例地址 +- 修复 示例项目缺少组件的Bug +## 1.0.3(2021-04-16) +- 新增 sortable 属性,是否开启单列排序 +- 优化 表格多选逻辑 +## 1.0.2(2021-03-22) +- uni-tr 添加 disabled 属性,用于 type=selection 时,设置某行是否可由全选按钮控制 +## 1.0.1(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-table/components/uni-table/uni-table.vue b/uni_modules/uni-table/components/uni-table/uni-table.vue new file mode 100644 index 0000000..21d9527 --- /dev/null +++ b/uni_modules/uni-table/components/uni-table/uni-table.vue @@ -0,0 +1,455 @@ + + + + + diff --git a/uni_modules/uni-table/components/uni-tbody/uni-tbody.vue b/uni_modules/uni-table/components/uni-tbody/uni-tbody.vue new file mode 100644 index 0000000..fbe1bdc --- /dev/null +++ b/uni_modules/uni-table/components/uni-tbody/uni-tbody.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/uni_modules/uni-table/components/uni-td/uni-td.vue b/uni_modules/uni-table/components/uni-td/uni-td.vue new file mode 100644 index 0000000..9ce93e9 --- /dev/null +++ b/uni_modules/uni-table/components/uni-td/uni-td.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/uni_modules/uni-table/components/uni-th/filter-dropdown.vue b/uni_modules/uni-table/components/uni-th/filter-dropdown.vue new file mode 100644 index 0000000..df22a71 --- /dev/null +++ b/uni_modules/uni-table/components/uni-th/filter-dropdown.vue @@ -0,0 +1,511 @@ + + + + + diff --git a/uni_modules/uni-table/components/uni-th/uni-th.vue b/uni_modules/uni-table/components/uni-th/uni-th.vue new file mode 100644 index 0000000..14889dd --- /dev/null +++ b/uni_modules/uni-table/components/uni-th/uni-th.vue @@ -0,0 +1,285 @@ + + + + + diff --git a/uni_modules/uni-table/components/uni-thead/uni-thead.vue b/uni_modules/uni-table/components/uni-thead/uni-thead.vue new file mode 100644 index 0000000..0dd18cd --- /dev/null +++ b/uni_modules/uni-table/components/uni-thead/uni-thead.vue @@ -0,0 +1,129 @@ + + + + + diff --git a/uni_modules/uni-table/components/uni-tr/table-checkbox.vue b/uni_modules/uni-table/components/uni-tr/table-checkbox.vue new file mode 100644 index 0000000..1089187 --- /dev/null +++ b/uni_modules/uni-table/components/uni-tr/table-checkbox.vue @@ -0,0 +1,179 @@ + + + + + diff --git a/uni_modules/uni-table/components/uni-tr/uni-tr.vue b/uni_modules/uni-table/components/uni-tr/uni-tr.vue new file mode 100644 index 0000000..f9b9671 --- /dev/null +++ b/uni_modules/uni-table/components/uni-tr/uni-tr.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/uni_modules/uni-table/i18n/en.json b/uni_modules/uni-table/i18n/en.json new file mode 100644 index 0000000..e32023c --- /dev/null +++ b/uni_modules/uni-table/i18n/en.json @@ -0,0 +1,9 @@ +{ + "filter-dropdown.reset": "Reset", + "filter-dropdown.search": "Search", + "filter-dropdown.submit": "Submit", + "filter-dropdown.filter": "Filter", + "filter-dropdown.gt": "Greater or equal to", + "filter-dropdown.lt": "Less than or equal to", + "filter-dropdown.date": "Date" +} diff --git a/uni_modules/uni-table/i18n/es.json b/uni_modules/uni-table/i18n/es.json new file mode 100644 index 0000000..9afd04b --- /dev/null +++ b/uni_modules/uni-table/i18n/es.json @@ -0,0 +1,9 @@ +{ + "filter-dropdown.reset": "Reiniciar", + "filter-dropdown.search": "Búsqueda", + "filter-dropdown.submit": "Entregar", + "filter-dropdown.filter": "Filtrar", + "filter-dropdown.gt": "Mayor o igual a", + "filter-dropdown.lt": "Menos que o igual a", + "filter-dropdown.date": "Fecha" +} diff --git a/uni_modules/uni-table/i18n/fr.json b/uni_modules/uni-table/i18n/fr.json new file mode 100644 index 0000000..b006237 --- /dev/null +++ b/uni_modules/uni-table/i18n/fr.json @@ -0,0 +1,9 @@ +{ + "filter-dropdown.reset": "Réinitialiser", + "filter-dropdown.search": "Chercher", + "filter-dropdown.submit": "Soumettre", + "filter-dropdown.filter": "Filtre", + "filter-dropdown.gt": "Supérieur ou égal à", + "filter-dropdown.lt": "Inférieur ou égal à", + "filter-dropdown.date": "Date" +} diff --git a/uni_modules/uni-table/i18n/index.js b/uni_modules/uni-table/i18n/index.js new file mode 100644 index 0000000..2469dd0 --- /dev/null +++ b/uni_modules/uni-table/i18n/index.js @@ -0,0 +1,12 @@ +import en from './en.json' +import es from './es.json' +import fr from './fr.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + es, + fr, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-table/i18n/zh-Hans.json b/uni_modules/uni-table/i18n/zh-Hans.json new file mode 100644 index 0000000..862af17 --- /dev/null +++ b/uni_modules/uni-table/i18n/zh-Hans.json @@ -0,0 +1,9 @@ +{ + "filter-dropdown.reset": "重置", + "filter-dropdown.search": "搜索", + "filter-dropdown.submit": "确定", + "filter-dropdown.filter": "筛选", + "filter-dropdown.gt": "大于等于", + "filter-dropdown.lt": "小于等于", + "filter-dropdown.date": "日期范围" +} diff --git a/uni_modules/uni-table/i18n/zh-Hant.json b/uni_modules/uni-table/i18n/zh-Hant.json new file mode 100644 index 0000000..64f8061 --- /dev/null +++ b/uni_modules/uni-table/i18n/zh-Hant.json @@ -0,0 +1,9 @@ +{ + "filter-dropdown.reset": "重置", + "filter-dropdown.search": "搜索", + "filter-dropdown.submit": "確定", + "filter-dropdown.filter": "篩選", + "filter-dropdown.gt": "大於等於", + "filter-dropdown.lt": "小於等於", + "filter-dropdown.date": "日期範圍" +} diff --git a/uni_modules/uni-table/package.json b/uni_modules/uni-table/package.json new file mode 100644 index 0000000..7c2f91c --- /dev/null +++ b/uni_modules/uni-table/package.json @@ -0,0 +1,83 @@ +{ + "id": "uni-table", + "displayName": "uni-table 表格", + "version": "1.2.3", + "description": "表格组件,多用于展示多条结构类似的数据,如", + "keywords": [ + "uni-ui", + "uniui", + "table", + "表格" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-scss","uni-datetime-picker"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "n" + }, + "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", + "字节跳动": "n", + "QQ": "y" + }, + "快应用": { + "华为": "n", + "联盟": "n" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-table/readme.md b/uni_modules/uni-table/readme.md new file mode 100644 index 0000000..bb08c79 --- /dev/null +++ b/uni_modules/uni-table/readme.md @@ -0,0 +1,13 @@ + + +## Table 表单 +> 组件名:``uni-table``,代码块: `uTable`。 + +用于展示多条结构类似的数据 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-table) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + + + diff --git a/uni_modules/uni-tag/changelog.md b/uni_modules/uni-tag/changelog.md new file mode 100644 index 0000000..c0c5839 --- /dev/null +++ b/uni_modules/uni-tag/changelog.md @@ -0,0 +1,21 @@ +## 2.1.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-tag](https://uniapp.dcloud.io/component/uniui/uni-tag) +## 2.0.0(2021-11-09) +- 新增 提供组件设计资源,组件样式调整 +- 移除 插槽 +- 移除 type 属性的 royal 选项 +## 1.1.1(2021-08-11) +- type 不是 default 时,size 为 small 字体大小显示不正确 +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.7(2021-06-18) +- 修复 uni-tag 在字节跳动小程序上 css 类名编译错误的 bug +## 1.0.6(2021-06-04) +- 修复 未定义 sass 变量 "$uni-color-royal" 的bug +## 1.0.5(2021-05-10) +- 修复 royal 类型无效的bug +- 修复 uni-tag 宽度不自适应的bug +- 新增 uni-tag 支持属性 custom-style 自定义样式 +## 1.0.4(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-tag/components/uni-tag/uni-tag.vue b/uni_modules/uni-tag/components/uni-tag/uni-tag.vue new file mode 100644 index 0000000..418c955 --- /dev/null +++ b/uni_modules/uni-tag/components/uni-tag/uni-tag.vue @@ -0,0 +1,252 @@ + + + + + diff --git a/uni_modules/uni-tag/package.json b/uni_modules/uni-tag/package.json new file mode 100644 index 0000000..1878088 --- /dev/null +++ b/uni_modules/uni-tag/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-tag", + "displayName": "uni-tag 标签", + "version": "2.1.0", + "description": "Tag 组件,用于展示1个或多个文字标签,可点击切换选中、不选中的状态。", + "keywords": [ + "uni-ui", + "uniui", + "", + "tag", + "标签" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-tag/readme.md b/uni_modules/uni-tag/readme.md new file mode 100644 index 0000000..6e78ff5 --- /dev/null +++ b/uni_modules/uni-tag/readme.md @@ -0,0 +1,13 @@ + + +## Tag 标签 +> **组件名:uni-tag** +> 代码块: `uTag` + + +用于展示1个或多个文字标签,可点击切换选中、不选中的状态 。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-tag) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-title/changelog.md b/uni_modules/uni-title/changelog.md new file mode 100644 index 0000000..7626216 --- /dev/null +++ b/uni_modules/uni-title/changelog.md @@ -0,0 +1,10 @@ +## 1.1.1(2022-05-19) +- 修改组件描述 +## 1.1.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-title](https://uniapp.dcloud.io/component/uniui/uni-title) +## 1.0.2(2021-05-12) +- 新增 示例地址 +- 修复 示例项目缺少组件的Bug +## 1.0.1(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-title/components/uni-title/uni-title.vue b/uni_modules/uni-title/components/uni-title/uni-title.vue new file mode 100644 index 0000000..bf4f926 --- /dev/null +++ b/uni_modules/uni-title/components/uni-title/uni-title.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/uni_modules/uni-title/package.json b/uni_modules/uni-title/package.json new file mode 100644 index 0000000..2249f5a --- /dev/null +++ b/uni_modules/uni-title/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-title", + "displayName": "uni-title 章节标题", + "version": "1.1.1", + "description": "章节标题,通常用于记录页面标题,使用当前组件,uni-app 如果开启统计,将会自动统计页面标题", + "keywords": [ + "uni-ui", + "uniui", + "标题", + "章节", + "章节标题", + "" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-title/readme.md b/uni_modules/uni-title/readme.md new file mode 100644 index 0000000..0e60b1b --- /dev/null +++ b/uni_modules/uni-title/readme.md @@ -0,0 +1,14 @@ + + +## Title 标题 +> **组件名:uni-title** +> 代码块: `uTitle` + + +章节标题,通常用于记录页面标题,使用当前组件,uni-app 如果开启统计,将会自动统计页面标题 。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-title) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + + diff --git a/uni_modules/uni-tooltip/changelog.md b/uni_modules/uni-tooltip/changelog.md new file mode 100644 index 0000000..00f1572 --- /dev/null +++ b/uni_modules/uni-tooltip/changelog.md @@ -0,0 +1,10 @@ +## 0.2.1(2022-05-09) +- 修复 content 为空时仍然弹出的bug +## 0.2.0(2022-05-07) +**注意:破坏性更新** +- 更新 text 属性变更为 content +- 更新 移除 width 属性 +## 0.1.1(2022-04-27) +- 修复 组件根 text 嵌套组件 warning +## 0.1.0(2022-04-21) +- 初始化 diff --git a/uni_modules/uni-tooltip/components/uni-tooltip/uni-tooltip.vue b/uni_modules/uni-tooltip/components/uni-tooltip/uni-tooltip.vue new file mode 100644 index 0000000..ffbb6fa --- /dev/null +++ b/uni_modules/uni-tooltip/components/uni-tooltip/uni-tooltip.vue @@ -0,0 +1,68 @@ + + + + + + diff --git a/uni_modules/uni-tooltip/package.json b/uni_modules/uni-tooltip/package.json new file mode 100644 index 0000000..b626efb --- /dev/null +++ b/uni_modules/uni-tooltip/package.json @@ -0,0 +1,83 @@ +{ + "id": "uni-tooltip", + "displayName": "uni-tooltip", + "version": "0.2.1", + "description": "Tooltip 提示文字", + "keywords": [ + "uni-tooltip", + "uni-ui", + "tooltip", + "tip", + "文字提示" +], + "repository": "", +"engines": { + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无 ", + "data": "无", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-tooltip/readme.md b/uni_modules/uni-tooltip/readme.md new file mode 100644 index 0000000..faafa2e --- /dev/null +++ b/uni_modules/uni-tooltip/readme.md @@ -0,0 +1,8 @@ +## Badge 数字角标 +> **组件名:uni-tooltip** +> 代码块: `uTooltip` + +数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景, + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-tooltip) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 diff --git a/uni_modules/uni-transition/changelog.md b/uni_modules/uni-transition/changelog.md new file mode 100644 index 0000000..faaf336 --- /dev/null +++ b/uni_modules/uni-transition/changelog.md @@ -0,0 +1,24 @@ +## 1.3.3(2024-04-23) +- 修复 当元素会受变量影响自动隐藏的bug +## 1.3.2(2023-05-04) +- 修复 NVUE 平台报错的问题 +## 1.3.1(2021-11-23) +- 修复 init 方法初始化问题 +## 1.3.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-transition](https://uniapp.dcloud.io/component/uniui/uni-transition) +## 1.2.1(2021-09-27) +- 修复 init 方法不生效的 Bug +## 1.2.0(2021-07-30) +- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.1(2021-05-12) +- 新增 示例地址 +- 修复 示例项目缺少组件的 Bug +## 1.1.0(2021-04-22) +- 新增 通过方法自定义动画 +- 新增 custom-class 非 NVUE 平台支持自定义 class 定制样式 +- 优化 动画触发逻辑,使动画更流畅 +- 优化 支持单独的动画类型 +- 优化 文档示例 +## 1.0.2(2021-02-05) +- 调整为 uni_modules 目录规范 diff --git a/uni_modules/uni-transition/components/uni-transition/createAnimation.js b/uni_modules/uni-transition/components/uni-transition/createAnimation.js new file mode 100644 index 0000000..8f89b18 --- /dev/null +++ b/uni_modules/uni-transition/components/uni-transition/createAnimation.js @@ -0,0 +1,131 @@ +// const defaultOption = { +// duration: 300, +// timingFunction: 'linear', +// delay: 0, +// transformOrigin: '50% 50% 0' +// } +// #ifdef APP-NVUE +const nvueAnimation = uni.requireNativePlugin('animation') +// #endif +class MPAnimation { + constructor(options, _this) { + this.options = options + // 在iOS10+QQ小程序平台下,传给原生的对象一定是个普通对象而不是Proxy对象,否则会报parameter should be Object instead of ProxyObject的错误 + this.animation = uni.createAnimation({ + ...options + }) + this.currentStepAnimates = {} + this.next = 0 + this.$ = _this + + } + + _nvuePushAnimates(type, args) { + let aniObj = this.currentStepAnimates[this.next] + let styles = {} + if (!aniObj) { + styles = { + styles: {}, + config: {} + } + } else { + styles = aniObj + } + if (animateTypes1.includes(type)) { + if (!styles.styles.transform) { + styles.styles.transform = '' + } + let unit = '' + if(type === 'rotate'){ + unit = 'deg' + } + styles.styles.transform += `${type}(${args+unit}) ` + } else { + styles.styles[type] = `${args}` + } + this.currentStepAnimates[this.next] = styles + } + _animateRun(styles = {}, config = {}) { + let ref = this.$.$refs['ani'].ref + if (!ref) return + return new Promise((resolve, reject) => { + nvueAnimation.transition(ref, { + styles, + ...config + }, res => { + resolve() + }) + }) + } + + _nvueNextAnimate(animates, step = 0, fn) { + let obj = animates[step] + if (obj) { + let { + styles, + config + } = obj + this._animateRun(styles, config).then(() => { + step += 1 + this._nvueNextAnimate(animates, step, fn) + }) + } else { + this.currentStepAnimates = {} + typeof fn === 'function' && fn() + this.isEnd = true + } + } + + step(config = {}) { + // #ifndef APP-NVUE + this.animation.step(config) + // #endif + // #ifdef APP-NVUE + this.currentStepAnimates[this.next].config = Object.assign({}, this.options, config) + this.currentStepAnimates[this.next].styles.transformOrigin = this.currentStepAnimates[this.next].config.transformOrigin + this.next++ + // #endif + return this + } + + run(fn) { + // #ifndef APP-NVUE + this.$.animationData = this.animation.export() + this.$.timer = setTimeout(() => { + typeof fn === 'function' && fn() + }, this.$.durationTime) + // #endif + // #ifdef APP-NVUE + this.isEnd = false + let ref = this.$.$refs['ani'] && this.$.$refs['ani'].ref + if(!ref) return + this._nvueNextAnimate(this.currentStepAnimates, 0, fn) + this.next = 0 + // #endif + } +} + + +const animateTypes1 = ['matrix', 'matrix3d', 'rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scale3d', + 'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'translate', 'translate3d', 'translateX', 'translateY', + 'translateZ' +] +const animateTypes2 = ['opacity', 'backgroundColor'] +const animateTypes3 = ['width', 'height', 'left', 'right', 'top', 'bottom'] +animateTypes1.concat(animateTypes2, animateTypes3).forEach(type => { + MPAnimation.prototype[type] = function(...args) { + // #ifndef APP-NVUE + this.animation[type](...args) + // #endif + // #ifdef APP-NVUE + this._nvuePushAnimates(type, args) + // #endif + return this + } +}) + +export function createAnimation(option, _this) { + if(!_this) return + clearTimeout(_this.timer) + return new MPAnimation(option, _this) +} diff --git a/uni_modules/uni-transition/components/uni-transition/uni-transition.vue b/uni_modules/uni-transition/components/uni-transition/uni-transition.vue new file mode 100644 index 0000000..f3ddd1f --- /dev/null +++ b/uni_modules/uni-transition/components/uni-transition/uni-transition.vue @@ -0,0 +1,286 @@ + + + + + diff --git a/uni_modules/uni-transition/package.json b/uni_modules/uni-transition/package.json new file mode 100644 index 0000000..d5c20e1 --- /dev/null +++ b/uni_modules/uni-transition/package.json @@ -0,0 +1,85 @@ +{ + "id": "uni-transition", + "displayName": "uni-transition 过渡动画", + "version": "1.3.3", + "description": "元素的简单过渡动画", + "keywords": [ + "uni-ui", + "uniui", + "动画", + "过渡", + "过渡动画" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-transition/readme.md b/uni_modules/uni-transition/readme.md new file mode 100644 index 0000000..2f8a77e --- /dev/null +++ b/uni_modules/uni-transition/readme.md @@ -0,0 +1,11 @@ + + +## Transition 过渡动画 +> **组件名:uni-transition** +> 代码块: `uTransition` + + +元素过渡动画 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-transition) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-ui/changelog.md b/uni_modules/uni-ui/changelog.md new file mode 100644 index 0000000..61b26d0 --- /dev/null +++ b/uni_modules/uni-ui/changelog.md @@ -0,0 +1,541 @@ +## 1.4.27(2023-04-23) +- uni-calendar 修复 某些情况 monthSwitch 未触发的Bug +- uni-calendar 修复 某些情况切换月份错误的Bug +- uni-data-picker 修复 更改 modelValue 报错的 bug +- uni-data-picker 修复 v-for 未使用 key 值控制台 warning +- uni-data-picker 修复代码合并时引发 value 属性为空时不渲染数据的问题 +- uni-data-picker 修复 localdata 不支持动态更新的bug +- uni-data-select 修复 微信小程序点击时会改变背景颜色的 bug +- uni-data-select 修复 禁用时会显示清空按钮 +- uni-data-select 优化 查询条件短期内多次变更只查询最后一次变更后的结果 +- uni-data-select 调整 内部缓存键名调整为 uni-data-select-lastSelectedValue +- uni-datetime-picker 修复 日历 picker 修改年月后,自动选中当月1日 [详情](https://ask.dcloud.net.cn/question/165937) +- uni-datetime-picker 修复 小程序端 低版本 ios NaN [详情](https://ask.dcloud.net.cn/question/162979) +- uni-datetime-picker 修复 firefox 浏览器显示区域点击无法拉起日历弹框的Bug [详情](https://ask.dcloud.net.cn/question/163362) +- uni-datetime-picker 优化 值为空依然选中当天问题 +- uni-datetime-picker 优化 提供 default-value 属性支持配置选择器打开时默认显示的时间 +- uni-datetime-picker 优化 非范围选择未选择日期时间,点击确认按钮选中当前日期时间 +- uni-datetime-picker 优化 字节小程序日期时间范围选择,底部日期换行问题 +- uni-datetime-picker 修复 2.2.18 引起范围选择配置 end 选择无效的Bug [详情](https://github.com/dcloudio/uni-ui/issues/686) +- uni-datetime-picker 修复 移动端范围选择change事件触发异常的Bug [详情](https://github.com/dcloudio/uni-ui/issues/684) +- uni-datetime-picker 优化 PC端输入日期格式错误时返回当前日期时间 +- uni-datetime-picker 优化 PC端输入日期时间超出 start、end 限制的Bug +- uni-datetime-picker 优化 移动端日期时间范围用法时间展示不完整问题 +- uni-datetime-picker 修复 小程序端绑定 Date 类型报错的Bug [详情](https://github.com/dcloudio/uni-ui/issues/679) +- uni-datetime-picker 修复 vue3 time-picker 无法显示绑定时分秒的Bug +- uni-datetime-picker 修复 字节小程序报错的Bug +- uni-datetime-picker 修复 某些情况切换月份错误的Bug +- uni-easyinput 修复 vue3 下 keyboardheightchange 事件报错的bug +- uni-easyinput 优化 trim 属性默认值 +- uni-easyinput 新增 cursor-spacing 属性 +- uni-fab 新增 pattern.icon 属性,可自定义图标 +- uni-file-picker 修复 手动上传删除一个文件后不能再上传的bug +- uni-forms 修复 required 参数无法动态绑定 +- uni-list 优化 uni-list-chat 具名插槽`header` 非app端套一层元素,方便使用时通过外层元素定位实现样式修改 +- uni-list uni-list-chat 新增 支持具名插槽`header` +- uni-list 新增 列表图标新增 customPrefix 属性 ,用法 [详见](https://uniapp.dcloud.net.cn/component/uniui/uni-icons.html#icons-props) +- uni-nav-bar 修复 自定义状态栏高度闪动BUG +- uni-nav-bar 修复 暗黑模式下边线颜色错误的bug +- uni-popup 修复 uni-popup 重复打开时的 bug +- uni-popup uni-popup-dialog 组件新增 inputType 属性 +- uni-swipe-action 修复`uni-swipe-action`和`uni-swipe-action-item`不同时使用导致 closeOther 方法报错的 bug +- uni-table 修复 在vue3模式下可能会出现错误的问题 +## 1.4.26(2023-01-31) +- uni-badge 修复 运行/打包 控制台警告问题 +- uni-calendar 修复 某些情况切换月份错误问题 +- uni-data-select 修复 不关联服务空间报错的问题 +- uni-data-select 新增 属性 `format` 可用于格式化显示选项内容 +- uni-datetime-picker 修复 某些情况切换月份错误问题 +- uni-easyinput 新增 keyboardheightchange 事件,可监听键盘高度变化 +- uni-list 修复 无反馈效果呈现的bug +## 1.4.25(2023-01-11) +- uni-file-picker 新增 sourceType 属性, 可以自定义图片和视频选择的来源 +## 1.4.24(2023-01-11) +- uni-data-select 修复 当where变化时,数据不会自动更新的问题 +- uni-datetime-picker 修复 多次加载组件造成内存占用的 bug +- uni-datetime-picker 修复 vue3 下 i18n 国际化初始值不正确的 bug +- uni-easyinput 修复 props 中背景颜色无默认值的bug +- uni-list 修复 uni-list-chat 在vue3下跳转报错的bug +- uni-list 修复 uni-list-chat avatar属性 值为本地路径时错误的问题 +- uni-list 修复 uni-list-chat avatar属性 在腾讯云版uniCloud下错误的问题 +- uni-list 修复 uni-list-chat note属性 支持:“草稿”字样功能 文本少1位的问题 +- uni-list 修复 uni-list-item 的 customStyle 属性 padding值在 H5端 无效的bug +- uni-list 修复 uni-list-item 的 customStyle 属性 padding值在nvue(vue2)下无效的bug +- uni-list uni-list-chat 新增 avatar 支持 fileId +- uni-list uni-list 新增属性 render-reverse 详情参考:[https://uniapp.dcloud.net.cn/component/list.html](https://uniapp.dcloud.net.cn/component/list.html) +- uni-list uni-list-chat note属性 支持:“草稿”字样 加红显示 详情参考uni-im:[https://ext.dcloud.net.cn/plugin?name=uni-im](https://ext.dcloud.net.cn/plugin?name=uni-im) +- uni-list uni-list-item 新增属性 customStyle 支持设置padding、backgroundColor +- uni-popup 修复 nvue 下 v-show 报错 +## 1.4.23(2022-10-25) +- uni-datetime-picker 修复,支付宝小程序样式错乱,[详情](https://github.com/dcloudio/uni-app/issues/3861) + +- uni-nav-bar 修复 条件编译错误的bug +- uni-nav-bar 修复 nvue 环境 fixed 为 true 的情况下,无法置顶的 bug +## 1.4.22(2022-09-19) +- 优化 部分组件适配 uni-scss 主题色 +- uni-badge 修复 当 text 超过 max-num 时,badge 的宽度计算是根据 text 的长度计算,更改为 css 计算实际展示宽度,详见:[https://ask.dcloud.net.cn/question/150473](https://ask.dcloud.net.cn/question/150473) +- uni-calendar 修复 表头年月切换,导致改变当前日期为选择月1号,且未触发change事件 +- uni-data-select 修复 微信小程序下拉框出现后选择会点击到蒙板后面的输入框 +- uni-data-select 修复 点击的位置不准确 +- uni-data-select 新增 支持 disabled 属性 +- uni-datetime-picker 修复,反向选择日期范围,日期显示异常,[详情](https://ask.dcloud.net.cn/question/153401?item_id=212892&rf=false) +- uni-datetime-picker 修复 close事件无效的 bug +- uni-datetime-picker 修复 移动端 maskClick 无效的 bug,详见:[https://ask.dcloud.net.cn/question/140824?item_id=209458&rf=false](https://ask.dcloud.net.cn/question/140824?item_id=209458&rf=false) +- uni-fab 修复 小程序端由于 style 使用了对象导致报错,[详情](https://ask.dcloud.net.cn/question/152790?item_id=211778&rf=false) +- uni-fab 修复 nvue 环境下,具有 tabBar 时,fab 组件下部位置无法正常获取 --window-bottom 的bug,详见:[https://ask.dcloud.net.cn/question/110638?notification_id=826310](https://ask.dcloud.net.cn/question/110638?notification_id=826310) +- uni-forms 优化 根据 rules 自动添加 required 的问题 +- uni-forms 修复 item 未设置 require 属性,rules 设置 require 后,星号也显示的 bug,详见:[https://ask.dcloud.net.cn/question/151540](https://ask.dcloud.net.cn/question/151540) +- uni-nav-bar 修复 nvue 环境下 fixed 为 true 的情况下,无法置顶的 bug +- uni-notice-bar 新增 属性 fontSize,可修改文字大小。 +- uni-pagination 修复,未对主题色设置默认色,导致未引入 uni-scss 变量文件报错。 +- uni-pagination 修复,未对移动端当前页文字做主题色适配。 +- uni-pagination 修复 es 语言 i18n 错误 +## 1.4.21(2022-09-19) +- 修复,安装时未导入 uni-data-select 和 uni-tooltip 的问题。 +## 1.4.20(2022-07-25) +- uni-section 新增组件 +- uni-forms 修复 model 需要校验的值没有声明对应字段时,导致第一次不触发校验的bug + +## 1.4.19(2022-07-07) +- uni-data-picker 优化 pc端图标位置不正确的问题 +- uni-data-select 修复 pc端宽度异常的bug +## 1.4.18(2022-07-06) +- uni-forms 【重要】组件逻辑重构,部分用法旧版本不兼容,请注意兼容问题 +- uni-forms 【重要】组件使用 Provide/Inject 方式注入依赖,提供了自定义表单组件调用 uni-forms 校验表单的能力 +- uni-forms 新增 更多表单示例 +- uni-forms 新增 model 属性,等同于原 value/modelValue 属性,旧属性即将废弃 +- uni-forms 新增 validateTrigger 属性的 blur 值,仅 uni-easyinput 生效 +- uni-forms 新增 onFieldChange 方法,可以对子表单进行校验,可替代binddata方法 +- uni-forms 新增 子表单的 setRules 方法,配合自定义校验函数使用 +- uni-forms 新增 uni-forms-item 的 setRules 方法,配置动态表单使用可动态更新校验规则 +- uni-forms 修复 由 1.4.0 引发的 label 插槽不生效的bug +- uni-forms 修复 子组件找不到 setValue 报错的bug +- uni-forms 修复 uni-data-picker 在 uni-forms-item 中报错的bug +- uni-forms 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug +- uni-forms 修复 表单校验顺序无序问题 +- uni-forms 优化 子表单组件uni-datetime-picker、uni-data-select、uni-data-picker的显示样式 +- uni-forms 优化 动态表单校验方式,废弃拼接name的方式 +- uni-breadcrumb 修复 微信小程序 separator 不显示问题 +- uni-data-checkbox 优化 在 uni-forms 中的依赖注入方式 +- uni-data-picker 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug +- uni-data-picker 优化 显示样式 +- uni-data-select 优化 显示样式 +- uni-datetime-picker 修复 日历顶部年月及底部确认未国际化 bug +- uni-datetime-picker 优化 组件样式,调整了组件图标大小、高度、颜色等,与uni-ui风格保持一致 +- uni-easyinput 新增 在 uni-forms 1.4.0 中使用可以在 blur 时校验内容 +- uni-easyinput 新增 clear 事件,点击右侧叉号图标触发 +- uni-easyinput 新增 change 事件 ,仅在输入框失去焦点或用户按下回车时触发 +- uni-easyinput 优化 组件样式,组件获取焦点时高亮显示,图标颜色调整等 +- uni-easyinput 优化 clearable 显示策略 +- uni-file-picker 修复 在uni-forms下样式不生效的bug +- uni-nav-bar 修复 组件示例中插槽用法无法显示内容的bug +- uni-swipe-action 修复 vue3 下使用组件不能正常运行的Bug +- uni-swipe-action 修复 h5端点击click触发两次的Bug +- uni-table 修复 微信小程序存在无使用组件的问题 +## 1.4.17(2022-06-30) +- 支持 ios 安全区 +## 1.4.16(2022-06-06) +- uni-breadcrumb 新增 支持 uni.scss 修改颜色 +- uni-data-select 修复 localdata 赋值不生效的 bug +- uni-data-select 新增 支持选项禁用(数据选项设置 disabled: true 即禁用) +- uni-data-select 修复 当 value 为 0 时选择不生效的 bug +- uni-easyinput 修复 关闭图标某些情况下无法取消的bug +- uni-fav 新增 stat 属性 ,是否开启uni统计功能 +- uni-goods-nav 新增 stat属性,是否开启uni统计功能 +- uni-group 新增 stat属性,是否开启uni统计功能 +- uni-nav-bar 新增 stat 属性 ,可开启统计 title 上报 ,仅使用了title 属性且项目开启了uni统计生效 +- uni-search-bar 新增 readonly 属性,组件只读 +- uni-swipe-action 修复 isPC 找不到的Bug +- uni-swipe-action 修复 在 nvue 下 disabled 失效的bug +- uni-tooltip 修复 content 为空时仍然弹出的bug +## 1.4.15(2022-05-07) +- uni-data-picker 修复 字节小程序 本地数据无法选择下一级的Bug +- uni-data-select 新增 记住上次的选项(仅 collection 存在时有效) +- uni-search-bar 修复 vue3 input 事件不生效的bug +- uni-search-bar 修复 多余代码导致的bug +- uni-tooltip 更新 text 属性变更为 content +- uni-tooltip 更新 移除 width 属性 +- uni-tooltip 修复 组件根 text 嵌套组件 warning +## 1.4.14(2022-04-18) +- uni-datetime-picker 修复 Vue3 下动态赋值,单选类型未响应的 bug +- uni-easyinput 修复 默认值不生效的bug +## 1.4.13(2022-04-02) +- uni-calendar 修复 条件编译 nvue 不支持的 css 样式 +- uni-calendar 修复 startDate、 endDate 属性失效的 bug +- uni-data-picker 修复 nvue 不支持的 v-show 的 bug +- uni-data-picker 修复 条件编译 nvue 不支持的 css 样式 +- uni-datetime-picker 修复 Vue3 下动态赋值未响应的 bug +- uni-easyinput 修复 value不能为0的bug +- uni-popup 修复 弹出层内部无法滚动的bug +- uni-popup 修复 小程序中高度错误的bug +- uni-popup 修复 快速调用open出现问题的Bug +- uni-rate 修复 条件判断 `NaN` 错误的 bug +- uni-swipe-action 修复 按钮字体大小不能设置的bug +- uni-swipe-action 修复 h5和app端下报el错误的bug +- uni-swipe-action 修复 HBuilderX 1.4.X 版本中,h5和app端下报错的bug +## 1.4.12(2022-02-19) +- uni-collapse 修复 初始化的时候 ,open 属性失效的bug +- uni-data-checkbox 修复 multiple 为 true 时,v-model 的值为 null 报错的 bug +- uni-icons 优化 size 属性可以传入不带单位的字符串数值 +- uni-icons 优化 size 支持其他单位 +- uni-nav-bar 新增 left-width/right-width属性 ,可修改左右两侧的宽度 +- uni-popup 修复 safeArea 属性不能设置为false的bug +## 1.4.11(2022-01-21) +- uni-collapse 修复 微信小程序resize后组件收起的bug +- uni-countdown 修复 在微信小程序中样式不生效的bug +- uni-countdown 新增 update 方法 ,在动态更新时间后,刷新组件 +- uni-load-more 新增 showText属性 ,是否显示文本 +- uni-load-more 修复 nvue 平台下不显示文本的bug +- uni-load-more 修复 微信小程序平台样式选择器报警告的问题 +- uni-nav-bar 修复 在vue下,标题不垂直居中的bug +- uni-nav-bar 修复 height 属性类型错误 +- uni-nav-bar 新增 height 属性,可修改组件高度 +- uni-nav-bar 新增 dark 属性可可开启暗黑模式 +- uni-nav-bar 优化 标题字数过多显示省略号 +- uni-nav-bar 优化 插槽,插入内容可完全覆盖 +- uni-popup 修复 isMaskClick 失效的bug +- uni-popup 新增 cancelText \ confirmText 属性 ,可自定义文本 +- uni-popup 新增 maskBackgroundColor 属性 ,可以修改蒙版颜色 +- uni-popup 优化 maskClick属性 更新为 isMaskClick ,解决微信小程序警告的问题 + +## 1.4.10(2022-01-17) +- uni-card 修复 在vue页面下略缩图显示不正常的bug +- uni-datetime-picker 修复 clear-icon 属性在小程序平台不生效的 bug +- uni-datetime-picker 修复 日期范围选在小程序平台,必须多点击一次才能取消选中状态的 bug +- uni-fab 更新 组件依赖 +- +- uni-icons 修复 nvue 有些图标不显示的bug,兼容老版本图标 +- uni-icons 优化 示例可复制图标名称 +- uni-nav-bar 修复 color 属性不生效的bug +- uni-popup 修复 设置 safeArea 属性不生效的bug +- uni-popup 优化 组件示例 +- uni-popup 修复 vuedoc 文字错误 +## 1.4.9(2021-11-23) +- uni-ui 修复 vue3中某些scss变量无法找到的问题 +- uni-combox 优化 label、label-width 属性 +- uni-data-picker 修复 由上个版本引发的map、v-model等属性不生效的bug +- uni-file-picker 修复 参数为对象的情况下,url在某些情况显示错误的bug +- uni-icons 优化 兼容旧组件 type 值 +- uni-list 修复 在vue3中to属性在发行应用的时候报错的bug +- uni-scss 修复 vue3中scss语法兼容问题 +- uni-transition 修复 init 方法初始化问题 +## 1.4.8(2021-11-19) +- uni-fab 修复 阴影颜色不正确的bug +## 1.4.7(2021-11-19) +- uni-ui 新增 支持国际化 +- uni-ui 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- uni-ui 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-ui](https://uniapp.dcloud.io/component/uniui/uni-ui) +- uni-badge 修改 size 属性默认值调整为 small +- uni-badge 修改 type 属性,默认值调整为 error,info 替换 default +- uni-badge 修复 在字节小程序上样式不生效的 bug +- uni-calendar 修复 弹出层被 tabbar 遮盖 bug +- uni-card 重构插槽的用法 ,header 替换为 title +- uni-card 新增 actions 插槽 +- uni-card 新增 cover 封面图属性和插槽 +- uni-card 新增 padding 内容默认内边距离 +- uni-card 新增 margin 卡片默认外边距离 +- uni-card 新增 spacing 卡片默认内边距 +- uni-card 新增 shadow 卡片阴影属性 +- uni-card 取消 mode 属性,可使用组合插槽代替 +- uni-card 取消 note 属性 ,使用actions插槽代替 +- uni-collapse 优化 show-arrow 属性默认为true +- uni-collapse 新增 show-arrow 属性,控制是否显示右侧箭头 +- uni-countdown 新增 font-size 支持自定义字体大小 +- uni-data-checkbox 修复 在uni-forms中 modelValue 中不存在当前字段,当前字段必填写也不参与校验的问题 +- uni-data-checkbox 修复 单选 list 模式下 ,icon 为 left 时,选中图标不显示的问题 +- uni-data-checkbox 修复 在 uni-forms 中重置表单,错误信息无法清除的问题 +- uni-dateformat 优化 默认时间不再是当前时间,而是显示'-'字符 +- uni-datetime-picker 修复 hide-second 在移动端的 bug +- uni-datetime-picker 修复 单选赋默认值时,赋值日期未高亮的 bug +- uni-datetime-picker 修复 赋默认值时,移动端未正确显示时间的 bug +- uni-datetime-picker 新增 hide-second 属性,支持只使用时分,隐藏秒 +- uni-datetime-picker 优化 取消选中时(范围选)直接开始下一次选择, 避免多点一次 +- uni-datetime-picker 优化 移动端支持清除按钮,同时支持通过 ref 调用组件的 clear 方法 +- uni-datetime-picker 优化 调整字号大小,美化日历界面 +- uni-datetime-picker 优化 范围选择器在 pc 端过宽的问题 +- uni-datetime-picker 新增 支持作为 uni-forms 子组件相关功能 +- uni-datetime-picker 修复 在 uni-forms 中使用时,选择时间报 NAN 错误的 bug +- uni-datetime-picker 修复 type 属性动态赋值无效的 bug +- uni-datetime-picker 修复 ‘确认’按钮被 tabbar 遮盖 bug +- uni-datetime-picker 修复 组件未赋值时范围选左、右日历相同的 bug +- uni-datetime-picker 修复 范围选未正确显示当前值的 bug +- uni-datetime-picker 修复 h5 平台(移动端)报错 'cale' of undefined 的 bug +- uni-easyinput 修复 在 uni-forms 的动态表单中默认值校验不通过的 bug +- uni-easyinput 修复 在 uni-forms 中重置表单,错误信息无法清除的问题 +- uni-file-picker 新增 参数中返回 fileID 字段 +- uni-file-picker 修复 腾讯云传入fileID 不能回显的bug +- uni-file-picker 修复 选择图片后,不能放大的问题 +- uni-file-picker 修复 由于 0.2.11 版本引起的不能回显图片的Bug +- uni-file-picker 新增 clearFiles(index) 方法,可以手动删除指定文件 +- uni-file-picker 修复 v-model 值设为 null 报错的Bug +- uni-file-picker 修复 return-type="object" 时,无法删除文件的Bug +- uni-file-picker 修复 auto-upload 属性失效的Bug +- uni-forms 修复 label 插槽不生效的bug +- uni-forms 修复 没有添加校验规则的字段依然报错的Bug +- uni-forms 修复 重置表单错误信息无法清除的问题 +- uni-forms 修复 表单验证只生效一次的问题 +- uni-icons 新增 更多图标 +- uni-icons 优化 自定义图标使用方式 +- uni-link 修复 在 nvue 下不显示的 bug +- uni-pagination 修复 current 、value 属性未监听,导致高亮样式失效的 bug +- uni-rate 优化 默认值修改为 0 颗星 +- uni-search-bar 修复 value 属性与 modelValue 属性不兼容的Bug +- uni-swipe-action 新增 close-all 方法,关闭所有已打开的组件 +- uni-swipe-action 新增 resize() 方法,在非微信小程序、h5、app-vue端出现不能滑动的问题的时候,重置组件 +- uni-swipe-action 修复 app 端偶尔出现类似 Page[x][-x,xx;-x,xx,x,x-x] 的问题 +- uni-swipe-action 优化 微信小程序、h5、app-vue 滑动逻辑,避免出现动态新增组件后不能滑动的问题 +- uni-tag 新增 提供组件设计资源,组件样式调整 +- uni-tag 移除 插槽 +- uni-tag 移除 type 属性的 royal 选项 +- uni-tag type 不是 default 时,size 为 small 字体大小显示不正确 +## 1.4.2(2021-08-20) +- 新增 uni-ui 组件支持国际化 i18n +- uni-collapse 优化 show-arrow 属性默认为true +- uni-collapse 新增 show-arrow 属性,控制是否显示右侧箭头 +- uni-data-checkbox 修复 单选 list 模式下 ,icon 为 left 时,选中图标不显示的问题 +- uni-easyinput 修复 在 uni-forms 的动态表单中默认值校验不通过的 bug +- uni-file-picker 修复 由于 0.2.11 版本引起的不能回显图片的Bug +- uni-file-picker 新增 clearFiles(index) 方法,可以手动删除指定文件 +- uni-file-picker 修复 v-model 值设为 null 报错的Bug +- uni-swipe-action 新增 close-all 方法,关闭所有已打开的组件 +- uni-swipe-action 新增 resize() 方法,在非微信小程序、h5、app-vue端出现不能滑动的问题的时候,重置组件 +- uni-swipe-action 修复 app 端偶尔出现类似 Page[x][-x,xx;-x,xx,x,x-x] 的问题 +- uni-swipe-action 优化 微信小程序、h5、app-vue 滑动逻辑,避免出现动态新增组件后不能滑动的问题 +## 1.4.0(2021-08-13) +- uni-calendar 修复 弹出层被 tabbar 遮盖 bug +- uni-data-checkbox 修复 在 uni-forms 中重置表单,错误信息无法清除的问题 +- uni-dateformat 调整 默认时间不再是当前时间,而是显示'-'字符 +- uni-datetime-picker 新增 适配 vue3 +- uni-datetime-picker 新增 支持作为 uni-forms 子组件相关功能 +- uni-datetime-picker 修复 在 uni-forms 中使用时,选择时间报 NAN 错误的 bug +- uni-datetime-picker 修复 type 属性动态赋值无效的 bug +- uni-datetime-picker 修复 ‘确认’按钮被 tabbar 遮盖 bug +- uni-datetime-picker 修复 组件未赋值时范围选左、右日历相同的 bug +- uni-datetime-picker 修复 范围选未正确显示当前值的 bug +- uni-datetime-picker 修复 h5 平台(移动端)报错 'cale' of undefined 的 bug +- uni-easyinput 修复 在 uni-forms 中重置表单,错误信息无法清除的问题 +- uni-file-picker 修复 return-type="object" 时,无法删除文件的Bug +- uni-file-picker 修复 auto-upload 属性失效的Bug +- uni-forms 修复 没有添加校验规则的字段依然报错的Bug +- uni-forms 修复 重置表单错误信息无法清除的问题 +- uni-forms 优化 组件文档 +- uni-forms 修复 表单验证只生效一次的问题 +- uni-tag type 不是 default 时,size 为 small 字体大小显示不正确 +## 1.3.9(2021-08-02) +- uni-datetime-picker 新增 return-type 属性支持返回 date 日期对象 +- uni-file-picker 修复 fileExtname属性不指定值报错的Bug +- uni-file-picker 修复 在某种场景下图片不回显的Bug +- uni-link 支持自定义插槽 +## 1.3.8(2021-07-31) +- uni-ui 组件兼容 vue3 +- uni-collapse 修复 由1.2.0版本引起的 change 事件返回 undefined 的Bug +- uni-collapse 优化 组件示例 +- uni-collapse 新增 组件折叠动画 +- uni-collapse 新增 value\v-model 属性 ,动态修改面板折叠状态 +- uni-collapse 新增 title 插槽 ,可定义面板标题 +- uni-collapse 新增 border 属性 ,显示隐藏面板内容分隔线 +- uni-collapse 新增 title-border 属性 ,显示隐藏面板标题分隔线 +- uni-collapse 修复 resize 方法失效的Bug +- uni-collapse 修复 change 事件返回参数不正确的Bug +- uni-collapse 优化 H5、App 平台自动更具内容更新高度,无需调用 reszie() 方法 +- uni-data-checkbox 优化 在uni-forms组件,与label不对齐的问题 +- uni-data-checkbox 修复 单选默认值为0不能选中的Bug +- uni-easyinput 优化 errorMessage 属性支持 Boolean 类型 +- uni-file-picker 修复 return-type为object下,返回值不正确的Bug +- uni-file-picker 修复(重要) H5 平台下如果和uni-forms组件一同使用导致页面卡死的问题 +- uni-file-picker 优化 h5平台下上传文件导致页面卡死的问题 +- uni-forms 修复 vue2 下条件编译导致destroyed生命周期失效的Bug +- uni-forms 修复 1.2.1 引起的示例在小程序平台报错的Bug +- uni-forms 修复 动态校验表单,默认值为空的情况下校验失效的Bug +- uni-forms 修复 不指定name属性时,运行报错的Bug +- uni-forms 优化 label默认宽度从65调整至70,使required为true且四字时不换行 +- uni-forms 优化 组件示例,新增动态校验示例代码 +- uni-forms 优化 组件文档,使用方式更清晰 +- uni-list 修复 与其他组件嵌套使用时,点击失效的Bug +- uni-swipe-action 修复 跨页面修改组件数据 ,导致不能滑动的问题 +## 1.3.7(2021-07-16) +- uni-ui 兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +- uni-datetime-picker 修复 单选日期类型,初始赋值后不在当前日历的 bug +- uni-datetime-picker 新增 clearIcon 属性,显示框的清空按钮可配置显示隐藏(仅 pc 有效) +- uni-datetime-picker 优化 移动端移除显示框的清空按钮,无实际用途 +- uni-datetime-picker 修复 组件赋值为空,界面未更新的 bug +- uni-datetime-picker 修复 start 和 end 不能动态赋值的 bug +- uni-datetime-picker 修复 范围选类型,用户选择后再次选择右侧日历(结束日期)显示不正确的 bug +## 1.3.6(2021-07-09) +- uni-data-checkbox 优化 删除无用日志 +- uni-data-checkbox 修复 由 0.1.9 引起的非 nvue 端图标不显示的问题 +- uni-data-checkbox 修复 nvue 黑框样式问题 +- uni-datetime-picker 修复 范围选择不能动态赋值的 bug +- uni-datetime-picker 修复 范围选择的初始时间在一个月内时,造成无法选择的bug +- uni-datetime-picker 优化 弹出层在超出视窗边缘定位不准确的问题 +- uni-datetime-picker 修复 范围起始点样式的背景色与今日样式的字体前景色融合,导致日期字体看不清的 bug +- uni-datetime-picker 优化 弹出层在超出视窗边缘被遮盖的问题 +- uni-datetime-picker 新增 maskClick 事件 +- uni-datetime-picker 修复 特殊情况日历 rpx 布局错误的 bug,rpx -> px +- uni-datetime-picker 修复 范围选择时清空返回值不合理的bug,['', ''] -> [] +- uni-datetime-picker 新增 日期时间显示框支持插槽 +- uni-file-picker 修复 sourceType 缺少默认值导致 ios 无法选择文件 +- uni-file-picker 优化 解耦与uniCloud的强绑定关系 ,如不绑定服务空间,默认autoUpload为false且不可更改 +- uni-table 新增 uni-th 支持 date 日期筛选范围 +- uni-table 新增 uni-th 支持 range 筛选范围 +- uni-table 新增 uni-th 筛选功能 +## 1.3.5(2021-07-02) +- uni-card 优化 图文卡片无图片加载时,提供占位图标 +- uni-card 新增 header 插槽,自定义卡片头部( 图文卡片 mode="style" 时,不支持) +- uni-card 修复 thumbnail 不存在仍然占位的 bug +- uni-data-checkbox 修复 selectedTextColor 属性不生效的Bug +- uni-datetime-picker 优化 添加 uni-icons 依赖 +- uni-easyinput 修复 confirmType 属性(仅 type="text" 生效)导致多行文本框无法换行的 bug +- uni-file-picker 修复 由 0.0.10 版本引发的 returnType 属性失效的问题 +- uni-file-picker 优化 文件上传后进度条消失时机 +- uni-file-picker 修复 在uni-forms 中,删除文件 ,获取的值不对的Bug +- uni-forms 修复 pattern 属性在微信小程序平台无效的问题 +## 1.3.4(2021-06-25) +- uni-badge 优化 示例项目 +- uni-countdown 修复 uni-countdown 重复赋值跳两秒的 bug +- uni-easyinput 修复 passwordIcon 属性拼写错误的 bug +- uni-forms 修复 validate-trigger属性为submit且err-show-type属性为toast时不能弹出的Bug +- uni-forms 修复 只写setRules方法而导致校验不生效的Bug +- uni-forms 修复 由上个办法引发的错误提示文字错位的Bug +- uni-forms 修复 不设置 label 属性 ,无法设置label插槽的问题 +- uni-forms 修复 不设置label属性,label-width属性不生效的bug +- uni-forms 修复 setRules 方法与rules属性冲突的问题 +- uni-link 新增 download 属性,H5平台下载文件名 +- uni-popup 新增 mask-click 遮罩层点击事件 +- uni-popup 修复 nvue 平台中间弹出后,点击内容,再点击遮罩无法关闭的Bug +- uni-tag 修复 uni-tag 在字节跳动小程序上 css 类名编译错误的 bug +## 1.3.3(2021-06-18) +- uni-easyinput 新增 passwordIcon 属性,当type=password时是否显示小眼睛图标 +- uni-easyinput 修复 confirmType 属性不生效的问题 +- uni-easyinput 修复 disabled 状态可清出内容的 bug +- uni-file-picker 修复 删除文件时无法触发 v-model 的Bug +- uni-popup 修复 H5平台中间弹出后,点击内容,再点击遮罩无法关闭的Bug +- uni-popup 修复 错误的 watch 字段 +- uni-popup 修复 safeArea 属性不生效的问题 +- uni-popup 修复 点击内容,再点击遮罩无法关闭的Bug +## 1.3.2(2021-06-04) +- uni-data-checkbox 新增 map 属性,可以方便映射text/value属性 +- uni-data-checkbox 修复 不关联服务空间的情况下组件报错的Bug +- uni-data-picker 修复 上个版本引出的本地数据无法选择带有children的2级节点 +- uni-forms 修复 动态删减数据导致报错的问题 +- uni-forms 新增 modelValue 属性 ,value 即将废弃 +- uni-forms 新增 uni-forms-item 可以设置单独的 rules +- uni-forms 新增 validate 事件增加 keepitem 参数,可以选择那些字段不过滤 +- uni-forms 优化 submit 事件重命名为 validate +- uni-data-picker 修复 无法加载云端数据的问题 +- uni-data-picker 修复 v-model无效问题 +- uni-data-picker 修复 loaddata 为空数据组时加载时间过长问题 +- uni-datetime-picker 修复 图标在小程序上不显示的 bug +- uni-datetime-picker 优化 重命名引用组件,避免潜在组件命名冲突 +- uni-datetime-picker 优化 代码目录扁平化 +- uni-tag 修复 未定义 sass 变量 "$uni-color-royal" 的bug +## 1.3.1(2021-05-14) +- uni-badge 新增 uni-badge 的 absolute 属性,支持定位 +- uni-badge 新增 uni-badge 的 offset 属性,支持定位偏移 +- uni-badge 新增 uni-badge 的 is-dot 属性,支持仅显示有一个小点 +- uni-badge 新增 uni-badge 的 max-num 属性,支持自定义封顶的数字值,超过 99 显示99+ +- uni-badge 优化 uni-badge 属性 custom-style, 支持以对象形式自定义样式 +- uni-badge 修复 uni-badge 在 App 端,数字小于10时不是圆形的bug +- uni-badge 修复 uni-badge 在父元素不是 flex 布局时,宽度缩小的bug +- uni-badge 新增 uni-badge 属性 custom-style, 支持自定义样式 +- uni-datetime-picker 修复 ios 下不识别 '-' 日期格式的 bug +- uni-datetime-picker 优化 pc 下弹出层添加边框和阴影 +- uni-datetime-picker 修复 在 admin 中获取弹出层定位错误的bug +- uni-datetime-picker 修复 type 属性向下兼容,默认值从 date 变更为 datetime +- uni-datetime-picker 支持日历形式的日期+时间的范围选择 +- uni-steps 修复 uni-steps 横向布局时,多行文字高度不合理的 bug +- uni-countdown 修复 uni-countdown 不能控制倒计时的 bug +- uni-tag 修复 royal 类型无效的bug +- uni-tag 修复 uni-tag 宽度不自适应的bug +- uni-tag 新增 uni-tag 支持属性 custom-style 自定义样式 +- uni-link 新增 href 属性支持 tel:|mailto: +- uni-popup 修复 组件内放置 input 、textarea 组件,无法聚焦的问题 +- uni-popup 新增 type 属性的 left\right 值,支持左右弹出 +- uni-popup 新增 open(String:type) 方法参数 ,可以省略 type 属性 ,直接传入类型打开指定弹窗 +- uni-popup 新增 backgroundColor 属性,可定义主窗口背景色,默认不显示背景色 +- uni-popup 新增 safeArea 属性,是否适配底部安全区 +- uni-popup 修复 App\h5\微信小程序底部安全区占位不对的Bug +- uni-popup 修复 App 端弹出等待的Bug +- uni-popup 优化 提升低配设备性能,优化动画卡顿问题 +- uni-popup 优化 更简单的组件自定义方式 +- uni-table 修复 示例项目缺少组件的Bug +- uni-forms 修复 自定义检验器失效的问题 +- uni-title 修复 示例项目缺少组件的Bug +- uni-transition 修复 示例项目缺少组件的Bug +- uni-swiper-dot 修复 示例项目缺少组件的Bug +- uni-ui 新增 组件示例地址 +## 1.3.0(2021-04-23) +- uni-combox 优化 添加依赖 uni-icons, 导入后自动下载依赖 +- uni-data-picker 修复 非树形数据有 where 属性查询报错的问题 +- uni-fav 优化 添加依赖 uni-icons, 导入后自动下载依赖 +- uni-goods-nav 优化 添加依赖 uni-icons, 导入后自动下载依赖 +- uni-nav-bar 优化 添加依赖 uni-icons, 导入后自动下载依赖 +- uni-notice-bar 优化 添加依赖 uni-icons, 导入后自动下载依赖 +- uni-number-box 修复 uni-number-box 浮点数运算不精确的 bug +- uni-number-box 修复 uni-number-box change 事件触发不正确的 bug +- uni-number-box 新增 uni-number-box v-model 双向绑定 +- uni-rate 修复 布局变化后 uni-rate 星星计算不准确的 bug +- uni-rate 优化 添加依赖 uni-icons, 导入 uni-rate 自动下载依赖 +- uni-search-bar 优化 添加依赖 uni-icons, 导入后自动下载依赖 +- uni-steps 优化 添加依赖 uni-icons, 导入后自动下载依赖 +- uni-transition 新增 通过方法自定义动画 +- uni-transition 新增 custom-class 非 NVUE 平台支持自定义 class 定制样式 +- uni-transition 优化 动画触发逻辑,使动画更流畅 +- uni-transition 优化 支持单独的动画类型 +- uni-transition 优化 文档示例 +## 1.2.13(2021-04-16) +- uni-ui 新增 uni-data-picker 支持云端非树形表结构数据 +- uni-ui 修复 uni-data-checkbox nvue 下无法选中的问题 +- uni-ui 修复 uni-data-picker 根节点 parent_field 字段等于null时选择界面错乱问题 +- uni-ui 修复 uni-file-picker 选择的文件非 file-extname 字段指定的扩展名报错的Bug +- uni-ui 修复 uni-swipe-action 报错 nv_navigator is not defined 的bug +- uni-ui 修复 uni-load-more 在首页使用时,h5 平台报 'uni is not defined' 的 bug +- uni-ui 优化 uni-file-picker file-extname 字段支持字符串写法,多个扩展名需要用逗号分隔 +- uni-ui 优化 uni-pagination PC 和 移动端适配不同的 ui +- uni-ui 更新 uni-file-picker 组件示例 +- uni-ui 修复 uni-nav-bar 当 fixed 属性为 true 时铺不满屏幕的 bug +- uni-ui 新增 uni-search-bar 的 focus 事件 +- uni-ui 修复 uni-rate 属性 margin 值为 string 组件失效的 bug +- uni-data-picker 修复 本地数据概率无法回显时问题 +- uni-table 新增 sortable 属性,是否开启单列排序 +- uni-table 优化 表格多选逻辑 +## 1.2.12(2021-03-23) +- uni-ui 新增 uni-datetime-picker 的 hide-second 属性、border 属性; +- uni-ui 修复 uni-datetime-picker 选择跟显示的日期不一样的 bug, +- uni-ui 修复 uni-datetime-picker change事件触发2次的 bug +- uni-ui 修复 uni-datetime-picker 分、秒 end 范围错误的 bug +- uni-ui 新增 uni-tr selectable 属性,用于 type=selection 时,设置某行是否可由全选按钮控制 +- uni-ui 新增 uni-data-checkbox 新增 disabled属性,支持nvue +- uni-ui 优化 uni-data-checkbox 无选项时提示“暂无数据” +- uni-ui 优化 uni-data-checkbox 默认颜色显示 +- uni-ui 新增 uni-link href 属性支持 tel:|mailto: +- uni-ui 新增 uni-table 示例demo +- uni-ui 修复 uni-data-picker 微信小程序某些情况下无法选择的问题,事件无法触发的问题 +- uni-ui 修复 uni-nav-bar easycom 下,找不到 uni-status-bar 的bug +- uni-ui 修复 uni-easyinput 示例在 qq 小程序上的bug +- uni-ui 修复 uni-forms 动态显示uni-forms-item的情况下,submit 方法获取值错误的Bug +- uni-ui 调整 cli 项目 建议使用 easycom 方式引用组件,如使用按需引用,需手动维护组件内部引用 + +## 1.2.11(2021-02-24) +- 调整为uni_modules目录规范 +- uni-data-picker 新增 数据驱动的picker选择器 +- uni-file-picker 新增 文件选择上传 +- uni-row 新增 栅格系统 +- uni-data-checkbox 优化 支持 nvue +- uni-forms 修复 偶发性获取表单值错误的Bug +- uni-forms 修复 校验 uni-data-picker value 为 0 时,返回值错误的Bug +- uni-forms 修复 uni-forms-item 组件隐藏时依然触发校验的bug +- uni-forms 优化 实时校验 +- uni-forms 优化 兼容nvue页面 +- uni-easyinput 优化 兼容nvue页面 +- uni-group 优化 兼容nvue页面 +- uni-popup 优化 组件适配 PC +- uni-fab 优化 适配 PC +- uni-swiper-dot 优化 适配 PC +- uni-rate 优化 适配 PC +- uni-notice-bar 优化 适配 PC +- uni-indexed-list 优化 适配 PC +- uni-combox 优化 适配 PC +- uni-transition 优化 适配 PC +- uni-nav-bar 优化 适配 PC +- uni-swipe-action 优化 适配 PC diff --git a/uni_modules/uni-ui/components/uni-ui/uni-ui.vue b/uni_modules/uni-ui/components/uni-ui/uni-ui.vue new file mode 100644 index 0000000..0970892 --- /dev/null +++ b/uni_modules/uni-ui/components/uni-ui/uni-ui.vue @@ -0,0 +1,7 @@ + + + diff --git a/uni_modules/uni-ui/package.json b/uni_modules/uni-ui/package.json new file mode 100644 index 0000000..857ed51 --- /dev/null +++ b/uni_modules/uni-ui/package.json @@ -0,0 +1,129 @@ +{ + "id": "uni-ui", + "displayName": "uni-ui", + "version": "1.4.27", + "description": "uni-ui 是基于uni-app的、全端兼容的、高性能UI框架", + "keywords": [ + "uni-ui", + "uniui", + "UI组件库", + "ui框架", + "ui库" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.2.10" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [ + "uni-badge", + "uni-calendar", + "uni-card", + "uni-collapse", + "uni-combox", + "uni-countdown", + "uni-data-checkbox", + "uni-data-picker", + "uni-data-select", + "uni-dateformat", + "uni-datetime-picker", + "uni-drawer", + "uni-easyinput", + "uni-fab", + "uni-fav", + "uni-file-picker", + "uni-forms", + "uni-goods-nav", + "uni-grid", + "uni-group", + "uni-icons", + "uni-indexed-list", + "uni-link", + "uni-list", + "uni-load-more", + "uni-nav-bar", + "uni-notice-bar", + "uni-number-box", + "uni-pagination", + "uni-popup", + "uni-rate", + "uni-row", + "uni-search-bar", + "uni-section", + "uni-segmented-control", + "uni-steps", + "uni-swipe-action", + "uni-swiper-dot", + "uni-table", + "uni-tag", + "uni-title", + "uni-tooltip", + "uni-transition" + ], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-ui/readme.md b/uni_modules/uni-ui/readme.md new file mode 100644 index 0000000..23f8456 --- /dev/null +++ b/uni_modules/uni-ui/readme.md @@ -0,0 +1,247 @@ +> 当前插件不包含示例页面 ,如需示例请在 HBuiderX 中新建 `hello uni-app > 扩展组件` 中查看 +> +> 代码示例地址 :[https://ext.dcloud.net.cn/plugin?id=4941](https://ext.dcloud.net.cn/plugin?id=4941) +> +> 组件演示地址:[https://hellouniapp.dcloud.net.cn](https://hellouniapp.dcloud.net.cn/pages/extUI/badge/badge) +> +> 组件文档地址:[https://uniapp.dcloud.io/component/uniui/uni-ui](https://uniapp.dcloud.io/component/uniui/uni-ui) + +# uni-ui 介绍 + +## uni-ui产品特点 + +### 1. 高性能 + +目前为止,在小程序和混合app领域,暂时还没有比 `uni-ui` 更高性能的框架。 +- 自动差量更新数据 + +虽然uni-app支持小程序自定义组件,所有小程序的ui库都可以用。但小程序自定义组件的ui库都需要使用setData手动更新数据,在大数据量时、或高频更新数据时,很容易产生性能问题。 + +而 `uni-ui` 属于vue组件,uni-app引擎底层自动diff更新数据。当然其实插件市场里众多vue组件都具备这个特点。 +- 优化逻辑层和视图层通讯折损 + +非H5,不管是小程序还是App,不管是app的webview渲染还是原生渲染,全都是逻辑层和视图层分离的。这里就有一个逻辑层和视图层通讯的折损问题。 +比如在视图层拖动一个可跟手的组件,由于通讯的损耗,用js监听很难做到实时跟手。 + +这时就需要使用css动画以及平台底层提供的wxs、bindingx等技术。不过这些技术都比较复杂,所以 `uni-ui` 里做了封装,在需要跟手式操作的ui组件,比如swiperaction列表项左滑菜单,就在底层使用了这些技术,实现了高性能的交互体验 +- 背景停止 + +很多ui组件是会一直动的,比如轮播图、跑马灯。即便这个窗体被新窗体挡住,它在背景层仍然在消耗着硬件资源。在Android的webview版本为chrome66以上,背景操作ui会引发很严重的性能问题,造成前台界面明显卡顿。 + +而 `uni-ui` 的组件,会自动判断自己的显示状态,在组件不再可见时,不会再消耗硬件资源。 + +### 2. 全端 + + `uni-ui` 的组件都是多端自适应的,底层会抹平很多小程序平台的差异或bug。 + +比如导航栏navbar组件,会自动处理不同端的状态栏。 +比如swiperaction组件,在app和微信小程序上会使用交互体验更好的wxs技术,但在不支持wxs的其他小程序端会使用js模拟类似效果。 + + `uni-ui` 还支持nvue原生渲染,[详见](https://github.com/dcloudio/uni-ui/tree/nvue-uni-ui) + +未来 `uni-ui` 还会支持pc等大屏设备。 + +### 3. 与uni统计自动集成实现免打点 + +uni统计是优秀的多端统计平台,见[tongji.dcloud.net.cn](https://tongji.dcloud.net.cn)。 + +除了一张报表看全端,它的另一个重要特点是免打点。 +比如使用 `uni-ui` 的navbar标题栏、收藏、购物车等组件,均可实现自动打点,统计页面标题等各种行为数据。 +当然你也可以关闭uni统计,这不是强制的。 + +### 4. 主题扩展 + + `uni-ui` 支持[uni.scss](https://uniapp.dcloud.io/collocation/uni-scss),可以方便的切换App的风格。 + +ui是一种需求非常发散的产品,DCloud官方也无意用 `uni-ui` 压制第三方ui插件的空间,但官方有义务在性能和多端方面提供一个开源的标杆给大家。 + +我们欢迎更多优秀的ui组件出现,也欢迎更多人贡献 `uni-ui` 的主题风格,满足更多用户的需求。 + + +## 快速开始 + +uni-ui支持 HBuilderX直接新建项目模板、npm安装和单独导入个别组件等多种使用方式 + +### 在HBuilderX 新建uni-app项目的模板中,选择uni-ui模板 +![HBuilderX内创建uni-ui项目](https://img.cdn.aliyun.dcloud.net.cn/uni-app/doc/create-uni-ui-project.jpg) + +由于uni-app独特的[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)技术,可以免引用、注册,直接使用各种符合规则的vue组件。 + +在代码区键入`u`,拉出各种内置或uni-ui的组件列表,选择其中一个,即可使用该组件。 + +光标放在组件名称上,按F1,可以查阅组件的文档。 + +![uni-ui代码块](https://img.cdn.aliyun.dcloud.net.cn/uni-app/doc/uni-ui-snippet.jpg) + +### 通过 uni_modules 单独安装组件 +如果你没有创建uni-ui项目模板,也可以在你的工程里,通过 uni_modules 单独安装需要的某个组件。下表为uni-ui的扩展组件清单,点击每个组件在详情页面可以导入组件到项目下,导入后直接使用即可,无需import和注册。 + +|组件名|组件说明| +|---|---| +|uni-badge|[数字角标](https://ext.dcloud.net.cn/plugin?name=uni-badge)| +|uni-calendar|[日历](https://ext.dcloud.net.cn/plugin?name=uni-calendar)| +|uni-card|[卡片](https://ext.dcloud.net.cn/plugin?name=uni-card)| +|uni-collapse|[折叠面板](https://ext.dcloud.net.cn/plugin?name=uni-collapse)| +|uni-combox|[组合框](https://ext.dcloud.net.cn/plugin?name=uni-combox)| +|uni-countdown|[倒计时](https://ext.dcloud.net.cn/plugin?name=uni-countdown)| +|uni-data-checkbox|[数据选择器](https://ext.dcloud.net.cn/plugin?name=uni-data-checkbox)| +|uni-data-picker|[数据驱动的picker选择器](https://ext.dcloud.net.cn/plugin?name=uni-data-picker)| +|uni-dateformat|[日期格式化](https://ext.dcloud.net.cn/plugin?name=uni-dateformat)| +|uni-datetime-picker|[日期选择器](https://ext.dcloud.net.cn/plugin?name=uni-datetime-picker)| +|uni-drawer|[抽屉](https://ext.dcloud.net.cn/plugin?name=uni-drawer)| +|uni-easyinput|[增强输入框](https://ext.dcloud.net.cn/plugin?name=uni-easyinput)| +|uni-fab|[悬浮按钮](https://ext.dcloud.net.cn/plugin?name=uni-fab)| +|uni-fav|[收藏按钮](https://ext.dcloud.net.cn/plugin?name=uni-fav)| +|uni-file-picker|[文件选择上传](https://ext.dcloud.net.cn/plugin?name=uni-file-picker)| +|uni-forms|[表单](https://ext.dcloud.net.cn/plugin?name=uni-forms)| +|uni-goods-nav|[商品导航](https://ext.dcloud.net.cn/plugin?name=uni-goods-nav)| +|uni-grid|[宫格](https://ext.dcloud.net.cn/plugin?name=uni-grid)| +|uni-group|[分组](https://ext.dcloud.net.cn/plugin?name=uni-group)| +|uni-icons|[图标](https://ext.dcloud.net.cn/plugin?name=uni-icons)| +|uni-indexed-list|[索引列表](https://ext.dcloud.net.cn/plugin?name=uni-indexed-list)| +|uni-link|[超链接](https://ext.dcloud.net.cn/plugin?name=uni-link)| +|uni-list|[列表](https://ext.dcloud.net.cn/plugin?name=uni-list)| +|uni-load-more|[加载更多](https://ext.dcloud.net.cn/plugin?name=uni-load-more)| +|uni-nav-bar|[自定义导航栏](https://ext.dcloud.net.cn/plugin?name=uni-nav-bar)| +|uni-notice-bar|[通告栏](https://ext.dcloud.net.cn/plugin?name=uni-notice-bar)| +|uni-number-box|[数字输入框](https://ext.dcloud.net.cn/plugin?name=uni-number-box)| +|uni-pagination|[分页器](https://ext.dcloud.net.cn/plugin?name=uni-pagination)| +|uni-popup|[弹出层](https://ext.dcloud.net.cn/plugin?name=uni-popup)| +|uni-rate|[评分](https://ext.dcloud.net.cn/plugin?name=uni-rate)| +|uni-row|[布局-行](https://ext.dcloud.net.cn/plugin?name=uni-row)| +|uni-search-bar|[搜索栏](https://ext.dcloud.net.cn/plugin?name=uni-search-bar)| +|uni-segmented-control|[分段器](https://ext.dcloud.net.cn/plugin?name=uni-segmented-control)| +|uni-steps|[步骤条](https://ext.dcloud.net.cn/plugin?name=uni-steps)| +|uni-swipe-action|[滑动操作](https://ext.dcloud.net.cn/plugin?name=uni-swipe-action)| +|uni-swiper-dot|[轮播图指示点](https://ext.dcloud.net.cn/plugin?name=uni-swiper-dot)| +|uni-table|[表格](https://ext.dcloud.net.cn/plugin?name=uni-table)| +|uni-tag|[标签](https://ext.dcloud.net.cn/plugin?name=uni-tag)| +|uni-title|[章节标题](https://ext.dcloud.net.cn/plugin?name=uni-title)| +|uni-transition|[过渡动画](https://ext.dcloud.net.cn/plugin?name=uni-transition)| + + +使用 `uni_modules` 方式安装组件库,可以直接通过插件市场导入,通过右键菜单快速更新组件,不需要引用、注册,直接在页面中使用 `uni-ui` 组件。[点击安装 uni-ui 组件库](https://ext.dcloud.net.cn/plugin?id=55) + +**注意:下载最新的组件目前仅支持 uni_modules ,非 uni_modules 版本最高支持到组件的1.2.10版本** + +如不能升级到 `uni_modules` 版本,可以使用 `uni_modules` 安装好对应组件,将组件拷贝到对应目录。 + +例如需更新 `uni-list`和`uni-badge` ,将 `uni_modules>uni-list>components`和`uni_modules>uni-badege>components`下所有目录拷贝到如下目录即可: + + +**目录示例** + +```json +┌─components 组件目录 +│ ├─uni-list list 列表目录 +│ │ └─uni-list.vue list 组件文件 +│ ├─uni-list-item list-item 列表目录 +│ │ └─uni-list-item.vue list 组件文件 +│ ├─uni-badge badge 角标目录 +│ │ └─uni-badge.vue badge 组件文件 +│ └─ //.... 更多组件文件 +├─pages 业务页面文件存放的目录 +│ ├─index +│ │ └─index.vue index示例页面 +├─main.js Vue初始化入口文件 +├─App.vue 应用配置,用来配置App全局样式以及监听 应用生命周期 +├─manifest.json 配置应用名称、appid、logo、版本等打包信息,详见 +└─pages.json 配置页 + +``` + +### 通过 `uni_modules` 导入全部组件 +如果想一次把所有uni-ui组件导入到项目中,只需要导入一个 `uni-ui` 组件即可 [点击去导入](https://ext.dcloud.net.cn/plugin?id=55)。 + +如果没有自动导入其他组件,可以在 uni-ui 组件目录上右键选择 `安装三方插件依赖` 即可。 + + + +### npm安装 +在 `vue-cli` 项目中可以使用 `npm` 安装 `uni-ui` 库 ,或者直接在 `HBuilderX` 项目中使用 `npm` 。 + +> **注意** +> cli 项目默认是不编译 `node_modules` 下的组件的,导致条件编译等功能失效 ,导致组件异常 +> 需要在根目录创建 `vue.config.js` 文件 ,增加 `@dcloudio/uni-ui` 包的编译即可正常 +> ```javascript +> // vue.config.js +> module.exports = { +> transpileDependencies:['@dcloudio/uni-ui'] +> } +> ``` + + + +**准备 sass** + +`vue-cli` 项目请先安装 sass 及 sass-loader,如在 HBuliderX 中使用,可跳过此步。 + +- 安装 sass +``` + npm i sass -D 或 yarn add sass -D +``` + +- 安装 sass-loader +``` +npm i sass-loader@10.1.1 -D 或 yarn add sass-loader@10.1.1 -D +``` + +> 如果 `node` 版本小于 16 ,sass-loader 请使用低于 @11.0.0 的版本,[sass-loader@11.0.0 不支持 vue@2.6.12 ](https://stackoverflow.com/questions/66082397/typeerror-this-getoptions-is-not-a-function) +> 如果 `node` 版本大于 16 , `sass-loader` 建议使用 `v8.x` 版本 + +**安装 uni-ui** + +``` +npm i @dcloudio/uni-ui 或 yarn add @dcloudio/uni-ui +``` + + + +**配置easycom** + +使用 `npm` 安装好 `uni-ui` 之后,需要配置 `easycom` 规则,让 `npm` 安装的组件支持 `easycom` + +打开项目根目录下的 `pages.json` 并添加 `easycom` 节点: + +```javascript +// pages.json +{ + "easycom": { + "autoscan": true, + "custom": { + // uni-ui 规则如下配置 + "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue" + } + }, + + // 其他内容 + pages:[ + // ... + ] +} + +``` + +在 ``template`` 中使用组件: + +```html + + + +``` + + **注意** + - uni-ui 现在只推荐使用 `easycom` ,如自己引用组件,可能会出现组件找不到的问题 + - 使用 npm 安装的组件,默认情况下 babel-loader 会忽略所有 node_modules 中的文件 ,导致条件编译失效,需要通过配置 `vue.config.js` 解决: + ```javascript + // 在根目录创建 vue.config.js 文件,并配置如下 + module.exports = { + transpileDependencies: ['@dcloudio/uni-ui'] + } + ``` + - uni-ui 是uni-app内置组件的扩展。注意与web开发不同,uni-ui不包括基础组件,它是基础组件的补充。web开发中有的开发者习惯用一个ui库完成所有开发,但在uni-app体系中,推荐开发者首先使用性能更高的基础组件,然后按需引入必要的扩展组件。 + - `uni-ui` 不支持使用 `Vue.use()` 的方式安装 + + +### 贡献代码 +在使用 `uni-ui` 中,如遇到无法解决的问题,请提 [Issues](https://github.com/dcloudio/uni-ui/issues) 给我们,假如您有更好的点子或更好的实现方式,也欢迎给我们提交 [PR](https://github.com/dcloudio/uni-ui/pulls) \ No newline at end of file diff --git a/uni_modules/uni-upgrade-center-app/changelog.md b/uni_modules/uni-upgrade-center-app/changelog.md new file mode 100644 index 0000000..c325c59 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/changelog.md @@ -0,0 +1,70 @@ +## 0.6.4(2023-09-01) +chore: 优化代码结构 +## 0.6.3(2023-08-30) +- 修复 下载 wgt 时如果后缀名不正确,重命名后安装 +## 0.6.2(2022-11-21) +- 处理 cloudfunctions 目录 +## 0.6.1(2022-08-17) +- 修复 后台添加应用市场,但都没有启用的情况下报错的Bug (需要 uni-admin 1.9.3+) +## 0.6.0(2022-07-19) +- 新增 支持多应用商店配置(需要 uni-admin 1.9.3+) +## 0.4.1(2022-05-27) +- 修复 上版引出的报错问题 +## 0.4.0(2022-05-27) +- 新增 Android 支持跳转手机自带商店,填写升级包地址时请填写跳转商店链接 +- 新增 改为云对象调用方式,使用更直观 +## 0.3.3(2022-04-14) +- 修复 调用 check-update,当 code 为 0 时没有回调 +## 0.3.2(2022-01-12) +- 优化显示逻辑 +## 0.3.1(2021-11-24) +- 修复 vue3 上图片不显示的Bug +## 0.3.0(2021-11-18) +- 移除 wgt 安装成功后提示,防止重启过快弹框不消失 +## 0.2.2(2021-08-25) +- 兼容vue3.0 +## 0.2.1(2021-07-26) +- 修复 使用腾讯云并手动填写地址时,导致下载链接失效的bug +## 0.2.0(2021-07-13) +- 更新文档 关于报错local_storage_key 为空,请不要将页面路径设置为pages.json中第一项 +## 0.1.9(2021-06-28) +- 更新文档 +- 修复 wgt安装失败时,按钮状态不对 +## 0.1.8(2021-06-16) +- 修复 跳转安装时,导致上次下载的apk还没安装就被删掉的bug +## 0.1.7(2021-06-03) +- 修改 移除static中的图片 +## 0.1.6(2021-06-03) +- 修改 下载更新按钮使用CSS渐变色 +## 0.1.5(2021-04-22) +- 更新check-update函数。现在返回一个Promise,有更新时成功回调,其他情况错误回调 +## 0.1.4(2021-04-13) +- 更新文档。明确云函数调用结果 +## 0.1.3(2021-04-13) +- 解耦云函数与弹框处理。utils中新增 call-check-version.js,可用于单独检测是否有更新 +## 0.1.2(2021-04-07) +- 更新版本对比函数 compare +## 0.1.1(2021-04-07) +- 修复 腾讯云空间下载链接不能下载问题 +## 0.1.0(2021-04-07) +- 新增使用uni.showModal提示升级示例 +- 修改iOS升级提示方式 +## 0.0.7(2021-04-02) +- 修复在iOS上打开弹框报错 +## 0.0.6(2021-04-01) +- 兼容旧版本安卓 +## 0.0.5(2021-04-01) +- 修复低版本安卓上进度条错位 +## 0.0.4(2021-04-01) +- 更新readme +- 修复check-update语法错误 +## 0.0.3(2021-04-01) +- 新增前台更新弹框,详见readme +- 更新前台检查更新方法 + +## 0.0.2(2021-03-29) +- 更新文档 +- 移除 dependencies + +## 0.0.1(2021-03-25) +- 升级中心前台检查更新 diff --git a/uni_modules/uni-upgrade-center-app/images/app_update_close.png b/uni_modules/uni-upgrade-center-app/images/app_update_close.png new file mode 100644 index 0000000000000000000000000000000000000000..8b2ffe62cba2466f184ea9f8ee4f9395ed8cf37a GIT binary patch literal 7644 zcmW+*c|26__rEhn2FcixeasB9m$8TJW(XnsS}~D*>|0GEg`{y&#=aM_WNg{;t%MrM zR*_IfA-jZ--+X?5+@pR+(K{8TTifB;0}k}>Oq8z4vlIM(7WOY@^h-h9wbias&+)N? zwXYu5JJjy4hl&lTTBQCagz!fd>-s67{xX4Ejdu5b!h@rt$t^bQ{#^gg!pt}=j=t=G z?J$`E{*9QMo$S1*5PkG`Rd1kK6k>eG#!$y+>E#wjTSC^E)nJ}$CLU*{wogNokkqYP zjM2g63c?@Wox@~0icoOif$eyiP5bD{RB3}#*H(-JI&v?-crMqC zv-J$MPkvBpszG?aJWYwGQUm=7dASo?9cL~owtVYIS9ke@S*j+x?X5&C#|NESvJ!{S4~ihlF2iKHk9k&#ZR5UNqG2qXsr1+_!kG zuQJOXegDsC0h?}n^v!yj0>1%n^*SL~ofar8+B`#@P@D4xLOc^AjPIeUMw>!M0s;s% zCfLU^yVcYL-k!Zh=f4HSb(mz;JSl7N)8pIzf4Kk+)r$mw6H5F;YM|bx zGws&fZkbZe#s%K61{EhVC7z7#&7)s1YmS%~Oh=%4)qrrFNmt1#yXTgsdhH8O<0C3?2d^{VkB z_&0}p=lmHGZYRM9LeBP0?Tokg36TnL}F+MsSQ`7L>^t*Ym8f2 z8uz(c4>#OIV$bPC7}GDrrKX-bKh*CCnj(;UuX##+hd?ZA3K@ z7!Vs=P9RiTCZyubEHTd&q&7N7!gG-r)?FK+*@fdCj9oj^La<2^hSPhUf%&Pl6atuO zjNN{7ZxLgFdwbnF?*1p~KTao!s5csXqmR55QTjwqv#eU)n&8UR1D&nU;Xz z#J@XaI+X>(D6y@)^78w8Q*c9DJ)imOGMFd}yQl?Ii-|II%JJ3Lwv`=czhs_+jH&&| z<*0p*xQ*d+QG~8Ij1BWqmO^7pmPl8f*Xl5X9dc_QJ4-5d)qqw9DLxLd!Y#jKE9(gziS@16FC!_Uk zH5S*>dWz9Ezg9KL)$-jgZwjr*76I)b3({RU123i)?T_a*p=Q6X%hvK@Y!Zy8*#&}% znSX?!DZ%3H$240N7hKTE=jPId6y3Rt*`taBzuCPlz(O%Ed~ML)|PyhO8z1y04c+K@HbIL}@i zs_jxf5ql@={i3%;YOQSu*FcMO+z05xR{j+;;ZWHz zjDa3{{-yq!Ym8Yw#|rrT5uB2?5<0}Pen(pS6WoATNBk{sNKK<`@RfdZA*<&$g#m^S zQ|?EH1Ftfce%)lM`w`r%ix;9va#bF&-o`gdxRq7 z>nssq>N`otKYDDz?Q00F)S2q`GP_L^o{$@@#=J!nbwLvvEXA5q6DnK=SEg|%6vVk{ zeP!NHZjrWTPkZ|5RRx~6y@$j!mnWb<6w3nv?q&5-76!#9p_m9Z!A;f!TOf9R2yBP# zrBVa=p7_1{j??xRHUBQl6LNx9&%wWC57aY@I}eHRSrphTs9vb#cw$?QJY&bK2tIa} zZf=rYm~gfULQs5H8yiP{%&X<|x%2hUejzg0A`5ei2Wwai;#bem1R=N+I|UXLZq2Aa z-FgG|)^uF8td6-B>n(dkNJgEW1j+Q9it2+*3>6u)-8M~+KhbT))(~Y|D`jI)Yy!jG zKq0U;Ew~|TcM~F<*G0F4QQ%3T**SR*O-Ow zo-}%{Q^X17nQ_6_;5ZBnYx*Q2%8$*qJV#!XQ-s41$mi+Q#ieg0h2FzmI0|!3pDbWo zYLtCT0ZwOyfHHX#HwxdD)!@>QYw9#RourwyKjIog6+bIR$ofzyrpS*lc~7T5GyXgv zu^}LUPIlYcogx<=L;mp6Ea8;G8x*_4aOPbMu|k(RSTRzMuh#+risVdiLoGiIWKXZ9 z^24<6leVfV>|e_aK|)5$?@E&U(H%N8Yp}{v=-ho@zo}USQb>hsM?0UB$5J zL84Tx%mPYcOBztjjtaJ__yYI~2*~dw8|!5EXGMO!Q&cyTJ_DfHFf3t=*``qVZu4BaZ8Suj;ZMh9mhi%PyTkR12L~evnXS~#viaqi+lknf&1ppKCF^L zn+_^YdE6j}wb;3q)vmk!FrqK96CfF?a9g2TP&Lu#sm2t4pD*7G2&Loa*^I=m z^%mQDtH1i{fGbMM=TZz%T1{({UQY<483>LUmUZYFhvDW1;m5fFCrHn=d(#8#8DE~f zE-sU6iP~>4CO!#Hd@y5Z8|D_404l_FxwSAu2bZ5A{DuM@46F9;ilH1_mn7b_$b(zI zg!PyrMp=bcpi>afNwRhrdc)2;d9zc5l&;UFEX23O1;jr_74*oKDRUZ};4;U!^$7vt zRc)9#SjK90c!TtSDZpsDEQz^#<&Y0xHyJ$b&$k)AC9?^I0$-@p%wj4(yiMqTD}dppFbsintvV9toa5gZ$Dv6_ z3x+Z(lbsYsNDU4b6B-5lREq0G$<7<~?&n}8ltent*yLU}dUHFDk7TW3A6!6GnQU)h zgurYrKAzJ(RmADF6G~n<*dHi7K6DJZotc!Kma;t2Js3VolC5ejsTCZ;VLtzu~}cIdR5K*-LBIHq*^h8D>& zDzNc=jjj-1=tN9x-pZh_on&9XKBbdR_m~&TliJ=%MaJb!I2YcQfxubK1HzWiIY+*^ z?e=`azXmN7D9bn{0s~XcBS_Z*ra5MpQ;`xX*a_APV8!h~t`N_6gE=|18JIGzBvC$T z;eih?8yJXZsD8mgx}Z`NAE5F=v2jWHqJpS#_Em1+rz*RbWZ!RJFw3?sD@epYgmOnoJvWJz(4A%oXb<`inTeH&G zJ7jn z)#Wjc<6be49`IVp{_yOrnPao`{Fm6bN{oIWl8*0-e!pUZDDYV1_Xj&!dS3X9 zwXWl_(wiQ@dmKcejBc3DuWvR&iSM8m{1}K#hVyEFPhclqTwbLAP%zz0V;7Ucn>r_n zs#OZ&W1eMb%rPbz};Czy5*CFkEu|S=yu;?%=`WQa$YMwgL0=GQ|moz z`TvDpM-`cYH;*;Y6$z4N2~%OjcI3I%*v)tsn2p<(m=60#81fZ}Qse2*SqNrZU!&Go zJ8NA}x5&QFD4UNQx1;x>`URNh`Ga*z$$n)4?@al!7UnEXZE!jHHknh4S3gxMbhYpw z1HTi&^ZIA+p)w$Ts-{@S+6bA5k!3weEHBQ=xx+Z3POwO0URc34_P!}bB2$3J(*DVq zB+)98OeK2H_2=MCoxVX-a(shcsG)Ndkn{T}W&ELcCL#x93MpQY2hVHJ@K!uGmB>>o z>@9l3Um`eHT-#9oU^%6%g323xuiXr`=V=Z5um(_$icyM43LZ2}Kl!Fu4lEy%*gi}` zDncdXv@?ymGQ)7M+uO~3$+t0ZT~FqFi}1fB0PpM8-JO! z@j&O5WQNPdkW7#Cm}{!Sc3|1{`5SvD&k%(?lE1M86LREe^cPshZCwmu=Mi zAisxE*#3=JZ05BMe*4TrNd5?Ml+80fwHj~Z5D+TNppasv z($T8Qr6T=TZbwuoh7(_T>IHwq&XqH2tUcXNh4`l8*mG>&KmdNRr#NXSrtFwqFGHPg z%xN<%MXXD5==3jrK&E%np-|Zj*~@6r4D=28=zU?~v{p62Co2X4?Bywf$@;0IcW$cE z?&;18w4P7Vmv??+Y$a_biGKr(;eqWsV*VX~qSLLVEezk8=?-rZ!63`$$oR)2dJ-x zmwx$tsB`E~54<_F&Z!<%$arD^z5+xwFb8=H78ufdS>R7SoOjdO#jxT2eN(}Hn?%eS zYe)bepZ{qeW5Wi;y^1>crV2JwWEXEsj!rKgks|Vg7tF?Sh@nR;ZH=gY7eeIS$L-($ z^+85Wh-1iseLxiZbxhba2rN1C!5V0|l7a+D!^z_3MM%eMPCB$-NEgOviS`V0p3Ave zuqKi_u`Palm8BuK@IEgCip|u0iJ4#{WeE$~{?$)61Uswn%${=VD_;Vn$7&8XF-nhz zxGTXL!aVryWVBoV=gkg_=JiwP>`$EFqnwGzLO1!Y{h+ao0AtLFeV5dA20ycv-AGpr*`r3RqTJ^gab#D ziI@G#Q!w+04Pooc=ULYoOB0#~jQr(-!Zgk~A_2}gjoAp3Z9LlLCu!`%8}q0MZ|r`v z0+D{VUy3PtO~hSnGN##;=qopuL(V8b^lo$u)$3j>{EB;~=lhA&TM zp5NSiMqM0H#dM*~ewddI(DVS$u?qFsB4;Y5RgGq$E8xNHRW^Jr6ONiYI@D#&KjF1T z-6q@-$cV3_Cft0&=*J9j0`b9j)`yhe0Z(vMLWO#$3Y_km;Y zkN%RX_1o*M$90dZ58Ta}7!{Cro2+3GxAP+}pxo-6GrjGA8aHt(OtPyn$rL6PdDlH-XDK(F#B+l8eiEjR|coCh->IHo&w*%~Ks^IGqCmHqv&w^!)sbSt?zx zuHaG3Scd0T*wx}u&6)QhS@xJa(J|B7(4cLKbn?(}zZtL_Z=>w*dBWgIpHE`5fM0^K z1?znj;@Mt*dm&Dmx!O=r$-I#d=yg}NMdWZoF;S|tAvU?8_SyGRxYOQsljZ2x#&XG^1JRWs{9jvFEE9;RM8X)q;+>g%gn7<{0*-~_B$uG-_B5Wa8-cz(8O2fG^C>mOuvZ z6JW5wlcx_S!WGGyV16K>gH1RbNy;RUt*X3Bc#tt9YQZVsnx|R8eF*-s zau5Ah9e{4v$Cst74Uo+4Y4cm8Nl(@vCG3}gF(Ehe=k~di%;fcV6aEbACvEbgzyqnr zHd2BAFUuXmfNSMO3zGPQseCp0smOFp31Y;Yhysel9XU=&SsHkupcv~jG!~Y1g(PC( zv2JO2BlX-kNAp!dAl1vh9Qgqb#Rz;@q-DGemw6nhA4ttb1_`hy(QJ9E_g_sd%j7fS|*LXhyKHoT5pd1m-2?05D4-arP-7v2X=jQlI zriH^|$wMWM8#u)iZ`WqK4lbfM=@rOVz@d>dur1azZ*kO2gZvQ2mIfy3-Kv=Wg%>sTTUSfISlUMUpzbPf z1|$s?0Q@zCA1WH;wrqwi_KSMSClgLhNV%RA{=?ha_AoSwf^Ku@&~;=gi~mgjW4$nM zLUeNc-O5W@3gK;?(Nw=OWV1a>1V#`{%CUe6-n+R}{d*}2e9gK1TVGGvip8(ey(6M{ z8evaerc=;IRtP33Yob^Iwbr8;XMI)82Dau* zXr&Z9vXJZ|3cPSlAq}FbTdozYi4_0B;mYPZJuuPeG5kBOG?ObSp0nz$V?x%(ct&sH z)%TPkrP{6NXycc%*}_uU5n3*7(UFR2pT@M9KJ*tFW7vg$JosZJuGFL;cz0ssY_M)p z7)J5k2&H~%IC23nW%y1NUY&d&2_l)}k~j3IzWw?NH{-q0rk<>WJ$T!$s4(qfblL`4 zL?d%B`1yIW$IK&@Pi)IijXlOfXr&}*+62sb=8&nW6z{CmnAx8ZdyUE1xu^+;HGFu3 z3@>Dch$xEzZyyBRp9^cJirGQ$wVVz7=TOO+Q$@nZ`HY1ZqRr5CF)B-gR+F6Mv`%8L zj%GSb@j^$Vi53kZ6&D1%NC_S98d0hMTi@nb9}l{nVF^R)iu|x!crb* znoM*x?FPe-L%?4-&L(MUDgfv*d>6pkb!d##2zc|`gB)GO6<-C5yho6y4?a>+oTR)s ztht!)X?zmo({)MW>EoW&3%d>AIO)2Z3+JQYty*$Cxf zpB;GS45*nq-exCQpDkAW&P57*$ISD)*1Mne@5LvUS9mV{X3jwheZD1?|KV?(%&d$M z`=uMBKlUrDNi0?|5t;02*|hAhHlUR#A*S>7tuhaD;PrbgiHFJbK7p64<=lUR30Mu0 ze^X@y2|5E4a<&XV;klDtEN4pi-*~l(?^VU0h;|pnC1ELc<(0E~XPfM!LtsLZsp{F| zeirX5i3fdaf&}R#TtXcrB(UhF82+v7OKEgbbLGO2SBlML=8z{1VM6Eso)~u3}vkrEXryO_F@`lE?e@>DZx031f~@>`mHy~=*!jD+UIv2pCSN^ zMu?1tc5{r)@uw#X-=T;?er{sg2EtN_-){}M)P=DLXb*Szeaw!k=uVREUqDhW9kBD5 zNCd76+LXH&+nviOb(E6~Hf~EklwfK7OWGyA?2r=2dxs|8{dfoH-uM zSezYmZc)X`;+N3=eR}U|mEN@BLKT6SRN3za#RyE;b;=lfM(2Zf?6%j-|qSiX+X6Wga3lz z{NyH8k$mOTJQb+40GaTzdcNx6wT&aYd*y7>;|EJ|zt@(IyyqH0M6a3CIhMVng6XgO U2>e_sb7~9VO{|RT486$z2cgKqd;kCd literal 0 HcmV?d00001 diff --git a/uni_modules/uni-upgrade-center-app/images/bg_top.png b/uni_modules/uni-upgrade-center-app/images/bg_top.png new file mode 100644 index 0000000000000000000000000000000000000000..015f698cdd8c8caa63486a2bd87f5a96f17df630 GIT binary patch literal 30486 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 literal 0 HcmV?d00001 diff --git a/uni_modules/uni-upgrade-center-app/package.json b/uni_modules/uni-upgrade-center-app/package.json new file mode 100644 index 0000000..2eb955a --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/package.json @@ -0,0 +1,81 @@ +{ + "id": "uni-upgrade-center-app", + "displayName": "升级中心 uni-upgrade-center - App", + "version": "0.6.4", + "description": "uni升级中心 - 客户端检查更新", + "keywords": [ + "uniCloud", + "update", + "升级", + "wgt" +], + "repository": "https://gitee.com/dcloud/uni-upgrade-center/tree/master/uni_modules/uni-upgrade-center-app", + "engines": { + "HBuilderX": "^3.2.14" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "无" + }, + "npmurl": "", + "type": "unicloud-template-page" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-upgrade-center-app/pages/upgrade-popup.vue b/uni_modules/uni-upgrade-center-app/pages/upgrade-popup.vue new file mode 100644 index 0000000..633df2d --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/pages/upgrade-popup.vue @@ -0,0 +1,554 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-upgrade-center-app/readme.md b/uni_modules/uni-upgrade-center-app/readme.md new file mode 100644 index 0000000..3e830b5 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/readme.md @@ -0,0 +1,126 @@ +## 升级中心 - app插件与 `uni-admin` 版本关系 + +### `uni-admin >= 1.9.3`:云函数 `checkVersion` 废弃,使用 uni-admin 自带的 `uni-upgrade-center` 云函数。 + +# uni-upgrade-center - App + +### 概述 + +> 统一管理App及App在`Android`、`iOS`平台上`App安装包`和`wgt资源包`的发布升级 + +> uni升级中心分为业务插件和后台管理插件。本插件为业务插件,包括uni升级中心客户端检查更新的前后端逻辑。后台管理系统另见 [uni-upgrade-center - Admin](https://ext.dcloud.net.cn/plugin?id=4470) + +### uni升级中心 - 客户端检查更新插件 + - 一键式检查更新,同时支持整包升级与wgt资源包更新 + - 好看、实用、可自定义的客户端提示框 + +## 安装指引 + +1. 依赖数据库`opendb-app-versions`,如果没有此库,请在云服务空间中创建。 + +2. 使用`HBuilderX 3.1.0+`,因为要使用到`uni_modules` + +3. 在插件市场打开本插件页面,在右侧点击`使用 HBuilderX 导入插件`,选择要导入的项目点击确定 + +4. 绑定一个服务空间。自 `0.6.0` 起,依赖 `uni-admin 1.9.3+` 的 `uni-upgrade-center 云函数`,请和 uni-admin 项目关联同一个服务空间 + +5. 找到`/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/check-version`,右键上传部署。自 `0.6.0` 起,依赖 `uni-admin 1.9.3+` 的 `uni-upgrade-center 云函数`,插件不再单独提供云函数,这样可以省下一个云函数名额。 + +6. 在`pages.json`中添加页面路径。**注:请不要设置为pages.json中第一项** +```json +"pages": [ + // ……其他页面配置 + { + "path": "uni_modules/uni-upgrade-center-app/pages/upgrade-popup", + "style": { + "disableScroll": true, + "app-plus": { + "backgroundColorTop": "transparent", + "background": "transparent", + "titleNView": false, + "scrollIndicator": false, + "popGesture": "none", + "animationType": "fade-in", + "animationDuration": 200 + + } + } + } +] +``` + +7. 将`@/uni_modules/uni-upgrade-center-app/utils/check-update`import到需要用到的地方,调用一下即可 + 1. 默认使用当前绑定的服务空间,如果要请求其他服务空间,可以使用其他服务空间的 `callFunction`。[详情](https://uniapp.dcloud.io/uniCloud/cf-functions.html#call-by-function-cross-space) + +8. 升级弹框可自行编写,也可以使用`uni.showModal`,或使用现有的升级弹框样式,如果不满足UI需求请自行替换资源文件。在`utils/check-update.js`中都有实例。 + +9. wgt更新时,打包前请务必将manifest.json中的版本修改为更高版本。 + +### 更新下载安装`check-update.js` + +*该函数在utils目录下* + +1. 如果是静默更新,则不会打开更新弹框,会在后台下载后安装,下次启动应用生效 + +2. 如果是 iOS,则会直接打开AppStore的链接 + +3. 其他情况,会将`check-version`返回的结果保存在localStorage中,并跳转进入`upgrade-popup.vue`打开更新弹框 + +### 检查更新函数`check-version` + +*该函数在uniCloud/cloudfunctions目录下* + +1. 使用检查更新需要传递三个参数 `appid`、`appVersion`、`wgtVersion` + +2. `appid` 使用 plus.runtime.appid 获取,*注:真机运行时为固定值HBuilder,在调试的时候请使用本地调试云函数* + +3. `appVersion` 使用 plus.runtime.version 获取 + +4. `wgtVersion` 使用 plus.runtime.getProperty(plus.runtime.appid,(wgtInfo) => { wgtInfo.version }) 获取 + +5. `check-version`云函数内部会自动获取 App 平台 + + +**Tips** + +1. `check-version`云函数内部有版本对比函数(compare)。 + - 使用多段式版本格式(如:"3.0.0.0.0.1.0.1", "3.0.0.0.0.1")。如果不满足对比规则,请自行修改。 + - 如果修改,请将*pages/upgrade-popup.vue*中*compare*函数一并修改 + +## 项目代码说明 + +### 更新弹框 +- `upgrade-popup.vue` - 更新应用: + - 如果云函数`check-version`返回的参数表明需要更新,则将参数保存在localStorage中,带着键值跳转该页面 + - 进入时会先从localStorage中尝试取出之前存的安装包路径(此包不会是强制安装类型的包) + - 如果有已经保存的包,则和传进来的 `version` 进行比较,如果相等则安装。大于和小于都不进行安装,因为admin端可能会调整包的版本。不符合更新会将此包删除 + - 如果本地没有包或者包不符合安装条件,则进行下载安装包 + - 点击下载会有进度条、已下载大小和下载包的大小 + - 下载完成会提示安装: + - 如果是 wgt 包,安装时则会提示 正在安装…… 和 安装完成。安装完成会提示是否重启 + - 如果是 原生安装包,则直接跳出去覆盖安装 + - 下载过程中,如果退出会提示是否取消下载。如果是强制更新,则只会提示正在下载请稍后,此时不可退出 + - 如果是下载完成了没有安装就退出,则会将下载完成的包保存在本地。将包的本地路径和包version保存在localStorage中 + +### 工具类 utils +- `call-check-version` + - 请求云函数`check-version`拿取版本检测结果 +- `check-update` + - 调用`call-check-version`并根据结果判断是否显示更新弹框 + +### 云函数 +- `check-version` - 检查应用更新: + - 根据传参,先检测传参是否完整,appid appVersion wgtVersion 必传 + - 先从数据库取出所有该平台(会从上下文读取平台信息)的所有线上发行更新 + - 再从所有线上发行更新中取出版本最大的一版。如果可以,尽量先检测wgt的线上发行版更新 + - 使用上一步取出的版本包的版本号 和传参 appVersion、wgtVersion 来检测是否有更新。必须同时大于这两项,因为上一次可能是wgt热更新,否则返回暂无更新 + - 如果库中 wgt包 版本大于传参 appVersion,但是不满足 min_uni_version < appVersion,则不会使用wgt更新,会接着判断库中 app包version 是否大于 appVersion + - 返回结果: + + |code|message| + |:-:|:-:| + |0|当前版本已经是最新的,不需要更新| + |101|wgt更新| + |102|整包更新| + |-101|暂无更新或检查appid是否填写正确| + |-102|请检查传参是否填写正确| \ No newline at end of file diff --git a/uni_modules/uni-upgrade-center-app/uniCloud/database/db_init.json b/uni_modules/uni-upgrade-center-app/uniCloud/database/db_init.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/uniCloud/database/db_init.json @@ -0,0 +1 @@ +{} diff --git a/uni_modules/uni-upgrade-center-app/utils/call-check-version.js b/uni_modules/uni-upgrade-center-app/utils/call-check-version.js new file mode 100644 index 0000000..8c982ad --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/utils/call-check-version.js @@ -0,0 +1,32 @@ +export default function() { + // #ifdef APP-PLUS + return new Promise((resolve, reject) => { + plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) { + let data = { + action: 'checkVersion', + appid: plus.runtime.appid, + appVersion: plus.runtime.version, + wgtVersion: widgetInfo.version + } + uniCloud.callFunction({ + name: 'uni-upgrade-center', + data, + success: (e) => { + console.log("e: ", e); + resolve(e) + }, + fail: (error) => { + reject(error) + } + }) + }) + }) + // #endif + // #ifndef APP-PLUS + return new Promise((resolve, reject) => { + reject({ + message: '请在App中使用' + }) + }) + // #endif +} diff --git a/uni_modules/uni-upgrade-center-app/utils/check-update.js b/uni_modules/uni-upgrade-center-app/utils/check-update.js new file mode 100644 index 0000000..38fe7b0 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/utils/check-update.js @@ -0,0 +1,158 @@ +import callCheckVersion from './call-check-version' + +// 推荐再App.vue中使用 +const PACKAGE_INFO_KEY = '__package_info__' + +export default function() { + // #ifdef APP-PLUS + return new Promise((resolve, reject) => { + callCheckVersion().then(async (e) => { + if (!e.result) return; + const { + code, + message, + is_silently, // 是否静默更新 + url, // 安装包下载地址 + platform, // 安装包平台 + type // 安装包类型 + } = e.result; + + // 此处逻辑仅为实例,可自行编写 + if (code > 0) { + // 腾讯云和阿里云下载链接不同,需要处理一下,阿里云会原样返回 + const { + fileList + } = await uniCloud.getTempFileURL({ + fileList: [url] + }); + if (fileList[0].tempFileURL) + e.result.url = fileList[0].tempFileURL; + + resolve(e) + + // 静默更新,只有wgt有 + if (is_silently) { + uni.downloadFile({ + url: e.result.url, + success: res => { + if (res.statusCode == 200) { + // 下载好直接安装,下次启动生效 + plus.runtime.install(res.tempFilePath, { + force: false + }); + } + } + }); + return; + } + + /** + * 提示升级一 + * 使用 uni.showModal + */ + // return updateUseModal(e.result) + + /** + * 提示升级二 + * 官方适配的升级弹窗,可自行替换资源适配UI风格 + */ + uni.setStorageSync(PACKAGE_INFO_KEY, e.result) + uni.navigateTo({ + url: `/uni_modules/uni-upgrade-center-app/pages/upgrade-popup?local_storage_key=${PACKAGE_INFO_KEY}`, + fail: (err) => { + console.error('更新弹框跳转失败', err) + uni.removeStorageSync(PACKAGE_INFO_KEY) + } + }) + + return + } else if (code < 0) { + // TODO 云函数报错处理 + console.error(message) + return reject(e) + } + return resolve(e) + }).catch(err => { + // TODO 云函数报错处理 + console.error(err.message) + reject(err) + }) + }); + // #endif +} + +/** + * 使用 uni.showModal 升级 + */ +function updateUseModal(packageInfo) { + const { + title, // 标题 + contents, // 升级内容 + is_mandatory, // 是否强制更新 + url, // 安装包下载地址 + platform, // 安装包平台 + type // 安装包类型 + } = packageInfo; + + let isWGT = type === 'wgt' + let isiOS = !isWGT ? platform.includes('iOS') : false; + let confirmText = isiOS ? '立即跳转更新' : '立即下载更新' + + return uni.showModal({ + title, + content: contents, + showCancel: !is_mandatory, + confirmText, + success: res => { + if (res.cancel) return; + + // 安装包下载 + if (isiOS) { + plus.runtime.openURL(url); + return; + } + + uni.showToast({ + title: '后台下载中……', + duration: 1000 + }); + + // wgt 和 安卓下载更新 + downloadTask = uni.downloadFile({ + url, + success: res => { + if (res.statusCode !== 200) { + console.error('下载安装包失败', err); + return; + } + // 下载好直接安装,下次启动生效 + plus.runtime.install(res.tempFilePath, { + force: false + }, () => { + if (is_mandatory) { + //更新完重启app + plus.runtime.restart(); + return; + } + uni.showModal({ + title: '安装成功是否重启?', + success: res => { + if (res.confirm) { + //更新完重启app + plus.runtime.restart(); + } + } + }); + }, err => { + uni.showModal({ + title: '更新失败', + content: err + .message, + showCancel: false + }); + }); + } + }); + } + }); +} diff --git a/uni_modules/uni-upgrade-center/changelog.md b/uni_modules/uni-upgrade-center/changelog.md new file mode 100644 index 0000000..3d9885a --- /dev/null +++ b/uni_modules/uni-upgrade-center/changelog.md @@ -0,0 +1,51 @@ +## 0.6.0(2023-02-24) +- 修复 升级中心安卓应用市场不显示的Bug +## 0.5.1(2022-07-06) +- 修复 上版带出云函数不存在的Bug +- 升级 uni-admin 大于等于 1.9.0 务必更新至此版本。uni-admin 版本小于 1.9.0 请不要更新,历史版本在 Gitee 有发行版。后续 uni-admin 会集成升级中心 +## 0.5.0(2022-07-05) +- 修复 版本列表默认显示全部版本的Bug +- 升级 uni-admin 1.9.0 务必更新至此版本。uni-admin 版本小于 1.9.0 请不要更新,后续 uni-admin 会集成升级中心 + +## 0.4.2(2021-12-07) +- 更新 优化 list 页面显示,修复 list 页面报错 +## 0.4.1(2021-12-01) +- 修复 0.4.0版本带出来,发布新版时 appid、name 不会自动填充的Bug +## 0.4.0(2021-11-26) +- 更新 升级中心移除应用管理,现在由uni-admin接管。旧版本若没有应用管理请做升级处理 +## 0.3.0(2021-11-18) +- 兼容 uni-admin 新版内置 $request 函数改动 +## 0.2.2(2021-09-06) +- 解决 opendb-app-list表对应的schema名称冲突的问题 +## 0.2.1(2021-09-03) +- 修复 一个在添加菜单时报错,createdate不与默认值匹配 的Bug +## 0.2.0(2021-08-25) +- 兼容vue3.0 +## 0.1.9(2021-08-13) +- 更新 uni-forms使用validate校验字段 +- 修复 报错dirty_data、create_date在数据库中并不存在 +## 0.1.8(2021-08-09) +- 修复 默认配置项配置错误 +## 0.1.7(2021-08-09) +- 移除测试时配置项 +## 0.1.6(2021-08-09) +- 修复 修改版本信息时,上传时间丢失问题 +## 0.1.5(2021-07-21) +- 更新 :value.sync 改为 :value 和 @update:value +## 0.1.4(2021-07-13) +- 修复 uni-easyinput去除输入字符长度限制 +- 更新文档 关于 uni-id缺少配置信息 错误。请查看安装指引第13条 +## 0.1.3(2021-06-15) +- 修复 wgt更新某些情况下获取数据错误 +## 0.1.2(2021-06-04) +- 修复 上传包时根据平台筛选文件 +- 更新 文档 +## 0.1.1(2021-05-18) +- 更新uni-table中uni-tr组件的selectable属性为disabled +## 0.1.0(2021-04-07) +- 更新版本对比函数 compare +## 0.0.6(2021-04-01) +- 调整db_init.json +## 0.0.5(2021-03-25) +- 调整为uni_modules目录 +- 升级中心后台管理系统拆分为 Admin 后台管理 和 前台检查更新(uni-upgrade-center-app) diff --git a/uni_modules/uni-upgrade-center/js_sdk/validator/opendb-app-list.js b/uni_modules/uni-upgrade-center/js_sdk/validator/opendb-app-list.js new file mode 100644 index 0000000..e3ebf83 --- /dev/null +++ b/uni_modules/uni-upgrade-center/js_sdk/validator/opendb-app-list.js @@ -0,0 +1,44 @@ + +// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema + + + +const validator = { + "appid": { + "rules": [ + { + "required": true + }, + { + "format": "string" + } + ], + "label": "AppID" + }, + "name": { + "rules": [ + { + "required": true + }, + { + "format": "string" + } + ], + "label": "应用名称" + }, + "description": { + "rules": [ + { + "required": true + }, + { + "format": "string" + } + ], + "label": "应用描述" + } +} + +const enumConverter = {} + +export { validator, enumConverter } diff --git a/uni_modules/uni-upgrade-center/js_sdk/validator/opendb-app-versions.js b/uni_modules/uni-upgrade-center/js_sdk/validator/opendb-app-versions.js new file mode 100644 index 0000000..553f113 --- /dev/null +++ b/uni_modules/uni-upgrade-center/js_sdk/validator/opendb-app-versions.js @@ -0,0 +1,151 @@ +// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema + + + +const validator = { + "appid": { + "rules": [{ + "required": true + }, + { + "format": "string" + } + ], + "label": "AppID" + }, + "name": { + "rules": [{ + "format": "string" + }], + "label": "应用名称" + }, + "title": { + "rules": [{ + "format": "string" + }], + "label": "更新标题" + }, + "contents": { + "rules": [{ + "required": true + }, + { + "format": "string" + } + ], + "label": "更新内容" + }, + "platform": { + "rules": [{ + "required": true + }, + /* 此处不校验数据类型,因为platform在发布app端是单选,在发布wgt时可能是多选 + { + "format": "array" + }, */ + { + "range": [{ + "value": "Android", + "text": "安卓" + }, + { + "value": "iOS", + "text": "苹果" + } + ] + } + ], + "label": "平台" + }, + "type": { + "rules": [{ + "required": true + }, { + "format": "string" + }, + { + "range": [{ + "value": "native_app", + "text": "原生App安装包" + }, + { + "value": "wgt", + "text": "wgt资源包" + } + ] + } + ], + "label": "安装包类型" + }, + "version": { + "rules": [{ + "required": true + }, + { + "format": "string" + } + ], + "label": "版本号" + }, + "min_uni_version": { + "rules": [{ + "format": "string" + }], + "label": "原生App最低版本" + }, + "url": { + "rules": [{ + "required": true + }, { + "format": "string" + }], + "label": "包地址" + }, + "stable_publish": { + "rules": [{ + "format": "bool" + }], + "label": "上线发行" + }, + "create_date": { + "rules": [{ + "format": "timestamp" + }], + "label": "上传时间" + }, + "is_silently": { + "rules": [{ + "format": "bool" + }], + "label": "静默更新", + "defaultValue": false + }, + "is_mandatory": { + "rules": [{ + "format": "bool" + }], + "label": "强制更新", + "defaultValue": false + } +} + +const enumConverter = { + "platform_valuetotext": [{ + "value": "Android", + "text": "安卓" + }, + { + "value": "iOS", + "text": "苹果" + } + ], + "type_valuetotext": { + "native_app": "原生App安装包", + "wgt": "wgt资源包" + } +} + +export { + validator, + enumConverter +} diff --git a/uni_modules/uni-upgrade-center/menu.json b/uni_modules/uni-upgrade-center/menu.json new file mode 100644 index 0000000..49fd9fa --- /dev/null +++ b/uni_modules/uni-upgrade-center/menu.json @@ -0,0 +1,10 @@ +[{ + "menu_id": "system_update", + "name": "升级中心", + "icon": "uni-icons-cloud-upload", + "url": "uni_modules/uni-upgrade-center/pages/version/list", + "sort": 1050, + "parent_id": "system_management", + "permission": [], + "enable": true +}] diff --git a/uni_modules/uni-upgrade-center/package.json b/uni_modules/uni-upgrade-center/package.json new file mode 100644 index 0000000..73e401e --- /dev/null +++ b/uni_modules/uni-upgrade-center/package.json @@ -0,0 +1,91 @@ +{ + "id": "uni-upgrade-center", + "displayName": "升级中心 uni-upgrade-center - Admin", + "version": "0.6.0", + "description": "uni升级中心 - 后台管理系统", + "keywords": [ + "uniCloud", + "admin", + "update", + "升级", + "wgt" +], + "repository": "https://gitee.com/dcloud/uni-upgrade-center/tree/master/uni_modules/uni-upgrade-center", + "engines": { + "HBuilderX": "^3.3.10" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "无" + }, + "npmurl": "", + "type": "unicloud-admin" + }, + "uni_modules": { + "dependencies": [ + "uni-data-checkbox", + "uni-data-picker", + "uni-dateformat", + "uni-easyinput", + "uni-file-picker", + "uni-forms", + "uni-icons", + "uni-pagination", + "uni-table" + ], + "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" + }, + "快应用": { + "华为": "y", + "联盟": "y" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-upgrade-center/pages/components/show-info.vue b/uni_modules/uni-upgrade-center/pages/components/show-info.vue new file mode 100644 index 0000000..459eda6 --- /dev/null +++ b/uni_modules/uni-upgrade-center/pages/components/show-info.vue @@ -0,0 +1,52 @@ + + + + + diff --git a/uni_modules/uni-upgrade-center/pages/mixin/version_add_detail_mixin.js b/uni_modules/uni-upgrade-center/pages/mixin/version_add_detail_mixin.js new file mode 100644 index 0000000..cff2ffb --- /dev/null +++ b/uni_modules/uni-upgrade-center/pages/mixin/version_add_detail_mixin.js @@ -0,0 +1,187 @@ +import { + validator, + enumConverter +} from '@/js_sdk/validator/opendb-app-versions.js'; + +const platform_iOS = 'iOS'; +const platform_Android = 'Android'; +const db = uniCloud.database(); + +function getValidator(fields) { + let reuslt = {} + for (let key in validator) { + if (fields.includes(key)) { + reuslt[key] = validator[key] + } + } + return reuslt +} + +export const fields = + 'appid,name,title,contents,platform,type,version,min_uni_version,url,stable_publish,is_silently,is_mandatory,create_date,store_list' + +export default { + data() { + return { + labelWidth: '80px', + enableiOSWgt: true, // 是否开启iOS的wgt更新 + silentlyContent: '静默更新:App升级时会在后台下载wgt包并自行安装。新功能在下次启动App时生效', + mandatoryContent: '强制更新:App升级弹出框不可取消', + stablePublishContent: '同时只可有一个线上发行版,线上发行不可更设为下线。\n未上线可以设为上线发行并自动替换当前线上发行版', + stablePublishContent2: '使用本包替换当前线上发行版', + uploadFileContent: '可下载安装包地址。上传文件到云存储自动填写,也可以手动填写', + minUniVersionContent: '上次使用新Api或打包新模块的App版本', + priorityContent: '检查更新时,按照优先级从大到小依次尝试跳转商店。如果都跳转失败,则会打开浏览器使用下载链接下载apk安装包', + latestStableData: [], // 库中最新已上线版 + appFileList: null, // 上传包 + type_valuetotext: enumConverter.type_valuetotext, + preUrl: '', + formData: { + "appid": "", + "name": "", + "title": "", + "contents": "", + "platform": [], + "store_list": [], + "type": "", + "version": "", + "min_uni_version": "", + "url": "", + "stable_publish": false, + "create_date": null + }, + formOptions: { + "platform_localdata": [{ + "value": "Android", + "text": "安卓" + }, + { + "value": "iOS", + "text": "苹果" + } + ], + "type_localdata": [{ + "value": "native_app", + "text": "原生App安装包" + }, + { + "value": "wgt", + "text": "App资源包" + } + ] + }, + rules: { + ...getValidator([ + "appid", "contents", "platform", "type", + "version", "min_uni_version", "url", "stable_publish", + "title", "name", "is_silently", "is_mandatory", "store_list" + ]) + } + } + }, + onReady() { + this.$refs.form.setRules(this.rules) + }, + computed: { + isWGT() { + return this.formData.type === 'wgt' + }, + isiOS() { + return !this.isWGT ? this.formData.platform.includes(platform_iOS) : false; + }, + hasPackage() { + return this.appFileList && !!Object.keys(this.appFileList).length + }, + fileExtname() { + return this.isWGT ? ['wgt'] : ['apk'] + }, + platformLocaldata() { + return !this.isWGT ? this.formOptions.platform_localdata : this.enableiOSWgt ? this.formOptions + .platform_localdata : [this.formOptions.platform_localdata[0]] + }, + uni_platform() { + return (this.isiOS ? platform_iOS : platform_Android).toLocaleLowerCase() + } + }, + methods: { + getStoreList(appid) { + return db.collection('opendb-app-list') + .where({ + appid + }) + .get() + .then(res => { + const data = res.result.data[0] + return data.store_list || [] + }) + }, + packageUploadSuccess(res) { + uni.showToast({ + icon: 'success', + title: '上传成功', + duration: 800 + }) + this.preUrl = this.formData.url + this.formData.url = res.tempFilePaths[0] + }, + deleteFile(fileList) { + return this.$request('deleteFile', { + fileList + }, { + functionName: 'uni-upgrade-center' + }) + }, + async packageDelete(res) { + if (!this.hasPackage) return; + let [deleteRes] = await this.deleteFile([res.tempFilePath]) + if (deleteRes.success) { + uni.showToast({ + icon: 'success', + title: '删除成功', + duration: 800 + }) + this.formData.url = this.preUrl + this.$refs.form.clearValidate('url') + } + }, + selectFile() { + if (this.hasPackage) { + uni.showToast({ + icon: 'none', + title: '只可上传一个文件,请删除已上传后重试', + duration: 1000 + }); + } + }, + createCenterRecord(value) { + return { + ...value, + uni_platform: this.uni_platform, + create_env: 'upgrade-center' + } + }, + createCenterQuery({ + appid + }) { + return { + appid, + create_env: 'upgrade-center' + } + }, + createStatQuery({ + appid, + type, + version, + uni_platform + }) { + return { + appid, + type, + version, + uni_platform: uni_platform ? uni_platform : this.uni_platform, + create_env: 'uni-stat', + stable_publish: false + } + } + } +} diff --git a/uni_modules/uni-upgrade-center/pages/utils.js b/uni_modules/uni-upgrade-center/pages/utils.js new file mode 100644 index 0000000..df0aeb3 --- /dev/null +++ b/uni_modules/uni-upgrade-center/pages/utils.js @@ -0,0 +1,26 @@ +// 判断arr是否为一个数组,返回一个bool值 +function isArray(arr) { + return Object.prototype.toString.call(arr) === '[object Array]'; +} + +// 深度克隆 +export 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 const appListDbName = 'opendb-app-list' +export const appVersionListDbName = 'opendb-app-versions' +// 版本列表默认显示应用Appid +export const defaultDisplayApp = '' diff --git a/uni_modules/uni-upgrade-center/pages/version/add.vue b/uni_modules/uni-upgrade-center/pages/version/add.vue new file mode 100644 index 0000000..050a75c --- /dev/null +++ b/uni_modules/uni-upgrade-center/pages/version/add.vue @@ -0,0 +1,412 @@ + + + + + diff --git a/uni_modules/uni-upgrade-center/pages/version/detail.vue b/uni_modules/uni-upgrade-center/pages/version/detail.vue new file mode 100644 index 0000000..89f3730 --- /dev/null +++ b/uni_modules/uni-upgrade-center/pages/version/detail.vue @@ -0,0 +1,337 @@ + + + + diff --git a/uni_modules/uni-upgrade-center/pages/version/list.vue b/uni_modules/uni-upgrade-center/pages/version/list.vue new file mode 100644 index 0000000..9cdc9f3 --- /dev/null +++ b/uni_modules/uni-upgrade-center/pages/version/list.vue @@ -0,0 +1,368 @@ + + + + diff --git a/uni_modules/uni-upgrade-center/readme.md b/uni_modules/uni-upgrade-center/readme.md new file mode 100644 index 0000000..46ec891 --- /dev/null +++ b/uni_modules/uni-upgrade-center/readme.md @@ -0,0 +1,233 @@ +## uni-admin 1.9.3+ 已内置,此插件不再维护 [点击查看文档](https://uniapp.dcloud.net.cn/uniCloud/upgrade-center.html) + +- `uni-admin < 1.9.0`:请前往 [Gitee](https://gitee.com/dcloud/uni-upgrade-center/releases) 下载 `tag v0.4.2` 版本使用 +-`1.9.0 <= uni-admin < 1.9.2` :请前往 [Gitee](https://gitee.com/dcloud/uni-upgrade-center/releases) 下载 `tag v0.5.1` 版本使用 +- `uni-admin >= 1.9.3` :uni-admin 已内置 升级中心,直接使用即可 [详情](https://uniapp.dcloud.io/uniCloud/admin.html#app-manager)。并且云函数 `upgrade-center` 废弃,使用 `uni-upgrade-center` 云函数。 + +# uni-upgrade-center - Admin + +### 概述 + +> 统一管理App及App在`Android`、`iOS`平台上`App安装包`和`wgt资源包`的发布升级 + +> 本插件为uni升级中心后台管理系统,客户端检查更新插件请点击查看 [uni-upgrade-center-app](https://ext.dcloud.net.cn/plugin?id=4542) + +### 基于uniCloud的App升级中心,本插件具有如下特征: + - 云端基于uniCloud云函数实现 + - 数据库遵循opendb规范 + - 遵循uni-Admin框架规范,可直接导入uni-admin项目中 + - 支持App整包升级及wgt资源包升级 + +## 升级中心解决了什么问题? + +升级中心是一款uni-admin插件,负责App版本更新业务。包含后台管理界面、更新检查逻辑,App内只要调用弹出提示即可。 + +升级中心有以下功能点: + +- 应用管理,对App的信息记录和应用版本管理 +- 版本管理,可以发布新版,也可方便直观的对当前App历史版本以及线上发行版本进行查看、编辑和删除操作 +- 版本发布信息管理,包括 更新标题,更新内容,版本号,静默更新,强制更新,灵活上线发行 的设置和修改 +- 原生App安装包,发布Apk更新,用于App的整包更新,可设置是否强制更新 +- wgt资源包,发布wgt更新,用于App的热更新,可设置是否强制更新,静默更新 +- App管理列表及App版本记录列表搜索 + +只需导入插件,初始化数据库即可拥有上述功能。 + +您也可以自己修改逻辑自定义数据库字段,和随意定制 UI 样式。 + +## 安装指引 + +1. 使用`HBuilderX 3.1.0+`,因为要使用到`uni_modules` + +2. 使用已有`uniCloud-admin`项目或新建项目:`打开HBuilderX` -> `文件` -> `新建` -> `项目` -> `uni-app` 选择 `uniCloud admin`模板,键入一个名字,确定 + +3. 鼠标右键选择`关联云服务空间`和`运行云服务空间初始化向导` + +3. 在插件市场打开本插件页面,在右侧点击`使用 HBuilderX 导入插件`,选择 `uniCloud admin` 项目点击确定 + +4. 等待下载安装完毕。由于本插件依赖一些uni-ui插件,下载完成后会显示合并插件页面,自行选择即可 + +5. 找到`/uni_modules/uni-upgrade-center/uniCloud/cloudfunctions/upgrade-center`,右键上传部署 + +7. 在`pages.json`中添加页面路径 +```json +//此结构与uniCloud admin中的pages.json结构一致 +{ + "pages": [ + // ……其他页面配置 + { + "path": "uni_modules/uni-upgrade-center/pages/version/list", + "style": { + "navigationBarTitleText": "版本列表" + } + }, { + "path": "uni_modules/uni-upgrade-center/pages/version/add", + "style": { + "navigationBarTitleText": "新版发布" + } + }, { + "path": "uni_modules/uni-upgrade-center/pages/version/detail", + "style": { + "navigationBarTitleText": "版本信息查看" + } + } + ] +} +``` + +8. 在`manifest.json -> 源码视图`中添加以下配置: + ```js + "networkTimeout":{ + "uploadFile":1200000 //ms, 如果不配置,上传大文件可能会超时 + } + ``` + +9. 运行项目到`Chrome` + +10. 添加菜单 + - `vue2` + + 运行起来uniCloud admin,菜单管理模块会自动读取`/uni_modules/uni-upgrade-center/menu.json`文件中的菜单配置,生成【待添加菜单】,选中升级中心,点击`添加选中的菜单`即可 +
+ +
+ - `vue3` + + 可将 `/uni_modules/uni-upgrade-center/menu.json` 拷贝至 `uniCloud/database/db_init.json` 中的 `opendb-admin-menus` 节点下,并右键初始化数据库即可。 +11. 添加成功后,就可以在左侧的菜单栏中找到`升级中心`菜单 + +
+ +
+ +12. 在进入`升级中心`之前: + 1. 需要到`uni-admin`的`应用管理`中添加一个应用,才可以在`升级中心`中发布对应应用的版本。 + 2. 当你有多个应用时,可以在`/uni_modules/uni-upgrade-center/pages/utils.js`中修改`defaultDisplayApp`字段来设置默认显示应用的`appid`。 + 3. 如果不设置或设置应用不存在则默认从数据库中查出来的第一个应用。 + +13. 由于插件依赖的uni-ui的一些组件,建议右键`/uni_modules/uni-upgrade-center`安装一下第三方依赖,否则可能会出现一些问题 + +14. 运行在`uniCloud`,由于本插件使用了`clientDB`,因此可能需要配置一下`uni-config-center插件`关于`uni-id`的配置信息。如提示`公用模块uni-id缺少配置信息`请这样做: + 1. 点击[uni-config-center](https://ext.dcloud.net.cn/plugin?id=4425)导入插件 + 2. 在`/uniCloud/cloudfunctions/common/uni-config-center/`下创建`uni-id`文件夹,文件夹内创建`config.json`文件。 + 3. 点击[config.json默认配置](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=start)。将内容拷贝至`config.json`中。**注:一定要把注释去除!** + +## 使用指南 + +### 升级中心 + +#### 应用列表 + +1. 点击菜单 `应用管理`,这里展示你所添加的 App,点击右上角 `新增` 可以新增一个 App + +
+ +
+ +2. 将App的信息都填写完善后,你可以在列表的操作列进行`修改`应用信息或者`删除`该应用。 + +**Tips** +- 删除应用会把该应用的所有版本记录同时删除 + +#### 版本管理 +1. 在版本管理list的右上角点击`发布新版`,可以发布`原生App安装包`和`wgt资源包`。在左上角点击`下拉列表`,可以切换展示应用。 + +
+ +
+ +- #### 发布原生App安装包 + 1. 在上传安装包界面填写此次发版信息 + +
+ +
+ + 2. `包地址` + - 可以选择手动上传一个文件到 `云存储`,会自动将地址填入该项 + + - 也可以手动填写一个地址,就可以不用再上传文件 + + - 如果是发布`苹果`版本,包地址则为 应用在`AppStore的链接` + + 3. `强制更新` + - 如果使用强制更新,App端接收到该字段后,App升级弹出框不可取消 + + 4. `上线发行` + - 可设置当前包是否上线发行,只有已上线才会进行更新检测 + + - 同时只可有一个线上发行版,线上发行不可更设为下线。未上线可以设为上线发行并自动替换当前线上发行版 + + - 修改当前包为上线发行,自动替换当前线上发行版 + + **注:版本号请填写以`.`分隔字符串,例如:`0.0.1`** +- #### 发布wgt资源包 + 1. 大部分配置与发布 `原生App安装包` 一致 + +
+ +
+ + 2. `原生App最低版本` + - 上次使用新Api或打包新模块的App版本 + + - 如果此次打包wgt使用了`新的api`或者打包了`新的模块`,则在发布 `wgt资源包` 的时候,将此版本更新为本次版本 + + - 如果已有正式版`wgt资源包`,则本次新增会自动带出 + + 2. `静默更新` + - App升级时会在后台下载wgt包并自行安装。新功能在下次启动App时生效 + - **静默更新后不重启应用,可能会导致正在访问的应用的页面数据错乱,请谨慎使用!** + + **注:版本号请填写以`.`分隔字符串,例如:`0.0.1`** + +- #### 发布完成页面 + +
+ +
+ +**Tips** + +1. `pages/system/upgradecenter/version/add.vue`中有版本对比函数(compare)。 + - 使用多段式版本格式(如:"3.0.0.0.0.1.0.1", "3.0.0.0.0.1")。如果不满足对比规则,请自行修改。 + +## 项目代码说明 + +### uniCloud 数据表 + +数据表基于 [openDB](https://gitee.com/dcloud/opendb/tree/master) 规范,它约定了一个标准用户表的表名和字段定义,并且基于 nosql 的特性,可以由开发者自行扩展字段。 + +本项目用到了 2 个表: + +- opendb-app-list:app管理列表。记录应用的 appid、name、description 用于展示。[详见](https://gitee.com/dcloud/opendb/tree/master/collection/opendb-app-list) +- opendb-app-versions:应用版本管理表。记录管理应用的版本信息。[详见](https://gitee.com/dcloud/opendb/tree/master/collection/opendb-app-versions) + +### 前端页面 + +点击`升级中心`,会进入应用管理列表,在这里你可以新增应用,或者在`应用详情`中查看、修改或删除一个已经录入的应用。 + +在应用管理列表中点击某个应用的`版本管理`,进入该应用的所有版本记录。列表排序为:先排序已上线版本,剩下已下线版本根据创建时间排列。 + +在应用版本列表中点击`详情`,即可进入该版本的信息详情中查看、修改或删除该记录。 + +**Tips** +- 升级中心设计之初就支持iOS的wgt更新 +- iOS的wgt更新肯定是违反apple政策的,注意事项: + - 审核期间请不要弹窗升级 + - 升级完后尽量不要自行重启 + - 尽量使用静默更新 +- 可以通过以下修改支持iOS的wgt更新: + > \uni_modules\uni-upgrade-center\pages\mixin\version_add_detail_mixin.js + > + > 将 `data` 中的 `enableiOSWgt: false` 中 改为 `enableiOSWgt: true` + +**常见问题** +- 以下问题可以通过升级插件版本解决: + - createdate不与默认值匹配 + - ["create_date"]在数据库中并不存在 + - 提交的字段["dirty_data"]在数据库中并不存在 + - 集合[opendb-app-list]对应的schema内存在错误,详细信息:opendb-app-list表对应的schema名称冲突,这是什么意思呢 + +- 没有/找不到 [opendb-app-list] 集合/表。**解决方案:**升级 admin 至 1.6.0+ 即可 +- 测试时发布了高版本的包,测试完了发布包提示需要大于版本号 (x.x.x)。**解决方案:**直接在控制台修改数据库 \ No newline at end of file diff --git a/uni_modules/uni-upgrade-center/uniCloud/database/db_init.json b/uni_modules/uni-upgrade-center/uniCloud/database/db_init.json new file mode 100644 index 0000000..cb5b6ae --- /dev/null +++ b/uni_modules/uni-upgrade-center/uniCloud/database/db_init.json @@ -0,0 +1,10 @@ +// 在本文件中可配置云数据库初始化,数据格式见:https://uniapp.dcloud.io/uniCloud/hellodb?id=db-init + +// 编写完毕后对本文件点右键,可按配置规则创建表和添加数据 + +{ + + + +} + diff --git a/uni_modules/yjly-dictItemSelect/changelog.md b/uni_modules/yjly-dictItemSelect/changelog.md new file mode 100644 index 0000000..e69de29 diff --git a/uni_modules/yjly-dictItemSelect/components/yjly-dictItemSelect/yjly-dictItemSelect.vue b/uni_modules/yjly-dictItemSelect/components/yjly-dictItemSelect/yjly-dictItemSelect.vue new file mode 100644 index 0000000..a86f615 --- /dev/null +++ b/uni_modules/yjly-dictItemSelect/components/yjly-dictItemSelect/yjly-dictItemSelect.vue @@ -0,0 +1,78 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/yjly-dictItemSelect/package.json b/uni_modules/yjly-dictItemSelect/package.json new file mode 100644 index 0000000..0c6cfcb --- /dev/null +++ b/uni_modules/yjly-dictItemSelect/package.json @@ -0,0 +1,83 @@ +{ + "id": "yjly-dictItemSelect", + "displayName": "yjly-dictItemSelect", + "version": "1.0.0", + "description": "yjly-dictItemSelect", + "keywords": [ + "yjly-dictItemSelect" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "", + "data": "", + "permissions": "" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "u", + "aliyun": "u", + "alipay": "u" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-vue": "u", + "app-nvue": "u", + "app-uvue": "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", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/yjly-dictItemSelect/readme.md b/uni_modules/yjly-dictItemSelect/readme.md new file mode 100644 index 0000000..fbff129 --- /dev/null +++ b/uni_modules/yjly-dictItemSelect/readme.md @@ -0,0 +1 @@ +# yjly-dictItemSelect \ No newline at end of file diff --git a/uni_modules/yjly-ngtools-NGComponents/changelog.md b/uni_modules/yjly-ngtools-NGComponents/changelog.md new file mode 100644 index 0000000..e69de29 diff --git a/uni_modules/yjly-ngtools-NGComponents/components/yjly-ngtools-NGComponents/yjly-ngtools-NGComponents.vue b/uni_modules/yjly-ngtools-NGComponents/components/yjly-ngtools-NGComponents/yjly-ngtools-NGComponents.vue new file mode 100644 index 0000000..5577bc6 --- /dev/null +++ b/uni_modules/yjly-ngtools-NGComponents/components/yjly-ngtools-NGComponents/yjly-ngtools-NGComponents.vue @@ -0,0 +1,418 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/yjly-ngtools-NGComponents/package.json b/uni_modules/yjly-ngtools-NGComponents/package.json new file mode 100644 index 0000000..0d3d9d1 --- /dev/null +++ b/uni_modules/yjly-ngtools-NGComponents/package.json @@ -0,0 +1,83 @@ +{ + "id": "yjly-ngtools-NGComponents", + "displayName": "yjly-ngtools-NGComponents", + "version": "1.0.0", + "description": "yjly-ngtools-NGComponents", + "keywords": [ + "yjly-ngtools-NGComponents" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "", + "data": "", + "permissions": "" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "u", + "aliyun": "u", + "alipay": "u" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-vue": "u", + "app-nvue": "u", + "app-uvue": "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", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/yjly-ngtools-NGComponents/readme.md b/uni_modules/yjly-ngtools-NGComponents/readme.md new file mode 100644 index 0000000..b18cf7e --- /dev/null +++ b/uni_modules/yjly-ngtools-NGComponents/readme.md @@ -0,0 +1 @@ +# yjly-ngtools-NGComponents \ No newline at end of file diff --git a/uni_modules/yjly-ngtools-ParResult/changelog.md b/uni_modules/yjly-ngtools-ParResult/changelog.md new file mode 100644 index 0000000..e69de29 diff --git a/uni_modules/yjly-ngtools-ParResult/components/yjly-ngtools-ParResult/yjly-ngtools-ParResult.vue b/uni_modules/yjly-ngtools-ParResult/components/yjly-ngtools-ParResult/yjly-ngtools-ParResult.vue new file mode 100644 index 0000000..8a61936 --- /dev/null +++ b/uni_modules/yjly-ngtools-ParResult/components/yjly-ngtools-ParResult/yjly-ngtools-ParResult.vue @@ -0,0 +1,556 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/yjly-ngtools-ParResult/package.json b/uni_modules/yjly-ngtools-ParResult/package.json new file mode 100644 index 0000000..c0c1e70 --- /dev/null +++ b/uni_modules/yjly-ngtools-ParResult/package.json @@ -0,0 +1,83 @@ +{ + "id": "yjly-ngtools-ParResult", + "displayName": "yjly-ngtools-ParResult", + "version": "1.0.0", + "description": "yjly-ngtools-ParResult", + "keywords": [ + "yjly-ngtools-ParResult" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "", + "data": "", + "permissions": "" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "u", + "aliyun": "u", + "alipay": "u" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-vue": "u", + "app-nvue": "u", + "app-uvue": "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", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/yjly-ngtools-ParResult/readme.md b/uni_modules/yjly-ngtools-ParResult/readme.md new file mode 100644 index 0000000..7e039e2 --- /dev/null +++ b/uni_modules/yjly-ngtools-ParResult/readme.md @@ -0,0 +1 @@ +# yjly-ngtools-ParResult \ No newline at end of file diff --git a/uni_modules/yjly-ngtools-meterPar/changelog.md b/uni_modules/yjly-ngtools-meterPar/changelog.md new file mode 100644 index 0000000..e69de29 diff --git a/uni_modules/yjly-ngtools-meterPar/components/yjly-ngtools-meterPar/yjly-ngtools-meterPar.vue b/uni_modules/yjly-ngtools-meterPar/components/yjly-ngtools-meterPar/yjly-ngtools-meterPar.vue new file mode 100644 index 0000000..c3fcf01 --- /dev/null +++ b/uni_modules/yjly-ngtools-meterPar/components/yjly-ngtools-meterPar/yjly-ngtools-meterPar.vue @@ -0,0 +1,449 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/yjly-ngtools-meterPar/package.json b/uni_modules/yjly-ngtools-meterPar/package.json new file mode 100644 index 0000000..0f2efdb --- /dev/null +++ b/uni_modules/yjly-ngtools-meterPar/package.json @@ -0,0 +1,83 @@ +{ + "id": "yjly-ngtools-meterPar", + "displayName": "yjly-ngtools-meterPar", + "version": "1.0.0", + "description": "yjly-ngtools-meterPar", + "keywords": [ + "yjly-ngtools-meterPar" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "", + "data": "", + "permissions": "" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "u", + "aliyun": "u", + "alipay": "u" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-vue": "u", + "app-nvue": "u", + "app-uvue": "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", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/yjly-ngtools-meterPar/readme.md b/uni_modules/yjly-ngtools-meterPar/readme.md new file mode 100644 index 0000000..3012340 --- /dev/null +++ b/uni_modules/yjly-ngtools-meterPar/readme.md @@ -0,0 +1 @@ +# yjly-ngtools-meterPar \ No newline at end of file diff --git a/uni_modules/yjly-ngtools-meterResult/changelog.md b/uni_modules/yjly-ngtools-meterResult/changelog.md new file mode 100644 index 0000000..e69de29 diff --git a/uni_modules/yjly-ngtools-meterResult/components/yjly-ngtools-meterResult/yjly-ngtools-meterResult.vue b/uni_modules/yjly-ngtools-meterResult/components/yjly-ngtools-meterResult/yjly-ngtools-meterResult.vue new file mode 100644 index 0000000..52b531d --- /dev/null +++ b/uni_modules/yjly-ngtools-meterResult/components/yjly-ngtools-meterResult/yjly-ngtools-meterResult.vue @@ -0,0 +1,321 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/yjly-ngtools-meterResult/package.json b/uni_modules/yjly-ngtools-meterResult/package.json new file mode 100644 index 0000000..7113919 --- /dev/null +++ b/uni_modules/yjly-ngtools-meterResult/package.json @@ -0,0 +1,83 @@ +{ + "id": "yjly-ngtools-meterResult", + "displayName": "yjly-ngtools-meterResult", + "version": "1.0.0", + "description": "yjly-ngtools-meterResult", + "keywords": [ + "yjly-ngtools-meterResult" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "", + "data": "", + "permissions": "" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "u", + "aliyun": "u", + "alipay": "u" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-vue": "u", + "app-nvue": "u", + "app-uvue": "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", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/yjly-ngtools-meterResult/readme.md b/uni_modules/yjly-ngtools-meterResult/readme.md new file mode 100644 index 0000000..76fcc64 --- /dev/null +++ b/uni_modules/yjly-ngtools-meterResult/readme.md @@ -0,0 +1 @@ +# yjly-ngtools-meterResult \ No newline at end of file diff --git a/格式化.xlsx b/格式化.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..0efa3ab9ba0467584fb5df4b360964de4ae4949f GIT binary patch literal 41137 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 Nw+U3uTT;=u{{ck=4%+|# literal 0 HcmV?d00001
+ +
+ +
+ +

{@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@} +
+

复制成功

+
+