From bf5df656edc7b98201d19d2855ceefc0f17c3cce Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Wed, 3 Aug 2022 11:52:35 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=90=8E=E5=8F=B0=E7=9A=84=20uniapp=20=E7=89=88?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/user/UserProfileController.java | 2 +- yudao-ui-admin-uniapp/.gitignore | 16 + yudao-ui-admin-uniapp/App.vue | 34 + yudao-ui-admin-uniapp/LICENSE | 21 + yudao-ui-admin-uniapp/README.md | 43 + yudao-ui-admin-uniapp/api/login.js | 47 + yudao-ui-admin-uniapp/api/system/user.js | 42 + .../components/uni-section/uni-section.vue | 167 + yudao-ui-admin-uniapp/config.js | 26 + yudao-ui-admin-uniapp/main.js | 17 + yudao-ui-admin-uniapp/manifest.json | 69 + yudao-ui-admin-uniapp/pages.json | 97 + .../pages/common/textview/index.vue | 43 + .../pages/common/webview/index.vue | 34 + yudao-ui-admin-uniapp/pages/index.vue | 43 + yudao-ui-admin-uniapp/pages/login.vue | 182 + .../pages/mine/about/index.vue | 75 + .../pages/mine/avatar/index.vue | 631 +++ .../pages/mine/help/index.vue | 112 + yudao-ui-admin-uniapp/pages/mine/index.vue | 198 + .../pages/mine/info/edit.vue | 128 + .../pages/mine/info/index.vue | 44 + .../pages/mine/pwd/index.vue | 85 + .../pages/mine/setting/index.vue | 78 + yudao-ui-admin-uniapp/pages/work/index.vue | 183 + yudao-ui-admin-uniapp/permission.js | 39 + yudao-ui-admin-uniapp/plugins/auth.js | 60 + yudao-ui-admin-uniapp/plugins/index.js | 14 + yudao-ui-admin-uniapp/plugins/modal.js | 74 + yudao-ui-admin-uniapp/plugins/tab.js | 30 + yudao-ui-admin-uniapp/static/favicon.ico | Bin 0 -> 16958 bytes .../static/font/iconfont.css | 90 + .../static/font/iconfont.ttf | Bin 0 -> 6724 bytes .../static/images/banner/banner01.jpg | Bin 0 -> 39640 bytes .../static/images/banner/banner02.jpg | Bin 0 -> 37061 bytes .../static/images/banner/banner03.jpg | Bin 0 -> 38123 bytes .../static/images/profile.jpg | Bin 0 -> 81131 bytes .../static/images/tabbar/home.png | Bin 0 -> 3265 bytes .../static/images/tabbar/home_.png | Bin 0 -> 3229 bytes .../static/images/tabbar/mine.png | Bin 0 -> 4235 bytes .../static/images/tabbar/mine_.png | Bin 0 -> 4219 bytes .../static/images/tabbar/work.png | Bin 0 -> 4108 bytes .../static/images/tabbar/work_.png | Bin 0 -> 5008 bytes yudao-ui-admin-uniapp/static/index.html | 20 + yudao-ui-admin-uniapp/static/logo.png | Bin 0 -> 5748 bytes yudao-ui-admin-uniapp/static/logo200.png | Bin 0 -> 7995 bytes yudao-ui-admin-uniapp/static/scss/colorui.css | 3912 +++++++++++++++++ yudao-ui-admin-uniapp/static/scss/global.scss | 90 + yudao-ui-admin-uniapp/static/scss/index.scss | 6 + yudao-ui-admin-uniapp/store/getters.js | 8 + yudao-ui-admin-uniapp/store/index.js | 15 + yudao-ui-admin-uniapp/store/modules/user.js | 100 + yudao-ui-admin-uniapp/uni.scss | 64 + .../uni_modules/uni-badge/changelog.md | 29 + .../components/uni-badge/uni-badge.vue | 268 ++ .../uni_modules/uni-badge/package.json | 88 + .../uni_modules/uni-badge/readme.md | 10 + .../uni_modules/uni-breadcrumb/changelog.md | 6 + .../uni-breadcrumb-item.vue | 121 + .../uni-breadcrumb/uni-breadcrumb.vue | 41 + .../uni_modules/uni-breadcrumb/package.json | 88 + .../uni_modules/uni-breadcrumb/readme.md | 66 + .../uni_modules/uni-calendar/changelog.md | 16 + .../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 | 188 + .../components/uni-calendar/uni-calendar.vue | 562 +++ .../components/uni-calendar/util.js | 350 ++ .../uni_modules/uni-calendar/package.json | 88 + .../uni_modules/uni-calendar/readme.md | 103 + .../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-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-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-data-checkbox/changelog.md | 43 + .../uni-data-checkbox/uni-data-checkbox.vue | 817 ++++ .../uni-data-checkbox/package.json | 87 + .../uni_modules/uni-data-checkbox/readme.md | 18 + .../uni_modules/uni-data-picker/changelog.md | 64 + .../components/uni-data-picker/keypress.js | 45 + .../uni-data-picker/uni-data-picker.vue | 554 +++ .../uni-data-pickerview/uni-data-picker.js | 563 +++ .../uni-data-pickerview.vue | 333 ++ .../uni_modules/uni-data-picker/package.json | 93 + .../uni_modules/uni-data-picker/readme.md | 22 + .../uni_modules/uni-data-select/changelog.md | 16 + .../uni-data-select/uni-data-select.vue | 426 ++ .../uni_modules/uni-data-select/package.json | 88 + .../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-datetime-picker/changelog.md | 93 + .../uni-datetime-picker/calendar-item.vue | 185 + .../uni-datetime-picker/calendar.vue | 907 ++++ .../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 | 927 ++++ .../uni-datetime-picker.vue | 1012 +++++ .../components/uni-datetime-picker/util.js | 410 ++ .../uni-datetime-picker/package.json | 90 + .../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 | 47 + .../components/uni-easyinput/common.js | 56 + .../uni-easyinput/uni-easyinput.vue | 593 +++ .../uni_modules/uni-easyinput/package.json | 90 + .../uni_modules/uni-easyinput/readme.md | 11 + .../uni_modules/uni-fab/changelog.md | 17 + .../uni-fab/components/uni-fab/uni-fab.vue | 475 ++ .../uni_modules/uni-fab/package.json | 87 + .../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-file-picker/changelog.md | 63 + .../uni-file-picker/choose-and-upload-file.js | 224 + .../uni-file-picker/uni-file-picker.vue | 656 +++ .../uni-file-picker/upload-file.vue | 325 ++ .../uni-file-picker/upload-image.vue | 292 ++ .../components/uni-file-picker/utils.js | 109 + .../uni_modules/uni-file-picker/package.json | 86 + .../uni_modules/uni-file-picker/readme.md | 11 + .../uni_modules/uni-forms/changelog.md | 86 + .../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 | 91 + .../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 | 22 + .../uni-icons/components/uni-icons/icons.js | 1169 +++++ .../components/uni-icons/uni-icons.vue | 96 + .../components/uni-icons/uniicons.css | 663 +++ .../components/uni-icons/uniicons.ttf | Bin 0 -> 35760 bytes .../uni_modules/uni-icons/package.json | 86 + .../uni_modules/uni-icons/readme.md | 8 + .../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 | 20 + .../components/uni-list-ad/uni-list-ad.vue | 107 + .../uni-list-chat/uni-list-chat.scss | 58 + .../uni-list-chat/uni-list-chat.vue | 538 +++ .../uni-list-item/uni-list-item.vue | 454 ++ .../uni-list/components/uni-list/uni-list.vue | 108 + .../components/uni-list/uni-refresh.vue | 65 + .../components/uni-list/uni-refresh.wxs | 87 + .../uni_modules/uni-list/package.json | 91 + .../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 | 41 + .../components/uni-nav-bar/uni-nav-bar.vue | 348 ++ .../components/uni-nav-bar/uni-status-bar.vue | 27 + .../uni_modules/uni-nav-bar/package.json | 89 + .../uni_modules/uni-nav-bar/readme.md | 15 + .../uni_modules/uni-notice-bar/changelog.md | 16 + .../uni-notice-bar/uni-notice-bar.vue | 395 ++ .../uni_modules/uni-notice-bar/package.json | 90 + .../uni_modules/uni-notice-bar/readme.md | 13 + .../uni_modules/uni-number-box/changelog.md | 25 + .../uni-number-box/uni-number-box.vue | 221 + .../uni_modules/uni-number-box/package.json | 85 + .../uni_modules/uni-number-box/readme.md | 13 + .../uni_modules/uni-pagination/changelog.md | 20 + .../components/uni-pagination/i18n/en.json | 4 + .../components/uni-pagination/i18n/es.json | 4 + .../components/uni-pagination/i18n/fr.json | 4 + .../components/uni-pagination/i18n/index.js | 12 + .../uni-pagination/i18n/zh-Hans.json | 4 + .../uni-pagination/i18n/zh-Hant.json | 4 + .../uni-pagination/uni-pagination.vue | 409 ++ .../uni_modules/uni-pagination/package.json | 86 + .../uni_modules/uni-pagination/readme.md | 13 + .../uni_modules/uni-popup/changelog.md | 60 + .../components/uni-popup-dialog/keypress.js | 45 + .../uni-popup-dialog/uni-popup-dialog.vue | 271 ++ .../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/popup.js | 26 + .../components/uni-popup/uni-popup.vue | 474 ++ .../uni_modules/uni-popup/package.json | 90 + .../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 | 33 + .../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 | 89 + .../uni_modules/uni-search-bar/readme.md | 14 + .../uni-segmented-control/changelog.md | 9 + .../uni-segmented-control.vue | 145 + .../uni-segmented-control/package.json | 87 + .../uni-segmented-control/readme.md | 13 + .../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 | 41 + .../uni-swipe-action-item/bindingx.js | 302 ++ .../components/uni-swipe-action-item/isPC.js | 12 + .../uni-swipe-action-item/mpalipay.js | 193 + .../uni-swipe-action-item/mpother.js | 259 ++ .../components/uni-swipe-action-item/mpwxs.js | 83 + .../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 | 87 + .../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 | 23 + .../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 | 503 +++ .../uni-table/components/uni-th/uni-th.vue | 278 ++ .../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 | 86 + .../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 | 88 + .../uni_modules/uni-tooltip/readme.md | 8 + .../uni_modules/uni-transition/changelog.md | 20 + .../uni-transition/createAnimation.js | 128 + .../uni-transition/uni-transition.vue | 277 ++ .../uni_modules/uni-transition/package.json | 87 + .../uni_modules/uni-transition/readme.md | 11 + yudao-ui-admin-uniapp/utils/auth.js | 22 + yudao-ui-admin-uniapp/utils/common.js | 54 + yudao-ui-admin-uniapp/utils/constant.js | 8 + yudao-ui-admin-uniapp/utils/errorCode.js | 6 + yudao-ui-admin-uniapp/utils/permission.js | 51 + yudao-ui-admin-uniapp/utils/request.js | 76 + yudao-ui-admin-uniapp/utils/ruoyi.js | 47 + yudao-ui-admin-uniapp/utils/storage.js | 33 + yudao-ui-admin-uniapp/utils/upload.js | 73 + yudao-ui-admin/src/api/login.js | 3 + yudao-ui-admin/src/store/modules/user.js | 2 +- 353 files changed, 43224 insertions(+), 2 deletions(-) create mode 100644 yudao-ui-admin-uniapp/.gitignore create mode 100644 yudao-ui-admin-uniapp/App.vue create mode 100644 yudao-ui-admin-uniapp/LICENSE create mode 100644 yudao-ui-admin-uniapp/README.md create mode 100644 yudao-ui-admin-uniapp/api/login.js create mode 100644 yudao-ui-admin-uniapp/api/system/user.js create mode 100644 yudao-ui-admin-uniapp/components/uni-section/uni-section.vue create mode 100644 yudao-ui-admin-uniapp/config.js create mode 100644 yudao-ui-admin-uniapp/main.js create mode 100644 yudao-ui-admin-uniapp/manifest.json create mode 100644 yudao-ui-admin-uniapp/pages.json create mode 100644 yudao-ui-admin-uniapp/pages/common/textview/index.vue create mode 100644 yudao-ui-admin-uniapp/pages/common/webview/index.vue create mode 100644 yudao-ui-admin-uniapp/pages/index.vue create mode 100644 yudao-ui-admin-uniapp/pages/login.vue create mode 100644 yudao-ui-admin-uniapp/pages/mine/about/index.vue create mode 100644 yudao-ui-admin-uniapp/pages/mine/avatar/index.vue create mode 100644 yudao-ui-admin-uniapp/pages/mine/help/index.vue create mode 100644 yudao-ui-admin-uniapp/pages/mine/index.vue create mode 100644 yudao-ui-admin-uniapp/pages/mine/info/edit.vue create mode 100644 yudao-ui-admin-uniapp/pages/mine/info/index.vue create mode 100644 yudao-ui-admin-uniapp/pages/mine/pwd/index.vue create mode 100644 yudao-ui-admin-uniapp/pages/mine/setting/index.vue create mode 100644 yudao-ui-admin-uniapp/pages/work/index.vue create mode 100644 yudao-ui-admin-uniapp/permission.js create mode 100644 yudao-ui-admin-uniapp/plugins/auth.js create mode 100644 yudao-ui-admin-uniapp/plugins/index.js create mode 100644 yudao-ui-admin-uniapp/plugins/modal.js create mode 100644 yudao-ui-admin-uniapp/plugins/tab.js create mode 100644 yudao-ui-admin-uniapp/static/favicon.ico create mode 100644 yudao-ui-admin-uniapp/static/font/iconfont.css create mode 100644 yudao-ui-admin-uniapp/static/font/iconfont.ttf create mode 100644 yudao-ui-admin-uniapp/static/images/banner/banner01.jpg create mode 100644 yudao-ui-admin-uniapp/static/images/banner/banner02.jpg create mode 100644 yudao-ui-admin-uniapp/static/images/banner/banner03.jpg create mode 100644 yudao-ui-admin-uniapp/static/images/profile.jpg create mode 100644 yudao-ui-admin-uniapp/static/images/tabbar/home.png create mode 100644 yudao-ui-admin-uniapp/static/images/tabbar/home_.png create mode 100644 yudao-ui-admin-uniapp/static/images/tabbar/mine.png create mode 100644 yudao-ui-admin-uniapp/static/images/tabbar/mine_.png create mode 100644 yudao-ui-admin-uniapp/static/images/tabbar/work.png create mode 100644 yudao-ui-admin-uniapp/static/images/tabbar/work_.png create mode 100644 yudao-ui-admin-uniapp/static/index.html create mode 100644 yudao-ui-admin-uniapp/static/logo.png create mode 100644 yudao-ui-admin-uniapp/static/logo200.png create mode 100644 yudao-ui-admin-uniapp/static/scss/colorui.css create mode 100644 yudao-ui-admin-uniapp/static/scss/global.scss create mode 100644 yudao-ui-admin-uniapp/static/scss/index.scss create mode 100644 yudao-ui-admin-uniapp/store/getters.js create mode 100644 yudao-ui-admin-uniapp/store/index.js create mode 100644 yudao-ui-admin-uniapp/store/modules/user.js create mode 100644 yudao-ui-admin-uniapp/uni.scss create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-badge/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-badge/components/uni-badge/uni-badge.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-badge/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-badge/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/components/uni-breadcrumb-item/uni-breadcrumb-item.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/components/uni-breadcrumb/uni-breadcrumb.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-calendar/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/calendar.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/i18n/en.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/i18n/index.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/util.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-calendar/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-calendar/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-card/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-card/components/uni-card/uni-card.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-card/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-card/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-collapse/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-collapse/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-collapse/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-combox/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-combox/components/uni-combox/uni-combox.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-combox/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-combox/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-countdown/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/i18n/en.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/i18n/index.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hans.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hant.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/uni-countdown.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-countdown/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-countdown/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-data-checkbox/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-data-checkbox/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-data-checkbox/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-data-picker/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-data-picker/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-data-picker/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-data-select/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-data-select/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-data-select/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-dateformat/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-dateformat/components/uni-dateformat/date-format.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-dateformat/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-dateformat/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/keypress.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-drawer/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-drawer/components/uni-drawer/keypress.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-drawer/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-drawer/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-easyinput/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-easyinput/components/uni-easyinput/common.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-easyinput/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-easyinput/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-fab/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-fab/components/uni-fab/uni-fab.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-fab/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-fab/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-fav/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/i18n/en.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/i18n/index.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hans.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hant.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/uni-fav.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-fav/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-fav/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-file-picker/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/utils.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-file-picker/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-file-picker/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-forms/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-forms/components/uni-forms/uni-forms.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-forms/components/uni-forms/utils.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-forms/components/uni-forms/validate.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-forms/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-forms/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/en.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/index.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hans.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hant.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/components/uni-goods-nav/uni-goods-nav.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-grid/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-grid/components/uni-grid/uni-grid.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-grid/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-grid/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-group/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-group/components/uni-group/uni-group.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-group/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-group/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-icons/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-icons/components/uni-icons/icons.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-icons/components/uni-icons/uni-icons.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-icons/components/uni-icons/uniicons.css create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-icons/components/uni-icons/uniicons.ttf create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-icons/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-icons/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list-item.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-link/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-link/components/uni-link/uni-link.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-link/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-link/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-list/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list/uni-list.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list/uni-refresh.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list/uni-refresh.wxs create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-list/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-list/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-load-more/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-load-more/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-load-more/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-notice-bar/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-notice-bar/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-notice-bar/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-number-box/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-number-box/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-number-box/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-pagination/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/en.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/es.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/fr.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/index.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hans.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hant.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/uni-pagination.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-pagination/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-pagination/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-popup/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/i18n/en.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/i18n/index.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/keypress.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/popup.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/uni-popup.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-popup/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-popup/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-rate/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-rate/components/uni-rate/uni-rate.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-rate/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-rate/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-row/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-row/components/uni-col/uni-col.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-row/components/uni-row/uni-row.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-row/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-row/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-scss/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-scss/index.scss create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-scss/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-scss/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/index.scss create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_border.scss create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_color.scss create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_radius.scss create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_space.scss create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_styles.scss create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_text.scss create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_variables.scss create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/tools/functions.scss create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-scss/theme.scss create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-scss/variables.scss create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-search-bar/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/i18n/en.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/i18n/index.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hans.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hant.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/uni-search-bar.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-search-bar/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-search-bar/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-segmented-control/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-segmented-control/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-segmented-control/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-steps/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-steps/components/uni-steps/uni-steps.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-steps/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-steps/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/bindingx.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/isPC.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/render.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/wx.wxs create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-swiper-dot/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-swiper-dot/components/uni-swiper-dot/uni-swiper-dot.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-swiper-dot/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-swiper-dot/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-table/uni-table.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-tbody/uni-tbody.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-td/uni-td.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-th/filter-dropdown.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-th/uni-th.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-thead/uni-thead.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-tr/table-checkbox.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-tr/uni-tr.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/en.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/es.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/fr.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/index.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/zh-Hans.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/zh-Hant.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-table/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-tag/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-tag/components/uni-tag/uni-tag.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-tag/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-tag/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-title/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-title/components/uni-title/uni-title.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-title/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-title/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-tooltip/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-tooltip/components/uni-tooltip/uni-tooltip.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-tooltip/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-tooltip/readme.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-transition/changelog.md create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-transition/components/uni-transition/createAnimation.js create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-transition/components/uni-transition/uni-transition.vue create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-transition/package.json create mode 100644 yudao-ui-admin-uniapp/uni_modules/uni-transition/readme.md create mode 100644 yudao-ui-admin-uniapp/utils/auth.js create mode 100644 yudao-ui-admin-uniapp/utils/common.js create mode 100644 yudao-ui-admin-uniapp/utils/constant.js create mode 100644 yudao-ui-admin-uniapp/utils/errorCode.js create mode 100644 yudao-ui-admin-uniapp/utils/permission.js create mode 100644 yudao-ui-admin-uniapp/utils/request.js create mode 100644 yudao-ui-admin-uniapp/utils/ruoyi.js create mode 100644 yudao-ui-admin-uniapp/utils/storage.js create mode 100644 yudao-ui-admin-uniapp/utils/upload.js diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java index 3cc3a44dd..d65994379 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java @@ -95,7 +95,7 @@ public class UserProfileController { return success(true); } - @PutMapping("/update-avatar") + @RequestMapping(value = "/update-avatar", method = {RequestMethod.POST, RequestMethod.PUT}) // 解决 uni-app 不支持 Put 上传文件的问题 @ApiOperation("上传用户个人头像") public CommonResult<String> updateUserAvatar(@RequestParam("avatarFile") MultipartFile file) throws Exception { if (file.isEmpty()) { diff --git a/yudao-ui-admin-uniapp/.gitignore b/yudao-ui-admin-uniapp/.gitignore new file mode 100644 index 000000000..59c91545c --- /dev/null +++ b/yudao-ui-admin-uniapp/.gitignore @@ -0,0 +1,16 @@ +###################################################################### +# Build Tools + +/unpackage/* +/node_modules/* + +###################################################################### +# Development Tools + +/.idea/* +/.vscode/* +/.hbuilderx/* + +package-lock.json +yarn.lock + diff --git a/yudao-ui-admin-uniapp/App.vue b/yudao-ui-admin-uniapp/App.vue new file mode 100644 index 000000000..93318b588 --- /dev/null +++ b/yudao-ui-admin-uniapp/App.vue @@ -0,0 +1,34 @@ +<script> + import config from './config' + import store from '@/store' + import { getAccessToken } from '@/utils/auth' + + export default { + onLaunch: function() { + this.initApp() + }, + methods: { + // 初始化应用 + initApp() { + // 初始化应用配置 + this.initConfig() + // 检查用户登录状态 + //#ifdef H5 + this.checkLogin() + //#endif + }, + initConfig() { + this.globalData.config = config + }, + checkLogin() { + if (!getAccessToken()) { + this.$tab.reLaunch('/pages/login') + } + } + } + } +</script> + +<style lang="scss"> + @import '@/static/scss/index.scss' +</style> diff --git a/yudao-ui-admin-uniapp/LICENSE b/yudao-ui-admin-uniapp/LICENSE new file mode 100644 index 000000000..84f43b5ab --- /dev/null +++ b/yudao-ui-admin-uniapp/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 芋道 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/yudao-ui-admin-uniapp/README.md b/yudao-ui-admin-uniapp/README.md new file mode 100644 index 000000000..43a887f51 --- /dev/null +++ b/yudao-ui-admin-uniapp/README.md @@ -0,0 +1,43 @@ +<p align="center"> + <img alt="logo" src="https://oscimg.oschina.net/oscnet/up-43e3941654fa3054c9684bf53d1b1d356a1.png"> +</p> +<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v1.0.0</h1> +<h4 align="center">基于UniApp开发的轻量级移动端框架</h4> +<p align="center"> + <a href="https://gitee.com/y_project/RuoYi-App/stargazers"><img src="https://gitee.com/y_project/RuoYi-App/badge/star.svg?theme=dark"></a> + <a href="https://gitee.com/y_project/RuoYi-App"><img src="https://img.shields.io/badge/RuoYi-v1.0.0-brightgreen.svg"></a> + <a href="https://gitee.com/y_project/RuoYi-App/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a> +</p> + +## 平台简介 + +RuoYi App 移动解决方案,采用uniapp框架,一份代码多终端适配,同时支持APP、小程序、H5!实现了与[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue)、[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud)完美对接的移动解决方案!目前已经实现登录、我的、工作台、编辑资料、头像修改、密码修改、常见问题、关于我们等基础功能。 + +* 配套后端代码仓库地址[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) 或 [RuoYi-Cloud](https://github.com/yangzongzhuan/RuoYi-Cloud) 版本。 +* 应用框架基于[uniapp](https://uniapp.dcloud.net.cn/),支持小程序、H5、Android和IOS。 +* 前端组件采用[uni-ui](https://github.com/dcloudio/uni-ui),全端兼容的高性能UI框架。 + +## 技术文档 + +<img src="https://oscimg.oschina.net/oscnet/up-26c76dc90b92acdbd9ac8cd5252f07c8ad9.jpg" alt="小程序演示"/> + + +## 演示图 + +<table> + <tr> + <td><img src="https://oscimg.oschina.net/oscnet/up-3ea20e447ac621a161e395fb53ccc683d84.png"/></td> + <td><img src="https://oscimg.oschina.net/oscnet/up-a6f23cf9a371a30165e135eff6d9ae89a9d.png"/></td> + <td><img src="https://oscimg.oschina.net/oscnet/up-ff5f62016bf6624c1ff27eee57499dccd44.png"/></td> + </tr> + <tr> + <td><img src="https://oscimg.oschina.net/oscnet/up-b9a582fdb26ec69d407fabd044d2c8494df.png"/></td> + <td><img src="https://oscimg.oschina.net/oscnet/up-96427ee08fca29d77934cfc8d1b1a637cef.png"/></td> + <td><img src="https://oscimg.oschina.net/oscnet/up-5fdadc582d24cccd7727030d397b63185a3.png"/></td> + </tr> + <tr> + <td><img src="https://oscimg.oschina.net/oscnet/up-0a36797b6bcc50c36d40c3c782665b89efc.png"/></td> + <td><img src="https://oscimg.oschina.net/oscnet/up-d77995cc00687cedd00d5ac7d68a07ea276.png"/></td> + <td><img src="https://oscimg.oschina.net/oscnet/up-fa8f5ab20becf59b4b38c1b92a9989e7109.png"/></td> + </tr> +</table> diff --git a/yudao-ui-admin-uniapp/api/login.js b/yudao-ui-admin-uniapp/api/login.js new file mode 100644 index 000000000..628e2a741 --- /dev/null +++ b/yudao-ui-admin-uniapp/api/login.js @@ -0,0 +1,47 @@ +import request from '@/utils/request' + +// 登录方法 +export function login(username, password, code, uuid) { + const data = { + username, + password, + code, + uuid + } + return request({ + url: '/system/auth/login', + headers: { + isToken: false + }, + 'method': 'post', + 'data': data + }) +} + +// 获取用户详细信息 +export function getInfo() { + return request({ + url: '/system/auth/get-permission-info', + 'method': 'get' + }) +} + +// 退出方法 +export function logout() { + return request({ + url: '/system/auth/logout', + 'method': 'post' + }) +} + +// 获取验证码 +export function getCodeImg() { + return request({ + url: '/system/captcha/get-image', + headers: { + isToken: false + }, + method: 'get', + timeout: 20000 + }) +} diff --git a/yudao-ui-admin-uniapp/api/system/user.js b/yudao-ui-admin-uniapp/api/system/user.js new file mode 100644 index 000000000..9e9e7bf5e --- /dev/null +++ b/yudao-ui-admin-uniapp/api/system/user.js @@ -0,0 +1,42 @@ +import upload from '@/utils/upload' +import request from '@/utils/request' + +// 用户密码重置 +export function updateUserPwd(oldPassword, newPassword) { + const data = { + oldPassword, + newPassword + } + return request({ + url: '/system/user/profile/update-password', + method: 'put', + params: data + }) +} + +// 查询用户个人信息 +export function getUserProfile() { + return request({ + url: '/system/user/profile/get', + method: 'get' + }) +} + +// 修改用户个人信息 +export function updateUserProfile(data) { + return request({ + url: '/system/user/profile/update', + method: 'put', + data: data + }) +} + +// 用户头像上传 +export function uploadAvatar(data) { + return upload({ + url: '/system/user/profile/update-avatar', + method: 'put', + name: data.name, + filePath: data.filePath + }) +} diff --git a/yudao-ui-admin-uniapp/components/uni-section/uni-section.vue b/yudao-ui-admin-uniapp/components/uni-section/uni-section.vue new file mode 100644 index 000000000..9a52e0b8d --- /dev/null +++ b/yudao-ui-admin-uniapp/components/uni-section/uni-section.vue @@ -0,0 +1,167 @@ +<template> + <view class="uni-section"> + <view class="uni-section-header" @click="onClick"> + <view class="uni-section-header__decoration" v-if="type" :class="type" /> + <slot v-else name="decoration"></slot> + + <view class="uni-section-header__content"> + <text :style="{'font-size':titleFontSize,'color':titleColor}" class="uni-section__content-title" :class="{'distraction':!subTitle}">{{ title }}</text> + <text v-if="subTitle" :style="{'font-size':subTitleFontSize,'color':subTitleColor}" class="uni-section-header__content-sub">{{ subTitle }}</text> + </view> + + <view class="uni-section-header__slot-right"> + <slot name="right"></slot> + </view> + </view> + + <view class="uni-section-content" :style="{padding: _padding}"> + <slot /> + </view> + </view> +</template> + +<script> + + /** + * Section 标题栏 + * @description 标题栏 + * @property {String} type = [line|circle|square] 标题装饰类型 + * @value line 竖线 + * @value circle 圆形 + * @value square 正方形 + * @property {String} title 主标题 + * @property {String} titleFontSize 主标题字体大小 + * @property {String} titleColor 主标题字体颜色 + * @property {String} subTitle 副标题 + * @property {String} subTitleFontSize 副标题字体大小 + * @property {String} subTitleColor 副标题字体颜色 + * @property {String} padding 默认插槽 padding + */ + + export default { + name: 'UniSection', + emits:['click'], + props: { + type: { + type: String, + default: '' + }, + title: { + type: String, + required: true, + default: '' + }, + titleFontSize: { + type: String, + default: '14px' + }, + titleColor:{ + type: String, + default: '#333' + }, + subTitle: { + type: String, + default: '' + }, + subTitleFontSize: { + type: String, + default: '12px' + }, + subTitleColor: { + type: String, + default: '#999' + }, + padding: { + type: [Boolean, String], + default: false + } + }, + computed:{ + _padding(){ + if(typeof this.padding === 'string'){ + return this.padding + } + + return this.padding?'10px':'' + } + }, + watch: { + title(newVal) { + if (uni.report && newVal !== '') { + uni.report('title', newVal) + } + } + }, + methods: { + onClick() { + this.$emit('click') + } + } + } +</script> +<style lang="scss" > + $uni-primary: #2979ff !default; + + .uni-section { + background-color: #fff; + .uni-section-header { + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + align-items: center; + padding: 12px 10px; + font-weight: normal; + + &__decoration{ + margin-right: 6px; + background-color: $uni-primary; + &.line { + width: 4px; + height: 12px; + border-radius: 10px; + } + + &.circle { + width: 8px; + height: 8px; + border-top-right-radius: 50px; + border-top-left-radius: 50px; + border-bottom-left-radius: 50px; + border-bottom-right-radius: 50px; + } + + &.square { + width: 8px; + height: 8px; + } + } + + &__content { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + flex: 1; + color: #333; + + .distraction { + flex-direction: row; + align-items: center; + } + &-sub { + margin-top: 2px; + } + } + + &__slot-right{ + font-size: 14px; + } + } + + .uni-section-content{ + font-size: 14px; + } + } +</style> diff --git a/yudao-ui-admin-uniapp/config.js b/yudao-ui-admin-uniapp/config.js new file mode 100644 index 000000000..cd0a162b3 --- /dev/null +++ b/yudao-ui-admin-uniapp/config.js @@ -0,0 +1,26 @@ +// 应用全局配置 +module.exports = { + // baseUrl: 'http://localhost:8080', + baseUrl: 'http://localhost:48080/admin-api', + // 应用信息 + appInfo: { + // 应用名称 + name: "yudao-app", + // 应用版本 + version: "1.0.0", + // 应用logo + logo: "/static/logo.png", + // 官方网站 + site_url: "https://iocoder.cn", + // 政策协议 + agreements: [{ + title: "隐私政策", + url: "https://iocoder.cn" + }, + { + title: "用户服务协议", + url: "https://iocoder.cn" + } + ] + } +} diff --git a/yudao-ui-admin-uniapp/main.js b/yudao-ui-admin-uniapp/main.js new file mode 100644 index 000000000..3985b1b17 --- /dev/null +++ b/yudao-ui-admin-uniapp/main.js @@ -0,0 +1,17 @@ +import Vue from 'vue' +import App from './App' +import store from './store' // store +import plugins from './plugins' // plugins +import './permission' // permission +Vue.use(plugins) + +Vue.config.productionTip = false +Vue.prototype.$store = store + +App.mpType = 'app' + +const app = new Vue({ + ...App +}) + +app.$mount() diff --git a/yudao-ui-admin-uniapp/manifest.json b/yudao-ui-admin-uniapp/manifest.json new file mode 100644 index 000000000..8c138fa16 --- /dev/null +++ b/yudao-ui-admin-uniapp/manifest.json @@ -0,0 +1,69 @@ +{ + "name" : "芋道移动端", + "appid" : "__UNI__25A9D80", + "description" : "", + "versionName" : "1.0.0", + "versionCode" : "100", + "transformPx" : false, + "app-plus" : { + "usingComponents" : true, + "nvueCompiler" : "uni-app", + "splashscreen" : { + "alwaysShowBeforeRender" : true, + "waiting" : true, + "autoclose" : true, + "delay" : 0 + }, + "modules" : {}, + "distribute" : { + "android" : { + "permissions" : [ + "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", + "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", + "<uses-permission android:name=\"android.permission.VIBRATE\"/>", + "<uses-permission android:name=\"android.permission.READ_LOGS\"/>", + "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", + "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>", + "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", + "<uses-permission android:name=\"android.permission.CAMERA\"/>", + "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>", + "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", + "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", + "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", + "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", + "<uses-feature android:name=\"android.hardware.camera\"/>", + "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>" + ] + }, + "ios" : {}, + "sdkConfigs" : {} + } + }, + "quickapp" : {}, + "mp-weixin" : { + "appid" : "wxccd7e2a0911b3397", + "setting" : { + "urlCheck" : false, + "es6" : false, + "minified" : true, + "postcss" : true + }, + "optimization" : { + "subPackages" : true + }, + "usingComponents" : true + }, + "vueVersion" : "2", + "h5" : { + "template" : "static/index.html", + "devServer" : { + "port" : 9090, + "https" : false + }, + "title" : "Yudao-App", + "router" : { + "mode" : "hash", + "base" : "./" + } + } +} diff --git a/yudao-ui-admin-uniapp/pages.json b/yudao-ui-admin-uniapp/pages.json new file mode 100644 index 000000000..73c631aa8 --- /dev/null +++ b/yudao-ui-admin-uniapp/pages.json @@ -0,0 +1,97 @@ +{ + "pages": [{ + "path": "pages/login", + "style": { + "navigationBarTitleText": "登录" + } + }, { + "path": "pages/index", + "style": { + "navigationBarTitleText": "芋道移动端框架", + "navigationStyle": "custom" + } + }, { + "path": "pages/work/index", + "style": { + "navigationBarTitleText": "工作台" + } + }, { + "path": "pages/mine/index", + "style": { + "navigationBarTitleText": "我的" + } + }, { + "path": "pages/mine/avatar/index", + "style": { + "navigationBarTitleText": "修改头像" + } + }, { + "path": "pages/mine/info/index", + "style": { + "navigationBarTitleText": "个人信息" + } + }, { + "path": "pages/mine/info/edit", + "style": { + "navigationBarTitleText": "编辑资料" + } + }, { + "path": "pages/mine/pwd/index", + "style": { + "navigationBarTitleText": "修改密码" + } + }, { + "path": "pages/mine/setting/index", + "style": { + "navigationBarTitleText": "应用设置" + } + }, { + "path": "pages/mine/help/index", + "style": { + "navigationBarTitleText": "常见问题" + } + }, { + "path": "pages/mine/about/index", + "style": { + "navigationBarTitleText": "关于我们" + } + }, { + "path": "pages/common/webview/index", + "style": { + "navigationBarTitleText": "浏览网页" + } + }, { + "path": "pages/common/textview/index", + "style": { + "navigationBarTitleText": "浏览文本" + } + }], + "tabBar": { + "color": "#000000", + "selectedColor": "#000000", + "borderStyle": "white", + "backgroundColor": "#ffffff", + "list": [{ + "pagePath": "pages/index", + "iconPath": "static/images/tabbar/home.png", + "selectedIconPath": "static/images/tabbar/home_.png", + "text": "首页" + }, { + "pagePath": "pages/work/index", + "iconPath": "static/images/tabbar/work.png", + "selectedIconPath": "static/images/tabbar/work_.png", + "text": "工作台" + }, { + "pagePath": "pages/mine/index", + "iconPath": "static/images/tabbar/mine.png", + "selectedIconPath": "static/images/tabbar/mine_.png", + "text": "我的" + } + ] + }, + "globalStyle": { + "navigationBarTextStyle": "black", + "navigationBarTitleText": "RuoYi", + "navigationBarBackgroundColor": "#FFFFFF" + } +} diff --git a/yudao-ui-admin-uniapp/pages/common/textview/index.vue b/yudao-ui-admin-uniapp/pages/common/textview/index.vue new file mode 100644 index 000000000..e9b05fbb9 --- /dev/null +++ b/yudao-ui-admin-uniapp/pages/common/textview/index.vue @@ -0,0 +1,43 @@ +<template> + <view> + <uni-card class="view-title" :title="title"> + <text class="uni-body view-content">{{ content }}</text> + </uni-card> + </view> +</template> + +<script> + export default { + data() { + return { + title: '', + content: '' + } + }, + onLoad(options) { + this.title = options.title + this.content = options.content + uni.setNavigationBarTitle({ + title: options.title + }) + } + } +</script> + +<style scoped> + page { + background-color: #ffffff; + } + + .view-title { + font-weight: bold; + } + + .view-content { + font-size: 26rpx; + padding: 12px 5px 0; + color: #333; + line-height: 24px; + font-weight: normal; + } +</style> diff --git a/yudao-ui-admin-uniapp/pages/common/webview/index.vue b/yudao-ui-admin-uniapp/pages/common/webview/index.vue new file mode 100644 index 000000000..8388c76f2 --- /dev/null +++ b/yudao-ui-admin-uniapp/pages/common/webview/index.vue @@ -0,0 +1,34 @@ +<template> + <view v-if="params.url"> + <web-view :webview-styles="webviewStyles" :src="`${params.url}`"></web-view> + </view> +</template> + +<script> + export default { + data() { + return { + params: {}, + webviewStyles: { + progress: { + color: "#FF3333" + } + } + } + }, + props: { + src: { + type: [String], + default: null + } + }, + onLoad(event) { + this.params = event + if (event.title) { + uni.setNavigationBarTitle({ + title: event.title + }) + } + } + } +</script> diff --git a/yudao-ui-admin-uniapp/pages/index.vue b/yudao-ui-admin-uniapp/pages/index.vue new file mode 100644 index 000000000..17613f04f --- /dev/null +++ b/yudao-ui-admin-uniapp/pages/index.vue @@ -0,0 +1,43 @@ +<template> + <view class="content"> + <image class="logo" src="/static/logo.png"></image> + <view class="text-area"> + <text class="title">Hello 芋道</text> + </view> + </view> +</template> + +<script> + export default { + onLoad: function() { + } + } +</script> + +<style> + .content { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + + .logo { + height: 200rpx; + width: 200rpx; + margin-top: 200rpx; + margin-left: auto; + margin-right: auto; + margin-bottom: 50rpx; + } + + .text-area { + display: flex; + justify-content: center; + } + + .title { + font-size: 36rpx; + color: #8f8f94; + } +</style> diff --git a/yudao-ui-admin-uniapp/pages/login.vue b/yudao-ui-admin-uniapp/pages/login.vue new file mode 100644 index 000000000..021e0530b --- /dev/null +++ b/yudao-ui-admin-uniapp/pages/login.vue @@ -0,0 +1,182 @@ +<template> + <view class="normal-login-container"> + <view class="logo-content align-center justify-center flex"> + <image style="width: 100rpx;height: 100rpx;" :src="globalConfig.appInfo.logo" mode="widthFix"> + </image> + <text class="title">芋道移动端登录</text> + </view> + <view class="login-form-content"> + <view class="input-item flex align-center"> + <view class="iconfont icon-user icon"></view> + <input v-model="loginForm.username" class="input" type="text" placeholder="请输入账号" maxlength="30" /> + </view> + <view class="input-item flex align-center"> + <view class="iconfont icon-password icon"></view> + <input v-model="loginForm.password" type="password" class="input" placeholder="请输入密码" maxlength="20" /> + </view> + <view class="input-item flex align-center" v-if="captchaEnabled"> + <view class="iconfont icon-code icon"></view> + <input v-model="loginForm.code" class="input" placeholder="请输入验证码" maxlength="5" /> + <image :src="codeUrl" @click="getCode" class="login-code-img"></image> + </view> + <view class="action-btn"> + <button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">登录</button> + </view> + </view> + + <view class="xieyi text-center"> + <text class="text-grey1">登录即代表同意</text> + <text @click="handleUserAgrement" class="text-blue">《用户协议》</text> + <text @click="handlePrivacy" class="text-blue">《隐私协议》</text> + </view> + </view> +</template> + +<script> + import { getCodeImg } from '@/api/login' + + export default { + data() { + return { + codeUrl: "", + captchaEnabled: true, + globalConfig: getApp().globalData.config, + loginForm: { + username: "admin", + password: "admin123", + code: "", + uuid: '' + } + } + }, + created() { + this.getCode() + }, + methods: { + // 隐私协议 + handlePrivacy() { + let site = this.globalConfig.appInfo.agreements[0] + this.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`) + }, + // 用户协议 + handleUserAgrement() { + let site = this.globalConfig.appInfo.agreements[1] + this.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`) + }, + // 获取图形验证码 + getCode() { + getCodeImg().then(res => { + res = res.data; + this.captchaEnable = res.enable; + if (this.captchaEnable) { + this.codeUrl = "data:image/gif;base64," + res.img; + this.loginForm.uuid = res.uuid; + } + }) + }, + // 登录方法 + async handleLogin() { + if (this.loginForm.username === "") { + this.$modal.msgError("请输入您的账号") + } else if (this.loginForm.password === "") { + this.$modal.msgError("请输入您的密码") + } else if (this.loginForm.code === "" && this.captchaEnabled) { + this.$modal.msgError("请输入验证码") + } else { + this.$modal.loading("登录中,请耐心等待...") + this.pwdLogin() + } + }, + // 密码登录 + async pwdLogin() { + this.$store.dispatch('Login', this.loginForm).then(() => { + this.$modal.closeLoading() + this.loginSuccess() + }).catch(() => { + if (this.captchaEnabled) { + this.getCode() + } + }) + }, + // 登录成功后,处理函数 + loginSuccess(result) { + // 设置用户信息 + this.$store.dispatch('GetInfo').then(res => { + this.$tab.reLaunch('/pages/index') + }) + } + } + } +</script> + +<style lang="scss"> + page { + background-color: #ffffff; + } + + .normal-login-container { + width: 100%; + + .logo-content { + width: 100%; + font-size: 21px; + text-align: center; + padding-top: 15%; + + image { + border-radius: 4px; + } + + .title { + margin-left: 10px; + } + } + + .login-form-content { + text-align: center; + margin: 20px auto; + margin-top: 15%; + width: 80%; + + .input-item { + margin: 20px auto; + background-color: #f5f6f7; + height: 45px; + border-radius: 20px; + + .icon { + font-size: 38rpx; + margin-left: 10px; + color: #999; + } + + .input { + width: 100%; + font-size: 14px; + line-height: 20px; + text-align: left; + padding-left: 15px; + } + + } + + .login-btn { + margin-top: 40px; + height: 45px; + } + + .xieyi { + color: #333; + margin-top: 20px; + } + } + + .easyinput { + width: 100%; + } + } + + .login-code-img { + height: 45px; + } +</style> diff --git a/yudao-ui-admin-uniapp/pages/mine/about/index.vue b/yudao-ui-admin-uniapp/pages/mine/about/index.vue new file mode 100644 index 000000000..c5dd58aec --- /dev/null +++ b/yudao-ui-admin-uniapp/pages/mine/about/index.vue @@ -0,0 +1,75 @@ +<template> + <view class="about-container"> + <view class="header-section text-center"> + <image style="width: 150rpx;height: 150rpx;" src="/static/logo200.png" mode="widthFix"> + </image> + <uni-title type="h2" title="芋道移动端"></uni-title> + </view> + + <view class="content-section"> + <view class="menu-list"> + <view class="list-cell list-cell-arrow"> + <view class="menu-item-box"> + <view>版本信息</view> + <view class="text-right">v{{version}}</view> + </view> + </view> + <view class="list-cell list-cell-arrow"> + <view class="menu-item-box"> + <view>官方邮箱</view> + <view class="text-right">7685413@qq.com</view> + </view> + </view> + <view class="list-cell list-cell-arrow"> + <view class="menu-item-box"> + <view>服务热线</view> + <view class="text-right">400-999-9999</view> + </view> + </view> + <view class="list-cell list-cell-arrow"> + <view class="menu-item-box"> + <view>公司网站</view> + <view class="text-right"> + <uni-link :href="url" :text="url" showUnderLine="false"></uni-link> + </view> + </view> + </view> + </view> + </view> + + <view class="copyright"> + <view>Copyright © 2022 iocoder.cn All Rights Reserved.</view> + </view> + </view> +</template> + +<script> + export default { + data() { + return { + url: getApp().globalData.config.appInfo.site_url, + version: getApp().globalData.config.appInfo.version + } + } + } +</script> + +<style lang="scss"> + page { + background-color: #f8f8f8; + } + + .copyright { + margin-top: 50rpx; + text-align: center; + line-height: 60rpx; + color: #999; + } + + .header-section { + display: flex; + padding: 30rpx 0 0; + flex-direction: column; + align-items: center; + } +</style> diff --git a/yudao-ui-admin-uniapp/pages/mine/avatar/index.vue b/yudao-ui-admin-uniapp/pages/mine/avatar/index.vue new file mode 100644 index 000000000..773148668 --- /dev/null +++ b/yudao-ui-admin-uniapp/pages/mine/avatar/index.vue @@ -0,0 +1,631 @@ +<template> + <view class="container"> + <view class="page-body uni-content-info"> + <view class='cropper-content'> + <view v-if="isShowImg" class="uni-corpper" :style="'width:'+cropperInitW+'px;height:'+cropperInitH+'px;background:#000'"> + <view class="uni-corpper-content" :style="'width:'+cropperW+'px;height:'+cropperH+'px;left:'+cropperL+'px;top:'+cropperT+'px'"> + <image :src="imageSrc" :style="'width:'+cropperW+'px;height:'+cropperH+'px'"></image> + <view class="uni-corpper-crop-box" @touchstart.stop="contentStartMove" @touchmove.stop="contentMoveing" @touchend.stop="contentTouchEnd" + :style="'left:'+cutL+'px;top:'+cutT+'px;right:'+cutR+'px;bottom:'+cutB+'px'"> + <view class="uni-cropper-view-box"> + <view class="uni-cropper-dashed-h"></view> + <view class="uni-cropper-dashed-v"></view> + <view class="uni-cropper-line-t" data-drag="top" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view> + <view class="uni-cropper-line-r" data-drag="right" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view> + <view class="uni-cropper-line-b" data-drag="bottom" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view> + <view class="uni-cropper-line-l" data-drag="left" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view> + <view class="uni-cropper-point point-t" data-drag="top" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view> + <view class="uni-cropper-point point-tr" data-drag="topTight"></view> + <view class="uni-cropper-point point-r" data-drag="right" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view> + <view class="uni-cropper-point point-rb" data-drag="rightBottom" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view> + <view class="uni-cropper-point point-b" data-drag="bottom" @touchstart.stop="dragStart" @touchmove.stop="dragMove" @touchend.stop="dragEnd"></view> + <view class="uni-cropper-point point-bl" data-drag="bottomLeft"></view> + <view class="uni-cropper-point point-l" data-drag="left" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view> + <view class="uni-cropper-point point-lt" data-drag="leftTop"></view> + </view> + </view> + </view> + </view> + </view> + <view class='cropper-config'> + <button type="primary reverse" @click="getImage" style='margin-top: 30rpx;'> 选择头像 </button> + <button type="warn" @click="getImageInfo" style='margin-top: 30rpx;'> 提交 </button> + </view> + <canvas canvas-id="myCanvas" :style="'position:absolute;border: 1px solid red; width:'+imageW+'px;height:'+imageH+'px;top:-9999px;left:-9999px;'"></canvas> + </view> + </view> +</template> + +<script> + import config from '@/config' + import store from "@/store" + import { uploadAvatar } from "@/api/system/user" + + const baseUrl = config.baseUrl + let sysInfo = uni.getSystemInfoSync() + let SCREEN_WIDTH = sysInfo.screenWidth + let PAGE_X, // 手按下的x位置 + PAGE_Y, // 手按下y的位置 + PR = sysInfo.pixelRatio, // dpi + T_PAGE_X, // 手移动的时候x的位置 + T_PAGE_Y, // 手移动的时候Y的位置 + CUT_L, // 初始化拖拽元素的left值 + CUT_T, // 初始化拖拽元素的top值 + CUT_R, // 初始化拖拽元素的 + CUT_B, // 初始化拖拽元素的 + CUT_W, // 初始化拖拽元素的宽度 + CUT_H, // 初始化拖拽元素的高度 + IMG_RATIO, // 图片比例 + IMG_REAL_W, // 图片实际的宽度 + IMG_REAL_H, // 图片实际的高度 + DRAFG_MOVE_RATIO = 1, //移动时候的比例, + INIT_DRAG_POSITION = 100, // 初始化屏幕宽度和裁剪区域的宽度之差,用于设置初始化裁剪的宽度 + DRAW_IMAGE_W = sysInfo.screenWidth // 设置生成的图片宽度 + + export default { + /** + * 页面的初始数据 + */ + data() { + return { + imageSrc: store.getters.avatar, + isShowImg: false, + // 初始化的宽高 + cropperInitW: SCREEN_WIDTH, + cropperInitH: SCREEN_WIDTH, + // 动态的宽高 + cropperW: SCREEN_WIDTH, + cropperH: SCREEN_WIDTH, + // 动态的left top值 + cropperL: 0, + cropperT: 0, + + transL: 0, + transT: 0, + + // 图片缩放值 + scaleP: 0, + imageW: 0, + imageH: 0, + + // 裁剪框 宽高 + cutL: 0, + cutT: 0, + cutB: SCREEN_WIDTH, + cutR: '100%', + qualityWidth: DRAW_IMAGE_W, + innerAspectRadio: DRAFG_MOVE_RATIO + } + }, + /** + * 生命周期函数--监听页面初次渲染完成 + */ + onReady: function () { + this.loadImage() + }, + methods: { + setData: function (obj) { + let that = this + Object.keys(obj).forEach(function (key) { + that.$set(that.$data, key, obj[key]) + }) + }, + getImage: function () { + var _this = this + uni.chooseImage({ + success: function (res) { + _this.setData({ + imageSrc: res.tempFilePaths[0], + }) + _this.loadImage() + }, + }) + }, + loadImage: function () { + var _this = this + + uni.getImageInfo({ + src: _this.imageSrc, + success: function success(res) { + IMG_RATIO = 1 / 1 + if (IMG_RATIO >= 1) { + IMG_REAL_W = SCREEN_WIDTH + IMG_REAL_H = SCREEN_WIDTH / IMG_RATIO + } else { + IMG_REAL_W = SCREEN_WIDTH * IMG_RATIO + IMG_REAL_H = SCREEN_WIDTH + } + let minRange = IMG_REAL_W > IMG_REAL_H ? IMG_REAL_W : IMG_REAL_H + INIT_DRAG_POSITION = minRange > INIT_DRAG_POSITION ? INIT_DRAG_POSITION : minRange + // 根据图片的宽高显示不同的效果 保证图片可以正常显示 + if (IMG_RATIO >= 1) { + let cutT = Math.ceil((SCREEN_WIDTH / IMG_RATIO - (SCREEN_WIDTH / IMG_RATIO - INIT_DRAG_POSITION)) / 2) + let cutB = cutT + let cutL = Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH + INIT_DRAG_POSITION) / 2) + let cutR = cutL + _this.setData({ + cropperW: SCREEN_WIDTH, + cropperH: SCREEN_WIDTH / IMG_RATIO, + // 初始化left right + cropperL: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH) / 2), + cropperT: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH / IMG_RATIO) / 2), + cutL: cutL, + cutT: cutT, + cutR: cutR, + cutB: cutB, + // 图片缩放值 + imageW: IMG_REAL_W, + imageH: IMG_REAL_H, + scaleP: IMG_REAL_W / SCREEN_WIDTH, + qualityWidth: DRAW_IMAGE_W, + innerAspectRadio: IMG_RATIO + }) + } else { + let cutL = Math.ceil((SCREEN_WIDTH * IMG_RATIO - (SCREEN_WIDTH * IMG_RATIO)) / 2) + let cutR = cutL + let cutT = Math.ceil((SCREEN_WIDTH - INIT_DRAG_POSITION) / 2) + let cutB = cutT + _this.setData({ + cropperW: SCREEN_WIDTH * IMG_RATIO, + cropperH: SCREEN_WIDTH, + // 初始化left right + cropperL: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH * IMG_RATIO) / 2), + cropperT: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH) / 2), + + cutL: cutL, + cutT: cutT, + cutR: cutR, + cutB: cutB, + // 图片缩放值 + imageW: IMG_REAL_W, + imageH: IMG_REAL_H, + scaleP: IMG_REAL_W / SCREEN_WIDTH, + qualityWidth: DRAW_IMAGE_W, + innerAspectRadio: IMG_RATIO + }) + } + _this.setData({ + isShowImg: true + }) + uni.hideLoading() + } + }) + }, + // 拖动时候触发的touchStart事件 + contentStartMove(e) { + PAGE_X = e.touches[0].pageX + PAGE_Y = e.touches[0].pageY + }, + + // 拖动时候触发的touchMove事件 + contentMoveing(e) { + var _this = this + var dragLengthX = (PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO + var dragLengthY = (PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO + // 左移 + if (dragLengthX > 0) { + if (this.cutL - dragLengthX < 0) dragLengthX = this.cutL + } else { + if (this.cutR + dragLengthX < 0) dragLengthX = -this.cutR + } + + if (dragLengthY > 0) { + if (this.cutT - dragLengthY < 0) dragLengthY = this.cutT + } else { + if (this.cutB + dragLengthY < 0) dragLengthY = -this.cutB + } + this.setData({ + cutL: this.cutL - dragLengthX, + cutT: this.cutT - dragLengthY, + cutR: this.cutR + dragLengthX, + cutB: this.cutB + dragLengthY + }) + + PAGE_X = e.touches[0].pageX + PAGE_Y = e.touches[0].pageY + }, + + contentTouchEnd() { + + }, + + // 获取图片 + getImageInfo() { + var _this = this + uni.showLoading({ + title: '图片生成中...', + }) + // 将图片写入画布 + const ctx = uni.createCanvasContext('myCanvas') + ctx.drawImage(_this.imageSrc, 0, 0, IMG_REAL_W, IMG_REAL_H) + ctx.draw(true, () => { + // 获取画布要裁剪的位置和宽度 均为百分比 * 画布中图片的宽度 保证了在微信小程序中裁剪的图片模糊 位置不对的问题 canvasT = (_this.cutT / _this.cropperH) * (_this.imageH / pixelRatio) + var canvasW = ((_this.cropperW - _this.cutL - _this.cutR) / _this.cropperW) * IMG_REAL_W + var canvasH = ((_this.cropperH - _this.cutT - _this.cutB) / _this.cropperH) * IMG_REAL_H + var canvasL = (_this.cutL / _this.cropperW) * IMG_REAL_W + var canvasT = (_this.cutT / _this.cropperH) * IMG_REAL_H + uni.canvasToTempFilePath({ + x: canvasL, + y: canvasT, + width: canvasW, + height: canvasH, + destWidth: canvasW, + destHeight: canvasH, + quality: 0.5, + canvasId: 'myCanvas', + success: function (res) { + uni.hideLoading() + let data = {name: 'avatarFile', filePath: res.tempFilePath} + uploadAvatar(data).then(response => { + store.commit('SET_AVATAR', response.data) + uni.showToast({ title: "修改成功", icon: 'success' }) + uni.navigateBack() + }) + } + }) + }) + }, + // 设置大小的时候触发的touchStart事件 + dragStart(e) { + T_PAGE_X = e.touches[0].pageX + T_PAGE_Y = e.touches[0].pageY + CUT_L = this.cutL + CUT_R = this.cutR + CUT_B = this.cutB + CUT_T = this.cutT + }, + + // 设置大小的时候触发的touchMove事件 + dragMove(e) { + var _this = this + var dragType = e.target.dataset.drag + switch (dragType) { + case 'right': + var dragLength = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO + if (CUT_R + dragLength < 0) dragLength = -CUT_R + this.setData({ + cutR: CUT_R + dragLength + }) + break + case 'left': + var dragLength = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO + if (CUT_L - dragLength < 0) dragLength = CUT_L + if ((CUT_L - dragLength) > (this.cropperW - this.cutR)) dragLength = CUT_L - (this.cropperW - this.cutR) + this.setData({ + cutL: CUT_L - dragLength + }) + break + case 'top': + var dragLength = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO + if (CUT_T - dragLength < 0) dragLength = CUT_T + if ((CUT_T - dragLength) > (this.cropperH - this.cutB)) dragLength = CUT_T - (this.cropperH - this.cutB) + this.setData({ + cutT: CUT_T - dragLength + }) + break + case 'bottom': + var dragLength = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO + if (CUT_B + dragLength < 0) dragLength = -CUT_B + this.setData({ + cutB: CUT_B + dragLength + }) + break + case 'rightBottom': + var dragLengthX = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO + var dragLengthY = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO + + if (CUT_B + dragLengthY < 0) dragLengthY = -CUT_B + if (CUT_R + dragLengthX < 0) dragLengthX = -CUT_R + let cutB = CUT_B + dragLengthY + let cutR = CUT_R + dragLengthX + + this.setData({ + cutB: cutB, + cutR: cutR + }) + break + default: + break + } + } + } + } +</script> + +<style> + /* pages/uni-cropper/index.wxss */ + + .uni-content-info { + /* position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: block; + align-items: center; + flex-direction: column; */ + } + + .cropper-config { + padding: 20rpx 40rpx; + } + + .cropper-content { + min-height: 750rpx; + width: 100%; + } + + .uni-corpper { + position: relative; + overflow: hidden; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-tap-highlight-color: transparent; + -webkit-touch-callout: none; + box-sizing: border-box; + } + + .uni-corpper-content { + position: relative; + } + + .uni-corpper-content image { + display: block; + width: 100%; + min-width: 0 !important; + max-width: none !important; + height: 100%; + min-height: 0 !important; + max-height: none !important; + image-orientation: 0deg !important; + margin: 0 auto; + } + /* 移动图片效果 */ + + .uni-cropper-drag-box { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + cursor: move; + background: rgba(0, 0, 0, 0.6); + z-index: 1; + } + /* 内部的信息 */ + + .uni-corpper-crop-box { + position: absolute; + background: rgba(255, 255, 255, 0.3); + z-index: 2; + } + + .uni-corpper-crop-box .uni-cropper-view-box { + position: relative; + display: block; + width: 100%; + height: 100%; + overflow: visible; + outline: 1rpx solid #69f; + outline-color: rgba(102, 153, 255, .75) + } + /* 横向虚线 */ + + .uni-cropper-dashed-h { + position: absolute; + top: 33.33333333%; + left: 0; + width: 100%; + height: 33.33333333%; + border-top: 1rpx dashed rgba(255, 255, 255, 0.5); + border-bottom: 1rpx dashed rgba(255, 255, 255, 0.5); + } + /* 纵向虚线 */ + + .uni-cropper-dashed-v { + position: absolute; + left: 33.33333333%; + top: 0; + width: 33.33333333%; + height: 100%; + border-left: 1rpx dashed rgba(255, 255, 255, 0.5); + border-right: 1rpx dashed rgba(255, 255, 255, 0.5); + } + /* 四个方向的线 为了之后的拖动事件*/ + + .uni-cropper-line-t { + position: absolute; + display: block; + width: 100%; + background-color: #69f; + top: 0; + left: 0; + height: 1rpx; + opacity: 0.1; + cursor: n-resize; + } + + .uni-cropper-line-t::before { + content: ''; + position: absolute; + top: 50%; + right: 0rpx; + width: 100%; + -webkit-transform: translate3d(0, -50%, 0); + transform: translate3d(0, -50%, 0); + bottom: 0; + height: 41rpx; + background: transparent; + z-index: 11; + } + + .uni-cropper-line-r { + position: absolute; + display: block; + background-color: #69f; + top: 0; + right: 0rpx; + width: 1rpx; + opacity: 0.1; + height: 100%; + cursor: e-resize; + } + + .uni-cropper-line-r::before { + content: ''; + position: absolute; + top: 0; + left: 50%; + width: 41rpx; + -webkit-transform: translate3d(-50%, 0, 0); + transform: translate3d(-50%, 0, 0); + bottom: 0; + height: 100%; + background: transparent; + z-index: 11; + } + + .uni-cropper-line-b { + position: absolute; + display: block; + width: 100%; + background-color: #69f; + bottom: 0; + left: 0; + height: 1rpx; + opacity: 0.1; + cursor: s-resize; + } + + .uni-cropper-line-b::before { + content: ''; + position: absolute; + top: 50%; + right: 0rpx; + width: 100%; + -webkit-transform: translate3d(0, -50%, 0); + transform: translate3d(0, -50%, 0); + bottom: 0; + height: 41rpx; + background: transparent; + z-index: 11; + } + + .uni-cropper-line-l { + position: absolute; + display: block; + background-color: #69f; + top: 0; + left: 0; + width: 1rpx; + opacity: 0.1; + height: 100%; + cursor: w-resize; + } + + .uni-cropper-line-l::before { + content: ''; + position: absolute; + top: 0; + left: 50%; + width: 41rpx; + -webkit-transform: translate3d(-50%, 0, 0); + transform: translate3d(-50%, 0, 0); + bottom: 0; + height: 100%; + background: transparent; + z-index: 11; + } + + .uni-cropper-point { + width: 5rpx; + height: 5rpx; + background-color: #69f; + opacity: .75; + position: absolute; + z-index: 3; + } + + .point-t { + top: -3rpx; + left: 50%; + margin-left: -3rpx; + cursor: n-resize; + } + + .point-tr { + top: -3rpx; + left: 100%; + margin-left: -3rpx; + cursor: n-resize; + } + + .point-r { + top: 50%; + left: 100%; + margin-left: -3rpx; + margin-top: -3rpx; + cursor: n-resize; + } + + .point-rb { + left: 100%; + top: 100%; + -webkit-transform: translate3d(-50%, -50%, 0); + transform: translate3d(-50%, -50%, 0); + cursor: n-resize; + width: 36rpx; + height: 36rpx; + background-color: #69f; + position: absolute; + z-index: 1112; + opacity: 1; + } + + .point-b { + left: 50%; + top: 100%; + margin-left: -3rpx; + margin-top: -3rpx; + cursor: n-resize; + } + + .point-bl { + left: 0%; + top: 100%; + margin-left: -3rpx; + margin-top: -3rpx; + cursor: n-resize; + } + + .point-l { + left: 0%; + top: 50%; + margin-left: -3rpx; + margin-top: -3rpx; + cursor: n-resize; + } + + .point-lt { + left: 0%; + top: 0%; + margin-left: -3rpx; + margin-top: -3rpx; + cursor: n-resize; + } + /* 裁剪框预览内容 */ + + .uni-cropper-viewer { + position: relative; + width: 100%; + height: 100%; + overflow: hidden; + } + + .uni-cropper-viewer image { + position: absolute; + z-index: 2; + } +</style> diff --git a/yudao-ui-admin-uniapp/pages/mine/help/index.vue b/yudao-ui-admin-uniapp/pages/mine/help/index.vue new file mode 100644 index 000000000..4cffe5550 --- /dev/null +++ b/yudao-ui-admin-uniapp/pages/mine/help/index.vue @@ -0,0 +1,112 @@ +<template> + <view class="help-container"> + <view v-for="(item, findex) in list" :key="findex" :title="item.title" class="list-title"> + <view class="text-title"> + <view :class="item.icon"></view>{{ item.title }} + </view> + <view class="childList"> + <view v-for="(child, zindex) in item.childList" :key="zindex" class="question" hover-class="hover" + @click="handleText(child)"> + <view class="text-item">{{ child.title }}</view> + <view class="line" v-if="zindex !== item.childList.length - 1"></view> + </view> + </view> + </view> + </view> +</template> + +<script> + export default { + data() { + return { + list: [{ + icon: 'iconfont icon-github', + title: '芋道问题', + childList: [{ + title: '芋道开源吗?', + content: '开源' + }, { + title: '芋道可以商用吗?', + content: '可以' + }, { + title: '芋道官网地址多少?', + content: 'https://www.iocoder.cn' + }, { + title: '芋道文档地址多少?', + content: 'https://doc.iocoder.cn' + }] + }, + { + icon: 'iconfont icon-help', + title: '其他问题', + childList: [{ + title: '如何退出登录?', + content: '请点击[我的] - [应用设置] - [退出登录]即可退出登录', + }, { + title: '如何修改用户头像?', + content: '请点击[我的] - [选择头像] - [点击提交]即可更换用户头像', + }, { + title: '如何修改登录密码?', + content: '请点击[我的] - [应用设置] - [修改密码]即可修改登录密码', + }] + } + ] + } + }, + methods: { + handleText(item) { + this.$tab.navigateTo(`/pages/common/textview/index?title=${item.title}&content=${item.content}`) + } + } + } +</script> + +<style lang="scss" scoped> + page { + background-color: #f8f8f8; + } + + .help-container { + margin-bottom: 100rpx; + padding: 30rpx; + } + + .list-title { + margin-bottom: 30rpx; + } + + .childList { + background: #ffffff; + box-shadow: 0px 0px 10rpx rgba(193, 193, 193, 0.2); + border-radius: 16rpx; + margin-top: 10rpx; + } + + .line { + width: 100%; + height: 1rpx; + background-color: #F5F5F5; + } + + .text-title { + color: #303133; + font-size: 32rpx; + font-weight: bold; + margin-left: 10rpx; + + .iconfont { + font-size: 16px; + margin-right: 10rpx; + } + } + + .text-item { + font-size: 28rpx; + padding: 24rpx; + } + + .question { + color: #606266; + font-size: 28rpx; + } +</style> diff --git a/yudao-ui-admin-uniapp/pages/mine/index.vue b/yudao-ui-admin-uniapp/pages/mine/index.vue new file mode 100644 index 000000000..42e2120df --- /dev/null +++ b/yudao-ui-admin-uniapp/pages/mine/index.vue @@ -0,0 +1,198 @@ +<template> + <view class="mine-container" :style="{height: `${windowHeight}px`}"> + <!--顶部个人信息栏--> + <view class="header-section"> + <view class="flex padding justify-between"> + <view class="flex align-center"> + <view v-if="!avatar" class="cu-avatar xl round bg-white"> + <view class="iconfont icon-people text-gray icon"></view> + </view> + <image v-if="avatar" @click="handleToAvatar" :src="avatar" class="cu-avatar xl round" mode="widthFix"> + </image> + <view v-if="!name" @click="handleToLogin" class="login-tip"> + 点击登录 + </view> + <view v-if="name" @click="handleToInfo" class="user-info"> + <view class="u_title"> + 用户名:{{ name }} + </view> + </view> + </view> + <view @click="handleToInfo" class="flex align-center"> + <text>个人信息</text> + <view class="iconfont icon-right"></view> + </view> + </view> + </view> + + <view class="content-section"> + <view class="mine-actions grid col-4 text-center"> + <view class="action-item" @click="handleJiaoLiuQun"> + <view class="iconfont icon-friendfill text-pink icon"></view> + <text class="text">交流群</text> + </view> + <view class="action-item" @click="handleBuilding"> + <view class="iconfont icon-service text-blue icon"></view> + <text class="text">在线客服</text> + </view> + <view class="action-item" @click="handleBuilding"> + <view class="iconfont icon-community text-mauve icon"></view> + <text class="text">反馈社区</text> + </view> + <view class="action-item" @click="handleBuilding"> + <view class="iconfont icon-dianzan text-green icon"></view> + <text class="text">点赞我们</text> + </view> + </view> + + <view class="menu-list"> + <view class="list-cell list-cell-arrow" @click="handleToEditInfo"> + <view class="menu-item-box"> + <view class="iconfont icon-user menu-icon"></view> + <view>编辑资料</view> + </view> + </view> + <view class="list-cell list-cell-arrow" @click="handleHelp"> + <view class="menu-item-box"> + <view class="iconfont icon-help menu-icon"></view> + <view>常见问题</view> + </view> + </view> + <view class="list-cell list-cell-arrow" @click="handleAbout"> + <view class="menu-item-box"> + <view class="iconfont icon-aixin menu-icon"></view> + <view>关于我们</view> + </view> + </view> + <view class="list-cell list-cell-arrow" @click="handleToSetting"> + <view class="menu-item-box"> + <view class="iconfont icon-setting menu-icon"></view> + <view>应用设置</view> + </view> + </view> + </view> + + </view> + </view> +</template> + +<script> + import storage from '@/utils/storage' + + export default { + data() { + return { + name: this.$store.state.user.name, + version: getApp().globalData.config.appInfo.version + } + }, + computed: { + avatar() { + return this.$store.state.user.avatar + }, + windowHeight() { + return uni.getSystemInfoSync().windowHeight - 50 + } + }, + methods: { + handleToInfo() { + this.$tab.navigateTo('/pages/mine/info/index') + }, + handleToEditInfo() { + this.$tab.navigateTo('/pages/mine/info/edit') + }, + handleToSetting() { + this.$tab.navigateTo('/pages/mine/setting/index') + }, + handleToLogin() { + this.$tab.reLaunch('/pages/login') + }, + handleToAvatar() { + this.$tab.navigateTo('/pages/mine/avatar/index') + }, + handleLogout() { + this.$modal.confirm('确定注销并退出系统吗?').then(() => { + this.$store.dispatch('LogOut').then(() => { + this.$tab.reLaunch('/pages/index') + }) + }) + }, + handleHelp() { + this.$tab.navigateTo('/pages/mine/help/index') + }, + handleAbout() { + this.$tab.navigateTo('/pages/mine/about/index') + }, + handleJiaoLiuQun() { + this.$modal.showToast('微信搜索 naidaguo 后,添加好友后拉你进技术交流群') + }, + handleBuilding() { + this.$modal.showToast('模块建设中~') + } + } + } +</script> + +<style lang="scss"> + page { + background-color: #f5f6f7; + } + + .mine-container { + width: 100%; + height: 100%; + + + .header-section { + padding: 15px 15px 45px 15px; + background-color: #3c96f3; + color: white; + + .login-tip { + font-size: 18px; + margin-left: 10px; + } + + .cu-avatar { + border: 2px solid #eaeaea; + + .icon { + font-size: 40px; + } + } + + .user-info { + margin-left: 15px; + + .u_title { + font-size: 18px; + line-height: 30px; + } + } + } + + .content-section { + position: relative; + top: -50px; + + .mine-actions { + margin: 15px 15px; + padding: 20px 0px; + border-radius: 8px; + background-color: white; + + .action-item { + .icon { + font-size: 28px; + } + + .text { + display: block; + font-size: 13px; + margin: 8px 0px; + } + } + } + } + } +</style> diff --git a/yudao-ui-admin-uniapp/pages/mine/info/edit.vue b/yudao-ui-admin-uniapp/pages/mine/info/edit.vue new file mode 100644 index 000000000..44d8ce4c0 --- /dev/null +++ b/yudao-ui-admin-uniapp/pages/mine/info/edit.vue @@ -0,0 +1,128 @@ +<template> + <view class="container"> + <view class="example"> + <uni-forms ref="form" :model="user" labelWidth="80px"> + <uni-forms-item label="用户昵称" name="nickname"> + <uni-easyinput v-model="user.nickname" placeholder="请输入昵称" /> + </uni-forms-item> + <uni-forms-item label="手机号码" name="mobile"> + <uni-easyinput v-model="user.mobile" placeholder="请输入手机号码" /> + </uni-forms-item> + <uni-forms-item label="邮箱" name="email"> + <uni-easyinput v-model="user.email" placeholder="请输入邮箱" /> + </uni-forms-item> + <!-- TODO 芋艿:uni-data-checkbox 存在问题 --> + <uni-forms-item label="性别" name="sex" required> +<!-- <uni-data-checkbox v-model="user.sex" :localdata="sexs" />--> + </uni-forms-item> + </uni-forms> + <button type="primary" @click="submit">提交</button> + </view> + </view> +</template> + +<script> + import { getUserProfile } from "@/api/system/user" + import { updateUserProfile } from "@/api/system/user" + + export default { + data() { + return { + user: { + nickname: "", + mobile: "", + email: "", + sex: "" + }, + sexs: [{ + text: '男', + value: "1" + }, { + text: '女', + value: "2" + }], + rules: { + nickname: { + rules: [{ + required: true, + errorMessage: '用户昵称不能为空' + }] + }, + mobile: { + rules: [{ + required: true, + errorMessage: '手机号码不能为空' + }, { + pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, + errorMessage: '请输入正确的手机号码' + }] + }, + email: { + rules: [{ + required: true, + errorMessage: '邮箱地址不能为空' + }, { + format: 'email', + errorMessage: '请输入正确的邮箱地址' + }] + } + } + } + }, + onLoad() { + this.getUser() + }, + onReady() { + this.$refs.form.setRules(this.rules) + }, + methods: { + getUser() { + getUserProfile().then(response => { + this.user = response.data + }) + }, + submit(ref) { + this.$refs.form.validate().then(res => { + updateUserProfile(this.user).then(response => { + this.$modal.msgSuccess("修改成功") + }) + }) + } + } + } +</script> + +<style lang="scss"> + page { + background-color: #ffffff; + } + + .example { + padding: 15px; + background-color: #fff; + } + + .segmented-control { + margin-bottom: 15px; + } + + .button-group { + margin-top: 15px; + display: flex; + justify-content: space-around; + } + + .form-item { + display: flex; + align-items: center; + flex: 1; + } + + .button { + display: flex; + align-items: center; + height: 35px; + line-height: 35px; + margin-left: 10px; + } +</style> diff --git a/yudao-ui-admin-uniapp/pages/mine/info/index.vue b/yudao-ui-admin-uniapp/pages/mine/info/index.vue new file mode 100644 index 000000000..2e519e8f5 --- /dev/null +++ b/yudao-ui-admin-uniapp/pages/mine/info/index.vue @@ -0,0 +1,44 @@ +<template> + <view class="container"> + <uni-list> + <uni-list-item showExtraIcon="true" :extraIcon="{type: 'person-filled'}" title="昵称" :rightText="user.nickname" /> + <uni-list-item showExtraIcon="true" :extraIcon="{type: 'phone-filled'}" title="手机号码" :rightText="user.mobile" /> + <uni-list-item showExtraIcon="true" :extraIcon="{type: 'email-filled'}" title="邮箱" :rightText="user.email" /> + <uni-list-item showExtraIcon="true" :extraIcon="{type: 'auth-filled'}" title="岗位" :rightText="(user.posts || []).map(post => post.name).join(',')" /> + <uni-list-item showExtraIcon="true" :extraIcon="{type: 'staff-filled'}" title="角色" :rightText="(user.roles || []).map(role => role.name).join(',')" /> + <uni-list-item showExtraIcon="true" :extraIcon="{type: 'calendar-filled'}" title="创建日期" :rightText="this.parseTime(user.createTime)" /> + </uni-list> + </view> +</template> + +<script> + import { getUserProfile } from "@/api/system/user" + import { parseTime } from "@/utils/ruoyi" + + export default { + data() { + return { + user: {} + } + }, + onLoad() { + this.getUser() + }, + methods: { + getUser() { + getUserProfile().then(response => { + this.user = response.data + }) + }, + parseTime(time) { + return parseTime(time) + } + } + } +</script> + +<style lang="scss"> + page { + background-color: #ffffff; + } +</style> diff --git a/yudao-ui-admin-uniapp/pages/mine/pwd/index.vue b/yudao-ui-admin-uniapp/pages/mine/pwd/index.vue new file mode 100644 index 000000000..da9567f5f --- /dev/null +++ b/yudao-ui-admin-uniapp/pages/mine/pwd/index.vue @@ -0,0 +1,85 @@ +<template> + <view class="pwd-retrieve-container"> + <uni-forms ref="form" :value="user" labelWidth="80px"> + <uni-forms-item name="oldPassword" label="旧密码"> + <uni-easyinput type="password" v-model="user.oldPassword" placeholder="请输入旧密码" /> + </uni-forms-item> + <uni-forms-item name="newPassword" label="新密码"> + <uni-easyinput type="password" v-model="user.newPassword" placeholder="请输入新密码" /> + </uni-forms-item> + <uni-forms-item name="confirmPassword" label="确认密码"> + <uni-easyinput type="password" v-model="user.confirmPassword" placeholder="请确认新密码" /> + </uni-forms-item> + <button type="primary" @click="submit">提交</button> + </uni-forms> + </view> +</template> + +<script> + import { updateUserPwd } from "@/api/system/user" + + export default { + data() { + return { + user: { + oldPassword: undefined, + newPassword: undefined, + confirmPassword: undefined + }, + rules: { + oldPassword: { + rules: [{ + required: true, + errorMessage: '旧密码不能为空' + }] + }, + newPassword: { + rules: [{ + required: true, + errorMessage: '新密码不能为空', + }, + { + minLength: 6, + maxLength: 20, + errorMessage: '长度在 6 到 20 个字符' + } + ] + }, + confirmPassword: { + rules: [{ + required: true, + errorMessage: '确认密码不能为空' + }, { + validateFunction: (rule, value, data) => data.newPassword === value, + errorMessage: '两次输入的密码不一致' + } + ] + } + } + } + }, + onReady() { + this.$refs.form.setRules(this.rules) + }, + methods: { + submit() { + this.$refs.form.validate().then(res => { + updateUserPwd(this.user.oldPassword, this.user.newPassword).then(response => { + this.$modal.msgSuccess("修改成功") + }) + }) + } + } + } +</script> + +<style lang="scss"> + page { + background-color: #ffffff; + } + + .pwd-retrieve-container { + padding-top: 36rpx; + padding: 15px; + } +</style> diff --git a/yudao-ui-admin-uniapp/pages/mine/setting/index.vue b/yudao-ui-admin-uniapp/pages/mine/setting/index.vue new file mode 100644 index 000000000..0f9f058ea --- /dev/null +++ b/yudao-ui-admin-uniapp/pages/mine/setting/index.vue @@ -0,0 +1,78 @@ +<template> + <view class="setting-container" :style="{height: `${windowHeight}px`}"> + <view class="menu-list"> + <view class="list-cell list-cell-arrow" @click="handleToPwd"> + <view class="menu-item-box"> + <view class="iconfont icon-password menu-icon"></view> + <view>修改密码</view> + </view> + </view> + <view class="list-cell list-cell-arrow" @click="handleToUpgrade"> + <view class="menu-item-box"> + <view class="iconfont icon-refresh menu-icon"></view> + <view>检查更新</view> + </view> + </view> + <view class="list-cell list-cell-arrow" @click="handleCleanTmp"> + <view class="menu-item-box"> + <view class="iconfont icon-clean menu-icon"></view> + <view>清理缓存</view> + </view> + </view> + </view> + <view class="cu-list menu"> + <view class="cu-item item-box"> + <view class="content text-center" @click="handleLogout"> + <text class="text-black">退出登录</text> + </view> + </view> + </view> + </view> +</template> + +<script> + export default { + data() { + return { + windowHeight: uni.getSystemInfoSync().windowHeight + } + }, + methods: { + handleToPwd() { + this.$tab.navigateTo('/pages/mine/pwd/index') + }, + handleToUpgrade() { + this.$modal.showToast('模块建设中~') + }, + handleCleanTmp() { + this.$modal.showToast('模块建设中~') + }, + handleLogout() { + this.$modal.confirm('确定注销并退出系统吗?').then(() => { + this.$store.dispatch('LogOut').then(() => { + this.$tab.reLaunch('/pages/index') + }) + }) + } + } + } +</script> + +<style lang="scss" scoped> + .page { + background-color: #f8f8f8; + } + + .item-box { + background-color: #FFFFFF; + margin: 30rpx; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 10rpx; + border-radius: 8rpx; + color: #303133; + font-size: 32rpx; + } +</style> diff --git a/yudao-ui-admin-uniapp/pages/work/index.vue b/yudao-ui-admin-uniapp/pages/work/index.vue new file mode 100644 index 000000000..1afefc915 --- /dev/null +++ b/yudao-ui-admin-uniapp/pages/work/index.vue @@ -0,0 +1,183 @@ +<template> + <view class="work-container"> + <!-- 轮播图 --> + <uni-swiper-dot class="uni-swiper-dot-box" :info="data" :current="current" field="content"> + <swiper class="swiper-box" :current="swiperDotIndex" @change="changeSwiper"> + <swiper-item v-for="(item, index) in data" :key="index"> + <view class="swiper-item" @click="clickBannerItem(item)"> + <image :src="item.image" mode="aspectFill" :draggable="false" /> + </view> + </swiper-item> + </swiper> + </uni-swiper-dot> + + <!-- 宫格组件 --> + <uni-section title="系统管理" type="line"></uni-section> + <view class="grid-body"> + <uni-grid :column="4" :showBorder="false" @change="changeGrid"> + <uni-grid-item> + <view class="grid-item-box"> + <uni-icons type="person-filled" size="30"></uni-icons> + <text class="text">用户管理</text> + </view> + </uni-grid-item> + <uni-grid-item> + <view class="grid-item-box"> + <uni-icons type="staff-filled" size="30"></uni-icons> + <text class="text">角色管理</text> + </view> + </uni-grid-item> + <uni-grid-item> + <view class="grid-item-box"> + <uni-icons type="color" size="30"></uni-icons> + <text class="text">菜单管理</text> + </view> + </uni-grid-item> + <uni-grid-item> + <view class="grid-item-box"> + <uni-icons type="settings-filled" size="30"></uni-icons> + <text class="text">部门管理</text> + </view> + </uni-grid-item> + <uni-grid-item> + <view class="grid-item-box"> + <uni-icons type="heart-filled" size="30"></uni-icons> + <text class="text">岗位管理</text> + </view> + </uni-grid-item> + <uni-grid-item> + <view class="grid-item-box"> + <uni-icons type="bars" size="30"></uni-icons> + <text class="text">字典管理</text> + </view> + </uni-grid-item> + <uni-grid-item> + <view class="grid-item-box"> + <uni-icons type="gear-filled" size="30"></uni-icons> + <text class="text">参数设置</text> + </view> + </uni-grid-item> + <uni-grid-item> + <view class="grid-item-box"> + <uni-icons type="chat-filled" size="30"></uni-icons> + <text class="text">通知公告</text> + </view> + </uni-grid-item> + <uni-grid-item> + <view class="grid-item-box"> + <uni-icons type="wallet-filled" size="30"></uni-icons> + <text class="text">日志管理</text> + </view> + </uni-grid-item> + </uni-grid> + </view> + </view> +</template> + +<script> + export default { + data() { + return { + current: 0, + swiperDotIndex: 0, + data: [{ + image: '/static/images/banner/banner01.jpg' + }, + { + image: '/static/images/banner/banner02.jpg' + }, + { + image: '/static/images/banner/banner03.jpg' + } + ] + } + }, + methods: { + clickBannerItem(item) { + console.info(item) + }, + changeSwiper(e) { + this.current = e.detail.current + }, + changeGrid(e) { + this.$modal.showToast('模块建设中~') + } + } + } +</script> + +<style lang="scss"> + /* #ifndef APP-NVUE */ + page { + display: flex; + flex-direction: column; + box-sizing: border-box; + background-color: #fff; + min-height: 100%; + height: auto; + } + + view { + font-size: 14px; + line-height: inherit; + } + + /* #endif */ + + .text { + text-align: center; + font-size: 26rpx; + margin-top: 10rpx; + } + + .grid-item-box { + flex: 1; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + align-items: center; + justify-content: center; + padding: 15px 0; + } + + .uni-margin-wrap { + width: 690rpx; + width: 100%; + ; + } + + .swiper { + height: 300rpx; + } + + .swiper-box { + height: 150px; + } + + .swiper-item { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + justify-content: center; + align-items: center; + color: #fff; + height: 300rpx; + line-height: 300rpx; + } + + @media screen and (min-width: 500px) { + .uni-swiper-dot-box { + width: 400px; + /* #ifndef APP-NVUE */ + margin: 0 auto; + /* #endif */ + margin-top: 8px; + } + + .image { + width: 100%; + } + } +</style> diff --git a/yudao-ui-admin-uniapp/permission.js b/yudao-ui-admin-uniapp/permission.js new file mode 100644 index 000000000..a47d94738 --- /dev/null +++ b/yudao-ui-admin-uniapp/permission.js @@ -0,0 +1,39 @@ +import { getAccessToken } from '@/utils/auth' + +// 登录页面 +const loginPage = "/pages/login" + +// 页面白名单 +const whiteList = [ + '/pages/login', '/pages/common/webview/index' +] + +// 检查地址白名单 +function checkWhite(url) { + const path = url.split('?')[0] + return whiteList.indexOf(path) !== -1 +} + +// 页面跳转验证拦截器 +let list = ["navigateTo", "redirectTo", "reLaunch", "switchTab"] +list.forEach(item => { + uni.addInterceptor(item, { + invoke(to) { + if (getAccessToken()) { + if (to.path === loginPage) { + uni.reLaunch({ url: "/" }) + } + return true + } else { + if (checkWhite(to.url)) { + return true + } + uni.reLaunch({ url: loginPage }) + return false + } + }, + fail(err) { + console.log(err) + } + }) +}) diff --git a/yudao-ui-admin-uniapp/plugins/auth.js b/yudao-ui-admin-uniapp/plugins/auth.js new file mode 100644 index 000000000..3b91c14ef --- /dev/null +++ b/yudao-ui-admin-uniapp/plugins/auth.js @@ -0,0 +1,60 @@ +import store from '@/store' + +function authPermission(permission) { + const all_permission = "*:*:*" + const permissions = store.getters && store.getters.permissions + if (permission && permission.length > 0) { + return permissions.some(v => { + return all_permission === v || v === permission + }) + } else { + return false + } +} + +function authRole(role) { + const super_admin = "admin" + const roles = store.getters && store.getters.roles + if (role && role.length > 0) { + return roles.some(v => { + return super_admin === v || v === role + }) + } else { + return false + } +} + +export default { + // 验证用户是否具备某权限 + hasPermi(permission) { + return authPermission(permission) + }, + // 验证用户是否含有指定权限,只需包含其中一个 + hasPermiOr(permissions) { + return permissions.some(item => { + return authPermission(item) + }) + }, + // 验证用户是否含有指定权限,必须全部拥有 + hasPermiAnd(permissions) { + return permissions.every(item => { + return authPermission(item) + }) + }, + // 验证用户是否具备某角色 + hasRole(role) { + return authRole(role) + }, + // 验证用户是否含有指定角色,只需包含其中一个 + hasRoleOr(roles) { + return roles.some(item => { + return authRole(item) + }) + }, + // 验证用户是否含有指定角色,必须全部拥有 + hasRoleAnd(roles) { + return roles.every(item => { + return authRole(item) + }) + } +} diff --git a/yudao-ui-admin-uniapp/plugins/index.js b/yudao-ui-admin-uniapp/plugins/index.js new file mode 100644 index 000000000..efbae151d --- /dev/null +++ b/yudao-ui-admin-uniapp/plugins/index.js @@ -0,0 +1,14 @@ +import tab from './tab' +import auth from './auth' +import modal from './modal' + +export default { + install(Vue) { + // 页签操作 + Vue.prototype.$tab = tab + // 认证对象 + Vue.prototype.$auth = auth + // 模态框对象 + Vue.prototype.$modal = modal + } +} diff --git a/yudao-ui-admin-uniapp/plugins/modal.js b/yudao-ui-admin-uniapp/plugins/modal.js new file mode 100644 index 000000000..87960fd40 --- /dev/null +++ b/yudao-ui-admin-uniapp/plugins/modal.js @@ -0,0 +1,74 @@ +export default { + // 消息提示 + msg(content) { + uni.showToast({ + title: content, + icon: 'none' + }) + }, + // 错误消息 + msgError(content) { + uni.showToast({ + title: content, + icon: 'error' + }) + }, + // 成功消息 + msgSuccess(content) { + uni.showToast({ + title: content, + icon: 'success' + }) + }, + // 隐藏消息 + hideMsg(content) { + uni.hideToast() + }, + // 弹出提示 + alert(content) { + uni.showModal({ + title: '提示', + content: content, + showCancel: false + }) + }, + // 确认窗体 + confirm(content) { + return new Promise((resolve, reject) => { + uni.showModal({ + title: '系统提示', + content: content, + cancelText: '取消', + confirmText: '确定', + success: function(res) { + if (res.confirm) { + resolve(res.confirm) + } + } + }) + }) + }, + // 提示信息 + showToast(option) { + if (typeof option === "object") { + uni.showToast(option) + } else { + uni.showToast({ + title: option, + icon: "none", + duration: 2500 + }) + } + }, + // 打开遮罩层 + loading(content) { + uni.showLoading({ + title: content, + icon: 'none' + }) + }, + // 关闭遮罩层 + closeLoading() { + uni.hideLoading() + } +} diff --git a/yudao-ui-admin-uniapp/plugins/tab.js b/yudao-ui-admin-uniapp/plugins/tab.js new file mode 100644 index 000000000..5d1b30580 --- /dev/null +++ b/yudao-ui-admin-uniapp/plugins/tab.js @@ -0,0 +1,30 @@ +export default { + // 关闭所有页面,打开到应用内的某个页面 + reLaunch(url) { + return uni.reLaunch({ + url: url + }) + }, + // 跳转到tabBar页面,并关闭其他所有非tabBar页面 + switchTab(url) { + return uni.switchTab({ + url: url + }) + }, + // 关闭当前页面,跳转到应用内的某个页面 + redirectTo(url) { + return uni.redirectTo({ + url: url + }) + }, + // 保留当前页面,跳转到应用内的某个页面 + navigateTo(url) { + return uni.navigateTo({ + url: url + }) + }, + // 关闭当前页面,返回上一页面或多级页面 + navigateBack() { + return uni.navigateBack() + } +} diff --git a/yudao-ui-admin-uniapp/static/favicon.ico b/yudao-ui-admin-uniapp/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..6f07782abfc7881a73d3f47a00b761c183e06ff9 GIT binary patch literal 16958 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 literal 0 HcmV?d00001 diff --git a/yudao-ui-admin-uniapp/static/font/iconfont.css b/yudao-ui-admin-uniapp/static/font/iconfont.css new file mode 100644 index 000000000..39aed3da7 --- /dev/null +++ b/yudao-ui-admin-uniapp/static/font/iconfont.css @@ -0,0 +1,90 @@ +@font-face { + font-family: "iconfont"; + src: url('/static/font/iconfont.ttf') format('truetype'); +} + +.iconfont { + font-family: "iconfont" !important; + font-size: 16px; + display: inline-block; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-user:before { + content: "\e7ae"; +} + +.icon-password:before { + content: "\e8b2"; +} + +.icon-code:before { + content: "\e699"; +} + +.icon-setting:before { + content: "\e6cc"; +} + +.icon-share:before { + content: "\e739"; +} + +.icon-edit:before { + content: "\e60c"; +} + +.icon-version:before { + content: "\e63f"; +} + +.icon-service:before { + content: "\e6ff"; +} + +.icon-friendfill:before { + content: "\e726"; +} + +.icon-community:before { + content: "\e741"; +} + +.icon-people:before { + content: "\e736"; +} + +.icon-dianzan:before { + content: "\ec7f"; +} + +.icon-right:before { + content: "\e7eb"; +} + +.icon-logout:before { + content: "\e61d"; +} + +.icon-help:before { + content: "\e616"; +} + +.icon-github:before { + content: "\e628"; +} + +.icon-aixin:before { + content: "\e601"; +} + +.icon-clean:before { + content: "\e607"; +} + +.icon-refresh:before { + content: "\e604"; +} + diff --git a/yudao-ui-admin-uniapp/static/font/iconfont.ttf b/yudao-ui-admin-uniapp/static/font/iconfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..53915cafcb782962308dc5f2bea68bb528f84de4 GIT binary patch literal 6724 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 literal 0 HcmV?d00001 diff --git a/yudao-ui-admin-uniapp/static/images/banner/banner01.jpg b/yudao-ui-admin-uniapp/static/images/banner/banner01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c44d84c908b2bcb048e4dbe438d1f3ff48058f01 GIT binary patch literal 39640 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	~ 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 Rl0umNJDUFcqcQ(I`Cq|3vk?FQ literal 0 HcmV?d00001 diff --git a/yudao-ui-admin-uniapp/static/images/banner/banner02.jpg b/yudao-ui-admin-uniapp/static/images/banner/banner02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1086afd3c71c51472b01e2b8b1a14be3587a5b9f GIT binary patch literal 37061 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 literal 0 HcmV?d00001 diff --git a/yudao-ui-admin-uniapp/static/images/banner/banner03.jpg b/yudao-ui-admin-uniapp/static/images/banner/banner03.jpg new file mode 100644 index 0000000000000000000000000000000000000000..092a5fc234fddbcdcc6ed598c30f6e603aa9b9f5 GIT binary patch literal 38123 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ȇ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 Z^grK@u`mYS8yJRsR<o?et%Sc1{{tn)9hCq8 literal 0 HcmV?d00001 diff --git a/yudao-ui-admin-uniapp/static/images/profile.jpg b/yudao-ui-admin-uniapp/static/images/profile.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b3a940b21cc9dcea01e62d94e243eebcf76d96bc GIT binary patch literal 81131 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 z≺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 literal 0 HcmV?d00001 diff --git a/yudao-ui-admin-uniapp/static/images/tabbar/home.png b/yudao-ui-admin-uniapp/static/images/tabbar/home.png new file mode 100644 index 0000000000000000000000000000000000000000..50acdfdde68a0b48c62409c2706e8da8eee36910 GIT binary patch literal 3265 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 literal 0 HcmV?d00001 diff --git a/yudao-ui-admin-uniapp/static/images/tabbar/home_.png b/yudao-ui-admin-uniapp/static/images/tabbar/home_.png new file mode 100644 index 0000000000000000000000000000000000000000..a408f71b28693f358228ff050e2d04617ba1e007 GIT binary patch literal 3229 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 literal 0 HcmV?d00001 diff --git a/yudao-ui-admin-uniapp/static/images/tabbar/mine.png b/yudao-ui-admin-uniapp/static/images/tabbar/mine.png new file mode 100644 index 0000000000000000000000000000000000000000..f13fe44d266c1b0d6f17feda0ae376217865c88c GIT binary patch literal 4235 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 literal 0 HcmV?d00001 diff --git a/yudao-ui-admin-uniapp/static/images/tabbar/mine_.png b/yudao-ui-admin-uniapp/static/images/tabbar/mine_.png new file mode 100644 index 0000000000000000000000000000000000000000..8a0a742ff2812dd3189927f289ca6cefd9950472 GIT binary patch literal 4219 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 Ar~m)} literal 0 HcmV?d00001 diff --git a/yudao-ui-admin-uniapp/static/images/tabbar/work.png b/yudao-ui-admin-uniapp/static/images/tabbar/work.png new file mode 100644 index 0000000000000000000000000000000000000000..21e130d8e788d2ad97508c62ae7d65d618481b47 GIT binary patch literal 4108 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 G{r><2moMf3 literal 0 HcmV?d00001 diff --git a/yudao-ui-admin-uniapp/static/images/tabbar/work_.png b/yudao-ui-admin-uniapp/static/images/tabbar/work_.png new file mode 100644 index 0000000000000000000000000000000000000000..80b979c5a3356c09cf37f1ca742c0da982293448 GIT binary patch literal 5008 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 a-+ox4z)NM}p*%Hd0~qR>BFnTL9{&eNattW| literal 0 HcmV?d00001 diff --git a/yudao-ui-admin-uniapp/static/index.html b/yudao-ui-admin-uniapp/static/index.html new file mode 100644 index 000000000..a7af653b0 --- /dev/null +++ b/yudao-ui-admin-uniapp/static/index.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html lang="zh-CN"> + <head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> + <meta name="renderer" content="webkit"> + <title><%= htmlWebpackPlugin.options.title %></title> + <link rel="shortcut icon" type="image/x-icon" href="<%= BASE_URL %>static/favicon.ico"> + <script> + var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)')) + document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />') + </script> + <link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" /> + </head> + <body> + <noscript> + <strong>本站点必须要开启JavaScript才能运行.</strong> + </noscript> + <div id="app"></div> +</html> \ No newline at end of file diff --git a/yudao-ui-admin-uniapp/static/logo.png b/yudao-ui-admin-uniapp/static/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b4270c06716f80b3c722933329cd42a6dd4593fa GIT binary patch literal 5748 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 D>ZUMX literal 0 HcmV?d00001 diff --git a/yudao-ui-admin-uniapp/static/logo200.png b/yudao-ui-admin-uniapp/static/logo200.png new file mode 100644 index 0000000000000000000000000000000000000000..ffa9988266f7852b40e1475a89bd02aae63976bd GIT binary patch literal 7995 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 literal 0 HcmV?d00001 diff --git a/yudao-ui-admin-uniapp/static/scss/colorui.css b/yudao-ui-admin-uniapp/static/scss/colorui.css new file mode 100644 index 000000000..fade3b29e --- /dev/null +++ b/yudao-ui-admin-uniapp/static/scss/colorui.css @@ -0,0 +1,3912 @@ +/* + ColorUi for uniApp v2.1.6 | by 文晓港 2019-05-31 10:44:24 + 仅供学习交流,如作它用所承受的法律责任一概与作者无关 + + *使用ColorUi开发扩展与插件时,请注明基于ColorUi开发 + + (QQ交流群:240787041) +*/ + +/* ================== + 初始化 + ==================== */ +body { + background-color: #f1f1f1; + font-size: 28upx; + color: #333333; + font-family: Helvetica Neue, Helvetica, sans-serif; +} + +view, +scroll-view, +swiper, +button, +input, +textarea, +label, +navigator, +image { + box-sizing: border-box; +} + +.round { + border-radius: 5000upx; +} + +.radius { + border-radius: 6upx; +} + +/* ================== + 图片 + ==================== */ + +image { + max-width: 100%; + display: inline-block; + position: relative; + z-index: 0; +} + +image.loading::before { + content: ""; + background-color: #f5f5f5; + display: block; + position: absolute; + width: 100%; + height: 100%; + z-index: -2; +} + +image.loading::after { + content: "\e7f1"; + font-family: "cuIcon"; + position: absolute; + top: 0; + left: 0; + width: 32upx; + height: 32upx; + line-height: 32upx; + right: 0; + bottom: 0; + z-index: -1; + font-size: 32upx; + margin: auto; + color: #ccc; + -webkit-animation: cuIcon-spin 2s infinite linear; + animation: cuIcon-spin 2s infinite linear; + display: block; +} + +.response { + width: 100%; +} + +/* ================== + 开关 + ==================== */ + +switch, +checkbox, +radio { + position: relative; +} + +switch::after, +switch::before { + font-family: "cuIcon"; + content: "\e645"; + position: absolute; + color: #ffffff !important; + top: 0%; + left: 0upx; + font-size: 26upx; + line-height: 26px; + width: 50%; + text-align: center; + pointer-events: none; + transform: scale(0, 0); + transition: all 0.3s ease-in-out 0s; + z-index: 9; + bottom: 0; + height: 26px; + margin: auto; +} + +switch::before { + content: "\e646"; + right: 0; + transform: scale(1, 1); + left: auto; +} + +switch[checked]::after, +switch.checked::after { + transform: scale(1, 1); +} + +switch[checked]::before, +switch.checked::before { + transform: scale(0, 0); +} + +/* #ifndef MP-ALIPAY */ +radio::before, +checkbox::before { + font-family: "cuIcon"; + content: "\e645"; + position: absolute; + color: #ffffff !important; + top: 50%; + margin-top: -8px; + right: 5px; + font-size: 32upx; + line-height: 16px; + pointer-events: none; + transform: scale(1, 1); + transition: all 0.3s ease-in-out 0s; + z-index: 9; +} + +radio .wx-radio-input, +checkbox .wx-checkbox-input, +radio .uni-radio-input, +checkbox .uni-checkbox-input { + margin: 0; + width: 24px; + height: 24px; +} + +checkbox.round .wx-checkbox-input, +checkbox.round .uni-checkbox-input { + border-radius: 100upx; +} + +/* #endif */ + +switch[checked]::before { + transform: scale(0, 0); +} + +switch .wx-switch-input, +switch .uni-switch-input { + border: none; + padding: 0 24px; + width: 48px; + height: 26px; + margin: 0; + border-radius: 100upx; +} + +switch .wx-switch-input:not([class*="bg-"]), +switch .uni-switch-input:not([class*="bg-"]) { + background: #8799a3 !important; +} + +switch .wx-switch-input::after, +switch .uni-switch-input::after { + margin: auto; + width: 26px; + height: 26px; + border-radius: 100upx; + left: 0upx; + top: 0upx; + bottom: 0upx; + position: absolute; + transform: scale(0.9, 0.9); + transition: all 0.1s ease-in-out 0s; +} + +switch .wx-switch-input.wx-switch-input-checked::after, +switch .uni-switch-input.uni-switch-input-checked::after { + margin: auto; + left: 22px; + box-shadow: none; + transform: scale(0.9, 0.9); +} + +radio-group { + display: inline-block; +} + + + +switch.radius .wx-switch-input::after, +switch.radius .wx-switch-input, +switch.radius .wx-switch-input::before, +switch.radius .uni-switch-input::after, +switch.radius .uni-switch-input, +switch.radius .uni-switch-input::before { + border-radius: 10upx; +} + +switch .wx-switch-input::before, +radio.radio::before, +checkbox .wx-checkbox-input::before, +radio .wx-radio-input::before, +switch .uni-switch-input::before, +radio.radio::before, +checkbox .uni-checkbox-input::before, +radio .uni-radio-input::before { + display: none; +} + +radio.radio[checked]::after, +radio.radio .uni-radio-input-checked::after { + content: ""; + background-color: transparent; + display: block; + position: absolute; + width: 8px; + height: 8px; + z-index: 999; + top: 0upx; + left: 0upx; + right: 0; + bottom: 0; + margin: auto; + border-radius: 200upx; + /* #ifndef MP */ + border: 7px solid #ffffff !important; + /* #endif */ + + /* #ifdef MP */ + border: 8px solid #ffffff !important; + /* #endif */ +} + +.switch-sex::after { + content: "\e71c"; +} + +.switch-sex::before { + content: "\e71a"; +} + +.switch-sex .wx-switch-input, +.switch-sex .uni-switch-input { + background: #e54d42 !important; + border-color: #e54d42 !important; +} + +.switch-sex[checked] .wx-switch-input, +.switch-sex.checked .uni-switch-input { + background: #0081ff !important; + border-color: #0081ff !important; +} + +switch.red[checked] .wx-switch-input.wx-switch-input-checked, +checkbox.red[checked] .wx-checkbox-input, +radio.red[checked] .wx-radio-input, +switch.red.checked .uni-switch-input.uni-switch-input-checked, +checkbox.red.checked .uni-checkbox-input, +radio.red.checked .uni-radio-input { + background-color: #e54d42 !important; + border-color: #e54d42 !important; + color: #ffffff !important; +} + +switch.orange[checked] .wx-switch-input, +checkbox.orange[checked] .wx-checkbox-input, +radio.orange[checked] .wx-radio-input, +switch.orange.checked .uni-switch-input, +checkbox.orange.checked .uni-checkbox-input, +radio.orange.checked .uni-radio-input { + background-color: #f37b1d !important; + border-color: #f37b1d !important; + color: #ffffff !important; +} + +switch.yellow[checked] .wx-switch-input, +checkbox.yellow[checked] .wx-checkbox-input, +radio.yellow[checked] .wx-radio-input, +switch.yellow.checked .uni-switch-input, +checkbox.yellow.checked .uni-checkbox-input, +radio.yellow.checked .uni-radio-input { + background-color: #fbbd08 !important; + border-color: #fbbd08 !important; + color: #333333 !important; +} + +switch.olive[checked] .wx-switch-input, +checkbox.olive[checked] .wx-checkbox-input, +radio.olive[checked] .wx-radio-input, +switch.olive.checked .uni-switch-input, +checkbox.olive.checked .uni-checkbox-input, +radio.olive.checked .uni-radio-input { + background-color: #8dc63f !important; + border-color: #8dc63f !important; + color: #ffffff !important; +} + +switch.green[checked] .wx-switch-input, +switch[checked] .wx-switch-input, +checkbox.green[checked] .wx-checkbox-input, +checkbox[checked] .wx-checkbox-input, +radio.green[checked] .wx-radio-input, +radio[checked] .wx-radio-input, +switch.green.checked .uni-switch-input, +switch.checked .uni-switch-input, +checkbox.green.checked .uni-checkbox-input, +checkbox.checked .uni-checkbox-input, +radio.green.checked .uni-radio-input, +radio.checked .uni-radio-input { + background-color: #39b54a !important; + border-color: #39b54a !important; + color: #ffffff !important; + border-color: #39B54A !important; +} + +switch.cyan[checked] .wx-switch-input, +checkbox.cyan[checked] .wx-checkbox-input, +radio.cyan[checked] .wx-radio-input, +switch.cyan.checked .uni-switch-input, +checkbox.cyan.checked .uni-checkbox-input, +radio.cyan.checked .uni-radio-input { + background-color: #1cbbb4 !important; + border-color: #1cbbb4 !important; + color: #ffffff !important; +} + +switch.blue[checked] .wx-switch-input, +checkbox.blue[checked] .wx-checkbox-input, +radio.blue[checked] .wx-radio-input, +switch.blue.checked .uni-switch-input, +checkbox.blue.checked .uni-checkbox-input, +radio.blue.checked .uni-radio-input { + background-color: #0081ff !important; + border-color: #0081ff !important; + color: #ffffff !important; +} + +switch.purple[checked] .wx-switch-input, +checkbox.purple[checked] .wx-checkbox-input, +radio.purple[checked] .wx-radio-input, +switch.purple.checked .uni-switch-input, +checkbox.purple.checked .uni-checkbox-input, +radio.purple.checked .uni-radio-input { + background-color: #6739b6 !important; + border-color: #6739b6 !important; + color: #ffffff !important; +} + +switch.mauve[checked] .wx-switch-input, +checkbox.mauve[checked] .wx-checkbox-input, +radio.mauve[checked] .wx-radio-input, +switch.mauve.checked .uni-switch-input, +checkbox.mauve.checked .uni-checkbox-input, +radio.mauve.checked .uni-radio-input { + background-color: #9c26b0 !important; + border-color: #9c26b0 !important; + color: #ffffff !important; +} + +switch.pink[checked] .wx-switch-input, +checkbox.pink[checked] .wx-checkbox-input, +radio.pink[checked] .wx-radio-input, +switch.pink.checked .uni-switch-input, +checkbox.pink.checked .uni-checkbox-input, +radio.pink.checked .uni-radio-input { + background-color: #e03997 !important; + border-color: #e03997 !important; + color: #ffffff !important; +} + +switch.brown[checked] .wx-switch-input, +checkbox.brown[checked] .wx-checkbox-input, +radio.brown[checked] .wx-radio-input, +switch.brown.checked .uni-switch-input, +checkbox.brown.checked .uni-checkbox-input, +radio.brown.checked .uni-radio-input { + background-color: #a5673f !important; + border-color: #a5673f !important; + color: #ffffff !important; +} + +switch.grey[checked] .wx-switch-input, +checkbox.grey[checked] .wx-checkbox-input, +radio.grey[checked] .wx-radio-input, +switch.grey.checked .uni-switch-input, +checkbox.grey.checked .uni-checkbox-input, +radio.grey.checked .uni-radio-input { + background-color: #8799a3 !important; + border-color: #8799a3 !important; + color: #ffffff !important; +} + +switch.gray[checked] .wx-switch-input, +checkbox.gray[checked] .wx-checkbox-input, +radio.gray[checked] .wx-radio-input, +switch.gray.checked .uni-switch-input, +checkbox.gray.checked .uni-checkbox-input, +radio.gray.checked .uni-radio-input { + background-color: #f0f0f0 !important; + border-color: #f0f0f0 !important; + color: #333333 !important; +} + +switch.black[checked] .wx-switch-input, +checkbox.black[checked] .wx-checkbox-input, +radio.black[checked] .wx-radio-input, +switch.black.checked .uni-switch-input, +checkbox.black.checked .uni-checkbox-input, +radio.black.checked .uni-radio-input { + background-color: #333333 !important; + border-color: #333333 !important; + color: #ffffff !important; +} + +switch.white[checked] .wx-switch-input, +checkbox.white[checked] .wx-checkbox-input, +radio.white[checked] .wx-radio-input, +switch.white.checked .uni-switch-input, +checkbox.white.checked .uni-checkbox-input, +radio.white.checked .uni-radio-input { + background-color: #ffffff !important; + border-color: #ffffff !important; + color: #333333 !important; +} + +/* ================== + 边框 + ==================== */ + +/* -- 实线 -- */ + +.solid, +.solid-top, +.solid-right, +.solid-bottom, +.solid-left, +.solids, +.solids-top, +.solids-right, +.solids-bottom, +.solids-left, +.dashed, +.dashed-top, +.dashed-right, +.dashed-bottom, +.dashed-left { + position: relative; +} + +.solid::after, +.solid-top::after, +.solid-right::after, +.solid-bottom::after, +.solid-left::after, +.solids::after, +.solids-top::after, +.solids-right::after, +.solids-bottom::after, +.solids-left::after, +.dashed::after, +.dashed-top::after, +.dashed-right::after, +.dashed-bottom::after, +.dashed-left::after { + content: " "; + width: 200%; + height: 200%; + position: absolute; + top: 0; + left: 0; + border-radius: inherit; + transform: scale(0.5); + transform-origin: 0 0; + pointer-events: none; + box-sizing: border-box; +} + +.solid::after { + border: 1upx solid rgba(0, 0, 0, 0.1); +} + +.solid-top::after { + border-top: 1upx solid rgba(0, 0, 0, 0.1); +} + +.solid-right::after { + border-right: 1upx solid rgba(0, 0, 0, 0.1); +} + +.solid-bottom::after { + border-bottom: 1upx solid rgba(0, 0, 0, 0.1); +} + +.solid-left::after { + border-left: 1upx solid rgba(0, 0, 0, 0.1); +} + +.solids::after { + border: 8upx solid #eee; +} + +.solids-top::after { + border-top: 8upx solid #eee; +} + +.solids-right::after { + border-right: 8upx solid #eee; +} + +.solids-bottom::after { + border-bottom: 8upx solid #eee; +} + +.solids-left::after { + border-left: 8upx solid #eee; +} + +/* -- 虚线 -- */ + +.dashed::after { + border: 1upx dashed #ddd; +} + +.dashed-top::after { + border-top: 1upx dashed #ddd; +} + +.dashed-right::after { + border-right: 1upx dashed #ddd; +} + +.dashed-bottom::after { + border-bottom: 1upx dashed #ddd; +} + +.dashed-left::after { + border-left: 1upx dashed #ddd; +} + +/* -- 阴影 -- */ + +.shadow[class*='white'] { + --ShadowSize: 0 1upx 6upx; +} + +.shadow-lg { + --ShadowSize: 0upx 40upx 100upx 0upx; +} + +.shadow-warp { + position: relative; + box-shadow: 0 0 10upx rgba(0, 0, 0, 0.1); +} + +.shadow-warp:before, +.shadow-warp:after { + position: absolute; + content: ""; + top: 20upx; + bottom: 30upx; + left: 20upx; + width: 50%; + box-shadow: 0 30upx 20upx rgba(0, 0, 0, 0.2); + transform: rotate(-3deg); + z-index: -1; +} + +.shadow-warp:after { + right: 20upx; + left: auto; + transform: rotate(3deg); +} + +.shadow-blur { + position: relative; +} + +.shadow-blur::before { + content: ""; + display: block; + background: inherit; + filter: blur(10upx); + position: absolute; + width: 100%; + height: 100%; + top: 10upx; + left: 10upx; + z-index: -1; + opacity: 0.4; + transform-origin: 0 0; + border-radius: inherit; + transform: scale(1, 1); +} + +/* ================== + 按钮 + ==================== */ + +.cu-btn { + position: relative; + border: 0upx; + display: inline-flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + padding: 0 30upx; + font-size: 28upx; + height: 64upx; + line-height: 1; + text-align: center; + text-decoration: none; + overflow: visible; + margin-left: initial; + transform: translate(0upx, 0upx); + margin-right: initial; +} + +.cu-btn::after { + display: none; +} + +.cu-btn:not([class*="bg-"]) { + background-color: #f0f0f0; +} + +.cu-btn[class*="line"] { + background-color: transparent; +} + +.cu-btn[class*="line"]::after { + content: " "; + display: block; + width: 200%; + height: 200%; + position: absolute; + top: 0; + left: 0; + border: 1upx solid currentColor; + transform: scale(0.5); + transform-origin: 0 0; + box-sizing: border-box; + border-radius: 12upx; + z-index: 1; + pointer-events: none; +} + +.cu-btn.round[class*="line"]::after { + border-radius: 1000upx; +} + +.cu-btn[class*="lines"]::after { + border: 6upx solid currentColor; +} + +.cu-btn[class*="bg-"]::after { + display: none; +} + +.cu-btn.sm { + padding: 0 20upx; + font-size: 20upx; + height: 48upx; +} + +.cu-btn.lg { + padding: 0 40upx; + font-size: 32upx; + height: 80upx; +} + +.cu-btn.cuIcon.sm { + width: 48upx; + height: 48upx; +} + +.cu-btn.cuIcon { + width: 64upx; + height: 64upx; + border-radius: 500upx; + padding: 0; +} + +button.cuIcon.lg { + width: 80upx; + height: 80upx; +} + +.cu-btn.shadow-blur::before { + top: 4upx; + left: 4upx; + filter: blur(6upx); + opacity: 0.6; +} + +.cu-btn.button-hover { + transform: translate(1upx, 1upx); +} + +.block { + display: block; +} + +.cu-btn.block { + display: flex; +} + +.cu-btn[disabled] { + opacity: 0.6; + color: #ffffff; +} + +/* ================== + 徽章 + ==================== */ + +.cu-tag { + font-size: 24upx; + vertical-align: middle; + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + padding: 0upx 16upx; + height: 48upx; + font-family: Helvetica Neue, Helvetica, sans-serif; + white-space: nowrap; +} + +.cu-tag:not([class*="bg"]):not([class*="line"]) { + background-color: #f1f1f1; +} + +.cu-tag[class*="line-"]::after { + content: " "; + width: 200%; + height: 200%; + position: absolute; + top: 0; + left: 0; + border: 1upx solid currentColor; + transform: scale(0.5); + transform-origin: 0 0; + box-sizing: border-box; + border-radius: inherit; + z-index: 1; + pointer-events: none; +} + +.cu-tag.radius[class*="line"]::after { + border-radius: 12upx; +} + +.cu-tag.round[class*="line"]::after { + border-radius: 1000upx; +} + +.cu-tag[class*="line-"]::after { + border-radius: 0; +} + +.cu-tag+.cu-tag { + margin-left: 10upx; +} + +.cu-tag.sm { + font-size: 20upx; + padding: 0upx 12upx; + height: 32upx; +} + +.cu-capsule { + display: inline-flex; + vertical-align: middle; +} + +.cu-capsule+.cu-capsule { + margin-left: 10upx; +} + +.cu-capsule .cu-tag { + margin: 0; +} + +.cu-capsule .cu-tag[class*="line-"]:last-child::after { + border-left: 0upx solid transparent; +} + +.cu-capsule .cu-tag[class*="line-"]:first-child::after { + border-right: 0upx solid transparent; +} + +.cu-capsule.radius .cu-tag:first-child { + border-top-left-radius: 6upx; + border-bottom-left-radius: 6upx; +} + +.cu-capsule.radius .cu-tag:last-child::after, +.cu-capsule.radius .cu-tag[class*="line-"] { + border-top-right-radius: 12upx; + border-bottom-right-radius: 12upx; +} + +.cu-capsule.round .cu-tag:first-child { + border-top-left-radius: 200upx; + border-bottom-left-radius: 200upx; + text-indent: 4upx; +} + +.cu-capsule.round .cu-tag:last-child::after, +.cu-capsule.round .cu-tag:last-child { + border-top-right-radius: 200upx; + border-bottom-right-radius: 200upx; + text-indent: -4upx; +} + +.cu-tag.badge { + border-radius: 200upx; + position: absolute; + top: -10upx; + right: -10upx; + font-size: 20upx; + padding: 0upx 10upx; + height: 28upx; + color: #ffffff; +} + +.cu-tag.badge:not([class*="bg-"]) { + background-color: #dd514c; +} + +.cu-tag:empty:not([class*="cuIcon-"]) { + padding: 0upx; + width: 16upx; + height: 16upx; + top: -4upx; + right: -4upx; +} + +.cu-tag[class*="cuIcon-"] { + width: 32upx; + height: 32upx; + top: -4upx; + right: -4upx; +} + +/* ================== + 头像 + ==================== */ + +.cu-avatar { + font-variant: small-caps; + margin: 0; + padding: 0; + display: inline-flex; + text-align: center; + justify-content: center; + align-items: center; + background-color: #ccc; + color: #ffffff; + white-space: nowrap; + position: relative; + width: 64upx; + height: 64upx; + background-size: cover; + background-position: center; + vertical-align: middle; + font-size: 1.5em; +} + +.cu-avatar.sm { + width: 48upx; + height: 48upx; + font-size: 1em; +} + +.cu-avatar.lg { + width: 96upx; + height: 96upx; + font-size: 2em; +} + +.cu-avatar.xl { + width: 128upx; + height: 128upx; + font-size: 2.5em; +} + +.cu-avatar .avatar-text { + font-size: 0.4em; +} + +.cu-avatar-group { + direction: rtl; + unicode-bidi: bidi-override; + padding: 0 10upx 0 40upx; + display: inline-block; +} + +.cu-avatar-group .cu-avatar { + margin-left: -30upx; + border: 4upx solid #f1f1f1; + vertical-align: middle; +} + +.cu-avatar-group .cu-avatar.sm { + margin-left: -20upx; + border: 1upx solid #f1f1f1; +} + +/* ================== + 进度条 + ==================== */ + +.cu-progress { + overflow: hidden; + height: 28upx; + background-color: #ebeef5; + display: inline-flex; + align-items: center; + width: 100%; +} + +.cu-progress+view, +.cu-progress+text { + line-height: 1; +} + +.cu-progress.xs { + height: 10upx; +} + +.cu-progress.sm { + height: 20upx; +} + +.cu-progress view { + width: 0; + height: 100%; + align-items: center; + display: flex; + justify-items: flex-end; + justify-content: space-around; + font-size: 20upx; + color: #ffffff; + transition: width 0.6s ease; +} + +.cu-progress text { + align-items: center; + display: flex; + font-size: 20upx; + color: #333333; + text-indent: 10upx; +} + +.cu-progress.text-progress { + padding-right: 60upx; +} + +.cu-progress.striped view { + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: 72upx 72upx; +} + +.cu-progress.active view { + animation: progress-stripes 2s linear infinite; +} + +@keyframes progress-stripes { + from { + background-position: 72upx 0; + } + + to { + background-position: 0 0; + } +} + +/* ================== + 加载 + ==================== */ + +.cu-load { + display: block; + line-height: 3em; + text-align: center; +} + +.cu-load::before { + font-family: "cuIcon"; + display: inline-block; + margin-right: 6upx; +} + +.cu-load.loading::before { + content: "\e67a"; + animation: cuIcon-spin 2s infinite linear; +} + +.cu-load.loading::after { + content: "加载中..."; +} + +.cu-load.over::before { + content: "\e64a"; +} + +.cu-load.over::after { + content: "没有更多了"; +} + +.cu-load.erro::before { + content: "\e658"; +} + +.cu-load.erro::after { + content: "加载失败"; +} + +.cu-load.load-cuIcon::before { + font-size: 32upx; +} + +.cu-load.load-cuIcon::after { + display: none; +} + +.cu-load.load-cuIcon.over { + display: none; +} + +.cu-load.load-modal { + position: fixed; + top: 0; + right: 0; + bottom: 140upx; + left: 0; + margin: auto; + width: 260upx; + height: 260upx; + background-color: #ffffff; + border-radius: 10upx; + box-shadow: 0 0 0upx 2000upx rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + flex-direction: column; + justify-content: center; + font-size: 28upx; + z-index: 9999; + line-height: 2.4em; +} + +.cu-load.load-modal [class*="cuIcon-"] { + font-size: 60upx; +} + +.cu-load.load-modal image { + width: 70upx; + height: 70upx; +} + +.cu-load.load-modal::after { + content: ""; + position: absolute; + background-color: #ffffff; + border-radius: 50%; + width: 200upx; + height: 200upx; + font-size: 10px; + border-top: 6upx solid rgba(0, 0, 0, 0.05); + border-right: 6upx solid rgba(0, 0, 0, 0.05); + border-bottom: 6upx solid rgba(0, 0, 0, 0.05); + border-left: 6upx solid #f37b1d; + animation: cuIcon-spin 1s infinite linear; + z-index: -1; +} + +.load-progress { + pointer-events: none; + top: 0; + position: fixed; + width: 100%; + left: 0; + z-index: 2000; +} + +.load-progress.hide { + display: none; +} + +.load-progress .load-progress-bar { + position: relative; + width: 100%; + height: 4upx; + overflow: hidden; + transition: all 200ms ease 0s; +} + +.load-progress .load-progress-spinner { + position: absolute; + top: 10upx; + right: 10upx; + z-index: 2000; + display: block; +} + +.load-progress .load-progress-spinner::after { + content: ""; + display: block; + width: 24upx; + height: 24upx; + -webkit-box-sizing: border-box; + box-sizing: border-box; + border: solid 4upx transparent; + border-top-color: inherit; + border-left-color: inherit; + border-radius: 50%; + -webkit-animation: load-progress-spinner 0.4s linear infinite; + animation: load-progress-spinner 0.4s linear infinite; +} + +@-webkit-keyframes load-progress-spinner { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0); + } + + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes load-progress-spinner { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0); + } + + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +/* ================== + 列表 + ==================== */ +.grayscale { + filter: grayscale(1); +} + +.cu-list+.cu-list { + margin-top: 30upx +} + +.cu-list>.cu-item { + transition: all .6s ease-in-out 0s; + transform: translateX(0upx) +} + +.cu-list>.cu-item.move-cur { + transform: translateX(-260upx) +} + +.cu-list>.cu-item .move { + position: absolute; + right: 0; + display: flex; + width: 260upx; + height: 100%; + transform: translateX(100%) +} + +.cu-list>.cu-item .move view { + display: flex; + flex: 1; + justify-content: center; + align-items: center +} + +.cu-list.menu-avatar { + overflow: hidden; +} + +.cu-list.menu-avatar>.cu-item { + position: relative; + display: flex; + padding-right: 10upx; + height: 140upx; + background-color: #ffffff; + justify-content: flex-end; + align-items: center +} + +.cu-list.menu-avatar>.cu-item>.cu-avatar { + position: absolute; + left: 30upx +} + +.cu-list.menu-avatar>.cu-item .flex .text-cut { + max-width: 510upx +} + +.cu-list.menu-avatar>.cu-item .content { + position: absolute; + left: 146upx; + width: calc(100% - 96upx - 60upx - 120upx - 20upx); + line-height: 1.6em; +} + +.cu-list.menu-avatar>.cu-item .content.flex-sub { + width: calc(100% - 96upx - 60upx - 20upx); +} + +.cu-list.menu-avatar>.cu-item .content>view:first-child { + font-size: 30upx; + display: flex; + align-items: center +} + +.cu-list.menu-avatar>.cu-item .content .cu-tag.sm { + display: inline-block; + margin-left: 10upx; + height: 28upx; + font-size: 16upx; + line-height: 32upx +} + +.cu-list.menu-avatar>.cu-item .action { + width: 100upx; + text-align: center +} + +.cu-list.menu-avatar>.cu-item .action view+view { + margin-top: 10upx +} + +.cu-list.menu-avatar.comment>.cu-item .content { + position: relative; + left: 0; + width: auto; + flex: 1; +} + +.cu-list.menu-avatar.comment>.cu-item { + padding: 30upx 30upx 30upx 120upx; + height: auto +} + +.cu-list.menu-avatar.comment .cu-avatar { + align-self: flex-start +} + +.cu-list.menu>.cu-item { + position: relative; + display: flex; + padding: 0 30upx; + min-height: 100upx; + background-color: #ffffff; + justify-content: space-between; + align-items: center +} + +.cu-list.menu>.cu-item:last-child:after { + border: none +} + +.cu-list.menu-avatar>.cu-item:after, +.cu-list.menu>.cu-item:after { + position: absolute; + top: 0; + left: 0; + box-sizing: border-box; + width: 200%; + height: 200%; + border-bottom: 1upx solid #ddd; + border-radius: inherit; + content: " "; + transform: scale(.5); + transform-origin: 0 0; + pointer-events: none +} + +.cu-list.menu>.cu-item.grayscale { + background-color: #f5f5f5 +} + +.cu-list.menu>.cu-item.cur { + background-color: #fcf7e9 +} + +.cu-list.menu>.cu-item.arrow { + padding-right: 90upx +} + +.cu-list.menu>.cu-item.arrow:before { + position: absolute; + top: 0; + right: 30upx; + bottom: 0; + display: block; + margin: auto; + width: 30upx; + height: 30upx; + color: #8799a3; + content: "\e6a3"; + text-align: center; + font-size: 34upx; + font-family: cuIcon; + line-height: 30upx +} + +.cu-list.menu>.cu-item button.content { + padding: 0; + background-color: transparent; + justify-content: flex-start +} + +.cu-list.menu>.cu-item button.content:after { + display: none +} + +.cu-list.menu>.cu-item .cu-avatar-group .cu-avatar { + border-color: #ffffff +} + +.cu-list.menu>.cu-item .content>view:first-child { + display: flex; + align-items: center +} + +.cu-list.menu>.cu-item .content>text[class*=cuIcon] { + display: inline-block; + margin-right: 10upx; + width: 1.6em; + text-align: center +} + +.cu-list.menu>.cu-item .content>image { + display: inline-block; + margin-right: 10upx; + width: 1.6em; + height: 1.6em; + vertical-align: middle +} + +.cu-list.menu>.cu-item .content { + font-size: 30upx; + line-height: 1.6em; + flex: 1 +} + +.cu-list.menu>.cu-item .content .cu-tag.sm { + display: inline-block; + margin-left: 10upx; + height: 28upx; + font-size: 16upx; + line-height: 32upx +} + +.cu-list.menu>.cu-item .action .cu-tag:empty { + right: 10upx +} + +.cu-list.menu { + display: block; + overflow: hidden +} + +.cu-list.menu.sm-border>.cu-item:after { + left: 30upx; + width: calc(200% - 120upx) +} + +.cu-list.grid>.cu-item { + position: relative; + display: flex; + padding: 20upx 0 30upx; + transition-duration: 0s; + flex-direction: column +} + +.cu-list.grid>.cu-item:after { + position: absolute; + top: 0; + left: 0; + box-sizing: border-box; + width: 200%; + height: 200%; + border-right: 1px solid rgba(0, 0, 0, .1); + border-bottom: 1px solid rgba(0, 0, 0, .1); + border-radius: inherit; + content: " "; + transform: scale(.5); + transform-origin: 0 0; + pointer-events: none +} + +.cu-list.grid>.cu-item text { + display: block; + margin-top: 10upx; + color: #888; + font-size: 26upx; + line-height: 40upx +} + +.cu-list.grid>.cu-item [class*=cuIcon] { + position: relative; + display: block; + margin-top: 20upx; + width: 100%; + font-size: 48upx +} + +.cu-list.grid>.cu-item .cu-tag { + right: auto; + left: 50%; + margin-left: 20upx +} + +.cu-list.grid { + background-color: #ffffff; + text-align: center +} + +.cu-list.grid.no-border>.cu-item { + padding-top: 10upx; + padding-bottom: 20upx +} + +.cu-list.grid.no-border>.cu-item:after { + border: none +} + +.cu-list.grid.no-border { + padding: 20upx 10upx +} + +.cu-list.grid.col-3>.cu-item:nth-child(3n):after, +.cu-list.grid.col-4>.cu-item:nth-child(4n):after, +.cu-list.grid.col-5>.cu-item:nth-child(5n):after { + border-right-width: 0 +} + +.cu-list.card-menu { + overflow: hidden; + margin-right: 30upx; + margin-left: 30upx; + border-radius: 20upx +} + + +/* ================== + 操作条 + ==================== */ + +.cu-bar { + display: flex; + position: relative; + align-items: center; + min-height: 100upx; + justify-content: space-between; +} + +.cu-bar .action { + display: flex; + align-items: center; + height: 100%; + justify-content: center; + max-width: 100%; +} + +.cu-bar .action.border-title { + position: relative; + top: -10upx; +} + +.cu-bar .action.border-title text[class*="bg-"]:last-child { + position: absolute; + bottom: -0.5rem; + min-width: 2rem; + height: 6upx; + left: 0; +} + +.cu-bar .action.sub-title { + position: relative; + top: -0.2rem; +} + +.cu-bar .action.sub-title text { + position: relative; + z-index: 1; +} + +.cu-bar .action.sub-title text[class*="bg-"]:last-child { + position: absolute; + display: inline-block; + bottom: -0.2rem; + border-radius: 6upx; + width: 100%; + height: 0.6rem; + left: 0.6rem; + opacity: 0.3; + z-index: 0; +} + +.cu-bar .action.sub-title text[class*="text-"]:last-child { + position: absolute; + display: inline-block; + bottom: -0.7rem; + left: 0.5rem; + opacity: 0.2; + z-index: 0; + text-align: right; + font-weight: 900; + font-size: 36upx; +} + +.cu-bar.justify-center .action.border-title text:last-child, +.cu-bar.justify-center .action.sub-title text:last-child { + left: 0; + right: 0; + margin: auto; + text-align: center; +} + +.cu-bar .action:first-child { + margin-left: 30upx; + font-size: 30upx; +} + +.cu-bar .action text.text-cut { + text-align: left; + width: 100%; +} + +.cu-bar .cu-avatar:first-child { + margin-left: 20upx; +} + +.cu-bar .action:first-child>text[class*="cuIcon-"] { + margin-left: -0.3em; + margin-right: 0.3em; +} + +.cu-bar .action:last-child { + margin-right: 30upx; +} + +.cu-bar .action>text[class*="cuIcon-"], +.cu-bar .action>view[class*="cuIcon-"] { + font-size: 36upx; +} + +.cu-bar .action>text[class*="cuIcon-"]+text[class*="cuIcon-"] { + margin-left: 0.5em; +} + +.cu-bar .content { + position: absolute; + text-align: center; + width: calc(100% - 340upx); + left: 0; + right: 0; + bottom: 0; + top: 0; + margin: auto; + height: 60upx; + font-size: 32upx; + line-height: 60upx; + cursor: none; + pointer-events: none; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} + +.cu-bar.ios .content { + bottom: 7px; + height: 30px; + font-size: 32upx; + line-height: 30px; +} + +.cu-bar.btn-group { + justify-content: space-around; +} + +.cu-bar.btn-group button { + padding: 20upx 32upx; +} + +.cu-bar.btn-group button { + flex: 1; + margin: 0 20upx; + max-width: 50%; +} + +.cu-bar .search-form { + background-color: #f5f5f5; + line-height: 64upx; + height: 64upx; + font-size: 24upx; + color: #333333; + flex: 1; + display: flex; + align-items: center; + margin: 0 30upx; +} + +.cu-bar .search-form+.action { + margin-right: 30upx; +} + +.cu-bar .search-form input { + flex: 1; + padding-right: 30upx; + height: 64upx; + line-height: 64upx; + font-size: 26upx; + background-color: transparent; +} + +.cu-bar .search-form [class*="cuIcon-"] { + margin: 0 0.5em 0 0.8em; +} + +.cu-bar .search-form [class*="cuIcon-"]::before { + top: 0upx; +} + +.cu-bar.fixed, +.nav.fixed { + position: fixed; + width: 100%; + top: 0; + z-index: 1024; + box-shadow: 0 1upx 6upx rgba(0, 0, 0, 0.1); +} + +.cu-bar.foot { + position: fixed; + width: 100%; + bottom: 0; + z-index: 1024; + box-shadow: 0 -1upx 6upx rgba(0, 0, 0, 0.1); +} + +.cu-bar.tabbar { + padding: 0; + height: calc(100upx + env(safe-area-inset-bottom) / 2); + padding-bottom: calc(env(safe-area-inset-bottom) / 2); +} + +.cu-tabbar-height { + min-height: 100upx; + height: calc(100upx + env(safe-area-inset-bottom) / 2); +} + +.cu-bar.tabbar.shadow { + box-shadow: 0 -1upx 6upx rgba(0, 0, 0, 0.1); +} + +.cu-bar.tabbar .action { + font-size: 22upx; + position: relative; + flex: 1; + text-align: center; + padding: 0; + display: block; + height: auto; + line-height: 1; + margin: 0; + background-color: inherit; + overflow: initial; +} + +.cu-bar.tabbar.shop .action { + width: 140upx; + flex: initial; +} + +.cu-bar.tabbar .action.add-action { + position: relative; + z-index: 2; + padding-top: 50upx; +} + +.cu-bar.tabbar .action.add-action [class*="cuIcon-"] { + position: absolute; + width: 70upx; + z-index: 2; + height: 70upx; + border-radius: 50%; + line-height: 70upx; + font-size: 50upx; + top: -35upx; + left: 0; + right: 0; + margin: auto; + padding: 0; +} + +.cu-bar.tabbar .action.add-action::after { + content: ""; + position: absolute; + width: 100upx; + height: 100upx; + top: -50upx; + left: 0; + right: 0; + margin: auto; + box-shadow: 0 -3upx 8upx rgba(0, 0, 0, 0.08); + border-radius: 50upx; + background-color: inherit; + z-index: 0; +} + +.cu-bar.tabbar .action.add-action::before { + content: ""; + position: absolute; + width: 100upx; + height: 30upx; + bottom: 30upx; + left: 0; + right: 0; + margin: auto; + background-color: inherit; + z-index: 1; +} + +.cu-bar.tabbar .btn-group { + flex: 1; + display: flex; + justify-content: space-around; + align-items: center; + padding: 0 10upx; +} + +.cu-bar.tabbar button.action::after { + border: 0; +} + +.cu-bar.tabbar .action [class*="cuIcon-"] { + width: 100upx; + position: relative; + display: block; + height: auto; + margin: 0 auto 10upx; + text-align: center; + font-size: 40upx; +} + +.cu-bar.tabbar .action .cuIcon-cu-image { + margin: 0 auto; +} + +.cu-bar.tabbar .action .cuIcon-cu-image image { + width: 50upx; + height: 50upx; + display: inline-block; +} + +.cu-bar.tabbar .submit { + align-items: center; + display: flex; + justify-content: center; + text-align: center; + position: relative; + flex: 2; + align-self: stretch; +} + +.cu-bar.tabbar .submit:last-child { + flex: 2.6; +} + +.cu-bar.tabbar .submit+.submit { + flex: 2; +} + +.cu-bar.tabbar.border .action::before { + content: " "; + width: 200%; + height: 200%; + position: absolute; + top: 0; + left: 0; + transform: scale(0.5); + transform-origin: 0 0; + border-right: 1upx solid rgba(0, 0, 0, 0.1); + z-index: 3; +} + +.cu-bar.tabbar.border .action:last-child:before { + display: none; +} + +.cu-bar.input { + padding-right: 20upx; + background-color: #ffffff; +} + +.cu-bar.input input { + overflow: initial; + line-height: 64upx; + height: 64upx; + min-height: 64upx; + flex: 1; + font-size: 30upx; + margin: 0 20upx; +} + +.cu-bar.input .action { + margin-left: 20upx; +} + +.cu-bar.input .action [class*="cuIcon-"] { + font-size: 48upx; +} + +.cu-bar.input input+.action { + margin-right: 20upx; + margin-left: 0upx; +} + +.cu-bar.input .action:first-child [class*="cuIcon-"] { + margin-left: 0upx; +} + +.cu-custom { + display: block; + position: relative; +} + +.cu-custom .cu-bar .content { + width: calc(100% - 440upx); +} + +/* #ifdef MP-ALIPAY */ +.cu-custom .cu-bar .action .cuIcon-back { + opacity: 0; +} + +/* #endif */ + +.cu-custom .cu-bar .content image { + height: 60upx; + width: 240upx; +} + +.cu-custom .cu-bar { + min-height: 0px; + /* #ifdef MP-WEIXIN */ + padding-right: 220upx; + /* #endif */ + /* #ifdef MP-ALIPAY */ + padding-right: 150upx; + /* #endif */ + box-shadow: 0upx 0upx 0upx; + z-index: 9999; +} + +.cu-custom .cu-bar .border-custom { + position: relative; + background: rgba(0, 0, 0, 0.15); + border-radius: 1000upx; + height: 30px; +} + +.cu-custom .cu-bar .border-custom::after { + content: " "; + width: 200%; + height: 200%; + position: absolute; + top: 0; + left: 0; + border-radius: inherit; + transform: scale(0.5); + transform-origin: 0 0; + pointer-events: none; + box-sizing: border-box; + border: 1upx solid #ffffff; + opacity: 0.5; +} + +.cu-custom .cu-bar .border-custom::before { + content: " "; + width: 1upx; + height: 110%; + position: absolute; + top: 22.5%; + left: 0; + right: 0; + margin: auto; + transform: scale(0.5); + transform-origin: 0 0; + pointer-events: none; + box-sizing: border-box; + opacity: 0.6; + background-color: #ffffff; +} + +.cu-custom .cu-bar .border-custom text { + display: block; + flex: 1; + margin: auto !important; + text-align: center; + font-size: 34upx; +} + +/* ================== + 导航栏 + ==================== */ + +.nav { + white-space: nowrap; +} + +::-webkit-scrollbar { + display: none; +} + +.nav .cu-item { + height: 90upx; + display: inline-block; + line-height: 90upx; + margin: 0 10upx; + padding: 0 20upx; +} + +.nav .cu-item.cur { + border-bottom: 4upx solid; +} + +/* ================== + 时间轴 + ==================== */ + +.cu-timeline { + display: block; + background-color: #ffffff; +} + +.cu-timeline .cu-time { + width: 120upx; + text-align: center; + padding: 20upx 0; + font-size: 26upx; + color: #888; + display: block; +} + +.cu-timeline>.cu-item { + padding: 30upx 30upx 30upx 120upx; + position: relative; + display: block; + z-index: 0; +} + +.cu-timeline>.cu-item:not([class*="text-"]) { + color: #ccc; +} + +.cu-timeline>.cu-item::after { + content: ""; + display: block; + position: absolute; + width: 1upx; + background-color: #ddd; + left: 60upx; + height: 100%; + top: 0; + z-index: 8; +} + +.cu-timeline>.cu-item::before { + font-family: "cuIcon"; + display: block; + position: absolute; + top: 36upx; + z-index: 9; + background-color: #ffffff; + width: 50upx; + height: 50upx; + text-align: center; + border: none; + line-height: 50upx; + left: 36upx; +} + +.cu-timeline>.cu-item:not([class*="cuIcon-"])::before { + content: "\e763"; +} + +.cu-timeline>.cu-item[class*="cuIcon-"]::before { + background-color: #ffffff; + width: 50upx; + height: 50upx; + text-align: center; + border: none; + line-height: 50upx; + left: 36upx; +} + +.cu-timeline>.cu-item>.content { + padding: 30upx; + border-radius: 6upx; + display: block; + line-height: 1.6; +} + +.cu-timeline>.cu-item>.content:not([class*="bg-"]) { + background-color: #f1f1f1; + color: #333333; +} + +.cu-timeline>.cu-item>.content+.content { + margin-top: 20upx; +} + +/* ================== + 聊天 + ==================== */ + +.cu-chat { + display: flex; + flex-direction: column; +} + +.cu-chat .cu-item { + display: flex; + padding: 30upx 30upx 70upx; + position: relative; +} + +.cu-chat .cu-item>.cu-avatar { + width: 80upx; + height: 80upx; +} + +.cu-chat .cu-item>.main { + max-width: calc(100% - 260upx); + margin: 0 40upx; + display: flex; + align-items: center; +} + +.cu-chat .cu-item>image { + height: 320upx; +} + +.cu-chat .cu-item>.main .content { + padding: 20upx; + border-radius: 6upx; + display: inline-flex; + max-width: 100%; + align-items: center; + font-size: 30upx; + position: relative; + min-height: 80upx; + line-height: 40upx; + text-align: left; +} + +.cu-chat .cu-item>.main .content:not([class*="bg-"]) { + background-color: #ffffff; + color: #333333; +} + +.cu-chat .cu-item .date { + position: absolute; + font-size: 24upx; + color: #8799a3; + width: calc(100% - 320upx); + bottom: 20upx; + left: 160upx; +} + +.cu-chat .cu-item .action { + padding: 0 30upx; + display: flex; + align-items: center; +} + +.cu-chat .cu-item>.main .content::after { + content: ""; + top: 27upx; + transform: rotate(45deg); + position: absolute; + z-index: 100; + display: inline-block; + overflow: hidden; + width: 24upx; + height: 24upx; + left: -12upx; + right: initial; + background-color: inherit; +} + +.cu-chat .cu-item.self>.main .content::after { + left: auto; + right: -12upx; +} + +.cu-chat .cu-item>.main .content::before { + content: ""; + top: 30upx; + transform: rotate(45deg); + position: absolute; + z-index: -1; + display: inline-block; + overflow: hidden; + width: 24upx; + height: 24upx; + left: -12upx; + right: initial; + background-color: inherit; + filter: blur(5upx); + opacity: 0.3; +} + +.cu-chat .cu-item>.main .content:not([class*="bg-"])::before { + background-color: #333333; + opacity: 0.1; +} + +.cu-chat .cu-item.self>.main .content::before { + left: auto; + right: -12upx; +} + +.cu-chat .cu-item.self { + justify-content: flex-end; + text-align: right; +} + +.cu-chat .cu-info { + display: inline-block; + margin: 20upx auto; + font-size: 24upx; + padding: 8upx 12upx; + background-color: rgba(0, 0, 0, 0.2); + border-radius: 6upx; + color: #ffffff; + max-width: 400upx; + line-height: 1.4; +} + +/* ================== + 卡片 + ==================== */ + +.cu-card { + display: block; + overflow: hidden; +} + +.cu-card>.cu-item { + display: block; + background-color: #ffffff; + overflow: hidden; + border-radius: 10upx; + margin: 30upx; +} + +.cu-card>.cu-item.shadow-blur { + overflow: initial; +} + +.cu-card.no-card>.cu-item { + margin: 0upx; + border-radius: 0upx; +} + +.cu-card .grid.grid-square { + margin-bottom: -20upx; +} + +.cu-card.case .image { + position: relative; +} + +.cu-card.case .image image { + width: 100%; +} + +.cu-card.case .image .cu-tag { + position: absolute; + right: 0; + top: 0; +} + +.cu-card.case .image .cu-bar { + position: absolute; + bottom: 0; + width: 100%; + background-color: transparent; + padding: 0upx 30upx; +} + +.cu-card.case.no-card .image { + margin: 30upx 30upx 0; + overflow: hidden; + border-radius: 10upx; +} + +.cu-card.dynamic { + display: block; +} + +.cu-card.dynamic>.cu-item { + display: block; + background-color: #ffffff; + overflow: hidden; +} + +.cu-card.dynamic>.cu-item>.text-content { + padding: 0 30upx 0; + max-height: 6.4em; + overflow: hidden; + font-size: 30upx; + margin-bottom: 20upx; +} + +.cu-card.dynamic>.cu-item .square-img { + width: 100%; + height: 200upx; + border-radius: 6upx; +} + +.cu-card.dynamic>.cu-item .only-img { + width: 100%; + height: 320upx; + border-radius: 6upx; +} + +/* card.dynamic>.cu-item .comment { + padding: 20upx; + background-color: #f1f1f1; + margin: 0 30upx 30upx; + border-radius: 6upx; +} */ + +.cu-card.article { + display: block; +} + +.cu-card.article>.cu-item { + padding-bottom: 30upx; +} + +.cu-card.article>.cu-item .title { + font-size: 30upx; + font-weight: 900; + color: #333333; + line-height: 100upx; + padding: 0 30upx; +} + +.cu-card.article>.cu-item .content { + display: flex; + padding: 0 30upx; +} + +.cu-card.article>.cu-item .content>image { + width: 240upx; + height: 6.4em; + margin-right: 20upx; + border-radius: 6upx; +} + +.cu-card.article>.cu-item .content .desc { + flex: 1; + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.cu-card.article>.cu-item .content .text-content { + font-size: 28upx; + color: #888; + height: 4.8em; + overflow: hidden; +} + +/* ================== + 表单 + ==================== */ + +.cu-form-group { + background-color: #ffffff; + padding: 1upx 30upx; + display: flex; + align-items: center; + min-height: 100upx; + justify-content: space-between; +} + +.cu-form-group+.cu-form-group { + border-top: 1upx solid #eee; +} + +.cu-form-group .title { + text-align: justify; + padding-right: 30upx; + font-size: 30upx; + position: relative; + height: 60upx; + line-height: 60upx; +} + +.cu-form-group input { + flex: 1; + font-size: 30upx; + color: #555; + padding-right: 20upx; +} + +.cu-form-group>text[class*="cuIcon-"] { + font-size: 36upx; + padding: 0; + box-sizing: border-box; +} + +.cu-form-group textarea { + margin: 32upx 0 30upx; + height: 4.6em; + width: 100%; + line-height: 1.2em; + flex: 1; + font-size: 28upx; + padding: 0; +} + +.cu-form-group.align-start .title { + height: 1em; + margin-top: 32upx; + line-height: 1em; +} + +.cu-form-group picker { + flex: 1; + padding-right: 40upx; + overflow: hidden; + position: relative; +} + +.cu-form-group picker .picker { + line-height: 100upx; + font-size: 28upx; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + width: 100%; + text-align: right; +} + +.cu-form-group picker::after { + font-family: cuIcon; + display: block; + content: "\e6a3"; + position: absolute; + font-size: 34upx; + color: #8799a3; + line-height: 100upx; + width: 60upx; + text-align: center; + top: 0; + bottom: 0; + right: -20upx; + margin: auto; +} + +.cu-form-group textarea[disabled], +.cu-form-group textarea[disabled] .placeholder { + color: transparent; +} + +/* ================== + 模态窗口 + ==================== */ + +.cu-modal { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1110; + opacity: 0; + outline: 0; + text-align: center; + -ms-transform: scale(1.185); + transform: scale(1.185); + backface-visibility: hidden; + perspective: 2000upx; + background: rgba(0, 0, 0, 0.6); + transition: all 0.3s ease-in-out 0s; + pointer-events: none; +} + +.cu-modal::before { + content: "\200B"; + display: inline-block; + height: 100%; + vertical-align: middle; +} + +.cu-modal.show { + opacity: 1; + transition-duration: 0.3s; + -ms-transform: scale(1); + transform: scale(1); + overflow-x: hidden; + overflow-y: auto; + pointer-events: auto; +} + +.cu-dialog { + position: relative; + display: inline-block; + vertical-align: middle; + margin-left: auto; + margin-right: auto; + width: 680upx; + max-width: 100%; + background-color: #f8f8f8; + border-radius: 10upx; + overflow: hidden; +} + +.cu-modal.bottom-modal::before { + vertical-align: bottom; +} + +.cu-modal.bottom-modal .cu-dialog { + width: 100%; + border-radius: 0; +} + +.cu-modal.bottom-modal { + margin-bottom: -1000upx; +} + +.cu-modal.bottom-modal.show { + margin-bottom: 0; +} + +.cu-modal.drawer-modal { + transform: scale(1); + display: flex; +} + +.cu-modal.drawer-modal .cu-dialog { + height: 100%; + min-width: 200upx; + border-radius: 0; + margin: initial; + transition-duration: 0.3s; +} + +.cu-modal.drawer-modal.justify-start .cu-dialog { + transform: translateX(-100%); +} + +.cu-modal.drawer-modal.justify-end .cu-dialog { + transform: translateX(100%); +} + +.cu-modal.drawer-modal.show .cu-dialog { + transform: translateX(0%); +} +.cu-modal .cu-dialog>.cu-bar:first-child .action{ + min-width: 100rpx; + margin-right: 0; + min-height: 100rpx; +} +/* ================== + 轮播 + ==================== */ +swiper .a-swiper-dot { + display: inline-block; + width: 16upx; + height: 16upx; + background: rgba(0, 0, 0, .3); + border-radius: 50%; + vertical-align: middle; +} + +swiper[class*="-dot"] .wx-swiper-dots, +swiper[class*="-dot"] .a-swiper-dots, +swiper[class*="-dot"] .uni-swiper-dots { + display: flex; + align-items: center; + width: 100%; + justify-content: center; +} + +swiper.square-dot .wx-swiper-dot, +swiper.square-dot .a-swiper-dot, +swiper.square-dot .uni-swiper-dot { + background-color: #ffffff; + opacity: 0.4; + width: 10upx; + height: 10upx; + border-radius: 20upx; + margin: 0 8upx !important; +} + +swiper.square-dot .wx-swiper-dot.wx-swiper-dot-active, +swiper.square-dot .a-swiper-dot.a-swiper-dot-active, +swiper.square-dot .uni-swiper-dot.uni-swiper-dot-active { + opacity: 1; + width: 30upx; +} + +swiper.round-dot .wx-swiper-dot, +swiper.round-dot .a-swiper-dot, +swiper.round-dot .uni-swiper-dot { + width: 10upx; + height: 10upx; + position: relative; + margin: 4upx 8upx !important; +} + +swiper.round-dot .wx-swiper-dot.wx-swiper-dot-active::after, +swiper.round-dot .a-swiper-dot.a-swiper-dot-active::after, +swiper.round-dot .uni-swiper-dot.uni-swiper-dot-active::after { + content: ""; + position: absolute; + width: 10upx; + height: 10upx; + top: 0upx; + left: 0upx; + right: 0; + bottom: 0; + margin: auto; + background-color: #ffffff; + border-radius: 20upx; +} + +swiper.round-dot .wx-swiper-dot.wx-swiper-dot-active, +swiper.round-dot .a-swiper-dot.a-swiper-dot-active, +swiper.round-dot .uni-swiper-dot.uni-swiper-dot-active { + width: 18upx; + height: 18upx; +} + +.screen-swiper { + min-height: 375upx; +} + +.screen-swiper image, +.screen-swiper video, +.swiper-item image, +.swiper-item video { + width: 100%; + display: block; + height: 100%; + margin: 0; + pointer-events: none; +} + +.card-swiper { + height: 420upx !important; +} + +.card-swiper swiper-item { + width: 610upx !important; + left: 70upx; + box-sizing: border-box; + padding: 40upx 0upx 70upx; + overflow: initial; +} + +.card-swiper swiper-item .swiper-item { + width: 100%; + display: block; + height: 100%; + border-radius: 10upx; + transform: scale(0.9); + transition: all 0.2s ease-in 0s; + overflow: hidden; +} + +.card-swiper swiper-item.cur .swiper-item { + transform: none; + transition: all 0.2s ease-in 0s; +} + + +.tower-swiper { + height: 420upx; + position: relative; + max-width: 750upx; + overflow: hidden; +} + +.tower-swiper .tower-item { + position: absolute; + width: 300upx; + height: 380upx; + top: 0; + bottom: 0; + left: 50%; + margin: auto; + transition: all 0.2s ease-in 0s; + opacity: 1; +} + +.tower-swiper .tower-item.none { + opacity: 0; +} + +.tower-swiper .tower-item .swiper-item { + width: 100%; + height: 100%; + border-radius: 6upx; + overflow: hidden; +} + +/* ================== + 步骤条 + ==================== */ + +.cu-steps { + display: flex; +} + +scroll-view.cu-steps { + display: block; + white-space: nowrap; +} + +scroll-view.cu-steps .cu-item { + display: inline-block; +} + +.cu-steps .cu-item { + flex: 1; + text-align: center; + position: relative; + min-width: 100upx; +} + +.cu-steps .cu-item:not([class*="text-"]) { + color: #8799a3; +} + +.cu-steps .cu-item [class*="cuIcon-"], +.cu-steps .cu-item .num { + display: block; + font-size: 40upx; + line-height: 80upx; +} + +.cu-steps .cu-item::before, +.cu-steps .cu-item::after, +.cu-steps.steps-arrow .cu-item::before, +.cu-steps.steps-arrow .cu-item::after { + content: ""; + display: block; + position: absolute; + height: 0px; + width: calc(100% - 80upx); + border-bottom: 1px solid #ccc; + left: calc(0px - (100% - 80upx) / 2); + top: 40upx; + z-index: 0; +} + +.cu-steps.steps-arrow .cu-item::before, +.cu-steps.steps-arrow .cu-item::after { + content: "\e6a3"; + font-family: 'cuIcon'; + height: 30upx; + border-bottom-width: 0px; + line-height: 30upx; + top: 0; + bottom: 0; + margin: auto; + color: #ccc; +} + +.cu-steps.steps-bottom .cu-item::before, +.cu-steps.steps-bottom .cu-item::after { + bottom: 40upx; + top: initial; +} + +.cu-steps .cu-item::after { + border-bottom: 1px solid currentColor; + width: 0px; + transition: all 0.3s ease-in-out 0s; +} + +.cu-steps .cu-item[class*="text-"]::after { + width: calc(100% - 80upx); + color: currentColor; +} + +.cu-steps .cu-item:first-child::before, +.cu-steps .cu-item:first-child::after { + display: none; +} + +.cu-steps .cu-item .num { + width: 40upx; + height: 40upx; + border-radius: 50%; + line-height: 40upx; + margin: 20upx auto; + font-size: 24upx; + border: 1px solid currentColor; + position: relative; + overflow: hidden; +} + +.cu-steps .cu-item[class*="text-"] .num { + background-color: currentColor; +} + +.cu-steps .cu-item .num::before, +.cu-steps .cu-item .num::after { + content: attr(data-index); + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; + transition: all 0.3s ease-in-out 0s; + transform: translateY(0upx); +} + +.cu-steps .cu-item[class*="text-"] .num::before { + transform: translateY(-40upx); + color: #ffffff; +} + +.cu-steps .cu-item .num::after { + transform: translateY(40upx); + color: #ffffff; + transition: all 0.3s ease-in-out 0s; +} + +.cu-steps .cu-item[class*="text-"] .num::after { + content: "\e645"; + font-family: 'cuIcon'; + color: #ffffff; + transform: translateY(0upx); +} + +.cu-steps .cu-item[class*="text-"] .num.err::after { + content: "\e646"; +} + +/* ================== + 布局 + ==================== */ + +/* -- flex弹性布局 -- */ + +.flex { + display: flex; +} + +.basis-xs { + flex-basis: 20%; +} + +.basis-sm { + flex-basis: 40%; +} + +.basis-df { + flex-basis: 50%; +} + +.basis-lg { + flex-basis: 60%; +} + +.basis-xl { + flex-basis: 80%; +} + +.flex-sub { + flex: 1; +} + +.flex-twice { + flex: 2; +} + +.flex-treble { + flex: 3; +} + +.flex-direction { + flex-direction: column; +} + +.flex-wrap { + flex-wrap: wrap; +} + +.align-start { + align-items: flex-start; +} + +.align-end { + align-items: flex-end; +} + +.align-center { + align-items: center; +} + +.align-stretch { + align-items: stretch; +} + +.self-start { + align-self: flex-start; +} + +.self-center { + align-self: flex-center; +} + +.self-end { + align-self: flex-end; +} + +.self-stretch { + align-self: stretch; +} + +.align-stretch { + align-items: stretch; +} + +.justify-start { + justify-content: flex-start; +} + +.justify-end { + justify-content: flex-end; +} + +.justify-center { + justify-content: center; +} + +.justify-between { + justify-content: space-between; +} + +.justify-around { + justify-content: space-around; +} + +/* grid布局 */ + +.grid { + display: flex; + flex-wrap: wrap; +} + +.grid.grid-square { + overflow: hidden; +} + +.grid.grid-square .cu-tag { + position: absolute; + right: 0; + top: 0; + border-bottom-left-radius: 6upx; + padding: 6upx 12upx; + height: auto; + background-color: rgba(0, 0, 0, 0.5); +} + +.grid.grid-square>view>text[class*="cuIcon-"] { + font-size: 52upx; + position: absolute; + color: #8799a3; + margin: auto; + top: 0; + bottom: 0; + left: 0; + right: 0; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.grid.grid-square>view { + margin-right: 20upx; + margin-bottom: 20upx; + border-radius: 6upx; + position: relative; + overflow: hidden; +} +.grid.grid-square>view.bg-img image { + width: 100%; + height: 100%; + position: absolute; +} +.grid.col-1.grid-square>view { + padding-bottom: 100%; + height: 0; + margin-right: 0; +} + +.grid.col-2.grid-square>view { + padding-bottom: calc((100% - 20upx)/2); + height: 0; + width: calc((100% - 20upx)/2); +} + +.grid.col-3.grid-square>view { + padding-bottom: calc((100% - 40upx)/3); + height: 0; + width: calc((100% - 40upx)/3); +} + +.grid.col-4.grid-square>view { + padding-bottom: calc((100% - 60upx)/4); + height: 0; + width: calc((100% - 60upx)/4); +} + +.grid.col-5.grid-square>view { + padding-bottom: calc((100% - 80upx)/5); + height: 0; + width: calc((100% - 80upx)/5); +} + +.grid.col-2.grid-square>view:nth-child(2n), +.grid.col-3.grid-square>view:nth-child(3n), +.grid.col-4.grid-square>view:nth-child(4n), +.grid.col-5.grid-square>view:nth-child(5n) { + margin-right: 0; +} + +.grid.col-1>view { + width: 100%; +} + +.grid.col-2>view { + width: 50%; +} + +.grid.col-3>view { + width: 33.33%; +} + +.grid.col-4>view { + width: 25%; +} + +.grid.col-5>view { + width: 20%; +} + +/* -- 内外边距 -- */ + +.margin-0 { + margin: 0; +} + +.margin-xs { + margin: 10upx; +} + +.margin-sm { + margin: 20upx; +} + +.margin { + margin: 30upx; +} + +.margin-lg { + margin: 40upx; +} + +.margin-xl { + margin: 50upx; +} + +.margin-top-xs { + margin-top: 10upx; +} + +.margin-top-sm { + margin-top: 20upx; +} + +.margin-top { + margin-top: 30upx; +} + +.margin-top-lg { + margin-top: 40upx; +} + +.margin-top-xl { + margin-top: 50upx; +} + +.margin-right-xs { + margin-right: 10upx; +} + +.margin-right-sm { + margin-right: 20upx; +} + +.margin-right { + margin-right: 30upx; +} + +.margin-right-lg { + margin-right: 40upx; +} + +.margin-right-xl { + margin-right: 50upx; +} + +.margin-bottom-xs { + margin-bottom: 10upx; +} + +.margin-bottom-sm { + margin-bottom: 20upx; +} + +.margin-bottom { + margin-bottom: 30upx; +} + +.margin-bottom-lg { + margin-bottom: 40upx; +} + +.margin-bottom-xl { + margin-bottom: 50upx; +} + +.margin-left-xs { + margin-left: 10upx; +} + +.margin-left-sm { + margin-left: 20upx; +} + +.margin-left { + margin-left: 30upx; +} + +.margin-left-lg { + margin-left: 40upx; +} + +.margin-left-xl { + margin-left: 50upx; +} + +.margin-lr-xs { + margin-left: 10upx; + margin-right: 10upx; +} + +.margin-lr-sm { + margin-left: 20upx; + margin-right: 20upx; +} + +.margin-lr { + margin-left: 30upx; + margin-right: 30upx; +} + +.margin-lr-lg { + margin-left: 40upx; + margin-right: 40upx; +} + +.margin-lr-xl { + margin-left: 50upx; + margin-right: 50upx; +} + +.margin-tb-xs { + margin-top: 10upx; + margin-bottom: 10upx; +} + +.margin-tb-sm { + margin-top: 20upx; + margin-bottom: 20upx; +} + +.margin-tb { + margin-top: 30upx; + margin-bottom: 30upx; +} + +.margin-tb-lg { + margin-top: 40upx; + margin-bottom: 40upx; +} + +.margin-tb-xl { + margin-top: 50upx; + margin-bottom: 50upx; +} + +.padding-0 { + padding: 0; +} + +.padding-xs { + padding: 10upx; +} + +.padding-sm { + padding: 20upx; +} + +.padding { + padding: 30upx; +} + +.padding-lg { + padding: 40upx; +} + +.padding-xl { + padding: 50upx; +} + +.padding-top-xs { + padding-top: 10upx; +} + +.padding-top-sm { + padding-top: 20upx; +} + +.padding-top { + padding-top: 30upx; +} + +.padding-top-lg { + padding-top: 40upx; +} + +.padding-top-xl { + padding-top: 50upx; +} + +.padding-right-xs { + padding-right: 10upx; +} + +.padding-right-sm { + padding-right: 20upx; +} + +.padding-right { + padding-right: 30upx; +} + +.padding-right-lg { + padding-right: 40upx; +} + +.padding-right-xl { + padding-right: 50upx; +} + +.padding-bottom-xs { + padding-bottom: 10upx; +} + +.padding-bottom-sm { + padding-bottom: 20upx; +} + +.padding-bottom { + padding-bottom: 30upx; +} + +.padding-bottom-lg { + padding-bottom: 40upx; +} + +.padding-bottom-xl { + padding-bottom: 50upx; +} + +.padding-left-xs { + padding-left: 10upx; +} + +.padding-left-sm { + padding-left: 20upx; +} + +.padding-left { + padding-left: 30upx; +} + +.padding-left-lg { + padding-left: 40upx; +} + +.padding-left-xl { + padding-left: 50upx; +} + +.padding-lr-xs { + padding-left: 10upx; + padding-right: 10upx; +} + +.padding-lr-sm { + padding-left: 20upx; + padding-right: 20upx; +} + +.padding-lr { + padding-left: 30upx; + padding-right: 30upx; +} + +.padding-lr-lg { + padding-left: 40upx; + padding-right: 40upx; +} + +.padding-lr-xl { + padding-left: 50upx; + padding-right: 50upx; +} + +.padding-tb-xs { + padding-top: 10upx; + padding-bottom: 10upx; +} + +.padding-tb-sm { + padding-top: 20upx; + padding-bottom: 20upx; +} + +.padding-tb { + padding-top: 30upx; + padding-bottom: 30upx; +} + +.padding-tb-lg { + padding-top: 40upx; + padding-bottom: 40upx; +} + +.padding-tb-xl { + padding-top: 50upx; + padding-bottom: 50upx; +} + +/* -- 浮动 -- */ + +.cf::after, +.cf::before { + content: " "; + display: table; +} + +.cf::after { + clear: both; +} + +.fl { + float: left; +} + +.fr { + float: right; +} + +/* ================== + 背景 + ==================== */ + +.line-red::after, +.lines-red::after { + border-color: #e54d42; +} + +.line-orange::after, +.lines-orange::after { + border-color: #f37b1d; +} + +.line-yellow::after, +.lines-yellow::after { + border-color: #fbbd08; +} + +.line-olive::after, +.lines-olive::after { + border-color: #8dc63f; +} + +.line-green::after, +.lines-green::after { + border-color: #39b54a; +} + +.line-cyan::after, +.lines-cyan::after { + border-color: #1cbbb4; +} + +.line-blue::after, +.lines-blue::after { + border-color: #0081ff; +} + +.line-purple::after, +.lines-purple::after { + border-color: #6739b6; +} + +.line-mauve::after, +.lines-mauve::after { + border-color: #9c26b0; +} + +.line-pink::after, +.lines-pink::after { + border-color: #e03997; +} + +.line-brown::after, +.lines-brown::after { + border-color: #a5673f; +} + +.line-grey::after, +.lines-grey::after { + border-color: #8799a3; +} + +.line-gray::after, +.lines-gray::after { + border-color: #aaaaaa; +} + +.line-black::after, +.lines-black::after { + border-color: #333333; +} + +.line-white::after, +.lines-white::after { + border-color: #ffffff; +} + +.bg-red { + background-color: #e54d42; + color: #ffffff; +} + +.bg-orange { + background-color: #f37b1d; + color: #ffffff; +} + +.bg-yellow { + background-color: #fbbd08; + color: #333333; +} + +.bg-olive { + background-color: #8dc63f; + color: #ffffff; +} + +.bg-green { + background-color: #39b54a; + color: #ffffff; +} + +.bg-cyan { + background-color: #1cbbb4; + color: #ffffff; +} + +.bg-blue { + background-color: #0081ff; + color: #ffffff; +} + +.bg-purple { + background-color: #6739b6; + color: #ffffff; +} + +.bg-mauve { + background-color: #9c26b0; + color: #ffffff; +} + +.bg-pink { + background-color: #e03997; + color: #ffffff; +} + +.bg-brown { + background-color: #a5673f; + color: #ffffff; +} + +.bg-grey { + background-color: #8799a3; + color: #ffffff; +} + +.bg-gray { + background-color: #f0f0f0; + color: #333333; +} + +.bg-black { + background-color: #333333; + color: #ffffff; +} + +.bg-white { + background-color: #ffffff; + color: #666666; +} + +.bg-shadeTop { + background-image: linear-gradient(rgba(0, 0, 0, 1), rgba(0, 0, 0, 0.01)); + color: #ffffff; +} + +.bg-shadeBottom { + background-image: linear-gradient(rgba(0, 0, 0, 0.01), rgba(0, 0, 0, 1)); + color: #ffffff; +} + +.bg-red.light { + color: #e54d42; + background-color: #fadbd9; +} + +.bg-orange.light { + color: #f37b1d; + background-color: #fde6d2; +} + +.bg-yellow.light { + color: #fbbd08; + background-color: #fef2ced2; +} + +.bg-olive.light { + color: #8dc63f; + background-color: #e8f4d9; +} + +.bg-green.light { + color: #39b54a; + background-color: #d7f0dbff; +} + +.bg-cyan.light { + color: #1cbbb4; + background-color: #d2f1f0; +} + +.bg-blue.light { + color: #0081ff; + background-color: #cce6ff; +} + +.bg-purple.light { + color: #6739b6; + background-color: #e1d7f0; +} + +.bg-mauve.light { + color: #9c26b0; + background-color: #ebd4ef; +} + +.bg-pink.light { + color: #e03997; + background-color: #f9d7ea; +} + +.bg-brown.light { + color: #a5673f; + background-color: #ede1d9; +} + +.bg-grey.light { + color: #8799a3; + background-color: #e7ebed; +} + +.bg-gradual-red { + background-image: linear-gradient(45deg, #f43f3b, #ec008c); + color: #ffffff; +} + +.bg-gradual-orange { + background-image: linear-gradient(45deg, #ff9700, #ed1c24); + color: #ffffff; +} + +.bg-gradual-green { + background-image: linear-gradient(45deg, #39b54a, #8dc63f); + color: #ffffff; +} + +.bg-gradual-purple { + background-image: linear-gradient(45deg, #9000ff, #5e00ff); + color: #ffffff; +} + +.bg-gradual-pink { + background-image: linear-gradient(45deg, #ec008c, #6739b6); + color: #ffffff; +} + +.bg-gradual-blue { + background-image: linear-gradient(45deg, #0081ff, #1cbbb4); + color: #ffffff; +} + +.shadow[class*="-red"] { + box-shadow: 6upx 6upx 8upx rgba(204, 69, 59, 0.2); +} + +.shadow[class*="-orange"] { + box-shadow: 6upx 6upx 8upx rgba(217, 109, 26, 0.2); +} + +.shadow[class*="-yellow"] { + box-shadow: 6upx 6upx 8upx rgba(224, 170, 7, 0.2); +} + +.shadow[class*="-olive"] { + box-shadow: 6upx 6upx 8upx rgba(124, 173, 55, 0.2); +} + +.shadow[class*="-green"] { + box-shadow: 6upx 6upx 8upx rgba(48, 156, 63, 0.2); +} + +.shadow[class*="-cyan"] { + box-shadow: 6upx 6upx 8upx rgba(28, 187, 180, 0.2); +} + +.shadow[class*="-blue"] { + box-shadow: 6upx 6upx 8upx rgba(0, 102, 204, 0.2); +} + +.shadow[class*="-purple"] { + box-shadow: 6upx 6upx 8upx rgba(88, 48, 156, 0.2); +} + +.shadow[class*="-mauve"] { + box-shadow: 6upx 6upx 8upx rgba(133, 33, 150, 0.2); +} + +.shadow[class*="-pink"] { + box-shadow: 6upx 6upx 8upx rgba(199, 50, 134, 0.2); +} + +.shadow[class*="-brown"] { + box-shadow: 6upx 6upx 8upx rgba(140, 88, 53, 0.2); +} + +.shadow[class*="-grey"] { + box-shadow: 6upx 6upx 8upx rgba(114, 130, 138, 0.2); +} + +.shadow[class*="-gray"] { + box-shadow: 6upx 6upx 8upx rgba(114, 130, 138, 0.2); +} + +.shadow[class*="-black"] { + box-shadow: 6upx 6upx 8upx rgba(26, 26, 26, 0.2); +} + +.shadow[class*="-white"] { + box-shadow: 6upx 6upx 8upx rgba(26, 26, 26, 0.2); +} + +.text-shadow[class*="-red"] { + text-shadow: 6upx 6upx 8upx rgba(204, 69, 59, 0.2); +} + +.text-shadow[class*="-orange"] { + text-shadow: 6upx 6upx 8upx rgba(217, 109, 26, 0.2); +} + +.text-shadow[class*="-yellow"] { + text-shadow: 6upx 6upx 8upx rgba(224, 170, 7, 0.2); +} + +.text-shadow[class*="-olive"] { + text-shadow: 6upx 6upx 8upx rgba(124, 173, 55, 0.2); +} + +.text-shadow[class*="-green"] { + text-shadow: 6upx 6upx 8upx rgba(48, 156, 63, 0.2); +} + +.text-shadow[class*="-cyan"] { + text-shadow: 6upx 6upx 8upx rgba(28, 187, 180, 0.2); +} + +.text-shadow[class*="-blue"] { + text-shadow: 6upx 6upx 8upx rgba(0, 102, 204, 0.2); +} + +.text-shadow[class*="-purple"] { + text-shadow: 6upx 6upx 8upx rgba(88, 48, 156, 0.2); +} + +.text-shadow[class*="-mauve"] { + text-shadow: 6upx 6upx 8upx rgba(133, 33, 150, 0.2); +} + +.text-shadow[class*="-pink"] { + text-shadow: 6upx 6upx 8upx rgba(199, 50, 134, 0.2); +} + +.text-shadow[class*="-brown"] { + text-shadow: 6upx 6upx 8upx rgba(140, 88, 53, 0.2); +} + +.text-shadow[class*="-grey"] { + text-shadow: 6upx 6upx 8upx rgba(114, 130, 138, 0.2); +} + +.text-shadow[class*="-gray"] { + text-shadow: 6upx 6upx 8upx rgba(114, 130, 138, 0.2); +} + +.text-shadow[class*="-black"] { + text-shadow: 6upx 6upx 8upx rgba(26, 26, 26, 0.2); +} + +.bg-img { + background-size: cover; + background-position: center; + background-repeat: no-repeat; +} + +.bg-mask { + background-color: #333333; + position: relative; +} + +.bg-mask::after { + content: ""; + border-radius: inherit; + width: 100%; + height: 100%; + display: block; + background-color: rgba(0, 0, 0, 0.4); + position: absolute; + left: 0; + right: 0; + bottom: 0; + top: 0; +} + +.bg-mask view, +.bg-mask cover-view { + z-index: 5; + position: relative; +} + +.bg-video { + position: relative; +} + +.bg-video video { + display: block; + height: 100%; + width: 100%; + -o-object-fit: cover; + object-fit: cover; + position: absolute; + top: 0; + z-index: 0; + pointer-events: none; +} + +/* ================== + 文本 + ==================== */ + +.text-xs { + font-size: 20upx; +} + +.text-sm { + font-size: 24upx; +} + +.text-df { + font-size: 28upx; +} + +.text-lg { + font-size: 32upx; +} + +.text-xl { + font-size: 36upx; +} + +.text-xxl { + font-size: 44upx; +} + +.text-sl { + font-size: 80upx; +} + +.text-xsl { + font-size: 120upx; +} + +.text-Abc { + text-transform: Capitalize; +} + +.text-ABC { + text-transform: Uppercase; +} + +.text-abc { + text-transform: Lowercase; +} + +.text-price::before { + content: "¥"; + font-size: 80%; + margin-right: 4upx; +} + +.text-cut { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} + +.text-bold { + font-weight: bold; +} + +.text-center { + text-align: center; +} + +.text-content { + line-height: 1.6; +} + +.text-left { + text-align: left; +} + +.text-right { + text-align: right; +} + +.text-red, +.line-red, +.lines-red { + color: #e54d42; +} + +.text-orange, +.line-orange, +.lines-orange { + color: #f37b1d; +} + +.text-yellow, +.line-yellow, +.lines-yellow { + color: #fbbd08; +} + +.text-olive, +.line-olive, +.lines-olive { + color: #8dc63f; +} + +.text-green, +.line-green, +.lines-green { + color: #39b54a; +} + +.text-cyan, +.line-cyan, +.lines-cyan { + color: #1cbbb4; +} + +.text-blue, +.line-blue, +.lines-blue { + color: #0081ff; +} + +.text-purple, +.line-purple, +.lines-purple { + color: #6739b6; +} + +.text-mauve, +.line-mauve, +.lines-mauve { + color: #9c26b0; +} + +.text-pink, +.line-pink, +.lines-pink { + color: #e03997; +} + +.text-brown, +.line-brown, +.lines-brown { + color: #a5673f; +} + +.text-grey, +.line-grey, +.lines-grey { + color: #8799a3; +} + +.text-gray, +.line-gray, +.lines-gray { + color: #aaaaaa; +} + +.text-black, +.line-black, +.lines-black { + color: #333333; +} + +.text-white, +.line-white, +.lines-white { + color: #ffffff; +} diff --git a/yudao-ui-admin-uniapp/static/scss/global.scss b/yudao-ui-admin-uniapp/static/scss/global.scss new file mode 100644 index 000000000..ac636bdf9 --- /dev/null +++ b/yudao-ui-admin-uniapp/static/scss/global.scss @@ -0,0 +1,90 @@ +.text-center { + text-align: center; +} + +.font-13 { + font-size: 13px; +} + +.font-12 { + font-size: 12px; +} + +.font-11 { + font-size: 11px; +} + +.text-grey1 { + color: #888; +} +.text-grey2 { + color: #aaa; +} + +.list-cell-arrow::before { + content: ' '; + height: 10px; + width: 10px; + border-width: 2px 2px 0 0; + border-color: #c0c0c0; + border-style: solid; + -webkit-transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0); + transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0); + position: absolute; + top: 50%; + margin-top: -6px; + right: 30rpx; + } + + .list-cell { + position: relative; + width: 100%; + box-sizing: border-box; + background-color: #fff; + color: #333; + padding: 26rpx 30rpx; + } + + .list-cell:first-child { + border-radius: 8rpx 8rpx 0 0; + } + + .list-cell:last-child { + border-radius: 0 0 8rpx 8rpx; + } + + .list-cell::after { + content: ''; + position: absolute; + border-bottom: 1px solid #eaeef1; + -webkit-transform: scaleY(0.5) translateZ(0); + transform: scaleY(0.5) translateZ(0); + transform-origin: 0 100%; + bottom: 0; + right: 0; + left: 0; + pointer-events: none; + } + + + .menu-list { + margin: 15px 15px; + + .menu-item-box { + width: 100%; + display: flex; + align-items: center; + + .menu-icon { + color: #007AFF; + font-size: 16px; + margin-right: 5px; + } + + .text-right { + margin-left: auto; + margin-right: 34rpx; + color: #999; + } + } + } diff --git a/yudao-ui-admin-uniapp/static/scss/index.scss b/yudao-ui-admin-uniapp/static/scss/index.scss new file mode 100644 index 000000000..745cffa25 --- /dev/null +++ b/yudao-ui-admin-uniapp/static/scss/index.scss @@ -0,0 +1,6 @@ +// global +@import "./global.scss"; +// color-ui +@import "@/static/scss/colorui.css"; +// iconfont +@import "@/static/font/iconfont.css"; \ No newline at end of file diff --git a/yudao-ui-admin-uniapp/store/getters.js b/yudao-ui-admin-uniapp/store/getters.js new file mode 100644 index 000000000..885479411 --- /dev/null +++ b/yudao-ui-admin-uniapp/store/getters.js @@ -0,0 +1,8 @@ +const getters = { + token: state => state.user.token, + avatar: state => state.user.avatar, + name: state => state.user.name, + roles: state => state.user.roles, + permissions: state => state.user.permissions +} +export default getters diff --git a/yudao-ui-admin-uniapp/store/index.js b/yudao-ui-admin-uniapp/store/index.js new file mode 100644 index 000000000..83a9db562 --- /dev/null +++ b/yudao-ui-admin-uniapp/store/index.js @@ -0,0 +1,15 @@ +import Vue from 'vue' +import Vuex from 'vuex' +import user from '@/store/modules/user' +import getters from './getters' + +Vue.use(Vuex) + +const store = new Vuex.Store({ + modules: { + user + }, + getters +}) + +export default store diff --git a/yudao-ui-admin-uniapp/store/modules/user.js b/yudao-ui-admin-uniapp/store/modules/user.js new file mode 100644 index 000000000..d49cb9a9d --- /dev/null +++ b/yudao-ui-admin-uniapp/store/modules/user.js @@ -0,0 +1,100 @@ +import config from '@/config' +import storage from '@/utils/storage' +import constant from '@/utils/constant' +import { login, logout, getInfo } from '@/api/login' +import { setToken, removeToken } from '@/utils/auth' + +const baseUrl = config.baseUrl + +const user = { + state: { + id: 0, // 用户编号 + name: storage.get(constant.name), + avatar: storage.get(constant.avatar), + roles: storage.get(constant.roles), + permissions: storage.get(constant.permissions) + }, + + mutations: { + SET_ID: (state, id) => { + state.id = id + }, + SET_NAME: (state, name) => { + state.name = name + storage.set(constant.name, name) + }, + SET_AVATAR: (state, avatar) => { + state.avatar = avatar + storage.set(constant.avatar, avatar) + }, + SET_ROLES: (state, roles) => { + state.roles = roles + storage.set(constant.roles, roles) + }, + SET_PERMISSIONS: (state, permissions) => { + state.permissions = permissions + storage.set(constant.permissions, permissions) + } + }, + + actions: { + // 登录 + Login({ commit }, userInfo) { + const username = userInfo.username.trim() + const password = userInfo.password + const code = userInfo.code + const uuid = userInfo.uuid + return new Promise((resolve, reject) => { + login(username, password, code, uuid).then(res => { + res = res.data; + // 设置 token + setToken(res) + resolve() + }).catch(error => { + reject(error) + }) + }) + }, + + // 获取用户信息 + GetInfo({ commit, state }) { + return new Promise((resolve, reject) => { + getInfo().then(res => { + res = res.data; // 读取 data 数据 + const user = res.user + const avatar = (user == null || user.avatar === "" || user.avatar == null) ? require("@/static/images/profile.jpg") : user.avatar + const nickname = (user == null || user.nickname === "" || user.nickname == null) ? "" : user.nickname + if (res.roles && res.roles.length > 0) { + commit('SET_ROLES', res.roles) + commit('SET_PERMISSIONS', res.permissions) + } else { + commit('SET_ROLES', ['ROLE_DEFAULT']) + } + commit('SET_NAME', nickname) + commit('SET_AVATAR', avatar) + resolve(res) + }).catch(error => { + reject(error) + }) + }) + }, + + // 退出系统 + LogOut({ commit, state }) { + return new Promise((resolve, reject) => { + logout(state.token).then(() => { + commit('SET_TOKEN', '') + commit('SET_ROLES', []) + commit('SET_PERMISSIONS', []) + removeToken() + storage.clean() + resolve() + }).catch(error => { + reject(error) + }) + }) + } + } +} + +export default user diff --git a/yudao-ui-admin-uniapp/uni.scss b/yudao-ui-admin-uniapp/uni.scss new file mode 100644 index 000000000..5b30ca317 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni.scss @@ -0,0 +1,64 @@ +/** + * uni-app内置的常用样式变量 + */ + +/* 行为相关颜色 */ +$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:#e5e5e5; + +/* 尺寸变量 */ + +/* 文字尺寸 */ +$uni-font-size-sm:12px; +$uni-font-size-base:14px; +$uni-font-size-lg:16px; + +/* 图片尺寸 */ +$uni-img-size-sm:20px; +$uni-img-size-base:26px; +$uni-img-size-lg:40px; + +/* Border Radius */ +$uni-border-radius-sm: 2px; +$uni-border-radius-base: 3px; +$uni-border-radius-lg: 6px; +$uni-border-radius-circle: 50%; + +/* 水平间距 */ +$uni-spacing-row-sm: 5px; +$uni-spacing-row-base: 10px; +$uni-spacing-row-lg: 15px; + +/* 垂直间距 */ +$uni-spacing-col-sm: 4px; +$uni-spacing-col-base: 8px; +$uni-spacing-col-lg: 12px; + +/* 透明度 */ +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 + +/* 文章场景相关 */ +$uni-color-title: #2C405A; // 文章标题颜色 +$uni-font-size-title:20px; +$uni-color-subtitle: #555555; // 二级标题颜色 +$uni-font-size-subtitle:26px; +$uni-color-paragraph: #3F536E; // 文章段落颜色 +$uni-font-size-paragraph:15px; \ No newline at end of file diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-badge/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-badge/changelog.md new file mode 100644 index 000000000..544ecc135 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-badge/changelog.md @@ -0,0 +1,29 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-badge/components/uni-badge/uni-badge.vue b/yudao-ui-admin-uniapp/uni_modules/uni-badge/components/uni-badge/uni-badge.vue new file mode 100644 index 000000000..fcbfe9382 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-badge/components/uni-badge/uni-badge.vue @@ -0,0 +1,268 @@ +<template> + <view class="uni-badge--x"> + <slot /> + <text v-if="text" :class="classNames" :style="[badgeWidth, positionStyle, customStyle, dotStyle]" + class="uni-badge" @click="onClick()">{{displayValue}}</text> + </view> +</template> + +<script> + /** + * Badge 数字角标 + * @description 数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景 + * @tutorial https://ext.dcloud.net.cn/plugin?id=21 + * @property {String} text 角标内容 + * @property {String} size = [normal|small] 角标内容 + * @property {String} type = [info|primary|success|warning|error] 颜色类型 + * @value info 灰色 + * @value primary 蓝色 + * @value success 绿色 + * @value warning 黄色 + * @value error 红色 + * @property {String} inverted = [true|false] 是否无需背景颜色 + * @property {Number} maxNum 展示封顶的数字值,超过 99 显示 99+ + * @property {String} absolute = [rightTop|rightBottom|leftBottom|leftTop] 开启绝对定位, 角标将定位到其包裹的标签的四角上 + * @value rightTop 右上 + * @value rightBottom 右下 + * @value leftTop 左上 + * @value leftBottom 左下 + * @property {Array[number]} offset 距定位角中心点的偏移量,只有存在 absolute 属性时有效,例如:[-10, -10] 表示向外偏移 10px,[10, 10] 表示向 absolute 指定的内偏移 10px + * @property {String} isDot = [true|false] 是否显示为一个小点 + * @event {Function} click 点击 Badge 触发事件 + * @example <uni-badge text="1"></uni-badge> + */ + + export default { + name: 'UniBadge', + emits: ['click'], + props: { + type: { + type: String, + default: 'error' + }, + inverted: { + type: Boolean, + default: false + }, + isDot: { + type: Boolean, + default: false + }, + maxNum: { + type: Number, + default: 99 + }, + absolute: { + type: String, + default: '' + }, + offset: { + type: Array, + default () { + return [0, 0] + } + }, + text: { + type: [String, Number], + default: '' + }, + size: { + type: String, + default: 'small' + }, + customStyle: { + type: Object, + default () { + return {} + } + } + }, + data() { + return {}; + }, + computed: { + width() { + return String(this.text).length * 8 + 12 + }, + classNames() { + const { + inverted, + type, + size, + absolute + } = this + return [ + inverted ? 'uni-badge--' + type + '-inverted' : '', + 'uni-badge--' + type, + 'uni-badge--' + size, + absolute ? 'uni-badge--absolute' : '' + ].join(' ') + }, + positionStyle() { + if (!this.absolute) return {} + let w = this.width / 2, + h = 10 + if (this.isDot) { + w = 5 + h = 5 + } + const x = `${- w + this.offset[0]}px` + const y = `${- h + this.offset[1]}px` + + const whiteList = { + rightTop: { + right: x, + top: y + }, + rightBottom: { + right: x, + bottom: y + }, + leftBottom: { + left: x, + bottom: y + }, + leftTop: { + left: x, + top: y + } + } + const match = whiteList[this.absolute] + return match ? match : whiteList['rightTop'] + }, + badgeWidth() { + return { + width: `${this.width}px` + } + }, + dotStyle() { + if (!this.isDot) return {} + return { + width: '10px', + height: '10px', + borderRadius: '10px' + } + }, + displayValue() { + const { + isDot, + text, + maxNum + } = this + return isDot ? '' : (Number(text) > maxNum ? `${maxNum}+` : text) + } + }, + methods: { + onClick() { + this.$emit('click'); + } + } + }; +</script> + +<style lang="scss" > + $uni-primary: #2979ff !default; + $uni-success: #4cd964 !default; + $uni-warning: #f0ad4e !default; + $uni-error: #dd524d !default; + $uni-info: #909399 !default; + + + $bage-size: 12px; + $bage-small: scale(0.8); + + .uni-badge--x { + /* #ifdef APP-NVUE */ + // align-self: flex-start; + /* #endif */ + /* #ifndef APP-NVUE */ + display: inline-block; + /* #endif */ + position: relative; + } + + .uni-badge--absolute { + position: absolute; + } + + .uni-badge--small { + transform: $bage-small; + transform-origin: center center; + } + + .uni-badge { + /* #ifndef APP-NVUE */ + display: flex; + overflow: hidden; + box-sizing: border-box; + /* #endif */ + justify-content: center; + flex-direction: row; + height: 20px; + line-height: 18px; + color: #fff; + border-radius: 100px; + background-color: $uni-info; + background-color: transparent; + border: 1px solid #fff; + text-align: center; + font-family: 'Helvetica Neue', Helvetica, sans-serif; + font-size: $bage-size; + /* #ifdef H5 */ + z-index: 999; + cursor: pointer; + /* #endif */ + + &--info { + color: #fff; + background-color: $uni-info; + } + + &--primary { + background-color: $uni-primary; + } + + &--success { + background-color: $uni-success; + } + + &--warning { + background-color: $uni-warning; + } + + &--error { + background-color: $uni-error; + } + + &--inverted { + padding: 0 5px 0 0; + color: $uni-info; + } + + &--info-inverted { + color: $uni-info; + background-color: transparent; + } + + &--primary-inverted { + color: $uni-primary; + background-color: transparent; + } + + &--success-inverted { + color: $uni-success; + background-color: transparent; + } + + &--warning-inverted { + color: $uni-warning; + background-color: transparent; + } + + &--error-inverted { + color: $uni-error; + background-color: transparent; + } + + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-badge/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-badge/package.json new file mode 100644 index 000000000..4e9e631ab --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-badge/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-badge", + "displayName": "uni-badge 数字角标", + "version": "1.2.0", + "description": "数字角标(徽章)组件,在元素周围展示消息提醒,一般用于列表、九宫格、按钮等地方。", + "keywords": [ + "", + "badge", + "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/yudao-ui-admin-uniapp/uni_modules/uni-badge/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-badge/readme.md new file mode 100644 index 000000000..bdf175da9 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/changelog.md new file mode 100644 index 000000000..016e6cee3 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/changelog.md @@ -0,0 +1,6 @@ +## 0.1.2(2022-06-08) +- 修复 微信小程序 separator 不显示问题 +## 0.1.1(2022-06-02) +- 新增 支持 uni.scss 修改颜色 +## 0.1.0(2022-04-21) +- 初始化 diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/components/uni-breadcrumb-item/uni-breadcrumb-item.vue b/yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/components/uni-breadcrumb-item/uni-breadcrumb-item.vue new file mode 100644 index 000000000..b9edbd622 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/components/uni-breadcrumb-item/uni-breadcrumb-item.vue @@ -0,0 +1,121 @@ +<template> + <view class="uni-breadcrumb-item"> + <view :class="{ + 'uni-breadcrumb-item--slot': true, + 'uni-breadcrumb-item--slot-link': to && currentPage !== to + }" @click="navTo"> + <slot /> + </view> + <i v-if="separatorClass" class="uni-breadcrumb-item--separator" :class="separatorClass" /> + <text v-else class="uni-breadcrumb-item--separator">{{ separator }}</text> + </view> +</template> +<script> + /** + * BreadcrumbItem 面包屑导航子组件 + * @property {String/Object} to 路由跳转页面路径/对象 + * @property {Boolean} replace 在使用 to 进行路由跳转时,启用 replace 将不会向 history 添加新记录(仅 h5 支持) + */ + export default { + data() { + return { + currentPage: "" + } + }, + options: { + virtualHost: true + }, + props: { + to: { + type: String, + default: '' + }, + replace:{ + type: Boolean, + default: false + } + }, + inject: { + uniBreadcrumb: { + from: "uniBreadcrumb", + default: null + } + }, + created(){ + const pages = getCurrentPages() + const page = pages[pages.length-1] + + if(page){ + this.currentPage = `/${page.route}` + } + }, + computed: { + separator() { + return this.uniBreadcrumb.separator + }, + separatorClass() { + return this.uniBreadcrumb.separatorClass + } + }, + methods: { + navTo() { + const { to } = this + + if (!to || this.currentPage === to){ + return + } + + if(this.replace){ + uni.redirectTo({ + url:to + }) + }else{ + uni.navigateTo({ + url:to + }) + } + } + } + } +</script> +<style lang="scss"> + $uni-primary: #2979ff !default; + $uni-base-color: #6a6a6a !default; + $uni-main-color: #3a3a3a !default; + .uni-breadcrumb-item { + display: flex; + align-items: center; + white-space: nowrap; + font-size: 14px; + + &--slot { + color: $uni-base-color; + padding: 0 10px; + + &-link { + color: $uni-main-color; + font-weight: bold; + /* #ifndef APP-NVUE */ + cursor: pointer; + /* #endif */ + + &:hover { + color: $uni-primary; + } + } + } + + &--separator { + font-size: 12px; + color: $uni-base-color; + } + + &:first-child &--slot { + padding-left: 0; + } + + &:last-child &--separator { + display: none; + } + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/components/uni-breadcrumb/uni-breadcrumb.vue b/yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/components/uni-breadcrumb/uni-breadcrumb.vue new file mode 100644 index 000000000..94493a21f --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/components/uni-breadcrumb/uni-breadcrumb.vue @@ -0,0 +1,41 @@ +<template> + <view class="uni-breadcrumb"> + <slot /> + </view> +</template> +<script> + /** + * Breadcrumb 面包屑导航父组件 + * @description 显示当前页面的路径,快速返回之前的任意页面 + * @tutorial https://ext.dcloud.net.cn/plugin?id=xxx + * @property {String} separator 分隔符,默认为斜杠'/' + * @property {String} separatorClass 图标分隔符 class + */ + export default { + options: { + virtualHost: true + }, + props: { + separator: { + type: String, + default: '/' + }, + separatorClass: { + type: String, + default: '' + } + }, + + provide() { + return { + uniBreadcrumb: this + } + } + + } +</script> +<style lang="scss"> + .uni-breadcrumb { + display: flex; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/package.json new file mode 100644 index 000000000..0a04e5032 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-breadcrumb", + "displayName": "uni-breadcrumb 面包屑", + "version": "0.1.2", + "description": "Breadcrumb 面包屑", + "keywords": [ + "uni-breadcrumb", + "breadcrumb", + "uni-ui", + "面包屑导航", + "面包屑" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "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": "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" + } + } + } + } +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/readme.md new file mode 100644 index 000000000..6976b8d7d --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-breadcrumb/readme.md @@ -0,0 +1,66 @@ + +## breadcrumb 面包屑导航 +> **组件名:uni-breadcrumb** +> 代码块: `ubreadcrumb` + +显示当前页面的路径,快速返回之前的任意页面。 + +### 安装方式 + +本组件符合[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 +<uni-breadcrumb separator="/"> + <uni-breadcrumb-item v-for="(route,index) in routes" :key="index" :to="route.to">{{route.name}}</uni-breadcrumb-item> +</uni-breadcrumb> +``` + +```js +export default { + name: "uni-stat-breadcrumb", + data() { + return { + routes: [{ + to: '/A', + name: 'A页面' + }, { + to: '/B', + name: 'B页面' + }, { + to: '/C', + name: 'C页面' + }] + }; + } + } +``` + + +## API + +### Breadcrumb Props + +|属性名 |类型 |默认值 |说明 | +|:-: |:-: |:-: |:-: | +|separator |String |斜杠'/' |分隔符 | +|separatorClass |String | |图标分隔符 class | + +### Breadcrumb Item Props + +|属性名 |类型 |默认值 |说明 | +|:-: |:-: |:-: |:-: | +|to |String | |路由跳转页面路径 | +|replace|Boolean | |在使用 to 进行路由跳转时,启用 replace 将不会向 history 添加新记录(仅 h5 支持) | + + + + +## 组件示例 + +点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/breadcrumb/breadcrumb](https://hellouniapp.dcloud.net.cn/pages/extUI/breadcrumb/breadcrumb) \ No newline at end of file diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-calendar/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-calendar/changelog.md new file mode 100644 index 000000000..6df4493eb --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-calendar/changelog.md @@ -0,0 +1,16 @@ +## 1.4.5(2022-02-25) +- 修复 条件编译 nvue 不支持的 css 样式 +## 1.4.4(2022-02-25) +- 修复 条件编译 nvue 不支持的 css 样式 +## 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/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/calendar.js b/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/calendar.js new file mode 100644 index 000000000..b8d7d6fc4 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/i18n/en.json b/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/i18n/en.json new file mode 100644 index 000000000..fcbd13cfc --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/i18n/index.js b/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/i18n/index.js new file mode 100644 index 000000000..de7509c87 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json b/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json new file mode 100644 index 000000000..1ca43de01 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json b/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json new file mode 100644 index 000000000..e0fe33b95 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue b/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue new file mode 100644 index 000000000..30bd6c849 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue @@ -0,0 +1,188 @@ +<template> + <view class="uni-calendar-item__weeks-box" :class="{ + 'uni-calendar-item--disable':weeks.disable, + 'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay, + 'uni-calendar-item--checked':(calendar.fullDate === weeks.fullDate && !weeks.isDay) , + 'uni-calendar-item--before-checked':weeks.beforeMultiple, + 'uni-calendar-item--multiple': weeks.multiple, + 'uni-calendar-item--after-checked':weeks.afterMultiple, + }" + @click="choiceDate(weeks)"> + <view class="uni-calendar-item__weeks-box-item"> + <text v-if="selected&&weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text> + <text class="uni-calendar-item__weeks-box-text" :class="{ + 'uni-calendar-item--isDay-text': weeks.isDay, + 'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay, + 'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay, + 'uni-calendar-item--before-checked':weeks.beforeMultiple, + 'uni-calendar-item--multiple': weeks.multiple, + 'uni-calendar-item--after-checked':weeks.afterMultiple, + 'uni-calendar-item--disable':weeks.disable, + }">{{weeks.date}}</text> + <text v-if="!lunar&&!weeks.extraInfo && weeks.isDay" class="uni-calendar-item__weeks-lunar-text" :class="{ + 'uni-calendar-item--isDay-text':weeks.isDay, + 'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay, + 'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay, + 'uni-calendar-item--before-checked':weeks.beforeMultiple, + 'uni-calendar-item--multiple': weeks.multiple, + 'uni-calendar-item--after-checked':weeks.afterMultiple, + }">{{todayText}}</text> + <text v-if="lunar&&!weeks.extraInfo" class="uni-calendar-item__weeks-lunar-text" :class="{ + 'uni-calendar-item--isDay-text':weeks.isDay, + 'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay, + 'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay, + 'uni-calendar-item--before-checked':weeks.beforeMultiple, + 'uni-calendar-item--multiple': weeks.multiple, + 'uni-calendar-item--after-checked':weeks.afterMultiple, + 'uni-calendar-item--disable':weeks.disable, + }">{{weeks.isDay ? todayText : (weeks.lunar.IDayCn === '初一'?weeks.lunar.IMonthCn:weeks.lunar.IDayCn)}}</text> + <text v-if="weeks.extraInfo&&weeks.extraInfo.info" class="uni-calendar-item__weeks-lunar-text" :class="{ + 'uni-calendar-item--extra':weeks.extraInfo.info, + 'uni-calendar-item--isDay-text':weeks.isDay, + 'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay, + 'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay, + 'uni-calendar-item--before-checked':weeks.beforeMultiple, + 'uni-calendar-item--multiple': weeks.multiple, + 'uni-calendar-item--after-checked':weeks.afterMultiple, + 'uni-calendar-item--disable':weeks.disable, + }">{{weeks.extraInfo.info}}</text> + </view> + </view> +</template> + +<script> + import { + initVueI18n + } from '@dcloudio/uni-i18n' + import messages from './i18n/index.js' + const { t } = initVueI18n(messages) + export default { + emits:['change'], + props: { + weeks: { + type: Object, + default () { + return {} + } + }, + calendar: { + type: Object, + default: () => { + return {} + } + }, + selected: { + type: Array, + default: () => { + return [] + } + }, + lunar: { + type: Boolean, + default: false + } + }, + computed: { + todayText() { + return t("uni-calender.today") + }, + }, + methods: { + choiceDate(weeks) { + this.$emit('change', weeks) + } + } + } +</script> + +<style lang="scss" scoped> + $uni-font-size-base:14px; + $uni-text-color:#333; + $uni-font-size-sm:12px; + $uni-color-error: #e43d33; + $uni-opacity-disabled: 0.3; + $uni-text-color-disable:#c0c0c0; + $uni-color-primary: #2979ff; + .uni-calendar-item__weeks-box { + flex: 1; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + justify-content: center; + align-items: center; + } + + .uni-calendar-item__weeks-box-text { + font-size: $uni-font-size-base; + color: $uni-text-color; + } + + .uni-calendar-item__weeks-lunar-text { + font-size: $uni-font-size-sm; + color: $uni-text-color; + } + + .uni-calendar-item__weeks-box-item { + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + justify-content: center; + align-items: center; + width: 100rpx; + height: 100rpx; + } + + .uni-calendar-item__weeks-box-circle { + position: absolute; + top: 5px; + right: 5px; + width: 8px; + height: 8px; + border-radius: 8px; + background-color: $uni-color-error; + + } + + .uni-calendar-item--disable { + background-color: rgba(249, 249, 249, $uni-opacity-disabled); + color: $uni-text-color-disable; + } + + .uni-calendar-item--isDay-text { + color: $uni-color-primary; + } + + .uni-calendar-item--isDay { + background-color: $uni-color-primary; + opacity: 0.8; + color: #fff; + } + + .uni-calendar-item--extra { + color: $uni-color-error; + opacity: 0.8; + } + + .uni-calendar-item--checked { + background-color: $uni-color-primary; + color: #fff; + opacity: 0.8; + } + + .uni-calendar-item--multiple { + background-color: $uni-color-primary; + color: #fff; + opacity: 0.8; + } + .uni-calendar-item--before-checked { + background-color: #ff5a5f; + color: #fff; + } + .uni-calendar-item--after-checked { + background-color: #ff5a5f; + color: #fff; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue b/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue new file mode 100644 index 000000000..88381db73 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue @@ -0,0 +1,562 @@ +<template> + <view class="uni-calendar"> + <view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}" @click="clean"></view> + <view v-if="insert || show" class="uni-calendar__content" :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow}"> + <view v-if="!insert" class="uni-calendar__header uni-calendar--fixed-top"> + <view class="uni-calendar__header-btn-box" @click="close"> + <text class="uni-calendar__header-text uni-calendar--fixed-width">{{cancelText}}</text> + </view> + <view class="uni-calendar__header-btn-box" @click="confirm"> + <text class="uni-calendar__header-text uni-calendar--fixed-width">{{okText}}</text> + </view> + </view> + <view class="uni-calendar__header"> + <view class="uni-calendar__header-btn-box" @click.stop="pre"> + <view class="uni-calendar__header-btn uni-calendar--left"></view> + </view> + <picker mode="date" :value="date" fields="month" @change="bindDateChange"> + <text class="uni-calendar__header-text">{{ (nowDate.year||'') +' / '+( nowDate.month||'')}}</text> + </picker> + <view class="uni-calendar__header-btn-box" @click.stop="next"> + <view class="uni-calendar__header-btn uni-calendar--right"></view> + </view> + <text class="uni-calendar__backtoday" @click="backtoday">{{todayText}}</text> + + </view> + <view class="uni-calendar__box"> + <view v-if="showMonth" class="uni-calendar__box-bg"> + <text class="uni-calendar__box-bg-text">{{nowDate.month}}</text> + </view> + <view class="uni-calendar__weeks"> + <view class="uni-calendar__weeks-day"> + <text class="uni-calendar__weeks-day-text">{{SUNText}}</text> + </view> + <view class="uni-calendar__weeks-day"> + <text class="uni-calendar__weeks-day-text">{{monText}}</text> + </view> + <view class="uni-calendar__weeks-day"> + <text class="uni-calendar__weeks-day-text">{{TUEText}}</text> + </view> + <view class="uni-calendar__weeks-day"> + <text class="uni-calendar__weeks-day-text">{{WEDText}}</text> + </view> + <view class="uni-calendar__weeks-day"> + <text class="uni-calendar__weeks-day-text">{{THUText}}</text> + </view> + <view class="uni-calendar__weeks-day"> + <text class="uni-calendar__weeks-day-text">{{FRIText}}</text> + </view> + <view class="uni-calendar__weeks-day"> + <text class="uni-calendar__weeks-day-text">{{SATText}}</text> + </view> + </view> + <view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex"> + <view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex"> + <calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected" :lunar="lunar" @change="choiceDate"></calendar-item> + </view> + </view> + </view> + </view> + </view> +</template> + +<script> + import Calendar from './util.js'; + import calendarItem from './uni-calendar-item.vue' + import { + initVueI18n + } from '@dcloudio/uni-i18n' + import messages from './i18n/index.js' + const { t } = initVueI18n(messages) + /** + * Calendar 日历 + * @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等 + * @tutorial https://ext.dcloud.net.cn/plugin?id=56 + * @property {String} date 自定义当前时间,默认为今天 + * @property {Boolean} lunar 显示农历 + * @property {String} startDate 日期选择范围-开始日期 + * @property {String} endDate 日期选择范围-结束日期 + * @property {Boolean} range 范围选择 + * @property {Boolean} insert = [true|false] 插入模式,默认为false + * @value true 弹窗模式 + * @value false 插入模式 + * @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容 + * @property {Array} selected 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}] + * @property {Boolean} showMonth 是否选择月份为背景 + * @event {Function} change 日期改变,`insert :ture` 时生效 + * @event {Function} confirm 确认选择`insert :false` 时生效 + * @event {Function} monthSwitch 切换月份时触发 + * @example <uni-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" /> + */ + export default { + components: { + calendarItem + }, + emits:['close','confirm','change','monthSwitch'], + props: { + date: { + type: String, + default: '' + }, + selected: { + type: Array, + default () { + return [] + } + }, + lunar: { + type: Boolean, + default: false + }, + startDate: { + type: String, + default: '' + }, + endDate: { + type: String, + default: '' + }, + range: { + type: Boolean, + default: false + }, + insert: { + type: Boolean, + default: true + }, + showMonth: { + type: Boolean, + default: true + }, + clearDate: { + type: Boolean, + default: true + } + }, + data() { + return { + show: false, + weeks: [], + calendar: {}, + nowDate: '', + aniMaskShow: false + } + }, + computed:{ + /** + * for i18n + */ + + okText() { + return t("uni-calender.ok") + }, + cancelText() { + return t("uni-calender.cancel") + }, + todayText() { + return t("uni-calender.today") + }, + monText() { + return t("uni-calender.MON") + }, + TUEText() { + return t("uni-calender.TUE") + }, + WEDText() { + return t("uni-calender.WED") + }, + THUText() { + return t("uni-calender.THU") + }, + FRIText() { + return t("uni-calender.FRI") + }, + SATText() { + return t("uni-calender.SAT") + }, + SUNText() { + return t("uni-calender.SUN") + }, + }, + watch: { + date(newVal) { + // this.cale.setDate(newVal) + this.init(newVal) + }, + startDate(val){ + this.cale.resetSatrtDate(val) + this.cale.setDate(this.nowDate.fullDate) + this.weeks = this.cale.weeks + }, + endDate(val){ + this.cale.resetEndDate(val) + this.cale.setDate(this.nowDate.fullDate) + this.weeks = this.cale.weeks + }, + selected(newVal) { + this.cale.setSelectInfo(this.nowDate.fullDate, newVal) + this.weeks = this.cale.weeks + } + }, + created() { + // 获取日历方法实例 + this.cale = new Calendar({ + // date: new Date(), + selected: this.selected, + startDate: this.startDate, + endDate: this.endDate, + range: this.range, + }) + // 选中某一天 + // this.cale.setDate(this.date) + this.init(this.date) + // this.setDay + }, + methods: { + // 取消穿透 + clean() {}, + bindDateChange(e) { + const value = e.detail.value + '-1' + console.log(this.cale.getDate(value)); + this.init(value) + }, + /** + * 初始化日期显示 + * @param {Object} date + */ + init(date) { + this.cale.setDate(date) + this.weeks = this.cale.weeks + this.nowDate = this.calendar = this.cale.getInfo(date) + }, + /** + * 打开日历弹窗 + */ + open() { + // 弹窗模式并且清理数据 + if (this.clearDate && !this.insert) { + this.cale.cleanMultipleStatus() + // this.cale.setDate(this.date) + this.init(this.date) + } + this.show = true + this.$nextTick(() => { + setTimeout(() => { + this.aniMaskShow = true + }, 50) + }) + }, + /** + * 关闭日历弹窗 + */ + close() { + this.aniMaskShow = false + this.$nextTick(() => { + setTimeout(() => { + this.show = false + this.$emit('close') + }, 300) + }) + }, + /** + * 确认按钮 + */ + confirm() { + this.setEmit('confirm') + this.close() + }, + /** + * 变化触发 + */ + change() { + if (!this.insert) return + this.setEmit('change') + }, + /** + * 选择月份触发 + */ + monthSwitch() { + let { + year, + month + } = this.nowDate + this.$emit('monthSwitch', { + year, + month: Number(month) + }) + }, + /** + * 派发事件 + * @param {Object} name + */ + setEmit(name) { + let { + year, + month, + date, + fullDate, + lunar, + extraInfo + } = this.calendar + this.$emit(name, { + range: this.cale.multipleStatus, + year, + month, + date, + fulldate: fullDate, + lunar, + extraInfo: extraInfo || {} + }) + }, + /** + * 选择天触发 + * @param {Object} weeks + */ + choiceDate(weeks) { + if (weeks.disable) return + this.calendar = weeks + // 设置多选 + this.cale.setMultiple(this.calendar.fullDate) + this.weeks = this.cale.weeks + this.change() + }, + /** + * 回到今天 + */ + backtoday() { + console.log(this.cale.getDate(new Date()).fullDate); + let date = this.cale.getDate(new Date()).fullDate + // this.cale.setDate(date) + this.init(date) + this.change() + }, + /** + * 上个月 + */ + pre() { + const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate + this.setDate(preDate) + this.monthSwitch() + + }, + /** + * 下个月 + */ + next() { + const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate + this.setDate(nextDate) + this.monthSwitch() + }, + /** + * 设置日期 + * @param {Object} date + */ + setDate(date) { + this.cale.setDate(date) + this.weeks = this.cale.weeks + this.nowDate = this.cale.getInfo(date) + } + } + } +</script> + +<style lang="scss" scoped> + $uni-bg-color-mask: rgba($color: #000000, $alpha: 0.4); + $uni-border-color: #EDEDED; + $uni-text-color: #333; + $uni-bg-color-hover:#f1f1f1; + $uni-font-size-base:14px; + $uni-text-color-placeholder: #808080; + $uni-color-subtitle: #555555; + $uni-text-color-grey:#999; + .uni-calendar { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + } + + .uni-calendar__mask { + position: fixed; + bottom: 0; + top: 0; + left: 0; + right: 0; + background-color: $uni-bg-color-mask; + transition-property: opacity; + transition-duration: 0.3s; + opacity: 0; + /* #ifndef APP-NVUE */ + z-index: 99; + /* #endif */ + } + + .uni-calendar--mask-show { + opacity: 1 + } + + .uni-calendar--fixed { + position: fixed; + /* #ifdef APP-NVUE */ + bottom: 0; + /* #endif */ + left: 0; + right: 0; + transition-property: transform; + transition-duration: 0.3s; + transform: translateY(460px); + /* #ifndef APP-NVUE */ + bottom: calc(var(--window-bottom)); + z-index: 99; + /* #endif */ + } + + .uni-calendar--ani-show { + transform: translateY(0); + } + + .uni-calendar__content { + background-color: #fff; + } + + .uni-calendar__header { + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + justify-content: center; + align-items: center; + height: 50px; + border-bottom-color: $uni-border-color; + border-bottom-style: solid; + border-bottom-width: 1px; + } + + .uni-calendar--fixed-top { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + justify-content: space-between; + border-top-color: $uni-border-color; + border-top-style: solid; + border-top-width: 1px; + } + + .uni-calendar--fixed-width { + width: 50px; + // padding: 0 15px; + } + + .uni-calendar__backtoday { + position: absolute; + right: 0; + top: 25rpx; + padding: 0 5px; + padding-left: 10px; + height: 25px; + line-height: 25px; + font-size: 12px; + border-top-left-radius: 25px; + border-bottom-left-radius: 25px; + color: $uni-text-color; + background-color: $uni-bg-color-hover; + } + + .uni-calendar__header-text { + text-align: center; + width: 100px; + font-size: $uni-font-size-base; + color: $uni-text-color; + } + + .uni-calendar__header-btn-box { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + align-items: center; + justify-content: center; + width: 50px; + height: 50px; + } + + .uni-calendar__header-btn { + width: 10px; + height: 10px; + border-left-color: $uni-text-color-placeholder; + border-left-style: solid; + border-left-width: 2px; + border-top-color: $uni-color-subtitle; + border-top-style: solid; + border-top-width: 2px; + } + + .uni-calendar--left { + transform: rotate(-45deg); + } + + .uni-calendar--right { + transform: rotate(135deg); + } + + + .uni-calendar__weeks { + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + } + + .uni-calendar__weeks-item { + flex: 1; + } + + .uni-calendar__weeks-day { + flex: 1; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + justify-content: center; + align-items: center; + height: 45px; + border-bottom-color: #F5F5F5; + border-bottom-style: solid; + border-bottom-width: 1px; + } + + .uni-calendar__weeks-day-text { + font-size: 14px; + } + + .uni-calendar__box { + position: relative; + } + + .uni-calendar__box-bg { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + justify-content: center; + align-items: center; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + } + + .uni-calendar__box-bg-text { + font-size: 200px; + font-weight: bold; + color: $uni-text-color-grey; + opacity: 0.1; + text-align: center; + /* #ifndef APP-NVUE */ + line-height: 1; + /* #endif */ + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/util.js b/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/util.js new file mode 100644 index 000000000..2d6100bff --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-calendar/components/uni-calendar/util.js @@ -0,0 +1,350 @@ +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) { + dd.setDate(dd.getDate() + AddDayCount) + } else { + dd.setMonth(dd.getMonth() + AddDayCount) // 获取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/yudao-ui-admin-uniapp/uni_modules/uni-calendar/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-calendar/package.json new file mode 100644 index 000000000..40455c870 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-calendar/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-calendar", + "displayName": "uni-calendar 日历", + "version": "1.4.5", + "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": [], + "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/yudao-ui-admin-uniapp/uni_modules/uni-calendar/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-calendar/readme.md new file mode 100644 index 000000000..4f3ca0e84 --- /dev/null +++ b/yudao-ui-admin-uniapp/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 +<view> + <uni-calendar + :insert="true" + :lunar="true" + :start-date="'2019-3-2'" + :end-date="'2019-5-20'" + @change="change" + /> +</view> +``` + +### 通过方法打开日历 + +需要设置 `insert` 为 `false` + +```html +<view> + <uni-calendar + ref="calendar" + :insert="false" + @confirm="confirm" + /> + <button @click="open">打开日历</button> +</view> +``` + +```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) \ No newline at end of file diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-card/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-card/changelog.md new file mode 100644 index 000000000..c3cd8c45a --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-card/components/uni-card/uni-card.vue b/yudao-ui-admin-uniapp/uni_modules/uni-card/components/uni-card/uni-card.vue new file mode 100644 index 000000000..38cf594cf --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-card/components/uni-card/uni-card.vue @@ -0,0 +1,270 @@ +<template> + <view class="uni-card" :class="{ 'uni-card--full': isFull, 'uni-card--shadow': isShadow,'uni-card--border':border}" + :style="{'margin':isFull?0:margin,'padding':spacing,'box-shadow':isShadow?shadow:''}"> + <!-- 封面 --> + <slot name="cover"> + <view v-if="cover" class="uni-card__cover"> + <image class="uni-card__cover-image" mode="widthFix" @click="onClick('cover')" :src="cover"></image> + </view> + </slot> + <slot name="title"> + <view v-if="title || extra" class="uni-card__header"> + <!-- 卡片标题 --> + <view class="uni-card__header-box" @click="onClick('title')"> + <view v-if="thumbnail" class="uni-card__header-avatar"> + <image class="uni-card__header-avatar-image" :src="thumbnail" mode="aspectFit" /> + </view> + <view class="uni-card__header-content"> + <text class="uni-card__header-content-title uni-ellipsis">{{ title }}</text> + <text v-if="title&&subTitle" + class="uni-card__header-content-subtitle uni-ellipsis">{{ subTitle }}</text> + </view> + </view> + <view class="uni-card__header-extra" @click="onClick('extra')"> + <text class="uni-card__header-extra-text">{{ extra }}</text> + </view> + </view> + </slot> + <!-- 卡片内容 --> + <view class="uni-card__content" :style="{padding:padding}" @click="onClick('content')"> + <slot></slot> + </view> + <view class="uni-card__actions" @click="onClick('actions')"> + <slot name="actions"></slot> + </view> + </view> +</template> + +<script> + /** + * Card 卡片 + * @description 卡片视图组件 + * @tutorial https://ext.dcloud.net.cn/plugin?id=22 + * @property {String} title 标题文字 + * @property {String} subTitle 副标题 + * @property {Number} padding 内容内边距 + * @property {Number} margin 卡片外边距 + * @property {Number} spacing 卡片内边距 + * @property {String} extra 标题额外信息 + * @property {String} cover 封面图(本地路径需要引入) + * @property {String} thumbnail 标题左侧缩略图 + * @property {Boolean} is-full = [true | false] 卡片内容是否通栏,为 true 时将去除padding值 + * @property {Boolean} is-shadow = [true | false] 卡片内容是否开启阴影 + * @property {String} shadow 卡片阴影 + * @property {Boolean} border 卡片边框 + * @event {Function} click 点击 Card 触发事件 + */ + export default { + name: 'UniCard', + emits: ['click'], + props: { + title: { + type: String, + default: '' + }, + subTitle: { + type: String, + default: '' + }, + padding: { + type: String, + default: '10px' + }, + margin: { + type: String, + default: '15px' + }, + spacing: { + type: String, + default: '0 10px' + }, + extra: { + type: String, + default: '' + }, + cover: { + type: String, + default: '' + }, + thumbnail: { + type: String, + default: '' + }, + isFull: { + // 内容区域是否通栏 + type: Boolean, + default: false + }, + isShadow: { + // 是否开启阴影 + type: Boolean, + default: true + }, + shadow: { + type: String, + default: '0px 0px 3px 1px rgba(0, 0, 0, 0.08)' + }, + border: { + type: Boolean, + default: true + } + }, + methods: { + onClick(type) { + this.$emit('click', type) + } + } + } +</script> + +<style lang="scss"> + $uni-border-3: #EBEEF5 !default; + $uni-shadow-base:0 0px 6px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default; + $uni-main-color: #3a3a3a !default; + $uni-base-color: #6a6a6a !default; + $uni-secondary-color: #909399 !default; + $uni-spacing-sm: 8px !default; + $uni-border-color:$uni-border-3; + $uni-shadow: $uni-shadow-base; + $uni-card-title: 15px; + $uni-cart-title-color:$uni-main-color; + $uni-card-subtitle: 12px; + $uni-cart-subtitle-color:$uni-secondary-color; + $uni-card-spacing: 10px; + $uni-card-content-color: $uni-base-color; + + .uni-card { + margin: $uni-card-spacing; + padding: 0 $uni-spacing-sm; + border-radius: 4px; + overflow: hidden; + font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif; + background-color: #fff; + flex: 1; + + .uni-card__cover { + position: relative; + margin-top: $uni-card-spacing; + flex-direction: row; + overflow: hidden; + border-radius: 4px; + .uni-card__cover-image { + flex: 1; + // width: 100%; + /* #ifndef APP-PLUS */ + vertical-align: middle; + /* #endif */ + } + } + + .uni-card__header { + display: flex; + border-bottom: 1px $uni-border-color solid; + flex-direction: row; + align-items: center; + padding: $uni-card-spacing; + overflow: hidden; + + .uni-card__header-box { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex: 1; + flex-direction: row; + align-items: center; + overflow: hidden; + } + + .uni-card__header-avatar { + width: 40px; + height: 40px; + overflow: hidden; + border-radius: 5px; + margin-right: $uni-card-spacing; + .uni-card__header-avatar-image { + flex: 1; + width: 40px; + height: 40px; + } + } + + .uni-card__header-content { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + justify-content: center; + flex: 1; + // height: 40px; + overflow: hidden; + + .uni-card__header-content-title { + font-size: $uni-card-title; + color: $uni-cart-title-color; + // line-height: 22px; + } + + .uni-card__header-content-subtitle { + font-size: $uni-card-subtitle; + margin-top: 5px; + color: $uni-cart-subtitle-color; + } + } + + .uni-card__header-extra { + line-height: 12px; + + .uni-card__header-extra-text { + font-size: 12px; + color: $uni-cart-subtitle-color; + } + } + } + + .uni-card__content { + padding: $uni-card-spacing; + font-size: 14px; + color: $uni-card-content-color; + line-height: 22px; + } + + .uni-card__actions { + font-size: 12px; + } + } + + .uni-card--border { + border: 1px solid $uni-border-color; + } + + .uni-card--shadow { + position: relative; + /* #ifndef APP-NVUE */ + box-shadow: $uni-shadow; + /* #endif */ + } + + .uni-card--full { + margin: 0; + border-left-width: 0; + border-left-width: 0; + border-radius: 0; + } + + /* #ifndef APP-NVUE */ + .uni-card--full:after { + border-radius: 0; + } + + /* #endif */ + .uni-ellipsis { + /* #ifndef APP-NVUE */ + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + /* #endif */ + /* #ifdef APP-NVUE */ + lines: 1; + /* #endif */ + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-card/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-card/package.json new file mode 100644 index 000000000..f16224de2 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-card/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-card/readme.md new file mode 100644 index 000000000..7434e71d2 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-collapse/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-collapse/changelog.md new file mode 100644 index 000000000..292e4c79f --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue b/yudao-ui-admin-uniapp/uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue new file mode 100644 index 000000000..d62a6a713 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue @@ -0,0 +1,402 @@ +<template> + <view class="uni-collapse-item"> + <!-- onClick(!isOpen) --> + <view @click="onClick(!isOpen)" class="uni-collapse-item__title" + :class="{'is-open':isOpen &&titleBorder === 'auto' ,'uni-collapse-item-border':titleBorder !== 'none'}"> + <view class="uni-collapse-item__title-wrap"> + <slot name="title"> + <view class="uni-collapse-item__title-box" :class="{'is-disabled':disabled}"> + <image v-if="thumb" :src="thumb" class="uni-collapse-item__title-img" /> + <text class="uni-collapse-item__title-text">{{ title }}</text> + </view> + </slot> + </view> + <view v-if="showArrow" + :class="{ 'uni-collapse-item__title-arrow-active': isOpen, 'uni-collapse-item--animation': showAnimation === true }" + class="uni-collapse-item__title-arrow"> + <uni-icons :color="disabled?'#ddd':'#bbb'" size="14" type="bottom" /> + </view> + </view> + <view class="uni-collapse-item__wrap" :class="{'is--transition':showAnimation}" + :style="{height: (isOpen?height:0) +'px'}"> + <view :id="elId" ref="collapse--hook" class="uni-collapse-item__wrap-content" + :class="{open:isheight,'uni-collapse-item--border':border&&isOpen}"> + <slot></slot> + </view> + </view> + + </view> +</template> + +<script> + // #ifdef APP-NVUE + const dom = weex.requireModule('dom') + // #endif + /** + * CollapseItem 折叠面板子组件 + * @description 折叠面板子组件 + * @property {String} title 标题文字 + * @property {String} thumb 标题左侧缩略图 + * @property {String} name 唯一标志符 + * @property {Boolean} open = [true|false] 是否展开组件 + * @property {Boolean} titleBorder = [true|false] 是否显示标题分隔线 + * @property {Boolean} border = [true|false] 是否显示分隔线 + * @property {Boolean} disabled = [true|false] 是否展开面板 + * @property {Boolean} showAnimation = [true|false] 开启动画 + * @property {Boolean} showArrow = [true|false] 是否显示右侧箭头 + */ + export default { + name: 'uniCollapseItem', + props: { + // 列表标题 + title: { + type: String, + default: '' + }, + name: { + type: [Number, String], + default: '' + }, + // 是否禁用 + disabled: { + type: Boolean, + default: false + }, + // #ifdef APP-PLUS + // 是否显示动画,app 端默认不开启动画,卡顿严重 + showAnimation: { + type: Boolean, + default: false + }, + // #endif + // #ifndef APP-PLUS + // 是否显示动画 + showAnimation: { + type: Boolean, + default: true + }, + // #endif + // 是否展开 + open: { + type: Boolean, + default: false + }, + // 缩略图 + thumb: { + type: String, + default: '' + }, + // 标题分隔线显示类型 + titleBorder: { + type: String, + default: 'auto' + }, + border: { + type: Boolean, + default: true + }, + showArrow: { + type: Boolean, + default: true + } + }, + data() { + // TODO 随机生生元素ID,解决百度小程序获取同一个元素位置信息的bug + const elId = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}` + return { + isOpen: false, + isheight: null, + height: 0, + elId, + nameSync: 0 + } + }, + watch: { + open(val) { + this.isOpen = val + this.onClick(val, 'init') + } + }, + updated(e) { + this.$nextTick(() => { + this.init(true) + }) + }, + created() { + this.collapse = this.getCollapse() + this.oldHeight = 0 + this.onClick(this.open, 'init') + }, + // #ifndef VUE3 + // TODO vue2 + destroyed() { + if (this.__isUnmounted) return + this.uninstall() + }, + // #endif + // #ifdef VUE3 + // TODO vue3 + unmounted() { + this.__isUnmounted = true + this.uninstall() + }, + // #endif + mounted() { + if (!this.collapse) return + if (this.name !== '') { + this.nameSync = this.name + } else { + this.nameSync = this.collapse.childrens.length + '' + } + if (this.collapse.names.indexOf(this.nameSync) === -1) { + this.collapse.names.push(this.nameSync) + } else { + console.warn(`name 值 ${this.nameSync} 重复`); + } + if (this.collapse.childrens.indexOf(this) === -1) { + this.collapse.childrens.push(this) + } + this.init() + }, + methods: { + init(type) { + // #ifndef APP-NVUE + this.getCollapseHeight(type) + // #endif + // #ifdef APP-NVUE + this.getNvueHwight(type) + // #endif + }, + uninstall() { + if (this.collapse) { + this.collapse.childrens.forEach((item, index) => { + if (item === this) { + this.collapse.childrens.splice(index, 1) + } + }) + this.collapse.names.forEach((item, index) => { + if (item === this.nameSync) { + this.collapse.names.splice(index, 1) + } + }) + } + }, + onClick(isOpen, type) { + if (this.disabled) return + this.isOpen = isOpen + if (this.isOpen && this.collapse) { + this.collapse.setAccordion(this) + } + if (type !== 'init') { + this.collapse.onChange(isOpen, this) + } + }, + getCollapseHeight(type, index = 0) { + const views = uni.createSelectorQuery().in(this) + views + .select(`#${this.elId}`) + .fields({ + size: true + }, data => { + // TODO 百度中可能获取不到节点信息 ,需要循环获取 + if (index >= 10) return + if (!data) { + index++ + this.getCollapseHeight(false, index) + return + } + // #ifdef APP-NVUE + this.height = data.height + 1 + // #endif + // #ifndef APP-NVUE + this.height = data.height + // #endif + this.isheight = true + if (type) return + this.onClick(this.isOpen, 'init') + }) + .exec() + }, + getNvueHwight(type) { + const result = dom.getComponentRect(this.$refs['collapse--hook'], option => { + if (option && option.result && option.size) { + // #ifdef APP-NVUE + this.height = option.size.height + 1 + // #endif + // #ifndef APP-NVUE + this.height = option.size.height + // #endif + this.isheight = true + if (type) return + this.onClick(this.open, 'init') + } + }) + }, + /** + * 获取父元素实例 + */ + getCollapse(name = 'uniCollapse') { + 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; + } + } + } +</script> + +<style lang="scss"> + .uni-collapse-item { + /* #ifndef APP-NVUE */ + box-sizing: border-box; + + /* #endif */ + &__title { + /* #ifndef APP-NVUE */ + display: flex; + width: 100%; + box-sizing: border-box; + /* #endif */ + flex-direction: row; + align-items: center; + transition: border-bottom-color .3s; + + // transition-property: border-bottom-color; + // transition-duration: 5s; + &-wrap { + width: 100%; + flex: 1; + + } + + &-box { + padding: 0 15px; + /* #ifndef APP-NVUE */ + display: flex; + width: 100%; + box-sizing: border-box; + /* #endif */ + flex-direction: row; + justify-content: space-between; + align-items: center; + height: 48px; + line-height: 48px; + background-color: #fff; + color: #303133; + font-size: 13px; + font-weight: 500; + /* #ifdef H5 */ + cursor: pointer; + outline: none; + + /* #endif */ + &.is-disabled { + .uni-collapse-item__title-text { + color: #999; + } + } + + } + + &.uni-collapse-item-border { + border-bottom: 1px solid #ebeef5; + } + + &.is-open { + border-bottom-color: transparent; + } + + &-img { + height: 22px; + width: 22px; + margin-right: 10px; + } + + &-text { + flex: 1; + font-size: 14px; + /* #ifndef APP-NVUE */ + white-space: nowrap; + color: inherit; + /* #endif */ + /* #ifdef APP-NVUE */ + lines: 1; + /* #endif */ + overflow: hidden; + text-overflow: ellipsis; + } + + &-arrow { + /* #ifndef APP-NVUE */ + display: flex; + box-sizing: border-box; + /* #endif */ + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + margin-right: 10px; + transform: rotate(0deg); + + &-active { + transform: rotate(-180deg); + } + } + + + } + + &__wrap { + /* #ifndef APP-NVUE */ + will-change: height; + box-sizing: border-box; + /* #endif */ + background-color: #fff; + overflow: hidden; + position: relative; + height: 0; + + &.is--transition { + // transition: all 0.3s; + transition-property: height, border-bottom-width; + transition-duration: 0.3s; + /* #ifndef APP-NVUE */ + will-change: height; + /* #endif */ + } + + + + &-content { + position: absolute; + font-size: 13px; + color: #303133; + // transition: height 0.3s; + border-bottom-color: transparent; + border-bottom-style: solid; + border-bottom-width: 0; + + &.uni-collapse-item--border { + border-bottom-width: 1px; + border-bottom-color: red; + border-bottom-color: #ebeef5; + } + + &.open { + position: relative; + } + } + } + + &--animation { + transition-property: transform; + transition-duration: 0.3s; + transition-timing-function: ease; + } + + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue b/yudao-ui-admin-uniapp/uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue new file mode 100644 index 000000000..384c39a9c --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue @@ -0,0 +1,147 @@ +<template> + <view class="uni-collapse"> + <slot /> + </view> +</template> +<script> + /** + * Collapse 折叠面板 + * @description 展示可以折叠 / 展开的内容区域 + * @tutorial https://ext.dcloud.net.cn/plugin?id=23 + * @property {String|Array} value 当前激活面板改变时触发(如果是手风琴模式,参数类型为string,否则为array) + * @property {Boolean} accordion = [true|false] 是否开启手风琴效果是否开启手风琴效果 + * @event {Function} change 切换面板时触发,如果是手风琴模式,返回类型为string,否则为array + */ + export default { + name: 'uniCollapse', + emits:['change','activeItem','input','update:modelValue'], + props: { + value: { + type: [String, Array], + default: '' + }, + modelValue: { + type: [String, Array], + default: '' + }, + accordion: { + // 是否开启手风琴效果 + type: [Boolean, String], + default: false + }, + }, + data() { + return {} + }, + computed: { + // TODO 兼容 vue2 和 vue3 + dataValue() { + let value = (typeof this.value === 'string' && this.value === '') || + (Array.isArray(this.value) && this.value.length === 0) + let modelValue = (typeof this.modelValue === 'string' && this.modelValue === '') || + (Array.isArray(this.modelValue) && this.modelValue.length === 0) + if (value) { + return this.modelValue + } + if (modelValue) { + return this.value + } + + return this.value + } + }, + watch: { + dataValue(val) { + this.setOpen(val) + } + }, + created() { + this.childrens = [] + this.names = [] + }, + mounted() { + this.$nextTick(()=>{ + this.setOpen(this.dataValue) + }) + }, + methods: { + setOpen(val) { + let str = typeof val === 'string' + let arr = Array.isArray(val) + this.childrens.forEach((vm, index) => { + if (str) { + if (val === vm.nameSync) { + if (!this.accordion) { + console.warn('accordion 属性为 false ,v-model 类型应该为 array') + return + } + vm.isOpen = true + } + } + if (arr) { + val.forEach(v => { + if (v === vm.nameSync) { + if (this.accordion) { + console.warn('accordion 属性为 true ,v-model 类型应该为 string') + return + } + vm.isOpen = true + } + }) + } + }) + this.emit(val) + }, + setAccordion(self) { + if (!this.accordion) return + this.childrens.forEach((vm, index) => { + if (self !== vm) { + vm.isOpen = false + } + }) + }, + resize() { + this.childrens.forEach((vm, index) => { + // #ifndef APP-NVUE + vm.getCollapseHeight() + // #endif + // #ifdef APP-NVUE + vm.getNvueHwight() + // #endif + }) + }, + onChange(isOpen, self) { + let activeItem = [] + + if (this.accordion) { + activeItem = isOpen ? self.nameSync : '' + } else { + this.childrens.forEach((vm, index) => { + if (vm.isOpen) { + activeItem.push(vm.nameSync) + } + }) + } + this.$emit('change', activeItem) + this.emit(activeItem) + }, + emit(val){ + this.$emit('input', val) + this.$emit('update:modelValue', val) + } + } + } +</script> +<style lang="scss" > + .uni-collapse { + /* #ifndef APP-NVUE */ + width: 100%; + display: flex; + /* #endif */ + /* #ifdef APP-NVUE */ + flex: 1; + /* #endif */ + flex-direction: column; + background-color: #fff; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-collapse/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-collapse/package.json new file mode 100644 index 000000000..65349cf9f --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-collapse/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-collapse/readme.md new file mode 100644 index 000000000..bc758ebc4 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-combox/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-combox/changelog.md new file mode 100644 index 000000000..23c27485c --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-combox/components/uni-combox/uni-combox.vue b/yudao-ui-admin-uniapp/uni_modules/uni-combox/components/uni-combox/uni-combox.vue new file mode 100644 index 000000000..500b6f881 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-combox/components/uni-combox/uni-combox.vue @@ -0,0 +1,275 @@ +<template> + <view class="uni-combox" :class="border ? '' : 'uni-combox__no-border'"> + <view v-if="label" class="uni-combox__label" :style="labelStyle"> + <text>{{label}}</text> + </view> + <view class="uni-combox__input-box"> + <input class="uni-combox__input" type="text" :placeholder="placeholder" + placeholder-class="uni-combox__input-plac" v-model="inputVal" @input="onInput" @focus="onFocus" +@blur="onBlur" /> + <uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" @click="toggleSelector"> + </uni-icons> + </view> + <view class="uni-combox__selector" v-if="showSelector"> + <view class="uni-popper__arrow"></view> + <scroll-view scroll-y="true" class="uni-combox__selector-scroll"> + <view class="uni-combox__selector-empty" v-if="filterCandidatesLength === 0"> + <text>{{emptyTips}}</text> + </view> + <view class="uni-combox__selector-item" v-for="(item,index) in filterCandidates" :key="index" + @click="onSelectorClick(index)"> + <text>{{item}}</text> + </view> + </scroll-view> + </view> + </view> +</template> + +<script> + /** + * Combox 组合输入框 + * @description 组合输入框一般用于既可以输入也可以选择的场景 + * @tutorial https://ext.dcloud.net.cn/plugin?id=1261 + * @property {String} label 左侧文字 + * @property {String} labelWidth 左侧内容宽度 + * @property {String} placeholder 输入框占位符 + * @property {Array} candidates 候选项列表 + * @property {String} emptyTips 筛选结果为空时显示的文字 + * @property {String} value 组合框的值 + */ + export default { + name: 'uniCombox', + emits: ['input', 'update:modelValue'], + props: { + border: { + type: Boolean, + default: true + }, + label: { + type: String, + default: '' + }, + labelWidth: { + type: String, + default: 'auto' + }, + placeholder: { + type: String, + default: '' + }, + candidates: { + type: Array, + default () { + return [] + } + }, + emptyTips: { + type: String, + default: '无匹配项' + }, + // #ifndef VUE3 + value: { + type: [String, Number], + default: '' + }, + // #endif + // #ifdef VUE3 + modelValue: { + type: [String, Number], + default: '' + }, + // #endif + }, + data() { + return { + showSelector: false, + inputVal: '' + } + }, + computed: { + labelStyle() { + if (this.labelWidth === 'auto') { + return "" + } + return `width: ${this.labelWidth}` + }, + filterCandidates() { + return this.candidates.filter((item) => { + return item.toString().indexOf(this.inputVal) > -1 + }) + }, + filterCandidatesLength() { + return this.filterCandidates.length + } + }, + watch: { + // #ifndef VUE3 + value: { + handler(newVal) { + this.inputVal = newVal + }, + immediate: true + }, + // #endif + // #ifdef VUE3 + modelValue: { + handler(newVal) { + this.inputVal = newVal + }, + immediate: true + }, + // #endif + }, + methods: { + toggleSelector() { + this.showSelector = !this.showSelector + }, + onFocus() { + this.showSelector = true + }, + onBlur() { + setTimeout(() => { + this.showSelector = false + }, 153) + }, + onSelectorClick(index) { + this.inputVal = this.filterCandidates[index] + this.showSelector = false + this.$emit('input', this.inputVal) + this.$emit('update:modelValue', this.inputVal) + }, + onInput() { + setTimeout(() => { + this.$emit('input', this.inputVal) + this.$emit('update:modelValue', this.inputVal) + }) + } + } + } +</script> + +<style lang="scss" > + .uni-combox { + font-size: 14px; + border: 1px solid #DCDFE6; + border-radius: 4px; + padding: 6px 10px; + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + // height: 40px; + flex-direction: row; + align-items: center; + // border-bottom: solid 1px #DDDDDD; + } + + .uni-combox__label { + font-size: 16px; + line-height: 22px; + padding-right: 10px; + color: #999999; + } + + .uni-combox__input-box { + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex: 1; + flex-direction: row; + align-items: center; + } + + .uni-combox__input { + flex: 1; + font-size: 14px; + height: 22px; + line-height: 22px; + } + + .uni-combox__input-plac { + font-size: 14px; + color: #999; + } + + .uni-combox__selector { + /* #ifndef APP-NVUE */ + box-sizing: border-box; + /* #endif */ + position: absolute; + top: calc(100% + 12px); + left: 0; + width: 100%; + background-color: #FFFFFF; + border: 1px solid #EBEEF5; + border-radius: 6px; + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); + z-index: 2; + padding: 4px 0; + } + + .uni-combox__selector-scroll { + /* #ifndef APP-NVUE */ + max-height: 200px; + box-sizing: border-box; + /* #endif */ + } + + .uni-combox__selector-empty, + .uni-combox__selector-item { + /* #ifndef APP-NVUE */ + display: flex; + cursor: pointer; + /* #endif */ + line-height: 36px; + font-size: 14px; + text-align: center; + // border-bottom: solid 1px #DDDDDD; + padding: 0px 10px; + } + + .uni-combox__selector-item:hover { + background-color: #f9f9f9; + } + + .uni-combox__selector-empty:last-child, + .uni-combox__selector-item:last-child { + /* #ifndef APP-NVUE */ + border-bottom: none; + /* #endif */ + } + + // picker 弹出层通用的指示小三角 + .uni-popper__arrow, + .uni-popper__arrow::after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + border-width: 6px; + } + + .uni-popper__arrow { + filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03)); + top: -6px; + left: 10%; + margin-right: 3px; + border-top-width: 0; + border-bottom-color: #EBEEF5; + } + + .uni-popper__arrow::after { + content: " "; + top: 1px; + margin-left: -6px; + border-top-width: 0; + border-bottom-color: #fff; + } + + .uni-combox__no-border { + border: none; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-combox/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-combox/package.json new file mode 100644 index 000000000..4a05c3ff5 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-combox/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-combox/readme.md new file mode 100644 index 000000000..ffa2cc864 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-countdown/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-countdown/changelog.md new file mode 100644 index 000000000..f25beefca --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-countdown/changelog.md @@ -0,0 +1,24 @@ +## 1.2.2(2022-01-19) +- 修复 在微信小程序中样式不生效的bug +## 1.2.1(2022-01-18) +- 新增 update 方法 ,在动态更新时间后,刷新组件 +## 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-countdown](https://uniapp.dcloud.io/component/uniui/uni-countdown) +## 1.1.3(2021-10-18) +- 重构 +- 新增 font-size 支持自定义字体大小 +## 1.1.2(2021-08-24) +- 新增 支持国际化 +## 1.1.1(2021-07-30) +- 优化 vue3下小程序事件警告的问题 +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.5(2021-06-18) +- 修复 uni-countdown 重复赋值跳两秒的 bug +## 1.0.4(2021-05-12) +- 新增 组件示例地址 +## 1.0.3(2021-05-08) +- 修复 uni-countdown 不能控制倒计时的 bug +## 1.0.2(2021-02-04) +- 调整为uni_modules目录规范 diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/i18n/en.json b/yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/i18n/en.json new file mode 100644 index 000000000..06309cb0f --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/i18n/en.json @@ -0,0 +1,6 @@ +{ + "uni-countdown.day": "day", + "uni-countdown.h": "h", + "uni-countdown.m": "m", + "uni-countdown.s": "s" +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/i18n/index.js b/yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/i18n/index.js new file mode 100644 index 000000000..de7509c87 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/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/yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hans.json b/yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hans.json new file mode 100644 index 000000000..358cdd166 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hans.json @@ -0,0 +1,6 @@ +{ + "uni-countdown.day": "天", + "uni-countdown.h": "时", + "uni-countdown.m": "分", + "uni-countdown.s": "秒" +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hant.json b/yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hant.json new file mode 100644 index 000000000..e5a63deab --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hant.json @@ -0,0 +1,6 @@ +{ + "uni-countdown.day": "天", + "uni-countdown.h": "時", + "uni-countdown.m": "分", + "uni-countdown.s": "秒" +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/uni-countdown.vue b/yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/uni-countdown.vue new file mode 100644 index 000000000..1f8ef4eb9 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-countdown/components/uni-countdown/uni-countdown.vue @@ -0,0 +1,271 @@ +<template> + <view class="uni-countdown"> + <text v-if="showDay" :style="[timeStyle]" class="uni-countdown__number">{{ d }}</text> + <text v-if="showDay" :style="[splitorStyle]" class="uni-countdown__splitor">{{dayText}}</text> + <text :style="[timeStyle]" class="uni-countdown__number">{{ h }}</text> + <text :style="[splitorStyle]" class="uni-countdown__splitor">{{ showColon ? ':' : hourText }}</text> + <text :style="[timeStyle]" class="uni-countdown__number">{{ i }}</text> + <text :style="[splitorStyle]" class="uni-countdown__splitor">{{ showColon ? ':' : minuteText }}</text> + <text :style="[timeStyle]" class="uni-countdown__number">{{ s }}</text> + <text v-if="!showColon" :style="[splitorStyle]" class="uni-countdown__splitor">{{secondText}}</text> + </view> +</template> +<script> + import { + initVueI18n + } from '@dcloudio/uni-i18n' + import messages from './i18n/index.js' + const { + t + } = initVueI18n(messages) + /** + * Countdown 倒计时 + * @description 倒计时组件 + * @tutorial https://ext.dcloud.net.cn/plugin?id=25 + * @property {String} backgroundColor 背景色 + * @property {String} color 文字颜色 + * @property {Number} day 天数 + * @property {Number} hour 小时 + * @property {Number} minute 分钟 + * @property {Number} second 秒 + * @property {Number} timestamp 时间戳 + * @property {Boolean} showDay = [true|false] 是否显示天数 + * @property {Boolean} show-colon = [true|false] 是否以冒号为分隔符 + * @property {String} splitorColor 分割符号颜色 + * @event {Function} timeup 倒计时时间到触发事件 + * @example <uni-countdown :day="1" :hour="1" :minute="12" :second="40"></uni-countdown> + */ + export default { + name: 'UniCountdown', + emits: ['timeup'], + props: { + showDay: { + type: Boolean, + default: true + }, + showColon: { + type: Boolean, + default: true + }, + start: { + type: Boolean, + default: true + }, + backgroundColor: { + type: String, + default: '' + }, + color: { + type: String, + default: '#333' + }, + fontSize: { + type: Number, + default: 14 + }, + splitorColor: { + type: String, + default: '#333' + }, + day: { + type: Number, + default: 0 + }, + hour: { + type: Number, + default: 0 + }, + minute: { + type: Number, + default: 0 + }, + second: { + type: Number, + default: 0 + }, + timestamp: { + type: Number, + default: 0 + } + }, + data() { + return { + timer: null, + syncFlag: false, + d: '00', + h: '00', + i: '00', + s: '00', + leftTime: 0, + seconds: 0 + } + }, + computed: { + dayText() { + return t("uni-countdown.day") + }, + hourText(val) { + return t("uni-countdown.h") + }, + minuteText(val) { + return t("uni-countdown.m") + }, + secondText(val) { + return t("uni-countdown.s") + }, + timeStyle() { + const { + color, + backgroundColor, + fontSize + } = this + return { + color, + backgroundColor, + fontSize: `${fontSize}px`, + width: `${fontSize * 22 / 14}px`, // 按字体大小为 14px 时的比例缩放 + lineHeight: `${fontSize * 20 / 14}px`, + borderRadius: `${fontSize * 3 / 14}px`, + } + }, + splitorStyle() { + const { splitorColor, fontSize, backgroundColor } = this + return { + color: splitorColor, + fontSize: `${fontSize * 12 / 14}px`, + margin: backgroundColor ? `${fontSize * 4 / 14}px` : '' + } + } + }, + watch: { + day(val) { + this.changeFlag() + }, + hour(val) { + this.changeFlag() + }, + minute(val) { + this.changeFlag() + }, + second(val) { + this.changeFlag() + }, + start: { + immediate: true, + handler(newVal, oldVal) { + if (newVal) { + this.startData(); + } else { + if (!oldVal) return + clearInterval(this.timer) + } + } + + } + }, + created: function(e) { + this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second) + this.countDown() + }, + // #ifndef VUE3 + destroyed() { + clearInterval(this.timer) + }, + // #endif + // #ifdef VUE3 + unmounted() { + clearInterval(this.timer) + }, + // #endif + methods: { + toSeconds(timestamp, day, hours, minutes, seconds) { + if (timestamp) { + return timestamp - parseInt(new Date().getTime() / 1000, 10) + } + return day * 60 * 60 * 24 + hours * 60 * 60 + minutes * 60 + seconds + }, + timeUp() { + clearInterval(this.timer) + this.$emit('timeup') + }, + countDown() { + let seconds = this.seconds + let [day, hour, minute, second] = [0, 0, 0, 0] + if (seconds > 0) { + day = Math.floor(seconds / (60 * 60 * 24)) + hour = Math.floor(seconds / (60 * 60)) - (day * 24) + minute = Math.floor(seconds / 60) - (day * 24 * 60) - (hour * 60) + second = Math.floor(seconds) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60) + } else { + this.timeUp() + } + if (day < 10) { + day = '0' + day + } + if (hour < 10) { + hour = '0' + hour + } + if (minute < 10) { + minute = '0' + minute + } + if (second < 10) { + second = '0' + second + } + this.d = day + this.h = hour + this.i = minute + this.s = second + }, + startData() { + this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second) + if (this.seconds <= 0) { + this.seconds = this.toSeconds(0, 0, 0, 0, 0) + this.countDown() + return + } + clearInterval(this.timer) + this.countDown() + this.timer = setInterval(() => { + this.seconds-- + if (this.seconds < 0) { + this.timeUp() + return + } + this.countDown() + }, 1000) + }, + update(){ + this.startData(); + }, + changeFlag() { + if (!this.syncFlag) { + this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second) + this.startData(); + this.syncFlag = true; + } + } + } + } +</script> +<style lang="scss" scoped> + $font-size: 14px; + + .uni-countdown { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + + &__splitor { + margin: 0 2px; + font-size: $font-size; + color: #333; + } + + &__number { + border-radius: 3px; + text-align: center; + font-size: $font-size; + } + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-countdown/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-countdown/package.json new file mode 100644 index 000000000..70e99ee7c --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-countdown/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-countdown/readme.md new file mode 100644 index 000000000..4bcb1aa71 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-data-checkbox/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-data-checkbox/changelog.md new file mode 100644 index 000000000..dbc517a30 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-data-checkbox/changelog.md @@ -0,0 +1,43 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue b/yudao-ui-admin-uniapp/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue new file mode 100644 index 000000000..2e5171237 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue @@ -0,0 +1,817 @@ +<template> + <view class="uni-data-checklist" :style="{'margin-top':isTop+'px'}"> + <template v-if="!isLocal"> + <view class="uni-data-loading"> + <uni-load-more v-if="!mixinDatacomErrorMessage" status="loading" iconType="snow" :iconSize="18" :content-text="contentText"></uni-load-more> + <text v-else>{{mixinDatacomErrorMessage}}</text> + </view> + </template> + <template v-else> + <checkbox-group v-if="multiple" class="checklist-group" :class="{'is-list':mode==='list' || wrap}" @change="chagne"> + <label class="checklist-box" :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']" + :style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index"> + <checkbox class="hidden" hidden :disabled="disabled || !!item.disabled" :value="item[map.value]+''" :checked="item.selected" /> + <view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="checkbox__inner" :style="item.styleIcon"> + <view class="checkbox__inner-icon"></view> + </view> + <view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}"> + <text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text> + <view v-if="mode === 'list' && icon === 'right'" class="checkobx__list" :style="item.styleBackgroud"></view> + </view> + </label> + </checkbox-group> + <radio-group v-else class="checklist-group" :class="{'is-list':mode==='list','is-wrap':wrap}" @change="chagne"> + <!-- --> + <label class="checklist-box" :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']" + :style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index"> + <radio class="hidden" hidden :disabled="disabled || item.disabled" :value="item[map.value]+''" :checked="item.selected" /> + <view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="radio__inner" + :style="item.styleBackgroud"> + <view class="radio__inner-icon" :style="item.styleIcon"></view> + </view> + <view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}"> + <text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text> + <view v-if="mode === 'list' && icon === 'right'" :style="item.styleRightIcon" class="checkobx__list"></view> + </view> + </label> + </radio-group> + </template> + </view> +</template> + +<script> + /** + * DataChecklist 数据选择器 + * @description 通过数据渲染 checkbox 和 radio + * @tutorial https://ext.dcloud.net.cn/plugin?id=xxx + * @property {String} mode = [default| list | button | tag] 显示模式 + * @value default 默认横排模式 + * @value list 列表模式 + * @value button 按钮模式 + * @value tag 标签模式 + * @property {Boolean} multiple = [true|false] 是否多选 + * @property {Array|String|Number} value 默认值 + * @property {Array} localdata 本地数据 ,格式 [{text:'',value:''}] + * @property {Number|String} min 最小选择个数 ,multiple为true时生效 + * @property {Number|String} max 最大选择个数 ,multiple为true时生效 + * @property {Boolean} wrap 是否换行显示 + * @property {String} icon = [left|right] list 列表模式下icon显示位置 + * @property {Boolean} selectedColor 选中颜色 + * @property {Boolean} emptyText 没有数据时显示的文字 ,本地数据无效 + * @property {Boolean} selectedTextColor 选中文本颜色,如不填写则自动显示 + * @property {Object} map 字段映射, 默认 map={text:'text',value:'value'} + * @value left 左侧显示 + * @value right 右侧显示 + * @event {Function} change 选中发生变化触发 + */ + + export default { + name: 'uniDataChecklist', + mixins: [uniCloud.mixinDatacom || {}], + emits:['input','update:modelValue','change'], + props: { + mode: { + type: String, + default: 'default' + }, + + multiple: { + type: Boolean, + default: false + }, + value: { + type: [Array, String, Number], + default () { + return '' + } + }, + // TODO vue3 + modelValue: { + type: [Array, String, Number], + default() { + return ''; + } + }, + localdata: { + type: Array, + default () { + return [] + } + }, + min: { + type: [Number, String], + default: '' + }, + max: { + type: [Number, String], + default: '' + }, + wrap: { + type: Boolean, + default: false + }, + icon: { + type: String, + default: 'left' + }, + selectedColor: { + type: String, + default: '' + }, + selectedTextColor: { + type: String, + default: '' + }, + emptyText:{ + type: String, + default: '暂无数据' + }, + disabled:{ + type: Boolean, + default: false + }, + map:{ + type: Object, + default(){ + return { + text:'text', + value:'value' + } + } + } + }, + watch: { + localdata: { + handler(newVal) { + this.range = newVal + this.dataList = this.getDataList(this.getSelectedValue(newVal)) + }, + deep: true + }, + mixinDatacomResData(newVal) { + this.range = newVal + this.dataList = this.getDataList(this.getSelectedValue(newVal)) + }, + value(newVal) { + this.dataList = this.getDataList(newVal) + // fix by mehaotian is_reset 在 uni-forms 中定义 + // if(!this.is_reset){ + // this.is_reset = false + // this.formItem && this.formItem.setValue(newVal) + // } + }, + modelValue(newVal) { + this.dataList = this.getDataList(newVal); + // if(!this.is_reset){ + // this.is_reset = false + // this.formItem && this.formItem.setValue(newVal) + // } + } + }, + data() { + return { + dataList: [], + range: [], + contentText: { + contentdown: '查看更多', + contentrefresh: '加载中', + contentnomore: '没有更多' + }, + isLocal:true, + styles: { + selectedColor: '#2979ff', + selectedTextColor: '#666', + }, + isTop:0 + }; + }, + computed:{ + dataValue(){ + if(this.value === '')return this.modelValue + if(this.modelValue === '') return this.value + return this.value + } + }, + created() { + // this.form = this.getForm('uniForms') + // this.formItem = this.getForm('uniFormsItem') + // this.formItem && this.formItem.setValue(this.value) + + // if (this.formItem) { + // this.isTop = 6 + // if (this.formItem.name) { + // // 如果存在name添加默认值,否则formData 中不存在这个字段不校验 + // if(!this.is_reset){ + // this.is_reset = false + // this.formItem.setValue(this.dataValue) + // } + // this.rename = this.formItem.name + // this.form.inputChildrens.push(this) + // } + // } + + if (this.localdata && this.localdata.length !== 0) { + this.isLocal = true + this.range = this.localdata + this.dataList = this.getDataList(this.getSelectedValue(this.range)) + } else { + if (this.collection) { + this.isLocal = false + this.loadData() + } + } + }, + methods: { + loadData() { + this.mixinDatacomGet().then(res=>{ + this.mixinDatacomResData = res.result.data + if(this.mixinDatacomResData.length === 0){ + this.isLocal = false + this.mixinDatacomErrorMessage = this.emptyText + }else{ + this.isLocal = true + } + }).catch(err=>{ + this.mixinDatacomErrorMessage = err.message + }) + }, + /** + * 获取父元素实例 + */ + getForm(name = 'uniForms') { + 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; + }, + chagne(e) { + const values = e.detail.value + + let detail = { + value: [], + data: [] + } + + if (this.multiple) { + this.range.forEach(item => { + + if (values.includes(item[this.map.value] + '')) { + detail.value.push(item[this.map.value]) + detail.data.push(item) + } + }) + } else { + const range = this.range.find(item => (item[this.map.value] + '') === values) + if (range) { + detail = { + value: range[this.map.value], + data: range + } + } + } + // this.formItem && this.formItem.setValue(detail.value) + // TODO 兼容 vue2 + this.$emit('input', detail.value); + // // TOTO 兼容 vue3 + this.$emit('update:modelValue', detail.value); + this.$emit('change', { + detail + }) + if (this.multiple) { + // 如果 v-model 没有绑定 ,则走内部逻辑 + // if (this.value.length === 0) { + this.dataList = this.getDataList(detail.value, true) + // } + } else { + this.dataList = this.getDataList(detail.value) + } + }, + + /** + * 获取渲染的新数组 + * @param {Object} value 选中内容 + */ + getDataList(value) { + // 解除引用关系,破坏原引用关系,避免污染源数据 + let dataList = JSON.parse(JSON.stringify(this.range)) + let list = [] + if (this.multiple) { + if (!Array.isArray(value)) { + value = [] + } + } + dataList.forEach((item, index) => { + item.disabled = item.disable || item.disabled || false + if (this.multiple) { + if (value.length > 0) { + let have = value.find(val => val === item[this.map.value]) + item.selected = have !== undefined + } else { + item.selected = false + } + } else { + item.selected = value === item[this.map.value] + } + + list.push(item) + }) + return this.setRange(list) + }, + /** + * 处理最大最小值 + * @param {Object} list + */ + setRange(list) { + let selectList = list.filter(item => item.selected) + let min = Number(this.min) || 0 + let max = Number(this.max) || '' + list.forEach((item, index) => { + if (this.multiple) { + if (selectList.length <= min) { + let have = selectList.find(val => val[this.map.value] === item[this.map.value]) + if (have !== undefined) { + item.disabled = true + } + } + + if (selectList.length >= max && max !== '') { + let have = selectList.find(val => val[this.map.value] === item[this.map.value]) + if (have === undefined) { + item.disabled = true + } + } + } + this.setStyles(item, index) + list[index] = item + }) + return list + }, + /** + * 设置 class + * @param {Object} item + * @param {Object} index + */ + setStyles(item, index) { + // 设置自定义样式 + item.styleBackgroud = this.setStyleBackgroud(item) + item.styleIcon = this.setStyleIcon(item) + item.styleIconText = this.setStyleIconText(item) + item.styleRightIcon = this.setStyleRightIcon(item) + }, + + /** + * 获取选中值 + * @param {Object} range + */ + getSelectedValue(range) { + if (!this.multiple) return this.dataValue + let selectedArr = [] + range.forEach((item) => { + if (item.selected) { + selectedArr.push(item[this.map.value]) + } + }) + return this.dataValue.length > 0 ? this.dataValue : selectedArr + }, + + /** + * 设置背景样式 + */ + setStyleBackgroud(item) { + let styles = {} + let selectedColor = this.selectedColor?this.selectedColor:'#2979ff' + if (this.mode !== 'list') { + styles['border-color'] = item.selected?selectedColor:'#DCDFE6' + } + if (this.mode === 'tag') { + styles['background-color'] = item.selected? selectedColor:'#f5f5f5' + } + let classles = '' + for (let i in styles) { + classles += `${i}:${styles[i]};` + } + return classles + }, + setStyleIcon(item) { + let styles = {} + let classles = '' + let selectedColor = this.selectedColor?this.selectedColor:'#2979ff' + styles['background-color'] = item.selected?selectedColor:'#fff' + styles['border-color'] = item.selected?selectedColor:'#DCDFE6' + + if(!item.selected && item.disabled){ + styles['background-color'] = '#F2F6FC' + styles['border-color'] = item.selected?selectedColor:'#DCDFE6' + } + + for (let i in styles) { + classles += `${i}:${styles[i]};` + } + return classles + }, + setStyleIconText(item) { + let styles = {} + let classles = '' + let selectedColor = this.selectedColor?this.selectedColor:'#2979ff' + if (this.mode === 'tag') { + styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:'#fff'):'#666' + } else { + styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:selectedColor):'#666' + } + if(!item.selected && item.disabled){ + styles.color = '#999' + } + + for (let i in styles) { + classles += `${i}:${styles[i]};` + } + return classles + }, + setStyleRightIcon(item) { + let styles = {} + let classles = '' + if (this.mode === 'list') { + styles['border-color'] = item.selected?this.styles.selectedColor:'#DCDFE6' + } + for (let i in styles) { + classles += `${i}:${styles[i]};` + } + + return classles + } + } + } +</script> + +<style lang="scss"> + $checked-color: #2979ff; + $border-color: #DCDFE6; + $disable:0.4; + + @mixin flex { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + } + + .uni-data-loading { + @include flex; + flex-direction: row; + justify-content: center; + align-items: center; + height: 36px; + padding-left: 10px; + color: #999; + } + + .uni-data-checklist { + position: relative; + z-index: 0; + flex: 1; + // 多选样式 + .checklist-group { + @include flex; + flex-direction: row; + flex-wrap: wrap; + + &.is-list { + flex-direction: column; + } + + .checklist-box { + @include flex; + flex-direction: row; + align-items: center; + position: relative; + margin: 5px 0; + margin-right: 25px; + + .hidden { + position: absolute; + opacity: 0; + } + + // 文字样式 + .checklist-content { + @include flex; + flex: 1; + flex-direction: row; + align-items: center; + justify-content: space-between; + .checklist-text { + font-size: 14px; + color: #666; + margin-left: 5px; + line-height: 14px; + } + + .checkobx__list { + border-right-width: 1px; + border-right-color: #007aff; + border-right-style: solid; + border-bottom-width:1px; + border-bottom-color: #007aff; + border-bottom-style: solid; + height: 12px; + width: 6px; + left: -5px; + transform-origin: center; + transform: rotate(45deg); + opacity: 0; + } + } + + // 多选样式 + .checkbox__inner { + /* #ifndef APP-NVUE */ + flex-shrink: 0; + box-sizing: border-box; + /* #endif */ + position: relative; + width: 16px; + height: 16px; + border: 1px solid $border-color; + border-radius: 4px; + background-color: #fff; + z-index: 1; + .checkbox__inner-icon { + position: absolute; + /* #ifdef APP-NVUE */ + top: 2px; + /* #endif */ + /* #ifndef APP-NVUE */ + top: 1px; + /* #endif */ + left: 5px; + height: 8px; + width: 4px; + border-right-width: 1px; + border-right-color: #fff; + border-right-style: solid; + border-bottom-width:1px ; + border-bottom-color: #fff; + border-bottom-style: solid; + opacity: 0; + transform-origin: center; + transform: rotate(40deg); + } + } + + // 单选样式 + .radio__inner { + @include flex; + /* #ifndef APP-NVUE */ + flex-shrink: 0; + box-sizing: border-box; + /* #endif */ + justify-content: center; + align-items: center; + position: relative; + width: 16px; + height: 16px; + border: 1px solid $border-color; + border-radius: 16px; + background-color: #fff; + z-index: 1; + + .radio__inner-icon { + width: 8px; + height: 8px; + border-radius: 10px; + opacity: 0; + } + } + + // 默认样式 + &.is--default { + + // 禁用 + &.is-disable { + /* #ifdef H5 */ + cursor: not-allowed; + /* #endif */ + .checkbox__inner { + background-color: #F2F6FC; + border-color: $border-color; + /* #ifdef H5 */ + cursor: not-allowed; + /* #endif */ + } + + .radio__inner { + background-color: #F2F6FC; + border-color: $border-color; + } + .checklist-text { + color: #999; + } + } + + // 选中 + &.is-checked { + .checkbox__inner { + border-color: $checked-color; + background-color: $checked-color; + + .checkbox__inner-icon { + opacity: 1; + transform: rotate(45deg); + } + } + .radio__inner { + border-color: $checked-color; + .radio__inner-icon { + opacity: 1; + background-color: $checked-color; + } + } + .checklist-text { + color: $checked-color; + } + // 选中禁用 + &.is-disable { + .checkbox__inner { + opacity: $disable; + } + + .checklist-text { + opacity: $disable; + } + .radio__inner { + opacity: $disable; + } + } + } + } + + // 按钮样式 + &.is--button { + margin-right: 10px; + padding: 5px 10px; + border: 1px $border-color solid; + border-radius: 3px; + transition: border-color 0.2s; + + // 禁用 + &.is-disable { + /* #ifdef H5 */ + cursor: not-allowed; + /* #endif */ + border: 1px #eee solid; + opacity: $disable; + .checkbox__inner { + background-color: #F2F6FC; + border-color: $border-color; + /* #ifdef H5 */ + cursor: not-allowed; + /* #endif */ + } + .radio__inner { + background-color: #F2F6FC; + border-color: $border-color; + /* #ifdef H5 */ + cursor: not-allowed; + /* #endif */ + } + .checklist-text { + color: #999; + } + } + + &.is-checked { + border-color: $checked-color; + .checkbox__inner { + border-color: $checked-color; + background-color: $checked-color; + .checkbox__inner-icon { + opacity: 1; + transform: rotate(45deg); + } + } + + .radio__inner { + border-color: $checked-color; + + .radio__inner-icon { + opacity: 1; + background-color: $checked-color; + } + } + + .checklist-text { + color: $checked-color; + } + + // 选中禁用 + &.is-disable { + opacity: $disable; + } + } + } + + // 标签样式 + &.is--tag { + margin-right: 10px; + padding: 5px 10px; + border: 1px $border-color solid; + border-radius: 3px; + background-color: #f5f5f5; + + .checklist-text { + margin: 0; + color: #666; + } + + // 禁用 + &.is-disable { + /* #ifdef H5 */ + cursor: not-allowed; + /* #endif */ + opacity: $disable; + } + + &.is-checked { + background-color: $checked-color; + border-color: $checked-color; + + .checklist-text { + color: #fff; + } + } + } + // 列表样式 + &.is--list { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + padding: 10px 15px; + padding-left: 0; + margin: 0; + + &.is-list-border { + border-top: 1px #eee solid; + } + + // 禁用 + &.is-disable { + /* #ifdef H5 */ + cursor: not-allowed; + /* #endif */ + .checkbox__inner { + background-color: #F2F6FC; + border-color: $border-color; + /* #ifdef H5 */ + cursor: not-allowed; + /* #endif */ + } + .checklist-text { + color: #999; + } + } + + &.is-checked { + .checkbox__inner { + border-color: $checked-color; + background-color: $checked-color; + + .checkbox__inner-icon { + opacity: 1; + transform: rotate(45deg); + } + } + .radio__inner { + .radio__inner-icon { + opacity: 1; + } + } + .checklist-text { + color: $checked-color; + } + + .checklist-content { + .checkobx__list { + opacity: 1; + border-color: $checked-color; + } + } + + // 选中禁用 + &.is-disable { + .checkbox__inner { + opacity: $disable; + } + + .checklist-text { + opacity: $disable; + } + } + } + } + } + } + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-data-checkbox/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-data-checkbox/package.json new file mode 100644 index 000000000..51470a956 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-data-checkbox/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-data-checkbox", + "displayName": "uni-data-checkbox 数据选择器", + "version": "1.0.2", + "description": "通过数据驱动的单选框和复选框", + "keywords": [ + "uni-ui", + "checkbox", + "单选", + "多选", + "单选多选" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.1.1" + }, + "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-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/yudao-ui-admin-uniapp/uni_modules/uni-data-checkbox/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-data-checkbox/readme.md new file mode 100644 index 000000000..6eb253d42 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/changelog.md new file mode 100644 index 000000000..083e521fe --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/changelog.md @@ -0,0 +1,64 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js b/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js new file mode 100644 index 000000000..6ef26a262 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue b/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue new file mode 100644 index 000000000..455362755 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue @@ -0,0 +1,554 @@ +<template> + <view class="uni-data-tree"> + <view class="uni-data-tree-input" @click="handleInput"> + <slot :options="options" :data="inputSelected" :error="errorMessage"> + <view class="input-value" :class="{'input-value-border': border}"> + <text v-if="errorMessage" class="selected-area error-text">{{errorMessage}}</text> + <view v-else-if="loading && !isOpened" class="selected-area"> + <uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more> + </view> + <scroll-view v-else-if="inputSelected.length" class="selected-area" scroll-x="true"> + <view class="selected-list"> + <view class="selected-item" v-for="(item,index) in inputSelected" :key="index"> + <text class="text-color">{{item.text}}</text><text v-if="index<inputSelected.length-1" + class="input-split-line">{{split}}</text> + </view> + </view> + </scroll-view> + <text v-else class="selected-area placeholder">{{placeholder}}</text> + <view v-if="clearIcon && !readonly && inputSelected.length" class="icon-clear" + @click.stop="clear"> + <uni-icons type="clear" color="#c0c4cc" size="24"></uni-icons> + </view> + <view class="arrow-area" v-if="(!clearIcon || !inputSelected.length) && !readonly "> + <view class="input-arrow"></view> + </view> + </view> + </slot> + </view> + <view class="uni-data-tree-cover" v-if="isOpened" @click="handleClose"></view> + <view class="uni-data-tree-dialog" v-if="isOpened"> + <view class="uni-popper__arrow"></view> + <view class="dialog-caption"> + <view class="title-area"> + <text class="dialog-title">{{popupTitle}}</text> + </view> + <view class="dialog-close" @click="handleClose"> + <view class="dialog-close-plus" data-id="close"></view> + <view class="dialog-close-plus dialog-close-rotate" data-id="close"></view> + </view> + </view> + <data-picker-view class="picker-view" ref="pickerView" v-model="dataValue" :localdata="localdata" + :preload="preload" :collection="collection" :field="field" :orderby="orderby" :where="where" + :step-searh="stepSearh" :self-field="selfField" :parent-field="parentField" :managed-mode="true" + :map="map" :ellipsis="ellipsis" @change="onchange" @datachange="ondatachange" @nodeclick="onnodeclick"> + </data-picker-view> + </view> + </view> +</template> + +<script> + import dataPicker from "../uni-data-pickerview/uni-data-picker.js" + import DataPickerView from "../uni-data-pickerview/uni-data-pickerview.vue" + + /** + * DataPicker 级联选择 + * @description 支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。 + * @tutorial https://ext.dcloud.net.cn/plugin?id=3796 + * @property {String} popup-title 弹出窗口标题 + * @property {Array} localdata 本地数据,参考 + * @property {Boolean} border = [true|false] 是否有边框 + * @property {Boolean} readonly = [true|false] 是否仅读 + * @property {Boolean} preload = [true|false] 是否预加载数据 + * @value true 开启预加载数据,点击弹出窗口后显示已加载数据 + * @value false 关闭预加载数据,点击弹出窗口后开始加载数据 + * @property {Boolean} step-searh = [true|false] 是否分布查询 + * @value true 启用分布查询,仅查询当前选中节点 + * @value false 关闭分布查询,一次查询出所有数据 + * @property {String|DBFieldString} self-field 分布查询当前字段名称 + * @property {String|DBFieldString} parent-field 分布查询父字段名称 + * @property {String|DBCollectionString} collection 表名 + * @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割 + * @property {String} orderby 排序字段及正序倒叙设置 + * @property {String|JQLString} where 查询条件 + * @event {Function} popupshow 弹出的选择窗口打开时触发此事件 + * @event {Function} popuphide 弹出的选择窗口关闭时触发此事件 + */ + export default { + name: 'UniDataPicker', + emits: ['popupopened', 'popupclosed', 'nodeclick', 'input', 'change', 'update:modelValue'], + mixins: [dataPicker], + components: { + DataPickerView + }, + props: { + options: { + type: [Object, Array], + default () { + return {} + } + }, + popupTitle: { + type: String, + default: '请选择' + }, + placeholder: { + type: String, + default: '请选择' + }, + heightMobile: { + type: String, + default: '' + }, + readonly: { + type: Boolean, + default: false + }, + clearIcon: { + type: Boolean, + default: true + }, + border: { + type: Boolean, + default: true + }, + split: { + type: String, + default: '/' + }, + ellipsis: { + type: Boolean, + default: true + } + }, + data() { + return { + isOpened: false, + inputSelected: [] + } + }, + created() { + this.form = this.getForm('uniForms') + this.formItem = this.getForm('uniFormsItem') + if (this.formItem) { + if (this.formItem.name) { + this.rename = this.formItem.name + this.form.inputChildrens.push(this) + } + } + + this.$nextTick(() => { + this.load() + }) + }, + methods: { + clear() { + this.inputSelected.splice(0) + this._dispatchEvent([]) + }, + onPropsChange() { + this._treeData = [] + this.selectedIndex = 0 + this.load() + }, + load() { + if (this.readonly) { + this._processReadonly(this.localdata, this.dataValue) + return + } + + if (this.isLocaldata) { + this.loadData() + this.inputSelected = this.selected.slice(0) + } else if (!this.parentField && !this.selfField && this.hasValue) { + this.getNodeData(() => { + this.inputSelected = this.selected.slice(0) + }) + } else if (this.hasValue) { + this.getTreePath(() => { + this.inputSelected = this.selected.slice(0) + }) + } + }, + getForm(name = 'uniForms') { + 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; + }, + show() { + this.isOpened = true + setTimeout(() => { + this.$refs.pickerView.updateData({ + treeData: this._treeData, + selected: this.selected, + selectedIndex: this.selectedIndex + }) + }, 200) + this.$emit('popupopened') + }, + hide() { + this.isOpened = false + this.$emit('popupclosed') + }, + handleInput() { + if (this.readonly) { + return + } + this.show() + }, + handleClose(e) { + this.hide() + }, + onnodeclick(e) { + this.$emit('nodeclick', e) + }, + ondatachange(e) { + this._treeData = this.$refs.pickerView._treeData + }, + onchange(e) { + this.hide() + this.$nextTick(() => { + this.inputSelected = e; + }) + this._dispatchEvent(e) + }, + _processReadonly(dataList, value) { + var isTree = dataList.findIndex((item) => { + return item.children + }) + if (isTree > -1) { + let inputValue + if (Array.isArray(value)) { + inputValue = value[value.length - 1] + if (typeof inputValue === 'object' && inputValue.value) { + inputValue = inputValue.value + } + } else { + inputValue = value + } + this.inputSelected = this._findNodePath(inputValue, this.localdata) + return + } + + if (!this.hasValue) { + this.inputSelected = [] + return + } + + let result = [] + for (let i = 0; i < value.length; i++) { + var val = value[i] + var item = dataList.find((v) => { + return v.value == val + }) + if (item) { + result.push(item) + } + } + if (result.length) { + this.inputSelected = result + } + }, + _filterForArray(data, valueArray) { + var result = [] + for (let i = 0; i < valueArray.length; i++) { + var value = valueArray[i] + var found = data.find((item) => { + return item.value == value + }) + if (found) { + result.push(found) + } + } + return result + }, + _dispatchEvent(selected) { + let item = {} + if (selected.length) { + var value = new Array(selected.length) + for (var i = 0; i < selected.length; i++) { + value[i] = selected[i].value + } + item = selected[selected.length - 1] + } else { + item.value = '' + } + if (this.formItem) { + this.formItem.setValue(item.value) + } + + this.$emit('input', item.value) + this.$emit('update:modelValue', item.value) + this.$emit('change', { + detail: { + value: selected + } + }) + } + } + } +</script> + +<style > + .uni-data-tree { + flex: 1; + position: relative; + font-size: 14px; + } + + .error-text { + color: #DD524D; + } + + .input-value { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + align-items: center; + flex-wrap: nowrap; + font-size: 14px; + /* line-height: 35px; */ + padding: 0 10px; + padding-right: 5px; + overflow: hidden; + height: 35px; + /* #ifndef APP-NVUE */ + box-sizing: border-box; + /* #endif */ + } + + .input-value-border { + border: 1px solid #e5e5e5; + border-radius: 5px; + } + + .selected-area { + flex: 1; + overflow: hidden; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + } + + .load-more { + /* #ifndef APP-NVUE */ + margin-right: auto; + /* #endif */ + /* #ifdef APP-NVUE */ + width: 40px; + /* #endif */ + } + + .selected-list { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + flex-wrap: nowrap; + /* padding: 0 5px; */ + } + + .selected-item { + flex-direction: row; + /* padding: 0 1px; */ + /* #ifndef APP-NVUE */ + white-space: nowrap; + /* #endif */ + } + + .text-color { + color: #333; + } + + .placeholder { + color: grey; + font-size: 12px; + } + + .input-split-line { + opacity: .5; + } + + .arrow-area { + position: relative; + width: 20px; + /* #ifndef APP-NVUE */ + margin-bottom: 5px; + margin-left: auto; + display: flex; + /* #endif */ + justify-content: center; + transform: rotate(-45deg); + transform-origin: center; + } + + .input-arrow { + width: 7px; + height: 7px; + border-left: 1px solid #999; + border-bottom: 1px solid #999; + } + + .uni-data-tree-cover { + position: fixed; + left: 0; + top: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, .4); + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + z-index: 100; + } + + .uni-data-tree-dialog { + position: fixed; + left: 0; + top: 20%; + right: 0; + bottom: 0; + background-color: #FFFFFF; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + z-index: 102; + overflow: hidden; + /* #ifdef APP-NVUE */ + width: 750rpx; + /* #endif */ + } + + .dialog-caption { + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + /* border-bottom: 1px solid #f0f0f0; */ + } + + .title-area { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + align-items: center; + /* #ifndef APP-NVUE */ + margin: auto; + /* #endif */ + padding: 0 10px; + } + + .dialog-title { + /* font-weight: bold; */ + line-height: 44px; + } + + .dialog-close { + position: absolute; + top: 0; + right: 0; + bottom: 0; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + align-items: center; + padding: 0 15px; + } + + .dialog-close-plus { + width: 16px; + height: 2px; + background-color: #666; + border-radius: 2px; + transform: rotate(45deg); + } + + .dialog-close-rotate { + position: absolute; + transform: rotate(-45deg); + } + + .picker-view { + flex: 1; + overflow: hidden; + } + + .icon-clear { + display: flex; + align-items: center; + } + + /* #ifdef H5 */ + @media all and (min-width: 768px) { + .uni-data-tree-cover { + background-color: transparent; + } + + .uni-data-tree-dialog { + position: absolute; + top: 55px; + height: auto; + min-height: 400px; + max-height: 50vh; + background-color: #fff; + border: 1px solid #EBEEF5; + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); + border-radius: 4px; + overflow: unset; + } + + .dialog-caption { + display: none; + } + + .icon-clear { + /* margin-right: 5px; */ + } + } + + /* #endif */ + + /* picker 弹出层通用的指示小三角, todo:扩展至上下左右方向定位 */ + /* #ifndef APP-NVUE */ + .uni-popper__arrow, + .uni-popper__arrow::after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + border-width: 6px; + } + + .uni-popper__arrow { + filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03)); + top: -6px; + left: 10%; + margin-right: 3px; + border-top-width: 0; + border-bottom-color: #EBEEF5; + } + + .uni-popper__arrow::after { + content: " "; + top: 1px; + margin-left: -6px; + border-top-width: 0; + border-bottom-color: #fff; + } + /* #endif */ + </style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js b/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js new file mode 100644 index 000000000..c12fd54b3 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js @@ -0,0 +1,563 @@ +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: 20 + }, + 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 + }, + postField() { + let fields = [this.field]; + if (this.parentField) { + fields.push(`${this.parentField} as parent_value`); + } + return fields.join(','); + }, + 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 = [] + }, + 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 + }, + getNodeData(callback) { + if (this.loading) { + return + } + this.loading = true + this.getCommand({ + field: this.postField, + where: this._pathWhere() + }).then((res) => { + this.loading = false + this.selected = res.result.data + callback && callback() + }).catch((err) => { + this.loading = false + this.errorMessage = err + }) + }, + getTreePath(callback) { + if (this.loading) { + return + } + this.loading = true + + this.getCommand({ + field: this.postField, + getTreePath: { + startWith: `${this.selfField}=='${this.dataValue}'` + } + }).then((res) => { + this.loading = false + let treePath = [] + this._extractTreePath(res.result.data, treePath) + this.selected = treePath + callback && callback() + }).catch((err) => { + this.loading = false + this.errorMessage = err + }) + }, + loadData() { + if (this.isLocaldata) { + this._processLocalData() + return + } + + if (this.dataValue != null) { + this._loadNodeData((data) => { + this._treeData = data + this._updateBindData() + this._updateSelected() + }) + return + } + + if (this.stepSearh) { + this._loadNodeData((data) => { + this._treeData = data + this._updateBindData() + }) + } else { + this._loadAllData((data) => { + this._treeData = [] + this._extractTree(data, this._treeData, null) + this._updateBindData() + }) + } + }, + _loadAllData(callback) { + if (this.loading) { + return + } + this.loading = true + + this.getCommand({ + field: this.postField, + gettree: true, + startwith: `${this.selfField}=='${this.dataValue}'` + }).then((res) => { + this.loading = false + callback(res.result.data) + this.onDataChange() + }).catch((err) => { + this.loading = false + this.errorMessage = err + }) + }, + _loadNodeData(callback, pw) { + if (this.loading) { + return + } + this.loading = true + + this.getCommand({ + field: this.postField, + where: pw || this._postWhere(), + pageSize: 500 + }).then((res) => { + this.loading = false + callback(res.result.data) + this.onDataChange() + }).catch((err) => { + this.loading = false + this.errorMessage = err + }) + }, + _pathWhere() { + let result = [] + let where_field = this._getParentNameByField(); + if (where_field) { + result.push(`${where_field} == '${this.dataValue}'`) + } + + if (this.where) { + return `(${this.where}) && (${result.join(' || ')})` + } + + return result.join(' || ') + }, + _postWhere() { + 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(' && ') + }, + _nodeWhere() { + let result = [] + let selected = this.selected + if (selected.length) { + result.push(`${this.parentField} == '${selected[selected.length - 1].value}'`) + } + + if (this.where) { + return `(${this.where}) && (${result.join(' || ')})` + } + + return result.join(' || ') + }, + _getParentNameByField() { + const fields = this.field.split(','); + let where_field = 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') { + where_field = items[0].trim(); + break; + } + } + return where_field + }, + _isTreeView() { + return (this.parentField && this.selfField) + }, + _updateSelected() { + var dl = this.dataList + var sl = this.selected + let textField = this.map.text + let valueField = this.map.value + for (var i = 0; i < sl.length; i++) { + var value = sl[i].value + var dl2 = dl[i] + for (var j = 0; j < dl2.length; j++) { + var item2 = dl2[j] + if (item2[valueField] === value) { + sl[i].text = item2[textField] + break + } + } + } + }, + _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 + } + }, + _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++) { + var value = paths[i].value + var 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 [] + }, + _processLocalData() { + this._treeData = [] + this._extractTree(this.localdata, this._treeData) + + var 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) + } + } +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue b/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue new file mode 100644 index 000000000..065aac2b6 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue @@ -0,0 +1,333 @@ +<template> + <view class="uni-data-pickerview"> + <scroll-view class="selected-area" scroll-x="true" scroll-y="false" :show-scrollbar="false"> + <view class="selected-list"> + <template v-for="(item,index) in selected"> + <view class="selected-item" + :class="{'selected-item-active':index==selectedIndex, 'selected-item-text-overflow': ellipsis}" + v-if="item.text" @click="handleSelect(index)"> + <text class="">{{item.text}}</text> + </view> + </template> + </view> + </scroll-view> + <view class="tab-c"> + <template v-for="(child, i) in dataList" > + <scroll-view class="list" :key="i" v-if="i==selectedIndex" :scroll-y="true"> + <view class="item" :class="{'is-disabled': !!item.disable}" v-for="(item, j) in child" + @click="handleNodeClick(item, i, j)"> + <text class="item-text item-text-overflow">{{item[map.text]}}</text> + <view class="check" v-if="selected.length > i && item[map.value] == selected[i].value"></view> + </view> + </scroll-view> + </template> + + <view class="loading-cover" v-if="loading"> + <uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more> + </view> + <view class="error-message" v-if="errorMessage"> + <text class="error-text">{{errorMessage}}</text> + </view> + </view> + </view> +</template> + +<script> + import dataPicker from "./uni-data-picker.js" + + /** + * DataPickerview + * @description uni-data-pickerview + * @tutorial https://ext.dcloud.net.cn/plugin?id=3796 + * @property {Array} localdata 本地数据,参考 + * @property {Boolean} step-searh = [true|false] 是否分布查询 + * @value true 启用分布查询,仅查询当前选中节点 + * @value false 关闭分布查询,一次查询出所有数据 + * @property {String|DBFieldString} self-field 分布查询当前字段名称 + * @property {String|DBFieldString} parent-field 分布查询父字段名称 + * @property {String|DBCollectionString} collection 表名 + * @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割 + * @property {String} orderby 排序字段及正序倒叙设置 + * @property {String|JQLString} where 查询条件 + */ + export default { + name: 'UniDataPickerView', + emits: ['nodeclick', 'change', 'datachange', 'update:modelValue'], + mixins: [dataPicker], + props: { + managedMode: { + type: Boolean, + default: false + }, + ellipsis: { + type: Boolean, + default: true + } + }, + data() { + return {} + }, + created() { + if (this.managedMode) { + return + } + + this.$nextTick(() => { + this.load() + }) + }, + methods: { + onPropsChange() { + this._treeData = [] + this.selectedIndex = 0 + this.load() + }, + load() { + if (this.isLocaldata) { + this.loadData() + } else if (this.dataValue.length) { + this.getTreePath((res) => { + this.loadData() + }) + } + }, + handleSelect(index) { + this.selectedIndex = index + }, + handleNodeClick(item, i, j) { + if (item.disable) { + return + } + const node = this.dataList[i][j] + const text = node[this.map.text] + const value = node[this.map.value] + if (i < this.selected.length - 1) { + this.selected.splice(i, this.selected.length - i) + this.selected.push({ + text, + value + }) + } else if (i === this.selected.length - 1) { + this.selected.splice(i, 1, { + text, + value + }) + } + + if (node.isleaf) { + this.onSelectedChange(node, node.isleaf) + return + } + + const { + isleaf, + hasNodes + } = this._updateBindData() + + if (!this._isTreeView() && !hasNodes) { + this.onSelectedChange(node, true) + return + } + + if (this.isLocaldata && (!hasNodes || isleaf)) { + this.onSelectedChange(node, true) + return + } + + if (!isleaf && !hasNodes) { + this._loadNodeData((data) => { + if (!data.length) { + node.isleaf = true + } else { + this._treeData.push(...data) + this._updateBindData(node) + } + this.onSelectedChange(node, node.isleaf) + }, this._nodeWhere()) + return + } + + this.onSelectedChange(node, false) + }, + updateData(data) { + this._treeData = data.treeData + this.selected = data.selected + if (!this._treeData.length) { + this.loadData() + } else { + //this.selected = data.selected + this._updateBindData() + } + }, + onDataChange() { + this.$emit('datachange') + }, + onSelectedChange(node, isleaf) { + if (isleaf) { + this._dispatchEvent() + } + + if (node) { + this.$emit('nodeclick', node) + } + }, + _dispatchEvent() { + this.$emit('change', this.selected.slice(0)) + } + } + } +</script> +<style > + .uni-data-pickerview { + flex: 1; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + overflow: hidden; + height: 100%; + } + + .error-text { + color: #DD524D; + } + + .loading-cover { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + background-color: rgba(255, 255, 255, .5); + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + align-items: center; + z-index: 1001; + } + + .load-more { + /* #ifndef APP-NVUE */ + margin: auto; + /* #endif */ + } + + .error-message { + background-color: #fff; + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + padding: 15px; + opacity: .9; + z-index: 102; + } + + /* #ifdef APP-NVUE */ + .selected-area { + width: 750rpx; + } + + /* #endif */ + + .selected-list { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + flex-wrap: nowrap; + padding: 0 5px; + border-bottom: 1px solid #f8f8f8; + } + + .selected-item { + margin-left: 10px; + margin-right: 10px; + padding: 12px 0; + text-align: center; + /* #ifndef APP-NVUE */ + white-space: nowrap; + /* #endif */ + } + + .selected-item-text-overflow { + width: 168px; + /* fix nvue */ + overflow: hidden; + /* #ifndef APP-NVUE */ + width: 6em; + white-space: nowrap; + text-overflow: ellipsis; + -o-text-overflow: ellipsis; + /* #endif */ + } + + .selected-item-active { + border-bottom: 2px solid #007aff; + } + + .selected-item-text { + color: #007aff; + } + + .tab-c { + position: relative; + flex: 1; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + overflow: hidden; + } + + .list { + flex: 1; + } + + .item { + padding: 12px 15px; + /* border-bottom: 1px solid #f0f0f0; */ + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + justify-content: space-between; + } + + .is-disabled { + opacity: .5; + } + + .item-text { + /* flex: 1; */ + color: #333333; + } + + .item-text-overflow { + width: 280px; + /* fix nvue */ + overflow: hidden; + /* #ifndef APP-NVUE */ + width: 20em; + white-space: nowrap; + text-overflow: ellipsis; + -o-text-overflow: ellipsis; + /* #endif */ + } + + .check { + margin-right: 5px; + border: 2px solid #007aff; + border-left: 0; + border-top: 0; + height: 12px; + width: 6px; + transform-origin: center; + /* #ifndef APP-NVUE */ + transition: all 0.3s; + /* #endif */ + transform: rotate(45deg); + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/package.json new file mode 100644 index 000000000..990038024 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/package.json @@ -0,0 +1,93 @@ +{ + "id": "uni-data-picker", + "displayName": "uni-data-picker 数据驱动的picker选择器", + "version": "1.0.7", + "description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景", + "keywords": [ + "uni-ui", + "uniui", + "picker", + "级联", + "省市区", + "" +], + "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-load-more", + "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", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/readme.md new file mode 100644 index 000000000..6cda22406 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-data-picker/readme.md @@ -0,0 +1,22 @@ +## DataPicker 级联选择 +> **组件名:uni-data-picker** +> 代码块: `uDataPicker` +> 关联组件:`uni-data-pickerview`、`uni-load-more`。 + + +`<uni-data-picker>` 是一个选择类[datacom组件](https://uniapp.dcloud.net.cn/component/datacom)。 + +支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。 + +候选数据支持一次性加载完毕,也支持懒加载,比如示例图中,选择了“北京”后,动态加载北京的区县数据。 + +`<uni-data-picker>` 组件尤其适用于地址选择、分类选择等选择类。 + +`<uni-data-picker>` 支持本地数据、云端静态数据(json),uniCloud云数据库数据。 + +`<uni-data-picker>` 可以通过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/yudao-ui-admin-uniapp/uni_modules/uni-data-select/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-data-select/changelog.md new file mode 100644 index 000000000..d5beaa357 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-data-select/changelog.md @@ -0,0 +1,16 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue b/yudao-ui-admin-uniapp/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue new file mode 100644 index 000000000..16995bd69 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue @@ -0,0 +1,426 @@ +<template> + <view class="uni-stat__select"> + <span v-if="label" class="uni-label-text hide-on-phone">{{label + ':'}}</span> + <view class="uni-stat-box" :class="{'uni-stat__actived': current}"> + <view class="uni-select"> + <view class="uni-select__input-box" @click="toggleSelector"> + <view v-if="current" class="uni-select__input-text">{{current}}</view> + <view v-else class="uni-select__input-text uni-select__input-placeholder">{{typePlaceholder}}</view> + <uni-icons v-if="current && clear" type="clear" color="#c0c4cc" size="24" @click="clearVal" /> + <uni-icons v-else :type="showSelector? 'top' : 'bottom'" size="14" color="#999" /> + </view> + <view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" /> + <view class="uni-select__selector" v-if="showSelector"> + <view class="uni-popper__arrow"></view> + <scroll-view scroll-y="true" class="uni-select__selector-scroll"> + <view class="uni-select__selector-empty" v-if="mixinDatacomResData.length === 0"> + <text>{{emptyTips}}</text> + </view> + <view v-else class="uni-select__selector-item" v-for="(item,index) in mixinDatacomResData" + :key="index" @click="change(item)"> + <text + :class="{'uni-select__selector__disabled': item.disable}">{{formatItemName(item)}}</text> + </view> + </scroll-view> + </view> + </view> + </view> + </view> +</template> + +<script> + /** + * DataChecklist 数据选择器 + * @description 通过数据渲染的下拉框组件 + * @tutorial https://uniapp.dcloud.io/component/uniui/uni-data-select + * @property {String} value 默认值 + * @property {Array} localdata 本地数据 ,格式 [{text:'',value:''}] + * @property {Boolean} clear 是否可以清空已选项 + * @property {Boolean} emptyText 没有数据时显示的文字 ,本地数据无效 + * @property {String} label 左侧标题 + * @property {String} placeholder 输入框的提示文字 + * @event {Function} change 选中发生变化触发 + */ + + export default { + name: "uni-stat-select", + mixins: [uniCloud.mixinDatacom || {}], + data() { + return { + showSelector: false, + current: '', + mixinDatacomResData: [], + apps: [], + channels: [] + }; + }, + props: { + localdata: { + type: Array, + default () { + return [] + } + }, + value: { + type: [String, Number], + default: '' + }, + modelValue: { + type: [String, Number], + default: '' + }, + label: { + type: String, + default: '' + }, + placeholder: { + type: String, + default: '请选择' + }, + emptyTips: { + type: String, + default: '无选项' + }, + clear: { + type: Boolean, + default: true + }, + defItem: { + type: Number, + default: 0 + } + }, + created() { + this.last = `${this.collection}_last_selected_option_value` + if (this.collection && !this.localdata.length) { + this.mixinDatacomEasyGet() + } + }, + computed: { + typePlaceholder() { + const text = { + 'opendb-stat-app-versions': '版本', + 'opendb-app-channels': '渠道', + 'opendb-app-list': '应用' + } + const common = this.placeholder + const placeholder = text[this.collection] + return placeholder ? + common + placeholder : + common + } + }, + watch: { + localdata: { + immediate: true, + handler(val, old) { + if (Array.isArray(val) && old !== val) { + this.mixinDatacomResData = val + } + } + }, + // #ifndef VUE3 + value() { + this.initDefVal() + }, + // #endif + // #ifdef VUE3 + modelValue() { + this.initDefVal() + }, + // #endif + mixinDatacomResData: { + immediate: true, + handler(val) { + if (val.length) { + this.initDefVal() + } + } + } + }, + methods: { + initDefVal() { + let defValue = '' + if ((this.value || this.value === 0) && !this.isDisabled(this.value)) { + defValue = this.value + } else if ((this.modelValue || this.modelValue === 0) && !this.isDisabled(this.modelValue)) { + defValue = this.modelValue + } else { + let strogeValue + if (this.collection) { + strogeValue = uni.getStorageSync(this.last) + } + if (strogeValue || strogeValue === 0) { + defValue = strogeValue + } else { + let defItem = '' + if (this.defItem > 0 && this.defItem < this.mixinDatacomResData.length) { + defItem = this.mixinDatacomResData[this.defItem - 1].value + } + defValue = defItem + } + this.emit(defValue) + } + const def = this.mixinDatacomResData.find(item => item.value === defValue) + this.current = def ? this.formatItemName(def) : '' + }, + + /** + * @param {[String, Number]} value + * 判断用户给的 value 是否同时为禁用状态 + */ + isDisabled(value) { + let isDisabled = false; + + this.mixinDatacomResData.forEach(item => { + if (item.value === value) { + isDisabled = item.disable + } + }) + + return isDisabled; + }, + + clearVal() { + this.emit('') + if (this.collection) { + uni.removeStorageSync(this.last) + } + }, + change(item) { + if (!item.disable) { + this.showSelector = false + this.current = this.formatItemName(item) + this.emit(item.value) + } + }, + emit(val) { + this.$emit('change', val) + this.$emit('input', val) + this.$emit('update:modelValue', val) + if (this.collection) { + uni.setStorageSync(this.last, val) + } + }, + + toggleSelector() { + this.showSelector = !this.showSelector + }, + formatItemName(item) { + let { + text, + value, + channel_code + } = item + channel_code = channel_code ? `(${channel_code})` : '' + return this.collection.indexOf('app-list') > 0 ? + `${text}(${value})` : + ( + text ? + text : + `未命名${channel_code}` + ) + } + } + } +</script> + +<style lang="scss"> + $uni-base-color: #6a6a6a !default; + $uni-main-color: #333 !default; + $uni-secondary-color: #909399 !default; + $uni-border-3: #e5e5e5; + + + /* #ifndef APP-NVUE */ + @media screen and (max-width: 500px) { + .hide-on-phone { + display: none; + } + } + + /* #endif */ + .uni-stat__select { + display: flex; + align-items: center; + // padding: 15px; + cursor: pointer; + width: 100%; + flex: 1; + box-sizing: border-box; + } + + .uni-stat-box { + width: 100%; + flex: 1; + } + + .uni-stat__actived { + width: 100%; + flex: 1; + // outline: 1px solid #2979ff; + } + + .uni-label-text { + font-size: 14px; + font-weight: bold; + color: $uni-base-color; + margin: auto 0; + margin-right: 5px; + } + + .uni-select { + font-size: 14px; + border: 1px solid $uni-border-3; + box-sizing: border-box; + border-radius: 4px; + padding: 0 5px; + padding-left: 10px; + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + user-select: none; + /* #endif */ + flex-direction: row; + align-items: center; + border-bottom: solid 1px $uni-border-3; + width: 100%; + flex: 1; + height: 35px; + } + + .uni-select__label { + font-size: 16px; + // line-height: 22px; + height: 35px; + padding-right: 10px; + color: $uni-secondary-color; + } + + .uni-select__input-box { + // height: 35px; + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex: 1; + flex-direction: row; + align-items: center; + } + + .uni-select__input { + flex: 1; + font-size: 14px; + height: 22px; + line-height: 22px; + } + + .uni-select__input-plac { + font-size: 14px; + color: $uni-secondary-color; + } + + .uni-select__selector { + /* #ifndef APP-NVUE */ + box-sizing: border-box; + /* #endif */ + position: absolute; + top: calc(100% + 12px); + left: 0; + width: 100%; + background-color: #FFFFFF; + border: 1px solid #EBEEF5; + border-radius: 6px; + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); + z-index: 2; + padding: 4px 0; + } + + .uni-select__selector-scroll { + /* #ifndef APP-NVUE */ + max-height: 200px; + box-sizing: border-box; + /* #endif */ + } + + .uni-select__selector-empty, + .uni-select__selector-item { + /* #ifndef APP-NVUE */ + display: flex; + cursor: pointer; + /* #endif */ + line-height: 35px; + font-size: 14px; + text-align: center; + /* border-bottom: solid 1px $uni-border-3; */ + padding: 0px 10px; + } + + .uni-select__selector-item:hover { + background-color: #f9f9f9; + } + + .uni-select__selector-empty:last-child, + .uni-select__selector-item:last-child { + /* #ifndef APP-NVUE */ + border-bottom: none; + /* #endif */ + } + + .uni-select__selector__disabled { + opacity: 0.4; + cursor: default; + } + + /* picker 弹出层通用的指示小三角 */ + .uni-popper__arrow, + .uni-popper__arrow::after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + border-width: 6px; + } + + .uni-popper__arrow { + filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03)); + top: -6px; + left: 10%; + margin-right: 3px; + border-top-width: 0; + border-bottom-color: #EBEEF5; + } + + .uni-popper__arrow::after { + content: " "; + top: 1px; + margin-left: -6px; + border-top-width: 0; + border-bottom-color: #fff; + } + + .uni-select__input-text { + // width: 280px; + width: 100%; + color: $uni-main-color; + white-space: nowrap; + text-overflow: ellipsis; + -o-text-overflow: ellipsis; + overflow: hidden; + } + + .uni-select__input-placeholder { + color: $uni-base-color; + font-size: 12px; + } + + .uni-select--mask { + position: fixed; + top: 0; + bottom: 0; + right: 0; + left: 0; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-data-select/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-data-select/package.json new file mode 100644 index 000000000..1ebd8dd40 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-data-select/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-data-select", + "displayName": "uni-data-select 下拉框选择器", + "version": "0.1.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": { + "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-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/yudao-ui-admin-uniapp/uni_modules/uni-data-select/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-data-select/readme.md new file mode 100644 index 000000000..eb58de300 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-dateformat/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-dateformat/changelog.md new file mode 100644 index 000000000..d551d7b88 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-dateformat/components/uni-dateformat/date-format.js b/yudao-ui-admin-uniapp/uni_modules/uni-dateformat/components/uni-dateformat/date-format.js new file mode 100644 index 000000000..e00d5597e --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue b/yudao-ui-admin-uniapp/uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue new file mode 100644 index 000000000..c5ed03078 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue @@ -0,0 +1,88 @@ +<template> + <text>{{dateShow}}</text> +</template> + +<script> + import {friendlyDate} from './date-format.js' + /** + * Dateformat 日期格式化 + * @description 日期格式化组件 + * @tutorial https://ext.dcloud.net.cn/plugin?id=3279 + * @property {Object|String|Number} date 日期对象/日期字符串/时间戳 + * @property {String} locale 格式化使用的语言 + * @value zh 中文 + * @value en 英文 + * @property {Array} threshold 应用不同类型格式化的阈值 + * @property {String} format 输出日期字符串时的格式 + */ + export default { + name: 'uniDateformat', + props: { + date: { + type: [Object, String, Number], + default () { + return '-' + } + }, + locale: { + type: String, + default: 'zh', + }, + threshold: { + type: Array, + default () { + return [0, 0] + } + }, + format: { + type: String, + default: 'yyyy/MM/dd hh:mm:ss' + }, + // refreshRate使用不当可能导致性能问题,谨慎使用 + refreshRate: { + type: [Number, String], + default: 0 + } + }, + data() { + return { + refreshMark: 0 + } + }, + computed: { + dateShow() { + this.refreshMark + return friendlyDate(this.date, { + locale: this.locale, + threshold: this.threshold, + format: this.format + }) + } + }, + watch: { + refreshRate: { + handler() { + this.setAutoRefresh() + }, + immediate: true + } + }, + methods: { + refresh() { + this.refreshMark++ + }, + setAutoRefresh() { + clearInterval(this.refreshInterval) + if (this.refreshRate) { + this.refreshInterval = setInterval(() => { + this.refresh() + }, parseInt(this.refreshRate)) + } + } + } + } +</script> + +<style> + +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-dateformat/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-dateformat/package.json new file mode 100644 index 000000000..786a670b0 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-dateformat/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-dateformat/readme.md new file mode 100644 index 000000000..37ddb6ece --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/changelog.md new file mode 100644 index 000000000..5c9735a1b --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/changelog.md @@ -0,0 +1,93 @@ +## 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/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/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue new file mode 100644 index 000000000..3d2dbeac1 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue @@ -0,0 +1,185 @@ +<template> + <view class="uni-calendar-item__weeks-box" :class="{ + 'uni-calendar-item--disable':weeks.disable, + 'uni-calendar-item--before-checked-x':weeks.beforeMultiple, + 'uni-calendar-item--multiple': weeks.multiple, + 'uni-calendar-item--after-checked-x':weeks.afterMultiple, + }" @click="choiceDate(weeks)" @mouseenter="handleMousemove(weeks)"> + <view class="uni-calendar-item__weeks-box-item" :class="{ + 'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && (calendar.userChecked || !checkHover), + 'uni-calendar-item--checked-range-text': checkHover, + 'uni-calendar-item--before-checked':weeks.beforeMultiple, + 'uni-calendar-item--multiple': weeks.multiple, + 'uni-calendar-item--after-checked':weeks.afterMultiple, + 'uni-calendar-item--disable':weeks.disable, + }"> + <text v-if="selected&&weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text> + <text class="uni-calendar-item__weeks-box-text uni-calendar-item__weeks-box-text-disable uni-calendar-item--checked-text">{{weeks.date}}</text> + </view> + <view :class="{'uni-calendar-item--isDay': weeks.isDay}"></view> + </view> +</template> + +<script> + export default { + props: { + weeks: { + type: Object, + default () { + return {} + } + }, + calendar: { + type: Object, + default: () => { + return {} + } + }, + selected: { + type: Array, + default: () => { + return [] + } + }, + lunar: { + type: Boolean, + default: false + }, + checkHover: { + type: Boolean, + default: false + } + }, + methods: { + choiceDate(weeks) { + this.$emit('change', weeks) + }, + handleMousemove(weeks) { + this.$emit('handleMouse', weeks) + } + } + } +</script> + +<style lang="scss" > + .uni-calendar-item__weeks-box { + flex: 1; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + justify-content: center; + align-items: center; + margin: 1px 0; + position: relative; + } + + .uni-calendar-item__weeks-box-text { + font-size: 14px; + // font-family: Lato-Bold, Lato; + font-weight: bold; + color: #455997; + } + + .uni-calendar-item__weeks-lunar-text { + font-size: 12px; + color: #333; + } + + .uni-calendar-item__weeks-box-item { + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + justify-content: center; + align-items: center; + width: 40px; + height: 40px; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + + + .uni-calendar-item__weeks-box-circle { + position: absolute; + top: 5px; + right: 5px; + width: 8px; + height: 8px; + border-radius: 8px; + background-color: #dd524d; + + } + + .uni-calendar-item__weeks-box .uni-calendar-item--disable { + // background-color: rgba(249, 249, 249, $uni-opacity-disabled); + cursor: default; + } + + .uni-calendar-item--disable .uni-calendar-item__weeks-box-text-disable { + color: #D1D1D1; + } + + .uni-calendar-item--isDay { + position: absolute; + top: 10px; + right: 17%; + background-color: #dd524d; + width:6px; + height: 6px; + border-radius: 50%; + } + + .uni-calendar-item--extra { + color: #dd524d; + opacity: 0.8; + } + + .uni-calendar-item__weeks-box .uni-calendar-item--checked { + background-color: #007aff; + border-radius: 50%; + box-sizing: border-box; + border: 3px solid #fff; + } + + .uni-calendar-item--checked .uni-calendar-item--checked-text { + color: #fff; + } + + .uni-calendar-item--multiple .uni-calendar-item--checked-range-text { + color: #333; + } + + .uni-calendar-item--multiple { + background-color: #F6F7FC; + // color: #fff; + } + + .uni-calendar-item--multiple .uni-calendar-item--before-checked, + .uni-calendar-item--multiple .uni-calendar-item--after-checked { + background-color: #409eff; + border-radius: 50%; + box-sizing: border-box; + border: 3px solid #F6F7FC; + } + + .uni-calendar-item--before-checked .uni-calendar-item--checked-text, + .uni-calendar-item--after-checked .uni-calendar-item--checked-text { + color: #fff; + } + + .uni-calendar-item--before-checked-x { + border-top-left-radius: 50px; + border-bottom-left-radius: 50px; + box-sizing: border-box; + background-color: #F6F7FC; + } + + .uni-calendar-item--after-checked-x { + border-top-right-radius: 50px; + border-bottom-right-radius: 50px; + background-color: #F6F7FC; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue new file mode 100644 index 000000000..8f7f18158 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue @@ -0,0 +1,907 @@ +<template> + <view class="uni-calendar" @mouseleave="leaveCale"> + <view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}" + @click="clean"></view> + <view v-if="insert || show" class="uni-calendar__content" + :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow, 'uni-calendar__content-mobile': aniMaskShow}"> + <view class="uni-calendar__header" :class="{'uni-calendar__header-mobile' :!insert}"> + <view v-if="left" class="uni-calendar__header-btn-box" @click.stop="pre"> + <view class="uni-calendar__header-btn uni-calendar--left"></view> + </view> + <picker mode="date" :value="date" fields="month" @change="bindDateChange"> + <text + class="uni-calendar__header-text">{{ (nowDate.year||'') + yearText + ( nowDate.month||'') + monthText}}</text> + </picker> + <view v-if="right" class="uni-calendar__header-btn-box" @click.stop="next"> + <view class="uni-calendar__header-btn uni-calendar--right"></view> + </view> + <view v-if="!insert" class="dialog-close" @click="clean"> + <view class="dialog-close-plus" data-id="close"></view> + <view class="dialog-close-plus dialog-close-rotate" data-id="close"></view> + </view> + + <!-- <text class="uni-calendar__backtoday" @click="backtoday">回到今天</text> --> + </view> + <view class="uni-calendar__box"> + <view v-if="showMonth" class="uni-calendar__box-bg"> + <text class="uni-calendar__box-bg-text">{{nowDate.month}}</text> + </view> + <view class="uni-calendar__weeks" style="padding-bottom: 7px;"> + <view class="uni-calendar__weeks-day"> + <text class="uni-calendar__weeks-day-text">{{SUNText}}</text> + </view> + <view class="uni-calendar__weeks-day"> + <text class="uni-calendar__weeks-day-text">{{MONText}}</text> + </view> + <view class="uni-calendar__weeks-day"> + <text class="uni-calendar__weeks-day-text">{{TUEText}}</text> + </view> + <view class="uni-calendar__weeks-day"> + <text class="uni-calendar__weeks-day-text">{{WEDText}}</text> + </view> + <view class="uni-calendar__weeks-day"> + <text class="uni-calendar__weeks-day-text">{{THUText}}</text> + </view> + <view class="uni-calendar__weeks-day"> + <text class="uni-calendar__weeks-day-text">{{FRIText}}</text> + </view> + <view class="uni-calendar__weeks-day"> + <text class="uni-calendar__weeks-day-text">{{SATText}}</text> + </view> + </view> + <view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex"> + <view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex"> + <calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" + :selected="selected" :lunar="lunar" :checkHover="range" @change="choiceDate" + @handleMouse="handleMouse"> + </calendar-item> + </view> + </view> + </view> + <view v-if="!insert && !range && typeHasTime" class="uni-date-changed uni-calendar--fixed-top" + style="padding: 0 80px;"> + <view class="uni-date-changed--time-date">{{tempSingleDate ? tempSingleDate : selectDateText}}</view> + <time-picker type="time" :start="reactStartTime" :end="reactEndTime" v-model="time" + :disabled="!tempSingleDate" :border="false" :hide-second="hideSecond" class="time-picker-style"> + </time-picker> + </view> + + <view v-if="!insert && range && typeHasTime" class="uni-date-changed uni-calendar--fixed-top"> + <view class="uni-date-changed--time-start"> + <view class="uni-date-changed--time-date">{{tempRange.before ? tempRange.before : startDateText}} + </view> + <time-picker type="time" :start="reactStartTime" v-model="timeRange.startTime" :border="false" + :hide-second="hideSecond" :disabled="!tempRange.before" class="time-picker-style"> + </time-picker> + </view> + <uni-icons type="arrowthinright" color="#999" style="line-height: 50px;"></uni-icons> + <view class="uni-date-changed--time-end"> + <view class="uni-date-changed--time-date">{{tempRange.after ? tempRange.after : endDateText}}</view> + <time-picker type="time" :end="reactEndTime" v-model="timeRange.endTime" :border="false" + :hide-second="hideSecond" :disabled="!tempRange.after" class="time-picker-style"> + </time-picker> + </view> + </view> + <view v-if="!insert" class="uni-date-changed uni-date-btn--ok"> + <!-- <view class="uni-calendar__header-btn-box"> + <text class="uni-calendar__button-text uni-calendar--fixed-width">{{okText}}</text> + </view> --> + <view class="uni-datetime-picker--btn" @click="confirm">{{confirmText}}</view> + </view> + </view> + </view> +</template> + +<script> + import Calendar from './util.js'; + import calendarItem from './calendar-item.vue' + import timePicker from './time-picker.vue' + import { + initVueI18n + } from '@dcloudio/uni-i18n' + import messages from './i18n/index.js' + const { + t + } = initVueI18n(messages) + /** + * Calendar 日历 + * @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等 + * @tutorial https://ext.dcloud.net.cn/plugin?id=56 + * @property {String} date 自定义当前时间,默认为今天 + * @property {Boolean} lunar 显示农历 + * @property {String} startDate 日期选择范围-开始日期 + * @property {String} endDate 日期选择范围-结束日期 + * @property {Boolean} range 范围选择 + * @property {Boolean} insert = [true|false] 插入模式,默认为false + * @value true 弹窗模式 + * @value false 插入模式 + * @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容 + * @property {Array} selected 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}] + * @property {Boolean} showMonth 是否选择月份为背景 + * @event {Function} change 日期改变,`insert :ture` 时生效 + * @event {Function} confirm 确认选择`insert :false` 时生效 + * @event {Function} monthSwitch 切换月份时触发 + * @example <uni-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" /> + */ + export default { + components: { + calendarItem, + timePicker + }, + props: { + date: { + type: String, + default: '' + }, + defTime: { + type: [String, Object], + default: '' + }, + selectableTimes: { + type: [Object], + default () { + return {} + } + }, + selected: { + type: Array, + default () { + return [] + } + }, + lunar: { + type: Boolean, + default: false + }, + startDate: { + type: String, + default: '' + }, + endDate: { + type: String, + default: '' + }, + range: { + type: Boolean, + default: false + }, + typeHasTime: { + type: Boolean, + default: false + }, + insert: { + type: Boolean, + default: true + }, + showMonth: { + type: Boolean, + default: true + }, + clearDate: { + type: Boolean, + default: true + }, + left: { + type: Boolean, + default: true + }, + right: { + type: Boolean, + default: true + }, + checkHover: { + type: Boolean, + default: true + }, + hideSecond: { + type: [Boolean], + default: false + }, + pleStatus: { + type: Object, + default () { + return { + before: '', + after: '', + data: [], + fulldate: '' + } + } + } + }, + data() { + return { + show: false, + weeks: [], + calendar: {}, + nowDate: '', + aniMaskShow: false, + firstEnter: true, + time: '', + timeRange: { + startTime: '', + endTime: '' + }, + tempSingleDate: '', + tempRange: { + before: '', + after: '' + } + } + }, + watch: { + date: { + immediate: true, + handler(newVal, oldVal) { + if (!this.range) { + this.tempSingleDate = newVal + setTimeout(() => { + this.init(newVal) + }, 100) + } + } + }, + defTime: { + immediate: true, + handler(newVal, oldVal) { + if (!this.range) { + this.time = newVal + } else { + // console.log('-----', newVal); + this.timeRange.startTime = newVal.start + this.timeRange.endTime = newVal.end + } + } + }, + startDate(val) { + this.cale.resetSatrtDate(val) + this.cale.setDate(this.nowDate.fullDate) + this.weeks = this.cale.weeks + }, + endDate(val) { + this.cale.resetEndDate(val) + this.cale.setDate(this.nowDate.fullDate) + this.weeks = this.cale.weeks + }, + selected(newVal) { + this.cale.setSelectInfo(this.nowDate.fullDate, newVal) + this.weeks = this.cale.weeks + }, + pleStatus: { + immediate: true, + handler(newVal, oldVal) { + const { + before, + after, + fulldate, + which + } = newVal + this.tempRange.before = before + this.tempRange.after = after + setTimeout(() => { + if (fulldate) { + this.cale.setHoverMultiple(fulldate) + if (before && after) { + this.cale.lastHover = true + if (this.rangeWithinMonth(after, before)) return + this.setDate(before) + } else { + this.cale.setMultiple(fulldate) + this.setDate(this.nowDate.fullDate) + this.calendar.fullDate = '' + this.cale.lastHover = false + } + } else { + this.cale.setDefaultMultiple(before, after) + if (which === 'left') { + this.setDate(before) + this.weeks = this.cale.weeks + } else { + this.setDate(after) + this.weeks = this.cale.weeks + } + this.cale.lastHover = true + } + }, 16) + } + } + }, + computed: { + reactStartTime() { + const activeDate = this.range ? this.tempRange.before : this.calendar.fullDate + const res = activeDate === this.startDate ? this.selectableTimes.start : '' + return res + }, + reactEndTime() { + const activeDate = this.range ? this.tempRange.after : this.calendar.fullDate + const res = activeDate === this.endDate ? this.selectableTimes.end : '' + return res + }, + /** + * for i18n + */ + selectDateText() { + return t("uni-datetime-picker.selectDate") + }, + startDateText() { + return this.startPlaceholder || t("uni-datetime-picker.startDate") + }, + endDateText() { + return this.endPlaceholder || t("uni-datetime-picker.endDate") + }, + okText() { + return t("uni-datetime-picker.ok") + }, + yearText() { + return t("uni-datetime-picker.year") + }, + monthText() { + return t("uni-datetime-picker.month") + }, + MONText() { + return t("uni-calender.MON") + }, + TUEText() { + return t("uni-calender.TUE") + }, + WEDText() { + return t("uni-calender.WED") + }, + THUText() { + return t("uni-calender.THU") + }, + FRIText() { + return t("uni-calender.FRI") + }, + SATText() { + return t("uni-calender.SAT") + }, + SUNText() { + return t("uni-calender.SUN") + }, + confirmText() { + return t("uni-calender.confirm") + }, + }, + created() { + // 获取日历方法实例 + this.cale = new Calendar({ + // date: new Date(), + selected: this.selected, + startDate: this.startDate, + endDate: this.endDate, + range: this.range, + // multipleStatus: this.pleStatus + }) + // 选中某一天 + // this.cale.setDate(this.date) + this.init(this.date) + // this.setDay + }, + methods: { + leaveCale() { + this.firstEnter = true + }, + handleMouse(weeks) { + if (weeks.disable) return + if (this.cale.lastHover) return + let { + before, + after + } = this.cale.multipleStatus + if (!before) return + this.calendar = weeks + // 设置范围选 + this.cale.setHoverMultiple(this.calendar.fullDate) + this.weeks = this.cale.weeks + // hover时,进入一个日历,更新另一个 + if (this.firstEnter) { + this.$emit('firstEnterCale', this.cale.multipleStatus) + this.firstEnter = false + } + }, + rangeWithinMonth(A, B) { + const [yearA, monthA] = A.split('-') + const [yearB, monthB] = B.split('-') + return yearA === yearB && monthA === monthB + }, + + // 取消穿透 + clean() { + this.close() + }, + + clearCalender() { + if (this.range) { + this.timeRange.startTime = '' + this.timeRange.endTime = '' + this.tempRange.before = '' + this.tempRange.after = '' + this.cale.multipleStatus.before = '' + this.cale.multipleStatus.after = '' + this.cale.multipleStatus.data = [] + this.cale.lastHover = false + } else { + this.time = '' + this.tempSingleDate = '' + } + this.calendar.fullDate = '' + this.setDate() + }, + + bindDateChange(e) { + const value = e.detail.value + '-1' + this.init(value) + }, + /** + * 初始化日期显示 + * @param {Object} date + */ + init(date) { + this.cale.setDate(date) + this.weeks = this.cale.weeks + this.nowDate = this.calendar = this.cale.getInfo(date) + }, + // choiceDate(weeks) { + // if (weeks.disable) return + // this.calendar = weeks + // // 设置多选 + // this.cale.setMultiple(this.calendar.fullDate, true) + // this.weeks = this.cale.weeks + // this.tempSingleDate = this.calendar.fullDate + // this.tempRange.before = this.cale.multipleStatus.before + // this.tempRange.after = this.cale.multipleStatus.after + // this.change() + // }, + /** + * 打开日历弹窗 + */ + open() { + // 弹窗模式并且清理数据 + if (this.clearDate && !this.insert) { + this.cale.cleanMultipleStatus() + // this.cale.setDate(this.date) + this.init(this.date) + } + this.show = true + this.$nextTick(() => { + setTimeout(() => { + this.aniMaskShow = true + }, 50) + }) + }, + /** + * 关闭日历弹窗 + */ + close() { + this.aniMaskShow = false + this.$nextTick(() => { + setTimeout(() => { + this.show = false + this.$emit('close') + }, 300) + }) + }, + /** + * 确认按钮 + */ + confirm() { + this.setEmit('confirm') + this.close() + }, + /** + * 变化触发 + */ + change() { + if (!this.insert) return + this.setEmit('change') + }, + /** + * 选择月份触发 + */ + monthSwitch() { + let { + year, + month + } = this.nowDate + this.$emit('monthSwitch', { + year, + month: Number(month) + }) + }, + /** + * 派发事件 + * @param {Object} name + */ + setEmit(name) { + let { + year, + month, + date, + fullDate, + lunar, + extraInfo + } = this.calendar + this.$emit(name, { + range: this.cale.multipleStatus, + year, + month, + date, + time: this.time, + timeRange: this.timeRange, + fulldate: fullDate, + lunar, + extraInfo: extraInfo || {} + }) + }, + /** + * 选择天触发 + * @param {Object} weeks + */ + choiceDate(weeks) { + if (weeks.disable) return + this.calendar = weeks + this.calendar.userChecked = true + // 设置多选 + this.cale.setMultiple(this.calendar.fullDate, true) + this.weeks = this.cale.weeks + this.tempSingleDate = this.calendar.fullDate + this.tempRange.before = this.cale.multipleStatus.before + this.tempRange.after = this.cale.multipleStatus.after + this.change() + }, + /** + * 回到今天 + */ + backtoday() { + let date = this.cale.getDate(new Date()).fullDate + // this.cale.setDate(date) + this.init(date) + this.change() + }, + /** + * 比较时间大小 + */ + dateCompare(startDate, endDate) { + // 计算截止时间 + startDate = new Date(startDate.replace('-', '/').replace('-', '/')) + // 计算详细项的截止时间 + endDate = new Date(endDate.replace('-', '/').replace('-', '/')) + if (startDate <= endDate) { + return true + } else { + return false + } + }, + /** + * 上个月 + */ + pre() { + const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate + this.setDate(preDate) + this.monthSwitch() + + }, + /** + * 下个月 + */ + next() { + const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate + this.setDate(nextDate) + this.monthSwitch() + }, + /** + * 设置日期 + * @param {Object} date + */ + setDate(date) { + this.cale.setDate(date) + this.weeks = this.cale.weeks + this.nowDate = this.cale.getInfo(date) + } + } + } +</script> + +<style lang="scss" > + .uni-calendar { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + } + + .uni-calendar__mask { + position: fixed; + bottom: 0; + top: 0; + left: 0; + right: 0; + background-color: rgba(0, 0, 0, 0.4); + transition-property: opacity; + transition-duration: 0.3s; + opacity: 0; + /* #ifndef APP-NVUE */ + z-index: 99; + /* #endif */ + } + + .uni-calendar--mask-show { + opacity: 1 + } + + .uni-calendar--fixed { + position: fixed; + bottom: calc(var(--window-bottom)); + left: 0; + right: 0; + transition-property: transform; + transition-duration: 0.3s; + transform: translateY(460px); + /* #ifndef APP-NVUE */ + z-index: 99; + /* #endif */ + } + + .uni-calendar--ani-show { + transform: translateY(0); + } + + .uni-calendar__content { + background-color: #fff; + } + + .uni-calendar__content-mobile { + border-top-left-radius: 10px; + border-top-right-radius: 10px; + box-shadow: 0px 0px 5px 3px rgba(0, 0, 0, 0.1); + } + + .uni-calendar__header { + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + justify-content: center; + align-items: center; + height: 50px; + } + + .uni-calendar__header-mobile { + padding: 10px; + padding-bottom: 0; + } + + .uni-calendar--fixed-top { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + justify-content: space-between; + border-top-color: rgba(0, 0, 0, 0.4); + border-top-style: solid; + border-top-width: 1px; + } + + .uni-calendar--fixed-width { + width: 50px; + } + + .uni-calendar__backtoday { + position: absolute; + right: 0; + top: 25rpx; + padding: 0 5px; + padding-left: 10px; + height: 25px; + line-height: 25px; + font-size: 12px; + border-top-left-radius: 25px; + border-bottom-left-radius: 25px; + color: #fff; + background-color: #f1f1f1; + } + + .uni-calendar__header-text { + text-align: center; + width: 100px; + font-size: 15px; + color: #666; + } + + .uni-calendar__button-text { + text-align: center; + width: 100px; + font-size: 14px; + color: #007aff; + /* #ifndef APP-NVUE */ + letter-spacing: 3px; + /* #endif */ + } + + .uni-calendar__header-btn-box { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + align-items: center; + justify-content: center; + width: 50px; + height: 50px; + } + + .uni-calendar__header-btn { + width: 9px; + height: 9px; + border-left-color: #808080; + border-left-style: solid; + border-left-width: 1px; + border-top-color: #555555; + border-top-style: solid; + border-top-width: 1px; + } + + .uni-calendar--left { + transform: rotate(-45deg); + } + + .uni-calendar--right { + transform: rotate(135deg); + } + + + .uni-calendar__weeks { + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + } + + .uni-calendar__weeks-item { + flex: 1; + } + + .uni-calendar__weeks-day { + flex: 1; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + justify-content: center; + align-items: center; + height: 40px; + border-bottom-color: #F5F5F5; + border-bottom-style: solid; + border-bottom-width: 1px; + } + + .uni-calendar__weeks-day-text { + font-size: 12px; + color: #B2B2B2; + } + + .uni-calendar__box { + position: relative; + // padding: 0 10px; + padding-bottom: 7px; + } + + .uni-calendar__box-bg { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + justify-content: center; + align-items: center; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + } + + .uni-calendar__box-bg-text { + font-size: 200px; + font-weight: bold; + color: #999; + opacity: 0.1; + text-align: center; + /* #ifndef APP-NVUE */ + line-height: 1; + /* #endif */ + } + + .uni-date-changed { + padding: 0 10px; + // line-height: 50px; + text-align: center; + color: #333; + border-top-color: #DCDCDC; + ; + border-top-style: solid; + border-top-width: 1px; + flex: 1; + } + + .uni-date-btn--ok { + padding: 20px 15px; + } + + .uni-date-changed--time-start { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + align-items: center; + } + + .uni-date-changed--time-end { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + align-items: center; + } + + .uni-date-changed--time-date { + color: #999; + line-height: 50px; + margin-right: 5px; + // opacity: 0.6; + } + + .time-picker-style { + // width: 62px; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + justify-content: center; + align-items: center + } + + .mr-10 { + margin-right: 10px; + } + + .dialog-close { + position: absolute; + top: 0; + right: 0; + bottom: 0; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + align-items: center; + padding: 0 25px; + margin-top: 10px; + } + + .dialog-close-plus { + width: 16px; + height: 2px; + background-color: #737987; + border-radius: 2px; + transform: rotate(45deg); + } + + .dialog-close-rotate { + position: absolute; + transform: rotate(-45deg); + } + + .uni-datetime-picker--btn { + border-radius: 100px; + height: 40px; + line-height: 40px; + background-color: #007aff; + color: #fff; + font-size: 16px; + letter-spacing: 2px; + } + + /* #ifndef APP-NVUE */ + .uni-datetime-picker--btn:active { + opacity: 0.7; + } + /* #endif */ +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json new file mode 100644 index 000000000..9acf1ab0e --- /dev/null +++ b/yudao-ui-admin-uniapp/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 datetime", + "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/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js new file mode 100644 index 000000000..de7509c87 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json new file mode 100644 index 000000000..d2df5e722 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json new file mode 100644 index 000000000..d23fa3c39 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/keypress.js b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/keypress.js new file mode 100644 index 000000000..9601abae3 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue new file mode 100644 index 000000000..699aa639f --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue @@ -0,0 +1,927 @@ +<template> + <view class="uni-datetime-picker"> + <view @click="initTimePicker"> + <slot> + <view class="uni-datetime-picker-timebox-pointer" + :class="{'uni-datetime-picker-disabled': disabled, 'uni-datetime-picker-timebox': border}"> + <text class="uni-datetime-picker-text">{{time}}</text> + <view v-if="!time" class="uni-datetime-picker-time"> + <text class="uni-datetime-picker-text">{{selectTimeText}}</text> + </view> + </view> + </slot> + </view> + <view v-if="visible" id="mask" class="uni-datetime-picker-mask" @click="tiggerTimePicker"></view> + <view v-if="visible" class="uni-datetime-picker-popup" :class="[dateShow && timeShow ? '' : 'fix-nvue-height']" + :style="fixNvueBug"> + <view class="uni-title"> + <text class="uni-datetime-picker-text">{{selectTimeText}}</text> + </view> + <view v-if="dateShow" class="uni-datetime-picker__container-box"> + <picker-view class="uni-datetime-picker-view" :indicator-style="indicatorStyle" :value="ymd" + @change="bindDateChange"> + <picker-view-column> + <view class="uni-datetime-picker-item" v-for="(item,index) in years" :key="index"> + <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text> + </view> + </picker-view-column> + <picker-view-column> + <view class="uni-datetime-picker-item" v-for="(item,index) in months" :key="index"> + <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text> + </view> + </picker-view-column> + <picker-view-column> + <view class="uni-datetime-picker-item" v-for="(item,index) in days" :key="index"> + <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text> + </view> + </picker-view-column> + </picker-view> + <!-- 兼容 nvue 不支持伪类 --> + <text class="uni-datetime-picker-sign sign-left">-</text> + <text class="uni-datetime-picker-sign sign-right">-</text> + </view> + <view v-if="timeShow" class="uni-datetime-picker__container-box"> + <picker-view class="uni-datetime-picker-view" :class="[hideSecond ? 'time-hide-second' : '']" + :indicator-style="indicatorStyle" :value="hms" @change="bindTimeChange"> + <picker-view-column> + <view class="uni-datetime-picker-item" v-for="(item,index) in hours" :key="index"> + <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text> + </view> + </picker-view-column> + <picker-view-column> + <view class="uni-datetime-picker-item" v-for="(item,index) in minutes" :key="index"> + <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text> + </view> + </picker-view-column> + <picker-view-column v-if="!hideSecond"> + <view class="uni-datetime-picker-item" v-for="(item,index) in seconds" :key="index"> + <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text> + </view> + </picker-view-column> + </picker-view> + <!-- 兼容 nvue 不支持伪类 --> + <text class="uni-datetime-picker-sign" :class="[hideSecond ? 'sign-center' : 'sign-left']">:</text> + <text v-if="!hideSecond" class="uni-datetime-picker-sign sign-right">:</text> + </view> + <view class="uni-datetime-picker-btn"> + <view @click="clearTime"> + <text class="uni-datetime-picker-btn-text">{{clearText}}</text> + </view> + <view class="uni-datetime-picker-btn-group"> + <view class="uni-datetime-picker-cancel" @click="tiggerTimePicker"> + <text class="uni-datetime-picker-btn-text">{{cancelText}}</text> + </view> + <view @click="setTime"> + <text class="uni-datetime-picker-btn-text">{{okText}}</text> + </view> + </view> + </view> + </view> + <!-- #ifdef H5 --> + <!-- <keypress v-if="visible" @esc="tiggerTimePicker" @enter="setTime" /> --> + <!-- #endif --> + </view> +</template> + +<script> + // #ifdef H5 + import keypress from './keypress' + // #endif + import { + initVueI18n + } from '@dcloudio/uni-i18n' + import messages from './i18n/index.js' + const { t } = initVueI18n(messages) + + /** + * DatetimePicker 时间选择器 + * @description 可以同时选择日期和时间的选择器 + * @tutorial https://ext.dcloud.net.cn/plugin?id=xxx + * @property {String} type = [datetime | date | time] 显示模式 + * @property {Boolean} multiple = [true|false] 是否多选 + * @property {String|Number} value 默认值 + * @property {String|Number} start 起始日期或时间 + * @property {String|Number} end 起始日期或时间 + * @property {String} return-type = [timestamp | string] + * @event {Function} change 选中发生变化触发 + */ + + export default { + name: 'UniDatetimePicker', + components: { + // #ifdef H5 + keypress + // #endif + }, + data() { + return { + indicatorStyle: `height: 50px;`, + visible: false, + fixNvueBug: {}, + dateShow: true, + timeShow: true, + title: '日期和时间', + // 输入框当前时间 + time: '', + // 当前的年月日时分秒 + year: 1920, + month: 0, + day: 0, + hour: 0, + minute: 0, + second: 0, + // 起始时间 + startYear: 1920, + startMonth: 1, + startDay: 1, + startHour: 0, + startMinute: 0, + startSecond: 0, + // 结束时间 + endYear: 2120, + endMonth: 12, + endDay: 31, + endHour: 23, + endMinute: 59, + endSecond: 59, + } + }, + props: { + type: { + type: String, + default: 'datetime' + }, + value: { + type: [String, Number], + default: '' + }, + modelValue: { + type: [String, Number], + default: '' + }, + start: { + type: [Number, String], + default: '' + }, + end: { + type: [Number, String], + default: '' + }, + returnType: { + type: String, + default: 'string' + }, + disabled: { + type: [Boolean, String], + default: false + }, + border: { + type: [Boolean, String], + default: true + }, + hideSecond: { + type: [Boolean, String], + default: false + } + }, + watch: { + value: { + handler(newVal, oldVal) { + if (newVal) { + this.parseValue(this.fixIosDateFormat(newVal)) //兼容 iOS、safari 日期格式 + this.initTime(false) + } else { + this.time = '' + this.parseValue(Date.now()) + } + }, + immediate: true + }, + type: { + handler(newValue) { + if (newValue === 'date') { + this.dateShow = true + this.timeShow = false + this.title = '日期' + } else if (newValue === 'time') { + this.dateShow = false + this.timeShow = true + this.title = '时间' + } else { + this.dateShow = true + this.timeShow = true + this.title = '日期和时间' + } + }, + immediate: true + }, + start: { + handler(newVal) { + this.parseDatetimeRange(this.fixIosDateFormat(newVal), 'start') //兼容 iOS、safari 日期格式 + }, + immediate: true + }, + end: { + handler(newVal) { + this.parseDatetimeRange(this.fixIosDateFormat(newVal), 'end') //兼容 iOS、safari 日期格式 + }, + immediate: true + }, + + // 月、日、时、分、秒可选范围变化后,检查当前值是否在范围内,不在则当前值重置为可选范围第一项 + months(newVal) { + this.checkValue('month', this.month, newVal) + }, + days(newVal) { + this.checkValue('day', this.day, newVal) + }, + hours(newVal) { + this.checkValue('hour', this.hour, newVal) + }, + minutes(newVal) { + this.checkValue('minute', this.minute, newVal) + }, + seconds(newVal) { + this.checkValue('second', this.second, newVal) + } + }, + computed: { + // 当前年、月、日、时、分、秒选择范围 + years() { + return this.getCurrentRange('year') + }, + + months() { + return this.getCurrentRange('month') + }, + + days() { + return this.getCurrentRange('day') + }, + + hours() { + return this.getCurrentRange('hour') + }, + + minutes() { + return this.getCurrentRange('minute') + }, + + seconds() { + return this.getCurrentRange('second') + }, + + // picker 当前值数组 + ymd() { + return [this.year - this.minYear, this.month - this.minMonth, this.day - this.minDay] + }, + hms() { + return [this.hour - this.minHour, this.minute - this.minMinute, this.second - this.minSecond] + }, + + // 当前 date 是 start + currentDateIsStart() { + return this.year === this.startYear && this.month === this.startMonth && this.day === this.startDay + }, + + // 当前 date 是 end + currentDateIsEnd() { + return this.year === this.endYear && this.month === this.endMonth && this.day === this.endDay + }, + + // 当前年、月、日、时、分、秒的最小值和最大值 + minYear() { + return this.startYear + }, + maxYear() { + return this.endYear + }, + minMonth() { + if (this.year === this.startYear) { + return this.startMonth + } else { + return 1 + } + }, + maxMonth() { + if (this.year === this.endYear) { + return this.endMonth + } else { + return 12 + } + }, + minDay() { + if (this.year === this.startYear && this.month === this.startMonth) { + return this.startDay + } else { + return 1 + } + }, + maxDay() { + if (this.year === this.endYear && this.month === this.endMonth) { + return this.endDay + } else { + return this.daysInMonth(this.year, this.month) + } + }, + minHour() { + if (this.type === 'datetime') { + if (this.currentDateIsStart) { + return this.startHour + } else { + return 0 + } + } + if (this.type === 'time') { + return this.startHour + } + }, + maxHour() { + if (this.type === 'datetime') { + if (this.currentDateIsEnd) { + return this.endHour + } else { + return 23 + } + } + if (this.type === 'time') { + return this.endHour + } + }, + minMinute() { + if (this.type === 'datetime') { + if (this.currentDateIsStart && this.hour === this.startHour) { + return this.startMinute + } else { + return 0 + } + } + if (this.type === 'time') { + if (this.hour === this.startHour) { + return this.startMinute + } else { + return 0 + } + } + }, + maxMinute() { + if (this.type === 'datetime') { + if (this.currentDateIsEnd && this.hour === this.endHour) { + return this.endMinute + } else { + return 59 + } + } + if (this.type === 'time') { + if (this.hour === this.endHour) { + return this.endMinute + } else { + return 59 + } + } + }, + minSecond() { + if (this.type === 'datetime') { + if (this.currentDateIsStart && this.hour === this.startHour && this.minute === this.startMinute) { + return this.startSecond + } else { + return 0 + } + } + if (this.type === 'time') { + if (this.hour === this.startHour && this.minute === this.startMinute) { + return this.startSecond + } else { + return 0 + } + } + }, + maxSecond() { + if (this.type === 'datetime') { + if (this.currentDateIsEnd && this.hour === this.endHour && this.minute === this.endMinute) { + return this.endSecond + } else { + return 59 + } + } + if (this.type === 'time') { + if (this.hour === this.endHour && this.minute === this.endMinute) { + return this.endSecond + } else { + return 59 + } + } + }, + + /** + * for i18n + */ + selectTimeText() { + return t("uni-datetime-picker.selectTime") + }, + okText() { + return t("uni-datetime-picker.ok") + }, + clearText() { + return t("uni-datetime-picker.clear") + }, + cancelText() { + return t("uni-datetime-picker.cancel") + } + }, + + mounted() { + // #ifdef APP-NVUE + const res = uni.getSystemInfoSync(); + this.fixNvueBug = { + top: res.windowHeight / 2, + left: res.windowWidth / 2 + } + // #endif + }, + + methods: { + /** + * @param {Object} item + * 小于 10 在前面加个 0 + */ + + lessThanTen(item) { + return item < 10 ? '0' + item : item + }, + + /** + * 解析时分秒字符串,例如:00:00:00 + * @param {String} timeString + */ + parseTimeType(timeString) { + if (timeString) { + let timeArr = timeString.split(':') + this.hour = Number(timeArr[0]) + this.minute = Number(timeArr[1]) + this.second = Number(timeArr[2]) + } + }, + + /** + * 解析选择器初始值,类型可以是字符串、时间戳,例如:2000-10-02、'08:30:00'、 1610695109000 + * @param {String | Number} datetime + */ + initPickerValue(datetime) { + let defaultValue = null + if (datetime) { + defaultValue = this.compareValueWithStartAndEnd(datetime, this.start, this.end) + } else { + defaultValue = Date.now() + defaultValue = this.compareValueWithStartAndEnd(defaultValue, this.start, this.end) + } + this.parseValue(defaultValue) + }, + + /** + * 初始值规则: + * - 用户设置初始值 value + * - 设置了起始时间 start、终止时间 end,并 start < value < end,初始值为 value, 否则初始值为 start + * - 只设置了起始时间 start,并 start < value,初始值为 value,否则初始值为 start + * - 只设置了终止时间 end,并 value < end,初始值为 value,否则初始值为 end + * - 无起始终止时间,则初始值为 value + * - 无初始值 value,则初始值为当前本地时间 Date.now() + * @param {Object} value + * @param {Object} dateBase + */ + compareValueWithStartAndEnd(value, start, end) { + let winner = null + value = this.superTimeStamp(value) + start = this.superTimeStamp(start) + end = this.superTimeStamp(end) + + if (start && end) { + if (value < start) { + winner = new Date(start) + } else if (value > end) { + winner = new Date(end) + } else { + winner = new Date(value) + } + } else if (start && !end) { + winner = start <= value ? new Date(value) : new Date(start) + } else if (!start && end) { + winner = value <= end ? new Date(value) : new Date(end) + } else { + winner = new Date(value) + } + + return winner + }, + + /** + * 转换为可比较的时间戳,接受日期、时分秒、时间戳 + * @param {Object} value + */ + superTimeStamp(value) { + let dateBase = '' + if (this.type === 'time' && value && typeof value === 'string') { + const now = new Date() + const year = now.getFullYear() + const month = now.getMonth() + 1 + const day = now.getDate() + dateBase = year + '/' + month + '/' + day + ' ' + } + if (Number(value) && typeof value !== NaN) { + value = parseInt(value) + dateBase = 0 + } + return this.createTimeStamp(dateBase + value) + }, + + /** + * 解析默认值 value,字符串、时间戳 + * @param {Object} defaultTime + */ + parseValue(value) { + if (!value) { + return + } + if (this.type === 'time' && typeof value === "string") { + this.parseTimeType(value) + } else { + let defaultDate = null + defaultDate = new Date(value) + if (this.type !== 'time') { + this.year = defaultDate.getFullYear() + this.month = defaultDate.getMonth() + 1 + this.day = defaultDate.getDate() + } + if (this.type !== 'date') { + this.hour = defaultDate.getHours() + this.minute = defaultDate.getMinutes() + this.second = defaultDate.getSeconds() + } + } + if (this.hideSecond) { + this.second = 0 + } + }, + + /** + * 解析可选择时间范围 start、end,年月日字符串、时间戳 + * @param {Object} defaultTime + */ + parseDatetimeRange(point, pointType) { + // 时间为空,则重置为初始值 + if (!point) { + if (pointType === 'start') { + this.startYear = 1920 + this.startMonth = 1 + this.startDay = 1 + this.startHour = 0 + this.startMinute = 0 + this.startSecond = 0 + } + if (pointType === 'end') { + this.endYear = 2120 + this.endMonth = 12 + this.endDay = 31 + this.endHour = 23 + this.endMinute = 59 + this.endSecond = 59 + } + return + } + if (this.type === 'time') { + const pointArr = point.split(':') + this[pointType + 'Hour'] = Number(pointArr[0]) + this[pointType + 'Minute'] = Number(pointArr[1]) + this[pointType + 'Second'] = Number(pointArr[2]) + } else { + if (!point) { + pointType === 'start' ? this.startYear = this.year - 60 : this.endYear = this.year + 60 + return + } + if (Number(point) && Number(point) !== NaN) { + point = parseInt(point) + } + // datetime 的 end 没有时分秒, 则不限制 + const hasTime = /[0-9]:[0-9]/ + if (this.type === 'datetime' && pointType === 'end' && typeof point === 'string' && !hasTime.test( + point)) { + point = point + ' 23:59:59' + } + const pointDate = new Date(point) + this[pointType + 'Year'] = pointDate.getFullYear() + this[pointType + 'Month'] = pointDate.getMonth() + 1 + this[pointType + 'Day'] = pointDate.getDate() + if (this.type === 'datetime') { + this[pointType + 'Hour'] = pointDate.getHours() + this[pointType + 'Minute'] = pointDate.getMinutes() + this[pointType + 'Second'] = pointDate.getSeconds() + } + } + }, + + // 获取 年、月、日、时、分、秒 当前可选范围 + getCurrentRange(value) { + const range = [] + for (let i = this['min' + this.capitalize(value)]; i <= this['max' + this.capitalize(value)]; i++) { + range.push(i) + } + return range + }, + + // 字符串首字母大写 + capitalize(str) { + return str.charAt(0).toUpperCase() + str.slice(1) + }, + + // 检查当前值是否在范围内,不在则当前值重置为可选范围第一项 + checkValue(name, value, values) { + if (values.indexOf(value) === -1) { + this[name] = values[0] + } + }, + + // 每个月的实际天数 + daysInMonth(year, month) { // Use 1 for January, 2 for February, etc. + return new Date(year, month, 0).getDate(); + }, + + //兼容 iOS、safari 日期格式 + fixIosDateFormat(value) { + if (typeof value === 'string') { + value = value.replace(/-/g, '/') + } + return value + }, + + /** + * 生成时间戳 + * @param {Object} time + */ + createTimeStamp(time) { + if (!time) return + if (typeof time === "number") { + return time + } else { + time = time.replace(/-/g, '/') + if (this.type === 'date') { + time = time + ' ' + '00:00:00' + } + return Date.parse(time) + } + }, + + /** + * 生成日期或时间的字符串 + */ + createDomSting() { + const yymmdd = this.year + + '-' + + this.lessThanTen(this.month) + + '-' + + this.lessThanTen(this.day) + + let hhmmss = this.lessThanTen(this.hour) + + ':' + + this.lessThanTen(this.minute) + + if (!this.hideSecond) { + hhmmss = hhmmss + ':' + this.lessThanTen(this.second) + } + + if (this.type === 'date') { + return yymmdd + } else if (this.type === 'time') { + return hhmmss + } else { + return yymmdd + ' ' + hhmmss + } + }, + + /** + * 初始化返回值,并抛出 change 事件 + */ + initTime(emit = true) { + this.time = this.createDomSting() + if (!emit) return + if (this.returnType === 'timestamp' && this.type !== 'time') { + this.$emit('change', this.createTimeStamp(this.time)) + this.$emit('input', this.createTimeStamp(this.time)) + this.$emit('update:modelValue', this.createTimeStamp(this.time)) + } else { + this.$emit('change', this.time) + this.$emit('input', this.time) + this.$emit('update:modelValue', this.time) + } + }, + + /** + * 用户选择日期或时间更新 data + * @param {Object} e + */ + bindDateChange(e) { + const val = e.detail.value + this.year = this.years[val[0]] + this.month = this.months[val[1]] + this.day = this.days[val[2]] + }, + bindTimeChange(e) { + const val = e.detail.value + this.hour = this.hours[val[0]] + this.minute = this.minutes[val[1]] + this.second = this.seconds[val[2]] + }, + + /** + * 初始化弹出层 + */ + initTimePicker() { + if (this.disabled) return + const value = this.fixIosDateFormat(this.value) + this.initPickerValue(value) + this.visible = !this.visible + }, + + /** + * 触发或关闭弹框 + */ + tiggerTimePicker(e) { + this.visible = !this.visible + }, + + /** + * 用户点击“清空”按钮,清空当前值 + */ + clearTime() { + this.time = '' + this.$emit('change', this.time) + this.$emit('input', this.time) + this.$emit('update:modelValue', this.time) + this.tiggerTimePicker() + }, + + /** + * 用户点击“确定”按钮 + */ + setTime() { + this.initTime() + this.tiggerTimePicker() + } + } + } +</script> + +<style> + .uni-datetime-picker { + /* #ifndef APP-NVUE */ + /* width: 100%; */ + /* #endif */ + } + + .uni-datetime-picker-view { + height: 130px; + width: 270px; + /* #ifndef APP-NVUE */ + cursor: pointer; + /* #endif */ + } + + .uni-datetime-picker-item { + height: 50px; + line-height: 50px; + text-align: center; + font-size: 14px; + } + + .uni-datetime-picker-btn { + margin-top: 60px; + /* #ifndef APP-NVUE */ + display: flex; + cursor: pointer; + /* #endif */ + flex-direction: row; + justify-content: space-between; + } + + .uni-datetime-picker-btn-text { + font-size: 14px; + color: #007AFF; + } + + .uni-datetime-picker-btn-group { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + } + + .uni-datetime-picker-cancel { + margin-right: 30px; + } + + .uni-datetime-picker-mask { + position: fixed; + bottom: 0px; + top: 0px; + left: 0px; + right: 0px; + background-color: rgba(0, 0, 0, 0.4); + transition-duration: 0.3s; + z-index: 998; + } + + .uni-datetime-picker-popup { + border-radius: 8px; + padding: 30px; + width: 270px; + /* #ifdef APP-NVUE */ + height: 500px; + /* #endif */ + /* #ifdef APP-NVUE */ + width: 330px; + /* #endif */ + background-color: #fff; + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + transition-duration: 0.3s; + z-index: 999; + } + + .fix-nvue-height { + /* #ifdef APP-NVUE */ + height: 330px; + /* #endif */ + } + + .uni-datetime-picker-time { + color: grey; + } + + .uni-datetime-picker-column { + height: 50px; + } + + .uni-datetime-picker-timebox { + + border: 1px solid #E5E5E5; + border-radius: 5px; + padding: 7px 10px; + /* #ifndef APP-NVUE */ + box-sizing: border-box; + cursor: pointer; + /* #endif */ + } + + .uni-datetime-picker-timebox-pointer { + /* #ifndef APP-NVUE */ + cursor: pointer; + /* #endif */ + } + + + .uni-datetime-picker-disabled { + opacity: 0.4; + /* #ifdef H5 */ + cursor: not-allowed !important; + /* #endif */ + } + + .uni-datetime-picker-text { + font-size: 14px; + } + + .uni-datetime-picker-sign { + position: absolute; + top: 53px; + /* 减掉 10px 的元素高度,兼容nvue */ + color: #999; + /* #ifdef APP-NVUE */ + font-size: 16px; + /* #endif */ + } + + .sign-left { + left: 86px; + } + + .sign-right { + right: 86px; + } + + .sign-center { + left: 135px; + } + + .uni-datetime-picker__container-box { + position: relative; + display: flex; + align-items: center; + justify-content: center; + margin-top: 40px; + } + + .time-hide-second { + width: 180px; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue new file mode 100644 index 000000000..9bdf8bca8 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue @@ -0,0 +1,1012 @@ +<template> + <view class="uni-date"> + <view class="uni-date-editor" @click="show"> + <slot> + <view class="uni-date-editor--x" :class="{'uni-date-editor--x__disabled': disabled, + 'uni-date-x--border': border}"> + <view v-if="!isRange" class="uni-date-x uni-date-single"> + <uni-icons type="calendar" color="#c0c4cc" size="22"></uni-icons> + <input class="uni-date__x-input" type="text" v-model="singleVal" + :placeholder="singlePlaceholderText" :disabled="true" /> + </view> + <view v-else class="uni-date-x uni-date-range"> + <uni-icons type="calendar" color="#c0c4cc" size="22"></uni-icons> + <input class="uni-date__x-input t-c" type="text" v-model="range.startDate" + :placeholder="startPlaceholderText" :disabled="true" /> + <slot> + <view class="">{{rangeSeparator}}</view> + </slot> + <input class="uni-date__x-input t-c" type="text" v-model="range.endDate" + :placeholder="endPlaceholderText" :disabled="true" /> + </view> + <view v-if="showClearIcon" class="uni-date__icon-clear" @click.stop="clear"> + <uni-icons type="clear" color="#c0c4cc" size="24"></uni-icons> + </view> + </view> + </slot> + </view> + + <view v-show="popup" class="uni-date-mask" @click="close"></view> + <view v-if="!isPhone" ref="datePicker" v-show="popup" class="uni-date-picker__container"> + <view v-if="!isRange" class="uni-date-single--x" :style="popover"> + <view class="uni-popper__arrow"></view> + <view v-if="hasTime" class="uni-date-changed popup-x-header"> + <input class="uni-date__input t-c" type="text" v-model="tempSingleDate" + :placeholder="selectDateText" /> + <time-picker type="time" v-model="time" :border="false" :disabled="!tempSingleDate" + :start="reactStartTime" :end="reactEndTime" :hideSecond="hideSecond" style="width: 100%;"> + <input class="uni-date__input t-c" type="text" v-model="time" :placeholder="selectTimeText" + :disabled="!tempSingleDate" /> + </time-picker> + </view> + <calendar ref="pcSingle" :showMonth="false" :start-date="caleRange.startDate" + :end-date="caleRange.endDate" :date="defSingleDate" @change="singleChange" + style="padding: 0 8px;" /> + <view v-if="hasTime" class="popup-x-footer"> + <!-- <text class="">此刻</text> --> + <text class="confirm" @click="confirmSingleChange">{{okText}}</text> + </view> + <view class="uni-date-popper__arrow"></view> + </view> + + <view v-else class="uni-date-range--x" :style="popover"> + <view class="uni-popper__arrow"></view> + <view v-if="hasTime" class="popup-x-header uni-date-changed"> + <view class="popup-x-header--datetime"> + <input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.startDate" + :placeholder="startDateText" /> + <time-picker type="time" v-model="tempRange.startTime" :start="reactStartTime" :border="false" + :disabled="!tempRange.startDate" :hideSecond="hideSecond"> + <input class="uni-date__input uni-date-range__input" type="text" + v-model="tempRange.startTime" :placeholder="startTimeText" + :disabled="!tempRange.startDate" /> + </time-picker> + </view> + <uni-icons type="arrowthinright" color="#999" style="line-height: 40px;"></uni-icons> + <view class="popup-x-header--datetime"> + <input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.endDate" + :placeholder="endDateText" /> + <time-picker type="time" v-model="tempRange.endTime" :end="reactEndTime" :border="false" + :disabled="!tempRange.endDate" :hideSecond="hideSecond"> + <input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.endTime" + :placeholder="endTimeText" :disabled="!tempRange.endDate" /> + </time-picker> + </view> + </view> + <view class="popup-x-body"> + <calendar ref="left" :showMonth="false" :start-date="caleRange.startDate" + :end-date="caleRange.endDate" :range="true" @change="leftChange" :pleStatus="endMultipleStatus" + @firstEnterCale="updateRightCale" @monthSwitch="leftMonthSwitch" style="padding: 0 8px;" /> + <calendar ref="right" :showMonth="false" :start-date="caleRange.startDate" + :end-date="caleRange.endDate" :range="true" @change="rightChange" + :pleStatus="startMultipleStatus" @firstEnterCale="updateLeftCale" + @monthSwitch="rightMonthSwitch" style="padding: 0 8px;border-left: 1px solid #F1F1F1;" /> + </view> + <view v-if="hasTime" class="popup-x-footer"> + <text class="" @click="clear">{{clearText}}</text> + <text class="confirm" @click="confirmRangeChange">{{okText}}</text> + </view> + </view> + </view> + <calendar v-show="isPhone" ref="mobile" :clearDate="false" :date="defSingleDate" :defTime="reactMobDefTime" + :start-date="caleRange.startDate" :end-date="caleRange.endDate" :selectableTimes="mobSelectableTime" + :pleStatus="endMultipleStatus" :showMonth="false" :range="isRange" :typeHasTime="hasTime" :insert="false" + :hideSecond="hideSecond" @confirm="mobileChange" /> + </view> +</template> +<script> + /** + * DatetimePicker 时间选择器 + * @description 同时支持 PC 和移动端使用日历选择日期和日期范围 + * @tutorial https://ext.dcloud.net.cn/plugin?id=3962 + * @property {String} type 选择器类型 + * @property {String|Number|Array|Date} value 绑定值 + * @property {String} placeholder 单选择时的占位内容 + * @property {String} start 起始时间 + * @property {String} end 终止时间 + * @property {String} start-placeholder 范围选择时开始日期的占位内容 + * @property {String} end-placeholder 范围选择时结束日期的占位内容 + * @property {String} range-separator 选择范围时的分隔符 + * @property {Boolean} border = [true|false] 是否有边框 + * @property {Boolean} disabled = [true|false] 是否禁用 + * @property {Boolean} clearIcon = [true|false] 是否显示清除按钮(仅PC端适用) + * @event {Function} change 确定日期时触发的事件 + * @event {Function} show 打开弹出层 + * @event {Function} close 关闭弹出层 + * @event {Function} clear 清除上次选中的状态和值 + **/ + import calendar from './calendar.vue' + import timePicker from './time-picker.vue' + import { + initVueI18n + } from '@dcloudio/uni-i18n' + import messages from './i18n/index.js' + const { + t + } = initVueI18n(messages) + + export default { + name: 'UniDatetimePicker', + options: { + virtualHost: true + }, + components: { + calendar, + timePicker + }, + inject: { + form: { + from: 'uniForm', + default: null + }, + formItem: { + from: 'uniFormItem', + default: null + }, + }, + data() { + return { + isRange: false, + hasTime: false, + mobileRange: false, + // 单选 + singleVal: '', + tempSingleDate: '', + defSingleDate: '', + time: '', + // 范围选 + caleRange: { + startDate: '', + startTime: '', + endDate: '', + endTime: '' + }, + range: { + startDate: '', + // startTime: '', + endDate: '', + // endTime: '' + }, + tempRange: { + startDate: '', + startTime: '', + endDate: '', + endTime: '' + }, + // 左右日历同步数据 + startMultipleStatus: { + before: '', + after: '', + data: [], + fulldate: '' + }, + endMultipleStatus: { + before: '', + after: '', + data: [], + fulldate: '' + }, + visible: false, + popup: false, + popover: null, + isEmitValue: false, + isPhone: false, + isFirstShow: true, + } + }, + props: { + type: { + type: String, + default: 'datetime' + }, + value: { + type: [String, Number, Array, Date], + default: '' + }, + modelValue: { + type: [String, Number, Array, Date], + default: '' + }, + start: { + type: [Number, String], + default: '' + }, + end: { + type: [Number, String], + default: '' + }, + returnType: { + type: String, + default: 'string' + }, + placeholder: { + type: String, + default: '' + }, + startPlaceholder: { + type: String, + default: '' + }, + endPlaceholder: { + type: String, + default: '' + }, + rangeSeparator: { + type: String, + default: '-' + }, + border: { + type: [Boolean], + default: true + }, + disabled: { + type: [Boolean], + default: false + }, + clearIcon: { + type: [Boolean], + default: true + }, + hideSecond: { + type: [Boolean], + default: false + } + }, + watch: { + type: { + immediate: true, + handler(newVal, oldVal) { + if (newVal.indexOf('time') !== -1) { + this.hasTime = true + } else { + this.hasTime = false + } + if (newVal.indexOf('range') !== -1) { + this.isRange = true + } else { + this.isRange = false + } + } + }, + // #ifndef VUE3 + value: { + immediate: true, + handler(newVal, oldVal) { + if (this.isEmitValue) { + this.isEmitValue = false + return + } + this.initPicker(newVal) + } + }, + // #endif + // #ifdef VUE3 + modelValue: { + immediate: true, + handler(newVal, oldVal) { + if (this.isEmitValue) { + this.isEmitValue = false + return + } + this.initPicker(newVal) + } + }, + // #endif + start: { + immediate: true, + handler(newVal, oldVal) { + if (!newVal) return + const { + defDate, + defTime + } = this.parseDate(newVal) + this.caleRange.startDate = defDate + if (this.hasTime) { + this.caleRange.startTime = defTime + } + } + }, + end: { + immediate: true, + handler(newVal, oldVal) { + if (!newVal) return + const { + defDate, + defTime + } = this.parseDate(newVal) + this.caleRange.endDate = defDate + if (this.hasTime) { + this.caleRange.endTime = defTime + } + } + }, + }, + computed: { + reactStartTime() { + const activeDate = this.isRange ? this.tempRange.startDate : this.tempSingleDate + const res = activeDate === this.caleRange.startDate ? this.caleRange.startTime : '' + return res + }, + reactEndTime() { + const activeDate = this.isRange ? this.tempRange.endDate : this.tempSingleDate + const res = activeDate === this.caleRange.endDate ? this.caleRange.endTime : '' + return res + }, + reactMobDefTime() { + const times = { + start: this.tempRange.startTime, + end: this.tempRange.endTime + } + return this.isRange ? times : this.time + }, + mobSelectableTime() { + return { + start: this.caleRange.startTime, + end: this.caleRange.endTime + } + }, + datePopupWidth() { + // todo + return this.isRange ? 653 : 301 + }, + + /** + * for i18n + */ + singlePlaceholderText() { + return this.placeholder || (this.type === 'date' ? this.selectDateText : t( + "uni-datetime-picker.selectDateTime")) + }, + startPlaceholderText() { + return this.startPlaceholder || this.startDateText + }, + endPlaceholderText() { + return this.endPlaceholder || this.endDateText + }, + selectDateText() { + return t("uni-datetime-picker.selectDate") + }, + selectTimeText() { + return t("uni-datetime-picker.selectTime") + }, + startDateText() { + return this.startPlaceholder || t("uni-datetime-picker.startDate") + }, + startTimeText() { + return t("uni-datetime-picker.startTime") + }, + endDateText() { + return this.endPlaceholder || t("uni-datetime-picker.endDate") + }, + endTimeText() { + return t("uni-datetime-picker.endTime") + }, + okText() { + return t("uni-datetime-picker.ok") + }, + clearText() { + return t("uni-datetime-picker.clear") + }, + showClearIcon() { + const { + clearIcon, + disabled, + singleVal, + range + } = this + const bool = clearIcon && !disabled && (singleVal || (range.startDate && range.endDate)) + return bool + } + }, + created() { + // if (this.form && this.formItem) { + // this.$watch('formItem.errMsg', (newVal) => { + // this.localMsg = newVal + // }) + // } + }, + mounted() { + this.platform() + }, + methods: { + initPicker(newVal) { + if (!newVal || Array.isArray(newVal) && !newVal.length) { + this.$nextTick(() => { + this.clear(false) + }) + return + } + if (!Array.isArray(newVal) && !this.isRange) { + const { + defDate, + defTime + } = this.parseDate(newVal) + this.singleVal = defDate + this.tempSingleDate = defDate + this.defSingleDate = defDate + if (this.hasTime) { + this.singleVal = defDate + ' ' + defTime + this.time = defTime + } + } else { + const [before, after] = newVal + if (!before && !after) return + const defBefore = this.parseDate(before) + const defAfter = this.parseDate(after) + const startDate = defBefore.defDate + const endDate = defAfter.defDate + this.range.startDate = this.tempRange.startDate = startDate + this.range.endDate = this.tempRange.endDate = endDate + + if (this.hasTime) { + this.range.startDate = defBefore.defDate + ' ' + defBefore.defTime + this.range.endDate = defAfter.defDate + ' ' + defAfter.defTime + this.tempRange.startTime = defBefore.defTime + this.tempRange.endTime = defAfter.defTime + } + const defaultRange = { + before: defBefore.defDate, + after: defAfter.defDate + } + this.startMultipleStatus = Object.assign({}, this.startMultipleStatus, defaultRange, { + which: 'right' + }) + this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, defaultRange, { + which: 'left' + }) + } + }, + updateLeftCale(e) { + const left = this.$refs.left + // 设置范围选 + left.cale.setHoverMultiple(e.after) + left.setDate(this.$refs.left.nowDate.fullDate) + }, + updateRightCale(e) { + const right = this.$refs.right + // 设置范围选 + right.cale.setHoverMultiple(e.after) + right.setDate(this.$refs.right.nowDate.fullDate) + }, + platform() { + const systemInfo = uni.getSystemInfoSync() + this.isPhone = systemInfo.windowWidth <= 500 + this.windowWidth = systemInfo.windowWidth + }, + show(event) { + if (this.disabled) { + return + } + this.platform() + if (this.isPhone) { + this.$refs.mobile.open() + return + } + this.popover = { + top: '10px' + } + const dateEditor = uni.createSelectorQuery().in(this).select(".uni-date-editor") + dateEditor.boundingClientRect(rect => { + if (this.windowWidth - rect.left < this.datePopupWidth) { + this.popover.right = 0 + } + }).exec() + setTimeout(() => { + this.popup = !this.popup + if (!this.isPhone && this.isRange && this.isFirstShow) { + this.isFirstShow = false + const { + startDate, + endDate + } = this.range + if (startDate && endDate) { + if (this.diffDate(startDate, endDate) < 30) { + this.$refs.right.next() + } + } else { + this.$refs.right.next() + this.$refs.right.cale.lastHover = false + } + } + + }, 50) + }, + + close() { + setTimeout(() => { + this.popup = false + this.$emit('maskClick', this.value) + }, 20) + }, + setEmit(value) { + if (this.returnType === "timestamp" || this.returnType === "date") { + if (!Array.isArray(value)) { + if (!this.hasTime) { + value = value + ' ' + '00:00:00' + } + value = this.createTimestamp(value) + if (this.returnType === "date") { + value = new Date(value) + } + } else { + if (!this.hasTime) { + value[0] = value[0] + ' ' + '00:00:00' + value[1] = value[1] + ' ' + '00:00:00' + } + value[0] = this.createTimestamp(value[0]) + value[1] = this.createTimestamp(value[1]) + if (this.returnType === "date") { + value[0] = new Date(value[0]) + value[1] = new Date(value[1]) + } + } + } + + + this.$emit('change', value) + this.$emit('input', value) + this.$emit('update:modelValue', value) + this.isEmitValue = true + }, + createTimestamp(date) { + date = this.fixIosDateFormat(date) + return Date.parse(new Date(date)) + }, + singleChange(e) { + this.tempSingleDate = e.fulldate + if (this.hasTime) return + this.confirmSingleChange() + }, + + confirmSingleChange() { + if (!this.tempSingleDate) { + this.popup = false + return + } + if (this.hasTime) { + this.singleVal = this.tempSingleDate + ' ' + (this.time ? this.time : '00:00:00') + } else { + this.singleVal = this.tempSingleDate + } + this.setEmit(this.singleVal) + this.popup = false + }, + + leftChange(e) { + const { + before, + after + } = e.range + this.rangeChange(before, after) + const obj = { + before: e.range.before, + after: e.range.after, + data: e.range.data, + fulldate: e.fulldate + } + this.startMultipleStatus = Object.assign({}, this.startMultipleStatus, obj) + }, + + rightChange(e) { + const { + before, + after + } = e.range + this.rangeChange(before, after) + const obj = { + before: e.range.before, + after: e.range.after, + data: e.range.data, + fulldate: e.fulldate + } + this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, obj) + }, + + mobileChange(e) { + if (this.isRange) { + const { + before, + after + } = e.range + this.handleStartAndEnd(before, after, true) + if (this.hasTime) { + const { + startTime, + endTime + } = e.timeRange + this.tempRange.startTime = startTime + this.tempRange.endTime = endTime + } + this.confirmRangeChange() + + } else { + if (this.hasTime) { + this.singleVal = e.fulldate + ' ' + e.time + } else { + this.singleVal = e.fulldate + } + this.setEmit(this.singleVal) + } + this.$refs.mobile.close() + }, + + rangeChange(before, after) { + if (!(before && after)) return + this.handleStartAndEnd(before, after, true) + if (this.hasTime) return + this.confirmRangeChange() + }, + + confirmRangeChange() { + if (!this.tempRange.startDate && !this.tempRange.endDate) { + this.popup = false + return + } + let start, end + if (!this.hasTime) { + start = this.range.startDate = this.tempRange.startDate + end = this.range.endDate = this.tempRange.endDate + } else { + start = this.range.startDate = this.tempRange.startDate + ' ' + + (this.tempRange.startTime ? this.tempRange.startTime : '00:00:00') + end = this.range.endDate = this.tempRange.endDate + ' ' + + (this.tempRange.endTime ? this.tempRange.endTime : '00:00:00') + } + const displayRange = [start, end] + this.setEmit(displayRange) + this.popup = false + }, + + handleStartAndEnd(before, after, temp = false) { + if (!(before && after)) return + const type = temp ? 'tempRange' : 'range' + if (this.dateCompare(before, after)) { + this[type].startDate = before + this[type].endDate = after + } else { + this[type].startDate = after + this[type].endDate = before + } + }, + + /** + * 比较时间大小 + */ + dateCompare(startDate, endDate) { + // 计算截止时间 + startDate = new Date(startDate.replace('-', '/').replace('-', '/')) + // 计算详细项的截止时间 + endDate = new Date(endDate.replace('-', '/').replace('-', '/')) + if (startDate <= endDate) { + return true + } else { + return false + } + }, + + /** + * 比较时间差 + */ + diffDate(startDate, endDate) { + // 计算截止时间 + startDate = new Date(startDate.replace('-', '/').replace('-', '/')) + // 计算详细项的截止时间 + endDate = new Date(endDate.replace('-', '/').replace('-', '/')) + const diff = (endDate - startDate) / (24 * 60 * 60 * 1000) + return Math.abs(diff) + }, + + clear(needEmit = true) { + if (!this.isRange) { + this.singleVal = '' + this.tempSingleDate = '' + this.time = '' + if (this.isPhone) { + this.$refs.mobile && this.$refs.mobile.clearCalender() + } else { + this.$refs.pcSingle && this.$refs.pcSingle.clearCalender() + } + if (needEmit) { + // 校验规则 + // if(this.form && this.formItem){ + // const { + // validateTrigger + // } = this.form + // if (validateTrigger === 'blur') { + // this.formItem.onFieldChange() + // } + // } + this.$emit('change', '') + this.$emit('input', '') + this.$emit('update:modelValue', '') + } + } else { + this.range.startDate = '' + this.range.endDate = '' + this.tempRange.startDate = '' + this.tempRange.startTime = '' + this.tempRange.endDate = '' + this.tempRange.endTime = '' + if (this.isPhone) { + this.$refs.mobile && this.$refs.mobile.clearCalender() + } else { + this.$refs.left && this.$refs.left.clearCalender() + this.$refs.right && this.$refs.right.clearCalender() + this.$refs.right && this.$refs.right.next() + } + if (needEmit) { + this.$emit('change', []) + this.$emit('input', []) + this.$emit('update:modelValue', []) + } + } + }, + + parseDate(date) { + date = this.fixIosDateFormat(date) + const defVal = new Date(date) + const year = defVal.getFullYear() + const month = defVal.getMonth() + 1 + const day = defVal.getDate() + const hour = defVal.getHours() + const minute = defVal.getMinutes() + const second = defVal.getSeconds() + const defDate = year + '-' + this.lessTen(month) + '-' + this.lessTen(day) + const defTime = this.lessTen(hour) + ':' + this.lessTen(minute) + (this.hideSecond ? '' : (':' + this + .lessTen(second))) + return { + defDate, + defTime + } + }, + + lessTen(item) { + return item < 10 ? '0' + item : item + }, + + //兼容 iOS、safari 日期格式 + fixIosDateFormat(value) { + if (typeof value === 'string') { + value = value.replace(/-/g, '/') + } + return value + }, + + leftMonthSwitch(e) { + // console.log('leftMonthSwitch 返回:', e) + }, + rightMonthSwitch(e) { + // console.log('rightMonthSwitch 返回:', e) + } + } + } +</script> + +<style> + .uni-date { + /* #ifndef APP-NVUE */ + width: 100%; + /* #endif */ + flex: 1; + } + .uni-date-x { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + padding: 0 10px; + border-radius: 4px; + background-color: #fff; + color: #666; + font-size: 14px; + flex: 1; + } + + .uni-date-x--border { + box-sizing: border-box; + border-radius: 4px; + border: 1px solid #e5e5e5; + } + + .uni-date-editor--x { + display: flex; + align-items: center; + position: relative; + } + + .uni-date-editor--x .uni-date__icon-clear { + padding: 0 5px; + display: flex; + align-items: center; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + + .uni-date__x-input { + padding: 0 8px; + /* #ifndef APP-NVUE */ + width: auto; + /* #endif */ + position: relative; + overflow: hidden; + flex: 1; + line-height: 1; + font-size: 14px; + height: 35px; + } + + .t-c { + text-align: center; + } + + .uni-date__input { + height: 40px; + width: 100%; + line-height: 40px; + font-size: 14px; + } + + .uni-date-range__input { + text-align: center; + max-width: 142px; + } + + .uni-date-picker__container { + position: relative; + /* position: fixed; + left: 0; + right: 0; + top: 0; + bottom: 0; + box-sizing: border-box; + z-index: 996; + font-size: 14px; */ + } + + .uni-date-mask { + position: fixed; + bottom: 0px; + top: 0px; + left: 0px; + right: 0px; + background-color: rgba(0, 0, 0, 0); + transition-duration: 0.3s; + z-index: 996; + } + + .uni-date-single--x { + /* padding: 0 8px; */ + background-color: #fff; + position: absolute; + top: 0; + z-index: 999; + border: 1px solid #EBEEF5; + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); + border-radius: 4px; + } + + .uni-date-range--x { + /* padding: 0 8px; */ + background-color: #fff; + position: absolute; + top: 0; + z-index: 999; + border: 1px solid #EBEEF5; + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); + border-radius: 4px; + } + + .uni-date-editor--x__disabled { + opacity: 0.4; + cursor: default; + } + + .uni-date-editor--logo { + width: 16px; + height: 16px; + vertical-align: middle; + } + + /* 添加时间 */ + .popup-x-header { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + /* justify-content: space-between; */ + } + + .popup-x-header--datetime { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + flex: 1; + } + + .popup-x-body { + display: flex; + } + + .popup-x-footer { + padding: 0 15px; + border-top-color: #F1F1F1; + border-top-style: solid; + border-top-width: 1px; + /* background-color: #fff; */ + line-height: 40px; + text-align: right; + color: #666; + } + + .popup-x-footer text:hover { + color: #007aff; + cursor: pointer; + opacity: 0.8; + } + + .popup-x-footer .confirm { + margin-left: 20px; + color: #007aff; + } + + .uni-date-changed { + /* background-color: #fff; */ + text-align: center; + color: #333; + border-bottom-color: #F1F1F1; + border-bottom-style: solid; + border-bottom-width: 1px; + /* padding: 0 50px; */ + } + + .uni-date-changed--time text { + /* padding: 0 20px; */ + height: 50px; + line-height: 50px; + } + + .uni-date-changed .uni-date-changed--time { + /* display: flex; */ + flex: 1; + } + + .uni-date-changed--time-date { + color: #333; + opacity: 0.6; + } + + .mr-50 { + margin-right: 50px; + } + + /* picker 弹出层通用的指示小三角, todo:扩展至上下左右方向定位 */ + .uni-popper__arrow, + .uni-popper__arrow::after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + border-width: 6px; + } + + .uni-popper__arrow { + filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03)); + top: -6px; + left: 10%; + margin-right: 3px; + border-top-width: 0; + border-bottom-color: #EBEEF5; + } + + .uni-popper__arrow::after { + content: " "; + top: 1px; + margin-left: -6px; + border-top-width: 0; + border-bottom-color: #fff; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js new file mode 100644 index 000000000..efa5773ae --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js @@ -0,0 +1,410 @@ +class Calendar { + constructor({ + date, + selected, + startDate, + endDate, + range, + // multipleStatus + } = {}) { + // 当前日期 + 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) + // this.multipleStatus = multipleStatus + this.lastHover = false + } + /** + * 设置日期 + * @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) { + dd.setDate(dd.getDate() + AddDayCount) + } else { + dd.setMonth(dd.getMonth() + AddDayCount) // 获取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, + disable: true + }) + } + return dateArr + } + /** + * 获取本月天数 + */ + _currentMonthDys(dateData, full) { + let dateArr = [] + let fullDate = this.date.fullDate + for (let i = 1; i <= dateData; i++) { + let isinfo = false + 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.isLogicBefore(nowDate, this.multipleStatus.before, this.multipleStatus.after), + afterMultiple: this.isLogicAfter(nowDate, this.multipleStatus.before, this.multipleStatus.after), + month: full.month, + disable: !(disableBefore && disableAfter), + isDay, + userChecked: false + } + 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, + 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 + } + } + + /** + * 比较真实起始日期 + */ + + isLogicBefore(currentDay, before, after) { + let logicBefore = before + if (before && after) { + logicBefore = this.dateCompare(before, after) ? before : after + } + return this.dateEqual(logicBefore, currentDay) + } + + isLogicAfter(currentDay, before, after) { + let logicAfter = after + if (before && after) { + logicAfter = this.dateCompare(before, after) ? after : before + } + return this.dateEqual(logicAfter, currentDay) + } + + /** + * 获取日期范围内所有日期 + * @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 + } + + /** + * 获取多选状态 + */ + setMultiple(fullDate) { + let { + before, + after + } = this.multipleStatus + if (!this.range) return + 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.lastHover = false + } 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.lastHover = true + } + } + this._getWeek(fullDate) + } + + /** + * 鼠标 hover 更新多选状态 + */ + setHoverMultiple(fullDate) { + let { + before, + after + } = this.multipleStatus + + if (!this.range) return + if (this.lastHover) return + + 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) + } + + /** + * 更新默认值多选状态 + */ + setDefaultMultiple(before, after) { + this.multipleStatus.before = before + this.multipleStatus.after = after + if (before && after) { + if (this.dateCompare(before, after)) { + this.multipleStatus.data = this.geDateAll(before, after); + this._getWeek(after) + } else { + this.multipleStatus.data = this.geDateAll(after, before); + this._getWeek(before) + } + } + } + + /** + * 获取每周数据 + * @param {Object} dateData + */ + _getWeek(dateData) { + const { + fullDate, + year, + month, + date, + day + } = 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/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/package.json new file mode 100644 index 000000000..60fa1d028 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/package.json @@ -0,0 +1,90 @@ +{ + "id": "uni-datetime-picker", + "displayName": "uni-datetime-picker 日期选择器", + "version": "2.2.6", + "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": { + "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" + } + } + } + } +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-datetime-picker/readme.md new file mode 100644 index 000000000..162fbefaa --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-drawer/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-drawer/changelog.md new file mode 100644 index 000000000..6d2488c32 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-drawer/components/uni-drawer/keypress.js b/yudao-ui-admin-uniapp/uni_modules/uni-drawer/components/uni-drawer/keypress.js new file mode 100644 index 000000000..62dda461b --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue b/yudao-ui-admin-uniapp/uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue new file mode 100644 index 000000000..82331a81b --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue @@ -0,0 +1,183 @@ +<template> + <view v-if="visibleSync" :class="{ 'uni-drawer--visible': showDrawer }" class="uni-drawer" @touchmove.stop.prevent="clear"> + <view class="uni-drawer__mask" :class="{ 'uni-drawer__mask--visible': showDrawer && mask }" @tap="close('mask')" /> + <view class="uni-drawer__content" :class="{'uni-drawer--right': rightMode,'uni-drawer--left': !rightMode, 'uni-drawer__content--visible': showDrawer}" :style="{width:drawerWidth+'px'}"> + <slot /> + </view> + <!-- #ifdef H5 --> + <keypress @esc="close('mask')" /> + <!-- #endif --> + </view> +</template> + +<script> + // #ifdef H5 + import keypress from './keypress.js' + // #endif + /** + * Drawer 抽屉 + * @description 抽屉侧滑菜单 + * @tutorial https://ext.dcloud.net.cn/plugin?id=26 + * @property {Boolean} mask = [true | false] 是否显示遮罩 + * @property {Boolean} maskClick = [true | false] 点击遮罩是否关闭 + * @property {Boolean} mode = [left | right] Drawer 滑出位置 + * @value left 从左侧滑出 + * @value right 从右侧侧滑出 + * @property {Number} width 抽屉的宽度 ,仅 vue 页面生效 + * @event {Function} close 组件关闭时触发事件 + */ + export default { + name: 'UniDrawer', + components: { + // #ifdef H5 + keypress + // #endif + }, + emits:['change'], + props: { + /** + * 显示模式(左、右),只在初始化生效 + */ + mode: { + type: String, + default: '' + }, + /** + * 蒙层显示状态 + */ + mask: { + type: Boolean, + default: true + }, + /** + * 遮罩是否可点击关闭 + */ + maskClick:{ + type: Boolean, + default: true + }, + /** + * 抽屉宽度 + */ + width: { + type: Number, + default: 220 + } + }, + data() { + return { + visibleSync: false, + showDrawer: false, + rightMode: false, + watchTimer: null, + drawerWidth: 220 + } + }, + created() { + // #ifndef APP-NVUE + this.drawerWidth = this.width + // #endif + this.rightMode = this.mode === 'right' + }, + methods: { + clear(){}, + close(type) { + // fixed by mehaotian 抽屉尚未完全关闭或遮罩禁止点击时不触发以下逻辑 + if((type === 'mask' && !this.maskClick) || !this.visibleSync) return + this._change('showDrawer', 'visibleSync', false) + }, + open() { + // fixed by mehaotian 处理重复点击打开的事件 + if(this.visibleSync) return + this._change('visibleSync', 'showDrawer', true) + }, + _change(param1, param2, status) { + this[param1] = status + if (this.watchTimer) { + clearTimeout(this.watchTimer) + } + this.watchTimer = setTimeout(() => { + this[param2] = status + this.$emit('change',status) + }, status ? 50 : 300) + } + } + } +</script> + +<style lang="scss" > + $uni-mask: rgba($color: #000000, $alpha: 0.4) ; + // 抽屉宽度 + $drawer-width: 220px; + + .uni-drawer { + /* #ifndef APP-NVUE */ + display: block; + /* #endif */ + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + overflow: hidden; + z-index: 999; + } + + .uni-drawer__content { + /* #ifndef APP-NVUE */ + display: block; + /* #endif */ + position: absolute; + top: 0; + width: $drawer-width; + bottom: 0; + background-color: $uni-bg-color; + transition: transform 0.3s ease; + } + + .uni-drawer--left { + left: 0; + /* #ifdef APP-NVUE */ + transform: translateX(-$drawer-width); + /* #endif */ + /* #ifndef APP-NVUE */ + transform: translateX(-100%); + /* #endif */ + } + + .uni-drawer--right { + right: 0; + /* #ifdef APP-NVUE */ + transform: translateX($drawer-width); + /* #endif */ + /* #ifndef APP-NVUE */ + transform: translateX(100%); + /* #endif */ + } + + .uni-drawer__content--visible { + transform: translateX(0px); + } + + + .uni-drawer__mask { + /* #ifndef APP-NVUE */ + display: block; + /* #endif */ + opacity: 0; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + background-color: $uni-mask; + transition: opacity 0.3s; + } + + .uni-drawer__mask--visible { + /* #ifndef APP-NVUE */ + display: block; + /* #endif */ + opacity: 1; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-drawer/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-drawer/package.json new file mode 100644 index 000000000..dd056e4c6 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-drawer/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-drawer/readme.md new file mode 100644 index 000000000..dcf6e6b2e --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-easyinput/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-easyinput/changelog.md new file mode 100644 index 000000000..1e8c6f91b --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-easyinput/changelog.md @@ -0,0 +1,47 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-easyinput/components/uni-easyinput/common.js b/yudao-ui-admin-uniapp/uni_modules/uni-easyinput/components/uni-easyinput/common.js new file mode 100644 index 000000000..df9abe1da --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-easyinput/components/uni-easyinput/common.js @@ -0,0 +1,56 @@ +/** + * @desc 函数防抖 + * @param func 目标函数 + * @param wait 延迟执行毫秒数 + * @param immediate true - 立即执行, false - 延迟执行 + */ +export const debounce = function(func, wait = 1000, immediate = true) { + let timer; + console.log(1); + return function() { + console.log(123); + 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/yudao-ui-admin-uniapp/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue b/yudao-ui-admin-uniapp/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue new file mode 100644 index 000000000..5818d7fa4 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue @@ -0,0 +1,593 @@ +<template> + <view class="uni-easyinput" :class="{'uni-easyinput-error':msg}" :style="boxStyle"> + <view class="uni-easyinput__content" :class="inputContentClass" :style="inputContentStyle"> + <uni-icons v-if="prefixIcon" class="content-clear-icon" :type="prefixIcon" color="#c0c4cc" + @click="onClickIcon('prefix')" size="22"></uni-icons> + <textarea v-if="type === 'textarea'" class="uni-easyinput__content-textarea" + :class="{'input-padding':inputBorder}" :name="name" :value="val" :placeholder="placeholder" + :placeholderStyle="placeholderStyle" :disabled="disabled" + placeholder-class="uni-easyinput__placeholder-class" :maxlength="inputMaxlength" :focus="focused" + :autoHeight="autoHeight" @input="onInput" @blur="_Blur" @focus="_Focus" @confirm="onConfirm"></textarea> + <input v-else :type="type === 'password'?'text':type" class="uni-easyinput__content-input" + :style="inputStyle" :name="name" :value="val" :password="!showPassword && type === 'password'" + :placeholder="placeholder" :placeholderStyle="placeholderStyle" + placeholder-class="uni-easyinput__placeholder-class" :disabled="disabled" :maxlength="inputMaxlength" + :focus="focused" :confirmType="confirmType" @focus="_Focus" @blur="_Blur" @input="onInput" + @confirm="onConfirm" /> + <template v-if="type === 'password' && passwordIcon"> + <!-- 开启密码时显示小眼睛 --> + <uni-icons v-if="isVal" class="content-clear-icon" :class="{'is-textarea-icon':type==='textarea'}" + :type="showPassword?'eye-slash-filled':'eye-filled'" :size="22" + :color="focusShow?'#2979ff':'#c0c4cc'" @click="onEyes"> + </uni-icons> + </template> + <template v-else-if="suffixIcon"> + <uni-icons v-if="suffixIcon" class="content-clear-icon" :type="suffixIcon" color="#c0c4cc" + @click="onClickIcon('suffix')" size="22"></uni-icons> + </template> + <template v-else> + <uni-icons v-if="clearable && isVal && !disabled && type !== 'textarea'" class="content-clear-icon" + :class="{'is-textarea-icon':type==='textarea'}" type="clear" :size="clearSize" + :color="msg?'#dd524d':(focusShow?'#2979ff':'#c0c4cc')" @click="onClear"></uni-icons> + </template> + <slot name="right"></slot> + </view> + </view> +</template> + +<script> + /** + * Easyinput 输入框 + * @description 此组件可以实现表单的输入与校验,包括 "text" 和 "textarea" 类型。 + * @tutorial https://ext.dcloud.net.cn/plugin?id=3455 + * @property {String} value 输入内容 + * @property {String } type 输入框的类型(默认text) password/text/textarea/.. + * @value text 文本输入键盘 + * @value textarea 多行文本输入键盘 + * @value password 密码输入键盘 + * @value number 数字输入键盘,注意iOS上app-vue弹出的数字键盘并非9宫格方式 + * @value idcard 身份证输入键盘,信、支付宝、百度、QQ小程序 + * @value digit 带小数点的数字键盘 ,App的nvue页面、微信、支付宝、百度、头条、QQ小程序支持 + * @property {Boolean} clearable 是否显示右侧清空内容的图标控件,点击可清空输入框内容(默认true) + * @property {Boolean} autoHeight 是否自动增高输入区域,type为textarea时有效(默认true) + * @property {String } placeholder 输入框的提示文字 + * @property {String } placeholderStyle placeholder的样式(内联样式,字符串),如"color: #ddd" + * @property {Boolean} focus 是否自动获得焦点(默认false) + * @property {Boolean} disabled 是否禁用(默认false) + * @property {Number } maxlength 最大输入长度,设置为 -1 的时候不限制最大长度(默认140) + * @property {String } confirmType 设置键盘右下角按钮的文字,仅在type="text"时生效(默认done) + * @property {Number } clearSize 清除图标的大小,单位px(默认15) + * @property {String} prefixIcon 输入框头部图标 + * @property {String} suffixIcon 输入框尾部图标 + * @property {Boolean} trim 是否自动去除两端的空格 + * @value both 去除两端空格 + * @value left 去除左侧空格 + * @value right 去除右侧空格 + * @value start 去除左侧空格 + * @value end 去除右侧空格 + * @value all 去除全部空格 + * @value none 不去除空格 + * @property {Boolean} inputBorder 是否显示input输入框的边框(默认true) + * @property {Boolean} passwordIcon type=password时是否显示小眼睛图标 + * @property {Object} styles 自定义颜色 + * @event {Function} input 输入框内容发生变化时触发 + * @event {Function} focus 输入框获得焦点时触发 + * @event {Function} blur 输入框失去焦点时触发 + * @event {Function} confirm 点击完成按钮时触发 + * @event {Function} iconClick 点击图标时触发 + * @example <uni-easyinput v-model="mobile"></uni-easyinput> + */ + function obj2strClass(obj) { + let classess = '' + for (let key in obj) { + const val = obj[key] + if (val) { + classess += `${key} ` + } + } + return classess + } + + function obj2strStyle(obj) { + let style = '' + for (let key in obj) { + const val = obj[key] + style += `${key}:${val};` + } + return style + } + export default { + name: 'uni-easyinput', + emits: ['click', 'iconClick', 'update:modelValue', 'input', 'focus', 'blur', 'confirm', 'clear', 'eyes', 'change'], + model: { + prop: 'modelValue', + event: 'update:modelValue' + }, + options: { + virtualHost: true + }, + inject: { + form: { + from: 'uniForm', + default: null + }, + formItem: { + from: 'uniFormItem', + default: null + }, + }, + props: { + name: String, + value: [Number, String], + modelValue: [Number, String], + type: { + type: String, + default: 'text' + }, + clearable: { + type: Boolean, + default: true + }, + autoHeight: { + type: Boolean, + default: false + }, + placeholder: { + type: String, + default: ' ' + }, + placeholderStyle: String, + focus: { + type: Boolean, + default: false + }, + disabled: { + type: Boolean, + default: false + }, + maxlength: { + type: [Number, String], + default: 140 + }, + confirmType: { + type: String, + default: 'done' + }, + clearSize: { + type: [Number, String], + default: 24 + }, + inputBorder: { + type: Boolean, + default: true + }, + prefixIcon: { + type: String, + default: '' + }, + suffixIcon: { + type: String, + default: '' + }, + trim: { + type: [Boolean, String], + default: true + }, + passwordIcon: { + type: Boolean, + default: true + }, + styles: { + type: Object, + default () { + return { + color: '#333', + disableColor: '#F7F6F6', + borderColor: '#e5e5e5' + } + } + }, + errorMessage: { + type: [String, Boolean], + default: '' + } + }, + data() { + return { + focused: false, + val: '', + showMsg: '', + border: false, + isFirstBorder: false, + showClearIcon: false, + showPassword: false, + focusShow: false, + localMsg: '' + }; + }, + computed: { + // 输入框内是否有值 + isVal() { + const val = this.val + // fixed by mehaotian 处理值为0的情况,字符串0不在处理范围 + if (val || val === 0) { + return true + } + return false + }, + + msg() { + // console.log('computed', this.form, this.formItem); + // if (this.form) { + // return this.errorMessage || this.formItem.errMsg; + // } + // TODO 处理头条 formItem 中 errMsg 不更新的问题 + return this.localMsg || this.errorMessage + }, + // 因为uniapp的input组件的maxlength组件必须要数值,这里转为数值,用户可以传入字符串数值 + inputMaxlength() { + return Number(this.maxlength); + }, + + // 处理外层样式的style + boxStyle() { + return `color:${this.inputBorder && this.msg?'#e43d33':this.styles.color};` + }, + // input 内容的类和样式处理 + inputContentClass() { + return obj2strClass({ + 'is-input-border': this.inputBorder, + 'is-input-error-border': this.inputBorder && this.msg, + 'is-textarea': this.type === 'textarea', + 'is-disabled': this.disabled + }) + }, + inputContentStyle() { + const focusColor = this.focusShow ? '#2979ff' : this.styles.borderColor + const borderColor = this.inputBorder && this.msg ? '#dd524d' : focusColor + return obj2strStyle({ + 'border-color': borderColor || '#e5e5e5', + 'background-color': this.disabled ? this.styles.disableColor : '#fff' + }) + }, + // input右侧样式 + inputStyle() { + const paddingRight = this.type === 'password' || this.clearable || this.prefixIcon ? '' : '10px' + return obj2strStyle({ + 'padding-right': paddingRight, + 'padding-left': this.prefixIcon ? '' : '10px' + }) + } + }, + watch: { + value(newVal) { + this.val = newVal + }, + modelValue(newVal) { + this.val = newVal + }, + focus(newVal) { + this.$nextTick(() => { + this.focused = this.focus + this.focusShow = this.focus + }) + } + }, + created() { + this.init() + // TODO 处理头条vue3 computed 不监听 inject 更改的问题(formItem.errMsg) + if (this.form && this.formItem) { + this.$watch('formItem.errMsg', (newVal) => { + this.localMsg = newVal + }) + } + }, + mounted() { + this.$nextTick(() => { + this.focused = this.focus + this.focusShow = this.focus + }) + }, + methods: { + /** + * 初始化变量值 + */ + init() { + if (this.value || this.value === 0) { + this.val = this.value + } else if (this.modelValue || this.modelValue === 0) { + this.val = this.modelValue + } else { + this.val = null + } + }, + + /** + * 点击图标时触发 + * @param {Object} type + */ + onClickIcon(type) { + this.$emit('iconClick', type) + }, + + /** + * 显示隐藏内容,密码框时生效 + */ + onEyes() { + this.showPassword = !this.showPassword + this.$emit('eyes', this.showPassword) + }, + + /** + * 输入时触发 + * @param {Object} event + */ + onInput(event) { + let value = event.detail.value; + // 判断是否去除空格 + if (this.trim) { + if (typeof(this.trim) === 'boolean' && this.trim) { + value = this.trimStr(value) + } + if (typeof(this.trim) === 'string') { + value = this.trimStr(value, this.trim) + } + }; + if (this.errMsg) this.errMsg = '' + this.val = value + // TODO 兼容 vue2 + this.$emit('input', value); + // TODO 兼容 vue3 + this.$emit('update:modelValue', value) + }, + + /** + * 外部调用方法 + * 获取焦点时触发 + * @param {Object} event + */ + onFocus() { + this.$nextTick(() => { + this.focused = true + }) + this.$emit('focus', null); + }, + + _Focus(event) { + this.focusShow = true + this.$emit('focus', event); + }, + + /** + * 外部调用方法 + * 失去焦点时触发 + * @param {Object} event + */ + onBlur() { + this.focused = false + this.$emit('focus', null); + }, + _Blur(event) { + let value = event.detail.value; + this.focusShow = false + this.$emit('blur', event); + // 根据类型返回值,在event中获取的值理论上讲都是string + this.$emit('change', this.val) + // 失去焦点时参与表单校验 + if (this.form && this.formItem) { + const { + validateTrigger + } = this.form + if (validateTrigger === 'blur') { + this.formItem.onFieldChange() + } + } + }, + + /** + * 按下键盘的发送键 + * @param {Object} e + */ + onConfirm(e) { + this.$emit('confirm', this.val); + this.$emit('change', this.val) + }, + + /** + * 清理内容 + * @param {Object} event + */ + onClear(event) { + this.val = ''; + // TODO 兼容 vue2 + this.$emit('input', ''); + // TODO 兼容 vue2 + // TODO 兼容 vue3 + this.$emit('update:modelValue', '') + // 点击叉号触发 + this.$emit('clear') + }, + + /** + * 去除空格 + */ + trimStr(str, pos = 'both') { + if (pos === 'both') { + return str.trim(); + } else if (pos === 'left') { + return str.trimLeft(); + } else if (pos === 'right') { + return str.trimRight(); + } else if (pos === 'start') { + return str.trimStart() + } else if (pos === 'end') { + return str.trimEnd() + } else if (pos === 'all') { + return str.replace(/\s+/g, ''); + } else if (pos === 'none') { + return str; + } + return str; + } + } + }; +</script> + +<style lang="scss"> + $uni-error: #e43d33; + $uni-border-1: #DCDFE6 !default; + + .uni-easyinput { + /* #ifndef APP-NVUE */ + width: 100%; + /* #endif */ + flex: 1; + position: relative; + text-align: left; + color: #333; + font-size: 14px; + } + + .uni-easyinput__content { + flex: 1; + /* #ifndef APP-NVUE */ + width: 100%; + display: flex; + box-sizing: border-box; + // min-height: 36px; + /* #endif */ + flex-direction: row; + align-items: center; + // 处理border动画刚开始显示黑色的问题 + border-color: #fff; + transition-property: border-color; + transition-duration: 0.3s; + } + + .uni-easyinput__content-input { + /* #ifndef APP-NVUE */ + width: auto; + /* #endif */ + position: relative; + overflow: hidden; + flex: 1; + line-height: 1; + font-size: 14px; + height: 35px; + // min-height: 36px; + } + + .uni-easyinput__placeholder-class { + color: #999; + font-size: 12px; + // font-weight: 200; + } + + .is-textarea { + align-items: flex-start; + } + + .is-textarea-icon { + margin-top: 5px; + } + + .uni-easyinput__content-textarea { + position: relative; + overflow: hidden; + flex: 1; + line-height: 1.5; + font-size: 14px; + margin: 6px; + margin-left: 0; + height: 80px; + min-height: 80px; + /* #ifndef APP-NVUE */ + min-height: 80px; + width: auto; + /* #endif */ + } + + .input-padding { + padding-left: 10px; + } + + .content-clear-icon { + padding: 0 5px; + } + + .label-icon { + margin-right: 5px; + margin-top: -1px; + } + + // 显示边框 + .is-input-border { + /* #ifndef APP-NVUE */ + display: flex; + box-sizing: border-box; + /* #endif */ + flex-direction: row; + align-items: center; + border: 1px solid $uni-border-1; + border-radius: 4px; + /* #ifdef MP-ALIPAY */ + overflow: hidden; + /* #endif */ + } + + .uni-error-message { + position: absolute; + bottom: -17px; + left: 0; + line-height: 12px; + color: $uni-error; + font-size: 12px; + text-align: left; + } + + .uni-error-msg--boeder { + position: relative; + bottom: 0; + line-height: 22px; + } + + .is-input-error-border { + border-color: $uni-error; + + .uni-easyinput__placeholder-class { + color: mix(#fff, $uni-error, 50%); + ; + } + } + + + .uni-easyinput--border { + margin-bottom: 0; + padding: 10px 15px; + // padding-bottom: 0; + border-top: 1px #eee solid; + } + + .uni-easyinput-error { + padding-bottom: 0; + } + + .is-first-border { + /* #ifndef APP-NVUE */ + border: none; + /* #endif */ + /* #ifdef APP-NVUE */ + border-width: 0; + /* #endif */ + } + + .is-disabled { + background-color: #F7F6F6; + color: #D5D5D5; + + .uni-easyinput__placeholder-class { + color: #D5D5D5; + font-size: 12px; + } + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-easyinput/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-easyinput/package.json new file mode 100644 index 000000000..3cc793e61 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-easyinput/package.json @@ -0,0 +1,90 @@ +{ + "id": "uni-easyinput", + "displayName": "uni-easyinput 增强输入框", + "version": "1.1.0", + "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": { + "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/yudao-ui-admin-uniapp/uni_modules/uni-easyinput/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-easyinput/readme.md new file mode 100644 index 000000000..f1faf8fbb --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-fab/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-fab/changelog.md new file mode 100644 index 000000000..24e26b167 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-fab/changelog.md @@ -0,0 +1,17 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-fab/components/uni-fab/uni-fab.vue b/yudao-ui-admin-uniapp/uni_modules/uni-fab/components/uni-fab/uni-fab.vue new file mode 100644 index 000000000..bef97f117 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-fab/components/uni-fab/uni-fab.vue @@ -0,0 +1,475 @@ +<template> + <view class="uni-cursor-point"> + <view v-if="popMenu && (leftBottom||rightBottom||leftTop||rightTop) && content.length > 0" :class="{ + 'uni-fab--leftBottom': leftBottom, + 'uni-fab--rightBottom': rightBottom, + 'uni-fab--leftTop': leftTop, + 'uni-fab--rightTop': rightTop + }" class="uni-fab"> + <view :class="{ + 'uni-fab__content--left': horizontal === 'left', + 'uni-fab__content--right': horizontal === 'right', + 'uni-fab__content--flexDirection': direction === 'vertical', + 'uni-fab__content--flexDirectionStart': flexDirectionStart, + 'uni-fab__content--flexDirectionEnd': flexDirectionEnd, + 'uni-fab__content--other-platform': !isAndroidNvue + }" :style="{ width: boxWidth, height: boxHeight, backgroundColor: styles.backgroundColor }" + class="uni-fab__content" elevation="5"> + <view v-if="flexDirectionStart || horizontalLeft" class="uni-fab__item uni-fab__item--first" /> + <view v-for="(item, index) in content" :key="index" :class="{ 'uni-fab__item--active': isShow }" + class="uni-fab__item" @click="_onItemClick(index, item)"> + <image :src="item.active ? item.selectedIconPath : item.iconPath" class="uni-fab__item-image" + mode="aspectFit" /> + <text class="uni-fab__item-text" + :style="{ color: item.active ? styles.selectedColor : styles.color }">{{ item.text }}</text> + </view> + <view v-if="flexDirectionEnd || horizontalRight" class="uni-fab__item uni-fab__item--first" /> + </view> + </view> + <view :class="{ + 'uni-fab__circle--leftBottom': leftBottom, + 'uni-fab__circle--rightBottom': rightBottom, + 'uni-fab__circle--leftTop': leftTop, + 'uni-fab__circle--rightTop': rightTop, + 'uni-fab__content--other-platform': !isAndroidNvue + }" class="uni-fab__circle uni-fab__plus" :style="{ 'background-color': styles.buttonColor }" @click="_onClick"> + <uni-icons class="fab-circle-icon" type="plusempty" :color="styles.iconColor" size="32" + :class="{'uni-fab__plus--active': isShow && content.length > 0}"></uni-icons> + <!-- <view class="fab-circle-v" :class="{'uni-fab__plus--active': isShow && content.length > 0}"></view> + <view class="fab-circle-h" :class="{'uni-fab__plus--active': isShow && content.length > 0}"></view> --> + </view> + </view> +</template> + +<script> + let platform = 'other' + // #ifdef APP-NVUE + platform = uni.getSystemInfoSync().platform + // #endif + + /** + * Fab 悬浮按钮 + * @description 点击可展开一个图形按钮菜单 + * @tutorial https://ext.dcloud.net.cn/plugin?id=144 + * @property {Object} pattern 可选样式配置项 + * @property {Object} horizontal = [left | right] 水平对齐方式 + * @value left 左对齐 + * @value right 右对齐 + * @property {Object} vertical = [bottom | top] 垂直对齐方式 + * @value bottom 下对齐 + * @value top 上对齐 + * @property {Object} direction = [horizontal | vertical] 展开菜单显示方式 + * @value horizontal 水平显示 + * @value vertical 垂直显示 + * @property {Array} content 展开菜单内容配置项 + * @property {Boolean} popMenu 是否使用弹出菜单 + * @event {Function} trigger 展开菜单点击事件,返回点击信息 + * @event {Function} fabClick 悬浮按钮点击事件 + */ + export default { + name: 'UniFab', + emits: ['fabClick', 'trigger'], + props: { + pattern: { + type: Object, + default () { + return {} + } + }, + horizontal: { + type: String, + default: 'left' + }, + vertical: { + type: String, + default: 'bottom' + }, + direction: { + type: String, + default: 'horizontal' + }, + content: { + type: Array, + default () { + return [] + } + }, + show: { + type: Boolean, + default: false + }, + popMenu: { + type: Boolean, + default: true + } + }, + data() { + return { + fabShow: false, + isShow: false, + isAndroidNvue: platform === 'android', + styles: { + color: '#3c3e49', + selectedColor: '#007AFF', + backgroundColor: '#fff', + buttonColor: '#007AFF', + iconColor: '#fff' + } + } + }, + computed: { + contentWidth(e) { + return (this.content.length + 1) * 55 + 15 + 'px' + }, + contentWidthMin() { + return '55px' + }, + // 动态计算宽度 + boxWidth() { + return this.getPosition(3, 'horizontal') + }, + // 动态计算高度 + boxHeight() { + return this.getPosition(3, 'vertical') + }, + // 计算左下位置 + leftBottom() { + return this.getPosition(0, 'left', 'bottom') + }, + // 计算右下位置 + rightBottom() { + return this.getPosition(0, 'right', 'bottom') + }, + // 计算左上位置 + leftTop() { + return this.getPosition(0, 'left', 'top') + }, + rightTop() { + return this.getPosition(0, 'right', 'top') + }, + flexDirectionStart() { + return this.getPosition(1, 'vertical', 'top') + }, + flexDirectionEnd() { + return this.getPosition(1, 'vertical', 'bottom') + }, + horizontalLeft() { + return this.getPosition(2, 'horizontal', 'left') + }, + horizontalRight() { + return this.getPosition(2, 'horizontal', 'right') + } + }, + watch: { + pattern: { + handler(val, oldVal) { + this.styles = Object.assign({}, this.styles, val) + }, + deep: true + } + }, + created() { + this.isShow = this.show + if (this.top === 0) { + this.fabShow = true + } + // 初始化样式 + this.styles = Object.assign({}, this.styles, this.pattern) + }, + methods: { + _onClick() { + this.$emit('fabClick') + if (!this.popMenu) { + return + } + this.isShow = !this.isShow + }, + open() { + this.isShow = true + }, + close() { + this.isShow = false + }, + /** + * 按钮点击事件 + */ + _onItemClick(index, item) { + this.$emit('trigger', { + index, + item + }) + }, + /** + * 获取 位置信息 + */ + getPosition(types, paramA, paramB) { + if (types === 0) { + return this.horizontal === paramA && this.vertical === paramB + } else if (types === 1) { + return this.direction === paramA && this.vertical === paramB + } else if (types === 2) { + return this.direction === paramA && this.horizontal === paramB + } else { + return this.isShow && this.direction === paramA ? this.contentWidth : this.contentWidthMin + } + } + } + } +</script> + +<style lang="scss" > + $uni-shadow-base:0 1px 5px 2px rgba($color: #000000, $alpha: 0.3) !default; + + .uni-fab { + position: fixed; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + justify-content: center; + align-items: center; + z-index: 10; + border-radius: 45px; + box-shadow: $uni-shadow-base; + } + + .uni-cursor-point { + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + + .uni-fab--active { + opacity: 1; + } + + .uni-fab--leftBottom { + left: 15px; + bottom: 30px; + /* #ifdef H5 */ + left: calc(15px + var(--window-left)); + bottom: calc(30px + var(--window-bottom)); + /* #endif */ + // padding: 10px; + } + + .uni-fab--leftTop { + left: 15px; + top: 30px; + /* #ifdef H5 */ + left: calc(15px + var(--window-left)); + top: calc(30px + var(--window-top)); + /* #endif */ + // padding: 10px; + } + + .uni-fab--rightBottom { + right: 15px; + bottom: 30px; + /* #ifdef H5 */ + right: calc(15px + var(--window-right)); + bottom: calc(30px + var(--window-bottom)); + /* #endif */ + // padding: 10px; + } + + .uni-fab--rightTop { + right: 15px; + top: 30px; + /* #ifdef H5 */ + right: calc(15px + var(--window-right)); + top: calc(30px + var(--window-top)); + /* #endif */ + // padding: 10px; + } + + .uni-fab__circle { + position: fixed; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + justify-content: center; + align-items: center; + width: 55px; + height: 55px; + background-color: #3c3e49; + border-radius: 45px; + z-index: 11; + // box-shadow: $uni-shadow-base; + } + + .uni-fab__circle--leftBottom { + left: 15px; + bottom: 30px; + /* #ifdef H5 */ + left: calc(15px + var(--window-left)); + bottom: calc(30px + var(--window-bottom)); + /* #endif */ + } + + .uni-fab__circle--leftTop { + left: 15px; + top: 30px; + /* #ifdef H5 */ + left: calc(15px + var(--window-left)); + top: calc(30px + var(--window-top)); + /* #endif */ + } + + .uni-fab__circle--rightBottom { + right: 15px; + bottom: 30px; + /* #ifdef H5 */ + right: calc(15px + var(--window-right)); + bottom: calc(30px + var(--window-bottom)); + /* #endif */ + } + + .uni-fab__circle--rightTop { + right: 15px; + top: 30px; + /* #ifdef H5 */ + right: calc(15px + var(--window-right)); + top: calc(30px + var(--window-top)); + /* #endif */ + } + + .uni-fab__circle--left { + left: 0; + } + + .uni-fab__circle--right { + right: 0; + } + + .uni-fab__circle--top { + top: 0; + } + + .uni-fab__circle--bottom { + bottom: 0; + } + + .uni-fab__plus { + font-weight: bold; + } + + // .fab-circle-v { + // position: absolute; + // width: 2px; + // height: 24px; + // left: 0; + // top: 0; + // right: 0; + // bottom: 0; + // /* #ifndef APP-NVUE */ + // margin: auto; + // /* #endif */ + // background-color: white; + // transform: rotate(0deg); + // transition: transform 0.3s; + // } + + // .fab-circle-h { + // position: absolute; + // width: 24px; + // height: 2px; + // left: 0; + // top: 0; + // right: 0; + // bottom: 0; + // /* #ifndef APP-NVUE */ + // margin: auto; + // /* #endif */ + // background-color: white; + // transform: rotate(0deg); + // transition: transform 0.3s; + // } + + .fab-circle-icon { + transform: rotate(0deg); + transition: transform 0.3s; + font-weight: 200; + } + + .uni-fab__plus--active { + transform: rotate(135deg); + } + + .uni-fab__content { + /* #ifndef APP-NVUE */ + box-sizing: border-box; + display: flex; + /* #endif */ + flex-direction: row; + border-radius: 55px; + overflow: hidden; + transition-property: width, height; + transition-duration: 0.2s; + width: 55px; + border-color: #DDDDDD; + border-width: 1rpx; + border-style: solid; + } + + .uni-fab__content--other-platform { + border-width: 0px; + box-shadow: $uni-shadow-base; + } + + .uni-fab__content--left { + justify-content: flex-start; + } + + .uni-fab__content--right { + justify-content: flex-end; + } + + .uni-fab__content--flexDirection { + flex-direction: column; + justify-content: flex-end; + } + + .uni-fab__content--flexDirectionStart { + flex-direction: column; + justify-content: flex-start; + } + + .uni-fab__content--flexDirectionEnd { + flex-direction: column; + justify-content: flex-end; + } + + .uni-fab__item { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + justify-content: center; + align-items: center; + width: 55px; + height: 55px; + opacity: 0; + transition: opacity 0.2s; + } + + .uni-fab__item--active { + opacity: 1; + } + + .uni-fab__item-image { + width: 20px; + height: 20px; + margin-bottom: 4px; + } + + .uni-fab__item-text { + color: #FFFFFF; + font-size: 12px; + line-height: 12px; + margin-top: 2px; + } + + .uni-fab__item--first { + width: 55px; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-fab/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-fab/package.json new file mode 100644 index 000000000..0f27daa58 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-fab/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-fab", + "displayName": "uni-fab 悬浮按钮", + "version": "1.2.2", + "description": "悬浮按钮 fab button ,点击可展开一个图标按钮菜单。", + "keywords": [ + "uni-ui", + "uniui", + "按钮", + "悬浮按钮", + "fab" +], + "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/yudao-ui-admin-uniapp/uni_modules/uni-fab/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-fab/readme.md new file mode 100644 index 000000000..9a444e880 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-fav/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-fav/changelog.md new file mode 100644 index 000000000..d8a08d436 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/i18n/en.json b/yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/i18n/en.json new file mode 100644 index 000000000..9a0759e02 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/i18n/index.js b/yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/i18n/index.js new file mode 100644 index 000000000..de7509c87 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hans.json b/yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hans.json new file mode 100644 index 000000000..67c89bfc7 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hans.json @@ -0,0 +1,4 @@ +{ + "uni-fav.collect": "收藏", + "uni-fav.collected": "已收藏" +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hant.json b/yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hant.json new file mode 100644 index 000000000..67c89bfc7 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hant.json @@ -0,0 +1,4 @@ +{ + "uni-fav.collect": "收藏", + "uni-fav.collected": "已收藏" +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/uni-fav.vue b/yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/uni-fav.vue new file mode 100644 index 000000000..d2c58df9e --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-fav/components/uni-fav/uni-fav.vue @@ -0,0 +1,161 @@ +<template> + <view :class="[circle === true || circle === 'true' ? 'uni-fav--circle' : '']" :style="[{ backgroundColor: checked ? bgColorChecked : bgColor }]" + @click="onClick" class="uni-fav"> + <!-- #ifdef MP-ALIPAY --> + <view class="uni-fav-star" v-if="!checked && (star === true || star === 'true')"> + <uni-icons :color="fgColor" :style="{color: checked ? fgColorChecked : fgColor}" size="14" type="star-filled" /> + </view> + <!-- #endif --> + <!-- #ifndef MP-ALIPAY --> + <uni-icons :color="fgColor" :style="{color: checked ? fgColorChecked : fgColor}" class="uni-fav-star" size="14" type="star-filled" + v-if="!checked && (star === true || star === 'true')" /> + <!-- #endif --> + <text :style="{color: checked ? fgColorChecked : fgColor}" class="uni-fav-text">{{ checked ? contentFav : contentDefault }}</text> + </view> +</template> + +<script> + + /** + * Fav 收藏按钮 + * @description 用于收藏功能,可点击切换选中、不选中的状态 + * @tutorial https://ext.dcloud.net.cn/plugin?id=864 + * @property {Boolean} star = [true|false] 按钮是否带星星 + * @property {String} bgColor 未收藏时的背景色 + * @property {String} bgColorChecked 已收藏时的背景色 + * @property {String} fgColor 未收藏时的文字颜色 + * @property {String} fgColorChecked 已收藏时的文字颜色 + * @property {Boolean} circle = [true|false] 是否为圆角 + * @property {Boolean} checked = [true|false] 是否为已收藏 + * @property {Object} contentText = [true|false] 收藏按钮文字 + * @property {Boolean} stat 是否开启统计功能 + * @event {Function} click 点击 fav按钮触发事件 + * @example <uni-fav :checked="true"/> + */ + + import { + initVueI18n + } from '@dcloudio/uni-i18n' + import messages from './i18n/index.js' + const { t } = initVueI18n(messages) + + export default { + name: "UniFav", + // TODO 兼容 vue3,需要注册事件 + emits: ['click'], + props: { + star: { + type: [Boolean, String], + default: true + }, + bgColor: { + type: String, + default: "#eeeeee" + }, + fgColor: { + type: String, + default: "#666666" + }, + bgColorChecked: { + type: String, + default: "#007aff" + }, + fgColorChecked: { + type: String, + default: "#FFFFFF" + }, + circle: { + type: [Boolean, String], + default: false + }, + checked: { + type: Boolean, + default: false + }, + contentText: { + type: Object, + default () { + return { + contentDefault: "", + contentFav: "" + }; + } + }, + stat:{ + type: Boolean, + default: false + } + }, + computed: { + contentDefault() { + return this.contentText.contentDefault || t("uni-fav.collect") + }, + contentFav() { + return this.contentText.contentFav || t("uni-fav.collected") + }, + }, + watch: { + checked() { + if (uni.report && this.stat) { + if (this.checked) { + uni.report("收藏", "收藏"); + } else { + uni.report("取消收藏", "取消收藏"); + } + } + } + }, + methods: { + onClick() { + this.$emit("click"); + } + } + }; +</script> + +<style lang="scss" > + $fav-height: 25px; + + .uni-fav { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + align-items: center; + justify-content: center; + width: 60px; + height: $fav-height; + line-height: $fav-height; + text-align: center; + border-radius: 3px; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + + .uni-fav--circle { + border-radius: 30px; + } + + .uni-fav-star { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + height: $fav-height; + line-height: 24px; + margin-right: 3px; + align-items: center; + justify-content: center; + } + + .uni-fav-text { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + height: $fav-height; + line-height: $fav-height; + align-items: center; + justify-content: center; + font-size: 12px; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-fav/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-fav/package.json new file mode 100644 index 000000000..cc1469716 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-fav/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-fav/readme.md new file mode 100644 index 000000000..4de125d28 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/changelog.md new file mode 100644 index 000000000..5c8102682 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/changelog.md @@ -0,0 +1,63 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js b/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js new file mode 100644 index 000000000..24a07f578 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js @@ -0,0 +1,224 @@ +'use strict'; + +const ERR_MSG_OK = 'chooseAndUploadFile:ok'; +const ERR_MSG_FAIL = 'chooseAndUploadFile:fail'; + +function chooseImage(opts) { + const { + count, + sizeType = ['original', 'compressed'], + sourceType = ['album', 'camera'], + extension + } = opts + return new Promise((resolve, reject) => { + uni.chooseImage({ + count, + sizeType, + sourceType, + extension, + success(res) { + resolve(normalizeChooseAndUploadFileRes(res, 'image')); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL), + }); + }, + }); + }); +} + +function chooseVideo(opts) { + const { + camera, + compressed, + maxDuration, + sourceType = ['album', 'camera'], + extension + } = opts; + return new Promise((resolve, reject) => { + 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), + }); + }, + }); + }); +} + +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/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue b/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue new file mode 100644 index 000000000..0928a41af --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue @@ -0,0 +1,656 @@ +<template> + <view class="uni-file-picker"> + <view v-if="title" class="uni-file-picker__header"> + <text class="file-title">{{ title }}</text> + <text class="file-count">{{ filesList.length }}/{{ limitLength }}</text> + </view> + <upload-image v-if="fileMediatype === 'image' && showType === 'grid'" :readonly="readonly" + :image-styles="imageStyles" :files-list="filesList" :limit="limitLength" :disablePreview="disablePreview" + :delIcon="delIcon" @uploadFiles="uploadFiles" @choose="choose" @delFile="delFile"> + <slot> + <view class="is-add"> + <view class="icon-add"></view> + <view class="icon-add rotate"></view> + </view> + </slot> + </upload-image> + <upload-file v-if="fileMediatype !== 'image' || showType !== 'grid'" :readonly="readonly" + :list-styles="listStyles" :files-list="filesList" :showType="showType" :delIcon="delIcon" + @uploadFiles="uploadFiles" @choose="choose" @delFile="delFile"> + <slot><button type="primary" size="mini">选择文件</button></slot> + </upload-file> + </view> +</template> + +<script> + import { + chooseAndUploadFile, + uploadCloudFiles + } from './choose-and-upload-file.js' + import { + get_file_ext, + get_extname, + get_files_and_is_max, + get_file_info, + get_file_data + } from './utils.js' + import uploadImage from './upload-image.vue' + import uploadFile from './upload-file.vue' + let fileInput = null + /** + * FilePicker 文件选择上传 + * @description 文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间 + * @tutorial https://ext.dcloud.net.cn/plugin?id=4079 + * @property {Object|Array} value 组件数据,通常用来回显 ,类型由return-type属性决定 + * @property {Boolean} disabled = [true|false] 组件禁用 + * @value true 禁用 + * @value false 取消禁用 + * @property {Boolean} readonly = [true|false] 组件只读,不可选择,不显示进度,不显示删除按钮 + * @value true 只读 + * @value false 取消只读 + * @property {String} return-type = [array|object] 限制 value 格式,当为 object 时 ,组件只能单选,且会覆盖 + * @value array 规定 value 属性的类型为数组 + * @value object 规定 value 属性的类型为对象 + * @property {Boolean} disable-preview = [true|false] 禁用图片预览,仅 mode:grid 时生效 + * @value true 禁用图片预览 + * @value false 取消禁用图片预览 + * @property {Boolean} del-icon = [true|false] 是否显示删除按钮 + * @value true 显示删除按钮 + * @value false 不显示删除按钮 + * @property {Boolean} auto-upload = [true|false] 是否自动上传,值为true则只触发@select,可自行上传 + * @value true 自动上传 + * @value false 取消自动上传 + * @property {Number|String} limit 最大选择个数 ,h5 会自动忽略多选的部分 + * @property {String} title 组件标题,右侧显示上传计数 + * @property {String} mode = [list|grid] 选择文件后的文件列表样式 + * @value list 列表显示 + * @value grid 宫格显示 + * @property {String} file-mediatype = [image|video|all] 选择文件类型 + * @value image 只选择图片 + * @value video 只选择视频 + * @value all 选择所有文件 + * @property {Array} file-extname 选择文件后缀,根据 file-mediatype 属性而不同 + * @property {Object} list-style mode:list 时的样式 + * @property {Object} image-styles 选择文件后缀,根据 file-mediatype 属性而不同 + * @event {Function} select 选择文件后触发 + * @event {Function} progress 文件上传时触发 + * @event {Function} success 上传成功触发 + * @event {Function} fail 上传失败触发 + * @event {Function} delete 文件从列表移除时触发 + */ + export default { + name: 'uniFilePicker', + components: { + uploadImage, + uploadFile + }, + options: { + virtualHost: true + }, + emits: ['select', 'success', 'fail', 'progress', 'delete', 'update:modelValue', 'input'], + props: { + // #ifdef VUE3 + modelValue: { + type: [Array, Object], + default () { + return [] + } + }, + // #endif + + // #ifndef VUE3 + value: { + type: [Array, Object], + default () { + return [] + } + }, + // #endif + + disabled: { + type: Boolean, + default: false + }, + disablePreview: { + type: Boolean, + default: false + }, + delIcon: { + type: Boolean, + default: true + }, + // 自动上传 + autoUpload: { + type: Boolean, + default: true + }, + // 最大选择个数 ,h5只能限制单选或是多选 + limit: { + type: [Number, String], + default: 9 + }, + // 列表样式 grid | list | list-card + mode: { + type: String, + default: 'grid' + }, + // 选择文件类型 image/video/all + fileMediatype: { + type: String, + default: 'image' + }, + // 文件类型筛选 + fileExtname: { + type: [Array, String], + default () { + return [] + } + }, + title: { + type: String, + default: '' + }, + listStyles: { + type: Object, + default () { + return { + // 是否显示边框 + border: true, + // 是否显示分隔线 + dividline: true, + // 线条样式 + borderStyle: {} + } + } + }, + imageStyles: { + type: Object, + default () { + return { + width: 'auto', + height: 'auto' + } + } + }, + readonly: { + type: Boolean, + default: false + }, + returnType: { + type: String, + default: 'array' + }, + sizeType: { + type: Array, + default () { + return ['original', 'compressed'] + } + } + }, + data() { + return { + files: [], + localValue: [] + } + }, + watch: { + // #ifndef VUE3 + value: { + handler(newVal, oldVal) { + this.setValue(newVal, oldVal) + }, + immediate: true + }, + // #endif + // #ifdef VUE3 + modelValue: { + handler(newVal, oldVal) { + this.setValue(newVal, oldVal) + }, + immediate: true + }, + // #endif + }, + computed: { + filesList() { + let files = [] + this.files.forEach(v => { + files.push(v) + }) + return files + }, + showType() { + if (this.fileMediatype === 'image') { + return this.mode + } + return 'list' + }, + limitLength() { + if (this.returnType === 'object') { + return 1 + } + if (!this.limit) { + return 1 + } + if (this.limit >= 9) { + return 9 + } + return this.limit + } + }, + created() { + // TODO 兼容不开通服务空间的情况 + if (!(uniCloud.config && uniCloud.config.provider)) { + this.noSpace = true + uniCloud.chooseAndUploadFile = chooseAndUploadFile + } + this.form = this.getForm('uniForms') + this.formItem = this.getForm('uniFormsItem') + if (this.form && this.formItem) { + if (this.formItem.name) { + this.rename = this.formItem.name + this.form.inputChildrens.push(this) + } + } + }, + methods: { + /** + * 公开用户使用,清空文件 + * @param {Object} index + */ + clearFiles(index) { + if (index !== 0 && !index) { + this.files = [] + this.$nextTick(() => { + this.setEmit() + }) + } else { + this.files.splice(index, 1) + } + this.$nextTick(() => { + this.setEmit() + }) + }, + /** + * 公开用户使用,继续上传 + */ + upload() { + let files = [] + this.files.forEach((v, index) => { + if (v.status === 'ready' || v.status === 'error') { + files.push(Object.assign({}, v)) + } + }) + return this.uploadFiles(files) + }, + async setValue(newVal, oldVal) { + const newData = async (v) => { + const reg = /cloud:\/\/([\w.]+\/?)\S*/ + let url = '' + if(v.fileID){ + url = v.fileID + }else{ + url = v.url + } + if (reg.test(url)) { + v.fileID = url + v.url = await this.getTempFileURL(url) + } + if(v.url) v.path = v.url + return v + } + if (this.returnType === 'object') { + if (newVal) { + await newData(newVal) + } else { + newVal = {} + } + } else { + if (!newVal) newVal = [] + for(let i =0 ;i < newVal.length ;i++){ + let v = newVal[i] + await newData(v) + } + } + this.localValue = newVal + if (this.form && this.formItem &&!this.is_reset) { + this.is_reset = false + this.formItem.setValue(this.localValue) + } + let filesData = Object.keys(newVal).length > 0 ? newVal : []; + this.files = [].concat(filesData) + }, + + /** + * 选择文件 + */ + choose() { + + if (this.disabled) return + if (this.files.length >= Number(this.limitLength) && this.showType !== 'grid' && this.returnType === + 'array') { + uni.showToast({ + title: `您最多选择 ${this.limitLength} 个文件`, + icon: 'none' + }) + return + } + this.chooseFiles() + }, + + /** + * 选择文件并上传 + */ + chooseFiles() { + const _extname = get_extname(this.fileExtname) + // 获取后缀 + uniCloud + .chooseAndUploadFile({ + type: this.fileMediatype, + compressed: false, + sizeType: this.sizeType, + // TODO 如果为空,video 有问题 + extension: _extname.length > 0 ? _extname : undefined, + count: this.limitLength - this.files.length, //默认9 + onChooseFile: this.chooseFileCallback, + onUploadProgress: progressEvent => { + this.setProgress(progressEvent, progressEvent.index) + } + }) + .then(result => { + this.setSuccessAndError(result.tempFiles) + }) + .catch(err => { + console.log('选择失败', err) + }) + }, + + /** + * 选择文件回调 + * @param {Object} res + */ + async chooseFileCallback(res) { + const _extname = get_extname(this.fileExtname) + const is_one = (Number(this.limitLength) === 1 && + this.disablePreview && + !this.disabled) || + this.returnType === 'object' + // 如果这有一个文件 ,需要清空本地缓存数据 + if (is_one) { + this.files = [] + } + + let { + filePaths, + files + } = get_files_and_is_max(res, _extname) + if (!(_extname && _extname.length > 0)) { + filePaths = res.tempFilePaths + files = res.tempFiles + } + + let currentData = [] + for (let i = 0; i < files.length; i++) { + if (this.limitLength - this.files.length <= 0) break + files[i].uuid = Date.now() + let filedata = await get_file_data(files[i], this.fileMediatype) + filedata.progress = 0 + filedata.status = 'ready' + this.files.push(filedata) + currentData.push({ + ...filedata, + file: files[i] + }) + } + this.$emit('select', { + tempFiles: currentData, + tempFilePaths: filePaths + }) + res.tempFiles = files + // 停止自动上传 + if (!this.autoUpload || this.noSpace) { + res.tempFiles = [] + } + }, + + /** + * 批传 + * @param {Object} e + */ + uploadFiles(files) { + files = [].concat(files) + return uploadCloudFiles.call(this, files, 5, res => { + this.setProgress(res, res.index, true) + }) + .then(result => { + this.setSuccessAndError(result) + return result; + }) + .catch(err => { + console.log(err) + }) + }, + + /** + * 成功或失败 + */ + async setSuccessAndError(res, fn) { + let successData = [] + let errorData = [] + let tempFilePath = [] + let errorTempFilePath = [] + for (let i = 0; i < res.length; i++) { + const item = res[i] + const index = item.uuid ? this.files.findIndex(p => p.uuid === item.uuid) : item.index + + if (index === -1 || !this.files) break + if (item.errMsg === 'request:fail') { + this.files[index].url = item.path + this.files[index].status = 'error' + this.files[index].errMsg = item.errMsg + // this.files[index].progress = -1 + errorData.push(this.files[index]) + errorTempFilePath.push(this.files[index].url) + } else { + this.files[index].errMsg = '' + this.files[index].fileID = item.url + const reg = /cloud:\/\/([\w.]+\/?)\S*/ + if (reg.test(item.url)) { + this.files[index].url = await this.getTempFileURL(item.url) + }else{ + this.files[index].url = item.url + } + + this.files[index].status = 'success' + this.files[index].progress += 1 + successData.push(this.files[index]) + tempFilePath.push(this.files[index].fileID) + } + } + + if (successData.length > 0) { + this.setEmit() + // 状态改变返回 + this.$emit('success', { + tempFiles: this.backObject(successData), + tempFilePaths: tempFilePath + }) + } + + if (errorData.length > 0) { + this.$emit('fail', { + tempFiles: this.backObject(errorData), + tempFilePaths: errorTempFilePath + }) + } + }, + + /** + * 获取进度 + * @param {Object} progressEvent + * @param {Object} index + * @param {Object} type + */ + setProgress(progressEvent, index, type) { + const fileLenth = this.files.length + const percentNum = (index / fileLenth) * 100 + const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total) + let idx = index + if (!type) { + idx = this.files.findIndex(p => p.uuid === progressEvent.tempFile.uuid) + } + if (idx === -1 || !this.files[idx]) return + // fix by mehaotian 100 就会消失,-1 是为了让进度条消失 + this.files[idx].progress = percentCompleted - 1 + // 上传中 + this.$emit('progress', { + index: idx, + progress: parseInt(percentCompleted), + tempFile: this.files[idx] + }) + }, + + /** + * 删除文件 + * @param {Object} index + */ + delFile(index) { + this.$emit('delete', { + tempFile: this.files[index], + tempFilePath: this.files[index].url + }) + this.files.splice(index, 1) + this.$nextTick(() => { + this.setEmit() + }) + }, + + /** + * 获取文件名和后缀 + * @param {Object} name + */ + getFileExt(name) { + const last_len = name.lastIndexOf('.') + const len = name.length + return { + name: name.substring(0, last_len), + ext: name.substring(last_len + 1, len) + } + }, + + /** + * 处理返回事件 + */ + setEmit() { + let data = [] + if (this.returnType === 'object') { + data = this.backObject(this.files)[0] + this.localValue = data?data:null + } else { + data = this.backObject(this.files) + if (!this.localValue) { + this.localValue = [] + } + this.localValue = [...data] + } + // #ifdef VUE3 + this.$emit('update:modelValue', this.localValue) + // #endif + // #ifndef VUE3 + this.$emit('input', this.localValue) + // #endif + }, + + /** + * 处理返回参数 + * @param {Object} files + */ + backObject(files) { + let newFilesData = [] + files.forEach(v => { + newFilesData.push({ + extname: v.extname, + fileType: v.fileType, + image: v.image, + name: v.name, + path: v.path, + size: v.size, + fileID:v.fileID, + url: v.url + }) + }) + return newFilesData + }, + async getTempFileURL(fileList) { + fileList = { + fileList: [].concat(fileList) + } + const urls = await uniCloud.getTempFileURL(fileList) + return urls.fileList[0].tempFileURL || '' + }, + /** + * 获取父元素实例 + */ + getForm(name = 'uniForms') { + 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; + } + } + } +</script> + +<style> + .uni-file-picker { + /* #ifndef APP-NVUE */ + box-sizing: border-box; + overflow: hidden; + width: 100%; + /* #endif */ + flex: 1; + } + + .uni-file-picker__header { + padding-top: 5px; + padding-bottom: 10px; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + justify-content: space-between; + } + + .file-title { + font-size: 14px; + color: #333; + } + + .file-count { + font-size: 14px; + color: #999; + } + + .is-add { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + align-items: center; + justify-content: center; + } + + .icon-add { + width: 50px; + height: 5px; + background-color: #f1f1f1; + border-radius: 2px; + } + + .rotate { + position: absolute; + transform: rotate(90deg); + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue b/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue new file mode 100644 index 000000000..625d92ec7 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue @@ -0,0 +1,325 @@ +<template> + <view class="uni-file-picker__files"> + <view v-if="!readonly" class="files-button" @click="choose"> + <slot></slot> + </view> + <!-- :class="{'is-text-box':showType === 'list'}" --> + <view v-if="list.length > 0" class="uni-file-picker__lists is-text-box" :style="borderStyle"> + <!-- ,'is-list-card':showType === 'list-card' --> + + <view class="uni-file-picker__lists-box" v-for="(item ,index) in list" :key="index" :class="{ + 'files-border':index !== 0 && styles.dividline}" + :style="index !== 0 && styles.dividline &&borderLineStyle"> + <view class="uni-file-picker__item"> + <!-- :class="{'is-text-image':showType === 'list'}" --> + <!-- <view class="files__image is-text-image"> + <image class="header-image" :src="item.logo" mode="aspectFit"></image> + </view> --> + <view class="files__name">{{item.name}}</view> + <view v-if="delIcon&&!readonly" class="icon-del-box icon-files" @click="delFile(index)"> + <view class="icon-del icon-files"></view> + <view class="icon-del rotate"></view> + </view> + </view> + <view v-if="(item.progress && item.progress !== 100) ||item.progress===0 " class="file-picker__progress"> + <progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4" + :backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" /> + </view> + <view v-if="item.status === 'error'" class="file-picker__mask" @click.stop="uploadFiles(item,index)"> + 点击重试 + </view> + </view> + + </view> + </view> +</template> + +<script> + export default { + name: "uploadFile", + emits:['uploadFiles','choose','delFile'], + props: { + filesList: { + type: Array, + default () { + return [] + } + }, + delIcon: { + type: Boolean, + default: true + }, + limit: { + type: [Number, String], + default: 9 + }, + showType: { + type: String, + default: '' + }, + listStyles: { + type: Object, + default () { + return { + // 是否显示边框 + border: true, + // 是否显示分隔线 + dividline: true, + // 线条样式 + borderStyle: {} + } + } + }, + readonly:{ + type:Boolean, + default:false + } + }, + computed: { + list() { + let files = [] + this.filesList.forEach(v => { + files.push(v) + }) + return files + }, + styles() { + let styles = { + border: true, + dividline: true, + 'border-style': {} + } + return Object.assign(styles, this.listStyles) + }, + borderStyle() { + let { + borderStyle, + border + } = this.styles + let obj = {} + if (!border) { + obj.border = 'none' + } else { + let width = (borderStyle && borderStyle.width) || 1 + width = this.value2px(width) + let radius = (borderStyle && borderStyle.radius) || 5 + radius = this.value2px(radius) + obj = { + 'border-width': width, + 'border-style': (borderStyle && borderStyle.style) || 'solid', + 'border-color': (borderStyle && borderStyle.color) || '#eee', + 'border-radius': radius + } + } + let classles = '' + for (let i in obj) { + classles += `${i}:${obj[i]};` + } + return classles + }, + borderLineStyle() { + let obj = {} + let { + borderStyle + } = this.styles + if (borderStyle && borderStyle.color) { + obj['border-color'] = borderStyle.color + } + if (borderStyle && borderStyle.width) { + let width = borderStyle && borderStyle.width || 1 + let style = borderStyle && borderStyle.style || 0 + if (typeof width === 'number') { + width += 'px' + } else { + width = width.indexOf('px') ? width : width + 'px' + } + obj['border-width'] = width + + if (typeof style === 'number') { + style += 'px' + } else { + style = style.indexOf('px') ? style : style + 'px' + } + obj['border-top-style'] = style + } + let classles = '' + for (let i in obj) { + classles += `${i}:${obj[i]};` + } + return classles + } + }, + + methods: { + uploadFiles(item, index) { + this.$emit("uploadFiles", { + item, + index + }) + }, + choose() { + this.$emit("choose") + }, + delFile(index) { + this.$emit('delFile', index) + }, + value2px(value) { + if (typeof value === 'number') { + value += 'px' + } else { + value = value.indexOf('px') !== -1 ? value : value + 'px' + } + return value + } + } + } +</script> + +<style lang="scss"> + .uni-file-picker__files { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + justify-content: flex-start; + } + + .files-button { + // border: 1px red solid; + } + + .uni-file-picker__lists { + position: relative; + margin-top: 5px; + overflow: hidden; + } + + .file-picker__mask { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + justify-content: center; + align-items: center; + position: absolute; + right: 0; + top: 0; + bottom: 0; + left: 0; + color: #fff; + font-size: 14px; + background-color: rgba(0, 0, 0, 0.4); + } + + .uni-file-picker__lists-box { + position: relative; + } + + .uni-file-picker__item { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + align-items: center; + padding: 8px 10px; + padding-right: 5px; + padding-left: 10px; + } + + .files-border { + border-top: 1px #eee solid; + } + + .files__name { + flex: 1; + font-size: 14px; + color: #666; + margin-right: 25px; + /* #ifndef APP-NVUE */ + word-break: break-all; + word-wrap: break-word; + /* #endif */ + } + + .icon-files { + /* #ifndef APP-NVUE */ + position: static; + background-color: initial; + /* #endif */ + } + + // .icon-files .icon-del { + // background-color: #333; + // width: 12px; + // height: 1px; + // } + + + .is-list-card { + border: 1px #eee solid; + margin-bottom: 5px; + border-radius: 5px; + box-shadow: 0 0 2px 0px rgba(0, 0, 0, 0.1); + padding: 5px; + } + + .files__image { + width: 40px; + height: 40px; + margin-right: 10px; + } + + .header-image { + width: 100%; + height: 100%; + } + + .is-text-box { + border: 1px #eee solid; + border-radius: 5px; + } + + .is-text-image { + width: 25px; + height: 25px; + margin-left: 5px; + } + + .rotate { + position: absolute; + transform: rotate(90deg); + } + + .icon-del-box { + /* #ifndef APP-NVUE */ + display: flex; + margin: auto 0; + /* #endif */ + align-items: center; + justify-content: center; + position: absolute; + top: 0px; + bottom: 0; + right: 5px; + height: 26px; + width: 26px; + // border-radius: 50%; + // background-color: rgba(0, 0, 0, 0.5); + z-index: 2; + transform: rotate(-45deg); + } + + .icon-del { + width: 15px; + height: 1px; + background-color: #333; + // border-radius: 1px; + } + + /* #ifdef H5 */ + @media all and (min-width: 768px) { + .uni-file-picker__files { + max-width: 375px; + } + } + + /* #endif */ +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue b/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue new file mode 100644 index 000000000..2a29bc231 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue @@ -0,0 +1,292 @@ +<template> + <view class="uni-file-picker__container"> + <view class="file-picker__box" v-for="(item,index) in filesList" :key="index" :style="boxStyle"> + <view class="file-picker__box-content" :style="borderStyle"> + <image class="file-image" :src="item.url" mode="aspectFill" @click.stop="prviewImage(item,index)"></image> + <view v-if="delIcon && !readonly" class="icon-del-box" @click.stop="delFile(index)"> + <view class="icon-del"></view> + <view class="icon-del rotate"></view> + </view> + <view v-if="(item.progress && item.progress !== 100) ||item.progress===0 " class="file-picker__progress"> + <progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4" + :backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" /> + </view> + <view v-if="item.errMsg" class="file-picker__mask" @click.stop="uploadFiles(item,index)"> + 点击重试 + </view> + </view> + </view> + <view v-if="filesList.length < limit && !readonly" class="file-picker__box" :style="boxStyle"> + <view class="file-picker__box-content is-add" :style="borderStyle" @click="choose"> + <slot> + <view class="icon-add"></view> + <view class="icon-add rotate"></view> + </slot> + </view> + </view> + </view> +</template> + +<script> + export default { + name: "uploadImage", + emits:['uploadFiles','choose','delFile'], + props: { + filesList: { + type: Array, + default () { + return [] + } + }, + disabled:{ + type: Boolean, + default: false + }, + disablePreview: { + type: Boolean, + default: false + }, + limit: { + type: [Number, String], + default: 9 + }, + imageStyles: { + type: Object, + default () { + return { + width: 'auto', + height: 'auto', + border: {} + } + } + }, + delIcon: { + type: Boolean, + default: true + }, + readonly:{ + type:Boolean, + default:false + } + }, + computed: { + styles() { + let styles = { + width: 'auto', + height: 'auto', + border: {} + } + return Object.assign(styles, this.imageStyles) + }, + boxStyle() { + const { + width = 'auto', + height = 'auto' + } = this.styles + let obj = {} + if (height === 'auto') { + if (width !== 'auto') { + obj.height = this.value2px(width) + obj['padding-top'] = 0 + } else { + obj.height = 0 + } + } else { + obj.height = this.value2px(height) + obj['padding-top'] = 0 + } + + if (width === 'auto') { + if (height !== 'auto') { + obj.width = this.value2px(height) + } else { + obj.width = '33.3%' + } + } else { + obj.width = this.value2px(width) + } + + let classles = '' + for(let i in obj){ + classles+= `${i}:${obj[i]};` + } + return classles + }, + borderStyle() { + let { + border + } = this.styles + let obj = {} + const widthDefaultValue = 1 + const radiusDefaultValue = 3 + if (typeof border === 'boolean') { + obj.border = border ? '1px #eee solid' : 'none' + } else { + let width = (border && border.width) || widthDefaultValue + width = this.value2px(width) + let radius = (border && border.radius) || radiusDefaultValue + radius = this.value2px(radius) + obj = { + 'border-width': width, + 'border-style': (border && border.style) || 'solid', + 'border-color': (border && border.color) || '#eee', + 'border-radius': radius + } + } + let classles = '' + for(let i in obj){ + classles+= `${i}:${obj[i]};` + } + return classles + } + }, + methods: { + uploadFiles(item, index) { + this.$emit("uploadFiles", item) + }, + choose() { + this.$emit("choose") + }, + delFile(index) { + this.$emit('delFile', index) + }, + prviewImage(img, index) { + let urls = [] + if(Number(this.limit) === 1&&this.disablePreview&&!this.disabled){ + this.$emit("choose") + } + if(this.disablePreview) return + this.filesList.forEach(i => { + urls.push(i.url) + }) + + uni.previewImage({ + urls: urls, + current: index + }); + }, + value2px(value) { + if (typeof value === 'number') { + value += 'px' + } else { + if (value.indexOf('%') === -1) { + value = value.indexOf('px') !== -1 ? value : value + 'px' + } + } + return value + } + } + } +</script> + +<style lang="scss"> + .uni-file-picker__container { + /* #ifndef APP-NVUE */ + display: flex; + box-sizing: border-box; + /* #endif */ + flex-wrap: wrap; + margin: -5px; + } + + .file-picker__box { + position: relative; + // flex: 0 0 33.3%; + width: 33.3%; + height: 0; + padding-top: 33.33%; + /* #ifndef APP-NVUE */ + box-sizing: border-box; + /* #endif */ + } + + .file-picker__box-content { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + margin: 5px; + border: 1px #eee solid; + border-radius: 5px; + overflow: hidden; + } + + .file-picker__progress { + position: absolute; + bottom: 0; + left: 0; + right: 0; + /* border: 1px red solid; */ + z-index: 2; + } + + .file-picker__progress-item { + width: 100%; + } + + .file-picker__mask { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + justify-content: center; + align-items: center; + position: absolute; + right: 0; + top: 0; + bottom: 0; + left: 0; + color: #fff; + font-size: 12px; + background-color: rgba(0, 0, 0, 0.4); + } + + .file-image { + width: 100%; + height: 100%; + } + + .is-add { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + align-items: center; + justify-content: center; + } + + .icon-add { + width: 50px; + height: 5px; + background-color: #f1f1f1; + border-radius: 2px; + } + + .rotate { + position: absolute; + transform: rotate(90deg); + } + + .icon-del-box { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + align-items: center; + justify-content: center; + position: absolute; + top: 3px; + right: 3px; + height: 26px; + width: 26px; + border-radius: 50%; + background-color: rgba(0, 0, 0, 0.5); + z-index: 2; + transform: rotate(-45deg); + } + + .icon-del { + width: 15px; + height: 2px; + background-color: #fff; + border-radius: 2px; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/utils.js b/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/utils.js new file mode 100644 index 000000000..60aaa3e4e --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/components/uni-file-picker/utils.js @@ -0,0 +1,109 @@ +/** + * 获取文件名和后缀 + * @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, + 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/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/package.json new file mode 100644 index 000000000..08bd66ec3 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/package.json @@ -0,0 +1,86 @@ +{ + "id": "uni-file-picker", + "displayName": "uni-file-picker 文件选择上传", + "version": "1.0.2", + "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": "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/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-file-picker/readme.md new file mode 100644 index 000000000..c8399a5e7 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-forms/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-forms/changelog.md new file mode 100644 index 000000000..5a4bb79af --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-forms/changelog.md @@ -0,0 +1,86 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue b/yudao-ui-admin-uniapp/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue new file mode 100644 index 000000000..250ed875c --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue @@ -0,0 +1,627 @@ +<template> + <view class="uni-forms-item" + :class="['is-direction-' + localLabelPos ,border?'uni-forms-item--border':'' ,border && isFirstBorder?'is-first-border':'']"> + <slot name="label"> + <view class="uni-forms-item__label" :class="{'no-label':!label && !isRequired}" + :style="{width:localLabelWidth,justifyContent: localLabelAlign}"> + <text v-if="isRequired" class="is-required">*</text> + <text>{{label}}</text> + </view> + </slot> + <!-- #ifndef APP-NVUE --> + <view class="uni-forms-item__content"> + <slot></slot> + <view class="uni-forms-item__error" :class="{'msg--active':msg}"> + <text>{{msg}}</text> + </view> + </view> + <!-- #endif --> + <!-- #ifdef APP-NVUE --> + <view class="uni-forms-item__nuve-content"> + <view class="uni-forms-item__content"> + <slot></slot> + </view> + <view class="uni-forms-item__error" :class="{'msg--active':msg}"> + <text class="error-text">{{msg}}</text> + </view> + </view> + <!-- #endif --> + </view> +</template> + +<script> + /** + * uni-fomrs-item 表单子组件 + * @description uni-fomrs-item 表单子组件,提供了基础布局已经校验能力 + * @tutorial https://ext.dcloud.net.cn/plugin?id=2773 + * @property {Boolean} required 是否必填,左边显示红色"*"号 + * @property {String } label 输入框左边的文字提示 + * @property {Number } labelWidth label的宽度,单位px(默认65) + * @property {String } labelAlign = [left|center|right] label的文字对齐方式(默认left) + * @value left label 左侧显示 + * @value center label 居中 + * @value right label 右侧对齐 + * @property {String } errorMessage 显示的错误提示内容,如果为空字符串或者false,则不显示错误信息 + * @property {String } name 表单域的属性名,在使用校验规则时必填 + * @property {String } leftIcon 【1.4.0废弃】label左边的图标,限 uni-ui 的图标名称 + * @property {String } iconColor 【1.4.0废弃】左边通过icon配置的图标的颜色(默认#606266) + * @property {String} validateTrigger = [bind|submit|blur] 【1.4.0废弃】校验触发器方式 默认 submit + * @value bind 发生变化时触发 + * @value submit 提交时触发 + * @value blur 失去焦点触发 + * @property {String } labelPosition = [top|left] 【1.4.0废弃】label的文字的位置(默认left) + * @value top 顶部显示 label + * @value left 左侧显示 label + */ + + export default { + name: 'uniFormsItem', + options: { + virtualHost: true + }, + provide() { + return { + uniFormItem: this + } + }, + inject: { + form: { + from: 'uniForm', + default: null + }, + }, + props: { + // 表单校验规则 + rules: { + type: Array, + default () { + return null; + } + }, + // 表单域的属性名,在使用校验规则时必填 + name: { + type: [String, Array], + default: '' + }, + required: { + type: Boolean, + default: false + }, + label: { + type: String, + default: '' + }, + // label的宽度 ,默认 80 + labelWidth: { + type: [String, Number], + default: '' + }, + // label 居中方式,默认 left 取值 left/center/right + labelAlign: { + type: String, + default: '' + }, + // 强制显示错误信息 + errorMessage: { + type: [String, Boolean], + default: '' + }, + // 1.4.0 弃用,统一使用 form 的校验时机 + // validateTrigger: { + // type: String, + // default: '' + // }, + // 1.4.0 弃用,统一使用 form 的label 位置 + // labelPosition: { + // type: String, + // default: '' + // }, + // 1.4.0 以下属性已经废弃,请使用 #label 插槽代替 + leftIcon: String, + iconColor: { + type: String, + default: '#606266' + }, + }, + data() { + return { + errMsg: '', + isRequired: false, + userRules: null, + localLabelAlign: 'left', + localLabelWidth: '65px', + localLabelPos: 'left', + border: false, + isFirstBorder: false, + }; + }, + computed: { + // 处理错误信息 + msg() { + return this.errorMessage || this.errMsg; + } + }, + watch: { + // 规则发生变化通知子组件更新 + 'form.formRules'(val) { + // TODO 处理头条vue3 watch不生效的问题 + // #ifndef MP-TOUTIAO + this.init() + // #endif + }, + 'form.labelWidth'(val) { + // 宽度 + this.localLabelWidth = this._labelWidthUnit(val) + + }, + 'form.labelPosition'(val) { + // 标签位置 + this.localLabelPos = this._labelPosition() + }, + 'form.labelAlign'(val) { + + } + }, + created() { + this.init(true) + if (this.name && this.form) { + // TODO 处理头条vue3 watch不生效的问题 + // #ifdef MP-TOUTIAO + this.$watch('form.formRules', () => { + this.init() + }) + // #endif + + // 监听变化 + this.$watch( + () => { + const val = this.form._getDataValue(this.name, this.form.localData) + return val + }, + (value, oldVal) => { + const isEqual = this.form._isEqual(value, oldVal) + // 简单判断前后值的变化,只有发生变化才会发生校验 + // TODO 如果 oldVal = undefined ,那么大概率是源数据里没有值导致 ,这个情况不哦校验 ,可能不严谨 ,需要在做观察 + // fix by mehaotian 暂时取消 && oldVal !== undefined ,如果formData 中不存在,可能会不校验 + if (!isEqual) { + const val = this.itemSetValue(value) + this.onFieldChange(val, false) + } + }, { + immediate: false + } + ); + } + + }, + // #ifndef VUE3 + destroyed() { + if (this.__isUnmounted) return + this.unInit() + }, + // #endif + // #ifdef VUE3 + unmounted() { + this.__isUnmounted = true + this.unInit() + }, + // #endif + methods: { + /** + * 外部调用方法 + * 设置规则 ,主要用于小程序自定义检验规则 + * @param {Array} rules 规则源数据 + */ + setRules(rules = null) { + this.userRules = rules + this.init(false) + }, + // 兼容老版本表单组件 + setValue() { + // console.log('setValue 方法已经弃用,请使用最新版本的 uni-forms 表单组件以及其他关联组件。'); + }, + /** + * 外部调用方法 + * 校验数据 + * @param {any} value 需要校验的数据 + * @param {boolean} 是否立即校验 + * @return {Array|null} 校验内容 + */ + async onFieldChange(value, formtrigger = true) { + const { + formData, + localData, + errShowType, + validateCheck, + validateTrigger, + _isRequiredField, + _realName + } = this.form + const name = _realName(this.name) + if (!value) { + value = this.form.formData[name] + } + // fixd by mehaotian 不在校验前清空信息,解决闪屏的问题 + // this.errMsg = ''; + + // fix by mehaotian 解决没有检验规则的情况下,抛出错误的问题 + const ruleLen = this.itemRules.rules && this.itemRules.rules.length + if (!this.validator || !ruleLen || ruleLen === 0) return; + + // 检验时机 + // let trigger = this.isTrigger(this.itemRules.validateTrigger, this.validateTrigger, validateTrigger); + const isRequiredField = _isRequiredField(this.itemRules.rules || []); + let result = null; + // 只有等于 bind 时 ,才能开启时实校验 + if (validateTrigger === 'bind' || formtrigger) { + // 校验当前表单项 + result = await this.validator.validateUpdate({ + [name]: value + }, + formData + ); + + // 判断是否必填,非必填,不填不校验,填写才校验 ,暂时只处理 undefined 和空的情况 + if (!isRequiredField && (value === undefined || value === '')) { + result = null; + } + + // 判断错误信息显示类型 + if (result && result.errorMessage) { + if (errShowType === 'undertext') { + // 获取错误信息 + this.errMsg = !result ? '' : result.errorMessage; + } + if (errShowType === 'toast') { + uni.showToast({ + title: result.errorMessage || '校验错误', + icon: 'none' + }); + } + if (errShowType === 'modal') { + uni.showModal({ + title: '提示', + content: result.errorMessage || '校验错误' + }); + } + } else { + this.errMsg = '' + } + // 通知 form 组件更新事件 + validateCheck(result ? result : null) + } else { + this.errMsg = '' + } + return result ? result : null; + }, + /** + * 初始组件数据 + */ + init(type = false) { + const { + validator, + formRules, + childrens, + formData, + localData, + _realName, + labelWidth, + _getDataValue, + _setDataValue + } = this.form || {} + // 对齐方式 + this.localLabelAlign = this._justifyContent() + // 宽度 + this.localLabelWidth = this._labelWidthUnit(labelWidth) + // 标签位置 + this.localLabelPos = this._labelPosition() + this.isRequired = this.required + // 将需要校验的子组件加入form 队列 + this.form && type && childrens.push(this) + + if (!validator || !formRules) return + // 判断第一个 item + if (!this.form.isFirstBorder) { + this.form.isFirstBorder = true; + this.isFirstBorder = true; + } + + // 判断 group 里的第一个 item + if (this.group) { + if (!this.group.isFirstBorder) { + this.group.isFirstBorder = true; + this.isFirstBorder = true; + } + } + this.border = this.form.border; + // 获取子域的真实名称 + const name = _realName(this.name) + const itemRule = this.userRules || this.rules + if (typeof formRules === 'object' && itemRule) { + // 子规则替换父规则 + formRules[name] = { + rules: itemRule + } + validator.updateSchema(formRules); + } + // 注册校验规则 + const itemRules = formRules[name] || {} + this.itemRules = itemRules + // 注册校验函数 + this.validator = validator + // 默认值赋予 + this.itemSetValue(_getDataValue(this.name, localData)) + this.isRequired = this._isRequired() + + }, + unInit() { + if (this.form) { + const { + childrens, + formData, + _realName + } = this.form + childrens.forEach((item, index) => { + if (item === this) { + this.form.childrens.splice(index, 1) + delete formData[_realName(item.name)] + } + }) + } + }, + // 设置item 的值 + itemSetValue(value) { + const name = this.form._realName(this.name) + const rules = this.itemRules.rules || [] + const val = this.form._getValue(name, value, rules) + this.form._setDataValue(name, this.form.formData, val) + return val + }, + + /** + * 移除该表单项的校验结果 + */ + clearValidate() { + this.errMsg = ''; + }, + + // 是否显示星号 + _isRequired() { + if (this.form) { + return this.required || this.form._isRequiredField(this.itemRules.rules || []) + } + return this.required + }, + + // 处理对齐方式 + _justifyContent() { + if (this.form) { + const { + labelAlign + } = this.form + let labelAli = this.labelAlign ? this.labelAlign : labelAlign; + if (labelAli === 'left') return 'flex-start'; + if (labelAli === 'center') return 'center'; + if (labelAli === 'right') return 'flex-end'; + } + return 'flex-start'; + }, + // 处理 label宽度单位 ,继承父元素的值 + _labelWidthUnit(labelWidth) { + + // if (this.form) { + // const { + // labelWidth + // } = this.form + return this.num2px(this.labelWidth ? this.labelWidth : (labelWidth || (this.label ? 65 : 'auto'))) + // } + // return '65px' + }, + // 处理 label 位置 + _labelPosition() { + if (this.form) return this.form.labelPosition || 'left' + return 'left' + + }, + + /** + * 触发时机 + * @param {Object} rule 当前规则内时机 + * @param {Object} itemRlue 当前组件时机 + * @param {Object} parentRule 父组件时机 + */ + isTrigger(rule, itemRlue, parentRule) { + // bind submit + if (rule === 'submit' || !rule) { + if (rule === undefined) { + if (itemRlue !== 'bind') { + if (!itemRlue) { + return parentRule === '' ? 'bind' : 'submit'; + } + return 'submit'; + } + return 'bind'; + } + return 'submit'; + } + return 'bind'; + }, + num2px(num) { + if (typeof num === 'number') { + return `${num}px` + } + return num + } + } + }; +</script> + +<style lang="scss"> + .uni-forms-item { + position: relative; + display: flex; + /* #ifdef APP-NVUE */ + // 在 nvue 中,使用 margin-bottom error 信息会被隐藏 + padding-bottom: 22px; + /* #endif */ + /* #ifndef APP-NVUE */ + margin-bottom: 22px; + /* #endif */ + flex-direction: row; + + &__label { + display: flex; + flex-direction: row; + align-items: center; + text-align: left; + font-size: 14px; + color: #606266; + height: 36px; + padding: 0 12px 0 0; + /* #ifndef APP-NVUE */ + vertical-align: middle; + flex-shrink: 0; + /* #endif */ + + /* #ifndef APP-NVUE */ + box-sizing: border-box; + + /* #endif */ + &.no-label { + padding: 0; + } + } + + &__content { + /* #ifndef MP-TOUTIAO */ + // display: flex; + // align-items: center; + /* #endif */ + position: relative; + font-size: 14px; + flex: 1; + /* #ifndef APP-NVUE */ + box-sizing: border-box; + /* #endif */ + flex-direction: row; + + /* #ifndef APP || H5 || MP-WEIXIN || APP-NVUE */ + // TODO 因为小程序平台会多一层标签节点 ,所以需要在多余节点继承当前样式 + &>uni-easyinput, + &>uni-data-picker { + width: 100%; + } + + /* #endif */ + + } + + & .uni-forms-item__nuve-content { + display: flex; + flex-direction: column; + flex: 1; + } + + &__error { + color: #f56c6c; + font-size: 12px; + line-height: 1; + padding-top: 4px; + position: absolute; + /* #ifndef APP-NVUE */ + top: 100%; + left: 0; + transition: transform 0.3s; + transform: translateY(-100%); + /* #endif */ + /* #ifdef APP-NVUE */ + bottom: 5px; + /* #endif */ + + opacity: 0; + + .error-text { + // 只有 nvue 下这个样式才生效 + color: #f56c6c; + font-size: 12px; + } + + &.msg--active { + opacity: 1; + transform: translateY(0%); + } + } + + // 位置修饰样式 + &.is-direction-left { + flex-direction: row; + } + + &.is-direction-top { + flex-direction: column; + + .uni-forms-item__label { + padding: 0 0 8px; + line-height: 1.5715; + text-align: left; + /* #ifndef APP-NVUE */ + white-space: initial; + /* #endif */ + } + } + + .is-required { + // color: $uni-color-error; + color: #dd524d; + font-weight: bold; + } + } + + + .uni-forms-item--border { + margin-bottom: 0; + padding: 10px 0; + // padding-bottom: 0; + border-top: 1px #eee solid; + + /* #ifndef APP-NVUE */ + .uni-forms-item__content { + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + + .uni-forms-item__error { + position: relative; + top: 5px; + left: 0; + padding-top: 0; + } + } + + /* #endif */ + + /* #ifdef APP-NVUE */ + display: flex; + flex-direction: column; + + .uni-forms-item__error { + position: relative; + top: 0px; + left: 0; + padding-top: 0; + margin-top: 5px; + } + + /* #endif */ + + } + + .is-first-border { + /* #ifndef APP-NVUE */ + border: none; + /* #endif */ + /* #ifdef APP-NVUE */ + border-width: 0; + /* #endif */ + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-forms/components/uni-forms/uni-forms.vue b/yudao-ui-admin-uniapp/uni_modules/uni-forms/components/uni-forms/uni-forms.vue new file mode 100644 index 000000000..ed2f6d971 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-forms/components/uni-forms/uni-forms.vue @@ -0,0 +1,397 @@ +<template> + <view class="uni-forms"> + <form> + <slot></slot> + </form> + </view> +</template> + +<script> + import Validator from './validate.js'; + import { + deepCopy, + getValue, + isRequiredField, + setDataValue, + getDataValue, + realName, + isRealName, + rawData, + isEqual + } from './utils.js' + + // #ifndef VUE3 + // 后续会慢慢废弃这个方法 + import Vue from 'vue'; + Vue.prototype.binddata = function(name, value, formName) { + if (formName) { + this.$refs[formName].setValue(name, value); + } else { + let formVm; + for (let i in this.$refs) { + const vm = this.$refs[i]; + if (vm && vm.$options && vm.$options.name === 'uniForms') { + formVm = vm; + break; + } + } + if (!formVm) return console.error('当前 uni-froms 组件缺少 ref 属性'); + formVm.setValue(name, value); + } + }; + // #endif + /** + * Forms 表单 + * @description 由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据 + * @tutorial https://ext.dcloud.net.cn/plugin?id=2773 + * @property {Object} rules 表单校验规则 + * @property {String} validateTrigger = [bind|submit|blur] 校验触发器方式 默认 submit + * @value bind 发生变化时触发 + * @value submit 提交时触发 + * @value blur 失去焦点时触发 + * @property {String} labelPosition = [top|left] label 位置 默认 left + * @value top 顶部显示 label + * @value left 左侧显示 label + * @property {String} labelWidth label 宽度,默认 65px + * @property {String} labelAlign = [left|center|right] label 居中方式 默认 left + * @value left label 左侧显示 + * @value center label 居中 + * @value right label 右侧对齐 + * @property {String} errShowType = [undertext|toast|modal] 校验错误信息提示方式 + * @value undertext 错误信息在底部显示 + * @value toast 错误信息toast显示 + * @value modal 错误信息modal显示 + * @event {Function} submit 提交时触发 + * @event {Function} validate 校验结果发生变化触发 + */ + export default { + name: 'uniForms', + emits: ['validate', 'submit'], + options: { + virtualHost: true + }, + props: { + // 即将弃用 + value: { + type: Object, + default () { + return null; + } + }, + // vue3 替换 value 属性 + modelValue: { + type: Object, + default () { + return null; + } + }, + // 1.4.0 开始将不支持 v-model ,且废弃 value 和 modelValue + model: { + type: Object, + default () { + return null; + } + }, + // 表单校验规则 + rules: { + type: Object, + default () { + return {}; + } + }, + //校验错误信息提示方式 默认 undertext 取值 [undertext|toast|modal] + errShowType: { + type: String, + default: 'undertext' + }, + // 校验触发器方式 默认 bind 取值 [bind|submit] + validateTrigger: { + type: String, + default: 'submit' + }, + // label 位置,默认 left 取值 top/left + labelPosition: { + type: String, + default: 'left' + }, + // label 宽度 + labelWidth: { + type: [String, Number], + default: '' + }, + // label 居中方式,默认 left 取值 left/center/right + labelAlign: { + type: String, + default: 'left' + }, + border: { + type: Boolean, + default: false + } + }, + provide() { + return { + uniForm: this + } + }, + data() { + return { + // 表单本地值的记录,不应该与传如的值进行关联 + formData: {}, + formRules: {} + }; + }, + computed: { + // 计算数据源变化的 + localData() { + const localVal = this.model || this.modelValue || this.value + if (localVal) { + return deepCopy(localVal) + } + return {} + } + }, + watch: { + // 监听数据变化 ,暂时不使用,需要单独赋值 + // localData: {}, + // 监听规则变化 + rules: { + handler: function(val, oldVal) { + this.setRules(val) + }, + deep: true, + immediate: true + } + }, + created() { + // #ifdef VUE3 + let getbinddata = getApp().$vm.$.appContext.config.globalProperties.binddata + if (!getbinddata) { + getApp().$vm.$.appContext.config.globalProperties.binddata = function(name, value, formName) { + if (formName) { + this.$refs[formName].setValue(name, value); + } else { + let formVm; + for (let i in this.$refs) { + const vm = this.$refs[i]; + if (vm && vm.$options && vm.$options.name === 'uniForms') { + formVm = vm; + break; + } + } + if (!formVm) return console.error('当前 uni-froms 组件缺少 ref 属性'); + formVm.setValue(name, value); + } + } + } + // #endif + + // 子组件实例数组 + this.childrens = [] + // TODO 兼容旧版 uni-data-picker ,新版本中无效,只是避免报错 + this.inputChildrens = [] + this.setRules(this.rules) + }, + methods: { + /** + * 外部调用方法 + * 设置规则 ,主要用于小程序自定义检验规则 + * @param {Array} rules 规则源数据 + */ + setRules(rules) { + // TODO 有可能子组件合并规则的时机比这个要早,所以需要合并对象 ,而不是直接赋值,可能会被覆盖 + this.formRules = Object.assign({}, this.formRules, rules) + // 初始化校验函数 + this.validator = new Validator(rules); + }, + + /** + * 外部调用方法 + * 设置数据,用于设置表单数据,公开给用户使用 , 不支持在动态表单中使用 + * @param {Object} key + * @param {Object} value + */ + setValue(key, value) { + let example = this.childrens.find(child => child.name === key); + if (!example) return null; + this.formData[key] = getValue(key, value, (this.formRules[key] && this.formRules[key].rules) || []) + return example.onFieldChange(this.formData[key]); + }, + + /** + * 外部调用方法 + * 手动提交校验表单 + * 对整个表单进行校验的方法,参数为一个回调函数。 + * @param {Array} keepitem 保留不参与校验的字段 + * @param {type} callback 方法回调 + */ + validate(keepitem, callback) { + return this.checkAll(this.formData, keepitem, callback); + }, + + /** + * 外部调用方法 + * 部分表单校验 + * @param {Array|String} props 需要校验的字段 + * @param {Function} 回调函数 + */ + validateField(props = [], callback) { + props = [].concat(props); + let invalidFields = {}; + this.childrens.forEach(item => { + const name = realName(item.name) + if (props.indexOf(name) !== -1) { + invalidFields = Object.assign({}, invalidFields, { + [name]: this.formData[name] + }); + } + }); + return this.checkAll(invalidFields, [], callback); + }, + + /** + * 外部调用方法 + * 移除表单项的校验结果。传入待移除的表单项的 prop 属性或者 prop 组成的数组,如不传则移除整个表单的校验结果 + * @param {Array|String} props 需要移除校验的字段 ,不填为所有 + */ + clearValidate(props = []) { + props = [].concat(props); + this.childrens.forEach(item => { + if (props.length === 0) { + item.errMsg = ''; + } else { + const name = realName(item.name) + if (props.indexOf(name) !== -1) { + item.errMsg = ''; + } + } + }); + }, + + /** + * 外部调用方法 ,即将废弃 + * 手动提交校验表单 + * 对整个表单进行校验的方法,参数为一个回调函数。 + * @param {Array} keepitem 保留不参与校验的字段 + * @param {type} callback 方法回调 + */ + submit(keepitem, callback, type) { + for (let i in this.dataValue) { + const itemData = this.childrens.find(v => v.name === i); + if (itemData) { + if (this.formData[i] === undefined) { + this.formData[i] = this._getValue(i, this.dataValue[i]); + } + } + } + + if (!type) { + console.warn('submit 方法即将废弃,请使用validate方法代替!'); + } + + return this.checkAll(this.formData, keepitem, callback, 'submit'); + }, + + // 校验所有 + async checkAll(invalidFields, keepitem, callback, type) { + // 不存在校验规则 ,则停止校验流程 + if (!this.validator) return + let childrens = [] + // 处理参与校验的item实例 + for (let i in invalidFields) { + const item = this.childrens.find(v => realName(v.name) === i) + if (item) { + childrens.push(item) + } + } + + // 如果validate第一个参数是funciont ,那就走回调 + if (!callback && typeof keepitem === 'function') { + callback = keepitem; + } + + let promise; + // 如果不存在回调,那么使用 Promise 方式返回 + if (!callback && typeof callback !== 'function' && Promise) { + promise = new Promise((resolve, reject) => { + callback = function(valid, invalidFields) { + !valid ? resolve(invalidFields) : reject(valid); + }; + }); + } + + let results = []; + // 避免引用错乱 ,建议拷贝对象处理 + let tempFormData = JSON.parse(JSON.stringify(invalidFields)) + // 所有子组件参与校验,使用 for 可以使用 awiat + for (let i in childrens) { + const child = childrens[i] + let name = realName(child.name); + const result = await child.onFieldChange(tempFormData[name]); + if (result) { + results.push(result); + // toast ,modal 只需要执行第一次就可以 + if (this.errShowType === 'toast' || this.errShowType === 'modal') break; + } + } + + + if (Array.isArray(results)) { + if (results.length === 0) results = null; + } + if (Array.isArray(keepitem)) { + keepitem.forEach(v => { + let vName = realName(v); + let value = getDataValue(v, this.localData) + if (value !== undefined) { + tempFormData[vName] = value + } + }); + } + + // TODO submit 即将废弃 + if (type === 'submit') { + this.$emit('submit', { + detail: { + value: tempFormData, + errors: results + } + }); + } else { + this.$emit('validate', results); + } + + // const resetFormData = rawData(tempFormData, this.localData, this.name) + let resetFormData = {} + resetFormData = rawData(tempFormData, this.name) + callback && typeof callback === 'function' && callback(results, resetFormData); + + if (promise && callback) { + return promise; + } else { + return null; + } + + }, + + /** + * 返回validate事件 + * @param {Object} result + */ + validateCheck(result) { + this.$emit('validate', result); + }, + _getValue: getValue, + _isRequiredField: isRequiredField, + _setDataValue: setDataValue, + _getDataValue: getDataValue, + _realName: realName, + _isRealName: isRealName, + _isEqual: isEqual + } + }; +</script> + +<style lang="scss"> + .uni-forms {} +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-forms/components/uni-forms/utils.js b/yudao-ui-admin-uniapp/uni_modules/uni-forms/components/uni-forms/utils.js new file mode 100644 index 000000000..6da242165 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-forms/components/uni-forms/validate.js b/yudao-ui-admin-uniapp/uni_modules/uni-forms/components/uni-forms/validate.js new file mode 100644 index 000000000..1834c6cf6 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-forms/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-forms/package.json new file mode 100644 index 000000000..e69d39b51 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-forms/package.json @@ -0,0 +1,91 @@ +{ + "id": "uni-forms", + "displayName": "uni-forms 表单", + "version": "1.4.6", + "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", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-forms/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-forms/readme.md new file mode 100644 index 000000000..63d5a043e --- /dev/null +++ b/yudao-ui-admin-uniapp/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的内置组件已经有了 `<form>`组件,用于提交表单内容。 + +然而几乎每个表单都需要做表单验证,为了方便做表单验证,减少重复开发,`uni ui` 又基于 `<form>`组件封装了 `<uni-forms>`组件,内置了表单验证功能。 + +`<uni-forms>` 提供了 `rules`属性来描述校验规则、`<uni-forms-item>`子组件来包裹具体的表单项,以及给原生或三方组件提供了 `binddata()` 来设置表单值。 + +每个要校验的表单项,不管input还是checkbox,都必须放在`<uni-forms-item>`组件中,且一个`<uni-forms-item>`组件只能放置一个表单项。 + +`<uni-forms-item>`组件内部预留了显示error message的区域,默认是在表单项的底部。 + +另外,`<uni-forms>`组件下面的各个表单项,可以通过`<uni-group>`包裹为不同的分组。同一`<uni-group>`下的不同表单项目将聚拢在一起,同其他group保持垂直间距。`<uni-group>`仅影响视觉效果。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-forms) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/changelog.md new file mode 100644 index 000000000..c6264c67e --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/en.json b/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/en.json new file mode 100644 index 000000000..dcdba41ce --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/index.js b/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/index.js new file mode 100644 index 000000000..de7509c87 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hans.json b/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hans.json new file mode 100644 index 000000000..48ee344c3 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hant.json b/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hant.json new file mode 100644 index 000000000..d0a0255c7 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/components/uni-goods-nav/uni-goods-nav.vue b/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/components/uni-goods-nav/uni-goods-nav.vue new file mode 100644 index 000000000..8a16b1755 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/components/uni-goods-nav/uni-goods-nav.vue @@ -0,0 +1,229 @@ +<template> + <view class="uni-goods-nav"> + <!-- 底部占位 --> + <view class="uni-tab__seat" /> + <view class="uni-tab__cart-box flex"> + <view class="flex uni-tab__cart-sub-left"> + <view v-for="(item,index) in options" :key="index" class="flex uni-tab__cart-button-left uni-tab__shop-cart" @click="onClick(index,item)"> + <view class="uni-tab__icon"> + <uni-icons :type="item.icon" size="20" color="#646566"></uni-icons> + <!-- <image class="image" :src="item.icon" mode="widthFix" /> --> + </view> + <text class="uni-tab__text">{{ item.text }}</text> + <view class="flex uni-tab__dot-box"> + <text v-if="item.info" :class="{ 'uni-tab__dots': item.info > 9 }" class="uni-tab__dot " :style="{'backgroundColor':item.infoBackgroundColor?item.infoBackgroundColor:'#ff0000', + color:item.infoColor?item.infoColor:'#fff' + }">{{ item.info }}</text> + </view> + </view> + </view> + <view :class="{'uni-tab__right':fill}" class="flex uni-tab__cart-sub-right "> + <view v-for="(item,index) in buttonGroup" :key="index" :style="{background:item.backgroundColor,color:item.color}" + class="flex uni-tab__cart-button-right" @click="buttonClick(index,item)"><text :style="{color:item.color}" class="uni-tab__cart-button-right-text">{{ item.text }}</text></view> + </view> + </view> + </view> +</template> + +<script> + import { + initVueI18n + } from '@dcloudio/uni-i18n' + import messages from './i18n/index.js' + const { t } = initVueI18n(messages) + /** + * GoodsNav 商品导航 + * @description 商品加入购物车、立即购买等 + * @tutorial https://ext.dcloud.net.cn/plugin?id=865 + * @property {Array} options 组件参数 + * @property {Array} buttonGroup 组件按钮组参数 + * @property {Boolean} fill = [true | false] 组件按钮组参数 + * @property {Boolean} stat 是否开启统计功能 + * @event {Function} click 左侧点击事件 + * @event {Function} buttonClick 右侧按钮组点击事件 + * @example <uni-goods-nav :fill="true" options="" buttonGroup="buttonGroup" @click="" @buttonClick="" /> + */ + export default { + name: 'UniGoodsNav', + emits:['click','buttonClick'], + props: { + options: { + type: Array, + default () { + return [{ + icon: 'shop', + text: t("uni-goods-nav.options.shop"), + }, { + icon: 'cart', + text: t("uni-goods-nav.options.cart") + }] + } + }, + buttonGroup: { + type: Array, + default () { + return [{ + text: t("uni-goods-nav.buttonGroup.addToCart"), + backgroundColor: 'linear-gradient(90deg, #FFCD1E, #FF8A18)', + color: '#fff' + }, + { + text: t("uni-goods-nav.buttonGroup.buyNow"), + backgroundColor: 'linear-gradient(90deg, #FE6035, #EF1224)', + color: '#fff' + } + ] + } + }, + fill: { + type: Boolean, + default: false + }, + stat:{ + type: Boolean, + default: false + } + }, + methods: { + onClick(index, item) { + this.$emit('click', { + index, + content: item, + }) + }, + buttonClick(index, item) { + if (uni.report && this.stat) { + uni.report(item.text, item.text) + } + this.$emit('buttonClick', { + index, + content: item + }) + } + } + } +</script> + +<style lang="scss" > + .flex { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + } + + .uni-goods-nav { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex: 1; + flex-direction: row; + } + + .uni-tab__cart-box { + flex: 1; + height: 50px; + background-color: #fff; + z-index: 900; + } + + .uni-tab__cart-sub-left { + padding: 0 5px; + } + + .uni-tab__cart-sub-right { + flex: 1; + } + + .uni-tab__right { + margin: 5px 0; + margin-right: 10px; + border-radius: 100px; + overflow: hidden; + } + + .uni-tab__cart-button-left { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + // flex: 1; + position: relative; + justify-content: center; + align-items: center; + flex-direction: column; + margin: 0 10px; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + + .uni-tab__icon { + width: 18px; + height: 18px; + } + + .image { + width: 18px; + height: 18px; + } + + .uni-tab__text { + margin-top: 3px; + font-size: 12px; + color: #646566; + } + + .uni-tab__cart-button-right { + /* #ifndef APP-NVUE */ + display: flex; + flex-direction: column; + /* #endif */ + flex: 1; + justify-content: center; + align-items: center; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + + .uni-tab__cart-button-right-text { + font-size: 14px; + color: #fff; + } + + .uni-tab__cart-button-right:active { + opacity: 0.7; + } + + .uni-tab__dot-box { + /* #ifndef APP-NVUE */ + display: flex; + flex-direction: column; + /* #endif */ + position: absolute; + right: -2px; + top: 2px; + justify-content: center; + align-items: center; + // width: 0; + // height: 0; + } + + .uni-tab__dot { + // width: 30rpx; + // height: 30rpx; + padding: 0 4px; + line-height: 15px; + color: #ffffff; + text-align: center; + font-size: 12px; + background-color: #ff0000; + border-radius: 15px; + } + + .uni-tab__dots { + padding: 0 4px; + // width: auto; + border-radius: 15px; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/package.json new file mode 100644 index 000000000..636e45e7e --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-goods-nav/readme.md new file mode 100644 index 000000000..07df93f55 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-grid/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-grid/changelog.md new file mode 100644 index 000000000..d301166cf --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue b/yudao-ui-admin-uniapp/uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue new file mode 100644 index 000000000..20fd54e59 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue @@ -0,0 +1,127 @@ +<template> + <view v-if="width" :style="'width:'+width+';'+(square?'height:'+width:'')" class="uni-grid-item"> + <view :class="{ 'uni-grid-item--border': showBorder, 'uni-grid-item--border-top': showBorder && index < column, 'uni-highlight': highlight }" + :style="{'border-right-color': borderColor ,'border-bottom-color': borderColor ,'border-top-color': borderColor }" + class="uni-grid-item__box" @click="_onClick"> + <slot /> + </view> + </view> +</template> + +<script> + /** + * GridItem 宫格 + * @description 宫格组件 + * @tutorial https://ext.dcloud.net.cn/plugin?id=27 + * @property {Number} index 子组件的唯一标识 ,点击gird会返回当前的标识 + */ + export default { + name: 'UniGridItem', + inject: ['grid'], + props: { + index: { + type: Number, + default: 0 + } + }, + data() { + return { + column: 0, + showBorder: true, + square: true, + highlight: true, + left: 0, + top: 0, + openNum: 2, + width: 0, + borderColor: '#e5e5e5' + } + }, + created() { + this.column = this.grid.column + this.showBorder = this.grid.showBorder + this.square = this.grid.square + this.highlight = this.grid.highlight + this.top = this.hor === 0 ? this.grid.hor : this.hor + this.left = this.ver === 0 ? this.grid.ver : this.ver + this.borderColor = this.grid.borderColor + this.grid.children.push(this) + // this.grid.init() + this.width = this.grid.width + }, + beforeDestroy() { + this.grid.children.forEach((item, index) => { + if (item === this) { + this.grid.children.splice(index, 1) + } + }) + }, + methods: { + _onClick() { + this.grid.change({ + detail: { + index: this.index + } + }) + } + } + } +</script> + +<style lang="scss" > + .uni-grid-item { + /* #ifndef APP-NVUE */ + height: 100%; + display: flex; + /* #endif */ + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + + .uni-grid-item__box { + /* #ifndef APP-NVUE */ + display: flex; + width: 100%; + /* #endif */ + position: relative; + flex: 1; + flex-direction: column; + // justify-content: center; + // align-items: center; + } + + .uni-grid-item--border { + position: relative; + /* #ifdef APP-NVUE */ + border-bottom-color: #D2D2D2; + border-bottom-style: solid; + border-bottom-width: 0.5px; + border-right-color: #D2D2D2; + border-right-style: solid; + border-right-width: 0.5px; + /* #endif */ + /* #ifndef APP-NVUE */ + z-index: 0; + border-bottom: 1px #D2D2D2 solid; + border-right: 1px #D2D2D2 solid; + /* #endif */ + } + .uni-grid-item--border-top { + position: relative; + /* #ifdef APP-NVUE */ + border-top-color: #D2D2D2; + border-top-style: solid; + border-top-width: 0.5px; + /* #endif */ + /* #ifndef APP-NVUE */ + border-top: 1px #D2D2D2 solid; + z-index: 0; + /* #endif */ + } + + + .uni-highlight:active { + background-color: #f1f1f1; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-grid/components/uni-grid/uni-grid.vue b/yudao-ui-admin-uniapp/uni_modules/uni-grid/components/uni-grid/uni-grid.vue new file mode 100644 index 000000000..96a412f6d --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-grid/components/uni-grid/uni-grid.vue @@ -0,0 +1,142 @@ +<template> + <view class="uni-grid-wrap"> + <view :id="elId" ref="uni-grid" class="uni-grid" :class="{ 'uni-grid--border': showBorder }" :style="{ 'border-left-color':borderColor}"> + <slot /> + </view> + </view> +</template> + +<script> + // #ifdef APP-NVUE + const dom = uni.requireNativePlugin('dom'); + // #endif + + /** + * Grid 宫格 + * @description 宫格组件 + * @tutorial https://ext.dcloud.net.cn/plugin?id=27 + * @property {Number} column 每列显示个数 + * @property {String} borderColor 边框颜色 + * @property {Boolean} showBorder 是否显示边框 + * @property {Boolean} square 是否方形显示 + * @property {Boolean} Boolean 点击背景是否高亮 + * @event {Function} change 点击 grid 触发,e={detail:{index:0}},index 为当前点击 gird 下标 + */ + export default { + name: 'UniGrid', + emits:['change'], + props: { + // 每列显示个数 + column: { + type: Number, + default: 3 + }, + // 是否显示边框 + showBorder: { + type: Boolean, + default: true + }, + // 边框颜色 + borderColor: { + type: String, + default: '#D2D2D2' + }, + // 是否正方形显示,默认为 true + square: { + type: Boolean, + default: true + }, + highlight: { + type: Boolean, + default: true + } + }, + provide() { + return { + grid: this + } + }, + data() { + const elId = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}` + return { + elId, + width: 0 + } + }, + created() { + this.children = [] + }, + mounted() { + this.$nextTick(()=>{ + this.init() + }) + }, + methods: { + init() { + setTimeout(() => { + this._getSize((width) => { + this.children.forEach((item, index) => { + item.width = width + }) + }) + }, 50) + }, + change(e) { + this.$emit('change', e) + }, + _getSize(fn) { + // #ifndef APP-NVUE + uni.createSelectorQuery() + .in(this) + .select(`#${this.elId}`) + .boundingClientRect() + .exec(ret => { + this.width = parseInt((ret[0].width - 1) / this.column) + 'px' + fn(this.width) + }) + // #endif + // #ifdef APP-NVUE + dom.getComponentRect(this.$refs['uni-grid'], (ret) => { + this.width = parseInt((ret.size.width - 1) / this.column) + 'px' + fn(this.width) + }) + // #endif + } + } + } +</script> + +<style lang="scss" > + .uni-grid-wrap { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex: 1; + flex-direction: column; + /* #ifdef H5 */ + width: 100%; + /* #endif */ + } + + .uni-grid { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + // flex: 1; + flex-direction: row; + flex-wrap: wrap; + } + + .uni-grid--border { + position: relative; + /* #ifdef APP-NVUE */ + border-left-color: #D2D2D2; + border-left-style: solid; + border-left-width: 0.5px; + /* #endif */ + /* #ifndef APP-NVUE */ + z-index: 1; + border-left: 1px #D2D2D2 solid; + /* #endif */ + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-grid/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-grid/package.json new file mode 100644 index 000000000..ccb2c9171 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-grid/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-grid/readme.md new file mode 100644 index 000000000..0aa44cc13 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-group/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-group/changelog.md new file mode 100644 index 000000000..a7024fdf8 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-group/components/uni-group/uni-group.vue b/yudao-ui-admin-uniapp/uni_modules/uni-group/components/uni-group/uni-group.vue new file mode 100644 index 000000000..3425ecd3a --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-group/components/uni-group/uni-group.vue @@ -0,0 +1,134 @@ +<template> + <view class="uni-group" :class="['uni-group--'+mode ,margin?'group-margin':'']" :style="{marginTop: `${top}px` }"> + <slot name="title"> + <view v-if="title" class="uni-group__title" :style="{'padding-left':border?'30px':'15px'}"> + <text class="uni-group__title-text">{{ title }}</text> + </view> + </slot> + <view class="uni-group__content" :class="{'group-conent-padding':border}"> + <slot /> + </view> + </view> +</template> + +<script> + /** + * Group 分组 + * @description 表单字段分组 + * @tutorial https://ext.dcloud.net.cn/plugin?id=3281 + * @property {String} title 主标题 + * @property {Number} top 分组间隔 + * @property {Number} mode 模式 + */ + export default { + name: 'uniGroup', + emits:['click'], + props: { + title: { + type: String, + default: '' + }, + top: { + type: [Number, String], + default: 10 + }, + mode: { + type: String, + default: 'default' + }, + stat:{ + type: Boolean, + default: false + } + }, + data() { + return { + margin: false, + border: false + } + }, + watch: { + title(newVal) { + if (uni.report && this.stat && newVal !== '') { + uni.report('title', newVal) + } + } + }, + created() { + this.form = this.getForm() + if (this.form) { + this.margin = true + this.border = this.form.border + } + }, + methods: { + /** + * 获取父元素实例 + */ + getForm() { + let parent = this.$parent; + let parentName = parent.$options.name; + while (parentName !== 'uniForms') { + parent = parent.$parent; + if (!parent) return false + parentName = parent.$options.name; + } + return parent; + }, + onClick() { + this.$emit('click') + } + } + } +</script> +<style lang="scss" > + .uni-group { + background: #fff; + margin-top: 10px; + // border: 1px red solid; + } + + .group-margin { + // margin: 0 -15px; + } + + .uni-group__title { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + align-items: center; + padding-left: 15px; + height: 40px; + background-color: #eee; + font-weight: normal; + color: #666; + } + + .uni-group__content { + padding: 15px; + // padding-bottom: 5px; + // background-color: #FFF; + } + + .group-conent-padding { + padding: 0 15px; + } + + .uni-group__title-text { + font-size: 14px; + color: #666; + } + + .distraction { + flex-direction: row; + align-items: center; + } + + .uni-group--card { + margin: 10px; + border-radius: 5px; + overflow: hidden; + box-shadow: 0 0 5px 1px rgba($color: #000000, $alpha: 0.08); + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-group/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-group/package.json new file mode 100644 index 000000000..ea00a08c2 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-group/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-group/readme.md new file mode 100644 index 000000000..bae67f468 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-icons/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-icons/changelog.md new file mode 100644 index 000000000..64498853c --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-icons/changelog.md @@ -0,0 +1,22 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-icons/components/uni-icons/icons.js b/yudao-ui-admin-uniapp/uni_modules/uni-icons/components/uni-icons/icons.js new file mode 100644 index 000000000..78899364e --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-icons/components/uni-icons/uni-icons.vue b/yudao-ui-admin-uniapp/uni_modules/uni-icons/components/uni-icons/uni-icons.vue new file mode 100644 index 000000000..86e744452 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-icons/components/uni-icons/uni-icons.vue @@ -0,0 +1,96 @@ +<template> + <!-- #ifdef APP-NVUE --> + <text :style="{ color: color, 'font-size': iconSize }" class="uni-icons" @click="_onClick">{{unicode}}</text> + <!-- #endif --> + <!-- #ifndef APP-NVUE --> + <text :style="{ color: color, 'font-size': iconSize }" class="uni-icons" :class="['uniui-'+type,customPrefix,customPrefix?type:'']" @click="_onClick"></text> + <!-- #endif --> +</template> + +<script> + import icons from './icons.js'; + const getVal = (val) => { + const reg = /^[0-9]*$/g + return (typeof val === 'number' || reg.test(val) )? val + 'px' : val; + } + // #ifdef APP-NVUE + var domModule = weex.requireModule('dom'); + import iconUrl from './uniicons.ttf' + domModule.addRule('fontFace', { + 'fontFamily': "uniicons", + 'src': "url('"+iconUrl+"')" + }); + // #endif + + /** + * Icons 图标 + * @description 用于展示 icons 图标 + * @tutorial https://ext.dcloud.net.cn/plugin?id=28 + * @property {Number} size 图标大小 + * @property {String} type 图标图案,参考示例 + * @property {String} color 图标颜色 + * @property {String} customPrefix 自定义图标 + * @event {Function} click 点击 Icon 触发事件 + */ + export default { + name: 'UniIcons', + emits:['click'], + props: { + type: { + type: String, + default: '' + }, + color: { + type: String, + default: '#333333' + }, + size: { + type: [Number, String], + default: 16 + }, + customPrefix:{ + type: String, + default: '' + } + }, + data() { + return { + icons: icons.glyphs + } + }, + computed:{ + unicode(){ + let code = this.icons.find(v=>v.font_class === this.type) + if(code){ + return unescape(`%u${code.unicode}`) + } + return '' + }, + iconSize(){ + return getVal(this.size) + } + }, + methods: { + _onClick() { + this.$emit('click') + } + } + } +</script> + +<style lang="scss"> + /* #ifndef APP-NVUE */ + @import './uniicons.css'; + @font-face { + font-family: uniicons; + src: url('./uniicons.ttf') format('truetype'); + } + + /* #endif */ + .uni-icons { + font-family: uniicons; + text-decoration: none; + text-align: center; + } + +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-icons/components/uni-icons/uniicons.css b/yudao-ui-admin-uniapp/uni_modules/uni-icons/components/uni-icons/uniicons.css new file mode 100644 index 000000000..2f56eabde --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-icons/components/uni-icons/uniicons.css @@ -0,0 +1,663 @@ +.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-gift-filled:before { + content: "\e6c4"; +} + +.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-back:before { + content: "\e6b9"; +} + +.uniui-forward:before { + content: "\e6ba"; +} + +.uniui-arrow-right:before { + content: "\e6bb"; +} + +.uniui-arrowthinright:before { + content: "\e6bb"; +} + +.uniui-arrow-left:before { + content: "\e6bc"; +} + +.uniui-arrowthinleft:before { + content: "\e6bc"; +} + +.uniui-arrow-up:before { + content: "\e6bd"; +} + +.uniui-arrowthinup:before { + content: "\e6bd"; +} + +.uniui-arrow-down:before { + content: "\e6be"; +} + +.uniui-arrowthindown:before { + content: "\e6be"; +} + +.uniui-bottom:before { + content: "\e6b8"; +} + +.uniui-arrowdown:before { + content: "\e6b8"; +} + +.uniui-right:before { + content: "\e6b5"; +} + +.uniui-arrowright:before { + content: "\e6b5"; +} + +.uniui-top:before { + content: "\e6b6"; +} + +.uniui-arrowup:before { + content: "\e6b6"; +} + +.uniui-left:before { + content: "\e6b7"; +} + +.uniui-arrowleft:before { + content: "\e6b7"; +} + +.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-cart-filled:before { + content: "\e629"; +} + +.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/yudao-ui-admin-uniapp/uni_modules/uni-icons/components/uni-icons/uniicons.ttf b/yudao-ui-admin-uniapp/uni_modules/uni-icons/components/uni-icons/uniicons.ttf new file mode 100644 index 0000000000000000000000000000000000000000..835f33bc9411461b8b9046b3fec742e921d6ce3a GIT binary patch literal 35760 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 literal 0 HcmV?d00001 diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-icons/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-icons/package.json new file mode 100644 index 000000000..d1c4e77d4 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-icons/package.json @@ -0,0 +1,86 @@ +{ + "id": "uni-icons", + "displayName": "uni-icons 图标", + "version": "1.3.5", + "description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。", + "keywords": [ + "uni-ui", + "uniui", + "icon", + "图标" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.2.14" + }, + "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/yudao-ui-admin-uniapp/uni_modules/uni-icons/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-icons/readme.md new file mode 100644 index 000000000..86234ba1c --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/changelog.md new file mode 100644 index 000000000..08fa71cb4 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list-item.vue b/yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list-item.vue new file mode 100644 index 000000000..2f13baec9 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list-item.vue @@ -0,0 +1,144 @@ +<template> + <view> + <view v-if="loaded || list.itemIndex < 15" class="uni-indexed-list__title-wrapper"> + <text v-if="list.items && list.items.length > 0" class="uni-indexed-list__title">{{ list.key }}</text> + </view> + <view v-if="(loaded || list.itemIndex < 15) && list.items && list.items.length > 0" class="uni-indexed-list__list"> + <view v-for="(item, index) in list.items" :key="index" class="uni-indexed-list__item" hover-class="uni-indexed-list__item--hover"> + <view class="uni-indexed-list__item-container" @click="onClick(idx, index)"> + <view class="uni-indexed-list__item-border" :class="{'uni-indexed-list__item-border--last':index===list.items.length-1}"> + <view v-if="showSelect" style="margin-right: 20rpx;"> + <uni-icons :type="item.checked ? 'checkbox-filled' : 'circle'" :color="item.checked ? '#007aff' : '#C0C0C0'" size="24" /> + </view> + <text class="uni-indexed-list__item-content">{{ item.name }}</text> + </view> + </view> + </view> + </view> + </view> +</template> + +<script> + export default { + name: 'UniIndexedList', + emits:['itemClick'], + props: { + loaded: { + type: Boolean, + default: false + }, + idx: { + type: Number, + default: 0 + }, + list: { + type: Object, + default () { + return {} + } + }, + showSelect: { + type: Boolean, + default: false + } + }, + methods: { + onClick(idx, index) { + this.$emit("itemClick", { + idx, + index + }) + } + } + } +</script> + +<style lang="scss" > + .uni-indexed-list__list { + background-color: $uni-bg-color; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + border-top-style: solid; + border-top-width: 1px; + border-top-color: #DEDEDE; + } + + .uni-indexed-list__item { + font-size: 14px; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex: 1; + flex-direction: row; + justify-content: space-between; + align-items: center; + } + + .uni-indexed-list__item-container { + padding-left: 15px; + flex: 1; + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + box-sizing: border-box; + /* #endif */ + flex-direction: row; + justify-content: space-between; + align-items: center; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + + .uni-indexed-list__item-border { + flex: 1; + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + box-sizing: border-box; + /* #endif */ + flex-direction: row; + justify-content: space-between; + align-items: center; + height: 50px; + padding: 25px; + padding-left: 0; + border-bottom-style: solid; + border-bottom-width: 1px; + border-bottom-color: #DEDEDE; + } + + .uni-indexed-list__item-border--last { + border-bottom-width: 0px; + } + + .uni-indexed-list__item-content { + flex: 1; + font-size: 14px; + color: #191919; + } + + .uni-indexed-list { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + } + + .uni-indexed-list__title-wrapper { + /* #ifndef APP-NVUE */ + display: flex; + width: 100%; + /* #endif */ + background-color: #f7f7f7; + } + + .uni-indexed-list__title { + padding: 6px 12px; + line-height: 24px; + font-size: 16px; + font-weight: 500; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list.vue b/yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list.vue new file mode 100644 index 000000000..35e168c26 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list.vue @@ -0,0 +1,367 @@ +<template> + <view class="uni-indexed-list" ref="list" id="list"> + <!-- #ifdef APP-NVUE --> + <list class="uni-indexed-list__scroll" scrollable="true" show-scrollbar="false"> + <cell v-for="(list, idx) in lists" :key="idx" :ref="'uni-indexed-list-' + idx"> + <!-- #endif --> + <!-- #ifndef APP-NVUE --> + <scroll-view :scroll-into-view="scrollViewId" class="uni-indexed-list__scroll" scroll-y> + <view v-for="(list, idx) in lists" :key="idx" :id="'uni-indexed-list-' + idx"> + <!-- #endif --> + <indexed-list-item :list="list" :loaded="loaded" :idx="idx" :showSelect="showSelect" + @itemClick="onClick"></indexed-list-item> + <!-- #ifndef APP-NVUE --> + </view> + </scroll-view> + <!-- #endif --> + <!-- #ifdef APP-NVUE --> + </cell> + </list> + <!-- #endif --> + <view class="uni-indexed-list__menu" @touchstart="touchStart" @touchmove.stop.prevent="touchMove" + @touchend="touchEnd" @mousedown.stop="mousedown" @mousemove.stop.prevent="mousemove" + @mouseleave.stop="mouseleave"> + <view v-for="(list, key) in lists" :key="key" class="uni-indexed-list__menu-item" + :class="touchmoveIndex == key ? 'uni-indexed-list__menu--active' : ''"> + <text class="uni-indexed-list__menu-text" + :class="touchmoveIndex == key ? 'uni-indexed-list__menu-text--active' : ''">{{ list.key }}</text> + </view> + </view> + <view v-if="touchmove" class="uni-indexed-list__alert-wrapper"> + <text class="uni-indexed-list__alert">{{ lists[touchmoveIndex].key }}</text> + </view> + </view> +</template> +<script> + import indexedListItem from './uni-indexed-list-item.vue' + // #ifdef APP-NVUE + const dom = weex.requireModule('dom'); + // #endif + // #ifdef APP-PLUS + function throttle(func, delay) { + var prev = Date.now(); + return function() { + var context = this; + var args = arguments; + var now = Date.now(); + if (now - prev >= delay) { + func.apply(context, args); + prev = Date.now(); + } + } + } + + function touchMove(e) { + let pageY = e.touches[0].pageY + let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight) + if (this.touchmoveIndex === index) { + return false + } + let item = this.lists[index] + if (item) { + // #ifndef APP-NVUE + this.scrollViewId = 'uni-indexed-list-' + index + this.touchmoveIndex = index + // #endif + // #ifdef APP-NVUE + dom.scrollToElement(this.$refs['uni-indexed-list-' + index][0], { + animated: false + }) + this.touchmoveIndex = index + // #endif + } + } + const throttleTouchMove = throttle(touchMove, 40) + // #endif + + /** + * IndexedList 索引列表 + * @description 用于展示索引列表 + * @tutorial https://ext.dcloud.net.cn/plugin?id=375 + * @property {Boolean} showSelect = [true|false] 展示模式 + * @value true 展示模式 + * @value false 选择模式 + * @property {Object} options 索引列表需要的数据对象 + * @event {Function} click 点击列表事件 ,返回当前选择项的事件对象 + * @example <uni-indexed-list options="" showSelect="false" @click=""></uni-indexed-list> + */ + export default { + name: 'UniIndexedList', + components: { + indexedListItem + }, + emits: ['click'], + props: { + options: { + type: Array, + default () { + return [] + } + }, + showSelect: { + type: Boolean, + default: false + } + }, + data() { + return { + lists: [], + winHeight: 0, + itemHeight: 0, + winOffsetY: 0, + touchmove: false, + touchmoveIndex: -1, + scrollViewId: '', + touchmovable: true, + loaded: false, + isPC: false + } + }, + watch: { + options: { + handler: function() { + this.setList() + }, + deep: true + } + }, + mounted() { + // #ifdef H5 + this.isPC = this.IsPC() + // #endif + setTimeout(() => { + this.setList() + }, 50) + setTimeout(() => { + this.loaded = true + }, 300); + }, + methods: { + setList() { + let index = 0; + this.lists = [] + this.options.forEach((value) => { + if (value.data.length === 0) { + return + } + let indexBefore = index + let items = value.data.map(item => { + let obj = {} + obj['key'] = value.letter + obj['name'] = item + obj['itemIndex'] = index + index++ + obj.checked = item.checked ? item.checked : false + return obj + }) + this.lists.push({ + title: value.letter, + key: value.letter, + items: items, + itemIndex: indexBefore + }) + }) + // #ifndef APP-NVUE + uni.createSelectorQuery() + .in(this) + .select('#list') + .boundingClientRect() + .exec(ret => { + this.winOffsetY = ret[0].top + this.winHeight = ret[0].height + this.itemHeight = this.winHeight / this.lists.length + }) + // #endif + // #ifdef APP-NVUE + dom.getComponentRect(this.$refs['list'], (res) => { + this.winOffsetY = res.size.top + this.winHeight = res.size.height + this.itemHeight = this.winHeight / this.lists.length + }) + // #endif + }, + touchStart(e) { + this.touchmove = true + let pageY = this.isPC ? e.pageY : e.touches[0].pageY + let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight) + let item = this.lists[index] + if (item) { + this.scrollViewId = 'uni-indexed-list-' + index + this.touchmoveIndex = index + // #ifdef APP-NVUE + dom.scrollToElement(this.$refs['uni-indexed-list-' + index][0], { + animated: false + }) + // #endif + } + }, + touchMove(e) { + // #ifndef APP-PLUS + let pageY = this.isPC ? e.pageY : e.touches[0].pageY + let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight) + if (this.touchmoveIndex === index) { + return false + } + let item = this.lists[index] + if (item) { + this.scrollViewId = 'uni-indexed-list-' + index + this.touchmoveIndex = index + } + // #endif + // #ifdef APP-PLUS + throttleTouchMove.call(this, e) + // #endif + }, + touchEnd() { + this.touchmove = false + // this.touchmoveIndex = -1 + }, + + /** + * 兼容 PC @tian + */ + + mousedown(e) { + if (!this.isPC) return + this.touchStart(e) + }, + mousemove(e) { + if (!this.isPC) return + this.touchMove(e) + }, + mouseleave(e) { + if (!this.isPC) return + this.touchEnd(e) + }, + + // #ifdef H5 + 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; + }, + // #endif + + + onClick(e) { + let { + idx, + index + } = e + let obj = {} + for (let key in this.lists[idx].items[index]) { + obj[key] = this.lists[idx].items[index][key] + } + let select = [] + if (this.showSelect) { + this.lists[idx].items[index].checked = !this.lists[idx].items[index].checked + this.lists.forEach((value, idx) => { + value.items.forEach((item, index) => { + if (item.checked) { + let obj = {} + for (let key in this.lists[idx].items[index]) { + obj[key] = this.lists[idx].items[index][key] + } + select.push(obj) + } + }) + }) + } + this.$emit('click', { + item: obj, + select: select + }) + } + } + } +</script> +<style lang="scss" > + .uni-indexed-list { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + } + + .uni-indexed-list__scroll { + flex: 1; + } + + .uni-indexed-list__menu { + width: 24px; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + } + + .uni-indexed-list__menu-item { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex: 1; + align-items: center; + justify-content: center; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + + .uni-indexed-list__menu-text { + font-size: 12px; + text-align: center; + color: #aaa; + } + + .uni-indexed-list__menu--active { + // background-color: rgb(200, 200, 200); + } + + .uni-indexed-list__menu--active {} + + .uni-indexed-list__menu-text--active { + border-radius: 16px; + width: 16px; + height: 16px; + line-height: 16px; + background-color: #007aff; + color: #fff; + } + + .uni-indexed-list__alert-wrapper { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + align-items: center; + justify-content: center; + } + + .uni-indexed-list__alert { + width: 80px; + height: 80px; + border-radius: 80px; + text-align: center; + line-height: 80px; + font-size: 35px; + color: #fff; + background-color: rgba(0, 0, 0, 0.5); + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/package.json new file mode 100644 index 000000000..125c0e7f6 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-indexed-list/readme.md new file mode 100644 index 000000000..44ad84b28 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-link/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-link/changelog.md new file mode 100644 index 000000000..2cfbf5912 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-link/components/uni-link/uni-link.vue b/yudao-ui-admin-uniapp/uni_modules/uni-link/components/uni-link/uni-link.vue new file mode 100644 index 000000000..27c5468e1 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-link/components/uni-link/uni-link.vue @@ -0,0 +1,128 @@ +<template> + <a v-if="isShowA" class="uni-link" :href="href" + :class="{'uni-link--withline':showUnderLine===true||showUnderLine==='true'}" + :style="{color,fontSize:fontSize+'px'}" :download="download"> + <slot>{{text}}</slot> + </a> + <!-- #ifndef APP-NVUE --> + <text v-else class="uni-link" :class="{'uni-link--withline':showUnderLine===true||showUnderLine==='true'}" + :style="{color,fontSize:fontSize+'px'}" @click="openURL"> + <slot>{{text}}</slot> + </text> + <!-- #endif --> + <!-- #ifdef APP-NVUE --> + <text v-else class="uni-link" :class="{'uni-link--withline':showUnderLine===true||showUnderLine==='true'}" + :style="{color,fontSize:fontSize+'px'}" @click="openURL"> + {{text}} + </text> + <!-- #endif --> +</template> + +<script> + /** + * Link 外部网页超链接组件 + * @description uni-link是一个外部网页超链接组件,在小程序内复制url,在app内打开外部浏览器,在h5端打开新网页 + * @tutorial https://ext.dcloud.net.cn/plugin?id=1182 + * @property {String} href 点击后打开的外部网页url + * @property {String} text 显示的文字 + * @property {String} downlaod H5平台下载文件名 + * @property {Boolean} showUnderLine 是否显示下划线 + * @property {String} copyTips 在小程序端复制链接时显示的提示语 + * @property {String} color 链接文字颜色 + * @property {String} fontSize 链接文字大小 + * @example * <uni-link href="https://ext.dcloud.net.cn" text="https://ext.dcloud.net.cn"></uni-link> + */ + export default { + name: 'uniLink', + props: { + href: { + type: String, + default: '' + }, + text: { + type: String, + default: '' + }, + download: { + type: String, + default: '' + }, + showUnderLine: { + type: [Boolean, String], + default: true + }, + copyTips: { + type: String, + default: '已自动复制网址,请在手机浏览器里粘贴该网址' + }, + color: { + type: String, + default: '#999999' + }, + fontSize: { + type: [Number, String], + default: 14 + } + }, + computed: { + isShowA() { + // #ifdef H5 + this._isH5 = true; + // #endif + if ((this.isMail() || this.isTel()) && this._isH5 === true) { + return true; + } + return false; + } + }, + created() { + this._isH5 = null; + }, + methods: { + isMail() { + return this.href.startsWith('mailto:'); + }, + isTel() { + return this.href.startsWith('tel:'); + }, + openURL() { + // #ifdef APP-PLUS + if (this.isTel()) { + this.makePhoneCall(this.href.replace('tel:', '')); + } else { + plus.runtime.openURL(this.href); + } + // #endif + // #ifdef H5 + window.open(this.href) + // #endif + // #ifdef MP + uni.setClipboardData({ + data: this.href + }); + uni.showModal({ + content: this.copyTips, + showCancel: false + }); + // #endif + }, + makePhoneCall(phoneNumber) { + uni.makePhoneCall({ + phoneNumber + }) + } + } + } +</script> + +<style> + /* #ifndef APP-NVUE */ + .uni-link { + cursor: pointer; + } + + /* #endif */ + .uni-link--withline { + text-decoration: underline; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-link/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-link/package.json new file mode 100644 index 000000000..77b198652 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-link/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-link/readme.md new file mode 100644 index 000000000..7f09e941a --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-list/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-list/changelog.md new file mode 100644 index 000000000..6aa6e4e00 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-list/changelog.md @@ -0,0 +1,20 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue b/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue new file mode 100644 index 000000000..b9349c29a --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue @@ -0,0 +1,107 @@ +<template> + <!-- #ifdef APP-NVUE --> + <cell> + <!-- #endif --> + <view class="uni-list-ad"> + <view v-if="borderShow" :class="{'uni-list--border':border,'uni-list-item--first':isFirstChild}"></view> + <ad style="width: 200px;height: 300px;border-width: 1px;border-color: red;border-style: solid;" adpid="1111111111" + unit-id="" appid="" apid="" type="feed" @error="aderror" @close="closeAd"></ad> + </view> + <!-- #ifdef APP-NVUE --> + </cell> + <!-- #endif --> + +</template> + +<script> + // #ifdef APP-NVUE + const dom = uni.requireNativePlugin('dom'); + // #endif + export default { + name: 'UniListAd', + props: { + title: { + type: String, + default: '', + + } + }, + // inject: ['list'], + data() { + return { + isFirstChild: false, + border: false, + borderShow: true, + } + }, + + mounted() { + this.list = this.getForm() + if (this.list) { + if (!this.list.firstChildAppend) { + this.list.firstChildAppend = true + this.isFirstChild = true + } + this.border = this.list.border + } + }, + methods: { + /** + * 获取父元素实例 + */ + getForm(name = 'uniList') { + 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; + }, + aderror(e) { + console.log("aderror: " + JSON.stringify(e.detail)); + }, + closeAd(e) { + this.borderShow = false + } + } + } +</script> + +<style lang="scss" > + .uni-list-ad { + position: relative; + border: 1px red solid; + } + + .uni-list--border { + position: relative; + padding-bottom: 1px; + /* #ifdef APP-PLUS */ + border-top-color: $uni-border-color; + border-top-style: solid; + border-top-width: 0.5px; + /* #endif */ + margin-left: $uni-spacing-row-lg; + } + + /* #ifndef APP-NVUE */ + .uni-list--border:after { + position: absolute; + top: 0; + right: 0; + left: 0; + height: 1px; + content: ''; + -webkit-transform: scaleY(.5); + transform: scaleY(.5); + background-color: $uni-border-color; + } + + .uni-list-item--first:after { + height: 0px; + } + + /* #endif */ +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss b/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss new file mode 100644 index 000000000..311f8d9fa --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue b/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue new file mode 100644 index 000000000..2b3100859 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue @@ -0,0 +1,538 @@ +<template> + <!-- #ifdef APP-NVUE --> + <cell> + <!-- #endif --> + <view :hover-class="!clickable && !link ? '' : 'uni-list-chat--hover'" class="uni-list-chat" @click.stop="onClick"> + <view :class="{ 'uni-list--border': border, 'uni-list-chat--first': isFirstChild }"></view> + <view class="uni-list-chat__container"> + <view class="uni-list-chat__header-warp"> + <view v-if="avatarCircle || avatarList.length === 0" class="uni-list-chat__header" :class="{ 'header--circle': avatarCircle }"> + <image class="uni-list-chat__header-image" :class="{ 'header--circle': avatarCircle }" :src="avatar" mode="aspectFill"></image> + </view> + <!-- 头像组 --> + <view v-else class="uni-list-chat__header"> + <view v-for="(item, index) in avatarList" :key="index" class="uni-list-chat__header-box" :class="computedAvatar" + :style="{ width: imageWidth + 'px', height: imageWidth + 'px' }"> + <image class="uni-list-chat__header-image" :style="{ width: imageWidth + 'px', height: imageWidth + 'px' }" :src="item.url" + mode="aspectFill"></image> + </view> + </view> + </view> + <view v-if="badgeText && badgePositon === 'left'" class="uni-list-chat__badge uni-list-chat__badge-pos" :class="[isSingle]"> + <text class="uni-list-chat__badge-text">{{ badgeText === 'dot' ? '' : badgeText }}</text> + </view> + <view class="uni-list-chat__content"> + <view class="uni-list-chat__content-main"> + <text class="uni-list-chat__content-title uni-ellipsis">{{ title }}</text> + <text class="uni-list-chat__content-note uni-ellipsis">{{ note }}</text> + </view> + <view class="uni-list-chat__content-extra"> + <slot> + <text class="uni-list-chat__content-extra-text">{{ time }}</text> + <view v-if="badgeText && badgePositon === 'right'" class="uni-list-chat__badge" :class="[isSingle, badgePositon === 'right' ? 'uni-list-chat--right' : '']"> + <text class="uni-list-chat__badge-text">{{ badgeText === 'dot' ? '' : badgeText }}</text> + </view> + </slot> + </view> + </view> + </view> + </view> + <!-- #ifdef APP-NVUE --> + </cell> + <!-- #endif --> +</template> + +<script> + // 头像大小 + const avatarWidth = 45; + + /** + * ListChat 聊天列表 + * @description 聊天列表,用于创建聊天类列表 + * @tutorial https://ext.dcloud.net.cn/plugin?id=24 + * @property {String} title 标题 + * @property {String} note 描述 + * @property {Boolean} clickable = [true|false] 是否开启点击反馈,默认为false + * @property {String} badgeText 数字角标内容 + * @property {String} badgePositon = [left|right] 角标位置,默认为 right + * @property {String} link = [false|navigateTo|redirectTo|reLaunch|switchTab] 是否展示右侧箭头并开启点击反馈,默认为false + * @value false 不开启 + * @value navigateTo 同 uni.navigateTo() + * @value redirectTo 同 uni.redirectTo() + * @value reLaunch 同 uni.reLaunch() + * @value switchTab 同 uni.switchTab() + * @property {String | PageURIString} to 跳转目标页面 + * @property {String} time 右侧时间显示 + * @property {Boolean} avatarCircle = [true|false] 是否显示圆形头像,默认为false + * @property {String} avatar 头像地址,avatarCircle 不填时生效 + * @property {Array} avatarList 头像组,格式为 [{url:''}] + * @event {Function} click 点击 uniListChat 触发事件 + */ + export default { + name: 'UniListChat', + emits:['click'], + props: { + title: { + type: String, + default: '' + }, + note: { + type: String, + default: '' + }, + clickable: { + type: Boolean, + default: false + }, + link: { + type: [Boolean, String], + default: false + }, + to: { + type: String, + default: '' + }, + badgeText: { + type: [String, Number], + default: '' + }, + badgePositon: { + type: String, + default: 'right' + }, + time: { + type: String, + default: '' + }, + avatarCircle: { + type: Boolean, + default: false + }, + avatar: { + type: String, + default: '' + }, + avatarList: { + type: Array, + default () { + return []; + } + } + }, + // inject: ['list'], + computed: { + isSingle() { + if (this.badgeText === 'dot') { + return 'uni-badge--dot'; + } else { + const badgeText = this.badgeText.toString(); + if (badgeText.length > 1) { + return 'uni-badge--complex'; + } else { + return 'uni-badge--single'; + } + } + }, + computedAvatar() { + if (this.avatarList.length > 4) { + this.imageWidth = avatarWidth * 0.31; + return 'avatarItem--3'; + } else if (this.avatarList.length > 1) { + this.imageWidth = avatarWidth * 0.47; + return 'avatarItem--2'; + } else { + this.imageWidth = avatarWidth; + return 'avatarItem--1'; + } + } + }, + data() { + return { + isFirstChild: false, + border: true, + // avatarList: 3, + imageWidth: 50 + }; + }, + mounted() { + this.list = this.getForm() + if (this.list) { + if (!this.list.firstChildAppend) { + this.list.firstChildAppend = true; + this.isFirstChild = true; + } + this.border = this.list.border; + } + }, + methods: { + /** + * 获取父元素实例 + */ + getForm(name = 'uniList') { + 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; + }, + onClick() { + if (this.to !== '') { + this.openPage(); + return; + } + + if (this.clickable || this.link) { + this.$emit('click', { + data: {} + }); + } + }, + openPage() { + if (['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'].indexOf(this.link) !== -1) { + this.pageApi(this.link); + } else { + this.pageApi('navigateTo'); + } + }, + pageApi(api) { + uni[api]({ + url: this.to, + success: res => { + this.$emit('click', { + data: res + }); + }, + fail: err => { + this.$emit('click', { + data: err + }); + console.error(err.errMsg); + } + }); + } + } + }; +</script> + +<style lang="scss" > + $uni-font-size-lg:16px; + $uni-spacing-row-sm: 5px; + $uni-spacing-row-base: 10px; + $uni-spacing-row-lg: 15px; + $background-color: #fff; + $divide-line-color: #e5e5e5; + $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; + $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; + + .uni-list-chat { + font-size: $uni-font-size-lg; + position: relative; + flex-direction: column; + justify-content: space-between; + background-color: $background-color; + } + + // .uni-list-chat--disabled { + // opacity: 0.3; + // } + + .uni-list-chat--hover { + background-color: $hover; + } + + .uni-list--border { + position: relative; + margin-left: $uni-spacing-row-lg; + /* #ifdef APP-PLUS */ + border-top-color: $divide-line-color; + border-top-style: solid; + border-top-width: 0.5px; + /* #endif */ + } + + /* #ifndef APP-NVUE */ + .uni-list--border:after { + position: absolute; + top: 0; + right: 0; + left: 0; + height: 1px; + content: ''; + -webkit-transform: scaleY(0.5); + transform: scaleY(0.5); + background-color: $divide-line-color; + } + + .uni-list-item--first:after { + height: 0px; + } + + /* #endif */ + + .uni-list-chat--first { + border-top-width: 0px; + } + + .uni-ellipsis { + /* #ifndef APP-NVUE */ + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + /* #endif */ + /* #ifdef APP-NVUE */ + lines: 1; + /* #endif */ + } + + .uni-ellipsis-2 { + /* #ifndef APP-NVUE */ + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + /* #endif */ + + /* #ifdef APP-NVUE */ + lines: 2; + /* #endif */ + } + + .uni-list-chat__container { + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + flex: 1; + padding: $uni-spacing-row-base $uni-spacing-row-lg; + position: relative; + overflow: hidden; + } + + .uni-list-chat__header-warp { + position: relative; + } + + .uni-list-chat__header { + /* #ifndef APP-NVUE */ + display: flex; + align-content: center; + /* #endif */ + flex-direction: row; + justify-content: center; + align-items: center; + flex-wrap: wrap-reverse; + /* #ifdef APP-NVUE */ + width: 50px; + height: 50px; + /* #endif */ + /* #ifndef APP-NVUE */ + width: $avatar-width; + height: $avatar-width; + /* #endif */ + + border-radius: $avatar-border-radius; + border-color: $avatar-border-color; + border-width: $avatar-border-width; + border-style: solid; + overflow: hidden; + } + + .uni-list-chat__header-box { + /* #ifndef APP-PLUS */ + box-sizing: border-box; + display: flex; + width: $avatar-width; + height: $avatar-width; + /* #endif */ + /* #ifdef APP-NVUE */ + width: 50px; + height: 50px; + /* #endif */ + overflow: hidden; + border-radius: 2px; + } + + .uni-list-chat__header-image { + margin: 1px; + /* #ifdef APP-NVUE */ + width: 50px; + height: 50px; + /* #endif */ + /* #ifndef APP-NVUE */ + width: $avatar-width; + height: $avatar-width; + /* #endif */ + } + + /* #ifndef APP-NVUE */ + .uni-list-chat__header-image { + display: block; + width: 100%; + height: 100%; + } + + .avatarItem--1 { + width: 100%; + height: 100%; + } + + .avatarItem--2 { + width: 47%; + height: 47%; + } + + .avatarItem--3 { + width: 32%; + height: 32%; + } + + /* #endif */ + .header--circle { + border-radius: 50%; + } + + .uni-list-chat__content { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + flex: 1; + overflow: hidden; + padding: 2px 0; + } + + .uni-list-chat__content-main { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + justify-content: space-between; + padding-left: $uni-spacing-row-base; + flex: 1; + overflow: hidden; + } + + .uni-list-chat__content-title { + font-size: $title-size; + color: $title-color; + font-weight: $title-weight; + overflow: hidden; + } + + .uni-list-chat__content-note { + margin-top: 3px; + color: $note-color; + font-size: $note-size; + font-weight: $title-weight; + overflow: hidden; + } + + .uni-list-chat__content-extra { + /* #ifndef APP-NVUE */ + flex-shrink: 0; + display: flex; + /* #endif */ + flex-direction: column; + justify-content: space-between; + align-items: flex-end; + margin-left: 5px; + } + + .uni-list-chat__content-extra-text { + color: $right-text-color; + font-size: $right-text-size; + font-weight: $right-text-weight; + overflow: hidden; + } + + .uni-list-chat__badge-pos { + position: absolute; + /* #ifdef APP-NVUE */ + left: 55px; + top: 3px; + /* #endif */ + /* #ifndef APP-NVUE */ + left: calc(#{$avatar-width} + 10px - #{$badge-space} + #{$badge-left}); + top: calc(#{$uni-spacing-row-base}/ 2 + 1px + #{$badge-top}); + /* #endif */ + } + + .uni-list-chat__badge { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + justify-content: center; + align-items: center; + border-radius: 100px; + background-color: $badge-background-color; + } + + .uni-list-chat__badge-text { + color: $badge-color; + font-size: $badge-font; + } + + .uni-badge--single { + /* #ifndef APP-NVUE */ + // left: calc(#{$avatar-width} + 7px + #{$badge-left}); + /* #endif */ + width: $badge-size; + height: $badge-size; + } + + .uni-badge--complex { + /* #ifdef APP-NVUE */ + left: 50px; + /* #endif */ + /* #ifndef APP-NVUE */ + width: auto; + /* #endif */ + height: $badge-size; + padding: 0 $badge-space; + } + + .uni-badge--dot { + /* #ifdef APP-NVUE */ + left: 60px; + top: 6px; + /* #endif */ + /* #ifndef APP-NVUE */ + left: calc(#{$avatar-width} + 15px - #{$dot-width}/ 2 + 1px + #{$badge-left}); + /* #endif */ + width: $dot-width; + height: $dot-height; + padding: 0; + } + + .uni-list-chat--right { + /* #ifdef APP-NVUE */ + left: 0; + /* #endif */ + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue b/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue new file mode 100644 index 000000000..2c7d9ea7c --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue @@ -0,0 +1,454 @@ +<template> + <!-- #ifdef APP-NVUE --> + <cell> + <!-- #endif --> + + <view :class="{ 'uni-list-item--disabled': disabled }" + :hover-class="(!clickable && !link) || disabled || showSwitch ? '' : 'uni-list-item--hover'" + class="uni-list-item" @click="onClick"> + <view v-if="!isFirstChild" class="border--left" :class="{ 'uni-list--border': border }"></view> + <view class="uni-list-item__container" + :class="{ 'container--right': showArrow || link, 'flex--direction': direction === 'column' }"> + <slot name="header"> + <view class="uni-list-item__header"> + <view v-if="thumb" class="uni-list-item__icon"> + <image :src="thumb" class="uni-list-item__icon-img" :class="['uni-list--' + thumbSize]" /> + </view> + <view v-else-if="showExtraIcon" class="uni-list-item__icon"> + <uni-icons :color="extraIcon.color" :size="extraIcon.size" :type="extraIcon.type" /> + </view> + </view> + </slot> + <slot name="body"> + <view class="uni-list-item__content" + :class="{ 'uni-list-item__content--center': thumb || showExtraIcon || showBadge || showSwitch }"> + <text v-if="title" class="uni-list-item__content-title" + :class="[ellipsis !== 0 && ellipsis <= 2 ? 'uni-ellipsis-' + ellipsis : '']">{{ title }}</text> + <text v-if="note" class="uni-list-item__content-note">{{ note }}</text> + </view> + </slot> + <slot name="footer"> + <view v-if="rightText || showBadge || showSwitch" class="uni-list-item__extra" + :class="{ 'flex--justify': direction === 'column' }"> + <text v-if="rightText" class="uni-list-item__extra-text">{{ rightText }}</text> + <uni-badge v-if="showBadge" :type="badgeType" :text="badgeText" :custom-style="badgeStyle" /> + <switch v-if="showSwitch" :disabled="disabled" :checked="switchChecked" + @change="onSwitchChange" /> + </view> + </slot> + </view> + <uni-icons v-if="showArrow || link" :size="16" class="uni-icon-wrapper" color="#bbb" type="arrowright" /> + </view> + <!-- #ifdef APP-NVUE --> + </cell> + <!-- #endif --> +</template> + +<script> + /** + * ListItem 列表子组件 + * @description 列表子组件 + * @tutorial https://ext.dcloud.net.cn/plugin?id=24 + * @property {String} title 标题 + * @property {String} note 描述 + * @property {String} thumb 左侧缩略图,若thumb有值,则不会显示扩展图标 + * @property {String} thumbSize = [lg|base|sm] 略缩图大小 + * @value lg 大图 + * @value base 一般 + * @value sm 小图 + * @property {String} badgeText 数字角标内容 + * @property {String} badgeType 数字角标类型,参考[uni-icons](https://ext.dcloud.net.cn/plugin?id=21) + * @property {Object} badgeStyle 数字角标样式 + * @property {String} rightText 右侧文字内容 + * @property {Boolean} disabled = [true|false] 是否禁用 + * @property {Boolean} clickable = [true|false] 是否开启点击反馈 + * @property {String} link = [navigateTo|redirectTo|reLaunch|switchTab] 是否展示右侧箭头并开启点击反馈 + * @value navigateTo 同 uni.navigateTo() + * @value redirectTo 同 uni.redirectTo() + * @value reLaunch 同 uni.reLaunch() + * @value switchTab 同 uni.switchTab() + * @property {String | PageURIString} to 跳转目标页面 + * @property {Boolean} showBadge = [true|false] 是否显示数字角标 + * @property {Boolean} showSwitch = [true|false] 是否显示Switch + * @property {Boolean} switchChecked = [true|false] Switch是否被选中 + * @property {Boolean} showExtraIcon = [true|false] 左侧是否显示扩展图标 + * @property {Object} extraIcon 扩展图标参数,格式为 {color: '#4cd964',size: '22',type: 'spinner'} + * @property {String} direction = [row|column] 排版方向 + * @value row 水平排列 + * @value column 垂直排列 + * @event {Function} click 点击 uniListItem 触发事件 + * @event {Function} switchChange 点击切换 Switch 时触发 + */ + export default { + name: 'UniListItem', + emits: ['click', 'switchChange'], + props: { + direction: { + type: String, + default: 'row' + }, + title: { + type: String, + default: '' + }, + note: { + type: String, + default: '' + }, + ellipsis: { + type: [Number,String], + default: 0 + }, + disabled: { + type: [Boolean, String], + default: false + }, + clickable: { + type: Boolean, + default: false + }, + showArrow: { + type: [Boolean, String], + default: false + }, + link: { + type: [Boolean, String], + default: false + }, + to: { + type: String, + default: '' + }, + showBadge: { + type: [Boolean, String], + default: false + }, + showSwitch: { + type: [Boolean, String], + default: false + }, + switchChecked: { + type: [Boolean, String], + default: false + }, + badgeText: { + type: String, + default: '' + }, + badgeType: { + type: String, + default: 'success' + }, + badgeStyle:{ + type: Object, + default () { + return {} + } + }, + rightText: { + type: String, + default: '' + }, + thumb: { + type: String, + default: '' + }, + thumbSize: { + type: String, + default: 'base' + }, + showExtraIcon: { + type: [Boolean, String], + default: false + }, + extraIcon: { + type: Object, + default () { + return { + type: '', + color: '#000000', + size: 20 + }; + } + }, + border: { + type: Boolean, + default: true + } + }, + // inject: ['list'], + data() { + return { + isFirstChild: false + }; + }, + mounted() { + this.list = this.getForm() + // 判断是否存在 uni-list 组件 + if (this.list) { + if (!this.list.firstChildAppend) { + this.list.firstChildAppend = true; + this.isFirstChild = true; + } + } + }, + methods: { + /** + * 获取父元素实例 + */ + getForm(name = 'uniList') { + 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; + }, + onClick() { + if (this.to !== '') { + this.openPage(); + return; + } + if (this.clickable || this.link) { + this.$emit('click', { + data: {} + }); + } + }, + onSwitchChange(e) { + this.$emit('switchChange', e.detail); + }, + openPage() { + if (['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'].indexOf(this.link) !== -1) { + this.pageApi(this.link); + } else { + this.pageApi('navigateTo'); + } + }, + pageApi(api) { + let callback = { + url: this.to, + success: res => { + this.$emit('click', { + data: res + }); + }, + fail: err => { + this.$emit('click', { + data: err + }); + } + } + switch (api) { + case 'navigateTo': + uni.navigateTo(callback) + break + case 'redirectTo': + uni.redirectTo(callback) + break + case 'reLaunch': + uni.reLaunch(callback) + break + case 'switchTab': + uni.switchTab(callback) + break + default: + uni.navigateTo(callback) + } + } + } + }; +</script> + +<style lang="scss"> + $uni-font-size-sm:12px; + $uni-font-size-base:14px; + $uni-font-size-lg:16px; + $uni-spacing-col-lg: 12px; + $uni-spacing-row-lg: 15px; + $uni-img-size-sm:20px; + $uni-img-size-base:26px; + $uni-img-size-lg:40px; + $uni-border-color:#e5e5e5; + $uni-bg-color-hover:#f1f1f1; + $uni-text-color-grey:#999; + $list-item-pd: $uni-spacing-col-lg $uni-spacing-row-lg; + .uni-list-item { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + font-size: $uni-font-size-lg; + position: relative; + justify-content: space-between; + align-items: center; + background-color: #fff; + flex-direction: row; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + .uni-list-item--disabled { + opacity: 0.3; + } + .uni-list-item--hover { + background-color: $uni-bg-color-hover; + } + .uni-list-item__container { + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + padding: $list-item-pd; + padding-left: $uni-spacing-row-lg; + flex: 1; + overflow: hidden; + // align-items: center; + } + .container--right { + padding-right: 0; + } + // .border--left { + // margin-left: $uni-spacing-row-lg; + // } + .uni-list--border { + position: absolute; + top: 0; + right: 0; + left: 0; + /* #ifdef APP-NVUE */ + border-top-color: $uni-border-color; + border-top-style: solid; + border-top-width: 0.5px; + /* #endif */ + } + /* #ifndef APP-NVUE */ + .uni-list--border:after { + position: absolute; + top: 0; + right: 0; + left: 0; + height: 1px; + content: ''; + -webkit-transform: scaleY(0.5); + transform: scaleY(0.5); + background-color: $uni-border-color; + } + /* #endif */ + .uni-list-item__content { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + padding-right: 8px; + flex: 1; + color: #3b4144; + // overflow: hidden; + flex-direction: column; + justify-content: space-between; + overflow: hidden; + } + .uni-list-item__content--center { + justify-content: center; + } + .uni-list-item__content-title { + font-size: $uni-font-size-base; + color: #3b4144; + overflow: hidden; + } + .uni-list-item__content-note { + margin-top: 6rpx; + color: $uni-text-color-grey; + font-size: $uni-font-size-sm; + overflow: hidden; + } + .uni-list-item__extra { + // width: 25%; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + justify-content: flex-end; + align-items: center; + } + .uni-list-item__header { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + align-items: center; + } + .uni-list-item__icon { + margin-right: 18rpx; + flex-direction: row; + justify-content: center; + align-items: center; + } + .uni-list-item__icon-img { + /* #ifndef APP-NVUE */ + display: block; + /* #endif */ + height: $uni-img-size-base; + width: $uni-img-size-base; + margin-right: 10px; + } + .uni-icon-wrapper { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + align-items: center; + padding: 0 10px; + } + .flex--direction { + flex-direction: column; + /* #ifndef APP-NVUE */ + align-items: initial; + /* #endif */ + } + .flex--justify { + /* #ifndef APP-NVUE */ + justify-content: initial; + /* #endif */ + } + .uni-list--lg { + height: $uni-img-size-lg; + width: $uni-img-size-lg; + } + .uni-list--base { + height: $uni-img-size-base; + width: $uni-img-size-base; + } + .uni-list--sm { + height: $uni-img-size-sm; + width: $uni-img-size-sm; + } + .uni-list-item__extra-text { + color: $uni-text-color-grey; + font-size: $uni-font-size-sm; + } + .uni-ellipsis-1 { + /* #ifndef APP-NVUE */ + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + /* #endif */ + /* #ifdef APP-NVUE */ + lines: 1; + text-overflow:ellipsis; + /* #endif */ + } + .uni-ellipsis-2 { + /* #ifndef APP-NVUE */ + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + /* #endif */ + /* #ifdef APP-NVUE */ + lines: 2; + text-overflow:ellipsis; + /* #endif */ + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list/uni-list.vue b/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list/uni-list.vue new file mode 100644 index 000000000..ecda67653 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list/uni-list.vue @@ -0,0 +1,108 @@ +<template> + <!-- #ifndef APP-NVUE --> + <view class="uni-list uni-border-top-bottom"> + <view v-if="border" class="uni-list--border-top"></view> + <slot /> + <view v-if="border" class="uni-list--border-bottom"></view> + </view> + <!-- #endif --> + <!-- #ifdef APP-NVUE --> + <list class="uni-list" :class="{ 'uni-list--border': border }" :enableBackToTop="enableBackToTop" loadmoreoffset="15"><slot /></list> + <!-- #endif --> +</template> + +<script> +/** + * List 列表 + * @description 列表组件 + * @tutorial https://ext.dcloud.net.cn/plugin?id=24 + * @property {String} border = [true|false] 标题 + */ +export default { + name: 'uniList', + 'mp-weixin': { + options: { + multipleSlots: false + } + }, + props: { + enableBackToTop: { + type: [Boolean, String], + default: false + }, + scrollY: { + type: [Boolean, String], + default: false + }, + border: { + type: Boolean, + default: true + } + }, + // provide() { + // return { + // list: this + // }; + // }, + created() { + this.firstChildAppend = false; + }, + methods: { + loadMore(e) { + this.$emit('scrolltolower'); + } + } +}; +</script> +<style lang="scss" > +$uni-bg-color:#ffffff; +$uni-border-color:#e5e5e5; +.uni-list { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + background-color: $uni-bg-color; + position: relative; + flex-direction: column; +} + +.uni-list--border { + position: relative; + /* #ifdef APP-NVUE */ + border-top-color: $uni-border-color; + border-top-style: solid; + border-top-width: 0.5px; + border-bottom-color: $uni-border-color; + border-bottom-style: solid; + border-bottom-width: 0.5px; + /* #endif */ + z-index: -1; +} + +/* #ifndef APP-NVUE */ + +.uni-list--border-top { + position: absolute; + top: 0; + right: 0; + left: 0; + height: 1px; + -webkit-transform: scaleY(0.5); + transform: scaleY(0.5); + background-color: $uni-border-color; + z-index: 1; +} + +.uni-list--border-bottom { + position: absolute; + bottom: 0; + right: 0; + left: 0; + height: 1px; + -webkit-transform: scaleY(0.5); + transform: scaleY(0.5); + background-color: $uni-border-color; +} + +/* #endif */ +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list/uni-refresh.vue b/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list/uni-refresh.vue new file mode 100644 index 000000000..3b4c5a230 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list/uni-refresh.vue @@ -0,0 +1,65 @@ +<template> + <!-- #ifdef APP-NVUE --> + <refresh :display="display" @refresh="onrefresh" @pullingdown="onpullingdown"> + <slot /> + </refresh> + <!-- #endif --> + <!-- #ifndef APP-NVUE --> + <view ref="uni-refresh" class="uni-refresh" v-show="isShow"> + <slot /> + </view> + <!-- #endif --> +</template> + +<script> + export default { + name: 'UniRefresh', + props: { + display: { + type: [String], + default: "hide" + } + }, + data() { + return { + pulling: false + } + }, + computed: { + isShow() { + if (this.display === "show" || this.pulling === true) { + return true; + } + return false; + } + }, + created() {}, + methods: { + onchange(value) { + this.pulling = value; + }, + onrefresh(e) { + this.$emit("refresh", e); + }, + onpullingdown(e) { + // #ifdef APP-NVUE + this.$emit("pullingdown", e); + // #endif + // #ifndef APP-NVUE + var detail = { + viewHeight: 90, + pullingDistance: e.height + } + this.$emit("pullingdown", detail); + // #endif + } + } + } +</script> + +<style> + .uni-refresh { + height: 0; + overflow: hidden; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list/uni-refresh.wxs b/yudao-ui-admin-uniapp/uni_modules/uni-list/components/uni-list/uni-refresh.wxs new file mode 100644 index 000000000..818a6b721 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-list/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-list/package.json new file mode 100644 index 000000000..66e8bef0c --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-list/package.json @@ -0,0 +1,91 @@ +{ + "id": "uni-list", + "displayName": "uni-list 列表", + "version": "1.2.1", + "description": "List 组件 ,帮助使用者快速构建列表。", + "keywords": [ + "", + "uni-ui", + "uniui", + "列表", + "", + "list" +], + "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-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/yudao-ui-admin-uniapp/uni_modules/uni-list/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-list/readme.md new file mode 100644 index 000000000..32c28654e --- /dev/null +++ b/yudao-ui-admin-uniapp/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 +<uni-list> + <uni-list-item title="列表文字" ></uni-list-item> + <uni-list-item :disabled="true" title="列表禁用状态" ></uni-list-item> +</uni-list> + +``` + +### 多行内容显示 + +- 设置 `note` 属性 ,可以在第二行显示描述文本信息 + +```html +<uni-list> + <uni-list-item title="列表文字" note="列表描述信息"></uni-list-item> + <uni-list-item :disabled="true" title="列表文字" note="列表禁用状态"></uni-list-item> +</uni-list> + +``` + +### 右侧显示角标、switch + +- 设置 `show-badge` 属性 ,可以显示角标内容 +- 设置 `show-switch` 属性,可以显示 switch 开关 + +```html +<uni-list> + <uni-list-item title="列表右侧显示角标" :show-badge="true" badge-text="12" ></uni-list-item> + <uni-list-item title="列表右侧显示 switch" :show-switch="true" @switchChange="switchChange" ></uni-list-item> +</uni-list> + +``` + +### 左侧显示略缩图、图标 + +- 设置 `thumb` 属性 ,可以在列表左侧显示略缩图 +- 设置 `show-extra-icon` 属性,并指定 `extra-icon` 可以在左侧显示图标 + +```html + <uni-list> + <uni-list-item title="列表左侧带略缩图" note="列表描述信息" thumb="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" + thumb-size="lg" rightText="右侧文字"></uni-list-item> + <uni-list-item :show-extra-icon="true" :extra-icon="extraIcon1" title="列表左侧带扩展图标" ></uni-list-item> +</uni-list> +``` + +### 开启点击反馈和右侧箭头 +- 设置 `clickable` 为 `true` ,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 `click` 事件 +- 设置 `link` 属性,会自动开启点击反馈,并给列表右侧添加一个箭头 +- 设置 `to` 属性,可以跳转页面,`link` 的值表示跳转方式,如果不指定,默认为 `navigateTo` + +```html + +<uni-list> + <uni-list-item title="开启点击反馈" clickable @click="onClick" ></uni-list-item> + <uni-list-item title="默认 navigateTo 方式跳转页面" link to="/pages/vue/index/index" @click="onClick($event,1)" ></uni-list-item> + <uni-list-item title="reLaunch 方式跳转页面" link="reLaunch" to="/pages/vue/index/index" @click="onClick($event,1)" ></uni-list-item> +</uni-list> + +``` + + +### 聊天列表示例 +- 设置 `clickable` 为 `true` ,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 `click` 事件 +- 设置 `link` 属性,会自动开启点击反馈,`link` 的值表示跳转方式,如果不指定,默认为 `navigateTo` +- 设置 `to` 属性,可以跳转页面 +- `time` 属性,通常会设置成时间显示,但是这个属性不仅仅可以设置时间,你可以传入任何文本,注意文本长度可能会影响显示 +- `avatar` 和 `avatarList` 属性同时只会有一个生效,同时设置的话,`avatarList` 属性的长度大于1 ,`avatar` 属性将失效 +- 可以通过默认插槽自定义列表右侧内容 + +```html + +<uni-list> + <uni-list :border="true"> + <!-- 显示圆形头像 --> + <uni-list-chat :avatar-circle="true" title="uni-app" avatar="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" note="您收到一条新的消息" time="2020-02-02 20:20" ></uni-list-chat> + <!-- 右侧带角标 --> + <uni-list-chat title="uni-app" avatar="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" note="您收到一条新的消息" time="2020-02-02 20:20" badge-text="12" :badge-style="{backgroundColor:'#FF80AB'}"></uni-list-chat> + <!-- 头像显示圆点 --> + <uni-list-chat title="uni-app" avatar="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" note="您收到一条新的消息" time="2020-02-02 20:20" badge-positon="left" badge-text="dot"></uni-list-chat> + <!-- 头像显示角标 --> + <uni-list-chat title="uni-app" avatar="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" note="您收到一条新的消息" time="2020-02-02 20:20" badge-positon="left" badge-text="99"></uni-list-chat> + <!-- 显示多头像 --> + <uni-list-chat title="uni-app" :avatar-list="avatarList" note="您收到一条新的消息" time="2020-02-02 20:20" badge-positon="left" badge-text="dot"></uni-list-chat> + <!-- 自定义右侧内容 --> + <uni-list-chat title="uni-app" :avatar-list="avatarList" note="您收到一条新的消息" time="2020-02-02 20:20" badge-positon="left" badge-text="dot"> + <view class="chat-custom-right"> + <text class="chat-custom-text">刚刚</text> + <!-- 需要使用 uni-icons 请自行引入 --> + <uni-icons type="star-filled" color="#999" size="18"></uni-icons> + </view> + </uni-list-chat> + </uni-list> +</uni-list> + +``` + +```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 +<uni-list> + <uni-list-item title="自定义右侧插槽" note="列表描述信息" link> + <template slot="header"> + <image class="slot-image" src="/static/logo.png" mode="widthFix"></image> + </template> + </uni-list-item> + <uni-list-item> + <!-- 自定义 header --> + <view slot="header" class="slot-box"><image class="slot-image" src="/static/logo.png" mode="widthFix"></image></view> + <!-- 自定义 body --> + <text slot="body" class="slot-box slot-text">自定义插槽</text> + <!-- 自定义 footer--> + <template slot="footer"> + <image class="slot-image" src="/static/logo.png" mode="widthFix"></image> + </template> + </uni-list-item> +</uni-list> +``` + + + + + +### 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/yudao-ui-admin-uniapp/uni_modules/uni-load-more/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-load-more/changelog.md new file mode 100644 index 000000000..8f03f1d57 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json b/yudao-ui-admin-uniapp/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json new file mode 100644 index 000000000..a4f14a545 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js b/yudao-ui-admin-uniapp/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js new file mode 100644 index 000000000..de7509c87 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json b/yudao-ui-admin-uniapp/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json new file mode 100644 index 000000000..f15d51050 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json b/yudao-ui-admin-uniapp/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json new file mode 100644 index 000000000..a255c6ded --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue b/yudao-ui-admin-uniapp/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue new file mode 100644 index 000000000..e5eff4d65 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue @@ -0,0 +1,399 @@ +<template> + <view class="uni-load-more" @click="onClick"> + <!-- #ifdef APP-NVUE --> + <loading-indicator v-if="!webviewHide && status === 'loading' && showIcon" + :style="{color: color,width:iconSize+'px',height:iconSize+'px'}" :animating="true" + class="uni-load-more__img uni-load-more__img--nvue"></loading-indicator> + <!-- #endif --> + <!-- #ifdef H5 --> + <svg width="24" height="24" viewBox="25 25 50 50" + v-if="!webviewHide && (iconType==='circle' || iconType==='auto' && platform === 'android') && status === 'loading' && showIcon" + :style="{width:iconSize+'px',height:iconSize+'px'}" + class="uni-load-more__img uni-load-more__img--android-H5"> + <circle cx="50" cy="50" r="20" fill="none" :style="{color:color}" :stroke-width="3"></circle> + </svg> + <!-- #endif --> + <!-- #ifndef APP-NVUE || H5 --> + <view + v-if="!webviewHide && (iconType==='circle' || iconType==='auto' && platform === 'android') && status === 'loading' && showIcon" + :style="{width:iconSize+'px',height:iconSize+'px'}" + class="uni-load-more__img uni-load-more__img--android-MP"> + <view class="uni-load-more__img-icon" :style="{borderTopColor:color,borderTopWidth:iconSize/12}"></view> + <view class="uni-load-more__img-icon" :style="{borderTopColor:color,borderTopWidth:iconSize/12}"></view> + <view class="uni-load-more__img-icon" :style="{borderTopColor:color,borderTopWidth:iconSize/12}"></view> + </view> + <!-- #endif --> + <!-- #ifndef APP-NVUE --> + <view v-else-if="!webviewHide && status === 'loading' && showIcon" + :style="{width:iconSize+'px',height:iconSize+'px'}" class="uni-load-more__img uni-load-more__img--ios-H5"> + <image :src="imgBase64" mode="widthFix"></image> + </view> + <!-- #endif --> + <text v-if="showText" class="uni-load-more__text" + :style="{color: color}">{{ status === 'more' ? contentdownText : status === 'loading' ? contentrefreshText : contentnomoreText }}</text> + </view> +</template> + +<script> + let platform + setTimeout(() => { + platform = uni.getSystemInfoSync().platform + }, 16) + + import { + initVueI18n + } from '@dcloudio/uni-i18n' + import messages from './i18n/index.js' + const { + t + } = initVueI18n(messages) + + /** + * LoadMore 加载更多 + * @description 用于列表中,做滚动加载使用,展示 loading 的各种状态 + * @tutorial https://ext.dcloud.net.cn/plugin?id=29 + * @property {String} status = [more|loading|noMore] loading 的状态 + * @value more loading前 + * @value loading loading中 + * @value noMore 没有更多了 + * @property {Number} iconSize 指定图标大小 + * @property {Boolean} iconSize = [true|false] 是否显示 loading 图标 + * @property {String} iconType = [snow|circle|auto] 指定图标样式 + * @value snow ios雪花加载样式 + * @value circle 安卓唤醒加载样式 + * @value auto 根据平台自动选择加载样式 + * @property {String} color 图标和文字颜色 + * @property {Object} contentText 各状态文字说明,值为:{contentdown: "上拉显示更多",contentrefresh: "正在加载...",contentnomore: "没有更多数据了"} + * @event {Function} clickLoadMore 点击加载更多时触发 + */ + export default { + name: 'UniLoadMore', + emits: ['clickLoadMore'], + props: { + status: { + // 上拉的状态:more-loading前;loading-loading中;noMore-没有更多了 + type: String, + default: 'more' + }, + showIcon: { + type: Boolean, + default: true + }, + iconType: { + type: String, + default: 'auto' + }, + iconSize: { + type: Number, + default: 24 + }, + color: { + type: String, + default: '#777777' + }, + contentText: { + type: Object, + default () { + return { + contentdown: '', + contentrefresh: '', + contentnomore: '' + } + } + }, + showText: { + type: Boolean, + default: true + } + }, + data() { + return { + webviewHide: false, + platform: platform, + imgBase64: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QzlBMzU3OTlEOUM0MTFFOUI0NTZDNERBQURBQzI4RkUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QzlBMzU3OUFEOUM0MTFFOUI0NTZDNERBQURBQzI4RkUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDOUEzNTc5N0Q5QzQxMUU5QjQ1NkM0REFBREFDMjhGRSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDOUEzNTc5OEQ5QzQxMUU5QjQ1NkM0REFBREFDMjhGRSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pt+ALSwAAA6CSURBVHja1FsLkFZV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' + } + }, + computed: { + iconSnowWidth() { + return (Math.floor(this.iconSize / 24) || 1) * 2 + }, + contentdownText() { + return this.contentText.contentdown || t("uni-load-more.contentdown") + }, + contentrefreshText() { + return this.contentText.contentrefresh || t("uni-load-more.contentrefresh") + }, + contentnomoreText() { + return this.contentText.contentnomore || t("uni-load-more.contentnomore") + } + }, + mounted() { + // #ifdef APP-PLUS + var pages = getCurrentPages(); + var page = pages[pages.length - 1]; + var currentWebview = page.$getAppWebview(); + currentWebview.addEventListener('hide', () => { + this.webviewHide = true + }) + currentWebview.addEventListener('show', () => { + this.webviewHide = false + }) + // #endif + }, + methods: { + onClick() { + this.$emit('clickLoadMore', { + detail: { + status: this.status, + } + }) + } + } + } +</script> + +<style lang="scss" > + .uni-load-more { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + height: 40px; + align-items: center; + justify-content: center; + } + + .uni-load-more__text { + font-size: 14px; + margin-left: 8px; + } + + .uni-load-more__img { + width: 24px; + height: 24px; + // margin-right: 8px; + } + + .uni-load-more__img--nvue { + color: #666666; + } + + .uni-load-more__img--android, + .uni-load-more__img--ios { + width: 24px; + height: 24px; + transform: rotate(0deg); + } + + /* #ifndef APP-NVUE */ + .uni-load-more__img--android { + animation: loading-ios 1s 0s linear infinite; + } + + @keyframes loading-android { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } + } + + .uni-load-more__img--ios-H5 { + position: relative; + animation: loading-ios-H5 1s 0s step-end infinite; + } + + .uni-load-more__img--ios-H5 image { + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + } + + @keyframes loading-ios-H5 { + 0% { + transform: rotate(0deg); + } + + 8% { + transform: rotate(30deg); + } + + 16% { + transform: rotate(60deg); + } + + 24% { + transform: rotate(90deg); + } + + 32% { + transform: rotate(120deg); + } + + 40% { + transform: rotate(150deg); + } + + 48% { + transform: rotate(180deg); + } + + 56% { + transform: rotate(210deg); + } + + 64% { + transform: rotate(240deg); + } + + 73% { + transform: rotate(270deg); + } + + 82% { + transform: rotate(300deg); + } + + 91% { + transform: rotate(330deg); + } + + 100% { + transform: rotate(360deg); + } + } + + /* #endif */ + + /* #ifdef H5 */ + .uni-load-more__img--android-H5 { + animation: loading-android-H5-rotate 2s linear infinite; + transform-origin: center center; + } + + .uni-load-more__img--android-H5 circle { + display: inline-block; + animation: loading-android-H5-dash 1.5s ease-in-out infinite; + stroke: currentColor; + stroke-linecap: round; + } + + @keyframes loading-android-H5-rotate { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } + } + + @keyframes loading-android-H5-dash { + 0% { + stroke-dasharray: 1, 200; + stroke-dashoffset: 0; + } + + 50% { + stroke-dasharray: 90, 150; + stroke-dashoffset: -40; + } + + 100% { + stroke-dasharray: 90, 150; + stroke-dashoffset: -120; + } + } + + /* #endif */ + + /* #ifndef APP-NVUE || H5 */ + .uni-load-more__img--android-MP { + position: relative; + width: 24px; + height: 24px; + transform: rotate(0deg); + animation: loading-ios 1s 0s ease infinite; + } + + .uni-load-more__img--android-MP .uni-load-more__img-icon { + position: absolute; + box-sizing: border-box; + width: 100%; + height: 100%; + border-radius: 50%; + border: solid 2px transparent; + border-top: solid 2px #777777; + transform-origin: center; + } + + .uni-load-more__img--android-MP .uni-load-more__img-icon:nth-child(1) { + animation: loading-android-MP-1 1s 0s linear infinite; + } + + .uni-load-more__img--android-MP .uni-load-more__img-icon:nth-child(2) { + animation: loading-android-MP-2 1s 0s linear infinite; + } + + .uni-load-more__img--android-MP .uni-load-more__img-icon:nth-child(3) { + animation: loading-android-MP-3 1s 0s linear infinite; + } + + @keyframes loading-android { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } + } + + @keyframes loading-android-MP-1 { + 0% { + transform: rotate(0deg); + } + + 50% { + transform: rotate(90deg); + } + + 100% { + transform: rotate(360deg); + } + } + + @keyframes loading-android-MP-2 { + 0% { + transform: rotate(0deg); + } + + 50% { + transform: rotate(180deg); + } + + 100% { + transform: rotate(360deg); + } + } + + @keyframes loading-android-MP-3 { + 0% { + transform: rotate(0deg); + } + + 50% { + transform: rotate(270deg); + } + + 100% { + transform: rotate(360deg); + } + } + + /* #endif */ +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-load-more/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-load-more/package.json new file mode 100644 index 000000000..2fa6f040a --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-load-more/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-load-more/readme.md new file mode 100644 index 000000000..54dc1fad2 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/changelog.md new file mode 100644 index 000000000..f0f6b5661 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/changelog.md @@ -0,0 +1,41 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue b/yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue new file mode 100644 index 000000000..cbfc16859 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue @@ -0,0 +1,348 @@ +<template> + <view class="uni-navbar" :class="{'uni-dark':dark}"> + <view :class="{ 'uni-navbar--fixed': fixed, 'uni-navbar--shadow': shadow, 'uni-navbar--border': border }" + :style="{ 'background-color': themeBgColor }" class="uni-navbar__content"> + <status-bar v-if="statusBar" /> + <view :style="{ color: themeColor,backgroundColor: themeBgColor ,height:navbarHeight}" + class="uni-navbar__header"> + <view @tap="onClickLeft" class="uni-navbar__header-btns uni-navbar__header-btns-left" + :style="{width:leftIconWidth}"> + <slot name="left"> + <view class="uni-navbar__content_view" v-if="leftIcon.length > 0"> + <uni-icons :color="themeColor" :type="leftIcon" size="20" /> + </view> + <view :class="{ 'uni-navbar-btn-icon-left': !leftIcon.length > 0 }" class="uni-navbar-btn-text" + v-if="leftText.length"> + <text :style="{ color: themeColor, fontSize: '12px' }">{{ leftText }}</text> + </view> + </slot> + </view> + <view class="uni-navbar__header-container " @tap="onClickTitle"> + <slot> + <view class="uni-navbar__header-container-inner" v-if="title.length>0"> + <text class="uni-nav-bar-text uni-ellipsis-1" + :style="{color: themeColor }">{{ title }}</text> + </view> + </slot> + </view> + <view @click="onClickRight" class="uni-navbar__header-btns uni-navbar__header-btns-right" + :style="{width:rightIconWidth}"> + <slot name="right"> + <view v-if="rightIcon.length"> + <uni-icons :color="themeColor" :type="rightIcon" size="22" /> + </view> + <view class="uni-navbar-btn-text" v-if="rightText.length && !rightIcon.length"> + <text class="uni-nav-bar-right-text" :style="{ color: themeColor}">{{ rightText }}</text> + </view> + </slot> + </view> + </view> + </view> + <view class="uni-navbar__placeholder" v-if="fixed"> + <status-bar v-if="statusBar" /> + <view class="uni-navbar__placeholder-view" :style="{ height:navbarHeight}" /> + </view> + </view> +</template> + +<script> + import statusBar from "./uni-status-bar.vue"; + const getVal = (val) => typeof val === 'number' ? val + 'px' : val; + + /** + * NavBar 自定义导航栏 + * @description 导航栏组件,主要用于头部导航 + * @tutorial https://ext.dcloud.net.cn/plugin?id=52 + * @property {Boolean} dark 开启黑暗模式 + * @property {String} title 标题文字 + * @property {String} leftText 左侧按钮文本 + * @property {String} rightText 右侧按钮文本 + * @property {String} leftIcon 左侧按钮图标(图标类型参考 [Icon 图标](http://ext.dcloud.net.cn/plugin?id=28) type 属性) + * @property {String} rightIcon 右侧按钮图标(图标类型参考 [Icon 图标](http://ext.dcloud.net.cn/plugin?id=28) type 属性) + * @property {String} color 图标和文字颜色 + * @property {String} backgroundColor 导航栏背景颜色 + * @property {Boolean} fixed = [true|false] 是否固定顶部 + * @property {Boolean} statusBar = [true|false] 是否包含状态栏 + * @property {Boolean} shadow = [true|false] 导航栏下是否有阴影 + * @property {Boolean} stat 是否开启统计标题上报 + * @event {Function} clickLeft 左侧按钮点击时触发 + * @event {Function} clickRight 右侧按钮点击时触发 + * @event {Function} clickTitle 中间标题点击时触发 + */ + export default { + name: "UniNavBar", + components: { + statusBar + }, + emits: ['clickLeft', 'clickRight', 'clickTitle'], + props: { + dark: { + type: Boolean, + default: false + }, + title: { + type: String, + default: "" + }, + leftText: { + type: String, + default: "" + }, + rightText: { + type: String, + default: "" + }, + leftIcon: { + type: String, + default: "" + }, + rightIcon: { + type: String, + default: "" + }, + fixed: { + type: [Boolean, String], + default: false + }, + color: { + type: String, + default: "" + }, + backgroundColor: { + type: String, + default: "" + }, + statusBar: { + type: [Boolean, String], + default: false + }, + shadow: { + type: [Boolean, String], + default: false + }, + border: { + type: [Boolean, String], + default: true + }, + height: { + type: [Number, String], + default: 44 + }, + leftWidth: { + type: [Number, String], + default: 60 + }, + rightWidth: { + type: [Number, String], + default: 60 + }, + stat: { + type: [Boolean, String], + default: '' + } + }, + computed: { + themeBgColor() { + if (this.dark) { + // 默认值 + if (this.backgroundColor) { + return this.backgroundColor + } else { + return this.dark ? '#333' : '#FFF' + } + } + return this.backgroundColor || '#FFF' + }, + themeColor() { + if (this.dark) { + // 默认值 + if (this.color) { + return this.color + } else { + return this.dark ? '#fff' : '#333' + } + } + return this.color || '#333' + }, + navbarHeight() { + return getVal(this.height) + }, + leftIconWidth() { + return getVal(this.leftWidth) + }, + rightIconWidth() { + return getVal(this.rightWidth) + } + }, + mounted() { + if (uni.report && this.stat && this.title !== '') { + uni.report('title', this.title) + } + }, + methods: { + onClickLeft() { + this.$emit("clickLeft"); + }, + onClickRight() { + this.$emit("clickRight"); + }, + onClickTitle() { + this.$emit("clickTitle"); + } + } + }; +</script> + +<style lang="scss" scoped> + $nav-height: 44px; + + .uni-navbar { + // box-sizing: border-box; + } + + .uni-nav-bar-text { + /* #ifdef APP-PLUS */ + font-size: 34rpx; + /* #endif */ + /* #ifndef APP-PLUS */ + font-size: 14px; + /* #endif */ + } + + .uni-nav-bar-right-text { + font-size: 12px; + } + + .uni-navbar__content { + position: relative; + // background-color: #fff; + // box-sizing: border-box; + background-color: transparent; + } + + .uni-navbar__content_view { + // box-sizing: border-box; + } + + .uni-navbar-btn-text { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + justify-content: flex-start; + align-items: center; + line-height: 12px; + } + + .uni-navbar__header { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + padding: 0 10px; + flex-direction: row; + height: $nav-height; + font-size: 12px; + } + + .uni-navbar__header-btns { + /* #ifndef APP-NVUE */ + overflow: hidden; + display: flex; + /* #endif */ + flex-wrap: nowrap; + flex-direction: row; + width: 120rpx; + // padding: 0 6px; + justify-content: center; + align-items: center; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + + .uni-navbar__header-btns-left { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + width: 120rpx; + justify-content: flex-start; + align-items: center; + } + + .uni-navbar__header-btns-right { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + // width: 150rpx; + // padding-right: 30rpx; + justify-content: flex-end; + align-items: center; + } + + .uni-navbar__header-container { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex: 1; + padding: 0 10px; + overflow: hidden; + } + + .uni-navbar__header-container-inner { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex: 1; + flex-direction: row; + align-items: center; + justify-content: center; + font-size: 12px; + overflow: hidden; + // box-sizing: border-box; + } + + + .uni-navbar__placeholder-view { + height: $nav-height; + } + + .uni-navbar--fixed { + position: fixed; + z-index: 998; + /* #ifdef H5 */ + left: var(--window-left); + right: var(--window-right); + /* #endif */ + /* #ifndef H5 */ + left: 0; + right: 0; + /* #endif */ + + } + + .uni-navbar--shadow { + box-shadow: 0 1px 6px #ccc; + } + + .uni-navbar--border { + border-bottom-width: 1rpx; + border-bottom-style: solid; + border-bottom-color: #eee; + } + + .uni-ellipsis-1 { + overflow: hidden; + /* #ifndef APP-NVUE */ + white-space: nowrap; + text-overflow: ellipsis; + /* #endif */ + /* #ifdef APP-NVUE */ + lines: 1; + text-overflow: ellipsis; + /* #endif */ + } + + // 暗主题配置 + .uni-dark {} +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue b/yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue new file mode 100644 index 000000000..6a688744f --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue @@ -0,0 +1,27 @@ +<template> + <view :style="{ height: statusBarHeight }" class="uni-status-bar"> + <slot /> + </view> +</template> + +<script> + export default { + name: 'UniStatusBar', + data() { + return { + statusBarHeight: 20 + } + }, + mounted() { + this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight + 'px' + } + } +</script> + +<style lang="scss" > + .uni-status-bar { + // width: 750rpx; + height: 20px; + // height: var(--status-bar-height); + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/package.json new file mode 100644 index 000000000..e3fe073d4 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/package.json @@ -0,0 +1,89 @@ +{ + "id": "uni-nav-bar", + "displayName": "uni-nav-bar 自定义导航栏", + "version": "1.3.6", + "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" + } + } + } + } +} \ No newline at end of file diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-nav-bar/readme.md new file mode 100644 index 000000000..3934b3277 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-notice-bar/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-notice-bar/changelog.md new file mode 100644 index 000000000..9ee75a017 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-notice-bar/changelog.md @@ -0,0 +1,16 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue b/yudao-ui-admin-uniapp/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue new file mode 100644 index 000000000..1d2ac1dc1 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue @@ -0,0 +1,395 @@ +<template> + <view v-if="show" class="uni-noticebar" :style="{ backgroundColor: backgroundColor }" @click="onClick"> + <uni-icons v-if="showIcon === true || showIcon === 'true'" class="uni-noticebar-icon" type="sound" + :color="color" size="22" /> + <view ref="textBox" class="uni-noticebar__content-wrapper" + :class="{'uni-noticebar__content-wrapper--scrollable':scrollable, 'uni-noticebar__content-wrapper--single':!scrollable && (single || moreText)}"> + <view :id="elIdBox" class="uni-noticebar__content" + :class="{'uni-noticebar__content--scrollable':scrollable, 'uni-noticebar__content--single':!scrollable && (single || moreText)}"> + <text :id="elId" ref="animationEle" class="uni-noticebar__content-text" + :class="{'uni-noticebar__content-text--scrollable':scrollable,'uni-noticebar__content-text--single':!scrollable && (single || showGetMore)}" + :style="{color:color, width:wrapWidth+'px', 'animationDuration': animationDuration, '-webkit-animationDuration': animationDuration ,animationPlayState: webviewHide?'paused':animationPlayState,'-webkit-animationPlayState':webviewHide?'paused':animationPlayState, animationDelay: animationDelay, '-webkit-animationDelay':animationDelay}">{{text}}</text> + </view> + </view> + <view v-if="showGetMore === true || showGetMore === 'true'" class="uni-noticebar__more uni-cursor-point" + @click="clickMore"> + <text v-if="moreText.length > 0" :style="{ color: moreColor }" class="uni-noticebar__more-text">{{ moreText }}</text> + <uni-icons v-else type="right" :color="moreColor" size="16" /> + </view> + <view class="uni-noticebar-close uni-cursor-point" v-if="(showClose === true || showClose === 'true') && (showGetMore === false || showGetMore === 'false')"> + <uni-icons + type="closeempty" :color="color" size="16" @click="close" /> + </view> + </view> +</template> + +<script> + // #ifdef APP-NVUE + const dom = weex.requireModule('dom'); + const animation = weex.requireModule('animation'); + // #endif + + /** + * NoticeBar 自定义导航栏 + * @description 通告栏组件 + * @tutorial https://ext.dcloud.net.cn/plugin?id=30 + * @property {Number} speed 文字滚动的速度,默认100px/秒 + * @property {String} text 显示文字 + * @property {String} backgroundColor 背景颜色 + * @property {String} color 文字颜色 + * @property {String} moreColor 查看更多文字的颜色 + * @property {String} moreText 设置“查看更多”的文本 + * @property {Boolean} single = [true|false] 是否单行 + * @property {Boolean} scrollable = [true|false] 是否滚动,为true时,NoticeBar为单行 + * @property {Boolean} showIcon = [true|false] 是否显示左侧喇叭图标 + * @property {Boolean} showClose = [true|false] 是否显示左侧关闭按钮 + * @property {Boolean} showGetMore = [true|false] 是否显示右侧查看更多图标,为true时,NoticeBar为单行 + * @event {Function} click 点击 NoticeBar 触发事件 + * @event {Function} close 关闭 NoticeBar 触发事件 + * @event {Function} getmore 点击”查看更多“时触发事件 + */ + + export default { + name: 'UniNoticeBar', + emits: ['click', 'getmore', 'close'], + props: { + text: { + type: String, + default: '' + }, + moreText: { + type: String, + default: '' + }, + backgroundColor: { + type: String, + default: '#FFF9EA' + }, + speed: { + // 默认1s滚动100px + type: Number, + default: 100 + }, + color: { + type: String, + default: '#FF9A43' + }, + moreColor: { + type: String, + default: '#FF9A43' + }, + single: { + // 是否单行 + type: [Boolean, String], + default: false + }, + scrollable: { + // 是否滚动,添加后控制单行效果取消 + type: [Boolean, String], + default: false + }, + showIcon: { + // 是否显示左侧icon + type: [Boolean, String], + default: false + }, + showGetMore: { + // 是否显示右侧查看更多 + type: [Boolean, String], + default: false + }, + showClose: { + // 是否显示左侧关闭按钮 + type: [Boolean, String], + default: false + } + }, + data() { + const elId = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}` + const elIdBox = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}` + return { + textWidth: 0, + boxWidth: 0, + wrapWidth: '', + webviewHide: false, + // #ifdef APP-NVUE + stopAnimation: false, + // #endif + elId: elId, + elIdBox: elIdBox, + show: true, + animationDuration: 'none', + animationPlayState: 'paused', + animationDelay: '0s' + } + }, + mounted() { + // #ifdef APP-PLUS + var pages = getCurrentPages(); + var page = pages[pages.length - 1]; + var currentWebview = page.$getAppWebview(); + currentWebview.addEventListener('hide', () => { + this.webviewHide = true + }) + currentWebview.addEventListener('show', () => { + this.webviewHide = false + }) + // #endif + this.$nextTick(() => { + this.initSize() + }) + }, + // #ifdef APP-NVUE + beforeDestroy() { + this.stopAnimation = true + }, + // #endif + methods: { + initSize() { + if (this.scrollable) { + // #ifndef APP-NVUE + let query = [], + boxWidth = 0, + textWidth = 0; + let textQuery = new Promise((resolve, reject) => { + uni.createSelectorQuery() + // #ifndef MP-ALIPAY + .in(this) + // #endif + .select(`#${this.elId}`) + .boundingClientRect() + .exec(ret => { + this.textWidth = ret[0].width + resolve() + }) + }) + let boxQuery = new Promise((resolve, reject) => { + uni.createSelectorQuery() + // #ifndef MP-ALIPAY + .in(this) + // #endif + .select(`#${this.elIdBox}`) + .boundingClientRect() + .exec(ret => { + this.boxWidth = ret[0].width + resolve() + }) + }) + query.push(textQuery) + query.push(boxQuery) + Promise.all(query).then(() => { + this.animationDuration = `${this.textWidth / this.speed}s` + this.animationDelay = `-${this.boxWidth / this.speed}s` + setTimeout(() => { + this.animationPlayState = 'running' + }, 1000) + }) + // #endif + // #ifdef APP-NVUE + dom.getComponentRect(this.$refs['animationEle'], (res) => { + let winWidth = uni.getSystemInfoSync().windowWidth + this.textWidth = res.size.width + animation.transition(this.$refs['animationEle'], { + styles: { + transform: `translateX(-${winWidth}px)` + }, + duration: 0, + timingFunction: 'linear', + delay: 0 + }, () => { + if (!this.stopAnimation) { + animation.transition(this.$refs['animationEle'], { + styles: { + transform: `translateX(-${this.textWidth}px)` + }, + timingFunction: 'linear', + duration: (this.textWidth - winWidth) / this.speed * 1000, + delay: 1000 + }, () => { + if (!this.stopAnimation) { + this.loopAnimation() + } + }); + } + }); + }) + // #endif + } + // #ifdef APP-NVUE + if (!this.scrollable && (this.single || this.moreText)) { + dom.getComponentRect(this.$refs['textBox'], (res) => { + this.wrapWidth = res.size.width + }) + } + // #endif + }, + loopAnimation() { + // #ifdef APP-NVUE + animation.transition(this.$refs['animationEle'], { + styles: { + transform: `translateX(0px)` + }, + duration: 0 + }, () => { + if (!this.stopAnimation) { + animation.transition(this.$refs['animationEle'], { + styles: { + transform: `translateX(-${this.textWidth}px)` + }, + duration: this.textWidth / this.speed * 1000, + timingFunction: 'linear', + delay: 0 + }, () => { + if (!this.stopAnimation) { + this.loopAnimation() + } + }); + } + }); + // #endif + }, + clickMore() { + this.$emit('getmore') + }, + close() { + this.show = false; + this.$emit('close') + }, + onClick() { + this.$emit('click') + } + } + } +</script> + +<style lang="scss" > + .uni-noticebar { + /* #ifndef APP-NVUE */ + display: flex; + width: 100%; + box-sizing: border-box; + /* #endif */ + flex-direction: row; + align-items: center; + padding: 10px 12px; + margin-bottom: 10px; + } + + .uni-cursor-point { + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + + .uni-noticebar-close { + margin-left: 8px; + margin-right: 5px; + } + + .uni-noticebar-icon { + margin-right: 5px; + } + + .uni-noticebar__content-wrapper { + flex: 1; + flex-direction: column; + overflow: hidden; + } + + .uni-noticebar__content-wrapper--single { + /* #ifndef APP-NVUE */ + line-height: 18px; + /* #endif */ + } + + .uni-noticebar__content-wrapper--single, + .uni-noticebar__content-wrapper--scrollable { + flex-direction: row; + } + + /* #ifndef APP-NVUE */ + .uni-noticebar__content-wrapper--scrollable { + position: relative; + height: 18px; + } + + /* #endif */ + + .uni-noticebar__content--scrollable { + /* #ifdef APP-NVUE */ + flex: 0; + /* #endif */ + /* #ifndef APP-NVUE */ + flex: 1; + display: block; + overflow: hidden; + /* #endif */ + } + + .uni-noticebar__content--single { + /* #ifndef APP-NVUE */ + display: flex; + flex: none; + width: 100%; + justify-content: center; + /* #endif */ + } + + .uni-noticebar__content-text { + font-size: 14px; + line-height: 18px; + /* #ifndef APP-NVUE */ + word-break: break-all; + /* #endif */ + } + + .uni-noticebar__content-text--single { + /* #ifdef APP-NVUE */ + lines: 1; + /* #endif */ + /* #ifndef APP-NVUE */ + display: block; + width: 100%; + white-space: nowrap; + /* #endif */ + overflow: hidden; + text-overflow: ellipsis; + } + + .uni-noticebar__content-text--scrollable { + /* #ifdef APP-NVUE */ + lines: 1; + padding-left: 750rpx; + /* #endif */ + /* #ifndef APP-NVUE */ + position: absolute; + display: block; + height: 18px; + line-height: 18px; + white-space: nowrap; + padding-left: 100%; + animation: notice 10s 0s linear infinite both; + animation-play-state: paused; + /* #endif */ + } + + .uni-noticebar__more { + /* #ifndef APP-NVUE */ + display: inline-flex; + /* #endif */ + flex-direction: row; + flex-wrap: nowrap; + align-items: center; + padding-left: 5px; + } + + .uni-noticebar__more-text { + font-size: 14px; + } + + @keyframes notice { + 100% { + transform: translate3d(-100%, 0, 0); + } + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-notice-bar/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-notice-bar/package.json new file mode 100644 index 000000000..97719a0ff --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-notice-bar/package.json @@ -0,0 +1,90 @@ +{ + "id": "uni-notice-bar", + "displayName": "uni-notice-bar 通告栏", + "version": "1.2.0", + "description": "NoticeBar 通告栏组件,常用于展示公告信息,可设为滚动公告", + "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/yudao-ui-admin-uniapp/uni_modules/uni-notice-bar/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-notice-bar/readme.md new file mode 100644 index 000000000..fb2ede244 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-number-box/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-number-box/changelog.md new file mode 100644 index 000000000..5925c32a2 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-number-box/changelog.md @@ -0,0 +1,25 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue b/yudao-ui-admin-uniapp/uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue new file mode 100644 index 000000000..e91c03212 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue @@ -0,0 +1,221 @@ +<template> + <view class="uni-numbox"> + <view @click="_calcValue('minus')" class="uni-numbox__minus uni-numbox-btns" :style="{background}"> + <text class="uni-numbox--text" :class="{ 'uni-numbox--disabled': inputValue <= min || disabled }" :style="{color}">-</text> + </view> + <input :disabled="disabled" @focus="_onFocus" @blur="_onBlur" class="uni-numbox__value" type="number" + v-model="inputValue" :style="{background, color}" /> + <view @click="_calcValue('plus')" class="uni-numbox__plus uni-numbox-btns" :style="{background}"> + <text class="uni-numbox--text" :class="{ 'uni-numbox--disabled': inputValue >= max || disabled }" :style="{color}">+</text> + </view> + </view> +</template> +<script> + /** + * NumberBox 数字输入框 + * @description 带加减按钮的数字输入框 + * @tutorial https://ext.dcloud.net.cn/plugin?id=31 + * @property {Number} value 输入框当前值 + * @property {Number} min 最小值 + * @property {Number} max 最大值 + * @property {Number} step 每次点击改变的间隔大小 + * @property {String} background 背景色 + * @property {String} color 字体颜色(前景色) + * @property {Boolean} disabled = [true|false] 是否为禁用状态 + * @event {Function} change 输入框值改变时触发的事件,参数为输入框当前的 value + * @event {Function} focus 输入框聚焦时触发的事件,参数为 event 对象 + * @event {Function} blur 输入框失焦时触发的事件,参数为 event 对象 + */ + + export default { + name: "UniNumberBox", + emits: ['change', 'input', 'update:modelValue', 'blur', 'focus'], + props: { + value: { + type: [Number, String], + default: 1 + }, + modelValue: { + type: [Number, String], + default: 1 + }, + min: { + type: Number, + default: 0 + }, + max: { + type: Number, + default: 100 + }, + step: { + type: Number, + default: 1 + }, + background: { + type: String, + default: '#f5f5f5' + }, + color: { + type: String, + default: '#333' + }, + disabled: { + type: Boolean, + default: false + } + }, + data() { + return { + inputValue: 0 + }; + }, + watch: { + value(val) { + this.inputValue = +val; + }, + modelValue(val) { + this.inputValue = +val; + } + }, + created() { + if (this.value === 1) { + this.inputValue = +this.modelValue; + } + if (this.modelValue === 1) { + this.inputValue = +this.value; + } + }, + methods: { + _calcValue(type) { + if (this.disabled) { + return; + } + const scale = this._getDecimalScale(); + let value = this.inputValue * scale; + let step = this.step * scale; + if (type === "minus") { + value -= step; + if (value < (this.min * scale)) { + return; + } + if (value > (this.max * scale)) { + value = this.max * scale + } + } + + if (type === "plus") { + value += step; + if (value > (this.max * scale)) { + return; + } + if (value < (this.min * scale)) { + value = this.min * scale + } + } + + this.inputValue = (value / scale).toFixed(String(scale).length - 1); + this.$emit("change", +this.inputValue); + // TODO vue2 兼容 + this.$emit("input", +this.inputValue); + // TODO vue3 兼容 + this.$emit("update:modelValue", +this.inputValue); + }, + _getDecimalScale() { + + let scale = 1; + // 浮点型 + if (~~this.step !== this.step) { + scale = Math.pow(10, String(this.step).split(".")[1].length); + } + return scale; + }, + _onBlur(event) { + this.$emit('blur', event) + let value = event.detail.value; + if (isNaN(value)) { + this.inputValue = this.min; + return; + } + value = +value; + if (value > this.max) { + value = this.max; + } else if (value < this.min) { + value = this.min; + } + const scale = this._getDecimalScale(); + this.inputValue = value.toFixed(String(scale).length - 1); + this.$emit("change", +this.inputValue); + this.$emit("input", +this.inputValue); + this.$emit("update:modelValue", +this.inputValue); + }, + _onFocus(event) { + this.$emit('focus', event) + } + } + }; +</script> +<style lang="scss" > + $box-height: 26px; + $bg: #f5f5f5; + $br: 2px; + $color: #333; + + .uni-numbox { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + } + + .uni-numbox-btns { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + align-items: center; + justify-content: center; + padding: 0 8px; + background-color: $bg; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + + .uni-numbox__value { + margin: 0 2px; + background-color: $bg; + width: 40px; + height: $box-height; + text-align: center; + font-size: 14px; + border-left-width: 0; + border-right-width: 0; + color: $color; + } + + .uni-numbox__minus { + border-top-left-radius: $br; + border-bottom-left-radius: $br; + } + + .uni-numbox__plus { + border-top-right-radius: $br; + border-bottom-right-radius: $br; + } + + .uni-numbox--text { + // fix nvue + line-height: 20px; + + font-size: 20px; + font-weight: 300; + color: $color; + } + + .uni-numbox .uni-numbox--disabled { + color: #c0c0c0 !important; + /* #ifdef H5 */ + cursor: not-allowed; + /* #endif */ + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-number-box/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-number-box/package.json new file mode 100644 index 000000000..ad8233685 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-number-box/package.json @@ -0,0 +1,85 @@ +{ + "id": "uni-number-box", + "displayName": "uni-number-box 数字输入框", + "version": "1.2.1", + "description": "NumberBox 带加减按钮的数字输入框组件,用户可以控制每次点击增加的数值,支持小数。", + "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/yudao-ui-admin-uniapp/uni_modules/uni-number-box/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-number-box/readme.md new file mode 100644 index 000000000..affc56fa7 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-pagination/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/changelog.md new file mode 100644 index 000000000..336c2ba6d --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/changelog.md @@ -0,0 +1,20 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/en.json b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/en.json new file mode 100644 index 000000000..a57becdcd --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/en.json @@ -0,0 +1,4 @@ +{ + "uni-pagination.prevText": "prev", + "uni-pagination.nextText": "next" +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/es.json b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/es.json new file mode 100644 index 000000000..ccbba2f63 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/es.json @@ -0,0 +1,4 @@ +{ + "uni-pagination.prevText": "anterior", + "uni-pagination.nextText": "próxima" +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/fr.json b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/fr.json new file mode 100644 index 000000000..9b5f2d92d --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/fr.json @@ -0,0 +1,4 @@ +{ + "uni-pagination.prevText": "précédente", + "uni-pagination.nextText": "suivante" +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/index.js b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/index.js new file mode 100644 index 000000000..2469dd02b --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hans.json b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hans.json new file mode 100644 index 000000000..fedbe82a9 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hans.json @@ -0,0 +1,4 @@ +{ + "uni-pagination.prevText": "上一页", + "uni-pagination.nextText": "下一页" +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hant.json b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hant.json new file mode 100644 index 000000000..133b3404b --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hant.json @@ -0,0 +1,4 @@ +{ + "uni-pagination.prevText": "上一頁", + "uni-pagination.nextText": "下一頁" +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/uni-pagination.vue b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/uni-pagination.vue new file mode 100644 index 000000000..79db4b880 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/components/uni-pagination/uni-pagination.vue @@ -0,0 +1,409 @@ +<template> + <view class="uni-pagination"> + <!-- #ifndef APP-NVUE --> + <view class="uni-pagination__total is-phone-hide">共 {{ total }} 条</view> + <!-- #endif --> + <view class="uni-pagination__btn" + :class="currentIndex === 1 ? 'uni-pagination--disabled' : 'uni-pagination--enabled'" + :hover-class="currentIndex === 1 ? '' : 'uni-pagination--hover'" :hover-start-time="20" + :hover-stay-time="70" @click="clickLeft"> + <template v-if="showIcon === true || showIcon === 'true'"> + <uni-icons color="#666" size="16" type="left" /> + </template> + <template v-else> + <text class="uni-pagination__child-btn">{{ prevPageText }}</text> + </template> + </view> + <view class="uni-pagination__num uni-pagination__num-flex-none"> + <view class="uni-pagination__num-current"> + <text class="uni-pagination__num-current-text is-pc-hide" + style="color:#409EFF">{{ currentIndex }}</text> + <text class="uni-pagination__num-current-text is-pc-hide">/{{ maxPage || 0 }}</text> + <!-- #ifndef APP-NVUE --> + <view v-for="(item, index) in paper" :key="index" :class="{ 'page--active': item === currentIndex }" + class="uni-pagination__num-tag tag--active is-phone-hide" @click.top="selectPage(item, index)"> + <text>{{ item }}</text> + </view> + <!-- #endif --> + + </view> + </view> + <view class="uni-pagination__btn" + :class="currentIndex >= maxPage ? 'uni-pagination--disabled' : 'uni-pagination--enabled'" + :hover-class="currentIndex === maxPage ? '' : 'uni-pagination--hover'" :hover-start-time="20" + :hover-stay-time="70" @click="clickRight"> + <template v-if="showIcon === true || showIcon === 'true'"> + <uni-icons color="#666" size="16" type="right" /> + </template> + <template v-else> + <text class="uni-pagination__child-btn">{{ nextPageText }}</text> + </template> + </view> + </view> +</template> + +<script> + /** + * Pagination 分页器 + * @description 分页器组件,用于展示页码、请求数据等 + * @tutorial https://ext.dcloud.net.cn/plugin?id=32 + * @property {String} prevText 左侧按钮文字 + * @property {String} nextText 右侧按钮文字 + * @property {Number} current 当前页 + * @property {Number} total 数据总量 + * @property {Number} pageSize 每页数据量 + * @property {Number} showIcon = [true|false] 是否以 icon 形式展示按钮 + * @event {Function} change 点击页码按钮时触发 ,e={type,current} current为当前页,type值为:next/prev,表示点击的是上一页还是下一个 + */ + + import { + initVueI18n + } from '@dcloudio/uni-i18n' + import messages from './i18n/index.js' + const { + t + } = initVueI18n(messages) + export default { + name: 'UniPagination', + emits: ['update:modelValue', 'input', 'change'], + props: { + value: { + type: [Number, String], + default: 1 + }, + modelValue: { + type: [Number, String], + default: 1 + }, + prevText: { + type: String, + }, + nextText: { + type: String, + }, + current: { + type: [Number, String], + default: 1 + }, + total: { + // 数据总量 + type: [Number, String], + default: 0 + }, + pageSize: { + // 每页数据量 + type: [Number, String], + default: 10 + }, + showIcon: { + // 是否以 icon 形式展示按钮 + type: [Boolean, String], + default: false + }, + pagerCount: { + type: Number, + default: 7 + } + }, + data() { + return { + currentIndex: 1, + paperData: [] + } + }, + computed: { + prevPageText() { + return this.prevText || t('uni-pagination.prevText') + }, + nextPageText() { + return this.nextText || t('uni-pagination.nextText') + }, + maxPage() { + let maxPage = 1 + let total = Number(this.total) + let pageSize = Number(this.pageSize) + if (total && pageSize) { + maxPage = Math.ceil(total / pageSize) + } + return maxPage + }, + paper() { + const num = this.currentIndex + // TODO 最大页数 + const pagerCount = this.pagerCount + // const total = 181 + const total = this.total + const pageSize = this.pageSize + let totalArr = [] + let showPagerArr = [] + let pagerNum = Math.ceil(total / pageSize) + for (let i = 0; i < pagerNum; i++) { + totalArr.push(i + 1) + } + showPagerArr.push(1) + const totalNum = totalArr[totalArr.length - (pagerCount + 1) / 2] + totalArr.forEach((item, index) => { + if ((pagerCount + 1) / 2 >= num) { + if (item < pagerCount + 1 && item > 1) { + showPagerArr.push(item) + } + } else if (num + 2 <= totalNum) { + if (item > num - (pagerCount + 1) / 2 && item < num + (pagerCount + 1) / 2) { + showPagerArr.push(item) + } + } else { + if ((item > num - (pagerCount + 1) / 2 || pagerNum - pagerCount < item) && item < totalArr[ + totalArr.length - 1]) { + showPagerArr.push(item) + } + } + }) + if (pagerNum > pagerCount) { + if ((pagerCount + 1) / 2 >= num) { + showPagerArr[showPagerArr.length - 1] = '...' + } else if (num + 2 <= totalNum) { + showPagerArr[1] = '...' + showPagerArr[showPagerArr.length - 1] = '...' + } else { + showPagerArr[1] = '...' + } + showPagerArr.push(totalArr[totalArr.length - 1]) + } else { + if ((pagerCount + 1) / 2 >= num) {} else if (num + 2 <= totalNum) {} else { + showPagerArr.shift() + showPagerArr.push(totalArr[totalArr.length - 1]) + } + } + + return showPagerArr + } + }, + watch: { + current: { + immediate: true, + handler(val, old) { + if (val < 1) { + this.currentIndex = 1 + } else { + this.currentIndex = val + } + } + }, + value: { + immediate: true, + handler(val) { + if (Number(this.current) !== 1) return + if (val < 1) { + this.currentIndex = 1 + } else { + this.currentIndex = val + } + } + } + }, + methods: { + // 选择标签 + selectPage(e, index) { + if (parseInt(e)) { + this.currentIndex = e + this.change('current') + } else { + let pagerNum = Math.ceil(this.total / this.pageSize) + // let pagerNum = Math.ceil(181 / this.pageSize) + // 上一页 + if (index <= 1) { + if (this.currentIndex - 5 > 1) { + this.currentIndex -= 5 + } else { + this.currentIndex = 1 + } + return + } + // 下一页 + if (index >= 6) { + if (this.currentIndex + 5 > pagerNum) { + this.currentIndex = pagerNum + } else { + this.currentIndex += 5 + } + return + } + } + }, + clickLeft() { + if (Number(this.currentIndex) === 1) { + return + } + this.currentIndex -= 1 + this.change('prev') + }, + clickRight() { + if (Number(this.currentIndex) >= this.maxPage) { + return + } + this.currentIndex += 1 + this.change('next') + }, + change(e) { + this.$emit('input', this.currentIndex) + this.$emit('update:modelValue', this.currentIndex) + this.$emit('change', { + type: e, + current: this.currentIndex + }) + } + } + } +</script> + +<style lang="scss" > + $uni-primary: #2979ff; + .uni-pagination { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + position: relative; + overflow: hidden; + flex-direction: row; + justify-content: center; + align-items: center; + } + + .uni-pagination__total { + font-size: 14px; + color: #999; + margin-right: 15px; + } + + .uni-pagination__btn { + /* #ifndef APP-NVUE */ + display: flex; + cursor: pointer; + /* #endif */ + padding: 0 8px; + line-height: 30px; + font-size: 12px; + position: relative; + background-color: #F0F0F0; + flex-direction: row; + justify-content: center; + align-items: center; + text-align: center; + border-radius: 5px; + // border-width: 1px; + // border-style: solid; + // border-color: $uni-border-color; + } + + .uni-pagination__child-btn { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + font-size: 12px; + position: relative; + flex-direction: row; + justify-content: center; + align-items: center; + text-align: center; + color: #666; + font-size: 12px; + } + + .uni-pagination__num { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex: 1; + flex-direction: row; + justify-content: center; + align-items: center; + height: 30px; + line-height: 30px; + font-size: 12px; + color: #666; + margin: 0 5px; + } + + .uni-pagination__num-tag { + /* #ifdef H5 */ + cursor: pointer; + min-width: 30px; + /* #endif */ + margin: 0 5px; + height: 30px; + text-align: center; + line-height: 30px; + // border: 1px red solid; + color: #999; + border-radius: 4px; + // border-width: 1px; + // border-style: solid; + // border-color: $uni-border-color; + } + + .uni-pagination__num-current { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + } + + .uni-pagination__num-current-text { + font-size: 15px; + } + + .uni-pagination--enabled { + color: #333333; + opacity: 1; + } + + .uni-pagination--disabled { + opacity: 0.5; + /* #ifdef H5 */ + cursor: default; + /* #endif */ + } + + .uni-pagination--hover { + color: rgba(0, 0, 0, 0.6); + background-color: #eee; + } + + .tag--active:hover { + color: $uni-primary; + } + + .page--active { + color: #fff; + background-color: $uni-primary; + } + + .page--active:hover { + color: #fff; + } + + /* #ifndef APP-NVUE */ + .is-pc-hide { + display: block; + } + + .is-phone-hide { + display: none; + } + + @media screen and (min-width: 450px) { + .is-pc-hide { + display: none; + } + + .is-phone-hide { + display: block; + } + + .uni-pagination__num-flex-none { + flex: none; + } + } + + /* #endif */ +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-pagination/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/package.json new file mode 100644 index 000000000..adce67041 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/package.json @@ -0,0 +1,86 @@ +{ + "id": "uni-pagination", + "displayName": "uni-pagination 分页器", + "version": "1.2.1", + "description": "Pagination 分页器组件,用于展示页码、请求数据等。", + "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/yudao-ui-admin-uniapp/uni_modules/uni-pagination/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/readme.md new file mode 100644 index 000000000..eefa26348 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-pagination/readme.md @@ -0,0 +1,13 @@ + + +## Pagination 分页器 +> **组件名:uni-pagination** +> 代码块: `uPagination` + + +分页器组件,用于展示页码、请求数据等。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-pagination) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-popup/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-popup/changelog.md new file mode 100644 index 000000000..a9e2d6682 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-popup/changelog.md @@ -0,0 +1,60 @@ +## 1.7.9(2022-04-02) +- 修复 弹出层内部无法滚动的bug +## 1.7.8(2022-03-28) +- 修复 小程序中高度错误的bug +## 1.7.7(2022-03-17) +- 修复 快速调用open出现问题的Bug +## 1.7.6(2022-02-14) +- 修复 safeArea 属性不能设置为false的bug +## 1.7.5(2022-01-19) +- 修复 isMaskClick 失效的bug +## 1.7.4(2022-01-19) +- 新增 cancelText \ confirmText 属性 ,可自定义文本 +- 新增 maskBackgroundColor 属性 ,可以修改蒙版颜色 +- 优化 maskClick属性 更新为 isMaskClick ,解决微信小程序警告的问题 +## 1.7.3(2022-01-13) +- 修复 设置 safeArea 属性不生效的bug +## 1.7.2(2021-11-26) +- 优化 组件示例 +## 1.7.1(2021-11-26) +- 修复 vuedoc 文字错误 +## 1.7.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-popup](https://uniapp.dcloud.io/component/uniui/uni-popup) +## 1.6.2(2021-08-24) +- 新增 支持国际化 +## 1.6.1(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.6.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.5.0(2021-06-23) +- 新增 mask-click 遮罩层点击事件 +## 1.4.5(2021-06-22) +- 修复 nvue 平台中间弹出后,点击内容,再点击遮罩无法关闭的Bug +## 1.4.4(2021-06-18) +- 修复 H5平台中间弹出后,点击内容,再点击遮罩无法关闭的Bug +## 1.4.3(2021-06-08) +- 修复 错误的 watch 字段 +- 修复 safeArea 属性不生效的问题 +- 修复 点击内容,再点击遮罩无法关闭的Bug +## 1.4.2(2021-05-12) +- 新增 组件示例地址 +## 1.4.1(2021-04-29) +- 修复 组件内放置 input 、textarea 组件,无法聚焦的问题 +## 1.4.0 (2021-04-29) +- 新增 type 属性的 left\right 值,支持左右弹出 +- 新增 open(String:type) 方法参数 ,可以省略 type 属性 ,直接传入类型打开指定弹窗 +- 新增 backgroundColor 属性,可定义主窗口背景色,默认不显示背景色 +- 新增 safeArea 属性,是否适配底部安全区 +- 修复 App\h5\微信小程序底部安全区占位不对的Bug +- 修复 App 端弹出等待的Bug +- 优化 提升低配设备性能,优化动画卡顿问题 +- 优化 更简单的组件自定义方式 +## 1.2.9(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 +## 1.2.8(2021-02-05) +- 调整为uni_modules目录规范 +## 1.2.7(2021-02-05) +- 调整为uni_modules目录规范 +- 新增 支持 PC 端 +- 新增 uni-popup-message 、uni-popup-dialog扩展组件支持 PC 端 diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js b/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js new file mode 100644 index 000000000..6ef26a262 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup-dialog/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/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue b/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue new file mode 100644 index 000000000..a5d0f2a2d --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue @@ -0,0 +1,271 @@ +<template> + <view class="uni-popup-dialog"> + <view class="uni-dialog-title"> + <text class="uni-dialog-title-text" :class="['uni-popup__'+dialogType]">{{titleText}}</text> + </view> + <view v-if="mode === 'base'" class="uni-dialog-content"> + <slot> + <text class="uni-dialog-content-text">{{content}}</text> + </slot> + </view> + <view v-else class="uni-dialog-content"> + <slot> + <input class="uni-dialog-input" v-model="val" type="text" :placeholder="placeholderText" :focus="focus" > + </slot> + </view> + <view class="uni-dialog-button-group"> + <view class="uni-dialog-button" @click="closeDialog"> + <text class="uni-dialog-button-text">{{closeText}}</text> + </view> + <view class="uni-dialog-button uni-border-left" @click="onOk"> + <text class="uni-dialog-button-text uni-button-color">{{okText}}</text> + </view> + </view> + + </view> +</template> + +<script> + import popup from '../uni-popup/popup.js' + import { + initVueI18n + } from '@dcloudio/uni-i18n' + import messages from '../uni-popup/i18n/index.js' + const { t } = initVueI18n(messages) + /** + * PopUp 弹出层-对话框样式 + * @description 弹出层-对话框样式 + * @tutorial https://ext.dcloud.net.cn/plugin?id=329 + * @property {String} value input 模式下的默认值 + * @property {String} placeholder input 模式下输入提示 + * @property {String} type = [success|warning|info|error] 主题样式 + * @value success 成功 + * @value warning 提示 + * @value info 消息 + * @value error 错误 + * @property {String} mode = [base|input] 模式、 + * @value base 基础对话框 + * @value input 可输入对话框 + * @property {String} content 对话框内容 + * @property {Boolean} beforeClose 是否拦截取消事件 + * @event {Function} confirm 点击确认按钮触发 + * @event {Function} close 点击取消按钮触发 + */ + + export default { + name: "uniPopupDialog", + mixins: [popup], + emits:['confirm','close'], + props: { + value: { + type: [String, Number], + default: '' + }, + placeholder: { + type: [String, Number], + default: '' + }, + type: { + type: String, + default: 'error' + }, + mode: { + type: String, + default: 'base' + }, + title: { + type: String, + default: '' + }, + content: { + type: String, + default: '' + }, + beforeClose: { + type: Boolean, + default: false + }, + cancelText:{ + type: String, + default: '' + }, + confirmText:{ + type: String, + default: '' + } + }, + data() { + return { + dialogType: 'error', + focus: false, + val: "" + } + }, + computed: { + okText() { + return this.confirmText || t("uni-popup.ok") + }, + closeText() { + return this.cancelText || t("uni-popup.cancel") + }, + placeholderText() { + return this.placeholder || t("uni-popup.placeholder") + }, + titleText() { + return this.title || t("uni-popup.title") + } + }, + watch: { + type(val) { + this.dialogType = val + }, + mode(val) { + if (val === 'input') { + this.dialogType = 'info' + } + }, + value(val) { + this.val = val + } + }, + created() { + // 对话框遮罩不可点击 + this.popup.disableMask() + // this.popup.closeMask() + if (this.mode === 'input') { + this.dialogType = 'info' + this.val = this.value + } else { + this.dialogType = this.type + } + }, + mounted() { + this.focus = true + }, + methods: { + /** + * 点击确认按钮 + */ + onOk() { + if (this.mode === 'input'){ + this.$emit('confirm', this.val) + }else{ + this.$emit('confirm') + } + if(this.beforeClose) return + this.popup.close() + }, + /** + * 点击取消按钮 + */ + closeDialog() { + this.$emit('close') + if(this.beforeClose) return + this.popup.close() + }, + close(){ + this.popup.close() + } + } + } +</script> + +<style lang="scss" > + .uni-popup-dialog { + width: 300px; + border-radius: 11px; + background-color: #fff; + } + + .uni-dialog-title { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + justify-content: center; + padding-top: 25px; + } + + .uni-dialog-title-text { + font-size: 16px; + font-weight: 500; + } + + .uni-dialog-content { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + justify-content: center; + align-items: center; + padding: 20px; + } + + .uni-dialog-content-text { + font-size: 14px; + color: #6C6C6C; + } + + .uni-dialog-button-group { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + border-top-color: #f5f5f5; + border-top-style: solid; + border-top-width: 1px; + } + + .uni-dialog-button { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + + flex: 1; + flex-direction: row; + justify-content: center; + align-items: center; + height: 45px; + } + + .uni-border-left { + border-left-color: #f0f0f0; + border-left-style: solid; + border-left-width: 1px; + } + + .uni-dialog-button-text { + font-size: 16px; + color: #333; + } + + .uni-button-color { + color: #007aff; + } + + .uni-dialog-input { + flex: 1; + font-size: 14px; + border: 1px #eee solid; + height: 40px; + padding: 0 10px; + border-radius: 5px; + color: #555; + } + + .uni-popup__success { + color: #4cd964; + } + + .uni-popup__warn { + color: #f0ad4e; + } + + .uni-popup__error { + color: #dd524d; + } + + .uni-popup__info { + color: #909399; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue b/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue new file mode 100644 index 000000000..91370a829 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue @@ -0,0 +1,143 @@ +<template> + <view class="uni-popup-message"> + <view class="uni-popup-message__box fixforpc-width" :class="'uni-popup__'+type"> + <slot> + <text class="uni-popup-message-text" :class="'uni-popup__'+type+'-text'">{{message}}</text> + </slot> + </view> + </view> +</template> + +<script> + import popup from '../uni-popup/popup.js' + /** + * PopUp 弹出层-消息提示 + * @description 弹出层-消息提示 + * @tutorial https://ext.dcloud.net.cn/plugin?id=329 + * @property {String} type = [success|warning|info|error] 主题样式 + * @value success 成功 + * @value warning 提示 + * @value info 消息 + * @value error 错误 + * @property {String} message 消息提示文字 + * @property {String} duration 显示时间,设置为 0 则不会自动关闭 + */ + + export default { + name: 'uniPopupMessage', + mixins:[popup], + props: { + /** + * 主题 success/warning/info/error 默认 success + */ + type: { + type: String, + default: 'success' + }, + /** + * 消息文字 + */ + message: { + type: String, + default: '' + }, + /** + * 显示时间,设置为 0 则不会自动关闭 + */ + duration: { + type: Number, + default: 3000 + }, + maskShow:{ + type:Boolean, + default:false + } + }, + data() { + return {} + }, + created() { + this.popup.maskShow = this.maskShow + this.popup.messageChild = this + }, + methods: { + timerClose(){ + if(this.duration === 0) return + clearTimeout(this.timer) + this.timer = setTimeout(()=>{ + this.popup.close() + },this.duration) + } + } + } +</script> +<style lang="scss" > + .uni-popup-message { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + justify-content: center; + } + + .uni-popup-message__box { + background-color: #e1f3d8; + padding: 10px 15px; + border-color: #eee; + border-style: solid; + border-width: 1px; + flex: 1; + } + + @media screen and (min-width: 500px) { + .fixforpc-width { + margin-top: 20px; + border-radius: 4px; + flex: none; + min-width: 380px; + /* #ifndef APP-NVUE */ + max-width: 50%; + /* #endif */ + /* #ifdef APP-NVUE */ + max-width: 500px; + /* #endif */ + } + } + + .uni-popup-message-text { + font-size: 14px; + padding: 0; + } + + .uni-popup__success { + background-color: #e1f3d8; + } + + .uni-popup__success-text { + color: #67C23A; + } + + .uni-popup__warn { + background-color: #faecd8; + } + + .uni-popup__warn-text { + color: #E6A23C; + } + + .uni-popup__error { + background-color: #fde2e2; + } + + .uni-popup__error-text { + color: #F56C6C; + } + + .uni-popup__info { + background-color: #F2F6FC; + } + + .uni-popup__info-text { + color: #909399; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue b/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue new file mode 100644 index 000000000..5be76247a --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue @@ -0,0 +1,187 @@ +<template> + <view class="uni-popup-share"> + <view class="uni-share-title"><text class="uni-share-title-text">{{shareTitleText}}</text></view> + <view class="uni-share-content"> + <view class="uni-share-content-box"> + <view class="uni-share-content-item" v-for="(item,index) in bottomData" :key="index" @click.stop="select(item,index)"> + <image class="uni-share-image" :src="item.icon" mode="aspectFill"></image> + <text class="uni-share-text">{{item.text}}</text> + </view> + + </view> + </view> + <view class="uni-share-button-box"> + <button class="uni-share-button" @click="close">{{cancelText}}</button> + </view> + </view> +</template> + +<script> + import popup from '../uni-popup/popup.js' + import { + initVueI18n + } from '@dcloudio/uni-i18n' + import messages from '../uni-popup/i18n/index.js' + const { t } = initVueI18n(messages) + export default { + name: 'UniPopupShare', + mixins:[popup], + emits:['select'], + props: { + title: { + type: String, + default: '' + }, + beforeClose: { + type: Boolean, + default: false + } + }, + data() { + return { + bottomData: [{ + text: '微信', + icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/c2b17470-50be-11eb-b680-7980c8a877b8.png', + name: 'wx' + }, + { + text: '支付宝', + icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/d684ae40-50be-11eb-8ff1-d5dcf8779628.png', + name: 'wx' + }, + { + text: 'QQ', + icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/e7a79520-50be-11eb-b997-9918a5dda011.png', + name: 'qq' + }, + { + text: '新浪', + icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/0dacdbe0-50bf-11eb-8ff1-d5dcf8779628.png', + name: 'sina' + }, + // { + // text: '百度', + // icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/1ec6e920-50bf-11eb-8a36-ebb87efcf8c0.png', + // name: 'copy' + // }, + // { + // text: '其他', + // icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/2e0fdfe0-50bf-11eb-b997-9918a5dda011.png', + // name: 'more' + // } + ] + } + }, + created() {}, + computed: { + cancelText() { + return t("uni-popup.cancel") + }, + shareTitleText() { + return this.title || t("uni-popup.shareTitle") + } + }, + methods: { + /** + * 选择内容 + */ + select(item, index) { + this.$emit('select', { + item, + index + }) + this.close() + + }, + /** + * 关闭窗口 + */ + close() { + if(this.beforeClose) return + this.popup.close() + } + } + } +</script> +<style lang="scss" > + .uni-popup-share { + background-color: #fff; + border-top-left-radius: 11px; + border-top-right-radius: 11px; + } + .uni-share-title { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + align-items: center; + justify-content: center; + height: 40px; + } + .uni-share-title-text { + font-size: 14px; + color: #666; + } + .uni-share-content { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + justify-content: center; + padding-top: 10px; + } + + .uni-share-content-box { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + flex-wrap: wrap; + width: 360px; + } + + .uni-share-content-item { + width: 90px; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + justify-content: center; + padding: 10px 0; + align-items: center; + } + + .uni-share-content-item:active { + background-color: #f5f5f5; + } + + .uni-share-image { + width: 30px; + height: 30px; + } + + .uni-share-text { + margin-top: 10px; + font-size: 14px; + color: #3B4144; + } + + .uni-share-button-box { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + padding: 10px 15px; + } + + .uni-share-button { + flex: 1; + border-radius: 50px; + color: #666; + font-size: 16px; + } + + .uni-share-button::after { + border-radius: 50px; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/i18n/en.json b/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/i18n/en.json new file mode 100644 index 000000000..7f1bd06a0 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/i18n/index.js b/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/i18n/index.js new file mode 100644 index 000000000..de7509c87 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json b/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json new file mode 100644 index 000000000..5e3003cab --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json b/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json new file mode 100644 index 000000000..13e39eba1 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/keypress.js b/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/keypress.js new file mode 100644 index 000000000..62dda461b --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/popup.js b/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/popup.js new file mode 100644 index 000000000..c4e5781dd --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/uni-popup.vue b/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/uni-popup.vue new file mode 100644 index 000000000..db90c599e --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-popup/components/uni-popup/uni-popup.vue @@ -0,0 +1,474 @@ +<template> + <view v-if="showPopup" class="uni-popup" :class="[popupstyle, isDesktop ? 'fixforpc-z-index' : '']"> + <view @touchstart="touchstart"> + <uni-transition key="1" v-if="maskShow" name="mask" mode-class="fade" :styles="maskClass" + :duration="duration" :show="showTrans" @click="onTap" /> + <uni-transition key="2" :mode-class="ani" name="content" :styles="transClass" :duration="duration" + :show="showTrans" @click="onTap"> + <view class="uni-popup__wrapper" :style="{ backgroundColor: bg }" :class="[popupstyle]" @click="clear"> + <slot /> + </view> + </uni-transition> + </view> + <!-- #ifdef H5 --> + <keypress v-if="maskShow" @esc="onTap" /> + <!-- #endif --> + </view> +</template> + +<script> + // #ifdef H5 + import keypress from './keypress.js' + // #endif + + /** + * PopUp 弹出层 + * @description 弹出层组件,为了解决遮罩弹层的问题 + * @tutorial https://ext.dcloud.net.cn/plugin?id=329 + * @property {String} type = [top|center|bottom|left|right|message|dialog|share] 弹出方式 + * @value top 顶部弹出 + * @value center 中间弹出 + * @value bottom 底部弹出 + * @value left 左侧弹出 + * @value right 右侧弹出 + * @value message 消息提示 + * @value dialog 对话框 + * @value share 底部分享示例 + * @property {Boolean} animation = [true|false] 是否开启动画 + * @property {Boolean} maskClick = [true|false] 蒙版点击是否关闭弹窗(废弃) + * @property {Boolean} isMaskClick = [true|false] 蒙版点击是否关闭弹窗 + * @property {String} backgroundColor 主窗口背景色 + * @property {String} maskBackgroundColor 蒙版颜色 + * @property {Boolean} safeArea 是否适配底部安全区 + * @event {Function} change 打开关闭弹窗触发,e={show: false} + * @event {Function} maskClick 点击遮罩触发 + */ + + export default { + name: 'uniPopup', + components: { + // #ifdef H5 + keypress + // #endif + }, + emits: ['change', 'maskClick'], + props: { + // 开启动画 + animation: { + type: Boolean, + default: true + }, + // 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层 + // message: 消息提示 ; dialog : 对话框 + type: { + type: String, + default: 'center' + }, + // maskClick + isMaskClick: { + type: Boolean, + default: null + }, + // TODO 2 个版本后废弃属性 ,使用 isMaskClick + maskClick: { + type: Boolean, + default: null + }, + backgroundColor: { + type: String, + default: 'none' + }, + safeArea: { + type: Boolean, + default: true + }, + maskBackgroundColor: { + type: String, + default: 'rgba(0, 0, 0, 0.4)' + }, + }, + + watch: { + /** + * 监听type类型 + */ + type: { + handler: function(type) { + if (!this.config[type]) return + this[this.config[type]](true) + }, + immediate: true + }, + isDesktop: { + handler: function(newVal) { + if (!this.config[newVal]) return + this[this.config[this.type]](true) + }, + immediate: true + }, + /** + * 监听遮罩是否可点击 + * @param {Object} val + */ + maskClick: { + handler: function(val) { + this.mkclick = val + }, + immediate: true + }, + isMaskClick: { + handler: function(val) { + this.mkclick = val + }, + immediate: true + }, + // H5 下禁止底部滚动 + showPopup(show) { + // #ifdef H5 + // fix by mehaotian 处理 h5 滚动穿透的问题 + document.getElementsByTagName('body')[0].style.overflow = show ? 'hidden' : 'visible' + // #endif + } + }, + data() { + return { + duration: 300, + ani: [], + showPopup: false, + showTrans: false, + popupWidth: 0, + popupHeight: 0, + config: { + top: 'top', + bottom: 'bottom', + center: 'center', + left: 'left', + right: 'right', + message: 'top', + dialog: 'center', + share: 'bottom' + }, + maskClass: { + position: 'fixed', + bottom: 0, + top: 0, + left: 0, + right: 0, + backgroundColor: 'rgba(0, 0, 0, 0.4)' + }, + transClass: { + position: 'fixed', + left: 0, + right: 0 + }, + maskShow: true, + mkclick: true, + popupstyle: this.isDesktop ? 'fixforpc-top' : 'top' + } + }, + computed: { + isDesktop() { + return this.popupWidth >= 500 && this.popupHeight >= 500 + }, + bg() { + if (this.backgroundColor === '' || this.backgroundColor === 'none') { + return 'transparent' + } + return this.backgroundColor + } + }, + mounted() { + const fixSize = () => { + const { + windowWidth, + windowHeight, + windowTop, + safeArea, + screenHeight, + safeAreaInsets + } = uni.getSystemInfoSync() + this.popupWidth = windowWidth + this.popupHeight = windowHeight + (windowTop || 0) + // TODO fix by mehaotian 是否适配底部安全区 ,目前微信ios 、和 app ios 计算有差异,需要框架修复 + if (safeArea && this.safeArea) { + // #ifdef MP-WEIXIN + this.safeAreaInsets = screenHeight - safeArea.bottom + // #endif + // #ifndef MP-WEIXIN + this.safeAreaInsets = safeAreaInsets.bottom + // #endif + } else { + this.safeAreaInsets = 0 + } + } + fixSize() + // #ifdef H5 + // window.addEventListener('resize', fixSize) + // this.$once('hook:beforeDestroy', () => { + // window.removeEventListener('resize', fixSize) + // }) + // #endif + }, + // #ifndef VUE3 + // TODO vue2 + destroyed() { + this.setH5Visible() + }, + // #endif + // #ifdef VUE3 + // TODO vue3 + unmounted() { + this.setH5Visible() + }, + // #endif + created() { + // this.mkclick = this.isMaskClick || this.maskClick + if (this.isMaskClick === null && this.maskClick === null) { + this.mkclick = true + } else { + this.mkclick = this.isMaskClick !== null ? this.isMaskClick : this.maskClick + } + if (this.animation) { + this.duration = 300 + } else { + this.duration = 0 + } + // TODO 处理 message 组件生命周期异常的问题 + this.messageChild = null + // TODO 解决头条冒泡的问题 + this.clearPropagation = false + this.maskClass.backgroundColor = this.maskBackgroundColor + }, + methods: { + setH5Visible() { + // #ifdef H5 + // fix by mehaotian 处理 h5 滚动穿透的问题 + document.getElementsByTagName('body')[0].style.overflow = 'visible' + // #endif + }, + /** + * 公用方法,不显示遮罩层 + */ + closeMask() { + this.maskShow = false + }, + /** + * 公用方法,遮罩层禁止点击 + */ + disableMask() { + this.mkclick = false + }, + // TODO nvue 取消冒泡 + clear(e) { + // #ifndef APP-NVUE + e.stopPropagation() + // #endif + this.clearPropagation = true + }, + + open(direction) { + // fix by mehaotian 处理快速打开关闭的情况 + if (this.showPopup) { + clearTimeout(this.timer) + this.showPopup = false + } + let innerType = ['top', 'center', 'bottom', 'left', 'right', 'message', 'dialog', 'share'] + if (!(direction && innerType.indexOf(direction) !== -1)) { + direction = this.type + } + if (!this.config[direction]) { + console.error('缺少类型:', direction) + return + } + this[this.config[direction]]() + this.$emit('change', { + show: true, + type: direction + }) + }, + close(type) { + this.showTrans = false + this.$emit('change', { + show: false, + type: this.type + }) + clearTimeout(this.timer) + // // 自定义关闭事件 + // this.customOpen && this.customClose() + this.timer = setTimeout(() => { + this.showPopup = false + }, 300) + }, + // TODO 处理冒泡事件,头条的冒泡事件有问题 ,先这样兼容 + touchstart() { + this.clearPropagation = false + }, + + onTap() { + if (this.clearPropagation) { + // fix by mehaotian 兼容 nvue + this.clearPropagation = false + return + } + this.$emit('maskClick') + if (!this.mkclick) return + this.close() + }, + /** + * 顶部弹出样式处理 + */ + top(type) { + this.popupstyle = this.isDesktop ? 'fixforpc-top' : 'top' + this.ani = ['slide-top'] + this.transClass = { + position: 'fixed', + left: 0, + right: 0, + backgroundColor: this.bg + } + // TODO 兼容 type 属性 ,后续会废弃 + if (type) return + this.showPopup = true + this.showTrans = true + this.$nextTick(() => { + if (this.messageChild && this.type === 'message') { + this.messageChild.timerClose() + } + }) + }, + /** + * 底部弹出样式处理 + */ + bottom(type) { + this.popupstyle = 'bottom' + this.ani = ['slide-bottom'] + this.transClass = { + position: 'fixed', + left: 0, + right: 0, + bottom: 0, + paddingBottom: this.safeAreaInsets + 'px', + backgroundColor: this.bg + } + // TODO 兼容 type 属性 ,后续会废弃 + if (type) return + this.showPopup = true + this.showTrans = true + }, + /** + * 中间弹出样式处理 + */ + center(type) { + this.popupstyle = 'center' + this.ani = ['zoom-out', 'fade'] + this.transClass = { + position: 'fixed', + /* #ifndef APP-NVUE */ + display: 'flex', + flexDirection: 'column', + /* #endif */ + bottom: 0, + left: 0, + right: 0, + top: 0, + justifyContent: 'center', + alignItems: 'center' + } + // TODO 兼容 type 属性 ,后续会废弃 + if (type) return + this.showPopup = true + this.showTrans = true + }, + left(type) { + this.popupstyle = 'left' + this.ani = ['slide-left'] + this.transClass = { + position: 'fixed', + left: 0, + bottom: 0, + top: 0, + backgroundColor: this.bg, + /* #ifndef APP-NVUE */ + display: 'flex', + flexDirection: 'column' + /* #endif */ + } + // TODO 兼容 type 属性 ,后续会废弃 + if (type) return + this.showPopup = true + this.showTrans = true + }, + right(type) { + this.popupstyle = 'right' + this.ani = ['slide-right'] + this.transClass = { + position: 'fixed', + bottom: 0, + right: 0, + top: 0, + backgroundColor: this.bg, + /* #ifndef APP-NVUE */ + display: 'flex', + flexDirection: 'column' + /* #endif */ + } + // TODO 兼容 type 属性 ,后续会废弃 + if (type) return + this.showPopup = true + this.showTrans = true + } + } + } +</script> +<style lang="scss"> + .uni-popup { + position: fixed; + /* #ifndef APP-NVUE */ + z-index: 99; + + /* #endif */ + &.top, + &.left, + &.right { + /* #ifdef H5 */ + top: var(--window-top); + /* #endif */ + /* #ifndef H5 */ + top: 0; + /* #endif */ + } + + .uni-popup__wrapper { + /* #ifndef APP-NVUE */ + display: block; + /* #endif */ + position: relative; + + /* iphonex 等安全区设置,底部安全区适配 */ + /* #ifndef APP-NVUE */ + // padding-bottom: constant(safe-area-inset-bottom); + // padding-bottom: env(safe-area-inset-bottom); + /* #endif */ + &.left, + &.right { + /* #ifdef H5 */ + padding-top: var(--window-top); + /* #endif */ + /* #ifndef H5 */ + padding-top: 0; + /* #endif */ + flex: 1; + } + } + } + + .fixforpc-z-index { + /* #ifndef APP-NVUE */ + z-index: 999; + /* #endif */ + } + + .fixforpc-top { + top: 0; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-popup/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-popup/package.json new file mode 100644 index 000000000..069e9ce51 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-popup/package.json @@ -0,0 +1,90 @@ +{ + "id": "uni-popup", + "displayName": "uni-popup 弹出层", + "version": "1.7.9", + "description": " Popup 组件,提供常用的弹层", + "keywords": [ + "uni-ui", + "弹出层", + "弹窗", + "popup", + "弹框" + ], + "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-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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-popup/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-popup/readme.md new file mode 100644 index 000000000..fdad4b3d7 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-rate/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-rate/changelog.md new file mode 100644 index 000000000..8a98a6127 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-rate/components/uni-rate/uni-rate.vue b/yudao-ui-admin-uniapp/uni_modules/uni-rate/components/uni-rate/uni-rate.vue new file mode 100644 index 000000000..857f5f9c9 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-rate/components/uni-rate/uni-rate.vue @@ -0,0 +1,361 @@ +<template> + <view> + <view ref="uni-rate" class="uni-rate"> + <view class="uni-rate__icon" :class="{'uni-cursor-not-allowed': disabled}" + :style="{ 'margin-right': marginNumber + 'px' }" v-for="(star, index) in stars" :key="index" + @touchstart.stop="touchstart" @touchmove.stop="touchmove" @mousedown.stop="mousedown" + @mousemove.stop="mousemove" @mouseleave="mouseleave"> + <uni-icons :color="color" :size="size" :type="isFill ? 'star-filled' : 'star'" /> + <!-- #ifdef APP-NVUE --> + <view :style="{ width: star.activeWitch.replace('%','')*size/100+'px'}" class="uni-rate__icon-on"> + <uni-icons style="text-align: left;" :color="disabled?'#ccc':activeColor" :size="size" + type="star-filled" /> + </view> + <!-- #endif --> + <!-- #ifndef APP-NVUE --> + <view :style="{ width: star.activeWitch}" class="uni-rate__icon-on"> + <uni-icons :color="disabled?disabledColor:activeColor" :size="size" type="star-filled" /> + </view> + <!-- #endif --> + </view> + </view> + </view> +</template> + +<script> + // #ifdef APP-NVUE + const dom = uni.requireNativePlugin('dom'); + // #endif + /** + * Rate 评分 + * @description 评分组件 + * @tutorial https://ext.dcloud.net.cn/plugin?id=33 + * @property {Boolean} isFill = [true|false] 星星的类型,是否为实心类型, 默认为实心 + * @property {String} color 未选中状态的星星颜色,默认为 "#ececec" + * @property {String} activeColor 选中状态的星星颜色,默认为 "#ffca3e" + * @property {String} disabledColor 禁用状态的星星颜色,默认为 "#c0c0c0" + * @property {Number} size 星星的大小 + * @property {Number} value/v-model 当前评分 + * @property {Number} max 最大评分评分数量,目前一分一颗星 + * @property {Number} margin 星星的间距,单位 px + * @property {Boolean} disabled = [true|false] 是否为禁用状态,默认为 false + * @property {Boolean} readonly = [true|false] 是否为只读状态,默认为 false + * @property {Boolean} allowHalf = [true|false] 是否实现半星,默认为 false + * @property {Boolean} touchable = [true|false] 是否支持滑动手势,默认为 true + * @event {Function} change uniRate 的 value 改变时触发事件,e={value:Number} + */ + + export default { + name: "UniRate", + props: { + isFill: { + // 星星的类型,是否镂空 + type: [Boolean, String], + default: true + }, + color: { + // 星星未选中的颜色 + type: String, + default: "#ececec" + }, + activeColor: { + // 星星选中状态颜色 + type: String, + default: "#ffca3e" + }, + disabledColor: { + // 星星禁用状态颜色 + type: String, + default: "#c0c0c0" + }, + size: { + // 星星的大小 + type: [Number, String], + default: 24 + }, + value: { + // 当前评分 + type: [Number, String], + default: 0 + }, + modelValue: { + // 当前评分 + type: [Number, String], + default: 0 + }, + max: { + // 最大评分 + type: [Number, String], + default: 5 + }, + margin: { + // 星星的间距 + type: [Number, String], + default: 0 + }, + disabled: { + // 是否可点击 + type: [Boolean, String], + default: false + }, + readonly: { + // 是否只读 + type: [Boolean, String], + default: false + }, + allowHalf: { + // 是否显示半星 + type: [Boolean, String], + default: false + }, + touchable: { + // 是否支持滑动手势 + type: [Boolean, String], + default: true + } + }, + data() { + return { + valueSync: "", + userMouseFristMove: true, + userRated: false, + userLastRate: 1 + }; + }, + watch: { + value(newVal) { + this.valueSync = Number(newVal); + }, + modelValue(newVal) { + this.valueSync = Number(newVal); + }, + }, + computed: { + stars() { + const value = this.valueSync ? this.valueSync : 0; + const starList = []; + const floorValue = Math.floor(value); + const ceilValue = Math.ceil(value); + for (let i = 0; i < this.max; i++) { + if (floorValue > i) { + starList.push({ + activeWitch: "100%" + }); + } else if (ceilValue - 1 === i) { + starList.push({ + activeWitch: (value - floorValue) * 100 + "%" + }); + } else { + starList.push({ + activeWitch: "0" + }); + } + } + return starList; + }, + + marginNumber() { + return Number(this.margin) + } + }, + created() { + this.valueSync = Number(this.value || this.modelValue); + this._rateBoxLeft = 0 + this._oldValue = null + }, + mounted() { + setTimeout(() => { + this._getSize() + }, 100) + // #ifdef H5 + this.PC = this.IsPC() + // #endif + }, + methods: { + touchstart(e) { + // #ifdef H5 + if (this.IsPC()) return + // #endif + if (this.readonly || this.disabled) return + const { + clientX, + screenX + } = e.changedTouches[0] + // TODO 做一下兼容,只有 Nvue 下才有 screenX,其他平台式 clientX + this._getRateCount(clientX || screenX) + }, + touchmove(e) { + // #ifdef H5 + if (this.IsPC()) return + // #endif + if (this.readonly || this.disabled || !this.touchable) return + const { + clientX, + screenX + } = e.changedTouches[0] + this._getRateCount(clientX || screenX) + }, + + /** + * 兼容 PC @tian + */ + + mousedown(e) { + // #ifdef H5 + if (!this.IsPC()) return + if (this.readonly || this.disabled) return + const { + clientX, + } = e + this.userLastRate = this.valueSync + this._getRateCount(clientX) + this.userRated = true + // #endif + }, + mousemove(e) { + // #ifdef H5 + if (!this.IsPC()) return + if (this.userRated) return + if (this.userMouseFristMove) { + console.log('---mousemove----', this.valueSync); + this.userLastRate = this.valueSync + this.userMouseFristMove = false + } + if (this.readonly || this.disabled || !this.touchable) return + const { + clientX, + } = e + this._getRateCount(clientX) + // #endif + }, + mouseleave(e) { + // #ifdef H5 + if (!this.IsPC()) return + if (this.readonly || this.disabled || !this.touchable) return + if (this.userRated) { + this.userRated = false + return + } + this.valueSync = this.userLastRate + // #endif + }, + // #ifdef H5 + 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; + }, + // #endif + + /** + * 获取星星个数 + */ + _getRateCount(clientX) { + this._getSize() + const size = Number(this.size) + if (isNaN(size)) { + return new Error('size 属性只能设置为数字') + } + const rateMoveRange = clientX - this._rateBoxLeft + let index = parseInt(rateMoveRange / (size + this.marginNumber)) + index = index < 0 ? 0 : index; + index = index > this.max ? this.max : index; + const range = parseInt(rateMoveRange - (size + this.marginNumber) * index); + let value = 0; + if (this._oldValue === index && !this.PC) return; + this._oldValue = index; + if (this.allowHalf) { + if (range > (size / 2)) { + value = index + 1 + } else { + value = index + 0.5 + } + } else { + value = index + 1 + } + + value = Math.max(0.5, Math.min(value, this.max)) + this.valueSync = value + this._onChange() + }, + + /** + * 触发动态修改 + */ + _onChange() { + + this.$emit("input", this.valueSync); + this.$emit("update:modelValue", this.valueSync); + this.$emit("change", { + value: this.valueSync + }); + }, + /** + * 获取星星距离屏幕左侧距离 + */ + _getSize() { + // #ifndef APP-NVUE + uni.createSelectorQuery() + .in(this) + .select('.uni-rate') + .boundingClientRect() + .exec(ret => { + if (ret) { + this._rateBoxLeft = ret[0].left + } + }) + // #endif + // #ifdef APP-NVUE + dom.getComponentRect(this.$refs['uni-rate'], (ret) => { + const size = ret.size + if (size) { + this._rateBoxLeft = size.left + } + }) + // #endif + } + } + }; +</script> + +<style lang="scss"> + .uni-rate { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + line-height: 1; + font-size: 0; + flex-direction: row; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + + .uni-rate__icon { + position: relative; + line-height: 1; + font-size: 0; + } + + .uni-rate__icon-on { + overflow: hidden; + position: absolute; + top: 0; + left: 0; + line-height: 1; + text-align: left; + } + + .uni-cursor-not-allowed { + /* #ifdef H5 */ + cursor: not-allowed !important; + /* #endif */ + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-rate/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-rate/package.json new file mode 100644 index 000000000..64e8e3320 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-rate/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-rate/readme.md new file mode 100644 index 000000000..eae7b5ced --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-row/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-row/changelog.md new file mode 100644 index 000000000..5b465bc61 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-row/components/uni-col/uni-col.vue b/yudao-ui-admin-uniapp/uni_modules/uni-row/components/uni-col/uni-col.vue new file mode 100644 index 000000000..d5f372831 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-row/components/uni-col/uni-col.vue @@ -0,0 +1,317 @@ +<template> + <!-- #ifndef APP-NVUE --> + <view :class="['uni-col', sizeClass, pointClassList]" :style="{ + paddingLeft:`${Number(gutter)}rpx`, + paddingRight:`${Number(gutter)}rpx`, + }"> + <slot></slot> + </view> + <!-- #endif --> + <!-- #ifdef APP-NVUE --> + <!-- 在nvue上,类名样式不生效,换为style --> + <!-- 设置right正值失效,设置 left 负值 --> + <view :class="['uni-col']" :style="{ + paddingLeft:`${Number(gutter)}rpx`, + paddingRight:`${Number(gutter)}rpx`, + width:`${nvueWidth}rpx`, + position:'relative', + marginLeft:`${marginLeft}rpx`, + left:`${right === 0 ? left : -right}rpx` + }"> + <slot></slot> + </view> + <!-- #endif --> +</template> + +<script> + /** + * Col 布局-列 + * @description 搭配uni-row使用,构建布局。 + * @tutorial https://ext.dcloud.net.cn/plugin?id=3958 + * + * @property {span} type = Number 栅格占据的列数 + * 默认 24 + * @property {offset} type = Number 栅格左侧的间隔格数 + * @property {push} type = Number 栅格向右移动格数 + * @property {pull} type = Number 栅格向左移动格数 + * @property {xs} type = [Number, Object] <768px 响应式栅格数或者栅格属性对象 + * @description Number时表示在此屏幕宽度下,栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4} + * @property {sm} type = [Number, Object] ≥768px 响应式栅格数或者栅格属性对象 + * @description Number时表示在此屏幕宽度下,栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4} + * @property {md} type = [Number, Object] ≥992px 响应式栅格数或者栅格属性对象 + * @description Number时表示在此屏幕宽度下,栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4} + * @property {lg} type = [Number, Object] ≥1200px 响应式栅格数或者栅格属性对象 + * @description Number时表示在此屏幕宽度下,栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4} + * @property {xl} type = [Number, Object] ≥1920px 响应式栅格数或者栅格属性对象 + * @description Number时表示在此屏幕宽度下,栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4} + */ + const ComponentClass = 'uni-col'; + + // -1 默认值,因为在微信小程序端只给Number会有默认值0 + export default { + name: 'uniCol', + // #ifdef MP-WEIXIN + options: { + virtualHost: true // 在微信小程序中将组件节点渲染为虚拟节点,更加接近Vue组件的表现 + }, + // #endif + props: { + span: { + type: Number, + default: 24 + }, + offset: { + type: Number, + default: -1 + }, + pull: { + type: Number, + default: -1 + }, + push: { + type: Number, + default: -1 + }, + xs: [Number, Object], + sm: [Number, Object], + md: [Number, Object], + lg: [Number, Object], + xl: [Number, Object] + }, + data() { + return { + gutter: 0, + sizeClass: '', + parentWidth: 0, + nvueWidth: 0, + marginLeft: 0, + right: 0, + left: 0 + } + }, + created() { + // 字节小程序中,在computed中读取$parent为undefined + let parent = this.$parent; + + while (parent && parent.$options.componentName !== 'uniRow') { + parent = parent.$parent; + } + + this.updateGutter(parent.gutter) + parent.$watch('gutter', (gutter) => { + this.updateGutter(gutter) + }) + + // #ifdef APP-NVUE + this.updateNvueWidth(parent.width) + parent.$watch('width', (width) => { + this.updateNvueWidth(width) + }) + // #endif + }, + computed: { + sizeList() { + let { + span, + offset, + pull, + push + } = this; + + return { + span, + offset, + pull, + push + } + }, + // #ifndef APP-NVUE + pointClassList() { + let classList = []; + + ['xs', 'sm', 'md', 'lg', 'xl'].forEach(point => { + const props = this[point]; + if (typeof props === 'number') { + classList.push(`${ComponentClass}-${point}-${props}`) + } else if (typeof props === 'object' && props) { + Object.keys(props).forEach(pointProp => { + classList.push( + pointProp === 'span' ? + `${ComponentClass}-${point}-${props[pointProp]}` : + `${ComponentClass}-${point}-${pointProp}-${props[pointProp]}` + ) + }) + } + }); + + // 支付宝小程序使用 :class=[ ['a','b'] ],渲染错误 + return classList.join(' '); + } + // #endif + }, + methods: { + updateGutter(parentGutter) { + parentGutter = Number(parentGutter); + if (!isNaN(parentGutter)) { + this.gutter = parentGutter / 2 + } + }, + // #ifdef APP-NVUE + updateNvueWidth(width) { + // 用于在nvue端,span,offset,pull,push的计算 + this.parentWidth = width; + ['span', 'offset', 'pull', 'push'].forEach(size => { + const curSize = this[size]; + if ((curSize || curSize === 0) && curSize !== -1) { + let RPX = 1 / 24 * curSize * width + RPX = Number(RPX); + switch (size) { + case 'span': + this.nvueWidth = RPX + break; + case 'offset': + this.marginLeft = RPX + break; + case 'pull': + this.right = RPX + break; + case 'push': + this.left = RPX + break; + } + } + }); + } + // #endif + }, + watch: { + sizeList: { + immediate: true, + handler(newVal) { + // #ifndef APP-NVUE + let classList = []; + for (let size in newVal) { + const curSize = newVal[size]; + if ((curSize || curSize === 0) && curSize !== -1) { + classList.push( + size === 'span' ? + `${ComponentClass}-${curSize}` : + `${ComponentClass}-${size}-${curSize}` + ) + } + } + // 支付宝小程序使用 :class=[ ['a','b'] ],渲染错误 + this.sizeClass = classList.join(' '); + // #endif + // #ifdef APP-NVUE + this.updateNvueWidth(this.parentWidth); + // #endif + } + } + } + } +</script> + +<style lang='scss' > + /* breakpoints */ + $--sm: 768px !default; + $--md: 992px !default; + $--lg: 1200px !default; + $--xl: 1920px !default; + + $breakpoints: ('xs' : (max-width: $--sm - 1), + 'sm' : (min-width: $--sm), + 'md' : (min-width: $--md), + 'lg' : (min-width: $--lg), + 'xl' : (min-width: $--xl)); + + $layout-namespace: ".uni-"; + $col: $layout-namespace+"col"; + + @function getSize($size) { + /* TODO 1/24 * $size * 100 * 1%; 使用计算后的值,为了解决 vue3 控制台报错 */ + @return 0.04166666666 * $size * 100 * 1%; + } + + @mixin res($key, $map:$breakpoints) { + @if map-has-key($map, $key) { + @media screen and #{inspect(map-get($map,$key))} { + @content; + } + } + + @else { + @warn "Undeinfed point: `#{$key}`"; + } + } + + /* #ifndef APP-NVUE */ + #{$col} { + float: left; + box-sizing: border-box; + } + + #{$col}-0 { + /* #ifdef APP-NVUE */ + width: 0; + height: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + /* #endif */ + /* #ifndef APP-NVUE */ + display: none; + /* #endif */ + } + + @for $i from 0 through 24 { + #{$col}-#{$i} { + width: getSize($i); + } + + #{$col}-offset-#{$i} { + margin-left: getSize($i); + } + + #{$col}-pull-#{$i} { + position: relative; + right: getSize($i); + } + + #{$col}-push-#{$i} { + position: relative; + left: getSize($i); + } + } + + @each $point in map-keys($breakpoints) { + @include res($point) { + #{$col}-#{$point}-0 { + display: none; + } + + @for $i from 0 through 24 { + #{$col}-#{$point}-#{$i} { + width: getSize($i); + } + + #{$col}-#{$point}-offset-#{$i} { + margin-left: getSize($i); + } + + #{$col}-#{$point}-pull-#{$i} { + position: relative; + right: getSize($i); + } + + #{$col}-#{$point}-push-#{$i} { + position: relative; + left: getSize($i); + } + } + } + } + + /* #endif */ +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-row/components/uni-row/uni-row.vue b/yudao-ui-admin-uniapp/uni_modules/uni-row/components/uni-row/uni-row.vue new file mode 100644 index 000000000..c7d93701e --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-row/components/uni-row/uni-row.vue @@ -0,0 +1,190 @@ +<template> + <view :class="[ 'uni-row', typeClass , justifyClass, alignClass, ]" :style="{ + marginLeft:`${Number(marginValue)}rpx`, + marginRight:`${Number(marginValue)}rpx`, + }"> + <slot></slot> + </view> +</template> + +<script> + const ComponentClass = 'uni-row'; + const modifierSeparator = '--'; + /** + * Row 布局-行 + * @description 流式栅格系统,随着屏幕或视口分为 24 份,可以迅速简便地创建布局。 + * @tutorial https://ext.dcloud.net.cn/plugin?id=3958 + * + * @property {gutter} type = Number 栅格间隔 + * @property {justify} type = String flex 布局下的水平排列方式 + * 可选 start/end/center/space-around/space-between start + * 默认值 start + * @property {align} type = String flex 布局下的垂直排列方式 + * 可选 top/middle/bottom + * 默认值 top + * @property {width} type = String|Number nvue下需要自行配置宽度用于计算 + * 默认值 750 + */ + + + export default { + name: 'uniRow', + componentName: 'uniRow', + // #ifdef MP-WEIXIN + options: { + virtualHost: true // 在微信小程序中将组件节点渲染为虚拟节点,更加接近Vue组件的表现,可使用flex布局 + }, + // #endif + props: { + type: String, + gutter: Number, + justify: { + type: String, + default: 'start' + }, + align: { + type: String, + default: 'top' + }, + // nvue如果使用span等属性,需要配置宽度 + width: { + type: [String, Number], + default: 750 + } + }, + created() { + // #ifdef APP-NVUE + this.type = 'flex'; + // #endif + }, + computed: { + marginValue() { + // #ifndef APP-NVUE + if (this.gutter) { + return -(this.gutter / 2); + } + // #endif + return 0; + }, + typeClass() { + return this.type === 'flex' ? `${ComponentClass + modifierSeparator}flex` : ''; + }, + justifyClass() { + return this.justify !== 'start' ? `${ComponentClass + modifierSeparator}flex-justify-${this.justify}` : '' + }, + alignClass() { + return this.align !== 'top' ? `${ComponentClass + modifierSeparator}flex-align-${this.align}` : '' + } + } + }; +</script> + +<style lang="scss"> + $layout-namespace: ".uni-"; + $row:$layout-namespace+"row"; + $modifier-separator: "--"; + + @mixin utils-clearfix { + $selector: &; + + @at-root { + + /* #ifndef APP-NVUE */ + #{$selector}::before, + #{$selector}::after { + display: table; + content: ""; + } + + #{$selector}::after { + clear: both; + } + + /* #endif */ + } + + } + + @mixin utils-flex ($direction: row) { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: $direction; + } + + @mixin set-flex($state) { + @at-root &-#{$state} { + @content + } + } + + #{$row} { + position: relative; + flex-direction: row; + + /* #ifdef APP-NVUE */ + flex: 1; + /* #endif */ + + /* #ifndef APP-NVUE */ + box-sizing: border-box; + /* #endif */ + + // 非nvue使用float布局 + @include utils-clearfix; + + // 在QQ、字节、百度小程序平台,编译后使用shadow dom,不可使用flex布局,使用float + @at-root { + + /* #ifndef MP-QQ || MP-TOUTIAO || MP-BAIDU */ + &#{$modifier-separator}flex { + @include utils-flex; + flex-wrap: wrap; + flex: 1; + + &:before, + &:after { + /* #ifndef APP-NVUE */ + display: none; + /* #endif */ + } + + @include set-flex(justify-center) { + justify-content: center; + } + + @include set-flex(justify-end) { + justify-content: flex-end; + } + + @include set-flex(justify-space-between) { + justify-content: space-between; + } + + @include set-flex(justify-space-around) { + justify-content: space-around; + } + + @include set-flex(align-middle) { + align-items: center; + } + + @include set-flex(align-bottom) { + align-items: flex-end; + } + } + + /* #endif */ + } + + } + + // 字节、QQ配置后不生效 + // 此处用法无法使用 + /* #ifdef MP-WEIXIN || MP-TOUTIAO || MP-QQ */ + :host { + display: block; + } + + /* #endif */ +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-row/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-row/package.json new file mode 100644 index 000000000..3f52fa647 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-row/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-row/readme.md new file mode 100644 index 000000000..3c9c8b99e --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-scss/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-scss/changelog.md new file mode 100644 index 000000000..b863bb0f5 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-scss/index.scss b/yudao-ui-admin-uniapp/uni_modules/uni-scss/index.scss new file mode 100644 index 000000000..1744a5f98 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-scss/index.scss @@ -0,0 +1 @@ +@import './styles/index.scss'; diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-scss/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-scss/package.json new file mode 100644 index 000000000..7cc0ccb73 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-scss/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-scss/readme.md new file mode 100644 index 000000000..b7d1c25f3 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/index.scss b/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/index.scss new file mode 100644 index 000000000..ffac4fecd --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_border.scss b/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_border.scss new file mode 100644 index 000000000..12a11c322 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_color.scss b/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_color.scss new file mode 100644 index 000000000..1ededd94d --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_radius.scss b/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_radius.scss new file mode 100644 index 000000000..9a0428bb8 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_space.scss b/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_space.scss new file mode 100644 index 000000000..3c8952897 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_styles.scss b/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_styles.scss new file mode 100644 index 000000000..689afec66 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_text.scss b/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_text.scss new file mode 100644 index 000000000..a34d08f3f --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_variables.scss b/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/setting/_variables.scss new file mode 100644 index 000000000..557d3d7c9 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/tools/functions.scss b/yudao-ui-admin-uniapp/uni_modules/uni-scss/styles/tools/functions.scss new file mode 100644 index 000000000..ac6f63e53 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-scss/theme.scss b/yudao-ui-admin-uniapp/uni_modules/uni-scss/theme.scss new file mode 100644 index 000000000..80ee62f7d --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-scss/variables.scss b/yudao-ui-admin-uniapp/uni_modules/uni-scss/variables.scss new file mode 100644 index 000000000..1c062d42b --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/changelog.md new file mode 100644 index 000000000..b41fdd3ba --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/changelog.md @@ -0,0 +1,33 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/i18n/en.json b/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/i18n/en.json new file mode 100644 index 000000000..dd083a535 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/i18n/index.js b/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/i18n/index.js new file mode 100644 index 000000000..de7509c87 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hans.json b/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hans.json new file mode 100644 index 000000000..d4e5c120c --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hans.json @@ -0,0 +1,4 @@ +{ + "uni-search-bar.cancel": "cancel", + "uni-search-bar.placeholder": "请输入搜索内容" +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hant.json b/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hant.json new file mode 100644 index 000000000..318b6ef1b --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hant.json @@ -0,0 +1,4 @@ +{ + "uni-search-bar.cancel": "cancel", + "uni-search-bar.placeholder": "請輸入搜索內容" +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/uni-search-bar.vue b/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/uni-search-bar.vue new file mode 100644 index 000000000..5a518a8cc --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/components/uni-search-bar/uni-search-bar.vue @@ -0,0 +1,298 @@ +<template> + <view class="uni-searchbar"> + <view :style="{borderRadius:radius+'px',backgroundColor: bgColor}" class="uni-searchbar__box" + @click="searchClick"> + <view class="uni-searchbar__box-icon-search"> + <slot name="searchIcon"> + <uni-icons color="#c0c4cc" size="18" type="search" /> + </slot> + </view> + <input v-if="show || searchVal" :focus="showSync" :disabled="readonly" :placeholder="placeholderText" :maxlength="maxlength" + class="uni-searchbar__box-search-input" confirm-type="search" type="text" v-model="searchVal" + @confirm="confirm" @blur="blur" @focus="emitFocus" /> + <text v-else class="uni-searchbar__text-placeholder">{{ placeholder }}</text> + <view v-if="show && (clearButton==='always'||clearButton==='auto'&&searchVal!=='') &&!readonly" + class="uni-searchbar__box-icon-clear" @click="clear"> + <slot name="clearIcon"> + <uni-icons color="#c0c4cc" size="20" type="clear" /> + </slot> + </view> + </view> + <text @click="cancel" class="uni-searchbar__cancel" + v-if="cancelButton ==='always' || show && cancelButton ==='auto'">{{cancelTextI18n}}</text> + </view> +</template> + +<script> + import { + initVueI18n + } from '@dcloudio/uni-i18n' + import messages from './i18n/index.js' + const { + t + } = initVueI18n(messages) + + /** + * SearchBar 搜索栏 + * @description 搜索栏组件,通常用于搜索商品、文章等 + * @tutorial https://ext.dcloud.net.cn/plugin?id=866 + * @property {Number} radius 搜索栏圆角 + * @property {Number} maxlength 输入最大长度 + * @property {String} placeholder 搜索栏Placeholder + * @property {String} clearButton = [always|auto|none] 是否显示清除按钮 + * @value always 一直显示 + * @value auto 输入框不为空时显示 + * @value none 一直不显示 + * @property {String} cancelButton = [always|auto|none] 是否显示取消按钮 + * @value always 一直显示 + * @value auto 输入框不为空时显示 + * @value none 一直不显示 + * @property {String} cancelText 取消按钮的文字 + * @property {String} bgColor 输入框背景颜色 + * @property {Boolean} focus 是否自动聚焦 + * @property {Boolean} readonly 组件只读,不能有任何操作,只做展示 + * @event {Function} confirm uniSearchBar 的输入框 confirm 事件,返回参数为uniSearchBar的value,e={value:Number} + * @event {Function} input uniSearchBar 的 value 改变时触发事件,返回参数为uniSearchBar的value,e=value + * @event {Function} cancel 点击取消按钮时触发事件,返回参数为uniSearchBar的value,e={value:Number} + * @event {Function} clear 点击清除按钮时触发事件,返回参数为uniSearchBar的value,e={value:Number} + * @event {Function} blur input失去焦点时触发事件,返回参数为uniSearchBar的value,e={value:Number} + */ + + export default { + name: "UniSearchBar", + emits: ['input', 'update:modelValue', 'clear', 'cancel', 'confirm', 'blur', 'focus'], + props: { + placeholder: { + type: String, + default: "" + }, + radius: { + type: [Number, String], + default: 5 + }, + clearButton: { + type: String, + default: "auto" + }, + cancelButton: { + type: String, + default: "auto" + }, + cancelText: { + type: String, + default: '取消' + }, + bgColor: { + type: String, + default: "#F8F8F8" + }, + maxlength: { + type: [Number, String], + default: 100 + }, + value: { + type: [Number, String], + default: "" + }, + modelValue: { + type: [Number, String], + default: "" + }, + focus: { + type: Boolean, + default: false + }, + readonly: { + type: Boolean, + default: false + } + }, + data() { + return { + show: false, + showSync: false, + searchVal: '' + } + }, + computed: { + cancelTextI18n() { + return this.cancelText || t("uni-search-bar.cancel") + }, + placeholderText() { + return this.placeholder || t("uni-search-bar.placeholder") + } + }, + watch: { + // #ifndef VUE3 + value: { + immediate: true, + handler(newVal) { + this.searchVal = newVal + if (newVal) { + this.show = true + } + } + }, + // #endif + // #ifdef VUE3 + modelValue: { + immediate: true, + handler(newVal) { + this.searchVal = newVal + if (newVal) { + this.show = true + } + } + }, + // #endif + focus: { + immediate: true, + handler(newVal) { + if (newVal) { + if(this.readonly) return + this.show = true; + this.$nextTick(() => { + this.showSync = true + }) + } + } + }, + searchVal(newVal, oldVal) { + this.$emit("input", newVal) + // #ifdef VUE3 + this.$emit("update:modelValue", newVal) + // #endif + } + }, + methods: { + searchClick() { + if(this.readonly) return + if (this.show) { + return + } + this.show = true; + this.$nextTick(() => { + this.showSync = true + }) + }, + clear() { + this.$emit("clear", { + value: this.searchVal + }) + this.searchVal = "" + }, + cancel() { + if(this.readonly) return + this.$emit("cancel", { + value: this.searchVal + }); + this.searchVal = "" + this.show = false + this.showSync = false + // #ifndef APP-PLUS + uni.hideKeyboard() + // #endif + // #ifdef APP-PLUS + plus.key.hideSoftKeybord() + // #endif + }, + confirm() { + // #ifndef APP-PLUS + uni.hideKeyboard(); + // #endif + // #ifdef APP-PLUS + plus.key.hideSoftKeybord() + // #endif + this.$emit("confirm", { + value: this.searchVal + }) + }, + blur() { + // #ifndef APP-PLUS + uni.hideKeyboard(); + // #endif + // #ifdef APP-PLUS + plus.key.hideSoftKeybord() + // #endif + this.$emit("blur", { + value: this.searchVal + }) + }, + emitFocus(e) { + this.$emit("focus", e.detail) + } + } + }; +</script> + +<style lang="scss"> + $uni-searchbar-height: 36px; + + .uni-searchbar { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + position: relative; + padding: 10px; + // background-color: #fff; + } + + .uni-searchbar__box { + /* #ifndef APP-NVUE */ + display: flex; + box-sizing: border-box; + /* #endif */ + overflow: hidden; + position: relative; + flex: 1; + justify-content: center; + flex-direction: row; + align-items: center; + height: $uni-searchbar-height; + padding: 5px 8px 5px 0px; + } + + .uni-searchbar__box-icon-search { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + // width: 32px; + padding: 0 8px; + justify-content: center; + align-items: center; + color: #B3B3B3; + } + + .uni-searchbar__box-search-input { + flex: 1; + font-size: 14px; + color: #333; + } + + .uni-searchbar__box-icon-clear { + align-items: center; + line-height: 24px; + padding-left: 8px; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + + .uni-searchbar__text-placeholder { + font-size: 14px; + color: #B3B3B3; + margin-left: 5px; + } + + .uni-searchbar__cancel { + padding-left: 10px; + line-height: $uni-searchbar-height; + font-size: 14px; + color: #333333; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/package.json new file mode 100644 index 000000000..9352c574f --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/package.json @@ -0,0 +1,89 @@ +{ + "id": "uni-search-bar", + "displayName": "uni-search-bar 搜索栏", + "version": "1.2.3", + "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/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-search-bar/readme.md new file mode 100644 index 000000000..253092f0b --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-segmented-control/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-segmented-control/changelog.md new file mode 100644 index 000000000..a44385d7c --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue b/yudao-ui-admin-uniapp/uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue new file mode 100644 index 000000000..ddbcf8849 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue @@ -0,0 +1,145 @@ +<template> + <view :class="[styleType === 'text'?'segmented-control--text' : 'segmented-control--button' ]" + :style="{ borderColor: styleType === 'text' ? '' : activeColor }" class="segmented-control"> + <view v-for="(item, index) in values" :class="[ styleType === 'text' ? '': 'segmented-control__item--button', + index === currentIndex&&styleType === 'button' ? 'segmented-control__item--button--active': '', + index === 0&&styleType === 'button' ? 'segmented-control__item--button--first': '', + index === values.length - 1&&styleType === 'button' ? 'segmented-control__item--button--last': '' ]" :key="index" + :style="{ backgroundColor: index === currentIndex && styleType === 'button' ? activeColor : '',borderColor: index === currentIndex&&styleType === 'text'||styleType === 'button'?activeColor:'transparent' }" + class="segmented-control__item" @click="_onClick(index)"> + <view> + <text :style="{color: + index === currentIndex + ? styleType === 'text' + ? activeColor + : '#fff' + : styleType === 'text' + ? '#000' + : activeColor}" class="segmented-control__text" :class="styleType === 'text' && index === currentIndex ? 'segmented-control__item--text': ''">{{ item }}</text> + </view> + + </view> + </view> +</template> + +<script> + /** + * SegmentedControl 分段器 + * @description 用作不同视图的显示 + * @tutorial https://ext.dcloud.net.cn/plugin?id=54 + * @property {Number} current 当前选中的tab索引值,从0计数 + * @property {String} styleType = [button|text] 分段器样式类型 + * @value button 按钮类型 + * @value text 文字类型 + * @property {String} activeColor 选中的标签背景色与边框颜色 + * @property {Array} values 选项数组 + * @event {Function} clickItem 组件触发点击事件时触发,e={currentIndex} + */ + + export default { + name: 'UniSegmentedControl', + emits: ['clickItem'], + props: { + current: { + type: Number, + default: 0 + }, + values: { + type: Array, + default () { + return [] + } + }, + activeColor: { + type: String, + default: '#2979FF' + }, + styleType: { + type: String, + default: 'button' + } + }, + data() { + return { + currentIndex: 0 + } + }, + watch: { + current(val) { + if (val !== this.currentIndex) { + this.currentIndex = val + } + } + }, + created() { + this.currentIndex = this.current + }, + methods: { + _onClick(index) { + if (this.currentIndex !== index) { + this.currentIndex = index + this.$emit('clickItem', { + currentIndex: index + }) + } + } + } + } +</script> + +<style lang="scss" > + .segmented-control { + /* #ifndef APP-NVUE */ + display: flex; + box-sizing: border-box; + /* #endif */ + flex-direction: row; + height: 36px; + overflow: hidden; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + + .segmented-control__item { + /* #ifndef APP-NVUE */ + display: inline-flex; + box-sizing: border-box; + /* #endif */ + position: relative; + flex: 1; + justify-content: center; + align-items: center; + } + + .segmented-control__item--button { + border-style: solid; + border-top-width: 1px; + border-bottom-width: 1px; + border-right-width: 1px; + border-left-width: 0; + } + + .segmented-control__item--button--first { + border-left-width: 1px; + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; + } + + .segmented-control__item--button--last { + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + } + + .segmented-control__item--text { + border-bottom-style: solid; + border-bottom-width: 2px; + padding: 6px 0; + } + + .segmented-control__text { + font-size: 14px; + line-height: 20px; + text-align: center; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-segmented-control/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-segmented-control/package.json new file mode 100644 index 000000000..6cae41db2 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-segmented-control/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-segmented-control/readme.md new file mode 100644 index 000000000..3527b03f6 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-steps/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-steps/changelog.md new file mode 100644 index 000000000..cb9d36793 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-steps/components/uni-steps/uni-steps.vue b/yudao-ui-admin-uniapp/uni_modules/uni-steps/components/uni-steps/uni-steps.vue new file mode 100644 index 000000000..a6c8f2879 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-steps/components/uni-steps/uni-steps.vue @@ -0,0 +1,269 @@ +<template> + <view class="uni-steps"> + <view :class="[direction==='column'?'uni-steps__column':'uni-steps__row']"> + <view :class="[direction==='column'?'uni-steps__column-text-container':'uni-steps__row-text-container']"> + <view v-for="(item,index) in options" :key="index" + :class="[direction==='column'?'uni-steps__column-text':'uni-steps__row-text']"> + <text :style="{color:index === active?activeColor:deactiveColor}" + :class="[direction==='column'?'uni-steps__column-title':'uni-steps__row-title']">{{item.title}}</text> + <text :style="{color: deactiveColor}" + :class="[direction==='column'?'uni-steps__column-desc':'uni-steps__row-desc']">{{item.desc}}</text> + </view> + </view> + <view :class="[direction==='column'?'uni-steps__column-container':'uni-steps__row-container']"> + <view :class="[direction==='column'?'uni-steps__column-line-item':'uni-steps__row-line-item']" + v-for="(item,index) in options" :key="index"> + <view + :class="[direction==='column'?'uni-steps__column-line':'uni-steps__row-line',direction==='column'?'uni-steps__column-line--before':'uni-steps__row-line--before']" + :style="{backgroundColor:index<=active&&index!==0?activeColor:index===0?'transparent':deactiveColor}"> + </view> + <view :class="[direction==='column'?'uni-steps__column-check':'uni-steps__row-check']" + v-if="index === active"> + <uni-icons :color="activeColor" :type="activeIcon" size="14"></uni-icons> + </view> + <view v-else :class="[direction==='column'?'uni-steps__column-circle':'uni-steps__row-circle']" + :style="{backgroundColor:index<active?activeColor:deactiveColor}"></view> + <view + :class="[direction==='column'?'uni-steps__column-line':'uni-steps__row-line',direction==='column'?'uni-steps__column-line--after':'uni-steps__row-line--after']" + :style="{backgroundColor:index<active&&index!==options.length-1?activeColor:index===options.length-1?'transparent':deactiveColor}"> + </view> + </view> + </view> + </view> + </view> +</template> + +<script> + /** + * Steps 步骤条 + * @description 评分组件 + * @tutorial https://ext.dcloud.net.cn/plugin?id=34 + * @property {Number} active 当前步骤 + * @property {String} direction = [row|column] 当前步骤 + * @value row 横向 + * @value column 纵向 + * @property {String} activeColor 选中状态的颜色 + * @property {Array} options 数据源,格式为:[{title:'xxx',desc:'xxx'},{title:'xxx',desc:'xxx'}] + */ + + export default { + name: 'UniSteps', + props: { + direction: { + // 排列方向 row column + type: String, + default: 'row' + }, + activeColor: { + // 激活状态颜色 + type: String, + default: '#2979FF' + }, + deactiveColor: { + // 未激活状态颜色 + type: String, + default: '#B7BDC6' + }, + active: { + // 当前步骤 + type: Number, + default: 0 + }, + activeIcon: { + // 当前步骤 + type: String, + default: 'checkbox-filled' + }, + options: { + type: Array, + default () { + return [] + } + } // 数据 + }, + data() { + return {} + } + } +</script> + +<style lang="scss"> + $uni-primary: #2979ff !default; + $uni-border-color:#EDEDED; + .uni-steps { + /* #ifndef APP-NVUE */ + display: flex; + width: 100%; + /* #endif */ + /* #ifdef APP-NVUE */ + flex: 1; + /* #endif */ + flex-direction: column; + } + + .uni-steps__row { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + } + + .uni-steps__column { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row-reverse; + } + + .uni-steps__row-text-container { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + align-items: flex-end; + margin-bottom: 8px; + } + + .uni-steps__column-text-container { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + flex: 1; + } + + .uni-steps__row-text { + /* #ifndef APP-NVUE */ + display: inline-flex; + /* #endif */ + flex: 1; + flex-direction: column; + } + + .uni-steps__column-text { + padding: 6px 0px; + border-bottom-style: solid; + border-bottom-width: 1px; + border-bottom-color: $uni-border-color; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + } + + .uni-steps__row-title { + font-size: 14px; + line-height: 16px; + text-align: center; + } + + .uni-steps__column-title { + font-size: 14px; + text-align: left; + line-height: 18px; + } + + .uni-steps__row-desc { + font-size: 12px; + line-height: 14px; + text-align: center; + } + + .uni-steps__column-desc { + font-size: 12px; + text-align: left; + line-height: 18px; + } + + .uni-steps__row-container { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + } + + .uni-steps__column-container { + /* #ifndef APP-NVUE */ + display: inline-flex; + /* #endif */ + width: 30px; + flex-direction: column; + } + + .uni-steps__row-line-item { + /* #ifndef APP-NVUE */ + display: inline-flex; + /* #endif */ + flex-direction: row; + flex: 1; + height: 14px; + line-height: 14px; + align-items: center; + justify-content: center; + } + + .uni-steps__column-line-item { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + flex: 1; + align-items: center; + justify-content: center; + } + + .uni-steps__row-line { + flex: 1; + height: 1px; + background-color: #B7BDC6; + } + + .uni-steps__column-line { + width: 1px; + background-color: #B7BDC6; + } + + .uni-steps__row-line--after { + transform: translateX(1px); + } + + .uni-steps__column-line--after { + flex: 1; + transform: translate(0px, 1px); + } + + .uni-steps__row-line--before { + transform: translateX(-1px); + } + + .uni-steps__column-line--before { + height: 6px; + transform: translate(0px, -13px); + } + + .uni-steps__row-circle { + width: 5px; + height: 5px; + border-radius: 50%; + background-color: #B7BDC6; + margin: 0px 3px; + } + + .uni-steps__column-circle { + width: 5px; + height: 5px; + border-radius: 50%; + background-color: #B7BDC6; + margin: 4px 0px 5px 0px; + } + + .uni-steps__row-check { + margin: 0px 6px; + } + + .uni-steps__column-check { + height: 14px; + line-height: 14px; + margin: 2px 0px; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-steps/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-steps/package.json new file mode 100644 index 000000000..c687b40ab --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-steps/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-steps/readme.md new file mode 100644 index 000000000..da7a4bfaa --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/changelog.md new file mode 100644 index 000000000..c007cb5c4 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/changelog.md @@ -0,0 +1,41 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/bindingx.js b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/bindingx.js new file mode 100644 index 000000000..755c97c96 --- /dev/null +++ b/yudao-ui-admin-uniapp/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.children !== undefined) { + 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.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/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/isPC.js b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/isPC.js new file mode 100644 index 000000000..917cb4890 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js new file mode 100644 index 000000000..43cd56bdf --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js @@ -0,0 +1,193 @@ +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.children !== undefined) { + 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 + this.autoClose && 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/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js new file mode 100644 index 000000000..9a8bcbb64 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js @@ -0,0 +1,259 @@ +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.children !== undefined) { + 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) return + 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/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js new file mode 100644 index 000000000..435e0fbcb --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js @@ -0,0 +1,83 @@ +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.children !== undefined) { + this.swipeaction.children.push(this) + } + }, + mounted() { + this.is_show = this.show + }, + methods: { + // wxs 中调用 + closeSwipe(e) { + if (!this.autoClose) return + 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/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/render.js b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/render.js new file mode 100644 index 000000000..78f0ec60e --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue new file mode 100644 index 000000000..d79c2979f --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue @@ -0,0 +1,347 @@ +<template> + <!-- 在微信小程序 app vue端 h5 使用wxs 实现--> + <!-- #ifdef APP-VUE || MP-WEIXIN || H5 --> + <view class="uni-swipe"> + <!-- #ifdef MP-WEIXIN || VUE3 --> + <view class="uni-swipe_box" :change:prop="wxsswipe.showWatch" :prop="is_show" :data-threshold="threshold" + :data-disabled="disabled" @touchstart="wxsswipe.touchstart" @touchmove="wxsswipe.touchmove" + @touchend="wxsswipe.touchend"> + <!-- #endif --> + <!-- #ifndef MP-WEIXIN || VUE3 --> + <view class="uni-swipe_box" :change:prop="renderswipe.showWatch" :prop="is_show" :data-threshold="threshold" + :data-disabled="disabled+''" @touchstart="renderswipe.touchstart" @touchmove="renderswipe.touchmove" + @touchend="renderswipe.touchend"> + <!-- #endif --> + <!-- 在微信小程序 app vue端 h5 使用wxs 实现--> + <view class="uni-swipe_button-group button-group--left"> + <slot name="left"> + <view v-for="(item,index) in leftOptions" :key="index" :style="{ + backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD' + }" class="uni-swipe_button button-hock" @touchstart="appTouchStart" + @touchend="appTouchEnd($event,index,item,'left')" + @click.stop="onClickForPC(index,item,'left')"> + <text class="uni-swipe_button-text" + :style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'}">{{ item.text }}</text> + </view> + </slot> + </view> + <view class="uni-swipe_text--center"> + <slot></slot> + </view> + <view class="uni-swipe_button-group button-group--right"> + <slot name="right"> + <view v-for="(item,index) in rightOptions" :key="index" :style="{ + backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD' + }" class="uni-swipe_button button-hock" @touchstart="appTouchStart" + @touchend="appTouchEnd($event,index,item,'right')" + @click.stop="onClickForPC(index,item,'right')"><text class="uni-swipe_button-text" + :style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'}">{{ item.text }}</text> + </view> + </slot> + </view> + </view> + </view> + <!-- #endif --> + <!-- app nvue端 使用 bindingx --> + <!-- #ifdef APP-NVUE --> + <view ref="selector-box--hock" class="uni-swipe" @horizontalpan="touchstart" @touchend="touchend"> + <view ref='selector-left-button--hock' class="uni-swipe_button-group button-group--left"> + <slot name="left"> + <view v-for="(item,index) in leftOptions" :key="index" :style="{ + backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD' + }" class="uni-swipe_button button-hock" @click.stop="onClick(index,item,'left')"><text + class="uni-swipe_button-text" + :style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF', fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'}">{{ item.text }}</text> + </view> + </slot> + </view> + <view ref='selector-right-button--hock' class="uni-swipe_button-group button-group--right"> + <slot name="right"> + <view v-for="(item,index) in rightOptions" :key="index" :style="{ + backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD' + }" class="uni-swipe_button button-hock" @click.stop="onClick(index,item,'right')"><text + class="uni-swipe_button-text" + :style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'}">{{ item.text }}</text> + </view> + </slot> + </view> + <view ref='selector-content--hock' class="uni-swipe_box"> + <slot></slot> + </view> + </view> + <!-- #endif --> + <!-- 其他平台使用 js ,长列表性能可能会有影响--> + <!-- #ifdef MP-ALIPAY || MP-BAIDU || MP-TOUTIAO || MP-QQ --> + <view class="uni-swipe"> + <view class="uni-swipe_box" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend" + :style="{transform:moveLeft}" :class="{ani:ani}"> + <view class="uni-swipe_button-group button-group--left" :class="[elClass]"> + <slot name="left"> + <view v-for="(item,index) in leftOptions" :key="index" :style="{ + backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD', + fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px' + }" class="uni-swipe_button button-hock" @touchstart="appTouchStart" + @touchend="appTouchEnd($event,index,item,'left')"><text class="uni-swipe_button-text" + :style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',}">{{ item.text }}</text> + </view> + </slot> + </view> + <slot></slot> + <view class="uni-swipe_button-group button-group--right" :class="[elClass]"> + <slot name="right"> + <view v-for="(item,index) in rightOptions" :key="index" :style="{ + backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD', + fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px' + }" @touchstart="appTouchStart" @touchend="appTouchEnd($event,index,item,'right')" + class="uni-swipe_button button-hock"><text class="uni-swipe_button-text" + :style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',}">{{ item.text }}</text> + </view> + </slot> + </view> + </view> + </view> + <!-- #endif --> + +</template> +<script src="./wx.wxs" module="wxsswipe" lang="wxs"></script> + +<script module="renderswipe" lang="renderjs"> + import render from './render.js' + export default { + mounted(e, ins, owner) { + this.state = {} + }, + methods: { + showWatch(newVal, oldVal, ownerInstance, instance) { + render.showWatch(newVal, oldVal, ownerInstance, instance, this) + }, + touchstart(e, ownerInstance) { + render.touchstart(e, ownerInstance, this) + }, + touchmove(e, ownerInstance) { + render.touchmove(e, ownerInstance, this) + }, + touchend(e, ownerInstance) { + render.touchend(e, ownerInstance, this) + } + } + } +</script> +<script> + import mpwxs from './mpwxs' + import bindingx from './bindingx.js' + import mpother from './mpother' + + /** + * SwipeActionItem 滑动操作子组件 + * @description 通过滑动触发选项的容器 + * @tutorial https://ext.dcloud.net.cn/plugin?id=181 + * @property {Boolean} show = [left|right|none] 开启关闭组件,auto-close = false 时生效 + * @property {Boolean} disabled = [true|false] 是否禁止滑动 + * @property {Boolean} autoClose = [true|false] 滑动打开当前组件,是否关闭其他组件 + * @property {Number} threshold 滑动缺省值 + * @property {Array} leftOptions 左侧选项内容及样式 + * @property {Array} rgihtOptions 右侧选项内容及样式 + * @event {Function} click 点击选项按钮时触发事件,e = {content,index} ,content(点击内容)、index(下标) + * @event {Function} change 组件打开或关闭时触发,left\right\none + */ + + export default { + mixins: [mpwxs, bindingx, mpother], + emits: ['click', 'change'], + props: { + // 控制开关 + show: { + type: String, + default: 'none' + }, + + // 禁用 + disabled: { + type: Boolean, + default: false + }, + + // 是否自动关闭 + autoClose: { + type: Boolean, + default: true + }, + + // 滑动缺省距离 + threshold: { + type: Number, + default: 20 + }, + + // 左侧按钮内容 + leftOptions: { + type: Array, + default () { + return [] + } + }, + + // 右侧按钮内容 + rightOptions: { + type: Array, + default () { + return [] + } + } + + }, + // #ifndef VUE3 + // TODO vue2 + destroyed() { + if (this.__isUnmounted) return + this.uninstall() + }, + // #endif + // #ifdef VUE3 + // TODO vue3 + unmounted() { + this.__isUnmounted = true + this.uninstall() + }, + // #endif + + methods: { + uninstall() { + if (this.swipeaction) { + this.swipeaction.children.forEach((item, index) => { + if (item === this) { + this.swipeaction.children.splice(index, 1) + } + }) + } + }, + /** + * 获取父元素实例 + */ + getSwipeAction(name = 'uniSwipeAction') { + 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; + } + } + } +</script> +<style lang="scss"> + .uni-swipe { + position: relative; + /* #ifndef APP-NVUE */ + overflow: hidden; + /* #endif */ + } + + .uni-swipe_box { + /* #ifndef APP-NVUE */ + display: flex; + flex-shrink: 0; + // touch-action: none; + /* #endif */ + position: relative; + } + + .uni-swipe_content { + // border: 1px red solid; + } + + .uni-swipe_text--center { + width: 100%; + /* #ifndef APP-NVUE */ + cursor: grab; + /* #endif */ + } + + .uni-swipe_button-group { + /* #ifndef APP-NVUE */ + box-sizing: border-box; + display: flex; + /* #endif */ + flex-direction: row; + position: absolute; + top: 0; + bottom: 0; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + } + + .button-group--left { + left: 0; + transform: translateX(-100%) + } + + .button-group--right { + right: 0; + transform: translateX(100%) + } + + .uni-swipe_button { + /* #ifdef APP-NVUE */ + flex: 1; + /* #endif */ + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + justify-content: center; + align-items: center; + padding: 0 20px; + } + + .uni-swipe_button-text { + /* #ifndef APP-NVUE */ + flex-shrink: 0; + /* #endif */ + font-size: 14px; + } + + .ani { + transition-property: transform; + transition-duration: 0.3s; + transition-timing-function: cubic-bezier(0.165, 0.84, 0.44, 1); + } + + /* #ifdef MP-ALIPAY */ + .movable-area { + /* width: 100%; */ + height: 45px; + } + + .movable-view { + display: flex; + /* justify-content: center; */ + position: relative; + flex: 1; + height: 45px; + z-index: 2; + } + + .movable-view-button { + display: flex; + flex-shrink: 0; + flex-direction: row; + height: 100%; + background: #C0C0C0; + } + + /* .transition { + transition: all 0.3s; + } */ + + .movable-view-box { + flex-shrink: 0; + height: 100%; + background-color: #fff; + } + + /* #endif */ +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/wx.wxs b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action-item/wx.wxs new file mode 100644 index 000000000..b394244f2 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue new file mode 100644 index 000000000..49717824c --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue @@ -0,0 +1,60 @@ +<template> + <view> + <slot></slot> + </view> +</template> + +<script> + /** + * SwipeAction 滑动操作 + * @description 通过滑动触发选项的容器 + * @tutorial https://ext.dcloud.net.cn/plugin?id=181 + */ + export default { + name:"uniSwipeAction", + data() { + return {}; + }, + created() { + this.children = []; + }, + methods: { + // 公开给用户使用,重制组件样式 + resize(){ + // wxs 会自己计算组件大小,所以无需执行下面代码 + // #ifndef APP-VUE || H5 || MP-WEIXIN + this.children.forEach(vm=>{ + vm.init() + }) + // #endif + }, + // 公开给用户使用,关闭全部 已经打开的组件 + closeAll(){ + this.children.forEach(vm=>{ + // #ifdef APP-VUE || H5 || MP-WEIXIN + vm.is_show = 'none' + // #endif + + // #ifndef APP-VUE || H5 || MP-WEIXIN + vm.close() + // #endif + }) + }, + closeOther(vm) { + if (this.openItem && this.openItem !== vm) { + // #ifdef APP-VUE || H5 || MP-WEIXIN + this.openItem.is_show = 'none' + // #endif + + // #ifndef APP-VUE || H5 || MP-WEIXIN + this.openItem.close() + // #endif + } + // 记录上一个打开的 swipe-action-item ,用于 auto-close + this.openItem = vm + } + } + }; +</script> + +<style></style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/package.json new file mode 100644 index 000000000..c8998d9d6 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-swipe-action", + "displayName": "uni-swipe-action 滑动操作", + "version": "1.3.7", + "description": "SwipeAction 滑动操作操作组件", + "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", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-swipe-action/readme.md new file mode 100644 index 000000000..93a5cac6e --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-swiper-dot/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-swiper-dot/changelog.md new file mode 100644 index 000000000..85cf54d2a --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-swiper-dot/components/uni-swiper-dot/uni-swiper-dot.vue b/yudao-ui-admin-uniapp/uni_modules/uni-swiper-dot/components/uni-swiper-dot/uni-swiper-dot.vue new file mode 100644 index 000000000..46eb8c1fa --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-swiper-dot/components/uni-swiper-dot/uni-swiper-dot.vue @@ -0,0 +1,218 @@ +<template> + <view class="uni-swiper__warp"> + <slot /> + <view v-if="mode === 'default'" :style="{'bottom':dots.bottom + 'px'}" class="uni-swiper__dots-box" key='default'> + <view v-for="(item,index) in info" @click="clickItem(index)" :style="{ + 'width': (index === current? dots.width*2:dots.width ) + 'px','height':dots.width/2 +'px' ,'background-color':index !== current?dots.backgroundColor:dots.selectedBackgroundColor,'border-radius':'0px'}" + :key="index" class="uni-swiper__dots-item uni-swiper__dots-bar" /> + </view> + <view v-if="mode === 'dot'" :style="{'bottom':dots.bottom + 'px'}" class="uni-swiper__dots-box" key='dot'> + <view v-for="(item,index) in info" @click="clickItem(index)" :style="{ + 'width': dots.width + 'px','height':dots.height +'px' ,'background-color':index !== current?dots.backgroundColor:dots.selectedBackgroundColor,'border':index !==current ? dots.border:dots.selectedBorder}" + :key="index" class="uni-swiper__dots-item" /> + </view> + <view v-if="mode === 'round'" :style="{'bottom':dots.bottom + 'px'}" class="uni-swiper__dots-box" key='round'> + <view v-for="(item,index) in info" @click="clickItem(index)" :class="[index === current&&'uni-swiper__dots-long']" :style="{ + 'width':(index === current? dots.width*3:dots.width ) + 'px','height':dots.height +'px' ,'background-color':index !== current?dots.backgroundColor:dots.selectedBackgroundColor,'border':index !==current ? dots.border:dots.selectedBorder}" + :key="index" class="uni-swiper__dots-item " /> + </view> + <view v-if="mode === 'nav'" key='nav' :style="{'background-color':dotsStyles.backgroundColor,'bottom':'0'}" class="uni-swiper__dots-box uni-swiper__dots-nav"> + <text :style="{'color':dotsStyles.color}" class="uni-swiper__dots-nav-item">{{ (current+1)+"/"+info.length +' ' +info[current][field] }}</text> + </view> + <view v-if="mode === 'indexes'" key='indexes' :style="{'bottom':dots.bottom + 'px'}" class="uni-swiper__dots-box"> + <view v-for="(item,index) in info" @click="clickItem(index)" :style="{ + 'width':dots.width + 'px','height':dots.height +'px' ,'color':index === current?dots.selectedColor:dots.color,'background-color':index !== current?dots.backgroundColor:dots.selectedBackgroundColor,'border':index !==current ? dots.border:dots.selectedBorder}" + :key="index" class="uni-swiper__dots-item uni-swiper__dots-indexes"><text class="uni-swiper__dots-indexes-text">{{ index+1 }}</text></view> + </view> + </view> +</template> + +<script> + + /** + * SwiperDod 轮播图指示点 + * @description 自定义轮播图指示点 + * @tutorial https://ext.dcloud.net.cn/plugin?id=284 + * @property {Number} current 当前指示点索引,必须是通过 `swiper` 的 `change` 事件获取到的 `e.detail.current` + * @property {String} mode = [default|round|nav|indexes] 指示点的类型 + * @value defualt 默认指示点 + * @value round 圆形指示点 + * @value nav 条形指示点 + * @value indexes 索引指示点 + * @property {String} field mode 为 nav 时,显示的内容字段(mode = nav 时必填) + * @property {String} info 轮播图的数据,通过数组长度决定指示点个数 + * @property {Object} dotsStyles 指示点样式 + * @event {Function} clickItem 组件触发点击事件时触发,e={currentIndex} + */ + + export default { + name: 'UniSwiperDot', + emits:['clickItem'], + props: { + info: { + type: Array, + default () { + return [] + } + }, + current: { + type: Number, + default: 0 + }, + dotsStyles: { + type: Object, + default () { + return {} + } + }, + // 类型 :default(默认) indexes long nav + mode: { + type: String, + default: 'default' + }, + // 只在 nav 模式下生效,变量名称 + field: { + type: String, + default: '' + } + }, + data() { + return { + dots: { + width: 6, + height: 6, + bottom: 10, + color: '#fff', + backgroundColor: 'rgba(0, 0, 0, .3)', + border: '1px rgba(0, 0, 0, .3) solid', + selectedBackgroundColor: '#333', + selectedBorder: '1px rgba(0, 0, 0, .9) solid' + } + } + }, + watch: { + dotsStyles(newVal) { + this.dots = Object.assign(this.dots, this.dotsStyles) + }, + mode(newVal) { + if (newVal === 'indexes') { + this.dots.width = 14 + this.dots.height = 14 + } else { + this.dots.width = 6 + this.dots.height = 6 + } + } + + }, + created() { + if (this.mode === 'indexes') { + this.dots.width = 12 + this.dots.height = 12 + } + this.dots = Object.assign(this.dots, this.dotsStyles) + }, + methods: { + clickItem(index) { + this.$emit('clickItem', index) + } + } + } +</script> + +<style lang="scss"> + .uni-swiper__warp { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex: 1; + flex-direction: column; + position: relative; + overflow: hidden; + } + + .uni-swiper__dots-box { + position: absolute; + bottom: 10px; + left: 0; + right: 0; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex: 1; + flex-direction: row; + justify-content: center; + align-items: center; + } + + .uni-swiper__dots-item { + width: 8px; + border-radius: 100px; + margin-left: 6px; + background-color: rgba(0, 0, 0, 0.4); + /* #ifndef APP-NVUE */ + cursor: pointer; + /* #endif */ + /* #ifdef H5 */ + // border-width: 5px 0; + // border-style: solid; + // border-color: transparent; + // background-clip: padding-box; + /* #endif */ + // transition: width 0.2s linear; 不要取消注释,不然会不能变色 + } + + .uni-swiper__dots-item:first-child { + margin: 0; + } + + .uni-swiper__dots-default { + border-radius: 100px; + } + + .uni-swiper__dots-long { + border-radius: 50px; + } + + .uni-swiper__dots-bar { + border-radius: 50px; + } + + .uni-swiper__dots-nav { + bottom: 0px; + // height: 26px; + padding: 8px 0; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex: 1; + flex-direction: row; + justify-content: flex-start; + align-items: center; + background-color: rgba(0, 0, 0, 0.2); + } + + .uni-swiper__dots-nav-item { + /* overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; */ + font-size: 14px; + color: #fff; + margin: 0 15px; + } + + .uni-swiper__dots-indexes { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + // flex: 1; + justify-content: center; + align-items: center; + } + + .uni-swiper__dots-indexes-text { + color: #fff; + font-size: 12px; + line-height: 14px; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-swiper-dot/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-swiper-dot/package.json new file mode 100644 index 000000000..f2dd8d2a8 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-swiper-dot/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-swiper-dot/readme.md new file mode 100644 index 000000000..7d397e2cc --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-table/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-table/changelog.md new file mode 100644 index 000000000..8233b20f1 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-table/changelog.md @@ -0,0 +1,23 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-table/uni-table.vue b/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-table/uni-table.vue new file mode 100644 index 000000000..91b74fa78 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-table/uni-table.vue @@ -0,0 +1,455 @@ +<template> + <view class="uni-table-scroll" :class="{ 'table--border': border, 'border-none': !noData }"> + <!-- #ifdef H5 --> + <table class="uni-table" border="0" cellpadding="0" cellspacing="0" :class="{ 'table--stripe': stripe }" :style="{ 'min-width': minWidth + 'px' }"> + <slot></slot> + <view v-if="noData" class="uni-table-loading"> + <view class="uni-table-text" :class="{ 'empty-border': border }">{{ emptyText }}</view> + </view> + <view v-if="loading" class="uni-table-mask" :class="{ 'empty-border': border }"><div class="uni-table--loader"></div></view> + </table> + <!-- #endif --> + <!-- #ifndef H5 --> + <view class="uni-table" :style="{ 'min-width': minWidth + 'px' }" :class="{ 'table--stripe': stripe }"> + <slot></slot> + <view v-if="noData" class="uni-table-loading"> + <view class="uni-table-text" :class="{ 'empty-border': border }">{{ emptyText }}</view> + </view> + <view v-if="loading" class="uni-table-mask" :class="{ 'empty-border': border }"><div class="uni-table--loader"></div></view> + </view> + <!-- #endif --> + </view> +</template> + +<script> +/** + * Table 表格 + * @description 用于展示多条结构类似的数据 + * @tutorial https://ext.dcloud.net.cn/plugin?id=3270 + * @property {Boolean} border 是否带有纵向边框 + * @property {Boolean} stripe 是否显示斑马线 + * @property {Boolean} type 是否开启多选 + * @property {String} emptyText 空数据时显示的文本内容 + * @property {Boolean} loading 显示加载中 + * @event {Function} selection-change 开启多选时,当选择项发生变化时会触发该事件 + */ +export default { + name: 'uniTable', + options: { + virtualHost: true + }, + emits:['selection-change'], + props: { + data: { + type: Array, + default() { + return [] + } + }, + // 是否有竖线 + border: { + type: Boolean, + default: false + }, + // 是否显示斑马线 + stripe: { + type: Boolean, + default: false + }, + // 多选 + type: { + type: String, + default: '' + }, + // 没有更多数据 + emptyText: { + type: String, + default: '没有更多数据' + }, + loading: { + type: Boolean, + default: false + }, + rowKey: { + type: String, + default: '' + } + }, + data() { + return { + noData: true, + minWidth: 0, + multiTableHeads: [] + } + }, + watch: { + loading(val) {}, + data(newVal) { + let theadChildren = this.theadChildren + let rowspan = 1 + if (this.theadChildren) { + rowspan = this.theadChildren.rowspan + } + + // this.trChildren.length - rowspan + this.noData = false + // this.noData = newVal.length === 0 + } + }, + created() { + // 定义tr的实例数组 + this.trChildren = [] + this.thChildren = [] + this.theadChildren = null + this.backData = [] + this.backIndexData = [] + }, + + methods: { + isNodata() { + let theadChildren = this.theadChildren + let rowspan = 1 + if (this.theadChildren) { + rowspan = this.theadChildren.rowspan + } + this.noData = this.trChildren.length - rowspan <= 0 + }, + /** + * 选中所有 + */ + selectionAll() { + let startIndex = 1 + let theadChildren = this.theadChildren + if (!this.theadChildren) { + theadChildren = this.trChildren[0] + } else { + startIndex = theadChildren.rowspan - 1 + } + let isHaveData = this.data && this.data.length.length > 0 + theadChildren.checked = true + theadChildren.indeterminate = false + this.trChildren.forEach((item, index) => { + if (!item.disabled) { + item.checked = true + if (isHaveData && item.keyValue) { + const row = this.data.find(v => v[this.rowKey] === item.keyValue) + if (!this.backData.find(v => v[this.rowKey] === row[this.rowKey])) { + this.backData.push(row) + } + } + if (index > (startIndex - 1) && this.backIndexData.indexOf(index - startIndex) === -1) { + this.backIndexData.push(index - startIndex) + } + } + }) + // this.backData = JSON.parse(JSON.stringify(this.data)) + this.$emit('selection-change', { + detail: { + value: this.backData, + index: this.backIndexData + } + }) + }, + /** + * 用于多选表格,切换某一行的选中状态,如果使用了第二个参数,则是设置这一行选中与否(selected 为 true 则选中) + */ + toggleRowSelection(row, selected) { + // if (!this.theadChildren) return + row = [].concat(row) + + this.trChildren.forEach((item, index) => { + // if (item.keyValue) { + + const select = row.findIndex(v => { + // + if (typeof v === 'number') { + return v === index - 1 + } else { + return v[this.rowKey] === item.keyValue + } + }) + let ischeck = item.checked + if (select !== -1) { + if (typeof selected === 'boolean') { + item.checked = selected + } else { + item.checked = !item.checked + } + if (ischeck !== item.checked) { + this.check(item.rowData||item, item.checked, item.rowData?item.keyValue:null, true) + } + } + // } + }) + this.$emit('selection-change', { + detail: { + value: this.backData, + index:this.backIndexData + } + }) + }, + + /** + * 用于多选表格,清空用户的选择 + */ + clearSelection() { + let theadChildren = this.theadChildren + if (!this.theadChildren) { + theadChildren = this.trChildren[0] + } + // if (!this.theadChildren) return + theadChildren.checked = false + theadChildren.indeterminate = false + this.trChildren.forEach(item => { + // if (item.keyValue) { + item.checked = false + // } + }) + this.backData = [] + this.backIndexData = [] + this.$emit('selection-change', { + detail: { + value: [], + index: [] + } + }) + }, + /** + * 用于多选表格,切换所有行的选中状态 + */ + toggleAllSelection() { + let list = [] + let startIndex = 1 + let theadChildren = this.theadChildren + if (!this.theadChildren) { + theadChildren = this.trChildren[0] + } else { + startIndex = theadChildren.rowspan - 1 + } + this.trChildren.forEach((item, index) => { + if (!item.disabled) { + if (index > (startIndex - 1) ) { + list.push(index-startIndex) + } + } + }) + this.toggleRowSelection(list) + }, + + /** + * 选中\取消选中 + * @param {Object} child + * @param {Object} check + * @param {Object} rowValue + */ + check(child, check, keyValue, emit) { + let theadChildren = this.theadChildren + if (!this.theadChildren) { + theadChildren = this.trChildren[0] + } + + + + let childDomIndex = this.trChildren.findIndex((item, index) => child === item) + if(childDomIndex < 0){ + childDomIndex = this.data.findIndex(v=>v[this.rowKey] === keyValue) + 1 + } + const dataLen = this.trChildren.filter(v => !v.disabled && v.keyValue).length + if (childDomIndex === 0) { + check ? this.selectionAll() : this.clearSelection() + return + } + + if (check) { + if (keyValue) { + this.backData.push(child) + } + this.backIndexData.push(childDomIndex - 1) + } else { + const index = this.backData.findIndex(v => v[this.rowKey] === keyValue) + const idx = this.backIndexData.findIndex(item => item === childDomIndex - 1) + if (keyValue) { + this.backData.splice(index, 1) + } + this.backIndexData.splice(idx, 1) + } + + const domCheckAll = this.trChildren.find((item, index) => index > 0 && !item.checked && !item.disabled) + if (!domCheckAll) { + theadChildren.indeterminate = false + theadChildren.checked = true + } else { + theadChildren.indeterminate = true + theadChildren.checked = false + } + + if (this.backIndexData.length === 0) { + theadChildren.indeterminate = false + } + + if (!emit) { + this.$emit('selection-change', { + detail: { + value: this.backData, + index: this.backIndexData + } + }) + } + } + } +} +</script> + +<style lang="scss"> +$border-color: #ebeef5; + +.uni-table-scroll { + width: 100%; + /* #ifndef APP-NVUE */ + overflow-x: auto; + /* #endif */ +} + +.uni-table { + position: relative; + width: 100%; + border-radius: 5px; + // box-shadow: 0px 0px 3px 1px rgba(0, 0, 0, 0.1); + background-color: #fff; + /* #ifndef APP-NVUE */ + box-sizing: border-box; + display: table; + overflow-x: auto; + ::v-deep .uni-table-tr:nth-child(n + 2) { + &:hover { + background-color: #f5f7fa; + } + } + ::v-deep .uni-table-thead { + .uni-table-tr { + // background-color: #f5f7fa; + &:hover { + background-color:#fafafa; + } + } + } + /* #endif */ +} + +.table--border { + border: 1px $border-color solid; + border-right: none; +} + +.border-none { + /* #ifndef APP-NVUE */ + border-bottom: none; + /* #endif */ +} + +.table--stripe { + /* #ifndef APP-NVUE */ + ::v-deep .uni-table-tr:nth-child(2n + 3) { + background-color: #fafafa; + } + /* #endif */ +} + +/* 表格加载、无数据样式 */ +.uni-table-loading { + position: relative; + /* #ifndef APP-NVUE */ + display: table-row; + /* #endif */ + height: 50px; + line-height: 50px; + overflow: hidden; + box-sizing: border-box; +} +.empty-border { + border-right: 1px $border-color solid; +} +.uni-table-text { + position: absolute; + right: 0; + left: 0; + text-align: center; + font-size: 14px; + color: #999; +} + +.uni-table-mask { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + background-color: rgba(255, 255, 255, 0.8); + z-index: 99; + /* #ifndef APP-NVUE */ + display: flex; + margin: auto; + transition: all 0.5s; + /* #endif */ + justify-content: center; + align-items: center; +} + +.uni-table--loader { + width: 30px; + height: 30px; + border: 2px solid #aaa; + // border-bottom-color: transparent; + border-radius: 50%; + /* #ifndef APP-NVUE */ + animation: 2s uni-table--loader linear infinite; + /* #endif */ + position: relative; +} + +@keyframes uni-table--loader { + 0% { + transform: rotate(360deg); + } + + 10% { + border-left-color: transparent; + } + + 20% { + border-bottom-color: transparent; + } + + 30% { + border-right-color: transparent; + } + + 40% { + border-top-color: transparent; + } + + 50% { + transform: rotate(0deg); + } + + 60% { + border-top-color: transparent; + } + + 70% { + border-left-color: transparent; + } + + 80% { + border-bottom-color: transparent; + } + + 90% { + border-right-color: transparent; + } + + 100% { + transform: rotate(-360deg); + } +} +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-tbody/uni-tbody.vue b/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-tbody/uni-tbody.vue new file mode 100644 index 000000000..fbe1bdcb1 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-tbody/uni-tbody.vue @@ -0,0 +1,29 @@ +<template> + <!-- #ifdef H5 --> + <tbody> + <slot></slot> + </tbody> + <!-- #endif --> + <!-- #ifndef H5 --> + <view><slot></slot></view> + <!-- #endif --> +</template> + +<script> +export default { + name: 'uniBody', + options: { + virtualHost: true + }, + data() { + return { + + } + }, + created() {}, + methods: {} +} +</script> + +<style> +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-td/uni-td.vue b/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-td/uni-td.vue new file mode 100644 index 000000000..9ce93e936 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-td/uni-td.vue @@ -0,0 +1,90 @@ +<template> + <!-- #ifdef H5 --> + <td class="uni-table-td" :rowspan="rowspan" :colspan="colspan" :class="{'table--border':border}" :style="{width:width + 'px','text-align':align}"> + <slot></slot> + </td> + <!-- #endif --> + <!-- #ifndef H5 --> + <!-- :class="{'table--border':border}" --> + <view class="uni-table-td" :class="{'table--border':border}" :style="{width:width + 'px','text-align':align}"> + <slot></slot> + </view> + <!-- #endif --> + +</template> + +<script> + /** + * Td 单元格 + * @description 表格中的标准单元格组件 + * @tutorial https://ext.dcloud.net.cn/plugin?id=3270 + * @property {Number} align = [left|center|right] 单元格对齐方式 + */ + export default { + name: 'uniTd', + options: { + virtualHost: true + }, + props: { + width: { + type: [String, Number], + default: '' + }, + align: { + type: String, + default: 'left' + }, + rowspan: { + type: [Number,String], + default: 1 + }, + colspan: { + type: [Number,String], + default: 1 + } + }, + data() { + return { + border: false + }; + }, + created() { + this.root = this.getTable() + this.border = this.root.border + }, + methods: { + /** + * 获取父元素实例 + */ + getTable() { + let parent = this.$parent; + let parentName = parent.$options.name; + while (parentName !== 'uniTable') { + parent = parent.$parent; + if (!parent) return false; + parentName = parent.$options.name; + } + return parent; + }, + } + } +</script> + +<style lang="scss"> + $border-color:#EBEEF5; + + .uni-table-td { + display: table-cell; + padding: 8px 10px; + font-size: 14px; + border-bottom: 1px $border-color solid; + font-weight: 400; + color: #606266; + line-height: 23px; + box-sizing: border-box; + } + + .table--border { + border-right: 1px $border-color solid; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-th/filter-dropdown.vue b/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-th/filter-dropdown.vue new file mode 100644 index 000000000..bc9a0e3b0 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-th/filter-dropdown.vue @@ -0,0 +1,503 @@ +<template> + <view class="uni-filter-dropdown"> + <view class="dropdown-btn" @click="onDropdown"> + <view class="icon-select" :class="{active: canReset}" v-if="isSelect || isRange"></view> + <view class="icon-search" :class="{active: canReset}" v-if="isSearch"> + <view class="icon-search-0"></view> + <view class="icon-search-1"></view> + </view> + <view class="icon-calendar" :class="{active: canReset}" v-if="isDate"> + <view class="icon-calendar-0"></view> + <view class="icon-calendar-1"></view> + </view> + </view> + <view class="uni-dropdown-cover" v-if="isOpened" @click="handleClose"></view> + <view class="dropdown-popup dropdown-popup-right" v-if="isOpened" @click.stop> + <!-- select--> + <view v-if="isSelect" class="list"> + <label class="flex-r a-i-c list-item" v-for="(item,index) in dataList" :key="index" + @click="onItemClick($event, index)"> + <check-box class="check" :checked="item.checked" /> + <view class="checklist-content"> + <text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text> + </view> + </label> + </view> + <view v-if="isSelect" class="flex-r opera-area"> + <view class="flex-f btn btn-default" :class="{disable: !canReset}" @click="handleSelectReset"> + {{resource.reset}}</view> + <view class="flex-f btn btn-submit" @click="handleSelectSubmit">{{resource.submit}}</view> + </view> + <!-- search --> + <view v-if="isSearch" class="search-area"> + <input class="search-input" v-model="filterValue" /> + </view> + <view v-if="isSearch" class="flex-r opera-area"> + <view class="flex-f btn btn-submit" @click="handleSearchSubmit">{{resource.search}}</view> + <view class="flex-f btn btn-default" :class="{disable: !canReset}" @click="handleSearchReset"> + {{resource.reset}}</view> + </view> + <!-- range --> + <view v-if="isRange"> + <view class="input-label">{{resource.gt}}</view> + <input class="input" v-model="gtValue" /> + <view class="input-label">{{resource.lt}}</view> + <input class="input" v-model="ltValue" /> + </view> + <view v-if="isRange" class="flex-r opera-area"> + <view class="flex-f btn btn-default" :class="{disable: !canReset}" @click="handleRangeReset"> + {{resource.reset}}</view> + <view class="flex-f btn btn-submit" @click="handleRangeSubmit">{{resource.submit}}</view> + </view> + <!-- date --> + <view v-if="isDate"> + <uni-datetime-picker ref="datetimepicker" :value="dateRange" type="datetimerange" return-type="timestamp" @change="datetimechange" @maskClick="timepickerclose"> + <view></view> + </uni-datetime-picker> + </view> + </view> + </view> +</template> + +<script> + import checkBox from '../uni-tr/table-checkbox.vue' + + const resource = { + "reset": "重置", + "search": "搜索", + "submit": "确定", + "filter": "筛选", + "gt": "大于等于", + "lt": "小于等于", + "date": "日期范围" + } + + const DropdownType = { + Select: "select", + Search: "search", + Range: "range", + Date: "date", + Timestamp: "timestamp" + } + + export default { + name: 'FilterDropdown', + emits:['change'], + components: { + checkBox + }, + options: { + virtualHost: true + }, + props: { + filterType: { + type: String, + default: DropdownType.Select + }, + filterData: { + type: Array, + default () { + return [] + } + }, + mode: { + type: String, + default: 'default' + }, + map: { + type: Object, + default () { + return { + text: 'text', + value: 'value' + } + } + } + }, + computed: { + canReset() { + if (this.isSearch) { + return this.filterValue.length > 0 + } + if (this.isSelect) { + return this.checkedValues.length > 0 + } + if (this.isRange) { + return (this.gtValue.length > 0 && this.ltValue.length > 0) + } + if (this.isDate) { + return this.dateSelect.length > 0 + } + return false + }, + isSelect() { + return this.filterType === DropdownType.Select + }, + isSearch() { + return this.filterType === DropdownType.Search + }, + isRange() { + return this.filterType === DropdownType.Range + }, + isDate() { + return (this.filterType === DropdownType.Date || this.filterType === DropdownType.Timestamp) + } + }, + watch: { + filterData(newVal) { + this._copyFilters() + }, + indeterminate(newVal) { + this.isIndeterminate = newVal + } + }, + data() { + return { + resource, + enabled: true, + isOpened: false, + dataList: [], + filterValue: '', + checkedValues: [], + gtValue: '', + ltValue: '', + dateRange: [], + dateSelect: [] + }; + }, + created() { + this._copyFilters() + }, + methods: { + _copyFilters() { + let dl = JSON.parse(JSON.stringify(this.filterData)) + for (let i = 0; i < dl.length; i++) { + if (dl[i].checked === undefined) { + dl[i].checked = false + } + } + this.dataList = dl + }, + openPopup() { + this.isOpened = true + if (this.isDate) { + this.$nextTick(() => { + if (!this.dateRange.length) { + this.resetDate() + } + this.$refs.datetimepicker.show() + }) + } + }, + closePopup() { + this.isOpened = false + }, + handleClose(e) { + this.closePopup() + }, + resetDate() { + let date = new Date() + let dateText = date.toISOString().split('T')[0] + this.dateRange = [dateText + ' 0:00:00', dateText + ' 23:59:59'] + }, + onDropdown(e) { + this.openPopup() + }, + onItemClick(e, index) { + let items = this.dataList + let listItem = items[index] + if (listItem.checked === undefined) { + items[index].checked = true + } else { + items[index].checked = !listItem.checked + } + + let checkvalues = [] + for (let i = 0; i < items.length; i++) { + const item = items[i] + if (item.checked) { + checkvalues.push(item.value) + } + } + this.checkedValues = checkvalues + }, + datetimechange(e) { + this.closePopup() + this.dateRange = e + this.dateSelect = e + this.$emit('change', { + filterType: this.filterType, + filter: e + }) + }, + timepickerclose(e) { + this.closePopup() + }, + handleSelectSubmit() { + this.closePopup() + this.$emit('change', { + filterType: this.filterType, + filter: this.checkedValues + }) + }, + handleSelectReset() { + if (!this.canReset) { + return; + } + var items = this.dataList + for (let i = 0; i < items.length; i++) { + let item = items[i] + this.$set(item, 'checked', false) + } + this.checkedValues = [] + this.handleSelectSubmit() + }, + handleSearchSubmit() { + this.closePopup() + this.$emit('change', { + filterType: this.filterType, + filter: this.filterValue + }) + }, + handleSearchReset() { + if (!this.canReset) { + return; + } + this.filterValue = '' + this.handleSearchSubmit() + }, + handleRangeSubmit(isReset) { + this.closePopup() + this.$emit('change', { + filterType: this.filterType, + filter: isReset === true ? [] : [parseInt(this.gtValue), parseInt(this.ltValue)] + }) + }, + handleRangeReset() { + if (!this.canReset) { + return; + } + this.gtValue = '' + this.ltValue = '' + this.handleRangeSubmit(true) + } + } + } +</script> + +<style lang="scss"> + .flex-r { + display: flex; + flex-direction: row; + } + + .flex-f { + flex: 1; + } + + .a-i-c { + align-items: center; + } + + .j-c-c { + justify-content: center; + } + + .icon-select { + width: 14px; + height: 16px; + border: solid 6px transparent; + border-top: solid 6px #ddd; + border-bottom: none; + background-color: #ddd; + background-clip: content-box; + box-sizing: border-box; + } + + .icon-select.active { + background-color: #1890ff; + border-top-color: #1890ff; + } + + .icon-search { + width: 12px; + height: 16px; + position: relative; + } + + .icon-search-0 { + border: 2px solid #ddd; + border-radius: 8px; + width: 7px; + height: 7px; + } + + .icon-search-1 { + position: absolute; + top: 8px; + right: 0; + width: 1px; + height: 7px; + background-color: #ddd; + transform: rotate(-45deg); + } + + .icon-search.active .icon-search-0 { + border-color: #1890ff; + } + + .icon-search.active .icon-search-1 { + background-color: #1890ff; + } + + .icon-calendar { + color: #ddd; + width: 14px; + height: 16px; + } + + .icon-calendar-0 { + height: 4px; + margin-top: 3px; + margin-bottom: 1px; + background-color: #ddd; + border-radius: 2px 2px 1px 1px; + position: relative; + } + .icon-calendar-0:before, .icon-calendar-0:after { + content: ''; + position: absolute; + top: -3px; + width: 4px; + height: 3px; + border-radius: 1px; + background-color: #ddd; + } + .icon-calendar-0:before { + left: 2px; + } + .icon-calendar-0:after { + right: 2px; + } + + .icon-calendar-1 { + height: 9px; + background-color: #ddd; + border-radius: 1px 1px 2px 2px; + } + + .icon-calendar.active { + color: #1890ff; + } + + .icon-calendar.active .icon-calendar-0, + .icon-calendar.active .icon-calendar-1, + .icon-calendar.active .icon-calendar-0:before, + .icon-calendar.active .icon-calendar-0:after { + background-color: #1890ff; + } + + .uni-filter-dropdown { + position: relative; + font-weight: normal; + } + + .dropdown-popup { + position: absolute; + top: 100%; + background-color: #fff; + box-shadow: 0 3px 6px -4px #0000001f, 0 6px 16px #00000014, 0 9px 28px 8px #0000000d; + min-width: 150px; + z-index: 1000; + } + + .dropdown-popup-left { + left: 0; + } + + .dropdown-popup-right { + right: 0; + } + + .uni-dropdown-cover { + position: fixed; + left: 0; + top: 0; + right: 0; + bottom: 0; + background-color: transparent; + z-index: 100; + } + + .list { + margin-top: 5px; + margin-bottom: 5px; + } + + .list-item { + padding: 5px 10px; + text-align: left; + } + + .list-item:hover { + background-color: #f0f0f0; + } + + .check { + margin-right: 5px; + } + + .search-area { + padding: 10px; + } + + .search-input { + font-size: 12px; + border: 1px solid #f0f0f0; + border-radius: 3px; + padding: 2px 5px; + min-width: 150px; + text-align: left; + } + + .input-label { + margin: 10px 10px 5px 10px; + text-align: left; + } + + .input { + font-size: 12px; + border: 1px solid #f0f0f0; + border-radius: 3px; + margin: 10px; + padding: 2px 5px; + min-width: 150px; + text-align: left; + } + + .opera-area { + cursor: default; + border-top: 1px solid #ddd; + padding: 5px; + } + + .opera-area .btn { + font-size: 12px; + border-radius: 3px; + margin: 5px; + padding: 4px 4px; + } + + .btn-default { + border: 1px solid #ddd; + } + + .btn-default.disable { + border-color: transparent; + } + + .btn-submit { + background-color: #1890ff; + color: #ffffff; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-th/uni-th.vue b/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-th/uni-th.vue new file mode 100644 index 000000000..883e3f2ab --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-th/uni-th.vue @@ -0,0 +1,278 @@ +<template> + <!-- #ifdef H5 --> + <th :rowspan="rowspan" :colspan="colspan" class="uni-table-th" :class="{ 'table--border': border }" :style="{ width: customWidth + 'px', 'text-align': align }"> + <view class="uni-table-th-row"> + <view class="uni-table-th-content" :style="{ 'justify-content': contentAlign }" @click="sort"> + <slot></slot> + <view v-if="sortable" class="arrow-box"> + <text class="arrow up" :class="{ active: ascending }" @click.stop="ascendingFn"></text> + <text class="arrow down" :class="{ active: descending }" @click.stop="descendingFn"></text> + </view> + </view> + <dropdown v-if="filterType || filterData.length" :filterData="filterData" :filterType="filterType" @change="ondropdown"></dropdown> + </view> + </th> + <!-- #endif --> + <!-- #ifndef H5 --> + <view class="uni-table-th" :class="{ 'table--border': border }" :style="{ width: customWidth + 'px', 'text-align': align }"><slot></slot></view> + <!-- #endif --> +</template> + +<script> + // #ifdef H5 + import dropdown from './filter-dropdown.vue' + // #endif +/** + * Th 表头 + * @description 表格内的表头单元格组件 + * @tutorial https://ext.dcloud.net.cn/plugin?id=3270 + * @property {Number | String} width 单元格宽度(支持纯数字、携带单位px或rpx) + * @property {Boolean} sortable 是否启用排序 + * @property {Number} align = [left|center|right] 单元格对齐方式 + * @value left 单元格文字左侧对齐 + * @value center 单元格文字居中 + * @value right 单元格文字右侧对齐 + * @property {Array} filterData 筛选数据 + * @property {String} filterType [search|select] 筛选类型 + * @value search 关键字搜素 + * @value select 条件选择 + * @event {Function} sort-change 排序触发事件 + */ +export default { + name: 'uniTh', + options: { + virtualHost: true + }, + components: { + // #ifdef H5 + dropdown + // #endif + }, + emits:['sort-change','filter-change'], + props: { + width: { + type: [String, Number], + default: '' + }, + align: { + type: String, + default: 'left' + }, + rowspan: { + type: [Number, String], + default: 1 + }, + colspan: { + type: [Number, String], + default: 1 + }, + sortable: { + type: Boolean, + default: false + }, + filterType: { + type: String, + default: "" + }, + filterData: { + type: Array, + default () { + return [] + } + } + }, + data() { + return { + border: false, + ascending: false, + descending: false + } + }, + computed: { + // 根据props中的width属性 自动匹配当前th的宽度(px) + customWidth(){ + if(typeof this.width === 'number'){ + return this.width + } else if(typeof this.width === 'string') { + let regexHaveUnitPx = new RegExp(/^[1-9][0-9]*px$/g) + let regexHaveUnitRpx = new RegExp(/^[1-9][0-9]*rpx$/g) + let regexHaveNotUnit = new RegExp(/^[1-9][0-9]*$/g) + if (this.width.match(regexHaveUnitPx) !== null) { // 携带了 px + return this.width.replace('px', '') + } else if (this.width.match(regexHaveUnitRpx) !== null) { // 携带了 rpx + let numberRpx = Number(this.width.replace('rpx', '')) + let widthCoe = uni.getSystemInfoSync().screenWidth / 750 + return Math.round(numberRpx * widthCoe) + } else if (this.width.match(regexHaveNotUnit) !== null) { // 未携带 rpx或px 的纯数字 String + return this.width + } else { // 不符合格式 + return '' + } + } else { + return '' + } + }, + contentAlign() { + let align = 'left' + switch (this.align) { + case 'left': + align = 'flex-start' + break + case 'center': + align = 'center' + break + case 'right': + align = 'flex-end' + break + } + return align + } + }, + created() { + this.root = this.getTable('uniTable') + this.rootTr = this.getTable('uniTr') + this.rootTr.minWidthUpdate(this.customWidth ? this.customWidth : 140) + this.border = this.root.border + this.root.thChildren.push(this) + }, + methods: { + sort() { + if (!this.sortable) return + this.clearOther() + if (!this.ascending && !this.descending) { + this.ascending = true + this.$emit('sort-change', { order: 'ascending' }) + return + } + if (this.ascending && !this.descending) { + this.ascending = false + this.descending = true + this.$emit('sort-change', { order: 'descending' }) + return + } + + if (!this.ascending && this.descending) { + this.ascending = false + this.descending = false + this.$emit('sort-change', { order: null }) + } + }, + ascendingFn() { + this.clearOther() + this.ascending = !this.ascending + this.descending = false + this.$emit('sort-change', { order: this.ascending ? 'ascending' : null }) + }, + descendingFn() { + this.clearOther() + this.descending = !this.descending + this.ascending = false + this.$emit('sort-change', { order: this.descending ? 'descending' : null }) + }, + clearOther() { + this.root.thChildren.map(item => { + if (item !== this) { + item.ascending = false + item.descending = false + } + return item + }) + }, + ondropdown(e) { + this.$emit("filter-change", e) + }, + /** + * 获取父元素实例 + */ + getTable(name) { + 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 + } + } +} +</script> + +<style lang="scss"> +$border-color: #ebeef5; + +.uni-table-th { + padding: 12px 10px; + /* #ifndef APP-NVUE */ + display: table-cell; + box-sizing: border-box; + /* #endif */ + font-size: 14px; + font-weight: bold; + color: #909399; + border-bottom: 1px $border-color solid; +} + +.uni-table-th-row { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; +} + +.table--border { + border-right: 1px $border-color solid; +} +.uni-table-th-content { + display: flex; + align-items: center; + flex: 1; +} +.arrow-box { +} +.arrow { + display: block; + position: relative; + width: 10px; + height: 8px; + // border: 1px red solid; + left: 5px; + overflow: hidden; + cursor: pointer; +} +.down { + top: 3px; + ::after { + content: ''; + width: 8px; + height: 8px; + position: absolute; + left: 2px; + top: -5px; + transform: rotate(45deg); + background-color: #ccc; + } + &.active { + ::after { + background-color: #007aff; + } + } +} +.up { + ::after { + content: ''; + width: 8px; + height: 8px; + position: absolute; + left: 2px; + top: 5px; + transform: rotate(45deg); + background-color: #ccc; + } + &.active { + ::after { + background-color: #007aff; + } + } +} +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-thead/uni-thead.vue b/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-thead/uni-thead.vue new file mode 100644 index 000000000..0dd18cd8c --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-thead/uni-thead.vue @@ -0,0 +1,129 @@ +<template> + <!-- #ifdef H5 --> + <thead class="uni-table-thead"> + <tr class="uni-table-tr"> + <th :rowspan="rowspan" colspan="1" class="checkbox" :class="{ 'tr-table--border': border }"> + <table-checkbox :indeterminate="indeterminate" :checked="checked" @checkboxSelected="checkboxSelected"></table-checkbox> + </th> + </tr> + <slot></slot> + </thead> + <!-- #endif --> + <!-- #ifndef H5 --> + <view class="uni-table-thead"><slot></slot></view> + <!-- #endif --> +</template> + +<script> +import tableCheckbox from '../uni-tr/table-checkbox.vue' +export default { + name: 'uniThead', + components: { + tableCheckbox + }, + options: { + virtualHost: true + }, + data() { + return { + border: false, + selection: false, + rowspan: 1, + indeterminate: false, + checked: false + } + }, + created() { + this.root = this.getTable() + // #ifdef H5 + this.root.theadChildren = this + // #endif + this.border = this.root.border + this.selection = this.root.type + }, + methods: { + init(self) { + this.rowspan++ + }, + checkboxSelected(e) { + this.indeterminate = false + const backIndexData = this.root.backIndexData + const data = this.root.trChildren.filter(v => !v.disabled && v.keyValue) + if (backIndexData.length === data.length) { + this.checked = false + this.root.clearSelection() + } else { + this.checked = true + this.root.selectionAll() + } + }, + /** + * 获取父元素实例 + */ + getTable(name = 'uniTable') { + 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 + } + } +} +</script> + +<style lang="scss"> +$border-color: #ebeef5; + +.uni-table-thead { + display: table-header-group; +} + +.uni-table-tr { + /* #ifndef APP-NVUE */ + display: table-row; + transition: all 0.3s; + box-sizing: border-box; + /* #endif */ + border: 1px red solid; + background-color: #fafafa; +} + +.checkbox { + padding: 0 8px; + width: 26px; + padding-left: 12px; + /* #ifndef APP-NVUE */ + display: table-cell; + vertical-align: middle; + /* #endif */ + color: #333; + font-weight: 500; + border-bottom: 1px $border-color solid; + font-size: 14px; + // text-align: center; +} + +.tr-table--border { + border-right: 1px $border-color solid; +} + +/* #ifndef APP-NVUE */ +.uni-table-tr { + ::v-deep .uni-table-th { + &.table--border:last-child { + // border-right: none; + } + } + + ::v-deep .uni-table-td { + &.table--border:last-child { + // border-right: none; + } + } +} + +/* #endif */ +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-tr/table-checkbox.vue b/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-tr/table-checkbox.vue new file mode 100644 index 000000000..158f3ffd0 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-tr/table-checkbox.vue @@ -0,0 +1,179 @@ +<template> + <view class="uni-table-checkbox" @click="selected"> + <view v-if="!indeterminate" class="checkbox__inner" :class="{'is-checked':isChecked,'is-disable':isDisabled}"> + <view class="checkbox__inner-icon"></view> + </view> + <view v-else class="checkbox__inner checkbox--indeterminate"> + <view class="checkbox__inner-icon"></view> + </view> + </view> +</template> + +<script> + export default { + name: 'TableCheckbox', + emits:['checkboxSelected'], + props: { + indeterminate: { + type: Boolean, + default: false + }, + checked: { + type: [Boolean,String], + default: false + }, + disabled: { + type: Boolean, + default: false + }, + index: { + type: Number, + default: -1 + }, + cellData: { + type: Object, + default () { + return {} + } + } + }, + watch:{ + checked(newVal){ + if(typeof this.checked === 'boolean'){ + this.isChecked = newVal + }else{ + this.isChecked = true + } + }, + indeterminate(newVal){ + this.isIndeterminate = newVal + } + }, + data() { + return { + isChecked: false, + isDisabled: false, + isIndeterminate:false + } + }, + created() { + if(typeof this.checked === 'boolean'){ + this.isChecked = this.checked + } + this.isDisabled = this.disabled + }, + methods: { + selected() { + if (this.isDisabled) return + this.isIndeterminate = false + this.isChecked = !this.isChecked + this.$emit('checkboxSelected', { + checked: this.isChecked, + data: this.cellData + }) + } + } + } +</script> + +<style lang="scss"> + $checked-color: #007aff; + $border-color: #DCDFE6; + $disable:0.4; + + .uni-table-checkbox { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + position: relative; + margin: 5px 0; + cursor: pointer; + + // 多选样式 + .checkbox__inner { + /* #ifndef APP-NVUE */ + flex-shrink: 0; + box-sizing: border-box; + /* #endif */ + position: relative; + width: 16px; + height: 16px; + border: 1px solid $border-color; + border-radius: 2px; + background-color: #fff; + z-index: 1; + + .checkbox__inner-icon { + position: absolute; + /* #ifdef APP-NVUE */ + top: 2px; + /* #endif */ + /* #ifndef APP-NVUE */ + top: 2px; + /* #endif */ + left: 5px; + height: 7px; + width: 3px; + border: 1px solid #fff; + border-left: 0; + border-top: 0; + opacity: 0; + transform-origin: center; + transform: rotate(45deg); + box-sizing: content-box; + } + + &.checkbox--indeterminate { + border-color: $checked-color; + background-color: $checked-color; + + .checkbox__inner-icon { + position: absolute; + opacity: 1; + transform: rotate(0deg); + height: 2px; + top: 0; + bottom: 0; + margin: auto; + left: 0px; + right: 0px; + bottom: 0; + width: auto; + border: none; + border-radius: 2px; + transform: scale(0.5); + background-color: #fff; + } + } + &:hover{ + border-color: $checked-color; + } + // 禁用 + &.is-disable { + /* #ifdef H5 */ + cursor: not-allowed; + /* #endif */ + background-color: #F2F6FC; + border-color: $border-color; + } + + // 选中 + &.is-checked { + border-color: $checked-color; + background-color: $checked-color; + + .checkbox__inner-icon { + opacity: 1; + transform: rotate(45deg); + } + + // 选中禁用 + &.is-disable { + opacity: $disable; + } + } + + } + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-tr/uni-tr.vue b/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-tr/uni-tr.vue new file mode 100644 index 000000000..f9b96716c --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-table/components/uni-tr/uni-tr.vue @@ -0,0 +1,171 @@ +<template> + <!-- #ifdef H5 --> + <tr class="uni-table-tr"> + <th v-if="selection === 'selection' && ishead" class="checkbox" :class="{ 'tr-table--border': border }"> + <table-checkbox :checked="checked" :indeterminate="indeterminate" :disabled="disabled" @checkboxSelected="checkboxSelected"></table-checkbox> + </th> + <slot></slot> + <!-- <uni-th class="th-fixed">123</uni-th> --> + </tr> + <!-- #endif --> + <!-- #ifndef H5 --> + <view class="uni-table-tr"> + <view v-if="selection === 'selection' " class="checkbox" :class="{ 'tr-table--border': border }"> + <table-checkbox :checked="checked" :indeterminate="indeterminate" :disabled="disabled" @checkboxSelected="checkboxSelected"></table-checkbox> + </view> + <slot></slot> + </view> + <!-- #endif --> +</template> + +<script> + import tableCheckbox from './table-checkbox.vue' +/** + * Tr 表格行组件 + * @description 表格行组件 仅包含 th,td 组件 + * @tutorial https://ext.dcloud.net.cn/plugin?id= + */ +export default { + name: 'uniTr', + components: { tableCheckbox }, + props: { + disabled: { + type: Boolean, + default: false + }, + keyValue: { + type: [String, Number], + default: '' + } + }, + options: { + virtualHost: true + }, + data() { + return { + value: false, + border: false, + selection: false, + widthThArr: [], + ishead: true, + checked: false, + indeterminate:false + } + }, + created() { + this.root = this.getTable() + this.head = this.getTable('uniThead') + if (this.head) { + this.ishead = false + this.head.init(this) + } + this.border = this.root.border + this.selection = this.root.type + this.root.trChildren.push(this) + const rowData = this.root.data.find(v => v[this.root.rowKey] === this.keyValue) + if(rowData){ + this.rowData = rowData + } + this.root.isNodata() + }, + mounted() { + if (this.widthThArr.length > 0) { + const selectionWidth = this.selection === 'selection' ? 50 : 0 + this.root.minWidth = this.widthThArr.reduce((a, b) => Number(a) + Number(b)) + selectionWidth + } + }, + // #ifndef VUE3 + destroyed() { + const index = this.root.trChildren.findIndex(i => i === this) + this.root.trChildren.splice(index, 1) + this.root.isNodata() + }, + // #endif + // #ifdef VUE3 + unmounted() { + const index = this.root.trChildren.findIndex(i => i === this) + this.root.trChildren.splice(index, 1) + this.root.isNodata() + }, + // #endif + methods: { + minWidthUpdate(width) { + this.widthThArr.push(width) + }, + // 选中 + checkboxSelected(e) { + let rootData = this.root.data.find(v => v[this.root.rowKey] === this.keyValue) + this.checked = e.checked + this.root.check(rootData||this, e.checked,rootData? this.keyValue:null) + }, + change(e) { + this.root.trChildren.forEach(item => { + if (item === this) { + this.root.check(this, e.detail.value.length > 0 ? true : false) + } + }) + }, + /** + * 获取父元素实例 + */ + getTable(name = 'uniTable') { + 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 + } + } +} +</script> + +<style lang="scss"> +$border-color: #ebeef5; + +.uni-table-tr { + /* #ifndef APP-NVUE */ + display: table-row; + transition: all 0.3s; + box-sizing: border-box; + /* #endif */ +} + +.checkbox { + padding: 0 8px; + width: 26px; + padding-left: 12px; + /* #ifndef APP-NVUE */ + display: table-cell; + vertical-align: middle; + /* #endif */ + color: #333; + font-weight: 500; + border-bottom: 1px $border-color solid; + font-size: 14px; + // text-align: center; +} + +.tr-table--border { + border-right: 1px $border-color solid; +} + +/* #ifndef APP-NVUE */ +.uni-table-tr { + ::v-deep .uni-table-th { + &.table--border:last-child { + // border-right: none; + } + } + + ::v-deep .uni-table-td { + &.table--border:last-child { + // border-right: none; + } + } +} + +/* #endif */ +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/en.json b/yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/en.json new file mode 100644 index 000000000..e32023cc1 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/es.json b/yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/es.json new file mode 100644 index 000000000..9afd04bb6 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/fr.json b/yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/fr.json new file mode 100644 index 000000000..b0062371d --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/index.js b/yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/index.js new file mode 100644 index 000000000..2469dd02b --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/zh-Hans.json b/yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/zh-Hans.json new file mode 100644 index 000000000..862af1794 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/zh-Hant.json b/yudao-ui-admin-uniapp/uni_modules/uni-table/i18n/zh-Hant.json new file mode 100644 index 000000000..64f80615b --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-table/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-table/package.json new file mode 100644 index 000000000..f224ab72a --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-table/package.json @@ -0,0 +1,86 @@ +{ + "id": "uni-table", + "displayName": "uni-table 表格", + "version": "1.2.1", + "description": "表格组件,多用于展示多条结构类似的数据,如", + "keywords": [ + "uni-ui", + "uniui", + "table", + "表格" +], + "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-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/yudao-ui-admin-uniapp/uni_modules/uni-table/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-table/readme.md new file mode 100644 index 000000000..bb08c7918 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-tag/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-tag/changelog.md new file mode 100644 index 000000000..c0c5839b1 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-tag/components/uni-tag/uni-tag.vue b/yudao-ui-admin-uniapp/uni_modules/uni-tag/components/uni-tag/uni-tag.vue new file mode 100644 index 000000000..6378a0b97 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-tag/components/uni-tag/uni-tag.vue @@ -0,0 +1,252 @@ +<template> + <text class="uni-tag" v-if="text" :class="classes" :style="customStyle" @click="onClick">{{text}}</text> +</template> + +<script> + /** + * Tag 标签 + * @description 用于展示1个或多个文字标签,可点击切换选中、不选中的状态 + * @tutorial https://ext.dcloud.net.cn/plugin?id=35 + * @property {String} text 标签内容 + * @property {String} size = [default|small|mini] 大小尺寸 + * @value default 正常 + * @value small 小尺寸 + * @value mini 迷你尺寸 + * @property {String} type = [default|primary|success|warning|error] 颜色类型 + * @value default 灰色 + * @value primary 蓝色 + * @value success 绿色 + * @value warning 黄色 + * @value error 红色 + * @property {Boolean} disabled = [true|false] 是否为禁用状态 + * @property {Boolean} inverted = [true|false] 是否无需背景颜色(空心标签) + * @property {Boolean} circle = [true|false] 是否为圆角 + * @event {Function} click 点击 Tag 触发事件 + */ + + export default { + name: "UniTag", + emits: ['click'], + props: { + type: { + // 标签类型default、primary、success、warning、error、royal + type: String, + default: "default" + }, + size: { + // 标签大小 normal, small + type: String, + default: "normal" + }, + // 标签内容 + text: { + type: String, + default: "" + }, + disabled: { + // 是否为禁用状态 + type: [Boolean, String], + default: false + }, + inverted: { + // 是否为空心 + type: [Boolean, String], + default: false + }, + circle: { + // 是否为圆角样式 + type: [Boolean, String], + default: false + }, + mark: { + // 是否为标记样式 + type: [Boolean, String], + default: false + }, + customStyle: { + type: String, + default: '' + } + }, + computed: { + classes() { + const { + type, + disabled, + inverted, + circle, + mark, + size, + isTrue + } = this + const classArr = [ + 'uni-tag--' + type, + 'uni-tag--' + size, + isTrue(disabled) ? 'uni-tag--disabled' : '', + isTrue(inverted) ? 'uni-tag--' + type + '--inverted' : '', + isTrue(circle) ? 'uni-tag--circle' : '', + isTrue(mark) ? 'uni-tag--mark' : '', + // type === 'default' ? 'uni-tag--default' : 'uni-tag-text', + isTrue(inverted) ? 'uni-tag--inverted uni-tag-text--' + type : '', + size === 'small' ? 'uni-tag-text--small' : '' + ] + // 返回类的字符串,兼容字节小程序 + return classArr.join(' ') + } + }, + methods: { + isTrue(value) { + return value === true || value === 'true' + }, + onClick() { + if (this.isTrue(this.disabled)) return + this.$emit("click"); + } + } + }; +</script> + +<style lang="scss"> + $uni-primary: #2979ff !default; + $uni-success: #18bc37 !default; + $uni-warning: #f3a73f !default; + $uni-error: #e43d33 !default; + $uni-info: #8f939c !default; + + + $tag-default-pd: 4px 7px; + $tag-small-pd: 2px 5px; + $tag-mini-pd: 1px 3px; + + .uni-tag { + line-height: 14px; + font-size: 12px; + font-weight: 200; + padding: $tag-default-pd; + color: #fff; + border-radius: 3px; + background-color: $uni-info; + border-width: 1rpx; + border-style: solid; + border-color: $uni-info; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ + + // size attr + &--default { + font-size: 12px; + } + + &--default--inverted { + color: $uni-info; + border-color: $uni-info; + } + + &--small { + padding: $tag-small-pd; + font-size: 12px; + border-radius: 2px; + } + + &--mini { + padding: $tag-mini-pd; + font-size: 12px; + border-radius: 2px; + } + + // type attr + &--primary { + background-color: $uni-primary; + border-color: $uni-primary; + color: #fff; + } + + &--success { + color: #fff; + background-color: $uni-success; + border-color: $uni-success; + } + + &--warning { + color: #fff; + background-color: $uni-warning; + border-color: $uni-warning; + } + + &--error { + color: #fff; + background-color: $uni-error; + border-color: $uni-error; + } + + &--primary--inverted { + color: $uni-primary; + border-color: $uni-primary; + } + + &--success--inverted { + color: $uni-success; + border-color: $uni-success; + } + + &--warning--inverted { + color: $uni-warning; + border-color: $uni-warning; + } + + &--error--inverted { + color: $uni-error; + border-color: $uni-error; + } + + &--inverted { + background-color: #fff; + } + + // other attr + &--circle { + border-radius: 15px !important; + } + + &--mark { + border-top-left-radius: 0 !important; + border-bottom-left-radius: 0 !important; + border-top-right-radius: 15px !important; + border-bottom-right-radius: 15px !important; + } + + &--disabled { + opacity: 0.5; + /* #ifdef H5 */ + cursor: not-allowed; + /* #endif */ + } + } + + + .uni-tag-text { + color: #fff; + font-size: 14px; + + &--primary { + color: $uni-primary; + } + + &--success { + color: $uni-success; + } + + &--warning { + color: $uni-warning; + } + + &--error { + color: $uni-error; + } + + &--small { + font-size: 12px; + } + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-tag/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-tag/package.json new file mode 100644 index 000000000..187808863 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-tag/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-tag/readme.md new file mode 100644 index 000000000..6e78ff5e4 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-title/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-title/changelog.md new file mode 100644 index 000000000..762621653 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-title/components/uni-title/uni-title.vue b/yudao-ui-admin-uniapp/uni_modules/uni-title/components/uni-title/uni-title.vue new file mode 100644 index 000000000..bf4f92659 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-title/components/uni-title/uni-title.vue @@ -0,0 +1,171 @@ +<template> + <view class="uni-title__box" :style="{'align-items':textAlign}"> + <text class="uni-title__base" :class="['uni-'+type]" :style="{'color':color}">{{title}}</text> + </view> +</template> + +<script> + /** + * Title 标题 + * @description 标题,通常用于记录页面标题,使用当前组件,uni-app 如果开启统计,将会自动统计页面标题 + * @tutorial https://ext.dcloud.net.cn/plugin?id=1066 + * @property {String} type = [h1|h2|h3|h4|h5] 标题类型 + * @value h1 一级标题 + * @value h2 二级标题 + * @value h3 三级标题 + * @value h4 四级标题 + * @value h5 五级标题 + * @property {String} title 标题内容 + * @property {String} align = [left|center|right] 对齐方式 + * @value left 做对齐 + * @value center 居中对齐 + * @value right 右对齐 + * @property {String} color 字体颜色 + * @property {Boolean} stat = [true|false] 是否开启统计功能呢,如不填写type值,默认为开启,填写 type 属性,默认为关闭 + */ + export default { + name:"UniTitle", + props: { + type: { + type: String, + default: '' + }, + title: { + type: String, + default: '' + }, + align: { + type: String, + default: 'left' + }, + color: { + type: String, + default: '#333333' + }, + stat: { + type: [Boolean, String], + default: '' + } + }, + data() { + return { + + }; + }, + computed: { + textAlign() { + let align = 'center'; + switch (this.align) { + case 'left': + align = 'flex-start' + break; + case 'center': + align = 'center' + break; + case 'right': + align = 'flex-end' + break; + } + return align + } + }, + watch: { + title(newVal) { + if (this.isOpenStat()) { + // 上报数据 + if (uni.report) { + uni.report('title', this.title) + } + } + } + }, + mounted() { + if (this.isOpenStat()) { + // 上报数据 + if (uni.report) { + uni.report('title', this.title) + } + } + }, + methods: { + isOpenStat() { + if (this.stat === '') { + this.isStat = false + } + let stat_type = (typeof(this.stat) === 'boolean' && this.stat) || (typeof(this.stat) === 'string' && this.stat !== + '') + if (this.type === "") { + this.isStat = true + if (this.stat.toString() === 'false') { + this.isStat = false + } + } + + if (this.type !== '') { + this.isStat = true + if (stat_type) { + this.isStat = true + } else { + this.isStat = false + } + } + return this.isStat + } + } + } +</script> + +<style> + /* .uni-title { + + } */ + .uni-title__box { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + align-items: flex-start; + justify-content: center; + padding: 8px 0; + flex: 1; + } + + .uni-title__base { + font-size: 15px; + color: #333; + font-weight: 500; + } + + .uni-h1 { + font-size: 20px; + color: #333; + font-weight: bold; + } + + .uni-h2 { + font-size: 18px; + color: #333; + font-weight: bold; + } + + .uni-h3 { + font-size: 16px; + color: #333; + font-weight: bold; + /* font-weight: 400; */ + } + + .uni-h4 { + font-size: 14px; + color: #333; + font-weight: bold; + /* font-weight: 300; */ + } + + .uni-h5 { + font-size: 12px; + color: #333; + font-weight: bold; + /* font-weight: 200; */ + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-title/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-title/package.json new file mode 100644 index 000000000..2249f5a1c --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-title/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-title/readme.md new file mode 100644 index 000000000..0e60b1b95 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-tooltip/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-tooltip/changelog.md new file mode 100644 index 000000000..00f1572d7 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-tooltip/components/uni-tooltip/uni-tooltip.vue b/yudao-ui-admin-uniapp/uni_modules/uni-tooltip/components/uni-tooltip/uni-tooltip.vue new file mode 100644 index 000000000..ffbb6fa5d --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-tooltip/components/uni-tooltip/uni-tooltip.vue @@ -0,0 +1,68 @@ +<template> + <view class="uni-tooltip"> + <slot></slot> + <view v-if="content || $slots.content" class="uni-tooltip-popup"> + <slot name="content"> + {{content}} + </slot> + </view> + </view> +</template> + + +<script> + /** + * Tooltip 提示文字 + * @description 常用于展示鼠标 hover 时的提示信息。 + * @tutorial https://uniapp.dcloud.io/component/uniui/uni-tooltip + * @property {String} content 弹出层显示的内容 + * @property {String} placement出现位置, 目前只支持 left + */ + + + export default { + name: "uni-tooltip", + data() { + return { + + }; + }, + props: { + content: { + type: String, + default: '' + }, + + placement: { + type: String, + default: 'bottom' + }, + } + } +</script> + +<style> + .uni-tooltip { + position: relative; + cursor: pointer; + } + + .uni-tooltip-popup { + z-index: 1; + display: none; + position: absolute; + left: 0; + background-color: #333; + border-radius: 8px; + color: #fff; + font-size: 12px; + text-align: left; + line-height: 16px; + padding: 12px; + } + + + .uni-tooltip:hover .uni-tooltip-popup { + display: block; + } +</style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-tooltip/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-tooltip/package.json new file mode 100644 index 000000000..e88ecf8da --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-tooltip/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-tooltip", + "displayName": "uni-tooltip 提示文字", + "version": "0.2.1", + "description": "Tooltip 提示文字", + "keywords": [ + "uni-tooltip", + "uni-ui", + "tooltip", + "tip", + "文字提示" + ], + "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": "" + }, + "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", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-tooltip/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-tooltip/readme.md new file mode 100644 index 000000000..faafa2ecb --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/uni_modules/uni-transition/changelog.md b/yudao-ui-admin-uniapp/uni_modules/uni-transition/changelog.md new file mode 100644 index 000000000..b1a824b89 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-transition/changelog.md @@ -0,0 +1,20 @@ +## 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/yudao-ui-admin-uniapp/uni_modules/uni-transition/components/uni-transition/createAnimation.js b/yudao-ui-admin-uniapp/uni_modules/uni-transition/components/uni-transition/createAnimation.js new file mode 100644 index 000000000..5f54365e6 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-transition/components/uni-transition/createAnimation.js @@ -0,0 +1,128 @@ +// 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 + 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/yudao-ui-admin-uniapp/uni_modules/uni-transition/components/uni-transition/uni-transition.vue b/yudao-ui-admin-uniapp/uni_modules/uni-transition/components/uni-transition/uni-transition.vue new file mode 100644 index 000000000..0d739bd55 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-transition/components/uni-transition/uni-transition.vue @@ -0,0 +1,277 @@ +<template> + <view v-if="isShow" ref="ani" :animation="animationData" :class="customClass" :style="transformStyles" @click="onClick"><slot></slot></view> +</template> + +<script> +import { createAnimation } from './createAnimation' + +/** + * Transition 过渡动画 + * @description 简单过渡动画组件 + * @tutorial https://ext.dcloud.net.cn/plugin?id=985 + * @property {Boolean} show = [false|true] 控制组件显示或隐藏 + * @property {Array|String} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型 + * @value fade 渐隐渐出过渡 + * @value slide-top 由上至下过渡 + * @value slide-right 由右至左过渡 + * @value slide-bottom 由下至上过渡 + * @value slide-left 由左至右过渡 + * @value zoom-in 由小到大过渡 + * @value zoom-out 由大到小过渡 + * @property {Number} duration 过渡动画持续时间 + * @property {Object} styles 组件样式,同 css 样式,注意带’-‘连接符的属性需要使用小驼峰写法如:`backgroundColor:red` + */ +export default { + name: 'uniTransition', + emits:['click','change'], + props: { + show: { + type: Boolean, + default: false + }, + modeClass: { + type: [Array, String], + default() { + return 'fade' + } + }, + duration: { + type: Number, + default: 300 + }, + styles: { + type: Object, + default() { + return {} + } + }, + customClass:{ + type: String, + default: '' + } + }, + data() { + return { + isShow: false, + transform: '', + opacity: 1, + animationData: {}, + durationTime: 300, + config: {} + } + }, + watch: { + show: { + handler(newVal) { + if (newVal) { + this.open() + } else { + // 避免上来就执行 close,导致动画错乱 + if (this.isShow) { + this.close() + } + } + }, + immediate: true + } + }, + computed: { + // 生成样式数据 + stylesObject() { + let styles = { + ...this.styles, + 'transition-duration': this.duration / 1000 + 's' + } + let transform = '' + for (let i in styles) { + let line = this.toLine(i) + transform += line + ':' + styles[i] + ';' + } + return transform + }, + // 初始化动画条件 + transformStyles() { + return 'transform:' + this.transform + ';' + 'opacity:' + this.opacity + ';' + this.stylesObject + } + }, + created() { + // 动画默认配置 + this.config = { + duration: this.duration, + timingFunction: 'ease', + transformOrigin: '50% 50%', + delay: 0 + } + this.durationTime = this.duration + }, + methods: { + /** + * ref 触发 初始化动画 + */ + init(obj = {}) { + if (obj.duration) { + this.durationTime = obj.duration + } + this.animation = createAnimation(Object.assign(this.config, obj),this) + }, + /** + * 点击组件触发回调 + */ + onClick() { + this.$emit('click', { + detail: this.isShow + }) + }, + /** + * ref 触发 动画分组 + * @param {Object} obj + */ + step(obj, config = {}) { + if (!this.animation) return + for (let i in obj) { + try { + if(typeof obj[i] === 'object'){ + this.animation[i](...obj[i]) + }else{ + this.animation[i](obj[i]) + } + } catch (e) { + console.error(`方法 ${i} 不存在`) + } + } + this.animation.step(config) + return this + }, + /** + * ref 触发 执行动画 + */ + run(fn) { + if (!this.animation) return + this.animation.run(fn) + }, + // 开始过度动画 + open() { + clearTimeout(this.timer) + this.transform = '' + this.isShow = true + let { opacity, transform } = this.styleInit(false) + if (typeof opacity !== 'undefined') { + this.opacity = opacity + } + this.transform = transform + // 确保动态样式已经生效后,执行动画,如果不加 nextTick ,会导致 wx 动画执行异常 + this.$nextTick(() => { + // TODO 定时器保证动画完全执行,目前有些问题,后面会取消定时器 + this.timer = setTimeout(() => { + this.animation = createAnimation(this.config, this) + this.tranfromInit(false).step() + this.animation.run() + this.$emit('change', { + detail: this.isShow + }) + }, 20) + }) + }, + // 关闭过度动画 + close(type) { + if (!this.animation) return + this.tranfromInit(true) + .step() + .run(() => { + this.isShow = false + this.animationData = null + this.animation = null + let { opacity, transform } = this.styleInit(false) + this.opacity = opacity || 1 + this.transform = transform + this.$emit('change', { + detail: this.isShow + }) + }) + }, + // 处理动画开始前的默认样式 + styleInit(type) { + let styles = { + transform: '' + } + let buildStyle = (type, mode) => { + if (mode === 'fade') { + styles.opacity = this.animationType(type)[mode] + } else { + styles.transform += this.animationType(type)[mode] + ' ' + } + } + if (typeof this.modeClass === 'string') { + buildStyle(type, this.modeClass) + } else { + this.modeClass.forEach(mode => { + buildStyle(type, mode) + }) + } + return styles + }, + // 处理内置组合动画 + tranfromInit(type) { + let buildTranfrom = (type, mode) => { + let aniNum = null + if (mode === 'fade') { + aniNum = type ? 0 : 1 + } else { + aniNum = type ? '-100%' : '0' + if (mode === 'zoom-in') { + aniNum = type ? 0.8 : 1 + } + if (mode === 'zoom-out') { + aniNum = type ? 1.2 : 1 + } + if (mode === 'slide-right') { + aniNum = type ? '100%' : '0' + } + if (mode === 'slide-bottom') { + aniNum = type ? '100%' : '0' + } + } + this.animation[this.animationMode()[mode]](aniNum) + } + if (typeof this.modeClass === 'string') { + buildTranfrom(type, this.modeClass) + } else { + this.modeClass.forEach(mode => { + buildTranfrom(type, mode) + }) + } + + return this.animation + }, + animationType(type) { + return { + fade: type ? 1 : 0, + 'slide-top': `translateY(${type ? '0' : '-100%'})`, + 'slide-right': `translateX(${type ? '0' : '100%'})`, + 'slide-bottom': `translateY(${type ? '0' : '100%'})`, + 'slide-left': `translateX(${type ? '0' : '-100%'})`, + 'zoom-in': `scaleX(${type ? 1 : 0.8}) scaleY(${type ? 1 : 0.8})`, + 'zoom-out': `scaleX(${type ? 1 : 1.2}) scaleY(${type ? 1 : 1.2})` + } + }, + // 内置动画类型与实际动画对应字典 + animationMode() { + return { + fade: 'opacity', + 'slide-top': 'translateY', + 'slide-right': 'translateX', + 'slide-bottom': 'translateY', + 'slide-left': 'translateX', + 'zoom-in': 'scale', + 'zoom-out': 'scale' + } + }, + // 驼峰转中横线 + toLine(name) { + return name.replace(/([A-Z])/g, '-$1').toLowerCase() + } + } +} +</script> + +<style></style> diff --git a/yudao-ui-admin-uniapp/uni_modules/uni-transition/package.json b/yudao-ui-admin-uniapp/uni_modules/uni-transition/package.json new file mode 100644 index 000000000..d15fdf018 --- /dev/null +++ b/yudao-ui-admin-uniapp/uni_modules/uni-transition/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-transition", + "displayName": "uni-transition 过渡动画", + "version": "1.3.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/yudao-ui-admin-uniapp/uni_modules/uni-transition/readme.md b/yudao-ui-admin-uniapp/uni_modules/uni-transition/readme.md new file mode 100644 index 000000000..2f8a77e10 --- /dev/null +++ b/yudao-ui-admin-uniapp/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/yudao-ui-admin-uniapp/utils/auth.js b/yudao-ui-admin-uniapp/utils/auth.js new file mode 100644 index 000000000..cf27e275a --- /dev/null +++ b/yudao-ui-admin-uniapp/utils/auth.js @@ -0,0 +1,22 @@ +const AccessTokenKey = 'ACCESS_TOKEN' +const RefreshTokenKey = 'REFRESH_TOKEN' + +// ========== Token 相关 ========== + +export function getAccessToken() { + return uni.getStorageSync(AccessTokenKey) +} + +export function getRefreshToken() { + return uni.getStorageSync(RefreshTokenKey) +} + +export function setToken(token) { + uni.setStorageSync(AccessTokenKey, token.accessToken) + uni.setStorageSync(RefreshTokenKey, token.refreshToken) +} + +export function removeToken() { + uni.removeStorageSync(AccessTokenKey) + uni.removeStorageSync(RefreshTokenKey) +} diff --git a/yudao-ui-admin-uniapp/utils/common.js b/yudao-ui-admin-uniapp/utils/common.js new file mode 100644 index 000000000..00d4137d5 --- /dev/null +++ b/yudao-ui-admin-uniapp/utils/common.js @@ -0,0 +1,54 @@ +/** +* 显示消息提示框 +* @param content 提示的标题 +*/ +export function toast(content) { + uni.showToast({ + icon: 'none', + title: content + }) +} + +/** +* 显示模态弹窗 +* @param content 提示的标题 +*/ +export function showConfirm(content) { + return new Promise((resolve, reject) => { + uni.showModal({ + title: '提示', + content: content, + cancelText: '取消', + confirmText: '确定', + success: function(res) { + resolve(res) + } + }) + }) +} + +/** +* 参数处理 +* @param params 参数 +*/ +export function tansParams(params) { + let result = '' + for (const propName of Object.keys(params)) { + const value = params[propName] + var part = encodeURIComponent(propName) + "=" + if (value !== null && value !== "" && typeof (value) !== "undefined") { + if (typeof value === 'object') { + for (const key of Object.keys(value)) { + if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') { + let params = propName + '[' + key + ']' + var subPart = encodeURIComponent(params) + "=" + result += subPart + encodeURIComponent(value[key]) + "&" + } + } + } else { + result += part + encodeURIComponent(value) + "&" + } + } + } + return result +} \ No newline at end of file diff --git a/yudao-ui-admin-uniapp/utils/constant.js b/yudao-ui-admin-uniapp/utils/constant.js new file mode 100644 index 000000000..8becd84fa --- /dev/null +++ b/yudao-ui-admin-uniapp/utils/constant.js @@ -0,0 +1,8 @@ +const constant = { + avatar: 'vuex_avatar', + name: 'vuex_name', + roles: 'vuex_roles', + permissions: 'vuex_permissions' + } + + export default constant diff --git a/yudao-ui-admin-uniapp/utils/errorCode.js b/yudao-ui-admin-uniapp/utils/errorCode.js new file mode 100644 index 000000000..d2111ee10 --- /dev/null +++ b/yudao-ui-admin-uniapp/utils/errorCode.js @@ -0,0 +1,6 @@ +export default { + '401': '认证失败,无法访问系统资源', + '403': '当前操作没有权限', + '404': '访问资源不存在', + 'default': '系统未知错误,请反馈给管理员' +} diff --git a/yudao-ui-admin-uniapp/utils/permission.js b/yudao-ui-admin-uniapp/utils/permission.js new file mode 100644 index 000000000..17969f2f1 --- /dev/null +++ b/yudao-ui-admin-uniapp/utils/permission.js @@ -0,0 +1,51 @@ +import store from '@/store' + +/** + * 字符权限校验 + * @param {Array} value 校验值 + * @returns {Boolean} + */ +export function checkPermi(value) { + if (value && value instanceof Array && value.length > 0) { + const permissions = store.getters && store.getters.permissions + const permissionDatas = value + const all_permission = "*:*:*" + + const hasPermission = permissions.some(permission => { + return all_permission === permission || permissionDatas.includes(permission) + }) + + if (!hasPermission) { + return false + } + return true + } else { + console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`) + return false + } +} + +/** + * 角色权限校验 + * @param {Array} value 校验值 + * @returns {Boolean} + */ +export function checkRole(value) { + if (value && value instanceof Array && value.length > 0) { + const roles = store.getters && store.getters.roles + const permissionRoles = value + const super_admin = "admin" + + const hasRole = roles.some(role => { + return super_admin === role || permissionRoles.includes(role) + }) + + if (!hasRole) { + return false + } + return true + } else { + console.error(`need roles! Like checkRole="['admin','editor']"`) + return false + } +} \ No newline at end of file diff --git a/yudao-ui-admin-uniapp/utils/request.js b/yudao-ui-admin-uniapp/utils/request.js new file mode 100644 index 000000000..6c00a3f09 --- /dev/null +++ b/yudao-ui-admin-uniapp/utils/request.js @@ -0,0 +1,76 @@ +import store from '@/store' +import config from '@/config' +import { getAccessToken } from '@/utils/auth' +import errorCode from '@/utils/errorCode' +import { toast, showConfirm, tansParams } from '@/utils/common' + +let timeout = 10000 +const baseUrl = config.baseUrl + +const request = config => { + // 是否需要设置 token + const isToken = (config.headers || {}).isToken === false + config.header = config.header || {} + if (getAccessToken() && !isToken) { + config.header['Authorization'] = 'Bearer ' + getAccessToken() + } + // 设置租户 TODO 芋艿:强制 1 先 + config.header['tenant-id'] = '1'; + // get请求映射params参数 + if (config.params) { + let url = config.url + '?' + tansParams(config.params) + url = url.slice(0, -1) + config.url = url + } + return new Promise((resolve, reject) => { + uni.request({ + method: config.method || 'get', + timeout: config.timeout || timeout, + url: config.baseUrl || baseUrl + config.url, + data: config.data, + // header: config.header, + header: config.header, + dataType: 'json' + }).then(response => { + let [error, res] = response + if (error) { + toast('后端接口连接异常') + reject('后端接口连接异常') + return + } + const code = res.data.code || 200 + const msg = errorCode[code] || res.data.msg || errorCode['default'] + if (code === 401) { + showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then(res => { + if (res.confirm) { + store.dispatch('LogOut').then(res => { + uni.reLaunch({ url: '/pages/login' }) + }) + } + }) + reject('无效的会话,或者会话已过期,请重新登录。') + } else if (code === 500) { + toast(msg) + reject('500') + } else if (code !== 200) { + toast(msg) + reject(code) + } + resolve(res.data) + }) + .catch(error => { + let { message } = error + if (message === 'Network Error') { + message = '后端接口连接异常' + } else if (message.includes('timeout')) { + message = '系统接口请求超时' + } else if (message.includes('Request failed with status code')) { + message = '系统接口' + message.substr(message.length - 3) + '异常' + } + toast(message) + reject(error) + }) + }) +} + +export default request diff --git a/yudao-ui-admin-uniapp/utils/ruoyi.js b/yudao-ui-admin-uniapp/utils/ruoyi.js new file mode 100644 index 000000000..fb6021758 --- /dev/null +++ b/yudao-ui-admin-uniapp/utils/ruoyi.js @@ -0,0 +1,47 @@ +/** + * 通用js方法封装处理 + * Copyright (c) 2019 ruoyi + */ + +// 日期格式化 +export function parseTime(time, pattern) { + if (arguments.length === 0 || !time) { + return null + } + const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}' + let date + if (typeof time === 'object') { + date = time + } else { + if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) { + time = parseInt(time) + } else if (typeof time === 'string') { + time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm),''); + } + if ((typeof time === 'number') && (time.toString().length === 10)) { + time = time * 1000 + } + date = new Date(time) + } + const formatObj = { + y: date.getFullYear(), + m: date.getMonth() + 1, + d: date.getDate(), + h: date.getHours(), + i: date.getMinutes(), + s: date.getSeconds(), + a: date.getDay() + } + const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { + let value = formatObj[key] + // Note: getDay() returns 0 on Sunday + if (key === 'a') { + return ['日', '一', '二', '三', '四', '五', '六'][value] + } + if (result.length > 0 && value < 10) { + value = '0' + value + } + return value || 0 + }) + return time_str +} diff --git a/yudao-ui-admin-uniapp/utils/storage.js b/yudao-ui-admin-uniapp/utils/storage.js new file mode 100644 index 000000000..dd5c38bbf --- /dev/null +++ b/yudao-ui-admin-uniapp/utils/storage.js @@ -0,0 +1,33 @@ +import constant from './constant' + +// 存储变量名 +let storageKey = 'storage_data' + +// 存储节点变量名 +let storageNodeKeys = [constant.avatar, constant.name, constant.roles, constant.permissions] + +// 存储的数据 +let storageData = uni.getStorageSync(storageKey) || {} + +const storage = { + set: function(key, value) { + if (storageNodeKeys.indexOf(key) != -1) { + let tmp = uni.getStorageSync(storageKey) + tmp = tmp ? tmp : {} + tmp[key] = value + uni.setStorageSync(storageKey, tmp) + } + }, + get: function(key) { + return storageData[key] || "" + }, + remove: function(key) { + delete storageData[key] + uni.setStorageSync(storageKey, storageData) + }, + clean: function() { + uni.removeStorageSync(storageKey) + } +} + +export default storage diff --git a/yudao-ui-admin-uniapp/utils/upload.js b/yudao-ui-admin-uniapp/utils/upload.js new file mode 100644 index 000000000..fb6b37985 --- /dev/null +++ b/yudao-ui-admin-uniapp/utils/upload.js @@ -0,0 +1,73 @@ +import store from '@/store' +import config from '@/config' +import { getAccessToken } from '@/utils/auth' +import errorCode from '@/utils/errorCode' +import { toast, showConfirm, tansParams } from '@/utils/common' + +let timeout = 10000 +const baseUrl = config.baseUrl + +const upload = config => { + // 是否需要设置 token + const isToken = (config.headers || {}).isToken === false + config.header = config.header || {} + if (getAccessToken() && !isToken) { + config.header['Authorization'] = 'Bearer ' + getAccessToken() + } + // get请求映射params参数 + if (config.params) { + let url = config.url + '?' + tansParams(config.params) + url = url.slice(0, -1) + config.url = url + } + // 设置租户 TODO 芋艿:强制 1 先 + config.header['tenant-id'] = '1'; + return new Promise((resolve, reject) => { + uni.uploadFile({ + timeout: config.timeout || timeout, + url: baseUrl + config.url, + filePath: config.filePath, + name: config.name || 'file', + header: config.header, + formData: config.formData, + method: config.method || 'post', + success: (res) => { + let result = JSON.parse(res.data) + const code = result.code || 200 + const msg = errorCode[code] || result.msg || errorCode['default'] + if (code === 200) { + resolve(result) + } else if (code == 401) { + showConfirm("登录状态已过期,您可以继续留在该页面,或者重新登录?").then(res => { + if (res.confirm) { + store.dispatch('LogOut').then(res => { + uni.reLaunch({ url: '/pages/login/login' }) + }) + } + }) + reject('无效的会话,或者会话已过期,请重新登录。') + } else if (code === 500) { + toast(msg) + reject('500') + } else if (code !== 200) { + toast(msg) + reject(code) + } + }, + fail: (error) => { + let { message } = error + if (message == 'Network Error') { + message = '后端接口连接异常' + } else if (message.includes('timeout')) { + message = '系统接口请求超时' + } else if (message.includes('Request failed with status code')) { + message = '系统接口' + message.substr(message.length - 3) + '异常' + } + toast(message) + reject(error) + } + }) + }) +} + +export default upload diff --git a/yudao-ui-admin/src/api/login.js b/yudao-ui-admin/src/api/login.js index 390f66900..734e5a12a 100644 --- a/yudao-ui-admin/src/api/login.js +++ b/yudao-ui-admin/src/api/login.js @@ -134,3 +134,6 @@ export function authorize(responseType, clientId, redirectUri, state, method: 'post' }) } + +export class socialBindLogin { +} diff --git a/yudao-ui-admin/src/store/modules/user.js b/yudao-ui-admin/src/store/modules/user.js index 5b0b74994..aed5535bf 100644 --- a/yudao-ui-admin/src/store/modules/user.js +++ b/yudao-ui-admin/src/store/modules/user.js @@ -1,5 +1,5 @@ import {login, logout, getInfo, socialLogin, socialBindLogin, smsLogin} from '@/api/login' -import {getAccessToken, setToken, removeToken, getRefreshToken} from '@/utils/auth' +import {setToken, removeToken} from '@/utils/auth' const user = { state: { From 995f31af240a5e285b2ea1dad2b81743bf9cd6db Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Wed, 3 Aug 2022 13:07:22 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E8=B0=83=E6=95=B4=20yudao-ui-admin-uniapp?= =?UTF-8?q?=20=E7=9A=84=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 30 +++++++++--- yudao-ui-admin-uniapp/README.md | 43 ------------------ .../static/images/banner/banner01.jpg | Bin 39640 -> 44454 bytes 3 files changed, 24 insertions(+), 49 deletions(-) delete mode 100644 yudao-ui-admin-uniapp/README.md mode change 100644 => 100755 yudao-ui-admin-uniapp/static/images/banner/banner01.jpg diff --git a/README.md b/README.md index c98e2ed87..0c8ccac05 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,8 @@ > > 😜 给项目点点 Star 吧,这对我们真的很重要! -* 前端 Vue2 版本采用 [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) -* 前端 Vue3 版本采用 [vue-element-plus-admin](https://gitee.com/kailong110120130/vue-element-plus-admin) +* 管理后台的 Vue3 版本采用 [vue-element-plus-admin](https://gitee.com/kailong110120130/vue-element-plus-admin) ,Vue2 版本采用 [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) +* 管理后台的移动端采用 [uni-app](https://github.com/dcloudio/uni-app) 方案,一份代码多终端适配,同时支持 APP、小程序、H5! * 后端采用 Spring Boot、MySQL + MyBatis Plus、Redis + Redisson * 数据库可使用 MySQL、Oracle、PostgreSQL、SQL Server、MariaDB、国产达梦 DM、TiDB 等 * 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统,支持 SSO 单点登录 @@ -156,8 +156,9 @@ ps:核心功能已经实现,正在对接微信小程序中... | `yudao-dependencies` | Maven 依赖版本管理 | | `yudao-framework` | Java 框架拓展 | | `yudao-server` | 管理后台 + 用户 APP 的服务端 | -| `yudao-ui-admin` | Vue2 管理后台的 UI 界面 | -| `yudao-ui-admin-vue3` | Vue3 管理后台的 UI 界面 | +| `yudao-ui-admin` | 管理后台的 Vue2 前端项目 | +| `yudao-ui-admin-vue3` | 管理后台的 Vue3 前端项目 | +| `yudao-ui-admin-uniapp` | 管理后台的 uni-app 多端项目 | | `yudao-ui-app` | 用户 APP 的 UI 界面 | | `yudao-module-system` | 系统功能的 Module 模块 | | `yudao-module-member` | 会员中心的 Module 模块 | @@ -192,14 +193,14 @@ ps:核心功能已经实现,正在对接微信小程序中... | [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.8.2 | - | | [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 4.0.0 | - | -### [Vue2 前端](./yudao-ui-admin) +### [管理后台 Vue2 前端](./yudao-ui-admin) | 框架 | 说明 | 版本 | |------------------------------------------------------------------------------|---------------|--------| | [Vue](https://cn.vuejs.org/index.html) | JavaScript 框架 | 2.6.12 | | [Vue Element Admin](https://panjiachen.github.io/vue-element-admin-site/zh/) | 后台前端解决方案 | - | -### [Vue3 前端](./yudao-ui-admin-vue3) +### [管理后台 Vue3 前端](./yudao-ui-admin-vue3) | 框架 | 说明 | 版本 | |----------------------------------------------------------------------|------------------|--------| @@ -212,6 +213,13 @@ ps:核心功能已经实现,正在对接微信小程序中... | [windicss](https://cn.windicss.org/) | 下一代工具优先的 CSS 框架 | 3.5.6 | | [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 2.2.1 | +### [管理后台 uni-app 跨端](./yudao-ui-admin-uniapp) + +| 框架 | 说明 | 版本 | +|----------------------------------------------------------------------|------------------|--------| +| [uni-app](hhttps://github.com/dcloudio/uni-app) | 跨平台框架 | 2.0.0 | +| [uni-ui](https://github.com/dcloudio/uni-ui) | 基于 uni-app 的 UI 框架 | 1.4.20 | + ## 🐷 演示图 ### 系统功能 @@ -262,3 +270,13 @@ ps:核心功能已经实现,正在对接微信小程序中... | 模块 | biu | biu | biu | |---------|------------------------------------------------------------------|------------------------------------------------------------------------|------------------------------------------------------------------------| | 报表设计器 |  |  |  | + +### 移动端(管理后台) + +| biu | biu | biu | +|------------------------------------------------------------------|------------------------------------------------------------------------|------------------------------------------------------------------------| +|  |  |  | +|  |  |  | +|  |  |  | + +目前已经实现登录、我的、工作台、编辑资料、头像修改、密码修改、常见问题、关于我们等基础功能。 diff --git a/yudao-ui-admin-uniapp/README.md b/yudao-ui-admin-uniapp/README.md deleted file mode 100644 index 43a887f51..000000000 --- a/yudao-ui-admin-uniapp/README.md +++ /dev/null @@ -1,43 +0,0 @@ -<p align="center"> - <img alt="logo" src="https://oscimg.oschina.net/oscnet/up-43e3941654fa3054c9684bf53d1b1d356a1.png"> -</p> -<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v1.0.0</h1> -<h4 align="center">基于UniApp开发的轻量级移动端框架</h4> -<p align="center"> - <a href="https://gitee.com/y_project/RuoYi-App/stargazers"><img src="https://gitee.com/y_project/RuoYi-App/badge/star.svg?theme=dark"></a> - <a href="https://gitee.com/y_project/RuoYi-App"><img src="https://img.shields.io/badge/RuoYi-v1.0.0-brightgreen.svg"></a> - <a href="https://gitee.com/y_project/RuoYi-App/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a> -</p> - -## 平台简介 - -RuoYi App 移动解决方案,采用uniapp框架,一份代码多终端适配,同时支持APP、小程序、H5!实现了与[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue)、[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud)完美对接的移动解决方案!目前已经实现登录、我的、工作台、编辑资料、头像修改、密码修改、常见问题、关于我们等基础功能。 - -* 配套后端代码仓库地址[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) 或 [RuoYi-Cloud](https://github.com/yangzongzhuan/RuoYi-Cloud) 版本。 -* 应用框架基于[uniapp](https://uniapp.dcloud.net.cn/),支持小程序、H5、Android和IOS。 -* 前端组件采用[uni-ui](https://github.com/dcloudio/uni-ui),全端兼容的高性能UI框架。 - -## 技术文档 - -<img src="https://oscimg.oschina.net/oscnet/up-26c76dc90b92acdbd9ac8cd5252f07c8ad9.jpg" alt="小程序演示"/> - - -## 演示图 - -<table> - <tr> - <td><img src="https://oscimg.oschina.net/oscnet/up-3ea20e447ac621a161e395fb53ccc683d84.png"/></td> - <td><img src="https://oscimg.oschina.net/oscnet/up-a6f23cf9a371a30165e135eff6d9ae89a9d.png"/></td> - <td><img src="https://oscimg.oschina.net/oscnet/up-ff5f62016bf6624c1ff27eee57499dccd44.png"/></td> - </tr> - <tr> - <td><img src="https://oscimg.oschina.net/oscnet/up-b9a582fdb26ec69d407fabd044d2c8494df.png"/></td> - <td><img src="https://oscimg.oschina.net/oscnet/up-96427ee08fca29d77934cfc8d1b1a637cef.png"/></td> - <td><img src="https://oscimg.oschina.net/oscnet/up-5fdadc582d24cccd7727030d397b63185a3.png"/></td> - </tr> - <tr> - <td><img src="https://oscimg.oschina.net/oscnet/up-0a36797b6bcc50c36d40c3c782665b89efc.png"/></td> - <td><img src="https://oscimg.oschina.net/oscnet/up-d77995cc00687cedd00d5ac7d68a07ea276.png"/></td> - <td><img src="https://oscimg.oschina.net/oscnet/up-fa8f5ab20becf59b4b38c1b92a9989e7109.png"/></td> - </tr> -</table> diff --git a/yudao-ui-admin-uniapp/static/images/banner/banner01.jpg b/yudao-ui-admin-uniapp/static/images/banner/banner01.jpg old mode 100644 new mode 100755 index c44d84c908b2bcb048e4dbe438d1f3ff48058f01..fdb1e167eca46acee0482a1494d66537a1b6711a GIT binary patch literal 44454 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 J!~Kze|Jk+TNF4wG literal 39640 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	~ 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 Rl0umNJDUFcqcQ(I`Cq|3vk?FQ