lefengyang
2026-08-09 d7afd94e3858b85899c32c8f2b22376b15c3eab2
uni_module
523 files added
55596 ■■■■■ changed files
ledApp/uni_modules/uv-action-sheet/changelog.md 7 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-action-sheet/components/uv-action-sheet/props.js 50 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-action-sheet/components/uv-action-sheet/uv-action-sheet.vue 280 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-action-sheet/package.json 92 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-action-sheet/readme.md 13 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-album/changelog.md 10 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-album/components/uv-album/uv-album.vue 312 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-album/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-album/readme.md 21 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-alert/changelog.md 7 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-alert/components/uv-alert/props.js 45 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-alert/components/uv-alert/uv-alert.vue 246 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-alert/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-alert/readme.md 15 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-avatar/changelog.md 13 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-avatar/components/uv-avatar-group/props.js 53 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-avatar/components/uv-avatar-group/uv-avatar-group.vue 106 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-avatar/components/uv-avatar/props.js 80 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-avatar/components/uv-avatar/uv-avatar.vue 175 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-avatar/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-avatar/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-back-top/changelog.md 8 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-back-top/components/uv-back-top/props.js 58 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-back-top/components/uv-back-top/uv-back-top.vue 116 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-back-top/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-back-top/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-badge/changelog.md 7 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-badge/components/uv-badge/props.js 73 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-badge/components/uv-badge/uv-badge.vue 176 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-badge/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-badge/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-button/changelog.md 33 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-button/components/uv-button/nvue.scss 46 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-button/components/uv-button/props.js 163 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-button/components/uv-button/uv-button.vue 528 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-button/components/uv-button/vue.scss 93 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-button/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-button/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendar/changelog.md 16 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendar/components/uv-calendar/calendar.js 546 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendar/components/uv-calendar/header.vue 104 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendar/components/uv-calendar/month.vue 616 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendar/components/uv-calendar/props.js 145 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendar/components/uv-calendar/uv-calendar.vue 390 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendar/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendar/readme.md 21 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendars/changelog.md 40 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendars/components/uv-calendars/calendar-body.vue 376 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendars/components/uv-calendars/calendar-item.vue 248 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendars/components/uv-calendars/calendar.js 546 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendars/components/uv-calendars/i18n/en.json 12 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendars/components/uv-calendars/i18n/index.js 8 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendars/components/uv-calendars/i18n/zh-Hans.json 12 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendars/components/uv-calendars/i18n/zh-Hant.json 12 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendars/components/uv-calendars/util.js 435 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendars/components/uv-calendars/uv-calendars.vue 452 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendars/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-calendars/readme.md 23 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-cell/changelog.md 13 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-cell/components/uv-cell-group/props.js 15 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-cell/components/uv-cell-group/uv-cell-group.vue 63 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-cell/components/uv-cell/props.js 116 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-cell/components/uv-cell/uv-cell.vue 209 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-cell/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-cell/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-checkbox/changelog.md 34 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-checkbox/components/uv-checkbox-group/props.js 84 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-checkbox/components/uv-checkbox-group/uv-checkbox-group.vue 119 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-checkbox/components/uv-checkbox/props.js 70 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-checkbox/components/uv-checkbox/uv-checkbox.vue 370 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-checkbox/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-checkbox/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-code-input/changelog.md 13 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-code-input/components/uv-code-input/props.js 83 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-code-input/components/uv-code-input/uv-code-input.vue 272 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-code-input/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-code-input/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-code/changelog.md 9 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-code/components/uv-code/props.js 35 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-code/components/uv-code/uv-code.vue 136 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-code/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-code/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-collapse/changelog.md 5 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-collapse/components/uv-collapse-item/props.js 60 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-collapse/components/uv-collapse-item/uv-collapse-item.vue 229 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-collapse/components/uv-collapse/props.js 20 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-collapse/components/uv-collapse/uv-collapse.vue 86 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-collapse/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-collapse/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-count-down/changelog.md 9 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-count-down/components/uv-count-down/props.js 25 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-count-down/components/uv-count-down/utils.js 62 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-count-down/components/uv-count-down/uv-count-down.vue 169 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-count-down/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-count-down/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-count-to/changelog.md 13 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-count-to/components/uv-count-to/props.js 60 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-count-to/components/uv-count-to/uv-count-to.vue 187 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-count-to/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-count-to/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-datetime-picker/changelog.md 34 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-datetime-picker/components/uv-datetime-picker/props.js 130 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-datetime-picker/components/uv-datetime-picker/uv-datetime-picker.vue 360 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-datetime-picker/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-datetime-picker/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-divider/changelog.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-divider/components/uv-divider/props.js 45 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-divider/components/uv-divider/uv-divider.vue 113 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-divider/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-divider/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-drop-down/changelog.md 13 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-drop-down/components/uv-drop-down-item/uv-drop-down-item.vue 169 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-drop-down/components/uv-drop-down-popup/uv-drop-down-popup.vue 242 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-drop-down/components/uv-drop-down/uv-drop-down.vue 135 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-drop-down/package.json 91 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-drop-down/readme.md 23 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-empty/changelog.md 13 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-empty/components/uv-empty/props.js 60 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-empty/components/uv-empty/uv-empty.vue 126 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-empty/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-empty/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-form/changelog.md 23 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-form/components/uv-form-item/props.js 49 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-form/components/uv-form-item/uv-form-item.vue 226 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-form/components/uv-form/props.js 46 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-form/components/uv-form/uv-form.vue 209 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-form/components/uv-form/valid.js 1343 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-form/package.json 93 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-form/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-gap/changelog.md 5 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-gap/components/uv-gap/props.js 25 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-gap/components/uv-gap/uv-gap.vue 36 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-gap/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-gap/readme.md 12 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-grid/changelog.md 21 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-grid/components/uv-grid-item/props.js 15 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-grid/components/uv-grid-item/uv-grid-item.vue 226 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-grid/components/uv-grid/props.js 20 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-grid/components/uv-grid/uv-grid.vue 100 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-grid/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-grid/readme.md 17 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-icon/changelog.md 31 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-icon/components/uv-icon/icons.js 160 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-icon/components/uv-icon/props.js 90 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-icon/components/uv-icon/uv-icon.vue 226 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-icon/components/uv-icon/uvicons.ttf patch | view | raw | blame | history
ledApp/uni_modules/uv-icon/package.json 83 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-icon/readme.md 15 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-image/changelog.md 36 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-image/components/uv-image/props.js 95 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-image/components/uv-image/uv-image.vue 287 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-image/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-image/readme.md 15 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-index-list/changelog.md 18 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-index-list/components/uv-index-anchor/props.js 30 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-index-list/components/uv-index-anchor/uv-index-anchor.vue 98 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-index-list/components/uv-index-item/uv-index-item.vue 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-index-list/components/uv-index-list/props.js 30 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-index-list/components/uv-index-list/uv-index-list.vue 461 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-index-list/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-index-list/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-input/changelog.md 29 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-input/components/uv-input/props.js 175 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-input/components/uv-input/uv-input.vue 348 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-input/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-input/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-keyboard/changelog.md 17 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-keyboard/components/uv-keyboard-car/props.js 24 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-keyboard/components/uv-keyboard-car/uv-keyboard-car.vue 347 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-keyboard/components/uv-keyboard-number/props.js 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-keyboard/components/uv-keyboard-number/uv-keyboard-number.vue 201 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-keyboard/components/uv-keyboard/props.js 95 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-keyboard/components/uv-keyboard/uv-keyboard.vue 180 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-keyboard/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-keyboard/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-line-progress/changelog.md 7 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-line-progress/components/uv-line-progress/props.js 29 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-line-progress/components/uv-line-progress/uv-line-progress.vue 146 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-line-progress/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-line-progress/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-line/changelog.md 5 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-line/components/uv-line/props.js 34 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-line/components/uv-line/uv-line.vue 60 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-line/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-line/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-link/changelog.md 7 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-link/components/uv-link/props.js 40 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-link/components/uv-link/uv-link.vue 83 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-link/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-link/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-list/changelog.md 25 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-list/components/uv-list-item/uv-list-item.vue 535 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-list/components/uv-list/uv-list.vue 147 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-list/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-list/readme.md 27 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-load-more/changelog.md 7 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-load-more/components/uv-load-more/props.js 95 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-load-more/components/uv-load-more/uv-load-more.vue 152 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-load-more/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-load-more/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-loading-icon/changelog.md 9 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-loading-icon/components/uv-loading-icon/props.js 67 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-loading-icon/components/uv-loading-icon/uv-loading-icon.vue 347 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-loading-icon/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-loading-icon/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-loading-page/changelog.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-loading-page/components/uv-loading-page/props.js 55 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-loading-page/components/uv-loading-page/uv-loading-page.vue 96 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-loading-page/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-loading-page/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-modal/changelog.md 28 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-modal/components/uv-modal/props.js 90 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-modal/components/uv-modal/uv-modal.vue 245 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-modal/package.json 90 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-modal/readme.md 23 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-navbar/changelog.md 17 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-navbar/components/uv-navbar/props.js 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-navbar/components/uv-navbar/uv-navbar.vue 245 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-navbar/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-navbar/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-no-network/changelog.md 5 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-no-network/components/uv-no-network/props.js 20 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-no-network/components/uv-no-network/uv-no-network.vue 222 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-no-network/package.json 90 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-no-network/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-notice-bar/changelog.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-notice-bar/components/uv-column-notice/props.js 61 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-notice-bar/components/uv-column-notice/uv-column-notice.vue 176 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-notice-bar/components/uv-notice-bar/props.js 76 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-notice-bar/components/uv-notice-bar/uv-notice-bar.vue 110 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-notice-bar/components/uv-row-notice/props.js 40 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-notice-bar/components/uv-row-notice/uv-row-notice.vue 341 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-notice-bar/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-notice-bar/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-notify/changelog.md 9 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-notify/components/uv-notify/props.js 45 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-notify/components/uv-notify/uv-notify.vue 220 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-notify/package.json 90 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-notify/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-number-box/changelog.md 7 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-number-box/components/uv-number-box/props.js 113 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-number-box/components/uv-number-box/uv-number-box.vue 395 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-number-box/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-number-box/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-overlay/changelog.md 9 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-overlay/components/uv-overlay/props.js 25 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-overlay/components/uv-overlay/uv-overlay.vue 85 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-overlay/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-overlay/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-parse/changelog.md 13 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-parse/components/uv-parse/node/node.vue 576 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-parse/components/uv-parse/parser.js 1335 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-parse/components/uv-parse/uv-parse.vue 498 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-parse/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-parse/readme.md 21 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-parse/static/app-plus/uv-parse/js/handler.js 224 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-parse/static/app-plus/uv-parse/js/uni.webview.min.js 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-parse/static/app-plus/uv-parse/local.html 1 ●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-pick-color/changelog.md 18 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-pick-color/components/uv-pick-color/colors.js 217 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-pick-color/components/uv-pick-color/props.js 47 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-pick-color/components/uv-pick-color/uv-pick-color.vue 551 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-pick-color/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-pick-color/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-picker/changelog.md 33 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-picker/components/uv-picker/props.js 95 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-picker/components/uv-picker/uv-picker.vue 330 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-picker/package.json 90 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-picker/readme.md 21 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-popup/changelog.md 18 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-popup/components/uv-popup/keypress.js 45 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-popup/components/uv-popup/uv-popup.vue 539 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-popup/package.json 92 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-popup/readme.md 21 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/changelog.md 13 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/cache.js 1 ●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/bridge/bridge-weex.js 241 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-2d/FillStyleLinearGradient.js 18 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-2d/FillStylePattern.js 8 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-2d/FillStyleRadialGradient.js 17 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-2d/RenderingContext.js 666 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/ActiveInfo.js 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Buffer.js 21 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Framebuffer.js 21 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/GLenum.js 298 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/GLmethod.js 142 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/GLtype.js 23 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Program.js 21 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Renderbuffer.js 21 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/RenderingContext.js 1191 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Shader.js 22 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/ShaderPrecisionFormat.js 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Texture.js 22 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/UniformLocation.js 22 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/classUtils.js 3 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/env/canvas.js 74 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/env/image.js 96 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/env/tool.js 24 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/index.js 39 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/props.js 85 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/qrcode.js 34 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/queue.js 41 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/components/uv-qrcode/uv-qrcode.vue 1038 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-qrcode/readme.md 21 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-radio/changelog.md 31 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-radio/components/uv-radio-group/props.js 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-radio/components/uv-radio-group/uv-radio-group.vue 115 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-radio/components/uv-radio/props.js 65 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-radio/components/uv-radio/uv-radio.vue 348 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-radio/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-radio/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-rate/changelog.md 17 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-rate/components/uv-rate/props.js 73 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-rate/components/uv-rate/uv-rate.vue 274 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-rate/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-rate/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-read-more/changelog.md 7 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-read-more/components/uv-read-more/props.js 62 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-read-more/components/uv-read-more/uv-read-more.vue 162 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-read-more/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-read-more/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-row/changelog.md 5 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-row/components/uv-col/props.js 30 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-row/components/uv-col/uv-col.vue 165 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-row/components/uv-row/props.js 20 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-row/components/uv-row/uv-row.vue 95 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-row/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-row/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-safe-bottom/changelog.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-safe-bottom/components/uv-safe-bottom/uv-safe-bottom.vue 67 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-safe-bottom/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-safe-bottom/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-scroll-list/changelog.md 12 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-scroll-list/components/uv-scroll-list/nvue.js 29 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-scroll-list/components/uv-scroll-list/props.js 35 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-scroll-list/components/uv-scroll-list/scrollWxs.wxs 51 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-scroll-list/components/uv-scroll-list/uv-scroll-list.vue 218 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-scroll-list/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-scroll-list/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-search/changelog.md 25 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-search/components/uv-search/props.js 127 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-search/components/uv-search/uv-search.vue 311 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-search/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-search/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-skeleton/changelog.md 9 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-skeleton/components/uv-skeleton/props.js 65 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-skeleton/components/uv-skeleton/uv-skeleton.vue 250 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-skeleton/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-skeleton/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-skeletons/changelog.md 4 ●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-skeletons/components/uv-skeletons/uv-skeletons.vue 247 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-skeletons/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-skeletons/readme.md 23 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-slider/changelog.md 9 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-slider/components/uv-slider/props.js 58 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-slider/components/uv-slider/uv-slider.vue 58 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-slider/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-slider/readme.md 15 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-status-bar/changelog.md 7 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-status-bar/components/uv-status-bar/props.js 8 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-status-bar/components/uv-status-bar/uv-status-bar.vue 54 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-status-bar/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-status-bar/readme.md 10 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-steps/changelog.md 10 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-steps/components/uv-steps-item/props.js 25 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-steps/components/uv-steps-item/uv-steps-item.vue 347 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-steps/components/uv-steps/props.js 40 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-steps/components/uv-steps/uv-steps.vue 83 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-steps/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-steps/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-sticky/changelog.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-sticky/components/uv-sticky/props.js 41 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-sticky/components/uv-sticky/uv-sticky.vue 223 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-sticky/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-sticky/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-subsection/changelog.md 10 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-subsection/components/uv-subsection/props.js 54 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-subsection/components/uv-subsection/uv-subsection.vue 269 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-subsection/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-subsection/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swipe-action/changelog.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action-item/index - backup.wxs 256 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action-item/index.wxs 225 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action-item/nvue - backup.js 264 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action-item/nvue.js 182 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action-item/props.js 40 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action-item/uv-swipe-action-item.vue 200 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action-item/wxs.js 15 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action/props.js 10 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action/uv-swipe-action.vue 65 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swipe-action/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swipe-action/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swiper/changelog.md 16 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swiper/components/uv-swiper-indicator/props.js 30 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swiper/components/uv-swiper-indicator/uv-swiper-indicator.vue 112 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swiper/components/uv-swiper/props.js 136 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swiper/components/uv-swiper/uv-swiper.vue 263 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swiper/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-swiper/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-switch/changelog.md 14 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-switch/components/uv-switch/props.js 58 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-switch/components/uv-switch/uv-switch.vue 192 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-switch/package.json 88 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-switch/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tabbar/changelog.md 14 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tabbar/components/uv-tabbar-item/props.js 40 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tabbar/components/uv-tabbar-item/uv-tabbar-item.vue 146 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tabbar/components/uv-tabbar/props.js 50 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tabbar/components/uv-tabbar/uv-tabbar.vue 146 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tabbar/package.json 90 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tabbar/readme.md 21 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tabs/changelog.md 22 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tabs/components/uv-tabs/props.js 71 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tabs/components/uv-tabs/uv-tabs.vue 390 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tabs/package.json 90 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tabs/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tags/changelog.md 10 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tags/components/uv-tags/props.js 95 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tags/components/uv-tags/uv-tags.vue 379 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tags/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tags/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-text/changelog.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-text/components/uv-text/props.js 113 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-text/components/uv-text/uv-text.vue 218 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-text/components/uv-text/value.js 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-text/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-text/readme.md 17 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-textarea/changelog.md 28 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-textarea/components/uv-textarea/props.js 138 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-textarea/components/uv-textarea/uv-textarea.vue 238 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-textarea/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-textarea/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-toast/changelog.md 10 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-toast/components/uv-toast/uv-toast.vue 333 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-toast/package.json 90 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-toast/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-toolbar/changelog.md 2 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-toolbar/components/uv-toolbar/props.js 40 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-toolbar/components/uv-toolbar/uv-toolbar.vue 109 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-toolbar/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-toolbar/readme.md 31 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tooltip/changelog.md 13 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tooltip/components/uv-tooltip/props.js 60 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tooltip/components/uv-tooltip/uv-tooltip.vue 372 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tooltip/package.json 90 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-tooltip/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-transition/changelog.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-transition/components/uv-transition/createAnimation.js 131 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-transition/components/uv-transition/props.js 31 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-transition/components/uv-transition/uv-transition.vue 320 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-transition/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-transition/readme.md 15 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/changelog.md 76 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/components/uv-ui-tools/uv-ui-tools.vue 6 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/index.js 79 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/index.scss 7 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/config/config.js 34 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/css/color.scss 32 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/css/common.scss 100 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/css/components.scss 23 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/css/variable.scss 111 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/css/vue.scss 40 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/function/colorGradient.js 134 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/function/debounce.js 29 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/function/digit.js 167 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/function/index.js 734 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/function/platform.js 75 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/function/test.js 287 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/function/throttle.js 30 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/luch-request/adapters/index.js 132 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/luch-request/core/InterceptorManager.js 51 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/luch-request/core/Request.js 201 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/luch-request/core/buildFullPath.js 20 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/luch-request/core/defaults.js 33 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/luch-request/core/dispatchRequest.js 6 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/luch-request/core/mergeConfig.js 126 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/luch-request/core/settle.js 16 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/luch-request/helpers/buildURL.js 64 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/luch-request/helpers/combineURLs.js 14 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/luch-request/helpers/isAbsoluteURL.js 14 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/luch-request/index.d.ts 197 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/luch-request/index.js 2 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/luch-request/utils.js 135 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/luch-request/utils/clone.js 264 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/mixin/button.js 13 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/mixin/mixin.js 172 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js 8 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/mixin/mpShare.js 13 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/mixin/openType.js 47 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/mixin/touch.js 59 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/util/dayjs.js 216 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/libs/util/route.js 126 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/package.json 81 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/readme.md 23 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui-tools/theme.scss 43 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui/changelog.md 353 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui/components/uv-ui/uv-ui.vue 7 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui/package.json 162 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-ui/readme.md 164 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-upload/changelog.md 17 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-upload/components/uv-preview-video/uv-preview-video.vue 52 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-upload/components/uv-upload/mixin.js 22 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-upload/components/uv-upload/props.js 130 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-upload/components/uv-upload/utils.js 151 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-upload/components/uv-upload/uv-upload.vue 488 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-upload/package.json 90 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-upload/readme.md 11 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-vtabs/changelog.md 20 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-vtabs/components/uv-vtabs-item/uv-vtabs-item.vue 68 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-vtabs/components/uv-vtabs/props.js 79 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-vtabs/components/uv-vtabs/uv-vtabs.vue 438 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-vtabs/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-vtabs/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-waterfall/changelog.md 24 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-waterfall/components/uv-waterfall/props.js 69 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-waterfall/components/uv-waterfall/uv-waterfall.vue 265 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-waterfall/package.json 89 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-waterfall/readme.md 19 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/x-color-picker/changelog.md 2 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/x-color-picker/components/x-color-picker/x-color-picker.vue 1242 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/x-color-picker/package.json 87 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/x-color-picker/readme.md 225 ●●●●● patch | view | raw | blame | history
ledApp/uni_modules/uv-action-sheet/changelog.md
New file
@@ -0,0 +1,7 @@
## 1.0.2(2023-07-02)
uv-action-sheet  由于弹出层uv-popup的修改,打开和关闭方法更改,详情参考文档:https://www.uvui.cn/components/actionSheet.html
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-action-sheet 底部操作菜单
ledApp/uni_modules/uv-action-sheet/components/uv-action-sheet/props.js
New file
@@ -0,0 +1,50 @@
export default {
    props: {
        // 标题,有值则显示,同时会显示关闭按钮
        title: {
            type: String,
            default: ''
        },
        // 选项上方的描述信息
        description: {
            type: String,
            default: ''
        },
        // 数据
        actions: {
            type: Array,
            default: () => []
        },
        // 取消按钮的文字,不为空时显示按钮
        cancelText: {
            type: String,
            default: ''
        },
        // 点击某个菜单项时是否关闭弹窗
        closeOnClickAction: {
            type: Boolean,
            default: true
        },
        // 处理底部安全区(默认true)
        safeAreaInsetBottom: {
            type: Boolean,
            default: true
        },
        // 小程序的打开方式
        openType: {
            type: String,
            default: ''
        },
        // 点击遮罩是否允许关闭 (默认true)
        closeOnClickOverlay: {
            type: Boolean,
            default: true
        },
        // 圆角值
        round: {
            type: [Boolean, String, Number],
            default: 0
        },
        ...uni.$uv?.props?.actionSheet
    }
}
ledApp/uni_modules/uv-action-sheet/components/uv-action-sheet/uv-action-sheet.vue
New file
@@ -0,0 +1,280 @@
<template>
    <uv-popup
      ref="popup"
      mode="bottom"
      :safeAreaInsetBottom="safeAreaInsetBottom"
      :round="round"
        :close-on-click-overlay="closeOnClickOverlay"
        @change="popupChange"
    >
        <view class="uv-action-sheet">
            <view
              class="uv-action-sheet__header"
              v-if="title"
            >
                <text class="uv-action-sheet__header__title uv-line-1">{{title}}</text>
                <view
                  class="uv-action-sheet__header__icon-wrap"
                  @tap.stop="cancel"
                >
                    <uv-icon
                      name="close"
                      size="17"
                      color="#c8c9cc"
                      bold
                    ></uv-icon>
                </view>
            </view>
            <text
              class="uv-action-sheet__description"
                :style="[{
                    marginTop: `${title && description ? 0 : '18px'}`
                }]"
              v-if="description"
            >{{description}}</text>
            <slot>
                <uv-line v-if="description"></uv-line>
                <view class="uv-action-sheet__item-wrap">
                    <view v-for="(item, index) in actions" :key="index">
                        <!-- #ifdef MP -->
                        <button
                          class="uv-reset-button"
                          :openType="item.openType"
                          @getuserinfo="onGetUserInfo"
                          @contact="onContact"
                          @getphonenumber="onGetPhoneNumber"
                          @error="onError"
                          @launchapp="onLaunchApp"
                          @opensetting="onOpenSetting"
                          :lang="lang"
                          :session-from="sessionFrom"
                          :send-message-title="sendMessageTitle"
                          :send-message-path="sendMessagePath"
                          :send-message-img="sendMessageImg"
                          :show-message-card="showMessageCard"
                          :app-parameter="appParameter"
                          @tap="selectHandler(index)"
                          :hover-class="!item.disabled && !item.loading ? 'uv-action-sheet--hover' : ''"
                        >
                            <!-- #endif -->
                            <view
                              class="uv-action-sheet__item-wrap__item"
                              @tap.stop="selectHandler(index)"
                              :hover-class="!item.disabled && !item.loading ? 'uv-action-sheet--hover' : ''"
                              :hover-stay-time="150"
                            >
                                <template v-if="!item.loading">
                                    <text
                                      class="uv-action-sheet__item-wrap__item__name"
                                      :style="[itemStyle(index)]"
                                    >{{ item.name }}</text>
                                    <text
                                      v-if="item.subname"
                                      class="uv-action-sheet__item-wrap__item__subname"
                                    >{{ item.subname }}</text>
                                </template>
                                <uv-loading-icon
                                  v-else
                                  custom-class="van-action-sheet__loading"
                                  size="18"
                                  mode="circle"
                                />
                            </view>
                            <!-- #ifdef MP -->
                        </button>
                        <!-- #endif -->
                        <uv-line v-if="index !== actions.length - 1"></uv-line>
                    </view>
                </view>
            </slot>
            <uv-gap
              bgColor="#eaeaec"
              height="6"
              v-if="cancelText"
            ></uv-gap>
            <view hover-class="uv-action-sheet--hover">
                <text
                  @touchmove.stop.prevent
                  :hover-stay-time="150"
                  v-if="cancelText"
                  class="uv-action-sheet__cancel-text"
                  @tap="cancel"
                >{{cancelText}}</text>
            </view>
        </view>
    </uv-popup>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import button from '@/uni_modules/uv-ui-tools/libs/mixin/button.js'
    import openType from '@/uni_modules/uv-ui-tools/libs/mixin/openType.js'
    import props from './props.js';
    /**
     * ActionSheet 操作菜单
     * @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI,配置更加灵活,所有平台都表现一致。
     * @tutorial https://www.uvui.cn/components/actionSheet.html
     * @property {Boolean}          show                操作菜单是否展示 (默认 false )
     * @property {String}           title               操作菜单标题
     * @property {String}           description         选项上方的描述信息
     * @property {Array<Object>}    actions             按钮的文字数组,见官方文档示例
     * @property {String}           cancelText          取消按钮的提示文字,不为空时显示按钮
     * @property {Boolean}          closeOnClickAction  点击某个菜单项时是否关闭弹窗 (默认 true )
     * @property {Boolean}          safeAreaInsetBottom 处理底部安全区 (默认 true )
     * @property {String}           openType            小程序的打开方式 (contact | launchApp | getUserInfo | openSetting |getPhoneNumber |error )
     * @property {Boolean}          closeOnClickOverlay 点击遮罩是否允许关闭  (默认 true )
     * @property {String}           lang                指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文
     * @property {String}           sessionFrom         会话来源,openType="contact"时有效
     * @property {String}           sendMessageTitle    会话内消息卡片标题,openType="contact"时有效
     * @property {String}           sendMessagePath     会话内消息卡片点击跳转小程序路径,openType="contact"时有效
     * @property {String}           sendMessageImg      会话内消息卡片图片,openType="contact"时有效
     * @property {Boolean}          showMessageCard     是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,用户点击后可以快速发送小程序消息,openType="contact"时有效 (默认 false )
     * @property {String}           appParameter        打开 APP 时,向 APP 传递的参数,openType=launchApp 时有效
     *
     * @event {Function} select         点击ActionSheet列表项时触发
     * @event {Function} close          点击取消按钮时触发
     * @event {Function} getuserinfo    用户点击该按钮时,会返回获取到的用户信息,回调的 detail 数据与 wx.getUserInfo 返回的一致,openType="getUserInfo"时有效
     * @event {Function} contact        客服消息回调,openType="contact"时有效
     * @event {Function} getphonenumber 获取用户手机号回调,openType="getPhoneNumber"时有效
     * @event {Function} error          当使用开放能力时,发生错误的回调,openType="error"时有效
     * @event {Function} launchapp      打开 APP 成功的回调,openType="launchApp"时有效
     * @event {Function} opensetting    在打开授权设置页后回调,openType="openSetting"时有效
     * @example <uv-action-sheet ref="actionSheet" :actions="list" :title="title" ></uv-action-sheet>
     */
    export default {
        name: "uv-action-sheet",
        mixins: [openType, button, mpMixin , mixin, props],
        emits: ['close', 'select'],
        computed: {
            // 操作项目的样式
            itemStyle() {
                return (index) => {
                    let style = {};
                    if (this.actions[index].color) style.color = this.actions[index].color
                    if (this.actions[index].fontSize) style.fontSize = this.$uv.addUnit(this.actions[index].fontSize)
                    // 选项被禁用的样式
                    if (this.actions[index].disabled) style.color = '#c0c4cc'
                    return style;
                }
            },
        },
        methods: {
            open() {
                this.$refs.popup.open();
            },
            close() {
                this.$refs.popup.close();
            },
            popupChange(e) {
                if(!e.show) this.$emit('close');
            },
            // 点击取消按钮
            cancel() {
                this.close();
            },
            selectHandler(index) {
                const item = this.actions[index]
                if (item && !item.disabled && !item.loading) {
                    this.$emit('select', item)
                    if (this.closeOnClickAction) {
                        this.close();
                    }
                }
            },
        }
    }
</script>
<style lang="scss" scoped>
    $show-lines: 1;
    $show-reset-button: 1;
    @import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    $uv-action-sheet-reset-button-width:100% !default;
    $uv-action-sheet-title-font-size: 16px !default;
    $uv-action-sheet-title-padding: 12px 30px !default;
    $uv-action-sheet-title-color: $uv-main-color !default;
    $uv-action-sheet-header-icon-wrap-right:15px !default;
    $uv-action-sheet-header-icon-wrap-top:15px !default;
    $uv-action-sheet-description-font-size:13px !default;
    $uv-action-sheet-description-color:14px !default;
    $uv-action-sheet-description-margin: 18px 15px !default;
    $uv-action-sheet-item-wrap-item-padding:15px !default;
    $uv-action-sheet-item-wrap-name-font-size:16px !default;
    $uv-action-sheet-item-wrap-subname-font-size:13px !default;
    $uv-action-sheet-item-wrap-subname-color: #c0c4cc !default;
    $uv-action-sheet-item-wrap-subname-margin-top:10px !default;
    $uv-action-sheet-cancel-text-font-size:16px !default;
    $uv-action-sheet-cancel-text-color:$uv-content-color !default;
    $uv-action-sheet-cancel-text-font-size:15px !default;
    $uv-action-sheet-cancel-text-hover-background-color:rgb(242, 243, 245) !default;
    .uv-reset-button {
        width: $uv-action-sheet-reset-button-width;
    }
    .uv-action-sheet {
        text-align: center;
        &__header {
            position: relative;
            padding: $uv-action-sheet-title-padding;
            &__title {
                font-size: $uv-action-sheet-title-font-size;
                color: $uv-action-sheet-title-color;
                font-weight: bold;
                text-align: center;
            }
            &__icon-wrap {
                position: absolute;
                right: $uv-action-sheet-header-icon-wrap-right;
                top: $uv-action-sheet-header-icon-wrap-top;
            }
        }
        &__description {
            font-size: $uv-action-sheet-description-font-size;
            color: $uv-tips-color;
            margin: $uv-action-sheet-description-margin;
            text-align: center;
        }
        &__item-wrap {
            &__item {
                padding: $uv-action-sheet-item-wrap-item-padding;
                @include flex;
                align-items: center;
                justify-content: center;
                flex-direction: column;
                &__name {
                    font-size: $uv-action-sheet-item-wrap-name-font-size;
                    color: $uv-main-color;
                    text-align: center;
                }
                &__subname {
                    font-size: $uv-action-sheet-item-wrap-subname-font-size;
                    color: $uv-action-sheet-item-wrap-subname-color;
                    margin-top: $uv-action-sheet-item-wrap-subname-margin-top;
                    text-align: center;
                }
            }
        }
        &__cancel-text {
            font-size: $uv-action-sheet-cancel-text-font-size;
            color: $uv-action-sheet-cancel-text-color;
            text-align: center;
            padding: $uv-action-sheet-cancel-text-font-size;
        }
        &--hover {
            background-color: $uv-action-sheet-cancel-text-hover-background-color;
        }
    }
</style>
ledApp/uni_modules/uv-action-sheet/package.json
New file
@@ -0,0 +1,92 @@
{
  "id": "uv-action-sheet",
  "displayName": "uv-action-sheet 底部操作菜单 全面兼容小程序、nvue、vue2、vue3等多端",
  "version": "1.0.2",
  "description": "该组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheet API,配置更加灵活,所有平台都表现一致。",
  "keywords": [
    "action-sheet",
    "uvui",
    "uv-ui",
    "操作菜单",
    "菜单选择"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
      "ads": "无",
      "data": "插件不采集任何数据",
      "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools",
            "uv-popup",
            "uv-icon",
            "uv-line",
            "uv-loading-icon",
            "uv-gap"
        ],
    "encrypt": [],
    "platforms": {
      "cloud": {
        "tcb": "y",
        "aliyun": "y"
      },
      "client": {
        "Vue": {
          "vue2": "y",
          "vue3": "y"
        },
        "App": {
          "app-vue": "y",
          "app-nvue": "y"
        },
        "H5-mobile": {
          "Safari": "y",
          "Android Browser": "y",
          "微信浏览器(Android)": "y",
          "QQ浏览器(Android)": "y"
        },
        "H5-pc": {
          "Chrome": "y",
          "IE": "y",
          "Edge": "y",
          "Firefox": "y",
          "Safari": "y"
        },
        "小程序": {
          "微信": "y",
          "阿里": "y",
          "百度": "y",
          "字节跳动": "y",
          "QQ": "y",
          "钉钉": "u",
          "快手": "u",
          "飞书": "u",
          "京东": "u"
        },
        "快应用": {
          "华为": "u",
          "联盟": "u"
        }
      }
    }
  }
}
ledApp/uni_modules/uv-action-sheet/readme.md
New file
@@ -0,0 +1,13 @@
## ActionSheet 操作菜单
> **组件名:uv-action-sheet**
本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。
本组件功能类似于uni的uni.showActionSheet API,配置更加灵活,所有平台都表现一致。
### <a href="https://www.uvui.cn/components/actionSheet.html" target="_blank">查看文档</a>
### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)
#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-album/changelog.md
New file
@@ -0,0 +1,10 @@
## 1.0.4(2023-12-06)
1. 阻止事件冒泡处理
## 1.0.3(2023-10-23)
1. 修复报错的BUG
## 1.0.2(2023-10-23)
1. 修复设置singleSize、multipleSize、space等值带单位,存在不显示的BUG
## 1.0.1(2023-09-13)
1. 添加依赖
## 1.0.0(2023-08-30)
1. 新增uv-album相册组件
ledApp/uni_modules/uv-album/components/uv-album/uv-album.vue
New file
@@ -0,0 +1,312 @@
<template>
  <view class="uv-album">
    <view
      class="uv-album__row"
      ref="uv-album__row"
      v-for="(arr, index) in showUrls"
      :forComputedUse="albumWidth"
      :key="index"
    >
      <view
        class="uv-album__row__wrapper"
        v-for="(item, index1) in arr"
        :key="index1"
        :style="[imageStyle(index + 1, index1 + 1)]"
        @tap.stop="previewFullImage ? onPreviewTap(getSrc(item)) : ''"
      >
        <image
          :src="getSrc(item)"
          :mode="
            urls.length === 1
              ? imageHeight > 0
                ? singleMode
                  : 'widthFix'
                  : multipleMode
          "
          :style="[
            {
              width: imageWidth,
              height: imageHeight
            }
          ]"
        ></image>
        <view
          v-if="
            showMore &&
            urls.length > rowCount * showUrls.length &&
            index === showUrls.length - 1 &&
            index1 === showUrls[showUrls.length - 1].length - 1
          "
          class="uv-album__row__wrapper__text"
        >
          <uv-text
            :text="`+${urls.length - maxCount}`"
            color="#fff"
            :size="$uv.getPx(multipleSize) * 0.3"
            align="center"
            customStyle="justify-content: center"
          ></uv-text>
        </view>
      </view>
    </view>
  </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    // #ifdef APP-NVUE
    // 由于weex为阿里的KPI业绩考核的产物,所以不支持百分比单位,这里需要通过dom查询组件的宽度
    const dom = uni.requireNativePlugin('dom')
    // #endif
    /**
     * Album 相册
     * @description 本组件提供一个类似相册的功能,让开发者开发起来更加得心应手。减少重复的模板代码
     * @tutorial https://www.uvui.cn/components/album.html
     * @property {Array}           urls             图片地址列表 Array<String>|Array<Object>形式
     * @property {String}          keyName          指定从数组的对象元素中读取哪个属性作为图片地址
     * @property {String | Number} singleSize       单图时,图片长边的长度  (默认 180 )
     * @property {String | Number} multipleSize     多图时,图片边长 (默认 70 )
     * @property {String | Number} space            多图时,图片水平和垂直之间的间隔 (默认 6 )
     * @property {String}          singleMode       单图时,图片缩放裁剪的模式 (默认 'scaleToFill' )
     * @property {String}          multipleMode     多图时,图片缩放裁剪的模式 (默认 'aspectFill' )
     * @property {String | Number} maxCount         取消按钮的提示文字 (默认 9 )
     * @property {Boolean}         previewFullImage 是否可以预览图片 (默认 true )
     * @property {String | Number} rowCount         每行展示图片数量,如设置,singleSize和multipleSize将会无效    (默认 3 )
     * @property {Boolean}         showMore         超出maxCount时是否显示查看更多的提示 (默认 true )
     *
     * @event    {Function}        albumWidth       某些特殊的情况下,需要让文字与相册的宽度相等,这里事件的形式对外发送  (回调参数 width )
     * @example <uv-album :urls="urls2" @albumWidth="width => albumWidth = width" multipleSize="68" ></uv-album>
     */
    export default {
        name: 'uv-album',
        mixins: [mpMixin, mixin],
        emits: ['albumWidth'],
        props: {
            // 图片地址,Array<String>|Array<Object>形式
            urls: {
                type: Array,
                default: () => []
            },
            // 指定从数组的对象元素中读取哪个属性作为图片地址
            keyName: {
                type: String,
                default: ''
            },
            // 单图时,图片长边的长度
            singleSize: {
                type: [String, Number],
                default: 180
            },
            // 多图时,图片边长
            multipleSize: {
                type: [String, Number],
                default: 70
            },
            // 多图时,图片水平和垂直之间的间隔
            space: {
                type: [String, Number],
                default: 6
            },
            // 单图时,图片缩放裁剪的模式
            singleMode: {
                type: String,
                default: 'scaleToFill'
            },
            // 多图时,图片缩放裁剪的模式
            multipleMode: {
                type: String,
                default: 'aspectFill'
            },
            // 最多展示的图片数量,超出时最后一个位置将会显示剩余图片数量
            maxCount: {
                type: [String, Number],
                default: 9
            },
            // 是否可以预览图片
            previewFullImage: {
                type: Boolean,
                default: true
            },
            // 每行展示图片数量,如设置,singleSize和multipleSize将会无效
            rowCount: {
                type: [String, Number],
                default: 3
            },
            // 超出maxCount时是否显示查看更多的提示
            showMore: {
                type: Boolean,
                default: true
            },
            ...uni.$uv?.props?.album
        },
        data() {
            return {
                // 单图的宽度
                singleWidth: 0,
                // 单图的高度
                singleHeight: 0,
                // 单图时,如果无法获取图片的尺寸信息,让图片宽度默认为容器的一定百分比
                singlePercent: 0.6
            }
        },
        watch: {
            urls: {
                immediate: true,
                handler(newVal) {
                    if (newVal.length === 1) {
                        this.getImageRect()
                    }
                }
            }
        },
        computed: {
            imageStyle() {
                return (index1, index2) => {
                    const { space, rowCount, multipleSize, urls } = this;
                    const rowLen = this.showUrls.length;
                    const allLen = this.urls.length;
                    const style = {
                        marginRight: this.$uv.addUnit(space),
                        marginBottom: this.$uv.addUnit(space)
                    }
                    // 如果为最后一行,则每个图片都无需下边框
                    if (index1 === rowLen) style.marginBottom = 0
                    // 每行的最右边一张和总长度的最后一张无需右边框
                    if (
                        index2 === rowCount ||
                        (index1 === rowLen &&
                            index2 === this.showUrls[index1 - 1].length)
                    )
                        style.marginRight = 0
                    return style
                }
            },
            // 将数组划分为二维数组
            showUrls() {
                const arr = []
                this.urls.map((item, index) => {
                    // 限制最大展示数量
                    if (index + 1 <= this.maxCount) {
                        // 计算该元素为第几个素组内
                        const itemIndex = Math.floor(index / this.rowCount)
                        // 判断对应的索引是否存在
                        if (!arr[itemIndex]) {
                            arr[itemIndex] = []
                        }
                        arr[itemIndex].push(item)
                    }
                })
                return arr
            },
            imageWidth() {
                return this.$uv.addUnit(
                    this.urls.length === 1 ? this.singleWidth : this.multipleSize
                )
            },
            imageHeight() {
                return this.$uv.addUnit(
                    this.urls.length === 1 ? this.singleHeight : this.multipleSize
                )
            },
            // 此变量无实际用途,仅仅是为了利用computed特性,让其在urls长度等变化时,重新计算图片的宽度
            // 因为用户在某些特殊的情况下,需要让文字与相册的宽度相等,所以这里事件的形式对外发送
            albumWidth() {
                let width = 0
                if (this.urls.length === 1) {
                    width = this.singleWidth
                } else {
                    width =
                        this.showUrls[0].length * this.$uv.getPx(this.multipleSize) +
                        this.$uv.getPx(this.space) * (this.showUrls[0].length - 1)
                }
                this.$emit('albumWidth', width)
                return width
            }
        },
        methods: {
            // 预览图片
            onPreviewTap(url) {
                const urls = this.urls.map((item) => {
                    return this.getSrc(item)
                })
                uni.previewImage({
                    current: url,
                    urls
                })
            },
            // 获取图片的路径
            getSrc(item) {
                return this.$uv.test.object(item) ?
                    (this.keyName && item[this.keyName]) || item.src :
                    item
            },
            // 单图时,获取图片的尺寸
            // 在小程序中,需要将网络图片的的域名添加到小程序的download域名才可能获取尺寸
            // 在没有添加的情况下,让单图宽度默认为盒子的一定宽度(singlePercent)
            getImageRect() {
                const src = this.getSrc(this.urls[0])
                uni.getImageInfo({
                    src,
                    success: (res) => {
                        // 判断图片横向还是竖向展示方式
                        const isHorizotal = res.width >= res.height
                        this.singleWidth = isHorizotal ?
                            this.singleSize :
                            (res.width / res.height) * this.$uv.getPx(this.singleSize)
                        this.singleHeight = !isHorizotal ?
                            this.singleSize :
                            (res.height / res.width) * this.singleWidth
                    },
                    fail: () => {
                        this.getComponentWidth()
                    }
                })
            },
            // 获取组件的宽度
            async getComponentWidth() {
                // 延时一定时间,以获取dom尺寸
                await this.$uv.sleep(30)
                // #ifndef APP-NVUE
                this.$uGetRect('.uv-album__row').then((size) => {
                    this.singleWidth = size.width * this.singlePercent
                })
                // #endif
                // #ifdef APP-NVUE
                // 这里ref="uv-album__row"所在的标签为通过for循环出来,导致this.$refs['uv-album__row']是一个数组
                const ref = this.$refs['uv-album__row'][0]
                ref &&
                    dom.getComponentRect(ref, (res) => {
                        this.singleWidth = res.size.width * this.singlePercent
                    })
                // #endif
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    .uv-album {
        @include flex(column);
        &__row {
            @include flex(row);
            flex-wrap: wrap;
            &__wrapper {
                position: relative;
                &__text {
                    position: absolute;
                    top: 0;
                    left: 0;
                    right: 0;
                    bottom: 0;
                    background-color: rgba(0, 0, 0, 0.3);
                    @include flex(row);
                    justify-content: center;
                    align-items: center;
                }
            }
        }
    }
</style>
ledApp/uni_modules/uv-album/package.json
New file
@@ -0,0 +1,88 @@
{
  "id": "uv-album",
  "displayName": "uv-album 相册 全面兼容vue3+2、app、h5、小程序等多端",
  "version": "1.0.4",
  "description": "本组件提供一个类似相册的功能,让开发者开发起来更加得心应手,功能齐全,灵活配置可以,开箱即用。减少重复的模板代码",
  "keywords": [
    "album",
    "uv-ui",
    "uvui",
    "相册",
    "图片"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools",
            "uv-text"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-album/readme.md
New file
@@ -0,0 +1,21 @@
# Album 相册
> **组件名:uv-album**
本组件提供一个类似相册的功能,让开发者开发起来更加得心应手。
功能齐全,灵活配置可以,开箱即用。减少重复的模板代码。
# <a href="https://www.uvui.cn/components/album.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>(请不要 下载插件ZIP)</small>
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
</a>
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-alert/changelog.md
New file
@@ -0,0 +1,7 @@
## 1.0.2(2023-06-01)
1. 修复点击触发两次实践的BUG
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-alert 警告提示组件
ledApp/uni_modules/uv-alert/components/uv-alert/props.js
New file
@@ -0,0 +1,45 @@
export default {
    props: {
        // 显示文字
        title: {
            type: String,
            default: ''
        },
        // 主题,success/warning/info/error
        type: {
            type: String,
            default: 'warning'
        },
        // 辅助性文字
        description: {
            type: String,
            default: ''
        },
        // 是否可关闭
        closable: {
            type: Boolean,
            default: false
        },
        // 是否显示图标
        showIcon: {
            type: Boolean,
            default: false
        },
        // 浅或深色调,light-浅色,dark-深色
        effect: {
            type: String,
            default: 'light'
        },
        // 文字是否居中
        center: {
            type: Boolean,
            default: false
        },
        // 字体大小
        fontSize: {
            type: [String, Number],
            default: 14
        },
        ...uni.$uv?.props?.alert
    }
}
ledApp/uni_modules/uv-alert/components/uv-alert/uv-alert.vue
New file
@@ -0,0 +1,246 @@
<template>
    <uv-transition
        mode="fade"
        :show="show"
    >
        <view
            class="uv-alert"
            :class="[`uv-alert--${type}--${effect}`]"
            @tap.stop="clickHandler"
            :style="[$uv.addStyle(customStyle)]"
        >
            <view
                class="uv-alert__icon"
                v-if="showIcon"
            >
                <uv-icon
                    :name="iconName"
                    size="18"
                    :color="iconColor"
                ></uv-icon>
            </view>
            <view
                class="uv-alert__content"
                :style="[{
                    paddingRight: closable ? '20px' : 0
                }]"
            >
                <text
                    class="uv-alert__content__title"
                    v-if="title"
                    :style="[{
                        fontSize: $uv.addUnit(fontSize),
                        textAlign: center ? 'center' : 'left'
                    }]"
                    :class="[effect === 'dark' ? 'uv-alert__text--dark' : `uv-alert__text--${type}--light`]"
                >{{ title }}</text>
                <text
                    class="uv-alert__content__desc"
                    v-if="description"
                    :style="[{
                        fontSize: $uv.addUnit(fontSize),
                        textAlign: center ? 'center' : 'left'
                    }]"
                    :class="[effect === 'dark' ? 'uv-alert__text--dark' : `uv-alert__text--${type}--light`]"
                >{{ description }}</text>
            </view>
            <view
                class="uv-alert__close"
                v-if="closable"
                @tap.stop="closeHandler"
            >
                <uv-icon
                    name="close"
                    :color="iconColor"
                    size="15"
                ></uv-icon>
            </view>
        </view>
    </uv-transition>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * Alert  警告提示
     * @description 警告提示,展现需要关注的信息。
     * @tutorial https://www.uvui.cn/components/alertTips.html
     *
     * @property {String}           title       显示的文字
     * @property {String}           type        使用预设的颜色  (默认 'warning' )
     * @property {String}           description 辅助性文字,颜色比title浅一点,字号也小一点,可选
     * @property {Boolean}          closable    关闭按钮(默认为叉号icon图标)  (默认 false )
     * @property {Boolean}          showIcon    是否显示左边的辅助图标   ( 默认 false )
     * @property {String}           effect      多图时,图片缩放裁剪的模式  (默认 'light' )
     * @property {Boolean}          center      文字是否居中  (默认 false )
     * @property {String | Number}  fontSize    字体大小  (默认 14 )
     * @property {Object}           customStyle 定义需要用到的外部样式
     * @event    {Function}        click       点击组件时触发
     * @example  <uv-alert :title="title"  type = "warning" :closable="closable" :description = "description"></uv-alert>
     */
    export default {
        name: 'uv-alert',
        mixins: [mpMixin, mixin, props],
        emits: ['click'],
        data() {
            return {
                show: true
            }
        },
        computed: {
            iconColor() {
                return this.effect === 'light' ? this.type : '#fff'
            },
            // 不同主题对应不同的图标
            iconName() {
                switch (this.type) {
                    case 'success':
                        return 'checkmark-circle-fill';
                        break;
                    case 'error':
                        return 'close-circle-fill';
                        break;
                    case 'warning':
                        return 'error-circle-fill';
                        break;
                    case 'info':
                        return 'info-circle-fill';
                        break;
                    case 'primary':
                        return 'more-circle-fill';
                        break;
                    default:
                        return 'error-circle-fill';
                }
            }
        },
        methods: {
            // 点击内容
            clickHandler() {
                this.$emit('click')
            },
            // 点击关闭按钮
            closeHandler() {
                this.show = false
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    .uv-alert {
        position: relative;
        background-color: $uv-primary;
        padding: 8px 10px;
        @include flex(row);
        align-items: center;
        border-top-left-radius: 4px;
        border-top-right-radius: 4px;
        border-bottom-left-radius: 4px;
        border-bottom-right-radius: 4px;
        &--primary--dark {
            background-color: $uv-primary;
        }
        &--primary--light {
            background-color: #ecf5ff;
        }
        &--error--dark {
            background-color: $uv-error;
        }
        &--error--light {
            background-color: #FEF0F0;
        }
        &--success--dark {
            background-color: $uv-success;
        }
        &--success--light {
            background-color: #f5fff0;
        }
        &--warning--dark {
            background-color: $uv-warning;
        }
        &--warning--light {
            background-color: #FDF6EC;
        }
        &--info--dark {
            background-color: $uv-info;
        }
        &--info--light {
            background-color: #f4f4f5;
        }
        &__icon {
            margin-right: 5px;
        }
        &__content {
            @include flex(column);
            flex: 1;
            &__title {
                color: $uv-main-color;
                font-size: 14px;
                font-weight: bold;
                color: #fff;
                margin-bottom: 2px;
            }
            &__desc {
                color: $uv-main-color;
                font-size: 14px;
                flex-wrap: wrap;
                color: #fff;
            }
        }
        &__title--dark,
        &__desc--dark {
            color: #FFFFFF;
        }
        &__text--primary--light,
        &__text--primary--light {
            color: $uv-primary;
        }
        &__text--success--light,
        &__text--success--light {
            color: $uv-success;
        }
        &__text--warning--light,
        &__text--warning--light {
            color: $uv-warning;
        }
        &__text--error--light,
        &__text--error--light {
            color: $uv-error;
        }
        &__text--info--light,
        &__text--info--light {
            color: $uv-info;
        }
        &__close {
            position: absolute;
            top: 11px;
            right: 10px;
        }
    }
</style>
ledApp/uni_modules/uv-alert/package.json
New file
@@ -0,0 +1,88 @@
{
    "id": "uv-alert",
    "displayName": "uv-alert 警告提示 全面兼容小程序、nvue、vue2、vue3等多端",
    "version": "1.0.2",
    "description": "uv-alert 警告提示,展现需要关注的信息。灵活配置,功能齐全,兼容全端",
    "keywords": [
        "alert",
        "uvui",
        "uv-ui",
        "警告提示"
    ],
    "repository": "",
    "engines": {
        "HBuilderX": "^3.1.0"
    },
    "dcloudext": {
        "type": "component-vue",
        "sale": {
            "regular": {
                "price": "0.00"
            },
            "sourcecode": {
                "price": "0.00"
            }
        },
        "contact": {
            "qq": ""
        },
        "declaration": {
            "ads": "无",
            "data": "插件不采集任何数据",
            "permissions": "无"
        },
        "npmurl": ""
    },
    "uni_modules": {
        "dependencies": [
            "uv-ui-tools",
            "uv-transition",
            "uv-icon"
        ],
        "encrypt": [],
        "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
    }
}
ledApp/uni_modules/uv-alert/readme.md
New file
@@ -0,0 +1,15 @@
## Alert 警告提示
> **组件名:uv-alert**
警告提示,展现需要关注的信息。
当某个页面需要向用户显示警告的信息时。
非浮层的静态展现形式,始终展现,不会自动消失,用户可以点击关闭。
### <a href="https://www.uvui.cn/components/alert.html" target="_blank">查看文档</a>
### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)
#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-avatar/changelog.md
New file
@@ -0,0 +1,13 @@
## 1.0.5(2023-12-06)
1. 优化
## 1.0.4(2023-12-06)
1. 优化
## 1.0.3(2023-12-06)
1. 阻止事件冒泡处理,单个头像模式
## 1.0.2(2023-12-06)
1. 阻止事件冒泡处理
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-avatar 头像组件
ledApp/uni_modules/uv-avatar/components/uv-avatar-group/props.js
New file
@@ -0,0 +1,53 @@
export default {
    props: {
        // 头像图片组
        urls: {
            type: Array,
            default: () => []
        },
        // 最多展示的头像数量
        maxCount: {
            type: [String, Number],
            default: 5
        },
        // 头像形状
        shape: {
            type: String,
            default: 'circle'
        },
        // 图片裁剪模式
        mode: {
            type: String,
            default: 'scaleToFill'
        },
        // 超出maxCount时是否显示查看更多的提示
        showMore: {
            type: Boolean,
            default: true
        },
        // 头像大小
        size: {
            type: [String, Number],
            default: 40
        },
        // 指定从数组的对象元素中读取哪个属性作为图片地址
        keyName: {
            type: String,
            default: ''
        },
        // 头像之间的遮挡比例
        gap: {
            type: [String, Number],
            validator(value) {
                return value >= 0 && value <= 1
            },
            default: 0.5
        },
        // 需额外显示的值
        extraValue: {
            type: [Number, String],
            default: 0
        },
        ...uni.$uv?.props?.avatarGroup
    }
}
ledApp/uni_modules/uv-avatar/components/uv-avatar-group/uv-avatar-group.vue
New file
@@ -0,0 +1,106 @@
<template>
    <view class="uv-avatar-group">
        <view
            class="uv-avatar-group__item"
            v-for="(item, index) in showUrl"
            :key="index"
            :style="{
                marginLeft: index === 0 ? 0 : $uv.addUnit(-size * gap)
            }"
        >
            <uv-avatar
                :size="size"
                :shape="shape"
                :mode="mode"
                :src="$uv.test.object(item) ? keyName && item[keyName] || item.url : item"
            ></uv-avatar>
            <view
                class="uv-avatar-group__item__show-more"
                v-if="showMore && index === showUrl.length - 1 && (urls.length > maxCount || extraValue > 0)"
                @tap="clickHandler"
            >
                <uv-text
                    color="#ffffff"
                    :size="size * 0.4"
                    :text="`+${extraValue || urls.length - showUrl.length}`"
                    align="center"
                    customStyle="justify-content: center"
                ></uv-text>
            </view>
        </view>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * AvatarGroup  头像组
     * @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
     * @tutorial https://www.uvui.cn/components/avatar.html
     *
     * @property {Array}           urls     头像图片组 (默认 [] )
     * @property {String | Number} maxCount 最多展示的头像数量 ( 默认 5 )
     * @property {String}          shape    头像形状( 'circle' (默认) | 'square' )
     * @property {String}          mode     图片裁剪模式(默认 'scaleToFill' )
     * @property {Boolean}         showMore 超出maxCount时是否显示查看更多的提示 (默认 true )
     * @property {String | Number} size      头像大小 (默认 40 )
     * @property {String}          keyName  指定从数组的对象元素中读取哪个属性作为图片地址
     * @property {String | Number} gap      头像之间的遮挡比例(0.4代表遮挡40%)  (默认 0.5 )
     * @property {String | Number} extraValue  需额外显示的值
     * @event    {Function}        showMore 头像组更多点击
     * @example  <uv-avatar-group:urls="urls" size="35" gap="0.4" ></uv-avatar-group:urls=>
     */
    export default {
        name: 'uv-avatar-group',
        mixins: [mpMixin, mixin, props],
        data() {
            return {
            }
        },
        computed: {
            showUrl() {
                return this.urls.slice(0, this.maxCount)
            }
        },
        methods: {
            clickHandler() {
                this.$emit('showMore')
            }
        },
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    .uv-avatar-group {
        @include flex;
        &__item {
            margin-left: -10px;
            position: relative;
            &--no-indent {
                // 如果你想质疑作者不会使用:first-child,说明你太年轻,因为nvue不支持
                margin-left: 0;
            }
            &__show-more {
                position: absolute;
                top: 0;
                bottom: 0;
                left: 0;
                right: 0;
                background-color: rgba(0, 0, 0, 0.3);
                @include flex;
                align-items: center;
                justify-content: center;
                border-radius: 100px;
            }
        }
    }
</style>
ledApp/uni_modules/uv-avatar/components/uv-avatar/props.js
New file
@@ -0,0 +1,80 @@
import { range } from '@/uni_modules/uv-ui-tools/libs/function/test.js'
export default {
    props: {
        // 头像图片路径(不能为相对路径)
        src: {
            type: String,
            default: ''
        },
        // 头像形状,circle-圆形,square-方形
        shape: {
            type: String,
            default: 'circle'
        },
        // 头像尺寸
        size: {
            type: [String, Number],
            default: 40
        },
        // 裁剪模式
        mode: {
            type: String,
            default: 'scaleToFill'
        },
        // 显示的文字
        text: {
            type: String,
            default: ''
        },
        // 背景色
        bgColor: {
            type: String,
            default: '#c0c4cc'
        },
        // 文字颜色
        color: {
            type: String,
            default: '#fff'
        },
        // 文字大小
        fontSize: {
            type: [String, Number],
            default: 18
        },
        // 显示的图标
        icon: {
            type: String,
            default: ''
        },
        // 显示小程序头像,只对百度,微信,QQ小程序有效
        mpAvatar: {
            type: Boolean,
            default: false
        },
        // 是否使用随机背景色
        randomBgColor: {
            type: Boolean,
            default: false
        },
        // 加载失败的默认头像(组件有内置默认图片)
        defaultUrl: {
            type: String,
            default: ''
        },
        // 如果配置了randomBgColor为true,且配置了此值,则从默认的背景色数组中取出对应索引的颜色值,取值0-19之间
        colorIndex: {
            type: [String, Number],
            // 校验参数规则,索引在0-19之间
            validator(n) {
                return range(n, [0, 19]) || n === ''
            },
            default: ''
        },
        // 组件标识符
        name: {
            type: String,
            default: ''
        },
        ...uni.$uv?.props?.avatar
    }
}
ledApp/uni_modules/uv-avatar/components/uv-avatar/uv-avatar.vue
New file
@@ -0,0 +1,175 @@
<template>
    <view
        class="uv-avatar"
        :class="[`uv-avatar--${shape}`]"
        :style="[{
            backgroundColor: (text || icon) ? (randomBgColor ? colors[colorIndex !== '' ? colorIndex : $uv.random(0, 19)] : bgColor) : 'transparent',
            width: $uv.addUnit(size),
            height: $uv.addUnit(size),
        }, $uv.addStyle(customStyle)]"
        @tap="clickHandler"
    >
        <slot>
            <!-- #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU  -->
            <open-data
                v-if="mpAvatar && allowMp"
                type="userAvatarUrl"
                :style="[{
                    width: $uv.addUnit(size),
                    height: $uv.addUnit(size)
                }]"
            />
            <!-- #endif -->
            <!-- #ifndef MP-WEIXIN && MP-QQ && MP-BAIDU  -->
            <template v-if="mpAvatar && allowMp"></template>
            <!-- #endif -->
            <uv-icon
                v-else-if="icon"
                :name="icon"
                :size="fontSize"
                :color="color"
            ></uv-icon>
            <uv-text
                v-else-if="text"
                :text="text"
                :size="fontSize"
                :color="color"
                align="center"
                customStyle="justify-content: center"
            ></uv-text>
            <image
                class="uv-avatar__image"
                v-else
                :class="[`uv-avatar__image--${shape}`]"
                :src="avatarUrl || defaultUrl"
                :mode="mode"
                @error="errorHandler"
                :style="[{
                    width: $uv.addUnit(size),
                    height: $uv.addUnit(size)
                }]"
            ></image>
        </slot>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    const base64Avatar =
        "data:image/jpg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMraHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjREMEQwRkY0RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjREMEQwRkY1RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NEQwRDBGRjJGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NEQwRDBGRjNGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAGBAQEBQQGBQUGCQYFBgkLCAYGCAsMCgoLCgoMEAwMDAwMDBAMDg8QDw4MExMUFBMTHBsbGxwfHx8fHx8fHx8fAQcHBw0MDRgQEBgaFREVGh8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx//wAARCADIAMgDAREAAhEBAxEB/8QAcQABAQEAAwEBAAAAAAAAAAAAAAUEAQMGAgcBAQAAAAAAAAAAAAAAAAAAAAAQAAIBAwICBgkDBQAAAAAAAAABAhEDBCEFMVFBYXGREiKBscHRMkJSEyOh4XLxYjNDFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A/fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHbHFyZ/Dam+yLA+Z2L0Pjtyj2poD4AAAAAAAAAAAAAAAAAAAAAAAAKWFs9y6lcvvwQeqj8z9wFaziY1n/HbUX9XF97A7QAGXI23EvJ1goyfzR0YEfN269jeZ+a03pNe0DIAAAAAAAAAAAAAAAAAAAACvtO3RcVkXlWutuL9YFYAAAAAOJRjKLjJVi9GmB5/csH/mu1h/in8PU+QGMAAAAAAAAAAAAAAAAAAaMDG/6MmMH8C80+xAelSSVFolwQAAAAAAAHVlWI37ErUulaPk+hgeYnCUJuElSUXRrrQHAAAAAAAAAAAAAAAAABa2Oz4bM7r4zdF2ICmAAAAAAAAAg7zZ8GX41wuJP0rRgYAAAAAAAAAAAAAAAAAD0m2R8ODaXU33tsDSAAAAAAAAAlb9HyWZcnJd9PcBHAAAAAAAAAAAAAAAAAPS7e64Vn+KA0AAAAAAAAAJm+v8Ftf3ewCKAAAAAAAAAAAAAAAAAX9muqeGo9NttP06+0DcAAAAAAAAAjb7dTu2ra+VOT9P8AQCWAAAAAAAAAAAAAAAAAUNmyPt5Ltv4bui/kuAF0AAAAAAADiUlGLlJ0SVW+oDzOXfd/Ind6JPRdS0QHSAAAAAAAAAAAAAAAAAE2nVaNcGB6Lbs6OTao9LsF51z60BrAAAAAABJ3jOVHjW3r/sa9QEgAAAAAAAAAAAAAAAAAAAPu1duWriuW34ZR4MC9hbnZyEoy8l36XwfYBsAAADaSq9EuLAlZ+7xSdrGdW9Hc5dgEdtt1erfFgAAAAAAAAAAAAAAAAADVjbblX6NR8MH80tEBRs7HYivyzlN8lovaBPzduvY0m6eK10TXtAyAarO55lpJK54orolr+4GqO/Xaea1FvqbXvA+Z77kNeW3GPbV+4DJfzcm/pcm3H6Vou5AdAFLC2ed2Pjv1txa8sV8T6wOL+yZEKu1JXFy4MDBOE4ScZxcZLinoB8gAAAAAAAAAAAB242LeyJ+C3GvN9C7QLmJtePYpKS+5c+p8F2IDYAANJqj1T4oCfk7Nj3G5Wn9qXJax7gJ93Z82D8sVNc4v30A6Xg5i42Z+iLfqARwcyT0sz9MWvWBps7LlTf5Grce9/oBTxdtxseklHxT+uWr9AGoAB138ezfj4bsFJdD6V2MCPm7RdtJzs1uW1xXzL3gTgAAAAAAAAADRhYc8q74I6RWs5ckB6GxYtWLat21SK731sDsAAAAAAAAAAAAAAAASt021NO/YjrxuQXT1oCOAAAAAAABzGLlJRSq26JAelwsWONYjbXxcZvmwO8AAAAAAAAAAAAAAAAAAef3TEWPkVivx3NY9T6UBiAAAAAABo2+VmGXblddIJ8eivRUD0oAAAAAAAAAAAAAAAAAAAYt4tKeFKVNYNSXfRgefAAAAAAAAr7VuSSWPedKaW5v1MCsAAAAAAAAAAAAAAAAAAIe6bj96Ts2n+JPzSXzP3ATgAAAAAAAAFbbt1UUrOQ9FpC4/UwK6aaqtU+DAAAAAAAAAAAAAAA4lKMIuUmoxWrb4ARNx3R3q2rLpa4Sl0y/YCcAAAAAAAAAAANmFud7G8r89r6X0dgFvGzLGRGtuWvTF6NAdwAAAAAAAAAAAy5W442PVN+K59EePp5ARMvOv5MvO6QXCC4AZwAAAAAAAAAAAAAcxlKLUotprg1owN+PvORborq+7Hnwl3gUbO74VzRydt8pKn68ANcJwmqwkpLmnUDkAAAAfNy9atqtyagut0AxXt5xIV8Fbj6lRd7Am5G65V6qUvtwfyx94GMAAAAAAAAAAAAAAAAAAAOU2nVOj5gdsc3LiqRvTpyqwOxbnnrhdfpSfrQB7pnv/AGvuS9gHXPMy5/Fem1yq0v0A6W29XqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//Z";
    /**
     * Avatar  头像
     * @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
     * @tutorial https://www.uvui.cn/components/avatar.html
     *
     * @property {String}           src             头像路径,如加载失败,将会显示默认头像(不能为相对路径)
     * @property {String}           shape           头像形状  ( circle (默认) | square)
     * @property {String | Number}  size            头像尺寸,可以为指定字符串(large, default, mini),或者数值 (默认 40 )
     * @property {String}           mode            头像图片的裁剪类型,与uni的image组件的mode参数一致,如效果达不到需求,可尝试传widthFix值 (默认 'scaleToFill' )
     * @property {String}           text            用文字替代图片,级别优先于src
     * @property {String}           bgColor         背景颜色,一般显示文字时用 (默认 '#c0c4cc' )
     * @property {String}           color           文字颜色 (默认 '#ffffff' )
     * @property {String | Number}  fontSize        文字大小  (默认 18 )
     * @property {String}           icon            显示的图标
     * @property {Boolean}          mpAvatar        显示小程序头像,只对百度,微信,QQ小程序有效  (默认 false )
     * @property {Boolean}          randomBgColor   是否使用随机背景色  (默认 false )
     * @property {String}           defaultUrl      加载失败的默认头像(组件有内置默认图片)
     * @property {String | Number}  colorIndex      如果配置了randomBgColor为true,且配置了此值,则从默认的背景色数组中取出对应索引的颜色值,取值0-19之间
     * @property {String}           name            组件标识符  (默认 'level' )
     * @property {Object}           customStyle     定义需要用到的外部样式
     *
     * @event    {Function}        click       点击组件时触发   index: 用户传递的标识符
     * @example  <uv-avatar :src="src" mode="square"></uv-avatar>
     */
    export default {
        name: 'uv-avatar',
        emits: ['click'],
        mixins: [mpMixin, mixin, props],
        data() {
            return {
                // 如果配置randomBgColor参数为true,在图标或者文字的模式下,会随机从中取出一个颜色值当做背景色
                colors: ['#ffb34b', '#f2bba9', '#f7a196', '#f18080', '#88a867', '#bfbf39', '#89c152', '#94d554', '#f19ec2',
                    '#afaae4', '#e1b0df', '#c38cc1', '#72dcdc', '#9acdcb', '#77b1cc', '#448aca', '#86cefa', '#98d1ee',
                    '#73d1f1',
                    '#80a7dc'
                ],
                avatarUrl: this.src,
                allowMp: false
            }
        },
        watch: {
            // 监听头像src的变化,赋值给内部的avatarUrl变量,因为图片加载失败时,需要修改图片的src为默认值
            // 而组件内部不能直接修改props的值,所以需要一个中间变量
            src: {
                immediate: true,
                handler(newVal) {
                    this.avatarUrl = newVal
                    // 如果没有传src,则主动触发error事件,用于显示默认的头像,否则src为''空字符等的时候,会无内容展示
                    if(!newVal) {
                        this.errorHandler()
                    }
                }
            }
        },
        computed: {
            imageStyle() {
                const style = {}
                return style
            }
        },
        created() {
            this.init()
        },
        methods: {
            init() {
                // 目前只有这几个小程序平台具有open-data标签
                // 其他平台可以通过uni.getUserInfo类似接口获取信息,但是需要弹窗授权(首次),不合符组件逻辑
                // 故目前自动获取小程序头像只支持这几个平台
                // #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU
                this.allowMp = true
                // #endif
            },
            // 判断传入的name属性,是否图片路径,只要带有"/"均认为是图片形式
            isImg() {
                return this.src.indexOf('/') !== -1
            },
            // 图片加载时失败时触发
            errorHandler() {
                this.avatarUrl = this.defaultUrl || base64Avatar
            },
            clickHandler() {
                this.$emit('click', this.name)
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    .uv-avatar {
        @include flex;
        align-items: center;
        justify-content: center;
        &--circle {
            border-radius: 100px;
        }
        &--square {
            border-radius: 4px;
        }
        &__image {
            &--circle {
                border-radius: 100px;
            }
            &--square {
                border-radius: 4px;
            }
        }
    }
</style>
ledApp/uni_modules/uv-avatar/package.json
New file
@@ -0,0 +1,89 @@
{
    "id": "uv-avatar",
    "displayName": "uv-avatar 头像 全面兼容小程序、nvue、vue2、vue3等多端",
    "version": "1.0.5",
    "description": "uv-avatar 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。",
    "keywords": [
        "uv-avatar",
        "uvui",
        "uv-ui",
        "avatar",
        "头像"
    ],
    "repository": "",
    "engines": {
        "HBuilderX": "^3.1.0"
    },
    "dcloudext": {
        "type": "component-vue",
        "sale": {
            "regular": {
                "price": "0.00"
            },
            "sourcecode": {
                "price": "0.00"
            }
        },
        "contact": {
            "qq": ""
        },
        "declaration": {
            "ads": "无",
            "data": "插件不采集任何数据",
            "permissions": "无"
        },
        "npmurl": ""
    },
    "uni_modules": {
        "dependencies": [
            "uv-ui-tools",
            "uv-icon",
            "uv-text"
        ],
        "encrypt": [],
        "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
    }
}
ledApp/uni_modules/uv-avatar/readme.md
New file
@@ -0,0 +1,11 @@
## Avatar 头像
> **组件名:uv-avatar**
本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
### <a href="https://www.uvui.cn/components/avatar.html" target="_blank">查看文档</a>
### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)
#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-back-top/changelog.md
New file
@@ -0,0 +1,8 @@
## 1.0.2(2023-07-03)
1. 优化插槽自定义内容部分
2. 增加backToTop方法说明
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-back-top 返回顶部
ledApp/uni_modules/uv-back-top/components/uv-back-top/props.js
New file
@@ -0,0 +1,58 @@
export default {
    props: {
        // 返回顶部的形状,circle-圆形,square-方形
        mode: {
            type: String,
            default: 'circle'
        },
        // 自定义图标
        icon: {
            type: String,
            default: 'arrow-upward'
        },
        // 提示文字
        text: {
            type: String,
            default: ''
        },
        // 返回顶部滚动时间
        duration: {
            type: [String, Number],
            default: 100
        },
        // 滚动距离
        scrollTop: {
            type: [String, Number],
            default: 0
        },
        // 距离顶部多少距离显示,单位px
        top: {
            type: [String, Number],
            default: 400
        },
        // 返回顶部按钮到底部的距离,单位px
        bottom: {
            type: [String, Number],
            default: 100
        },
        // 返回顶部按钮到右边的距离,单位px
        right: {
            type: [String, Number],
            default: 20
        },
        // 层级
        zIndex: {
            type: [String, Number],
            default: 9
        },
        // 图标的样式,对象形式
        iconStyle: {
            type: Object,
            default: () => ({
                color: '#909399',
                fontSize: '19px'
            })
        },
        ...uni.$uv?.props?.backtop
    }
}
ledApp/uni_modules/uv-back-top/components/uv-back-top/uv-back-top.vue
New file
@@ -0,0 +1,116 @@
<template>
    <uv-transition mode="fade" :customStyle="backTopStyle" :show="show">
        <slot>
            <view class="uv-back-top" :style="[contentStyle]" @click="backToTop">
                <uv-icon :name="icon" :custom-style="iconStyle"></uv-icon>
                <text v-if="text" class="uv-back-top__text">{{text}}</text>
            </view>
        </slot>
    </uv-transition>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    // #ifdef APP-NVUE
    const dom = weex.requireModule('dom')
    // #endif
    /**
     * backTop 返回顶部
     * @description 本组件一个用于长页面,滑动一定距离后,出现返回顶部按钮,方便快速返回顶部的场景。
     * @tutorial https://www.uvui.cn/components/backTop.html
     * @property {String}           mode        返回顶部的形状,circle-圆形,square-方形 (默认 'circle' )
     * @property {String}           icon        自定义图标 (默认 'arrow-upward' ) 见官方文档示例
     * @property {String}           text        提示文字
     * @property {String | Number}  duration    返回顶部滚动时间 (默认 100)
     * @property {String | Number}  scrollTop   滚动距离 (默认 0 )
     * @property {String | Number}  top         距离顶部多少距离显示,单位px (默认 400 )
     * @property {String | Number}  bottom      返回顶部按钮到底部的距离,单位px (默认 100 )
     * @property {String | Number}  right       返回顶部按钮到右边的距离,单位px (默认 20 )
     * @property {String | Number}  zIndex      层级   (默认 9 )
     * @property {Object<Object>}   iconStyle   图标的样式,对象形式   (默认 {color: '#909399',fontSize: '19px'})
     * @property {Object}           customStyle 定义需要用到的外部样式
     *
     * @example <uv-back-top :scrollTop="scrollTop"></uv-back-top>
     */
    export default {
        name: 'uv-back-top',
        emits: ['click'],
        mixins: [mpMixin, mixin, props],
        computed: {
            backTopStyle() {
                // 动画组件样式
                const style = {
                    bottom: this.$uv.addUnit(this.bottom),
                    right: this.$uv.addUnit(this.right),
                    width: '40px',
                    height: '40px',
                    position: 'fixed',
                    zIndex: 10,
                }
                return style
            },
            show() {
                return this.$uv.getPx(this.scrollTop) > this.$uv.getPx(this.top)
            },
            contentStyle() {
                const style = {}
                let radius = 0
                // 是否圆形
                if (this.mode === 'circle') {
                    radius = '100px'
                } else {
                    radius = '4px'
                }
                // 为了兼容安卓nvue,只能这么分开写
                style.borderTopLeftRadius = radius
                style.borderTopRightRadius = radius
                style.borderBottomLeftRadius = radius
                style.borderBottomRightRadius = radius
                return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
            }
        },
        methods: {
            backToTop() {
                // #ifdef APP-NVUE
                if (!this.$parent.$refs['uv-back-top']) {
                    this.$uv.error(`nvue页面需要给页面最外层元素设置"ref='uv-back-top'`)
                }
                dom.scrollToElement(this.$parent.$refs['uv-back-top'], {
                    offset: 0
                })
                // #endif
                // #ifndef APP-NVUE
                uni.pageScrollTo({
                    scrollTop: 0,
                    duration: this.duration
                });
                // #endif
                this.$emit('click')
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    $uv-back-top-flex: 1 !default;
    $uv-back-top-height: 100% !default;
    $uv-back-top-background-color: #E1E1E1 !default;
    $uv-back-top-tips-font-size: 12px !default;
    .uv-back-top {
        @include flex;
        flex-direction: column;
        align-items: center;
        flex: $uv-back-top-flex;
        height: $uv-back-top-height;
        justify-content: center;
        background-color: $uv-back-top-background-color;
        &__tips {
            font-size: $uv-back-top-tips-font-size;
            transform: scale(0.8);
        }
    }
</style>
ledApp/uni_modules/uv-back-top/package.json
New file
@@ -0,0 +1,89 @@
{
    "id": "uv-back-top",
    "displayName": "uv-back-top 返回顶部  全面兼容小程序、nvue、vue2、vue3等多端",
    "version": "1.0.2",
    "description": "返回顶部 组件一个用于长页面,滑动一定距离后,出现返回顶部按钮,方便快速返回顶部的场景。",
    "keywords": [
        "uv-back-top",
        "uvui",
        "uv-ui",
        "avatar",
        "返回顶部"
    ],
    "repository": "",
    "engines": {
        "HBuilderX": "^3.1.0"
    },
    "dcloudext": {
        "type": "component-vue",
        "sale": {
            "regular": {
                "price": "0.00"
            },
            "sourcecode": {
                "price": "0.00"
            }
        },
        "contact": {
            "qq": ""
        },
        "declaration": {
            "ads": "无",
            "data": "插件不采集任何数据",
            "permissions": "无"
        },
        "npmurl": ""
    },
    "uni_modules": {
        "dependencies": [
            "uv-ui-tools",
            "uv-icon",
            "uv-transition"
        ],
        "encrypt": [],
        "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
    }
}
ledApp/uni_modules/uv-back-top/readme.md
New file
@@ -0,0 +1,11 @@
## BackTop 返回顶部
> **组件名:uv-back-top**
该组件一个用于长页面,滑动一定距离后,出现返回顶部按钮,方便快速返回顶部的场景。
### <a href="https://www.uvui.cn/components/backTop.html" target="_blank">查看文档</a>
### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)
#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-badge/changelog.md
New file
@@ -0,0 +1,7 @@
## 1.0.2(2023-06-04)
1. 修复type等属性为null的时候不显示徽标的BUG
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-badge 徽标数,数字角标
ledApp/uni_modules/uv-badge/components/uv-badge/props.js
New file
@@ -0,0 +1,73 @@
export default {
    props: {
        // 是否显示圆点
        isDot: {
            type: Boolean,
            default: false
        },
        // 显示的内容
        value: {
            type: [Number, String],
            default: ''
        },
        // 是否显示
        show: {
            type: Boolean,
            default: true
        },
        // 最大值,超过最大值会显示 '{max}+'
        max: {
            type: [Number, String],
            default: 999
        },
        // 主题类型,error|warning|success|primary
        type: {
            type: [String,undefined,null],
            default: 'error'
        },
        // 当数值为 0 时,是否展示 Badge
        showZero: {
            type: Boolean,
            default: false
        },
        // 背景颜色,优先级比type高,如设置,type参数会失效
        bgColor: {
            type: [String, null],
            default: null
        },
        // 字体颜色
        color: {
            type: [String, null],
            default: null
        },
        // 徽标形状,circle-四角均为圆角,horn-左下角为直角
        shape: {
            type: [String,undefined,null],
            default: 'circle'
        },
        // 设置数字的显示方式,overflow|ellipsis|limit
        // overflow会根据max字段判断,超出显示`${max}+`
        // ellipsis会根据max判断,超出显示`${max}...`
        // limit会依据1000作为判断条件,超出1000,显示`${value/1000}K`,比如2.2k、3.34w,最多保留2位小数
        numberType: {
            type: [String,undefined,null],
            default: 'overflow'
        },
        // 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,absolute为true时有效
        offset: {
            type: Array,
            default: () => []
        },
        // 是否反转背景和字体颜色
        inverted: {
            type: Boolean,
            default: false
        },
        // 是否绝对定位
        absolute: {
            type: Boolean,
            default: false
        },
        ...uni.$uv?.props?.badge
    }
}
ledApp/uni_modules/uv-badge/components/uv-badge/uv-badge.vue
New file
@@ -0,0 +1,176 @@
<template>
    <text
        v-if="show && ((Number(value) === 0 ? showZero : true) || isDot)"
        :class="[isDot ? 'uv-badge--dot' : 'uv-badge--not-dot', inverted && 'uv-badge--inverted', shape === 'horn' && 'uv-badge--horn', `uv-badge--${propsType}${inverted ? '--inverted' : ''}`]"
        :style="[$uv.addStyle(customStyle), badgeStyle]"
        class="uv-badge"
    >{{ isDot ? '' :showValue }}</text>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * badge 徽标数
     * @description 该组件一般用于图标右上角显示未读的消息数量,提示用户点击,有圆点和圆包含文字两种形式。
     * @tutorial https://www.uvui.cn/components/badge.html
     *
     * @property {Boolean}          isDot       是否显示圆点 (默认 false )
     * @property {String | Number}  value       显示的内容
     * @property {Boolean}          show        是否显示 (默认 true )
     * @property {String | Number}  max         最大值,超过最大值会显示 '{max}+'  (默认999)
     * @property {String}           type        主题类型,error|warning|success|primary (默认 'error' )
     * @property {Boolean}          showZero    当数值为 0 时,是否展示 Badge (默认 false )
     * @property {String}           bgColor     背景颜色,优先级比type高,如设置,type参数会失效
     * @property {String}           color       字体颜色 (默认 '#ffffff' )
     * @property {String}           shape       徽标形状,circle-四角均为圆角,horn-左下角为直角 (默认 'circle' )
     * @property {String}           numberType  设置数字的显示方式,overflow|ellipsis|limit  (默认 'overflow' )
     * @property {Array}}           offset      设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,absolute为true时有效
     * @property {Boolean}          inverted    是否反转背景和字体颜色(默认 false )
     * @property {Boolean}          absolute    是否绝对定位(默认 false )
     * @property {Object}           customStyle 定义需要用到的外部样式
     * @example <uv-badge :type="type" :count="count"></uv-badge>
     */
    export default {
        name: 'uv-badge',
        mixins: [mpMixin, mixin, props],
        computed: {
            // 是否将badge中心与父组件右上角重合
            boxStyle() {
                let style = {};
                return style;
            },
            // 整个组件的样式
            badgeStyle() {
                const style = {}
                if(this.color) {
                    style.color = this.color
                }
                if (this.bgColor && !this.inverted) {
                    style.backgroundColor = this.bgColor
                }
                if (this.absolute) {
                    style.position = 'absolute'
                    // 如果有设置offset参数
                    if(this.offset.length) {
                        // top和right分为为offset的第一个和第二个值,如果没有第二个值,则right等于top
                        const top = this.offset[0]
                        const right = this.offset[1] || top
                        style.top = this.$uv.addUnit(top)
                        style.right = this.$uv.addUnit(right)
                    }
                }
                return style
            },
            showValue() {
                switch (this.numberType) {
                    case "overflow":
                        return Number(this.value) > Number(this.max) ? this.max + "+" : this.value
                        break;
                    case "ellipsis":
                        return Number(this.value) > Number(this.max) ? "..." : this.value
                        break;
                    case "limit":
                        return Number(this.value) > 999 ? Number(this.value) >= 9999 ?
                            Math.floor(this.value / 1e4 * 100) / 100 + "w" : Math.floor(this.value /
                                1e3 * 100) / 100 + "k" : this.value
                        break;
                    default:
                        return Number(this.value)
                }
            },
            propsType(){
                return this.type || 'error'
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    $uv-badge-primary: $uv-primary !default;
    $uv-badge-error: $uv-error !default;
    $uv-badge-success: $uv-success !default;
    $uv-badge-info: $uv-info !default;
    $uv-badge-warning: $uv-warning !default;
    $uv-badge-dot-radius: 100px !default;
    $uv-badge-dot-size: 8px !default;
    $uv-badge-dot-right: 4px !default;
    $uv-badge-dot-top: 0 !default;
    $uv-badge-text-font-size: 11px !default;
    $uv-badge-text-right: 10px !default;
    $uv-badge-text-padding: 2px 5px !default;
    $uv-badge-text-align: center !default;
    $uv-badge-text-color: #FFFFFF !default;
    .uv-badge {
        border-top-right-radius: $uv-badge-dot-radius;
        border-top-left-radius: $uv-badge-dot-radius;
        border-bottom-left-radius: $uv-badge-dot-radius;
        border-bottom-right-radius: $uv-badge-dot-radius;
        @include flex;
        line-height: $uv-badge-text-font-size;
        text-align: $uv-badge-text-align;
        font-size: $uv-badge-text-font-size;
        color: $uv-badge-text-color;
        &--dot {
            height: $uv-badge-dot-size;
            width: $uv-badge-dot-size;
        }
        &--inverted {
            font-size: 13px;
        }
        &--not-dot {
            padding: $uv-badge-text-padding;
        }
        &--horn {
            border-bottom-left-radius: 0;
        }
        &--primary {
            background-color: $uv-badge-primary;
        }
        &--primary--inverted {
            color: $uv-badge-primary;
        }
        &--error {
            background-color: $uv-badge-error;
        }
        &--error--inverted {
            color: $uv-badge-error;
        }
        &--success {
            background-color: $uv-badge-success;
        }
        &--success--inverted {
            color: $uv-badge-success;
        }
        &--info {
            background-color: $uv-badge-info;
        }
        &--info--inverted {
            color: $uv-badge-info;
        }
        &--warning {
            background-color: $uv-badge-warning;
        }
        &--warning--inverted {
            color: $uv-badge-warning;
        }
    }
</style>
ledApp/uni_modules/uv-badge/package.json
New file
@@ -0,0 +1,87 @@
{
    "id": "uv-badge",
    "displayName": "uv-badge 徽标数,数字角标 全面兼容小程序、nvue、vue2、vue3等多端",
    "version": "1.0.2",
    "description": "徽标数一般用于图标右上角显示未读的消息数量,提示用户点击,有圆点和圆包含文字两种形式。",
    "keywords": [
        "uv-badge",
        "uvui",
        "uv-ui",
        "徽标数",
        "数字角标"
    ],
    "repository": "",
    "engines": {
        "HBuilderX": "^3.1.0"
    },
    "dcloudext": {
        "type": "component-vue",
        "sale": {
            "regular": {
                "price": "0.00"
            },
            "sourcecode": {
                "price": "0.00"
            }
        },
        "contact": {
            "qq": ""
        },
        "declaration": {
            "ads": "无",
            "data": "插件不采集任何数据",
            "permissions": "无"
        },
        "npmurl": ""
    },
    "uni_modules": {
        "dependencies": [
            "uv-ui-tools"
        ],
        "encrypt": [],
        "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
    }
}
ledApp/uni_modules/uv-badge/readme.md
New file
@@ -0,0 +1,11 @@
## Badge 徽标数
> **组件名:uv-badge**
该组件一般用于图标右上角显示未读的消息数量,提示用户点击,有圆点和圆包含文字两种形式。
### <a href="https://www.uvui.cn/components/badge.html" target="_blank">查看文档</a>
### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)
#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-button/changelog.md
New file
@@ -0,0 +1,33 @@
## 1.0.15(2023-12-20)
1. 优化
## 1.0.14(2023-12-06)
1. 优化
## 1.0.13(2023-12-06)
1. 阻止事件冒泡处理
## 1.0.12(2023-10-19)
1. 增加后置插槽
## 1.0.11(2023-09-21)
1. 修复通过customStyle修改按钮宽度,组件中最外层节点不改变的问题
## 1.0.10(2023-09-15)
1. 按钮支持open-type="agreePrivacyAuthorization"
## 1.0.9(2023-09-11)
1. 增加参数iconSize,用于控制图标的大小
## 1.0.8(2023-09-10)
1. 修复多个按钮在一行宽度不正常的BUG
## 1.0.7(2023-09-07)
1. 修复warning颜色对应错误的BUG
## 1.0.6(2023-07-25)
1. 增加customTextStyle属性,方便自定义文字样式
## 1.0.5(2023-07-20)
1. 解决微信小程序动态设置hover-class点击态不消失的BUG
## 1.0.4(2023-06-29)
1. 修改上次更新出现nvue报错异常
## 1.0.3(2023-06-28)
 修复:设置open-type="chooseAvatar"等值不生效的BUG
## 1.0.2(2023-06-01)
1. 修复按钮点击触发两次的BUG
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-button 按钮
ledApp/uni_modules/uv-button/components/uv-button/nvue.scss
New file
@@ -0,0 +1,46 @@
$uv-button-active-opacity:0.75 !default;
$uv-button-loading-text-margin-left:4px !default;
$uv-button-text-color: #FFFFFF !default;
$uv-button-text-plain-error-color:$uv-error !default;
$uv-button-text-plain-warning-color:$uv-warning !default;
$uv-button-text-plain-success-color:$uv-success !default;
$uv-button-text-plain-info-color:$uv-info !default;
$uv-button-text-plain-primary-color:$uv-primary !default;
.uv-button {
    &--active {
        opacity: $uv-button-active-opacity;
    }
    &--active--plain {
        background-color: rgb(217, 217, 217);
    }
    &__loading-text {
        margin-left:$uv-button-loading-text-margin-left;
    }
    &__text,
    &__loading-text {
        color:$uv-button-text-color;
    }
    &__text--plain--error {
        color:$uv-button-text-plain-error-color;
    }
    &__text--plain--warning {
        color:$uv-button-text-plain-warning-color;
    }
    &__text--plain--success{
        color:$uv-button-text-plain-success-color;
    }
    &__text--plain--info {
        color:$uv-button-text-plain-info-color;
    }
    &__text--plain--primary {
        color:$uv-button-text-plain-primary-color;
    }
}
ledApp/uni_modules/uv-button/components/uv-button/props.js
New file
@@ -0,0 +1,163 @@
export default {
    props: {
        // 是否细边框
        hairline: {
            type: Boolean,
            default: true
        },
        // 按钮的预置样式,info,primary,error,warning,success
        type: {
            type: String,
            default: 'info'
        },
        // 按钮尺寸,large,normal,small,mini
        size: {
            type: String,
            default: 'normal'
        },
        // 按钮形状,circle(两边为半圆),square(带圆角)
        shape: {
            type: String,
            default: 'square'
        },
        // 按钮是否镂空
        plain: {
            type: Boolean,
            default: false
        },
        // 是否禁止状态
        disabled: {
            type: Boolean,
            default: false
        },
        // 是否加载中
        loading: {
            type: Boolean,
            default: false
        },
        // 加载中提示文字
        loadingText: {
            type: [String, Number],
            default: ''
        },
        // 加载状态图标类型
        loadingMode: {
            type: String,
            default: 'spinner'
        },
        // 加载图标大小
        loadingSize: {
            type: [String, Number],
            default: 14
        },
        // 开放能力,具体请看uniapp稳定关于button组件部分说明
        // https://uniapp.dcloud.io/component/button
        openType: {
            type: String,
            default: ''
        },
        // 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
        // 取值为submit(提交表单),reset(重置表单)
        formType: {
            type: String,
            default: ''
        },
        // 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效
        // 只微信小程序、QQ小程序有效
        appParameter: {
            type: String,
            default: ''
        },
        // 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效
        hoverStopPropagation: {
            type: Boolean,
            default: true
        },
        // 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文。只微信小程序有效
        lang: {
            type: String,
            default: 'en'
        },
        // 会话来源,open-type="contact"时有效。只微信小程序有效
        sessionFrom: {
            type: String,
            default: ''
        },
        // 会话内消息卡片标题,open-type="contact"时有效
        // 默认当前标题,只微信小程序有效
        sendMessageTitle: {
            type: String,
            default: ''
        },
        // 会话内消息卡片点击跳转小程序路径,open-type="contact"时有效
        // 默认当前分享路径,只微信小程序有效
        sendMessagePath: {
            type: String,
            default: ''
        },
        // 会话内消息卡片图片,open-type="contact"时有效
        // 默认当前页面截图,只微信小程序有效
        sendMessageImg: {
            type: String,
            default: ''
        },
        // 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,
        // 用户点击后可以快速发送小程序消息,open-type="contact"时有效
        showMessageCard: {
            type: Boolean,
            default: true
        },
        // 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
        dataName: {
            type: String,
            default: ''
        },
        // 节流,一定时间内只能触发一次
        throttleTime: {
            type: [String, Number],
            default: 0
        },
        // 按住后多久出现点击态,单位毫秒
        hoverStartTime: {
            type: [String, Number],
            default: 0
        },
        // 手指松开后点击态保留时间,单位毫秒
        hoverStayTime: {
            type: [String, Number],
            default: 200
        },
        // 按钮文字,之所以通过props传入,是因为slot传入的话
        // nvue中无法控制文字的样式
        text: {
            type: [String, Number],
            default: ''
        },
        // 按钮图标
        icon: {
            type: String,
            default: ''
        },
        // 按钮图标大小
        iconSize: {
            type: [String, Number],
            default: ''
        },
        // 按钮图标颜色
        iconColor: {
            type: String,
            default: '#000000'
        },
        // 按钮颜色,支持传入linear-gradient渐变色
        color: {
            type: String,
            default: ''
        },
        // 自定义按钮文本样式
        customTextStyle: {
            type: [Object,String],
            default: ''
        },
        ...uni.$uv?.props?.button
    }
}
ledApp/uni_modules/uv-button/components/uv-button/uv-button.vue
New file
@@ -0,0 +1,528 @@
<template>
    <view
        class="uv-button-wrapper"
        :style="[btnWrapperStyle]"
    >
    <!-- #ifndef APP-NVUE -->
        <!-- #ifdef MP -->
        <!-- 为了解决微信小程序动态设置hover-class点击态不消失的BUG -->
        <view class="uv-button-wrapper--dis" v-if="disabled || loading"></view>
        <button
          :hover-start-time="Number(hoverStartTime)"
          :hover-stay-time="Number(hoverStayTime)"
          :form-type="formType"
          :open-type="openType"
          :app-parameter="appParameter"
          :hover-stop-propagation="hoverStopPropagation"
          :send-message-title="sendMessageTitle"
          :send-message-path="sendMessagePath"
          :lang="lang"
          :data-name="dataName"
          :session-from="sessionFrom"
          :send-message-img="sendMessageImg"
          :show-message-card="showMessageCard"
          @getphonenumber="onGetPhoneNumber"
          @getuserinfo="onGetUserInfo"
          @error="onError"
          @opensetting="onOpenSetting"
          @launchapp="onLaunchApp"
            @contact="onContact"
            @chooseavatar="onChooseavatar"
            @agreeprivacyauthorization="onAgreeprivacyauthorization"
            @addgroupapp="onAddgroupapp"
            @chooseaddress="onChooseaddress"
            @subscribe="onSubscribe"
            @login="onLogin"
            @im="onIm"
          hover-class="uv-button--active"
          class="uv-button uv-reset-button"
          :style="[baseColor, $uv.addStyle(customStyle)]"
          @tap="clickHandler"
          :class="bemClass"
        >
        <!-- #endif -->
    <!-- #ifndef MP -->
    <button
      :hover-start-time="Number(hoverStartTime)"
      :hover-stay-time="Number(hoverStayTime)"
      :form-type="formType"
      :open-type="openType"
      :app-parameter="appParameter"
      :hover-stop-propagation="hoverStopPropagation"
      :send-message-title="sendMessageTitle"
      :send-message-path="sendMessagePath"
      :lang="lang"
      :data-name="dataName"
      :session-from="sessionFrom"
      :send-message-img="sendMessageImg"
      :show-message-card="showMessageCard"
      :hover-class="!disabled && !loading ? 'uv-button--active' : ''"
      class="uv-button uv-reset-button"
      :style="[baseColor, $uv.addStyle(customStyle)]"
      @tap="clickHandler"
      :class="bemClass"
    >
    <!-- #endif -->
      <template v-if="loading">
        <uv-loading-icon
          :mode="loadingMode"
          :size="loadingSize * 1.15"
          :color="loadingColor"
        ></uv-loading-icon>
          <text
            class="uv-button__loading-text"
            :style="[
                            { fontSize: textSize + 'px' },
                            $uv.addStyle(customTextStyle)
                        ]"
          >{{ loadingText || text }}</text>
      </template>
      <template v-else>
        <uv-icon
          v-if="icon"
          :name="icon"
          :color="iconColorCom"
          :size="getIconSize"
          :customStyle="{ marginRight: '2px' }"
        ></uv-icon>
        <slot>
          <text
            class="uv-button__text"
            :style="[
                            { fontSize: textSize + 'px' },
                            $uv.addStyle(customTextStyle)
                        ]"
            >{{ text }}</text>
        </slot>
                <slot name="suffix"></slot>
      </template>
    </button>
    <!-- #endif -->
    <!-- #ifdef APP-NVUE -->
    <view
      :hover-start-time="Number(hoverStartTime)"
      :hover-stay-time="Number(hoverStayTime)"
      class="uv-button"
      :hover-class="
        !disabled && !loading && !color && (plain || type === 'info')
          ? 'uv-button--active--plain'
          : !disabled && !loading && !plain
          ? 'uv-button--active'
          : ''
      "
      @tap="clickHandler"
      :class="bemClass"
      :style="[baseColor, $uv.addStyle(customStyle)]"
    >
      <template v-if="loading">
        <uv-loading-icon
          :mode="loadingMode"
          :size="loadingSize * 1.15"
          :color="loadingColor"
        ></uv-loading-icon>
        <text
          class="uv-button__loading-text"
          :style="[nvueTextStyle,$uv.addStyle(customTextStyle)]"
          :class="[plain && `uv-button__text--plain--${type}`]"
          >{{ loadingText || text }}</text>
      </template>
      <template v-else>
        <uv-icon
          v-if="icon"
          :name="icon"
          :color="iconColorCom"
          :size="getIconSize"
        ></uv-icon>
        <text
          class="uv-button__text"
          :style="[
            {
              marginLeft: icon ? '2px' : 0,
            },
            nvueTextStyle,
                        $uv.addStyle(customTextStyle)
          ]"
          :class="[plain && `uv-button__text--plain--${type}`]"
          >{{ text }}</text>
                <slot name="suffix"></slot>
      </template>
    </view>
    <!-- #endif -->
    </view>
</template>
<script>
import throttle from '@/uni_modules/uv-ui-tools/libs/function/throttle.js';
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
import button from '@/uni_modules/uv-ui-tools/libs/mixin/button.js'
import openType from '@/uni_modules/uv-ui-tools/libs/mixin/openType.js'
import props from "./props.js";
/**
 * button 按钮
 * @description Button 按钮
 * @tutorial https://www.uvui.cn/components/button.html
 * @property {Boolean}          hairline                是否显示按钮的细边框 (默认 true )
 * @property {String}           type                    按钮的预置样式,info,primary,error,warning,success (默认 'info' )
 * @property {String}           size                    按钮尺寸,large,normal,mini (默认 normal)
 * @property {String}           shape                   按钮形状,circle(两边为半圆),square(带圆角) (默认 'square' )
 * @property {Boolean}          plain                   按钮是否镂空,背景色透明 (默认 false)
 * @property {Boolean}          disabled                是否禁用 (默认 false)
 * @property {Boolean}          loading                 按钮名称前是否带 loading 图标(App-nvue 平台,在 ios 上为雪花,Android上为圆圈) (默认 false)
 * @property {String | Number}  loadingText             加载中提示文字
 * @property {String}           loadingMode             加载状态图标类型 (默认 'spinner' )
 * @property {String | Number}  loadingSize             加载图标大小 (默认 15 )
 * @property {String}           openType                开放能力,具体请看uniapp稳定关于button组件部分说明
 * @property {String}           formType                用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
 * @property {String}           appParameter            打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效 (注:只微信小程序、QQ小程序有效)
 * @property {Boolean}          hoverStopPropagation    指定是否阻止本节点的祖先节点出现点击态,微信小程序有效(默认 true )
 * @property {String}           lang                    指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文(默认 en )
 * @property {String}           sessionFrom             会话来源,openType="contact"时有效
 * @property {String}           sendMessageTitle        会话内消息卡片标题,openType="contact"时有效
 * @property {String}           sendMessagePath         会话内消息卡片点击跳转小程序路径,openType="contact"时有效
 * @property {String}           sendMessageImg          会话内消息卡片图片,openType="contact"时有效
 * @property {Boolean}          showMessageCard         是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,用户点击后可以快速发送小程序消息,openType="contact"时有效(默认false)
 * @property {String}           dataName                额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
 * @property {String | Number}  throttleTime            节流,一定时间内只能触发一次 (默认 0 )
 * @property {String | Number}  hoverStartTime          按住后多久出现点击态,单位毫秒 (默认 0 )
 * @property {String | Number}  hoverStayTime           手指松开后点击态保留时间,单位毫秒 (默认 200 )
 * @property {String | Number}  text                    按钮文字,之所以通过props传入,是因为slot传入的话(注:nvue中无法控制文字的样式)
 * @property {String}           icon                    按钮图标
 * @property {String}           iconColor               按钮图标颜色
 * @property {String}           color                   按钮颜色,支持传入linear-gradient渐变色
 * @property {Object}           customStyle             定义需要用到的外部样式
 * @event {Function}    click           非禁止并且非加载中,才能点击
 * @event {Function}    getphonenumber  open-type="getPhoneNumber"时有效
 * @event {Function}    getuserinfo     用户点击该按钮时,会返回获取到的用户信息,从返回参数的detail中获取到的值同uni.getUserInfo
 * @event {Function}    error           当使用开放能力时,发生错误的回调
 * @event {Function}    opensetting     在打开授权设置页并关闭后回调
 * @event {Function}    launchapp       打开 APP 成功的回调
 * @example <uv-button>月落</uv-button>
 */
export default {
        name: "uv-button",
        // #ifdef MP
        mixins: [mpMixin, mixin, button, openType, props],
        // #endif
        // #ifndef MP
        mixins: [mpMixin, mixin, props],
        // #endif
        emits: ['click'],
        data() {
            return {};
        },
        computed: {
            // 生成bem风格的类名
            bemClass() {
                // this.bem为一个computed变量,在mixin中
                if (!this.color) {
                    return this.bem("button",
                        ["type", "shape", "size"],
                        ["disabled", "plain", "hairline"]);
                } else {
                    // 由于nvue的原因,在有color参数时,不需要传入type,否则会生成type相关的类型,影响最终的样式
                    return this.bem("button",
                        ["shape", "size"],
                        ["disabled", "plain", "hairline"]);
                }
            },
            loadingColor() {
                if (this.plain) {
                    // 如果有设置color值,则用color值,否则使用type主题颜色
                    return this.color ? this.color : '#3c9cff';
                }
                if (this.type === "info") {
                    return "#c9c9c9";
                }
                return "rgb(200, 200, 200)";
            },
            iconColorCom() {
                // 如果是镂空状态,设置了color就用color值,否则使用主题颜色,
                // uv-icon的color能接受一个主题颜色的值
                if (this.iconColor) return this.iconColor;
                if (this.plain) {
                    return this.color ? this.color : this.type;
                } else {
                    return this.type === "info" ? "#000000" : "#ffffff";
                }
            },
            baseColor() {
                let style = {};
                if (this.color) {
                    // 针对自定义了color颜色的情况,镂空状态下,就是用自定义的颜色
                    style.color = this.plain ? this.color : "white";
                    if (!this.plain) {
                        // 非镂空,背景色使用自定义的颜色
                        style["background-color"] = this.color;
                    }
                    if (this.color.indexOf("gradient") !== -1) {
                        // 如果自定义的颜色为渐变色,不显示边框,以及通过backgroundImage设置渐变色
                        // weex文档说明可以写borderWidth的形式,为什么这里需要分开写?
                        // 因为weex是阿里巴巴为了部门业绩考核而做的你懂的东西,所以需要这么写才有效
                        style.borderTopWidth = 0;
                        style.borderRightWidth = 0;
                        style.borderBottomWidth = 0;
                        style.borderLeftWidth = 0;
                        if (!this.plain) {
                            style.backgroundImage = this.color;
                        }
                    } else {
                        // 非渐变色,则设置边框相关的属性
                        style.borderColor = this.color;
                        style.borderWidth = "1px";
                        style.borderStyle = "solid";
                    }
                }
                return style;
            },
            // nvue版本按钮的字体不会继承父组件的颜色,需要对每一个text组件进行单独的设置
            nvueTextStyle() {
                let style = {};
                // 针对自定义了color颜色的情况,镂空状态下,就是用自定义的颜色
                if (this.type === "info") {
                    style.color = "#323233";
                }
                if (this.color) {
                    style.color = this.plain ? this.color : "white";
                }
                style.fontSize = this.textSize + "px";
                return style;
            },
            // 字体大小
            textSize() {
                let fontSize = 14,
                    { size } = this;
                if (size === "large") fontSize = 16;
                if (size === "normal") fontSize = 14;
                if (size === "small") fontSize = 12;
                if (size === "mini") fontSize = 10;
                return fontSize;
            },
            // 设置图标大小
            getIconSize() {
                const size = this.iconSize ? this.iconSize : this.textSize * 1.35;
                return this.$uv.addUnit(size);
            },
            // 设置外层盒子的宽度,其他样式不需要
            btnWrapperStyle() {
                const style = {};
                const customStyle = this.$uv.addStyle(this.customStyle);
                if(customStyle.width) style.width = customStyle.width;
                return style;
            }
        },
        methods: {
            clickHandler() {
                // 非禁止并且非加载中,才能点击
                if (!this.disabled && !this.loading) {
                    // 进行节流控制,每this.throttle毫秒内,只在开始处执行
                    throttle(() => {
                        this.$emit("click");
                    }, this.throttleTime);
                }
            }
        }
    }
</script>
<style lang="scss" scoped>
$show-reset-button: 1;
@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
/* #ifndef APP-NVUE */
@import "./vue.scss";
/* #endif */
/* #ifdef APP-NVUE */
@import "./nvue.scss";
/* #endif */
$uv-button-uv-button-height: 40px !default;
$uv-button-text-font-size: 15px !default;
$uv-button-loading-text-font-size: 15px !default;
$uv-button-loading-text-margin-left: 4px !default;
$uv-button-large-width: 100% !default;
$uv-button-large-height: 50px !default;
$uv-button-normal-padding: 0 12px !default;
$uv-button-large-padding: 0 15px !default;
$uv-button-normal-font-size: 14px !default;
$uv-button-small-min-width: 60px !default;
$uv-button-small-height: 30px !default;
$uv-button-small-padding: 0px 8px !default;
$uv-button-mini-padding: 0px 8px !default;
$uv-button-small-font-size: 12px !default;
$uv-button-mini-height: 22px !default;
$uv-button-mini-font-size: 10px !default;
$uv-button-mini-min-width: 50px !default;
$uv-button-disabled-opacity: 0.5 !default;
$uv-button-info-color: #323233 !default;
$uv-button-info-background-color: #fff !default;
$uv-button-info-border-color: #ebedf0 !default;
$uv-button-info-border-width: 1px !default;
$uv-button-info-border-style: solid !default;
$uv-button-success-color: #fff !default;
$uv-button-success-background-color: $uv-success !default;
$uv-button-success-border-color: $uv-button-success-background-color !default;
$uv-button-success-border-width: 1px !default;
$uv-button-success-border-style: solid !default;
$uv-button-primary-color: #fff !default;
$uv-button-primary-background-color: $uv-primary !default;
$uv-button-primary-border-color: $uv-button-primary-background-color !default;
$uv-button-primary-border-width: 1px !default;
$uv-button-primary-border-style: solid !default;
$uv-button-error-color: #fff !default;
$uv-button-error-background-color: $uv-error !default;
$uv-button-error-border-color: $uv-button-error-background-color !default;
$uv-button-error-border-width: 1px !default;
$uv-button-error-border-style: solid !default;
$uv-button-warning-color: #fff !default;
$uv-button-warning-background-color: $uv-warning !default;
$uv-button-warning-border-color: $uv-button-warning-background-color !default;
$uv-button-warning-border-width: 1px !default;
$uv-button-warning-border-style: solid !default;
$uv-button-block-width: 100% !default;
$uv-button-circle-border-top-right-radius: 100px !default;
$uv-button-circle-border-top-left-radius: 100px !default;
$uv-button-circle-border-bottom-left-radius: 100px !default;
$uv-button-circle-border-bottom-right-radius: 100px !default;
$uv-button-square-border-top-right-radius: 3px !default;
$uv-button-square-border-top-left-radius: 3px !default;
$uv-button-square-border-bottom-left-radius: 3px !default;
$uv-button-square-border-bottom-right-radius: 3px !default;
$uv-button-icon-min-width: 1em !default;
$uv-button-plain-background-color: #fff !default;
$uv-button-hairline-border-width: 0.5px !default;
.uv-button {
    height: $uv-button-uv-button-height;
    position: relative;
    align-items: center;
    justify-content: center;
    @include flex;
    /* #ifndef APP-NVUE */
    box-sizing: border-box;
    /* #endif */
    flex-direction: row;
    &__text {
        font-size: $uv-button-text-font-size;
    }
    &__loading-text {
        font-size: $uv-button-loading-text-font-size;
        margin-left: $uv-button-loading-text-margin-left;
    }
    &--large {
        /* #ifndef APP-NVUE */
        width: $uv-button-large-width;
        /* #endif */
        height: $uv-button-large-height;
        padding: $uv-button-large-padding;
    }
    &--normal {
        padding: $uv-button-normal-padding;
        font-size: $uv-button-normal-font-size;
    }
    &--small {
        /* #ifndef APP-NVUE */
        min-width: $uv-button-small-min-width;
        /* #endif */
        height: $uv-button-small-height;
        padding: $uv-button-small-padding;
        font-size: $uv-button-small-font-size;
    }
    &--mini {
        height: $uv-button-mini-height;
        font-size: $uv-button-mini-font-size;
        /* #ifndef APP-NVUE */
        min-width: $uv-button-mini-min-width;
        /* #endif */
        padding: $uv-button-mini-padding;
    }
    &--disabled {
        opacity: $uv-button-disabled-opacity;
    }
    &--info {
        color: $uv-button-info-color;
        background-color: $uv-button-info-background-color;
        border-color: $uv-button-info-border-color;
        border-width: $uv-button-info-border-width;
        border-style: $uv-button-info-border-style;
    }
    &--success {
        color: $uv-button-success-color;
        background-color: $uv-button-success-background-color;
        border-color: $uv-button-success-border-color;
        border-width: $uv-button-success-border-width;
        border-style: $uv-button-success-border-style;
    }
    &--primary {
        color: $uv-button-primary-color;
        background-color: $uv-button-primary-background-color;
        border-color: $uv-button-primary-border-color;
        border-width: $uv-button-primary-border-width;
        border-style: $uv-button-primary-border-style;
    }
    &--error {
        color: $uv-button-error-color;
        background-color: $uv-button-error-background-color;
        border-color: $uv-button-error-border-color;
        border-width: $uv-button-error-border-width;
        border-style: $uv-button-error-border-style;
    }
    &--warning {
        color: $uv-button-warning-color;
        background-color: $uv-button-warning-background-color;
        border-color: $uv-button-warning-border-color;
        border-width: $uv-button-warning-border-width;
        border-style: $uv-button-warning-border-style;
    }
    &--block {
        @include flex;
        width: $uv-button-block-width;
    }
    &--circle {
        border-top-right-radius: $uv-button-circle-border-top-right-radius;
        border-top-left-radius: $uv-button-circle-border-top-left-radius;
        border-bottom-left-radius: $uv-button-circle-border-bottom-left-radius;
        border-bottom-right-radius: $uv-button-circle-border-bottom-right-radius;
    }
    &--square {
        border-bottom-left-radius: $uv-button-square-border-top-right-radius;
        border-bottom-right-radius: $uv-button-square-border-top-left-radius;
        border-top-left-radius: $uv-button-square-border-bottom-left-radius;
        border-top-right-radius: $uv-button-square-border-bottom-right-radius;
    }
    &__icon {
        /* #ifndef APP-NVUE */
        min-width: $uv-button-icon-min-width;
        line-height: inherit !important;
        vertical-align: top;
        /* #endif */
    }
    &--plain {
        background-color: $uv-button-plain-background-color;
    }
    &--hairline {
        border-width: $uv-button-hairline-border-width !important;
    }
}
</style>
ledApp/uni_modules/uv-button/components/uv-button/vue.scss
New file
@@ -0,0 +1,93 @@
@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
// nvue下hover-class无效
$uv-button-before-top:50% !default;
$uv-button-before-left:50% !default;
$uv-button-before-width:100% !default;
$uv-button-before-height:100% !default;
$uv-button-before-transform:translate(-50%, -50%) !default;
$uv-button-before-opacity:0 !default;
$uv-button-before-background-color:#000 !default;
$uv-button-before-border-color:#000 !default;
$uv-button-active-before-opacity:.15 !default;
$uv-button-icon-margin-left:4px !default;
$uv-button-plain-uv-button-info-color:$uv-info;
$uv-button-plain-uv-button-success-color:$uv-success;
$uv-button-plain-uv-button-error-color:$uv-error;
$uv-button-plain-uv-button-warning-color:$uv-warning;
.uv-button-wrapper {
    position: relative;
    &--dis {
        position: absolute;
        left: 0;
        top: 0;
        right: 0;
        bottom: 0;
        z-index: 9;
    }
}
.uv-button {
    width: 100%;
    &__text {
        white-space: nowrap;
        line-height: 1;
    }
    &:before {
        position: absolute;
        top:$uv-button-before-top;
        left:$uv-button-before-left;
        width:$uv-button-before-width;
        height:$uv-button-before-height;
        border: inherit;
        border-radius: inherit;
        transform:$uv-button-before-transform;
        opacity:$uv-button-before-opacity;
        content: " ";
        background-color:$uv-button-before-background-color;
        border-color:$uv-button-before-border-color;
    }
    &--active {
        &:before {
            opacity: .15
        }
    }
    &__icon+&__text:not(:empty),
    &__loading-text {
        margin-left:$uv-button-icon-margin-left;
    }
    &--plain {
        &.uv-button--primary {
            color: $uv-primary;
        }
    }
    &--plain {
        &.uv-button--info {
            color:$uv-button-plain-uv-button-info-color;
        }
    }
    &--plain {
        &.uv-button--success {
            color:$uv-button-plain-uv-button-success-color;
        }
    }
    &--plain {
        &.uv-button--error {
            color:$uv-button-plain-uv-button-error-color;
        }
    }
    &--plain {
        &.uv-button--warning {
            color:$uv-button-plain-uv-button-warning-color;
        }
    }
}
ledApp/uni_modules/uv-button/package.json
New file
@@ -0,0 +1,89 @@
{
    "id": "uv-button",
    "displayName": "uv-button 按钮 全面兼容vue3+2、app、h5、小程序等多端",
    "version": "1.0.15",
    "description": "按钮组件内部实现以uni-app的button组件为基础,进行二次封装,灵活配置,功能齐全,兼容全端。",
    "keywords": [
        "uv-button",
        "uvui",
        "uv-ui",
        "button",
        "按钮"
    ],
    "repository": "",
    "engines": {
        "HBuilderX": "^3.1.0"
    },
    "dcloudext": {
        "type": "component-vue",
        "sale": {
            "regular": {
                "price": "0.00"
            },
            "sourcecode": {
                "price": "0.00"
            }
        },
        "contact": {
            "qq": ""
        },
        "declaration": {
            "ads": "无",
            "data": "插件不采集任何数据",
            "permissions": "无"
        },
        "npmurl": ""
    },
    "uni_modules": {
        "dependencies": [
            "uv-ui-tools",
            "uv-loading-icon",
            "uv-icon"
        ],
        "encrypt": [],
        "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
    }
}
ledApp/uni_modules/uv-button/readme.md
New file
@@ -0,0 +1,19 @@
## Button 按钮
> **组件名:uv-button**
该组件内部实现以`uni-app`的`button`组件为基础,进行二次封装,灵活配置,功能齐全,兼容全端。灵活配置,内置状态设置,开箱即用。
# <a href="https://www.uvui.cn/components/button.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>(请不要 下载插件ZIP)</small>
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
</a>
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-calendar/changelog.md
New file
@@ -0,0 +1,16 @@
## 1.0.6(2023-11-03)
1. **该版本不再维护**,推荐使用新版本[https://ext.dcloud.net.cn/plugin?name=uv-calendars](https://ext.dcloud.net.cn/plugin?name=uv-calendars)
## 1.0.5(2023-07-02)
uv-calendar  由于弹出层uv-popup的修改,打开和关闭方法更改,详情参考文档:https://www.uvui.cn/components/calendar.html
## 1.0.4(2023-06-15)
1. formatter格式化中增加topInfo参数
## 1.0.3(2023-06-08)
1. 增加点击日期change回调
2. 优化
## 1.0.2(2023-06-05)
1. 修改多个时间选择的时候存在反选的BUG
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-calendar 日历
ledApp/uni_modules/uv-calendar/components/uv-calendar/calendar.js
New file
@@ -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
ledApp/uni_modules/uv-calendar/components/uv-calendar/header.vue
New file
@@ -0,0 +1,104 @@
<template>
    <view class="uv-calendar-header uv-border-bottom">
        <text
            class="uv-calendar-header__title"
            v-if="showTitle"
        >{{ title }}</text>
        <text
            class="uv-calendar-header__subtitle"
            v-if="showSubtitle"
        >{{ subtitle }}</text>
        <view class="uv-calendar-header__weekdays">
            <text class="uv-calendar-header__weekdays__weekday">一</text>
            <text class="uv-calendar-header__weekdays__weekday">二</text>
            <text class="uv-calendar-header__weekdays__weekday">三</text>
            <text class="uv-calendar-header__weekdays__weekday">四</text>
            <text class="uv-calendar-header__weekdays__weekday">五</text>
            <text class="uv-calendar-header__weekdays__weekday">六</text>
            <text class="uv-calendar-header__weekdays__weekday">日</text>
        </view>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    export default {
        name: 'uv-calendar-header',
        mixins: [mpMixin, mixin],
        props: {
            // 标题
            title: {
                type: String,
                default: ''
            },
            // 副标题
            subtitle: {
                type: [String,null],
                default: ''
            },
            // 是否显示标题
            showTitle: {
                type: Boolean,
                default: true
            },
            // 是否显示副标题
            showSubtitle: {
                type: Boolean,
                default: true
            },
        },
        data() {
            return {
            }
        },
        methods: {
            name() {
            }
        },
    }
</script>
<style lang="scss" scoped>
    $show-border: 1;
    $show-border-bottom: 1;
    @import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    .uv-calendar-header {
        padding-bottom: 4px;
        &__title {
            font-size: 16px;
            color: $uv-main-color;
            text-align: center;
            height: 42px;
            line-height: 42px;
            font-weight: bold;
        }
        &__subtitle {
            font-size: 14px;
            color: $uv-main-color;
            height: 40px;
            text-align: center;
            line-height: 40px;
            font-weight: bold;
        }
        &__weekdays {
            @include flex;
            justify-content: space-between;
            &__weekday {
                font-size: 13px;
                color: $uv-main-color;
                line-height: 30px;
                flex: 1;
                text-align: center;
            }
        }
    }
</style>
ledApp/uni_modules/uv-calendar/components/uv-calendar/month.vue
New file
@@ -0,0 +1,616 @@
<template>
    <view class="uv-calendar-month-wrapper" ref="uv-calendar-month-wrapper">
        <view v-for="(item, index) in months" :key="index" :class="[`uv-calendar-month-${index}`]"
            :ref="`uv-calendar-month-${index}`" :id="`month-${index}`">
            <text v-if="index !== 0" class="uv-calendar-month__title">{{ item.year }}年{{ item.month }}月</text>
            <view class="uv-calendar-month__days">
                <view v-if="showMark" class="uv-calendar-month__days__month-mark-wrapper">
                    <text class="uv-calendar-month__days__month-mark-wrapper__text">{{ item.month }}</text>
                </view>
                <view class="uv-calendar-month__days__day" v-for="(item1, index1) in item.date" :key="index1"
                    :style="[dayStyle(index, index1, item1)]" @tap="clickHandler(index, index1, item1)"
                    :class="[item1.selected && 'uv-calendar-month__days__day__select--selected']">
                    <view class="uv-calendar-month__days__day__select" :style="[daySelectStyle(index, index1, item1)]">
                        <text v-if="getTopInfo(index, index1, item1)"
                        class="uv-calendar-month__days__day__select__top-info"
                        :class="[item1.disabled && 'uv-calendar-month__days__day__select__top-info--disabled']"
                        :style="[textStyle(item1)]"
                        >{{ getTopInfo(index, index1, item1) }}</text>
                        <text class="uv-calendar-month__days__day__select__info"
                            :class="[item1.disabled && 'uv-calendar-month__days__day__select__info--disabled']"
                            :style="[textStyle(item1)]">{{ item1.day }}</text>
                        <text v-if="getBottomInfo(index, index1, item1)"
                            class="uv-calendar-month__days__day__select__buttom-info"
                            :class="[item1.disabled && 'uv-calendar-month__days__day__select__buttom-info--disabled']"
                            :style="[textStyle(item1)]">{{ getBottomInfo(index, index1, item1) }}</text>
                        <text v-if="item1.dot" class="uv-calendar-month__days__day__select__dot"></text>
                    </view>
                </view>
            </view>
        </view>
    </view>
</template>
<script>
    // #ifdef APP-NVUE
    // 由于nvue不支持百分比单位,需要查询宽度来计算每个日期的宽度
    const dom = uni.requireNativePlugin('dom')
    // #endif
    import { colorGradient } from '@/uni_modules/uv-ui-tools/libs/function/colorGradient.js';
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import dayjs from '@/uni_modules/uv-ui-tools/libs/util/dayjs.js'
    export default {
        name: 'uv-calendar-month',
        emits:['monthSelected','updateMonthTop','change'],
        mixins: [mpMixin, mixin],
        props: {
            // 是否显示月份背景色
            showMark: {
                type: Boolean,
                default: true
            },
            // 主题色,对底部按钮和选中日期有效
            color: {
                type: String,
                default: '#3c9cff'
            },
            // 月份数据
            months: {
                type: Array,
                default: () => []
            },
            // 日期选择类型
            mode: {
                type: String,
                default: 'single'
            },
            // 日期行高
            rowHeight: {
                type: [String, Number],
                default: 58
            },
            // mode=multiple时,最多可选多少个日期
            maxCount: {
                type: [String, Number],
                default: Infinity
            },
            // mode=range时,第一个日期底部的提示文字
            startText: {
                type: String,
                default: '开始'
            },
            // mode=range时,最后一个日期底部的提示文字
            endText: {
                type: String,
                default: '结束'
            },
            // 默认选中的日期,mode为multiple或range是必须为数组格式
            defaultDate: {
                type: [Array, String, Date],
                default: null
            },
            // 最小的可选日期
            minDate: {
                type: [String, Number],
                default: 0
            },
            // 最大可选日期
            maxDate: {
                type: [String, Number],
                default: 0
            },
            // 如果没有设置maxDate,则往后推多少个月
            maxMonth: {
                type: [String, Number],
                default: 2
            },
            // 是否为只读状态,只读状态下禁止选择日期
            readonly: {
                type: Boolean,
                default: false
            },
            // 日期区间最多可选天数,默认无限制,mode = range时有效
            maxRange: {
                type: [Number, String],
                default: Infinity
            },
            // 范围选择超过最多可选天数时的提示文案,mode = range时有效
            rangePrompt: {
                type: String,
                default: ''
            },
            // 范围选择超过最多可选天数时,是否展示提示文案,mode = range时有效
            showRangePrompt: {
                type: Boolean,
                default: true
            },
            // 是否允许日期范围的起止时间为同一天,mode = range时有效
            allowSameDay: {
                type: Boolean,
                default: false
            }
        },
        data() {
            return {
                // 每个日期的宽度
                width: 0,
                // 当前选中的日期item
                item: {},
                selected: []
            }
        },
        watch: {
            selectedChange: {
                immediate: true,
                handler(n) {
                    this.setDefaultDate()
                }
            }
        },
        computed: {
            // 多个条件的变化,会引起选中日期的变化,这里统一管理监听
            selectedChange() {
                return [this.minDate, this.maxDate, this.defaultDate]
            },
            dayStyle(index1, index2, item) {
                return (index1, index2, item) => {
                    const style = {}
                    let week = item.week
                    // 不进行四舍五入的形式保留2位小数
                    const dayWidth = Number(parseFloat(this.width / 7).toFixed(3).slice(0, -1))
                    // 得出每个日期的宽度
                    // #ifdef APP-NVUE
                    style.width = this.$uv.addUnit(dayWidth)
                    // #endif
                    style.height = this.$uv.addUnit(this.rowHeight)
                    if (index2 === 0) {
                        // 获取当前为星期几,如果为0,则为星期天,减一为每月第一天时,需要向左偏移的item个数
                        week = (week === 0 ? 7 : week) - 1
                        style.marginLeft = this.$uv.addUnit(week * dayWidth)
                    }
                    if (this.mode === 'range') {
                        // 之所以需要这么写,是因为DCloud公司的iOS客户端的开发者能力有限导致的bug
                        style.paddingLeft = 0
                        style.paddingRight = 0
                        style.paddingBottom = 0
                        style.paddingTop = 0
                    }
                    return style
                }
            },
            daySelectStyle() {
                return (index1, index2, item) => {
                    let date = dayjs(item.date).format("YYYY-MM-DD"),
                        style = {}
                    // 判断date是否在selected数组中,因为月份可能会需要补0,所以使用dateSame判断,而不用数组的includes判断
                    if (this.selected.some(item => this.dateSame(item, date))) {
                        style.backgroundColor = this.color
                    }
                    if (this.mode === 'single') {
                        if (date === this.selected[0]) {
                            // 因为需要对nvue的兼容,只能这么写,无法缩写,也无法通过类名控制等等
                            style.borderTopLeftRadius = '3px'
                            style.borderBottomLeftRadius = '3px'
                            style.borderTopRightRadius = '3px'
                            style.borderBottomRightRadius = '3px'
                        }
                    } else if (this.mode === 'range') {
                        if (this.selected.length >= 2) {
                            const len = this.selected.length - 1
                            // 第一个日期设置左上角和左下角的圆角
                            if (this.dateSame(date, this.selected[0])) {
                                style.borderTopLeftRadius = '3px'
                                style.borderBottomLeftRadius = '3px'
                            }
                            // 最后一个日期设置右上角和右下角的圆角
                            if (this.dateSame(date, this.selected[len])) {
                                style.borderTopRightRadius = '3px'
                                style.borderBottomRightRadius = '3px'
                            }
                            // 处于第一和最后一个之间的日期,背景色设置为浅色,通过将对应颜色进行等分,再取其尾部的颜色值
                            if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this
                                    .selected[len]))) {
                                style.backgroundColor = colorGradient(this.color, '#ffffff', 100)[90]
                                // 增加一个透明度,让范围区间的背景色也能看到底部的mark水印字符
                                style.opacity = 0.7
                            }
                        } else if (this.selected.length === 1) {
                            // 之所以需要这么写,是因为DCloud公司的iOS客户端的开发者能力有限导致的bug
                            // 进行还原操作,否则在nvue的iOS,uni-app有bug,会导致诡异的表现
                            style.borderTopLeftRadius = '3px'
                            style.borderBottomLeftRadius = '3px'
                        }
                    } else {
                        if (this.selected.some(item => this.dateSame(item, date))) {
                            style.borderTopLeftRadius = '3px'
                            style.borderBottomLeftRadius = '3px'
                            style.borderTopRightRadius = '3px'
                            style.borderBottomRightRadius = '3px'
                        }
                    }
                    return style
                }
            },
            // 某个日期是否被选中
            textStyle() {
                return (item) => {
                    const date = dayjs(item.date).format("YYYY-MM-DD"),
                        style = {}
                    // 选中的日期,提示文字设置白色
                    if (this.selected.some(item => this.dateSame(item, date))) {
                        style.color = '#ffffff'
                    }
                    if (this.mode === 'range') {
                        const len = this.selected.length - 1
                        // 如果是范围选择模式,第一个和最后一个之间的日期,文字颜色设置为高亮的主题色
                        if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this
                                .selected[len]))) {
                            style.color = this.color
                        }
                    }
                    return style
                }
            },
            // 获取顶部的提示文字
            getTopInfo() {
                return (index1, index2, item) => {
                    return item.topInfo;
                }
            },
            // 获取底部的提示文字
            getBottomInfo() {
                return (index1, index2, item) => {
                    const date = dayjs(item.date).format("YYYY-MM-DD")
                    const bottomInfo = item.bottomInfo
                    // 当为日期范围模式时,且选择的日期个数大于0时
                    if (this.mode === 'range' && this.selected.length > 0) {
                        if (this.selected.length === 1) {
                            // 选择了一个日期时,如果当前日期为数组中的第一个日期,则显示底部文字为“开始”
                            if (this.dateSame(date, this.selected[0])) return this.startText
                            else return bottomInfo
                        } else {
                            const len = this.selected.length - 1
                            // 如果数组中的日期大于2个时,第一个和最后一个显示为开始和结束日期
                            if (this.dateSame(date, this.selected[0]) && this.dateSame(date, this.selected[1]) &&
                                len === 1) {
                                // 如果长度为2,且第一个等于第二个日期,则提示语放在同一个item中
                                return `${this.startText}/${this.endText}`
                            } else if (this.dateSame(date, this.selected[0])) {
                                return this.startText
                            } else if (this.dateSame(date, this.selected[len])) {
                                return this.endText
                            } else {
                                return bottomInfo
                            }
                        }
                    } else {
                        return bottomInfo
                    }
                }
            }
        },
        mounted() {
            this.init()
        },
        methods: {
            init() {
                // 初始化默认选中
                this.$emit('monthSelected', this.selected)
                this.$nextTick(() => {
                    // 这里需要另一个延时,因为获取宽度后,会进行月份数据渲染,只有渲染完成之后,才有真正的高度
                    // 因为nvue下,$nextTick并不是100%可靠的
                    this.$uv.sleep(10).then(() => {
                        this.getWrapperWidth()
                        this.getMonthRect()
                    })
                })
            },
            // 判断两个日期是否相等
            dateSame(date1, date2) {
                return dayjs(date1).isSame(dayjs(date2))
            },
            // 获取月份数据区域的宽度,因为nvue不支持百分比,所以无法通过css设置每个日期item的宽度
            getWrapperWidth() {
                // #ifdef APP-NVUE
                dom.getComponentRect(this.$refs['uv-calendar-month-wrapper'], res => {
                    this.width = res.size.width
                })
                // #endif
                // #ifndef APP-NVUE
                this.$uvGetRect('.uv-calendar-month-wrapper').then(size => {
                    this.width = size.width
                })
                // #endif
            },
            getMonthRect() {
                // 获取每个月份数据的尺寸,用于父组件在scroll-view滚动事件中,监听当前滚动到了第几个月份
                const promiseAllArr = this.months.map((item, index) => this.getMonthRectByPromise(
                    `uv-calendar-month-${index}`))
                // 一次性返回
                Promise.all(promiseAllArr).then(
                    sizes => {
                        let height = 1
                        const topArr = []
                        for (let i = 0; i < this.months.length; i++) {
                            // 添加到months数组中,供scroll-view滚动事件中,判断当前滚动到哪个月份
                            topArr[i] = height
                            height += sizes[i].height
                        }
                        // 由于微信下,无法通过this.months[i].top的形式(引用类型)去修改父组件的month的top值,所以使用事件形式对外发出
                        this.$emit('updateMonthTop', topArr)
                    })
            },
            // 获取每个月份区域的尺寸
            getMonthRectByPromise(el) {
                // #ifndef APP-NVUE
                // $uvGetRect为uvui自带的节点查询简化方法,详见文档介绍:https://www.uvui.cn/js/getRect.html
                // 组件内部一般用this.$uvGetRect,对外的为getRect,二者功能一致,名称不同
                return new Promise(resolve => {
                    this.$uvGetRect(`.${el}`).then(size => {
                        resolve(size)
                    })
                })
                // #endif
                // #ifdef APP-NVUE
                // nvue下,使用dom模块查询元素高度
                // 返回一个promise,让调用此方法的主体能使用then回调
                return new Promise(resolve => {
                    dom.getComponentRect(this.$refs[el][0], res => {
                        resolve(res.size)
                    })
                })
                // #endif
            },
            // 点击某一个日期
            clickHandler(index1, index2, item) {
                if (this.readonly) {
                    return;
                }
                this.item = item
                const date = dayjs(item.date).format("YYYY-MM-DD")
                if (item.disabled) return
                // 对上一次选择的日期数组进行深度克隆
                let selected = this.$uv.deepClone(this.selected)
                if (this.mode === 'single') {
                    // 单选情况下,让数组中的元素为当前点击的日期
                    selected = [date]
                } else if (this.mode === 'multiple') {
                    if (selected.some(item => this.dateSame(item, date))) {
                        // 如果点击的日期已在数组中,则进行移除操作,也就是达到反选的效果
                        const itemIndex = selected.findIndex(item => dayjs(item).format("YYYY-MM-DD") === dayjs(date).format("YYYY-MM-DD"))
                        selected.splice(itemIndex, 1)
                    } else {
                        // 如果点击的日期不在数组中,且已有的长度小于总可选长度时,则添加到数组中去
                        if (selected.length < this.maxCount) selected.push(date)
                    }
                } else {
                    // 选择区间形式
                    if (selected.length === 0 || selected.length >= 2) {
                        // 如果原来就为0或者大于2的长度,则当前点击的日期,就是开始日期
                        selected = [date]
                    } else if (selected.length === 1) {
                        // 如果已经选择了开始日期
                        const existsDate = selected[0]
                        // 如果当前选择的日期小于上一次选择的日期,则当前的日期定为开始日期
                        if (dayjs(date).isBefore(existsDate)) {
                            selected = [date]
                        } else if (dayjs(date).isAfter(existsDate)) {
                            // 当前日期减去最大可选的日期天数,如果大于起始时间,则进行提示
                            if(dayjs(dayjs(date).subtract(this.maxRange, 'day')).isAfter(dayjs(selected[0])) && this.showRangePrompt) {
                                if(this.rangePrompt) {
                                    this.$uv.toast(this.rangePrompt)
                                } else {
                                    this.$uv.toast(`选择天数不能超过 ${this.maxRange} 天`)
                                }
                                return
                            }
                            // 如果当前日期大于已有日期,将当前的添加到数组尾部
                            selected.push(date)
                            const startDate = selected[0]
                            const endDate = selected[1]
                            const arr = []
                            let i = 0
                            do {
                                // 将开始和结束日期之间的日期添加到数组中
                                arr.push(dayjs(startDate).add(i, 'day').format("YYYY-MM-DD"))
                                i++
                                // 累加的日期小于结束日期时,继续下一次的循环
                            } while (dayjs(startDate).add(i, 'day').isBefore(dayjs(endDate)))
                            // 为了一次性修改数组,避免computed中多次触发,这里才用arr变量一次性赋值的方式,同时将最后一个日期添加近来
                            arr.push(endDate)
                            selected = arr
                        } else {
                            // 选择区间时,只有一个日期的情况下,且不允许选择起止为同一天的话,不允许选择自己
                            if (selected[0] === date && !this.allowSameDay) return
                            selected.push(date)
                        }
                    }
                }
                this.setSelected(selected)
                this.$emit('change',{
                    day: date,
                    selected: selected
                });
            },
            // 设置默认日期
            setDefaultDate() {
                if (!this.defaultDate) {
                    // 如果没有设置默认日期,则将当天日期设置为默认选中的日期
                    const selected = [dayjs().format("YYYY-MM-DD")]
                    return this.setSelected(selected, false)
                }
                let defaultDate = []
                const minDate = this.minDate || dayjs().format("YYYY-MM-DD")
                const maxDate = this.maxDate || dayjs(minDate).add(this.maxMonth - 1, 'month').format("YYYY-MM-DD")
                if (this.mode === 'single') {
                    // 单选模式,可以是字符串或数组,Date对象等
                    if (!this.$uv.test.array(this.defaultDate)) {
                        defaultDate = [dayjs(this.defaultDate).format("YYYY-MM-DD")]
                    } else {
                        defaultDate = [this.defaultDate[0]]
                    }
                } else {
                    // 如果为非数组,则不执行
                    if (!this.$uv.test.array(this.defaultDate)) return
                    defaultDate = this.defaultDate
                }
                // 过滤用户传递的默认数组,取出只在可允许最大值与最小值之间的元素
                defaultDate = defaultDate.filter(item => {
                    return dayjs(item).isAfter(dayjs(minDate).subtract(1, 'day')) && dayjs(item).isBefore(dayjs(
                        maxDate).add(1, 'day'))
                })
                this.setSelected(defaultDate, false)
            },
            setSelected(selected, event = true) {
                this.selected = selected
                event && this.$emit('monthSelected', this.selected)
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    .uv-calendar-month-wrapper {
        margin-top: 4px;
    }
    .uv-calendar-month {
        &__title {
            font-size: 14px;
            line-height: 42px;
            height: 42px;
            color: $uv-main-color;
            text-align: center;
            font-weight: bold;
        }
        &__days {
            position: relative;
            @include flex;
            flex-wrap: wrap;
            &__month-mark-wrapper {
                position: absolute;
                top: 0;
                bottom: 0;
                left: 0;
                right: 0;
                @include flex;
                justify-content: center;
                align-items: center;
                &__text {
                    font-size: 155px;
                    color: rgba(231, 232, 234, 0.83);
                }
            }
            &__day {
                @include flex;
                padding: 2px;
                /* #ifndef APP-NVUE */
                // vue下使用css进行宽度计算,因为某些安卓机会无法进行js获取父元素宽度进行计算得出,会有偏移
                width: calc(100% / 7);
                box-sizing: border-box;
                /* #endif */
                &__select {
                    flex: 1;
                    @include flex;
                    align-items: center;
                    justify-content: center;
                    position: relative;
                    &__dot {
                        width: 7px;
                        height: 7px;
                        border-radius: 100px;
                        background-color: $uv-error;
                        position: absolute;
                        top: 12px;
                        right: 7px;
                    }
                    &__top-info {
                        color: $uv-content-color;
                        text-align: center;
                        position: absolute;
                        top: 2px;
                        font-size: 10px;
                        text-align: center;
                        left: 0;
                        right: 0;
                        &--selected {
                            color: #ffffff;
                        }
                        &--disabled {
                            color: #cacbcd;
                        }
                    }
                    &__buttom-info {
                        color: $uv-content-color;
                        text-align: center;
                        position: absolute;
                        bottom: 5px;
                        font-size: 10px;
                        text-align: center;
                        left: 0;
                        right: 0;
                        &--selected {
                            color: #ffffff;
                        }
                        &--disabled {
                            color: #cacbcd;
                        }
                    }
                    &__info {
                        text-align: center;
                        font-size: 16px;
                        &--selected {
                            color: #ffffff;
                        }
                        &--disabled {
                            color: #cacbcd;
                        }
                    }
                    &--selected {
                        background-color: $uv-primary;
                        @include flex;
                        justify-content: center;
                        align-items: center;
                        flex: 1;
                        border-radius: 3px;
                    }
                    &--range-selected {
                        opacity: 0.3;
                        border-radius: 0;
                    }
                    &--range-start-selected {
                        border-top-right-radius: 0;
                        border-bottom-right-radius: 0;
                    }
                    &--range-end-selected {
                        border-top-left-radius: 0;
                        border-bottom-left-radius: 0;
                    }
                }
            }
        }
    }
</style>
ledApp/uni_modules/uv-calendar/components/uv-calendar/props.js
New file
@@ -0,0 +1,145 @@
export default {
    props: {
        // 日历顶部标题
        title: {
            type: String,
            default: '日期选择'
        },
        // 是否显示标题
        showTitle: {
            type: Boolean,
            default: true
        },
        // 是否显示副标题
        showSubtitle: {
            type: Boolean,
            default: true
        },
        // 日期类型选择,single-选择单个日期,multiple-可以选择多个日期,range-选择日期范围
        mode: {
            type: String,
            default: 'single'
        },
        // mode=range时,第一个日期底部的提示文字
        startText: {
            type: String,
            default: '开始'
        },
        // mode=range时,最后一个日期底部的提示文字
        endText: {
            type: String,
            default: '结束'
        },
        // 自定义列表
        customList: {
            type: Array,
            default: () => []
        },
        // 主题色,对底部按钮和选中日期有效
        color: {
            type: String,
            default: '#3c9cff'
        },
        // 最小的可选日期
        minDate: {
            type: [String, Number],
            default: 0
        },
        // 最大可选日期
        maxDate: {
            type: [String, Number],
            default: 0
        },
        // 默认选中的日期,mode为multiple或range是必须为数组格式
        defaultDate: {
            type: [Array, String, Date, null],
            default: null
        },
        // mode=multiple时,最多可选多少个日期
        maxCount: {
            type: [String, Number],
            default: Number.MAX_SAFE_INTEGER
        },
        // 日期行高
        rowHeight: {
            type: [String, Number],
            default: 56
        },
        // 日期格式化函数
        formatter: {
            type: [Function, null],
            default: null
        },
        // 是否显示农历
        showLunar: {
            type: Boolean,
            default: false
        },
        // 是否显示月份背景色
        showMark: {
            type: Boolean,
            default: true
        },
        // 确定按钮的文字
        confirmText: {
            type: String,
            default: '确定'
        },
        // 确认按钮处于禁用状态时的文字
        confirmDisabledText: {
            type: String,
            default: '确定'
        },
        // 是否允许点击遮罩关闭日历
        closeOnClickOverlay: {
            type: Boolean,
            default: false
        },
        // 是否允许点击确认按钮关闭日历
        closeOnClickConfirm: {
            type: Boolean,
            default: true
        },
        // 是否为只读状态,只读状态下禁止选择日期
        readonly: {
            type: Boolean,
            default: false
        },
        //  是否展示确认按钮
        showConfirm: {
            type: Boolean,
            default: true
        },
        // 日期区间最多可选天数,默认无限制,mode = range时有效 Infinity
        maxRange: {
            type: [Number, String],
            default: Number.MAX_SAFE_INTEGER
        },
        // 范围选择超过最多可选天数时的提示文案,mode = range时有效
        rangePrompt: {
            type: String,
            default: ''
        },
        // 范围选择超过最多可选天数时,是否展示提示文案,mode = range时有效
        showRangePrompt: {
            type: Boolean,
            default: true
        },
        // 是否允许日期范围的起止时间为同一天,mode = range时有效
        allowSameDay: {
            type: Boolean,
            default: false
        },
        // 圆角值
        round: {
            type: [Boolean, String, Number],
            default: 0
        },
        // 最多展示月份数量
        monthNum: {
            type: [Number, String],
            default: 3
        },
        ...uni.$uv?.props?.calendar
    }
}
ledApp/uni_modules/uv-calendar/components/uv-calendar/uv-calendar.vue
New file
@@ -0,0 +1,390 @@
<template>
    <uv-popup
        ref="calendarPopup"
        mode="bottom"
        closeable
        :round="round"
        :closeOnClickOverlay="closeOnClickOverlay"
        @change="popupChange"
    >
        <view class="uv-calendar">
            <uvHeader
                :title="title"
                :subtitle="subtitle"
                :showSubtitle="showSubtitle"
                :showTitle="showTitle"
            ></uvHeader>
            <scroll-view
                :style="{ height: $uv.addUnit(listHeight) }"
                scroll-y
                @scroll="onScroll"
                :scroll-top="scrollTop"
                :scrollIntoView="scrollIntoView"
            >
                <uvMonth
                    :color="color"
                    :rowHeight="rowHeight"
                    :showMark="showMark"
                    :months="months"
                    :mode="mode"
                    :maxCount="maxCount"
                    :startText="startText"
                    :endText="endText"
                    :defaultDate="defaultDate"
                    :minDate="innerMinDate"
                    :maxDate="innerMaxDate"
                    :maxMonth="monthNum"
                    :readonly="readonly"
                    :maxRange="maxRange"
                    :rangePrompt="rangePrompt"
                    :showRangePrompt="showRangePrompt"
                    :allowSameDay="allowSameDay"
                    ref="month"
                    @monthSelected="monthSelected"
                    @updateMonthTop="updateMonthTop"
                    @change="changeDay"
                ></uvMonth>
            </scroll-view>
            <slot name="footer" v-if="showConfirm">
                <view class="uv-calendar__confirm">
                    <uv-button
                        shape="circle"
                        :text="buttonDisabled ? confirmDisabledText : confirmText"
                        :color="color"
                        @click="confirm"
                        :disabled="buttonDisabled"
                    ></uv-button>
                </view>
            </slot>
        </view>
    </uv-popup>
</template>
<script>
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
import uvHeader from './header.vue'
import uvMonth from './month.vue'
import props from './props.js'
import dayjs from '@/uni_modules/uv-ui-tools/libs/util/dayjs.js'
import Calendar from './calendar.js'
/**
 * Calendar 日历
 * @description  此组件用于单个选择日期,范围选择日期等,日历被包裹在底部弹起的容器中.
 * @tutorial https://www.uvui.cn/components/calendar.html
 *
 * @property {String}               title               标题内容 (默认 日期选择 )
 * @property {Boolean}              showTitle           是否显示标题  (默认 true )
 * @property {Boolean}              showSubtitle        是否显示副标题 (默认 true )
 * @property {String}               mode                日期类型选择  single-选择单个日期,multiple-可以选择多个日期,range-选择日期范围 ( 默认 'single' )
 * @property {String}               startText           mode=range时,第一个日期底部的提示文字  (默认 '开始' )
 * @property {String}               endText             mode=range时,最后一个日期底部的提示文字 (默认 '结束' )
 * @property {Array}                customList          自定义列表
 * @property {String}               color               主题色,对底部按钮和选中日期有效  (默认 ‘#3c9cff' )
 * @property {String | Number}      minDate             最小的可选日期  (默认 0 )
 * @property {String | Number}      maxDate             最大可选日期  (默认 0 )
 * @property {Array | String| Date} defaultDate         默认选中的日期,mode为multiple或range是必须为数组格式
 * @property {String | Number}      maxCount            mode=multiple时,最多可选多少个日期  (默认   Number.MAX_SAFE_INTEGER  )
 * @property {String | Number}      rowHeight           日期行高 (默认 56 )
 * @property {Function}             formatter           日期格式化函数
 * @property {Boolean}              showLunar           是否显示农历  (默认 false )
 * @property {Boolean}              showMark            是否显示月份背景色 (默认 true )
 * @property {String}               confirmText         确定按钮的文字 (默认 '确定' )
 * @property {String}               confirmDisabledText 确认按钮处于禁用状态时的文字 (默认 '确定' )
 * @property {Boolean}              show                是否显示日历弹窗 (默认 false )
 * @property {Boolean}              closeOnClickOverlay 是否允许点击遮罩关闭日历 (默认 false )
 * @property {Boolean}              closeOnClickConfirm 是否允许点击确认按钮关闭日历,设置为false不影响confirm事件返回 (默认 true )
 * @property {Boolean}              readonly            是否为只读状态,只读状态下禁止选择日期 (默认 false )
 * @property {String | Number}      maxRange            日期区间最多可选天数,默认无限制,mode = range时有效
 * @property {String}               rangePrompt         范围选择超过最多可选天数时的提示文案,mode = range时有效
 * @property {Boolean}              showRangePrompt     范围选择超过最多可选天数时,是否展示提示文案,mode = range时有效 (默认 true )
 * @property {Boolean}              allowSameDay        是否允许日期范围的起止时间为同一天,mode = range时有效 (默认 false )
 * @property {Number|String}        round               圆角值,默认无圆角  (默认 0 )
 * @property {Number|String}        monthNum            最多展示的月份数量  (默认 3 )
 *
 * @event {Function()} confirm      点击确定按钮时触发       选择日期相关的返回参数
 * @event {Function()} close        日历关闭时触发         可定义页面关闭时的回调事件
 * @example <uv-calendar ref="calendar" :defaultDate="defaultDateMultiple" mode="multiple" @confirm="confirm">
    </uv-calendar>
 * */
export default {
    name: 'uv-calendar',
    emits:['confirm','close','change'],
    mixins: [mpMixin, mixin, props],
    components: {
        uvHeader,
        uvMonth
    },
    data() {
        return {
            // 需要显示的月份的数组
            months: [],
            // 在月份滚动区域中,当前视图中月份的index索引
            monthIndex: 0,
            // 月份滚动区域的高度
            listHeight: 0,
            // month组件中选择的日期数组
            selected: [],
            scrollIntoView: '',
            scrollTop:0,
            // 过滤处理方法
            innerFormatter: (value) => value
        }
    },
    watch: {
        selectedChange: {
            immediate: true,
            handler(n) {
                this.setMonth()
            }
        }
    },
    computed: {
        // 由于maxDate和minDate可以为字符串(2021-10-10),或者数值(时间戳),但是dayjs如果接受字符串形式的时间戳会有问题,这里进行处理
        innerMaxDate() {
            return this.$uv.test.number(this.maxDate)
                ? Number(this.maxDate)
                : this.maxDate
        },
        innerMinDate() {
            return this.$uv.test.number(this.minDate)
                ? Number(this.minDate)
                : this.minDate
        },
        // 多个条件的变化,会引起选中日期的变化,这里统一管理监听
        selectedChange() {
            return [this.innerMinDate, this.innerMaxDate, this.defaultDate]
        },
        subtitle() {
            // 初始化时,this.months为空数组,所以需要特别判断处理
            if (this.months.length) {
                return `${this.months[this.monthIndex].year}年${
                    this.months[this.monthIndex].month
                }月`
            } else {
                return ''
            }
        },
        buttonDisabled() {
            // 如果为range类型,且选择的日期个数不足1个时,让底部的按钮出于disabled状态
            if (this.mode === 'range') {
                if (this.selected.length <= 1) {
                    return true
                } else {
                    return false
                }
            } else {
                return false
            }
        }
    },
    mounted() {
        this.start = Date.now()
        this.init()
    },
    methods: {
        // 在微信小程序中,不支持将函数当做props参数,故只能通过ref形式调用
        setFormatter(e) {
            this.innerFormatter = e
        },
        // 点击日期框触发
        changeDay(e) {
            this.$emit('change',e);
        },
        // month组件内部选择日期后,通过事件通知给父组件
        monthSelected(e) {
            this.selected = e
            if (!this.showConfirm) {
                // 在不需要确认按钮的情况下,如果为单选,或者范围多选且已选长度大于2,则直接进行返还
                if (
                    this.mode === 'multiple' ||
                    this.mode === 'single' ||
                    (this.mode === 'range' && this.selected.length >= 2)
                ) {
                    this.$emit('confirm', this.selected)
                }
            }
        },
        init() {
            // 校验maxDate,不能小于minDate
            if (
                this.innerMaxDate &&
                this.innerMinDate &&
                new Date(this.innerMaxDate).getTime() < new Date(this.innerMinDate).getTime()
            ) {
                return this.$uv.error('maxDate不能小于minDate')
            }
            // 滚动区域的高度
            this.listHeight = this.rowHeight * 5 + 30
            this.setMonth()
        },
        open() {
            this.setMonth()
            this.$refs.calendarPopup.open();
        },
        popupChange(e) {
            if(!e.show) {
                this.$emit('close');
            }
        },
        // 点击确定按钮
        confirm() {
            if (!this.buttonDisabled) {
                this.$emit('confirm', this.selected)
            }
            if (this.closeOnClickConfirm) {
                this.$refs.calendarPopup.close();
            }
        },
        // 获得两个日期之间的月份数
        getMonths(minDate, maxDate) {
            const minYear = dayjs(minDate).year()
            const minMonth = dayjs(minDate).month() + 1
            const maxYear = dayjs(maxDate).year()
            const maxMonth = dayjs(maxDate).month() + 1
            return (maxYear - minYear) * 12 + (maxMonth - minMonth) + 1
        },
        // 设置月份数据
        setMonth() {
            // 最小日期的毫秒数
            const minDate = this.innerMinDate || dayjs().valueOf()
            // 如果没有指定最大日期,则往后推3个月
            const maxDate =
                this.innerMaxDate ||
                dayjs(minDate)
                    .add(this.monthNum - 1, 'month')
                    .valueOf()
            // 最大最小月份之间的共有多少个月份,
            const months = this.$uv.range(
                1,
                this.monthNum,
                this.getMonths(minDate, maxDate)
            )
            // 先清空数组
            this.months = []
            for (let i = 0; i < months; i++) {
                this.months.push({
                    date: new Array(
                        dayjs(minDate).add(i, 'month').daysInMonth()
                    )
                        .fill(1)
                        .map((item, index) => {
                            // 日期,取值1-31
                            let day = index + 1
                            // 星期,0-6,0为周日
                            const week = dayjs(minDate)
                                .add(i, 'month')
                                .date(day)
                                .day()
                            const date = dayjs(minDate)
                                .add(i, 'month')
                                .date(day)
                                .format('YYYY-MM-DD')
                            let topInfo = ''
                            let bottomInfo = ''
                            if (this.showLunar) {
                                // 将日期转为农历格式
                                const lunar = Calendar.solar2lunar(
                                    dayjs(date).year(),
                                    dayjs(date).month() + 1,
                                    dayjs(date).date()
                                )
                                bottomInfo = lunar.IDayCn
                            }
                            let config = {
                                day,
                                week,
                                // 小于最小允许的日期,或者大于最大的日期,则设置为disabled状态
                                disabled:
                                    dayjs(date).isBefore(
                                        dayjs(minDate).format('YYYY-MM-DD')
                                    ) ||
                                    dayjs(date).isAfter(
                                        dayjs(maxDate).format('YYYY-MM-DD')
                                    ),
                                // 返回一个日期对象,供外部的formatter获取当前日期的年月日等信息,进行加工处理
                                date: new Date(date),
                                topInfo,
                                bottomInfo,
                                dot: false,
                                month:
                                    dayjs(minDate).add(i, 'month').month() + 1
                            }
                            const formatter =
                                this.formatter || this.innerFormatter
                            return formatter(config)
                        }),
                    // 当前所属的月份
                    month: dayjs(minDate).add(i, 'month').month() + 1,
                    // 当前年份
                    year: dayjs(minDate).add(i, 'month').year()
                })
            }
        },
        // 滚动到默认设置的月份
        scrollIntoDefaultMonth(selected) {
            // 查询默认日期在可选列表的下标
            const _index = this.months.findIndex(({
                  year,
                  month
              }) => {
                month = this.$uv.padZero(month)
                return `${year}-${month}` === selected
            })
            if (_index !== -1) {
                // #ifndef MP-WEIXIN
                this.$nextTick(() => {
                    this.scrollIntoView = `month-${_index}`
                })
                // #endif
                // #ifdef MP-WEIXIN
                this.scrollTop = this.months[_index].top || 0;
                // #endif
            }
        },
        // scroll-view滚动监听
        onScroll(event) {
            // 不允许小于0的滚动值,如果scroll-view到顶了,继续下拉,会出现负数值
            const scrollTop = Math.max(0, event.detail.scrollTop)
            // 将当前滚动条数值,除以滚动区域的高度,可以得出当前滚动到了哪一个月份的索引
            for (let i = 0; i < this.months.length; i++) {
                if (scrollTop >= (this.months[i].top || this.listHeight)) {
                    this.monthIndex = i
                }
            }
        },
        // 更新月份的top值
        updateMonthTop(topArr = []) {
            // 设置对应月份的top值,用于onScroll方法更新月份
            topArr.map((item, index) => {
                this.months[index].top = item
            })
            // 获取默认日期的下标
            if (!this.defaultDate) {
                // 如果没有设置默认日期,则将当天日期设置为默认选中的日期
                const selected = dayjs().format("YYYY-MM")
                this.scrollIntoDefaultMonth(selected)
                return
            }
            let selected = dayjs().format("YYYY-MM");
            // 单选模式,可以是字符串或数组,Date对象等
            if (!this.$uv.test.array(this.defaultDate)) {
                selected = dayjs(this.defaultDate).format("YYYY-MM")
            } else {
                selected = dayjs(this.defaultDate[0]).format("YYYY-MM");
            }
            this.scrollIntoDefaultMonth(selected)
        }
    }
}
</script>
<style lang="scss" scoped>
.uv-calendar {
    &__confirm {
        padding: 7px 18px;
    }
}
</style>
ledApp/uni_modules/uv-calendar/package.json
New file
@@ -0,0 +1,89 @@
{
    "id": "uv-calendar",
    "displayName": "uv-calendar 日历 全面兼容vue3+2、app、h5、小程序等多端",
    "version": "1.0.6",
    "description": "日历组件用于单个选择日期,范围选择日期等,日历被包裹在底部弹起的容器中,灵活配置,功能齐全,兼容全端。强烈推荐使用最新版日历组件,在下方跳入。",
    "keywords": [
        "uv-calendar",
        "uvui",
        "uv-ui",
        "calendar",
        "日历"
    ],
    "repository": "",
    "engines": {
        "HBuilderX": "^3.1.0"
    },
    "dcloudext": {
        "type": "component-vue",
        "sale": {
            "regular": {
                "price": "0.00"
            },
            "sourcecode": {
                "price": "0.00"
            }
        },
        "contact": {
            "qq": ""
        },
        "declaration": {
            "ads": "无",
            "data": "插件不采集任何数据",
            "permissions": "无"
        },
        "npmurl": ""
    },
    "uni_modules": {
        "dependencies": [
            "uv-ui-tools",
            "uv-button",
            "uv-popup"
        ],
        "encrypt": [],
        "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
    }
}
ledApp/uni_modules/uv-calendar/readme.md
New file
@@ -0,0 +1,21 @@
## Calendar 日历
> **组件名:uv-calendar**
此组件用于单个选择日期,范围选择日期等,日历被包裹在底部弹起的容器中。灵活配置,功能齐全,兼容全端。
## 温馨提示:该组件不再更新,强烈推荐使用最新版日历组件:[https://www.uvui.cn/components/calendars.html](https://www.uvui.cn/components/calendars.html)。基于 `uv-ui` 插件市场首款多功能日历组件,不仅可以查看、选择日期,还可以选择任意范围内的日期、打点操作、自定义主题颜色、自定义文案、农历显示等。追求的就是完美。
# <a href="https://www.uvui.cn/components/calendar.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>(请不要 下载插件ZIP)</small>
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
</a>
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-calendars/changelog.md
New file
@@ -0,0 +1,40 @@
## 1.0.15(2023-11-08)
1. 增加readonly属性,是否为只读状态,只读状态下禁止选择日期
## 1.0.14(2023-10-12)
1. 修复selected没有设置了info或者info设置为空字符串后,文本则无法恢复BUG
## 1.0.13(2023-09-19)
1. 修复range模式下,selected设置了info后选中后,导致文本不恢复的问题
2. 修复multiple模式下,selected自定义信息的颜色没变,依然是白色
## 1.0.12(2023-09-14)
1. 优化
## 1.0.11(2023-09-14)
1. 增加allowSameDay参数,是否允许日期范围的起止时间为同一天,mode = range时有效
2. 修复在vue2+小程序渲染时闪烁的问题
## 1.0.10(2023-09-07)
1. 修复国际化失效的BUG
## 1.0.9(2023-09-01)
1. 修复在pages.json中设置easycom会报错的BUG
## 1.0.8(2023-08-29)
1. 修复mainjs中设置setConfig修改属性不生效的问题,出自评论区:https://ext.dcloud.net.cn/plugin?id=12287
## 1.0.7(2023-08-26)
1. 去除range参数,由mode="range"替换
2. 新增mode参数,不传 / multiple / range,分别为单日期, 多个日期,选择日期范围
3. 与uv-calendar选择日期的功能保持一致
## 1.0.6(2023-08-25)
1. 修复点击返回今天按钮时,monthSwitch方法回调参数返回月份不是当天对应月份:https://github.com/climblee/uv-ui/issues/7
## 1.0.5(2023-08-13)
1. 修复选择月份弹窗层级的问题
## 1.0.4(2023-08-06)
1. 优化
## 1.0.3(2023-08-06)
1. 修复高度不对的BUG
2. 修复文案在小屏幕的BUG
## 1.0.2(2023-08-05)
1. 增加startText参数
2. 增加endText参数
3. 增加selected中的参数
4. 优化日历范围选择
## 1.0.1(2023-08-04)
1. 修复 自定义主题时 颜色错误的BUG
## 1.0.0(2023-08-03)
1. 新增 uv-calendars 新版日历发布
ledApp/uni_modules/uv-calendars/components/uv-calendars/calendar-body.vue
New file
@@ -0,0 +1,376 @@
<template>
    <view class="uv-calendar-body">
        <view class="uv-calendar__header">
            <view class="uv-calendar__header-btn-box" @click.stop="pre">
                <view class="uv-calendar__header-btn uv-calendar--left"></view>
            </view>
            <picker mode="date" :value="getDate" fields="month" @change="bindDateChange">
                <text class="uv-calendar__header-text">{{ (nowDate.year||'') +' / '+( nowDate.month||'')}}</text>
            </picker>
            <view class="uv-calendar__header-btn-box" @click.stop="next">
                <view class="uv-calendar__header-btn uv-calendar--right"></view>
            </view>
            <text class="uv-calendar__backtoday" @click="backToday">{{todayText}}</text>
        </view>
        <view class="uv-calendar__box">
            <view v-if="showMonth" class="uv-calendar__box-bg">
                <text class="uv-calendar__box-bg-text">{{nowDate.month}}</text>
            </view>
            <view class="uv-calendar__weeks uv-calendar__weeks-week">
                <view class="uv-calendar__weeks-day">
                    <text class="uv-calendar__weeks-day-text">{{SUNText}}</text>
                </view>
                <view class="uv-calendar__weeks-day">
                    <text class="uv-calendar__weeks-day-text">{{monText}}</text>
                </view>
                <view class="uv-calendar__weeks-day">
                    <text class="uv-calendar__weeks-day-text">{{TUEText}}</text>
                </view>
                <view class="uv-calendar__weeks-day">
                    <text class="uv-calendar__weeks-day-text">{{WEDText}}</text>
                </view>
                <view class="uv-calendar__weeks-day">
                    <text class="uv-calendar__weeks-day-text">{{THUText}}</text>
                </view>
                <view class="uv-calendar__weeks-day">
                    <text class="uv-calendar__weeks-day-text">{{FRIText}}</text>
                </view>
                <view class="uv-calendar__weeks-day">
                    <text class="uv-calendar__weeks-day-text">{{SATText}}</text>
                </view>
            </view>
            <view class="uv-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
                <view class="uv-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
                    <calendar-item class="uv-calendar-item--hook" :weeks="weeks" :rangeInfoText="rangeInfoText(weeks)" :multiple="multiple" :range="range" :calendar="calendar" :selected="selected" :lunar="lunar" :color="color" @change="choiceDate"></calendar-item>
                </view>
            </view>
        </view>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
    import CalendarItem from './calendar-item.vue';
    import { initVueI18n } from '@dcloudio/uni-i18n';
    import i18nMessages from './i18n/index.js';
    const { t } = initVueI18n(i18nMessages);
    export default {
        mixins: [mpMixin, mixin],
        components: {
            CalendarItem
        },
        props: {
            date: {
                type: [String,Array],
                default: ''
            },
            nowDate: {
                type: [String, Object],
                default: ''
            },
            weeks: {
                type: [Array, Object],
                default () {
                    return []
                }
            },
            calendar: {
                type: Object,
                default () {
                    return {}
                }
            },
            selected: {
                type: Array,
                default () {
                    return []
                }
            },
            lunar: {
                type: Boolean,
                default: false
            },
            showMonth: {
                type: Boolean,
                default: true
            },
            color: {
                type: String,
                default: '#3c9cff'
            },
            startText: {
                type: String,
                default: '开始'
            },
            endText: {
                type: String,
                default: '结束'
            },
            range: {
                type: Boolean,
                default: false
            },
            multiple: {
                type: Boolean,
                default: false
            },
            // 是否允许日期范围的起止时间为同一天,mode = range时有效
            allowSameDay: {
                type: Boolean,
                default: false
            }
        },
        computed: {
            getDate() {
                return Array.isArray(this.date) ? this.date[0] : this.date;
            },
            /**
             * for i18n
             */
            todayText() {
                return t("uv-calender.today")
            },
            monText() {
                return t("uv-calender.MON")
            },
            TUEText() {
                return t("uv-calender.TUE")
            },
            WEDText() {
                return t("uv-calender.WED")
            },
            THUText() {
                return t("uv-calender.THU")
            },
            FRIText() {
                return t("uv-calender.FRI")
            },
            SATText() {
                return t("uv-calender.SAT")
            },
            SUNText() {
                return t("uv-calender.SUN")
            },
            rangeInfoText(weeks) {
                return weeks=> {
                    if(this.allowSameDay && weeks.beforeRange && weeks.afterRange && weeks.dateEqual) {
                        return this.setInfo(weeks,`${this.startText}/${this.endText}`);
                    }
                    if(weeks.beforeRange) {
                        return this.setInfo(weeks,this.startText);
                    }
                    if(weeks.afterRange) {
                        return this.setInfo(weeks,this.endText);
                    }
                    if(weeks.extraInfo?.info_old == ' ') {
                        weeks.extraInfo.info = null;
                    }else if(weeks.extraInfo?.info_old) {
                        weeks.extraInfo.info = weeks.extraInfo.info_old;
                    }
                }
            }
        },
        methods: {
            setInfo(weeks,text) {
                this.setInfoOld(weeks);
                if(weeks.extraInfo) {
                    weeks.extraInfo.info = text;
                }else {
                    weeks.extraInfo = {
                        info: text
                    }
                }
            },
            setInfoOld(weeks) {
                if(weeks.extraInfo) {
                    weeks.extraInfo.info_old = weeks.extraInfo.info ? weeks.extraInfo.info_old || weeks.extraInfo.info : ' ';
                }
            },
            bindDateChange(e) {
                this.$emit('bindDateChange', e);
            },
            backToday() {
                this.$emit('backToday');
            },
            pre() {
                this.$emit('pre');
            },
            next() {
                this.$emit('next');
            },
            choiceDate(e) {
                this.$emit('choiceDate', e);
            }
        }
    }
</script>
<style scoped lang="scss">
    @mixin flex($direction: row) {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: $direction;
    }
    $uv-bg-color-mask: rgba($color: #000000, $alpha: 0.4);
    $uv-border-color: #EDEDED !default;
    $uv-text-color: #333;
    $uv-bg-color-hover: #f1f1f1;
    $uv-font-size-base: 14px;
    $uv-text-color-placeholder: #808080;
    $uv-color-subtitle: #555555;
    $uv-text-color-grey: #999;
    .uv-calendar {
        @include flex(column);
    }
    .uv-calendar__mask {
        position: fixed;
        bottom: 0;
        top: 0;
        left: 0;
        right: 0;
        background-color: $uv-bg-color-mask;
        transition-property: opacity;
        transition-duration: 0.3s;
        opacity: 0;
        /* #ifndef APP-NVUE */
        z-index: 99;
        /* #endif */
    }
    .uv-calendar--mask-show {
        opacity: 1
    }
    .uv-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 */
    }
    .uv-calendar--ani-show {
        transform: translateY(0);
    }
    .uv-calendar__content {
        background-color: #fff;
    }
    .uv-calendar__header {
        position: relative;
        @include flex;
        justify-content: center;
        align-items: center;
        height: 50px;
        border-bottom-color: $uv-border-color;
        border-bottom-style: solid;
        border-bottom-width: 1px;
    }
    .uv-calendar--fixed-top {
        @include flex;
        justify-content: space-between;
        border-top-color: $uv-border-color;
        border-top-style: solid;
        border-top-width: 1px;
    }
    .uv-calendar--fixed-width {
        width: 50px;
    }
    .uv-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: $uv-text-color;
        background-color: $uv-bg-color-hover;
    }
    .uv-calendar__header-text {
        text-align: center;
        width: 100px;
        font-size: $uv-font-size-base;
        color: $uv-text-color;
    }
    .uv-calendar__header-btn-box {
        @include flex;
        align-items: center;
        justify-content: center;
        width: 50px;
        height: 50px;
    }
    .uv-calendar__header-btn {
        width: 10px;
        height: 10px;
        border-left-color: $uv-text-color-placeholder;
        border-left-style: solid;
        border-left-width: 2px;
        border-top-color: $uv-color-subtitle;
        border-top-style: solid;
        border-top-width: 2px;
    }
    .uv-calendar--left {
        transform: rotate(-45deg);
    }
    .uv-calendar--right {
        transform: rotate(135deg);
    }
    .uv-calendar__weeks {
        position: relative;
        @include flex;
    }
    .uv-calendar__weeks-week {
        padding: 0 0 2rpx;
    }
    .uv-calendar__weeks-item {
        flex: 1;
    }
    .uv-calendar__weeks-day {
        flex: 1;
        @include flex(column);
        justify-content: center;
        align-items: center;
        height: 45px;
        border-bottom-color: #F5F5F5;
        border-bottom-style: solid;
        border-bottom-width: 1px;
    }
    .uv-calendar__weeks-day-text {
        font-size: 14px;
    }
    .uv-calendar__box {
        position: relative;
    }
    .uv-calendar__box-bg {
        @include flex(column);
        justify-content: center;
        align-items: center;
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
    }
    .uv-calendar__box-bg-text {
        font-size: 200px;
        font-weight: bold;
        color: $uv-text-color-grey;
        opacity: 0.1;
        text-align: center;
        /* #ifndef APP-NVUE */
        line-height: 1;
        /* #endif */
    }
</style>
ledApp/uni_modules/uv-calendars/components/uv-calendars/calendar-item.vue
New file
@@ -0,0 +1,248 @@
<template>
    <view class="uv-calendar-item__weeks-box" :class="{
        'uv-calendar-item--disable':weeks.disable || (weeks.extraInfo&&weeks.extraInfo.disable),
        'uv-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay && !multiple,
        'uv-calendar-item--checked':(calendar.fullDate === weeks.fullDate && !weeks.isDay && !multiple) ,
        'uv-calendar-item--before-checked':weeks.beforeRange,
        'uv-calendar-item--range': weeks.range,
        'uv-calendar-item--after-checked':weeks.afterRange,
        'uv-calendar-item--multiple':weeks.multiple
        }" :style="[itemBoxStyle]" @click="choiceDate(weeks)">
        <view class="uv-calendar-item__weeks-box-item">
            <text v-if="selected&&weeks.extraInfo&&weeks.extraInfo.badge" class="uv-calendar-item__weeks-box-circle"></text>
            <text class="uv-calendar-item__weeks-top-text" v-if="weeks.extraInfo&&weeks.extraInfo.topinfo" :style="[infoStyle('top')]">{{weeks.extraInfo&&weeks.extraInfo.topinfo}}</text>
            <text class="uv-calendar-item__weeks-box-text" :class="{
                'uv-calendar-item--isDay-text': weeks.isDay,
                'uv-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay && !multiple,
                'uv-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay && !multiple,
                'uv-calendar-item--before-checked':weeks.beforeRange,
                'uv-calendar-item--range': weeks.range,
                'uv-calendar-item--after-checked':weeks.afterRange,
                'uv-calendar-item--multiple':weeks.multiple,
                'uv-calendar-item--disable':weeks.disable || (weeks.extraInfo&&weeks.extraInfo.disable)
                }" :style="[itemBoxStyle]">{{weeks.date}}</text>
            <text v-if="!lunar&&!weeks.extraInfo && weeks.isDay" class="uv-calendar-item__weeks-lunar-text" :class="{
                'uv-calendar-item--isDay-text':weeks.isDay,
                'uv-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay && !multiple,
                'uv-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay && !multiple,
                'uv-calendar-item--before-checked':weeks.beforeRange,
                'uv-calendar-item--range': weeks.range,
                'uv-calendar-item--after-checked':weeks.afterRange,
                'uv-calendar-item--multiple':weeks.multiple
                }" :style="[itemBoxStyle]">{{todayText}}</text>
            <text v-if="lunar&&!weeks.extraInfo" class="uv-calendar-item__weeks-lunar-text" :class="{
                'uv-calendar-item--isDay-text':weeks.isDay,
                'uv-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay && !multiple,
                'uv-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay && !multiple,
                'uv-calendar-item--before-checked':weeks.beforeRange,
                'uv-calendar-item--range': weeks.range,
                'uv-calendar-item--after-checked':weeks.afterRange,
                'uv-calendar-item--multiple':weeks.multiple,
                'uv-calendar-item--disable':weeks.disable || (weeks.extraInfo&&weeks.extraInfo.disable)
                }" :style="[itemBoxStyle]">{{weeks.isDay ? todayText : (weeks.lunar.IDayCn === '初一'?weeks.lunar.IMonthCn:weeks.lunar.IDayCn)}}</text>
            <text v-if="weeks.extraInfo&&weeks.extraInfo.info" class="uv-calendar-item__weeks-lunar-text" :class="{
                        'uv-calendar-item__weeks-lunar-text--equal': weeks.dateEqual
                    }" :style="[infoStyle('bottom')]">{{weeks.extraInfo.info}}</text>
        </view>
    </view>
</template>
<script>
    import { colorGradient } from '@/uni_modules/uv-ui-tools/libs/function/colorGradient.js';
    import { initVueI18n } from '@dcloudio/uni-i18n'
    import i18nMessages from './i18n/index.js'
    const { t } = initVueI18n(i18nMessages)
    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
            },
            color: {
                type: String,
                default: '#3c9cff'
            },
            range: {
                type: Boolean,
                default: false
            },
            multiple: {
                type: Boolean,
                default: false
            }
        },
        computed: {
            todayText() {
                return t("uv-calender.today")
            },
            itemBoxStyle() {
                const style = {};
                if (this.multiple) { // 多选状态
                    if (this.weeks.multiple) {
                        style.backgroundColor = this.color;
                        style.color = '#fff';
                    } else if (this.weeks.isDay) {
                        style.color = this.color;
                    }
                } else if (this.range) { // 范围选择
                    if (this.weeks.beforeRange || this.weeks.afterRange) {
                        style.backgroundColor = this.color;
                    } else if (this.weeks.range) {
                        style.backgroundColor = colorGradient(this.color, '#ffffff', 100)[90]
                        style.color = this.color;
                        style.opacity = 0.8;
                        style.borderRadius = 0;
                    }
                } else {
                    if (this.weeks.isDay) {
                        style.color = this.color;
                    }
                    if (this.calendar.fullDate === this.weeks.fullDate) {
                        style.backgroundColor = this.color;
                        style.color = '#fff';
                    }
                }
                return style;
            },
            infoStyle(val) {
                return val => {
                    const style = {};
                    if (!this.weeks.multiple) {
                        if (val == 'top') {
                            style.color = this.weeks.extraInfo.topinfoColor ? this.weeks.extraInfo.topinfoColor : '#606266';
                        } else if (val == 'bottom') {
                            style.color = this.weeks.extraInfo.infoColor ? this.weeks.extraInfo.infoColor : '#f56c6c';
                        }
                        if (this.weeks.range) {
                            style.color = this.color;
                        }
                        if (this.calendar.fullDate === this.weeks.fullDate || this.weeks.beforeRange || this.weeks.afterRange) {
                            style.color = this.multiple ? style.color : '#fff';
                        }
                    } else {
                        style.color = '#fff';
                    }
                    return style;
                }
            }
        },
        methods: {
            choiceDate(weeks) {
                if (this.weeks.extraInfo && this.weeks.extraInfo.disable) return;
                this.$emit('change', weeks)
            }
        }
    }
</script>
<style lang="scss" scoped>
    @mixin flex($direction: row) {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: $direction;
    }
    $uv-font-size-base: 14px;
    $uv-text-color: #333;
    $uv-font-size-sm: 24rpx;
    $uv-error: #f56c6c !default;
    $uv-opacity-disabled: 0.3;
    $uv-text-color-disable: #c0c0c0;
    $uv-primary: #3c9cff !default;
    $info-height: 32rpx;
    .uv-calendar-item__weeks-box {
        flex: 1;
        @include flex(column);
        justify-content: center;
        align-items: center;
        border-radius: 4px;
    }
    .uv-calendar-item__weeks-top-text {
        height: $info-height;
        line-height: $info-height;
        font-size: $uv-font-size-sm;
    }
    .uv-calendar-item__weeks-box-text {
        font-size: $uv-font-size-base;
        color: $uv-text-color;
    }
    .uv-calendar-item__weeks-lunar-text {
        height: $info-height;
        line-height: $info-height;
        font-size: $uv-font-size-sm;
        color: $uv-text-color;
    }
    .uv-calendar-item__weeks-lunar-text--equal {
        /* #ifdef H5 */
        white-space: nowrap;
        transform: scale(.8);
        /* #endif */
        /* #ifndef H5 */
        font-size: 20rpx;
        /* #endif */
    }
    .uv-calendar-item__weeks-box-item {
        position: relative;
        @include flex(column);
        justify-content: center;
        align-items: center;
        width: 106rpx;
        height: 56px;
    }
    .uv-calendar-item__weeks-box-circle {
        position: absolute;
        top: 5px;
        right: 5px;
        width: 8px;
        height: 8px;
        border-radius: 8px;
        background-color: $uv-error;
    }
    .uv-calendar-item--disable {
        background-color: rgba(249, 249, 249, $uv-opacity-disabled);
        color: $uv-text-color-disable;
    }
    .uv-calendar-item--isDay-text {
        color: $uv-primary;
    }
    .uv-calendar-item--isDay {
        background-color: $uv-primary;
        color: #fff;
    }
    .uv-calendar-item--checked {
        background-color: $uv-primary;
        color: #fff;
        border-radius: 4px;
    }
    // .uv-calendar-item--range {
    //  background-color: $uv-primary;
    //  color: #fff;
    // }
    .uv-calendar-item--before-checked {
        color: #fff;
    }
    .uv-calendar-item--after-checked {
        color: #fff;
    }
    .uv-calendar-item--multiple {
        background-color: $uv-primary;
        color: #fff;
    }
</style>
ledApp/uni_modules/uv-calendars/components/uv-calendars/calendar.js
New file
@@ -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
ledApp/uni_modules/uv-calendars/components/uv-calendars/i18n/en.json
New file
@@ -0,0 +1,12 @@
{
    "uv-calender.ok": "ok",
    "uv-calender.cancel": "cancel",
    "uv-calender.today": "today",
    "uv-calender.MON": "MON",
    "uv-calender.TUE": "TUE",
    "uv-calender.WED": "WED",
    "uv-calender.THU": "THU",
    "uv-calender.FRI": "FRI",
    "uv-calender.SAT": "SAT",
    "uv-calender.SUN": "SUN"
}
ledApp/uni_modules/uv-calendars/components/uv-calendars/i18n/index.js
New file
@@ -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
}
ledApp/uni_modules/uv-calendars/components/uv-calendars/i18n/zh-Hans.json
New file
@@ -0,0 +1,12 @@
{
    "uv-calender.ok": "确定",
    "uv-calender.cancel": "取消",
    "uv-calender.today": "今日",
    "uv-calender.SUN": "日",
    "uv-calender.MON": "一",
    "uv-calender.TUE": "二",
    "uv-calender.WED": "三",
    "uv-calender.THU": "四",
    "uv-calender.FRI": "五",
    "uv-calender.SAT": "六"
}
ledApp/uni_modules/uv-calendars/components/uv-calendars/i18n/zh-Hant.json
New file
@@ -0,0 +1,12 @@
{
    "uv-calender.ok": "確定",
    "uv-calender.cancel": "取消",
    "uv-calender.today": "今日",
    "uv-calender.SUN": "日",
    "uv-calender.MON": "一",
    "uv-calender.TUE": "二",
    "uv-calender.WED": "三",
    "uv-calender.THU": "四",
    "uv-calender.FRI": "五",
    "uv-calender.SAT": "六"
}
ledApp/uni_modules/uv-calendars/components/uv-calendars/util.js
New file
@@ -0,0 +1,435 @@
import CALENDAR from './calendar.js'
class Calendar {
    constructor({
        date,
        selected,
        startDate,
        endDate,
        range,
        multiple,
        allowSameDay
    } = {}) {
        // 当前日期
        this.date = this.getDate(new Date()) // 当前初入日期
        // 打点信息
        this.selected = selected || [];
        // 范围开始
        this.startDate = startDate
        // 范围结束
        this.endDate = endDate
        this.range = range
        this.multiple = multiple
        this.allowSameDay = allowSameDay
        // 多选状态
        this.cleanRangeStatus()
        // 范围状态
        this.cleanMultipleStatus()
        // 每周日期
        this.weeks = {}
        // this._getWeek(this.date.fullDate)
    }
    /**
     * 设置日期
     * @param {Object} date
     */
    setDate(date, status) {
        if (this.range && status == 'init') {
            this.cleanRangeStatus();
            if (Array.isArray(date)) {
                this.rangeStatus.before = date[0];
                this.rangeStatus.after = date.length > 1 ? date[date.length - 1] : '';
                if (this.rangeStatus.after && this.dateCompare(this.rangeStatus.before, this.rangeStatus.after)) {
                    this.rangeStatus.data = this.geDateAll(this.rangeStatus.before, this.rangeStatus.after)
                }
                this.selectDate = this.getDate(date[0])
                this._getWeek(this.selectDate.fullDate)
            } else {
                this.selectDate = this.getDate(date)
                this.rangeStatus.before = this.selectDate.fullDate;
                this._getWeek(this.selectDate.fullDate)
            }
        } else if (this.multiple && status == 'init') {
            this.cleanMultipleStatus();
            if (Array.isArray(date)) {
                this.multipleStatus.data = date;
                this.selectDate = this.getDate(date[0])
                this._getWeek(this.selectDate.fullDate)
            } else {
                this.selectDate = this.getDate(date)
                this.multipleStatus.data = [this.selectDate.fullDate];
                this._getWeek(this.selectDate.fullDate)
            }
        } else {
            if (Array.isArray(date)) {
                this.selectDate = this.getDate(date[0])
                this._getWeek(this.selectDate.fullDate)
            } else {
                this.selectDate = this.getDate(date)
                this._getWeek(this.selectDate.fullDate)
            }
        }
    }
    /**
     * 清理多选状态
     */
    cleanRangeStatus() {
        this.rangeStatus = {
            before: '',
            after: '',
            data: []
        }
    }
    /**
     * 清理多选状态
     */
    cleanMultipleStatus() {
        this.multipleStatus = {
            data: []
        }
    }
    /**
     * 重置开始日期
     */
    resetSatrtDate(startDate) {
        // 范围开始
        this.startDate = startDate
    }
    /**
     * 重置结束日期
     */
    resetEndDate(endDate) {
        // 范围结束
        this.endDate = endDate
    }
    /**
     * 获取任意时间
     */
    getDate(date, AddDayCount = 0, str = 'day') {
        if (!date) {
            date = new Date()
        }
        if (typeof date !== 'object') {
            date = date.replace(/-/g, '/')
        }
        const dd = new Date(date)
        switch (str) {
            case 'day':
                dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
                break
            case 'month':
                if (dd.getDate() === 31 && AddDayCount > 0) {
                    dd.setDate(dd.getDate() + AddDayCount)
                } else {
                    const preMonth = dd.getMonth()
                    dd.setMonth(preMonth + AddDayCount) // 获取AddDayCount天后的日期
                    const nextMonth = dd.getMonth()
                    // 处理 pre 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
                    if (AddDayCount < 0 && preMonth !== 0 && nextMonth - preMonth > AddDayCount) {
                        dd.setMonth(nextMonth + (nextMonth - preMonth + AddDayCount))
                    }
                    // 处理 next 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
                    if (AddDayCount > 0 && nextMonth - preMonth > AddDayCount) {
                        dd.setMonth(nextMonth - (nextMonth - preMonth - AddDayCount))
                    }
                }
                break
            case 'year':
                dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
                break
        }
        const y = dd.getFullYear()
        const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
        const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
        return {
            fullDate: y + '-' + m + '-' + d,
            year: y,
            month: m,
            date: d,
            day: dd.getDay()
        }
    }
    /**
     * 获取上月剩余天数
     */
    _getLastMonthDays(firstDay, full) {
        let dateArr = []
        for (let i = firstDay; i > 0; i--) {
            const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
            dateArr.push({
                date: beforeDate,
                month: full.month - 1,
                lunar: this.getlunar(full.year, full.month - 1, beforeDate),
                disable: true
            })
        }
        return dateArr
    }
    /**
     * 获取本月天数
     */
    _currentMonthDys(dateData, full) {
        let dateArr = []
        let fullDate = this.date.fullDate
        for (let i = 1; i <= dateData; i++) {
            let nowDate = full.year + '-' + (full.month < 10 ? full.month : full.month) + '-' + (i < 10 ? '0' + i : i)
            // 是否今天
            let isDay = fullDate === nowDate
            // 获取打点信息
            let info = this.selected && this.selected.find((item) => {
                if (this.dateEqual(nowDate, item.date)) {
                    return item
                }
            })
            // 日期禁用
            let disableBefore = true
            let disableAfter = true
            if (this.startDate) {
                // let dateCompBefore = this.dateCompare(this.startDate, fullDate)
                // disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
                disableBefore = this.dateCompare(this.startDate, nowDate)
            }
            if (this.endDate) {
                // let dateCompAfter = this.dateCompare(fullDate, this.endDate)
                // disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
                disableAfter = this.dateCompare(nowDate, this.endDate)
            }
            let ranges = this.rangeStatus.data
            let checked = false
            let rangesStatus = -1
            if (this.range) {
                if (ranges) {
                    rangesStatus = ranges.findIndex((item) => {
                        return this.dateEqual(item, nowDate)
                    })
                }
                if (rangesStatus !== -1) {
                    checked = true
                }
            }
            let multiples = this.multipleStatus.data
            let checked_multiple = false
            let multiplesStatus = -1
            if (this.multiple) {
                if (multiples) {
                    multiplesStatus = multiples.findIndex((item) => {
                        return this.dateEqual(item, nowDate)
                    })
                }
                if (multiplesStatus !== -1) {
                    checked_multiple = true
                }
            }
            let data = {
                fullDate: nowDate,
                year: full.year,
                date: i,
                range: this.range ? checked : false,
                multiple: this.multiple ? checked_multiple : false,
                beforeRange: this.dateEqual(this.rangeStatus.before, nowDate),
                afterRange: this.dateEqual(this.rangeStatus.after, nowDate),
                dateEqual: this.range && checked && this.dateEqual(this.rangeStatus.before, this.rangeStatus.after),
                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()
        } else if (Array.isArray(date)) {
            date = date[0]
        }
        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
        }
    }
    /**
     * 比较after时间是否大于before时间
     */
    dateAfterLgBefore(before, after) {
        // 计算截止时间
        before = new Date(before.replace('-', '/').replace('-', '/'))
        // 计算详细项的截止时间
        after = new Date(after.replace('-', '/').replace('-', '/'))
        if (after.getTime() - before.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) {
        if (!this.multiple) return
        let multiples = this.multipleStatus.data;
        const findIndex = multiples.findIndex(item => this.dateEqual(fullDate, item));
        if (findIndex < 0) {
            this.multipleStatus.data = this.multipleStatus.data.concat([fullDate]);
        } else {
            this.multipleStatus.data.splice(findIndex, 1);
        }
        this._getWeek(fullDate)
    }
    /**
     *  获取范围状态
     */
    setRange(fullDate) {
        let {
            before,
            after
        } = this.rangeStatus
        if (!this.range) return
        if (before && after) {
            this.cleanRangeStatus();
            this.rangeStatus.before = fullDate
        } else {
            if (!before) {
                this.rangeStatus.before = fullDate
            } else {
                if (this.allowSameDay && this.dateEqual(before, fullDate)) {
                    this.rangeStatus.after = fullDate
                } else if (!this.dateAfterLgBefore(this.rangeStatus.before, fullDate)) {
                    this.cleanRangeStatus();
                    this.rangeStatus.before = fullDate
                    this._getWeek(fullDate)
                    return;
                }
                this.rangeStatus.after = fullDate
                if (this.dateCompare(this.rangeStatus.before, this.rangeStatus.after)) {
                    this.rangeStatus.data = this.geDateAll(this.rangeStatus.before, this.rangeStatus.after);
                } else {
                    this.rangeStatus.data = this.geDateAll(this.rangeStatus.after, this.rangeStatus.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
ledApp/uni_modules/uv-calendars/components/uv-calendars/uv-calendars.vue
New file
@@ -0,0 +1,452 @@
<template>
    <view class="uv-calendar">
        <view class="uv-calendar__content" v-if="insert">
            <calendar-body
                :date="date"
                :nowDate="nowDate"
                :weeks="weeks"
                :calendar="calendar"
                :selected="selected"
                :lunar="lunar"
                :showMonth="showMonth"
                :color="color"
                :startText="startText"
                :endText="endText"
                :range="range"
                :multiple="multiple"
                :allowSameDay="allowSameDay"
                @bindDateChange="bindDateChange"
                @pre="pre"
                @next="next"
                @backToday="backToday"
                @choiceDate="choiceDate"
            ></calendar-body>
        </view>
        <uv-popup ref="popup" mode="bottom" v-else :round="round" z-index="998" :close-on-click-overlay="closeOnClickOverlay" @maskClick="maskClick">
            <view style="min-height: 100px;">
                <uv-toolbar
                    :show="true"
                    :cancelColor="cancelColor"
                    :confirmColor="getConfirmColor"
                    :cancelText="cancelText"
                    :confirmText="confirmText"
                    :title="title"
                    @cancel="close"
                    @confirm="confirm"></uv-toolbar>
                <view class="line"></view>
                <calendar-body
                    :nowDate="nowDate"
                    :weeks="weeks"
                    :calendar="calendar"
                    :selected="selected"
                    :lunar="lunar"
                    :showMonth="showMonth"
                    :color="color"
                    :startText="startText"
                    :endText="endText"
                    :range="range"
                    :multiple="multiple"
                    :allowSameDay="allowSameDay"
                    @bindDateChange="bindDateChange"
                    @pre="pre"
                    @next="next"
                    @backToday="backToday"
                    @choiceDate="choiceDate"
                ></calendar-body>
            </view>
        </uv-popup>
    </view>
</template>
<script>
    /**
     * Calendar 日历
     * @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
     * @tutorial https://ext.dcloud.net.cn/plugin?name=uv-calendar
     * @property {String} date 自定义当前时间,默认为今天
     * @property {Boolean} lunar 显示农历
     * @property {String} startDate 日期选择范围-开始日期
     * @property {String} endDate 日期选择范围-结束日期
     * @property {String} mode = [不传 | multiple | 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 {String} cancelColor 取消按钮颜色
     * @property {String} confirmColor  确认按钮颜色,默认#3c9cff
     * @property {String} title 头部工具条中间的标题文字
     * @property {String} color 主题色,默认#3c9cff
     * @property {Number} round :insert="false"时的圆角
     * @property {Boolean} closeOnClickOverlay 点击遮罩是否关闭
     * @property {String} startText range为true时,第一个日期底部的提示文字
     * @property {String} endText range为true时,最后一个日期底部的提示文字
     * @property {String} readonly 是否为只读状态,只读状态下禁止选择日期,默认false
     *
     * @event {Function} change 日期改变,`insert :ture` 时生效
     * @event {Function} confirm 确认选择`insert :false` 时生效
     * @event {Function} monthSwitch 切换月份时触发
     *
     * @example <uv-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
     */
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
    import Calendar from './util.js';
    import calendarBody from './calendar-body.vue';
    import { initVueI18n } from '@dcloudio/uni-i18n';
    import i18nMessages from './i18n/index.js';
    const { t } = initVueI18n(i18nMessages);
    export default {
        components: {
            calendarBody
        },
        mixins: [mpMixin, mixin],
        emits: ['close', 'confirm', 'change', 'monthSwitch'],
        props: {
            // 取消按钮颜色
            cancelColor: {
                type: String,
                default: ''
            },
            // 确认按钮颜色,range模式下未选全显示灰色
            confirmColor: {
                type: String,
                default: '#3c9cff'
            },
            // 标题
            title: {
                type: String,
                default: ''
            },
            // 主题色
            color: {
                type: String,
                default: '#3c9cff'
            },
            // 默认显示日期
            date: {
                type: [String,Array],
                default: ''
            },
            // 打点等设置
            selected: {
                type: Array,
                default () {
                    return []
                }
            },
            // 是否显示农历
            lunar: {
                type: Boolean,
                default: false
            },
            // 可选择的起始日期
            startDate: {
                type: String,
                default: ''
            },
            // 可选择的结束日期
            endDate: {
                type: String,
                default: ''
            },
            // multiple - 选择多日期  range - 选择日期范围
            mode: {
                type: String,
                default: ''
            },
            // 是否插入模式
            insert: {
                type: Boolean,
                default: false
            },
            // 是否显示月份为背景
            showMonth: {
                type: Boolean,
                default: true
            },
            // 弹窗模式是否清空上次选择内容
            clearDate: {
                type: Boolean,
                default: true
            },
            // 弹窗圆角
            round: {
                type: [Number,String],
                default: 8
            },
            // 点击遮罩是否关闭弹窗
            closeOnClickOverlay: {
                type: Boolean,
                default: true
            },
            // range为true时,第一个日期底部的提示文字
            startText: {
                type: String,
                default: '开始'
            },
            // range为true时,最后一个日期底部的提示文字
            endText: {
                type: String,
                default: '结束'
            },
            // 是否允许日期范围的起止时间为同一天,mode = range时有效
            allowSameDay: {
                type: Boolean,
                default: false
            },
            // 是否禁用
            readonly: {
                type: Boolean,
                default: false
            },
            ...uni.$uv?.props?.calendars
        },
        data(){
            return {
                weeks: [],
                calendar: {},
                nowDate: '',
                allowConfirm: false,
                multiple: false,
                range: false
            }
        },
        computed:{
            /**
             * for i18n
             */
            confirmText() {
                return t("uv-calender.ok")
            },
            cancelText() {
                return t("uv-calender.cancel")
            },
            getConfirmColor() {
                if(this.range || this.multiple || this.readonly) {
                    return this.allowConfirm? this.confirmColor: '#999'
                }else {
                    return this.confirmColor;
                }
            }
        },
        watch: {
            date(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.setMode();
            this.cale = new Calendar({
                selected: this.selected,
                startDate: this.startDate,
                endDate: this.endDate,
                range: this.range,
                multiple: this.multiple,
                allowSameDay: this.allowSameDay
            })
            this.init(this.date)
        },
        methods: {
            setMode() {
                switch (this.mode){
                    case 'range':
                        this.range = true;
                        break;
                    case 'multiple':
                        this.multiple = true;
                    default:
                        break;
                }
            },
            async open() {
                if (this.clearDate && !this.insert) {
                    this.cale.cleanRangeStatus()
                    this.init(this.date)
                }
                if(!this.insert){
                    this.$refs.popup.open();
                }
            },
            close() {
                this.$refs.popup.close();
                this.$emit('close');
            },
            confirm() {
                if(this.readonly) {
                    return;
                } else if(this.range && !this.cale.rangeStatus.after) {
                    return;
                } else if(this.multiple && this.cale.multipleStatus.data.length == 0){
                    return;
                }
                this.setEmit('confirm');
                this.close()
            },
            maskClick() {
                if(this.closeOnClickOverlay) {
                    this.$emit('close');
                }
            },
            bindDateChange(e) {
                const value = e.detail.value + '-1'
                this.setDate(value)
                const { year, month } = this.cale.getDate(value)
                this.$emit('monthSwitch', {
                    year,
                    month
                })
            },
            /**
             * 初始化日期显示
             * @param {Object} date
             */
            init(date) {
                if(this.range) {
                    // 重置范围选择状态
                    this.cale.cleanRangeStatus();
                }else if(this.multiple){
                    // 重置多选状态
                    this.cale.cleanMultipleStatus();
                }
                this.cale.setDate(date,'init')
                this.weeks = this.cale.weeks
                this.nowDate = this.calendar = this.cale.getInfo(date)
                this.changeConfirmStatus();
            },
            /**
             * 变化触发
             */
            change() {
                this.changeConfirmStatus();
                if (!this.insert) return
                this.setEmit('change')
            },
            changeConfirmStatus() {
                if(this.readonly) {
                    this.allowConfirm = false;
                } else if (this.range) {
                    this.allowConfirm = this.cale.rangeStatus.after ? true : false;
                } else if(this.multiple) {
                    this.allowConfirm = this.cale.multipleStatus.data.length > 0 ? true : false;
                }
            },
            /**
             * 选择月份触发
             */
            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.rangeStatus,
                    multiple: this.cale.multipleStatus,
                    year,
                    month,
                    date,
                    fulldate: fullDate,
                    lunar,
                    extraInfo: extraInfo || {}
                })
            },
            /**
             * 选择天触发
             * @param {Object} weeks
             */
            choiceDate(weeks) {
                if (weeks.disable || this.readonly) return
                this.calendar = weeks
                // 设置范围选择
                this.cale.setRange(this.calendar.fullDate)
                // 设置多选
                this.cale.setMultiple(this.calendar.fullDate);
                this.weeks = this.cale.weeks
                this.change()
            },
            /**
             * 回到今天
             */
            backToday() {
                const nowYearMonth = `${this.nowDate.year}-${this.nowDate.month}`
                const date = this.cale.getDate(new Date())
                const todayYearMonth = `${date.year}-${date.month}`
                this.init(date.fullDate)
                if (nowYearMonth !== todayYearMonth) {
                    this.monthSwitch()
                }
                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 scoped lang="scss">
    $uv-border-color: #EDEDED !default;
    .uv-calendar__content {
        background-color: #fff;
    }
    .line {
        width: 750rpx;
        height: 1px;
        border-bottom-color: $uv-border-color;
        border-bottom-style: solid;
        border-bottom-width: 1px;
    }
</style>
ledApp/uni_modules/uv-calendars/package.json
New file
@@ -0,0 +1,89 @@
{
  "id": "uv-calendars",
  "displayName": "uv-calendars 最新日历 全面兼容vue3+2、app、h5、小程序等多端",
  "version": "1.0.15",
  "description": "新版本uv-calendars,不仅拥有老版本的所有功能,还增加了更加适用的插入页面等强大功能,且更加简洁。查看日期、选择单个或多个或任意范围日期,打点操作,自定义文案,自定义主题等强大功能。",
  "keywords": [
    "uv-ui",
    "uvui",
    "日历",
    "打卡",
    "日历选择"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration":{
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools",
            "uv-popup",
            "uv-toolbar"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-calendars/readme.md
New file
@@ -0,0 +1,23 @@
## Calendars 全新日历
> **组件名:uv-calendars**
为了解决老版本`uv-calendar`性能问题,特别是对日期选择范围有很大限制,体验不友好等缺点。于是有了新版日历组件。
新版本`uv-calendars`,不仅拥有老版本的所有功能,还增加了更加适用的插入页面等强大功能,且更加简洁。查看日期、选择单个或多个或任意范围日期,打点操作,自定义文案,自定义主题等强大功能。
常用场景:酒店日期预订、火车机票选择购买日期、上下班打卡等。
# <a href="https://www.uvui.cn/components/calendars.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>(请不要 下载插件ZIP)</small>
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
</a>
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-cell/changelog.md
New file
@@ -0,0 +1,13 @@
## 1.0.5(2023-12-06)
1. 修复uv-cell right-icon插槽编译到APP端不显示的BUG,问题来源:https://gitee.com/climblee/uv-ui/issues/I8LXZI
## 1.0.4(2023-09-19)
1. 增加cellStyle参数,方便自定义单元格的样式
## 1.0.3(2023-07-03)
去除插槽判断,避免某些平台不显示的BUG
## 1.0.2(2023-06-21)
1. 优化
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-cell 单元格
ledApp/uni_modules/uv-cell/components/uv-cell-group/props.js
New file
@@ -0,0 +1,15 @@
export default {
    props: {
        // 分组标题
        title: {
            type: String,
            default: ''
        },
        // 是否显示外边框
        border: {
            type: Boolean,
            default: true
        },
        ...uni.$uv?.props?.cellGroup
    }
}
ledApp/uni_modules/uv-cell/components/uv-cell-group/uv-cell-group.vue
New file
@@ -0,0 +1,63 @@
<template>
    <view :style="[$uv.addStyle(customStyle)]" :class="[customClass]" class="uv-cell-group">
        <view v-if="title" class="uv-cell-group__title">
            <slot name="title">
                <text class="uv-cell-group__title__text">{{ title }}</text>
            </slot>
        </view>
        <view class="uv-cell-group__wrapper">
            <uv-line v-if="border"></uv-line>
            <slot />
        </view>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * cellGroup  单元格
     * @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。
     * @tutorial https://www.uvui.cn/components/cell.html
     *
     * @property {String}   title       分组标题
     * @property {Boolean}  border      是否显示外边框 (默认 true )
     * @property {Object}   customStyle 定义需要用到的外部样式
     *
     * @event {Function} click  点击cell列表时触发
     * @example <uv-cell-group title="设置喜好">
     */
    export default {
        name: 'uv-cell-group',
        mixins: [mpMixin, mixin, props]
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    $uv-cell-group-title-padding: 16px 16px 8px !default;
    $uv-cell-group-title-font-size: 15px !default;
    $uv-cell-group-title-line-height: 16px !default;
    $uv-cell-group-title-color: $uv-main-color !default;
    .uv-cell-group {
        flex: 1;
        &__title {
            padding: $uv-cell-group-title-padding;
            &__text {
                font-size: $uv-cell-group-title-font-size;
                line-height: $uv-cell-group-title-line-height;
                color: $uv-cell-group-title-color;
            }
        }
        &__wrapper {
            position: relative;
        }
    }
</style>
ledApp/uni_modules/uv-cell/components/uv-cell/props.js
New file
@@ -0,0 +1,116 @@
export default {
    props: {
        // 标题
        title: {
            type: [String, Number],
            default: ''
        },
        // 标题下方的描述信息
        label: {
            type: [String, Number],
            default: ''
        },
        // 右侧的内容
        value: {
            type: [String, Number],
            default: ''
        },
        // 左侧图标名称,或者图片链接(本地文件建议使用绝对地址)
        icon: {
            type: String,
            default: ''
        },
        // 是否禁用cell
        disabled: {
            type: Boolean,
            default: false
        },
        // 是否显示下边框
        border: {
            type: Boolean,
            default: true
        },
        // 内容是否垂直居中(主要是针对右侧的value部分)
        center: {
            type: Boolean,
            default: true
        },
        // 点击后跳转的URL地址
        url: {
            type: String,
            default: ''
        },
        // 链接跳转的方式,内部使用的是uvui封装的route方法,可能会进行拦截操作
        linkType: {
            type: String,
            default: 'navigateTo'
        },
        // 是否开启点击反馈(表现为点击时加上灰色背景)
        clickable: {
            type: Boolean,
            default: false
        },
        // 是否展示右侧箭头并开启点击反馈
        isLink: {
            type: Boolean,
            default: false
        },
        // 是否显示表单状态下的必填星号(此组件可能会内嵌入input组件)
        required: {
            type: Boolean,
            default: false
        },
        // 右侧的图标箭头
        rightIcon: {
            type: String,
            default: 'arrow-right'
        },
        // 右侧箭头的方向,可选值为:left,up,down
        arrowDirection: {
            type: String,
            default: ''
        },
        // 左侧图标样式
        iconStyle: {
            type: [Object, String],
            default: () => {
                return {}
            }
        },
        // 右侧箭头图标的样式
        rightIconStyle: {
            type: [Object, String],
            default: () => {
                return {}
            }
        },
        // 标题的样式
        titleStyle: {
            type: [Object, String],
            default: () => {
                return {}
            }
        },
        // 单位元的大小,可选值为large
        size: {
            type: String,
            default: ''
        },
        // 点击cell是否阻止事件传播
        stop: {
            type: Boolean,
            default: true
        },
        // 标识符,cell被点击时返回
        name: {
            type: [Number, String],
            default: ''
        },
        // 单元格自定义样式
        cellStyle: {
            type: [Object, String],
            default: () => {}
        },
        ...uni.$uv?.props?.cell
    }
}
ledApp/uni_modules/uv-cell/components/uv-cell/uv-cell.vue
New file
@@ -0,0 +1,209 @@
<template>
    <view class="uv-cell" :class="[customClass]" :style="[$uv.addStyle(customStyle)]"
        :hover-class="(!disabled && (clickable || isLink)) ? 'uv-cell--clickable' : ''" :hover-stay-time="250"
        @click="clickHandler">
        <view class="uv-cell__body"
            :class="[ center && 'uv-cell--center', size === 'large' && 'uv-cell__body--large']"
            :style="[cellStyle]"
        >
            <view class="uv-cell__body__content">
                <view class="uv-cell__left-icon-wrap">
                    <slot name="icon">
                        <uv-icon v-if="icon" :name="icon" :custom-style="iconStyle" :size="size === 'large' ? 22 : 18"></uv-icon>
                    </slot>
                </view>
                <view class="uv-cell__title">
                    <slot name="title">
                        <text v-if="title" class="uv-cell__title-text" :style="[titleTextStyle]"
                            :class="[disabled && 'uv-cell--disabled', size === 'large' && 'uv-cell__title-text--large']">{{ title }}</text>
                    </slot>
                    <slot name="label">
                        <text class="uv-cell__label" v-if="label"
                            :class="[disabled && 'uv-cell--disabled', size === 'large' && 'uv-cell__label--large']">{{ label }}</text>
                    </slot>
                </view>
            </view>
            <slot name="value">
                <text class="uv-cell__value"
                    :class="[disabled && 'uv-cell--disabled', size === 'large' && 'uv-cell__value--large']"
                    v-if="!$uv.test.empty(value)">{{ value }}</text>
            </slot>
            <view class="uv-cell__right-icon-wrap"
                :class="[`uv-cell__right-icon-wrap--${arrowDirection}`]">
                <slot name="right-icon">
                    <uv-icon v-if="isLink" :name="rightIcon" :custom-style="rightIconStyle" :color="disabled ? '#c8c9cc' : 'info'"
                        :size="size === 'large' ? 18 : 16"></uv-icon>
                </slot>
            </view>
        </view>
        <uv-line v-if="border"></uv-line>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * cell  单元格
     * @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。
     * @tutorial https://www.uvui.cn/components/cell.html
     * @property {String | Number}  title           标题
     * @property {String | Number}  label           标题下方的描述信息
     * @property {String | Number}  value           右侧的内容
     * @property {String}           icon            左侧图标名称,或者图片链接(本地文件建议使用绝对地址)
     * @property {Boolean}          disabled        是否禁用cell
     * @property {Boolean}          border          是否显示下边框 (默认 true )
     * @property {Boolean}          center          内容是否垂直居中(主要是针对右侧的value部分) (默认 false )
     * @property {String}           url             点击后跳转的URL地址
     * @property {String}           linkType        链接跳转的方式,内部使用的是uvui封装的route方法,可能会进行拦截操作 (默认 'navigateTo' )
     * @property {Boolean}          clickable       是否开启点击反馈(表现为点击时加上灰色背景) (默认 false )
     * @property {Boolean}          isLink          是否展示右侧箭头并开启点击反馈 (默认 false )
     * @property {Boolean}          required        是否显示表单状态下的必填星号(此组件可能会内嵌入input组件) (默认 false )
     * @property {String}           rightIcon       右侧的图标箭头 (默认 'arrow-right')
     * @property {String}           arrowDirection  右侧箭头的方向,可选值为:left,up,down
     * @property {Object | String}          rightIconStyle  右侧箭头图标的样式
     * @property {Object | String}          titleStyle      标题的样式
     * @property {Object | String}          iconStyle       左侧图标样式
     * @property {String}           size            单位元的大小,可选值为 large,normal,mini
     * @property {Boolean}          stop            点击cell是否阻止事件传播 (默认 true )
     * @property {Object | String}  cellStyle 单元格自定义样式
     * @property {Object}           customStyle     定义需要用到的外部样式
     *
     * @event {Function}            click           点击cell列表时触发
     * @example 该组件需要搭配cell-group组件使用,见官方文档示例
     */
    export default {
        name: 'uv-cell',
        emits: ['click'],
        mixins: [mpMixin, mixin, props],
        computed: {
            titleTextStyle() {
                return this.$uv.addStyle(this.titleStyle)
            }
        },
        methods: {
            // 点击cell
            clickHandler(e) {
                if (this.disabled) return
                this.$emit('click', {
                    name: this.name
                })
                // 如果配置了url(此props参数通过mixin引入)参数,跳转页面
                this.openPage()
                // 是否阻止事件传播
                this.stop && this.preventEvent(e)
            },
        }
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    $uv-cell-padding: 10px 15px !default;
    $uv-cell-font-size: 15px !default;
    $uv-cell-line-height: 24px !default;
    $uv-cell-color: $uv-main-color !default;
    $uv-cell-icon-size: 16px !default;
    $uv-cell-title-font-size: 15px !default;
    $uv-cell-title-line-height: 22px !default;
    $uv-cell-title-color: $uv-main-color !default;
    $uv-cell-label-font-size: 12px !default;
    $uv-cell-label-color: $uv-tips-color !default;
    $uv-cell-label-line-height: 18px !default;
    $uv-cell-value-font-size: 14px !default;
    $uv-cell-value-color: $uv-content-color !default;
    $uv-cell-clickable-color: $uv-bg-color !default;
    $uv-cell-disabled-color: #c8c9cc !default;
    $uv-cell-padding-top-large: 13px !default;
    $uv-cell-padding-bottom-large: 13px !default;
    $uv-cell-value-font-size-large: 15px !default;
    $uv-cell-label-font-size-large: 14px !default;
    $uv-cell-title-font-size-large: 16px !default;
    $uv-cell-left-icon-wrap-margin-right: 4px !default;
    $uv-cell-right-icon-wrap-margin-left: 4px !default;
    $uv-cell-title-flex: 1 !default;
    $uv-cell-label-margin-top: 5px !default;
    .uv-cell {
        &__body {
            @include flex();
            /* #ifndef APP-NVUE */
            box-sizing: border-box;
            /* #endif */
            padding: $uv-cell-padding;
            font-size: $uv-cell-font-size;
            color: $uv-cell-color;
            &__content {
                @include flex(row);
                align-items: center;
                flex: 1;
            }
            &--large {
                padding-top: $uv-cell-padding-top-large;
                padding-bottom: $uv-cell-padding-bottom-large;
            }
        }
        &__left-icon-wrap,
        &__right-icon-wrap {
            @include flex();
            align-items: center;
            // height: $uv-cell-line-height;
            font-size: $uv-cell-icon-size;
        }
        &__left-icon-wrap {
            margin-right: $uv-cell-left-icon-wrap-margin-right;
        }
        &__right-icon-wrap {
            margin-left: $uv-cell-right-icon-wrap-margin-left;
            transition: transform 0.3s;
            &--up {
                transform: rotate(-90deg);
            }
            &--down {
                transform: rotate(90deg);
            }
        }
        &__title {
            flex: $uv-cell-title-flex;
            &-text {
                font-size: $uv-cell-title-font-size;
                line-height: $uv-cell-title-line-height;
                color: $uv-cell-title-color;
                &--large {
                    font-size: $uv-cell-title-font-size-large;
                }
            }
        }
        &__label {
            margin-top: $uv-cell-label-margin-top;
            font-size: $uv-cell-label-font-size;
            color: $uv-cell-label-color;
            line-height: $uv-cell-label-line-height;
            &--large {
                font-size: $uv-cell-label-font-size-large;
            }
        }
        &__value {
            text-align: right;
            font-size: $uv-cell-value-font-size;
            line-height: $uv-cell-line-height;
            color: $uv-cell-value-color;
            &--large {
                font-size: $uv-cell-value-font-size-large;
            }
        }
        &--clickable {
            background-color: $uv-cell-clickable-color;
        }
        &--disabled {
            color: $uv-cell-disabled-color;
            /* #ifndef APP-NVUE */
            cursor: not-allowed;
            /* #endif */
        }
        &--center {
            align-items: center;
        }
    }
</style>
ledApp/uni_modules/uv-cell/package.json
New file
@@ -0,0 +1,89 @@
{
  "id": "uv-cell",
  "displayName": "uv-cell 单元格 全面兼容小程序、nvue、vue2、vue3等多端",
  "version": "1.0.5",
  "description": "cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。",
  "keywords": [
    "uv-cell",
    "uvui",
    "uv-ui",
    "单元格",
    "设置页"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools",
            "uv-icon",
            "uv-line"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-cell/readme.md
New file
@@ -0,0 +1,11 @@
## Cell 单元格
> **组件名:uv-cell**
cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。
### <a href="https://www.uvui.cn/components/cell.html" target="_blank">查看文档</a>
### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)
#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-checkbox/changelog.md
New file
@@ -0,0 +1,34 @@
## 1.0.14(2023-11-04)
1. 修复label文字较多不分行的问题
## 1.0.13(2023-10-11)
1. 优化同类问题:https://gitee.com/climblee/uv-ui/issues/I872VD
## 1.0.12(2023-09-22)
1. 修复change回调中v-model值不更新的BUG
## 1.0.11(2023-09-01)
1. 修复点击空隙处无效的问题
2. label支持插槽下可点击
## 1.0.10(2023-08-27)
1. 修复label设置布尔值不生效的BUG
## 1.0.9(2023-08-16)
1. 解决数据多不换行的BUG
## 1.0.8(2023-07-13)
1. 修复  uv-checkbox设置value属性不生效的BUG
## 1.0.7(2023-07-05)
修复vue3模式下,动态修改v-model绑定的值无效的BUG
## 1.0.6(2023-06-29)
1. 增加label插槽,与radio保持一致
2. 优化文档
## 1.0.5(2023-06-12)
1. 修复1.0.4改出的问题
## 1.0.4(2023-06-08)
1. 复选框修复全局设置不生效的BUG
## 1.0.3(2023-06-06)
1. uv-checkbox-group 兼容自定义样式customStyle,方便通过样式调整整体位置等;
2. .uv-checkbox-group--row增加flex-wrap: wrap;允许换行
## 1.0.2(2023-05-30)
1. 修复error报错的BUG
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-checkbox 复选框
ledApp/uni_modules/uv-checkbox/components/uv-checkbox-group/props.js
New file
@@ -0,0 +1,84 @@
export default {
    props: {
        // 绑定的值
        value: {
            type: Array,
            default: () => []
        },
        modelValue: {
            type: Array,
            default: () => []
        },
        // 标识符
        name: {
            type: String,
            default: ''
        },
        // 形状,circle-圆形,square-方形
        shape: {
            type: String,
            default: 'square'
        },
        // 是否禁用全部checkbox
        disabled: {
            type: Boolean,
            default: false
        },
        // 选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值
        activeColor: {
            type: String,
            default: '#2979ff'
        },
        // 未选中的颜色
        inactiveColor: {
            type: String,
            default: '#c8c9cc'
        },
        // 整个组件的尺寸,默认px
        size: {
            type: [String, Number],
            default: 18
        },
        // 布局方式,row-横向,column-纵向
        placement: {
            type: String,
            default: 'row'
        },
        // label的字体大小,px单位
        labelSize: {
            type: [String, Number],
            default: 14
        },
        // label的字体颜色
        labelColor: {
            type: [String],
            default: '#303133'
        },
        // 是否禁止点击文本操作
        labelDisabled: {
            type: Boolean,
            default: false
        },
        // 图标颜色
        iconColor: {
            type: String,
            default: '#fff'
        },
        // 图标的大小,单位px
        iconSize: {
            type: [String, Number],
            default: 12
        },
        // 勾选图标的对齐方式,left-左边,right-右边
        iconPlacement: {
            type: String,
            default: 'left'
        },
        // 竖向配列时,是否显示下划线
        borderBottom: {
            type: Boolean,
            default: false
        },
        ...uni.$uv?.props?.checkboxGroup
    }
}
ledApp/uni_modules/uv-checkbox/components/uv-checkbox-group/uv-checkbox-group.vue
New file
@@ -0,0 +1,119 @@
<template>
    <view
        class="uv-checkbox-group"
        :class="bemClass"
            :style="[$uv.addStyle(this.customStyle)]"
    >
        <slot></slot>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * checkboxGroup 复选框组
     * @description 复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便
     * @tutorial https://www.uvui.cn/components/checkbox.html
     * @property {String}           name            标识符
     * @property {Array}            value           绑定的值
     * @property {String}           shape           形状,circle-圆形,square-方形 (默认 'square' )
     * @property {Boolean}          disabled        是否禁用全部checkbox (默认 false )
     * @property {String}           activeColor     选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值 (默认 '#2979ff' )
     * @property {String}           inactiveColor   未选中的颜色 (默认 '#c8c9cc' )
     * @property {String | Number}  size            整个组件的尺寸 单位px (默认 18 )
     * @property {String}           placement       布局方式,row-横向,column-纵向 (默认 'row' )
     * @property {String | Number}  labelSize       label的字体大小,px单位  (默认 14 )
     * @property {String}           labelColor      label的字体颜色 (默认 '#303133' )
     * @property {Boolean}          labelDisabled   是否禁止点击文本操作 (默认 false )
     * @property {String}           iconColor       图标颜色 (默认 '#ffffff' )
     * @property {String | Number}  iconSize        图标的大小,单位px (默认 12 )
     * @property {String}           iconPlacement   勾选图标的对齐方式,left-左边,right-右边  (默认 'left' )
     * @property {Boolean}          borderBottom    placement为row时,是否显示下边框 (默认 false )
     * @event {Function}    change  任一个checkbox状态发生变化时触发,回调为一个对象
     * @event {Function}    input   修改通过v-model绑定的值时触发,回调为一个对象
     * @example <uv-checkbox-group></uv-checkbox-group>
     */
    export default {
        name: 'uv-checkbox-group',
        mixins: [mpMixin, mixin, props],
        computed: {
            // 这里computed的变量,都是子组件uv-checkbox需要用到的,由于头条小程序的兼容性差异,子组件无法实时监听父组件参数的变化
            // 所以需要手动通知子组件,这里返回一个parentData变量,供watch监听,在其中去通知每一个子组件重新从父组件(uv-checkbox-group)
            // 拉取父组件新的变化后的参数
            parentData() {
                let value = [];
                if(this.value.length) {
                    value  = this.value;
                } else if (this.modelValue.length){
                    value = this.modelValue;
                }
                return [value, this.disabled, this.inactiveColor, this.activeColor, this.size, this.labelDisabled, this.shape,
                    this.iconSize, this.borderBottom, this.placement, this.labelSize, this.labelColor]
            },
            bemClass() {
                // this.bem为一个computed变量,在mixin中
                return this.bem('checkbox-group', ['placement'])
            },
        },
        watch: {
            // 当父组件需要子组件需要共享的参数发生了变化,手动通知子组件
            parentData() {
                if (this.children.length) {
                    this.children.map(child => {
                        // 判断子组件(uv-checkbox)如果有init方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
                        typeof(child.init) === 'function' && child.init()
                    })
                }
            },
        },
        data() {
            return {
            }
        },
        created() {
            this.children = []
        },
        methods: {
            // 将其他的checkbox设置为未选中的状态
            unCheckedOther(childInstance) {
                const values = []
                this.children.map(child => {
                    // 将被选中的checkbox,放到数组中返回
                    if (child.isChecked) {
                        values.push(child.name)
                    }
                })
                // 修改通过v-model绑定的值
                // #ifdef VUE2
                this.$emit('input', values)
                // #endif
                // #ifdef VUE3
                this.$emit('update:modelValue',values)
                // #endif
                // 发出事件
                this.$emit('change', values)
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    .uv-checkbox-group {
        flex: 1;
        &--row {
            @include flex;
            flex-wrap: wrap;
        }
        &--column {
            @include flex(column);
        }
    }
</style>
ledApp/uni_modules/uv-checkbox/components/uv-checkbox/props.js
New file
@@ -0,0 +1,70 @@
export default {
    props: {
        // checkbox的名称
        name: {
            type: [String, Number, Boolean],
            default: ''
        },
        // 形状,square为方形,circle为圆型
        shape: {
            type: String,
            default: ''
        },
        // 整体的大小
        size: {
            type: [String, Number],
            default: ''
        },
        // 是否默认选中
        checked: {
            type: Boolean,
            default: false
        },
        // 是否禁用
        disabled: {
            type: [String, Boolean],
            default: ''
        },
        // 选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值
        activeColor: {
            type: String,
            default: ''
        },
        // 未选中的颜色
        inactiveColor: {
            type: String,
            default: ''
        },
        // 图标的大小,单位px
        iconSize: {
            type: [String, Number],
            default: ''
        },
        // 图标颜色
        iconColor: {
            type: String,
            default: ''
        },
        // label提示文字,因为nvue下,直接slot进来的文字,由于特殊的结构,无法修改样式
        label: {
            type: [String, Number, Boolean],
            default: ''
        },
        // label的字体大小,px单位
        labelSize: {
            type: [String, Number],
            default: ''
        },
        // label的颜色
        labelColor: {
            type: String,
            default: ''
        },
        // 是否禁止点击提示语选中复选框
        labelDisabled: {
            type: [String, Boolean],
            default: ''
        },
        ...uni.$uv?.props?.checkbox
    }
}
ledApp/uni_modules/uv-checkbox/components/uv-checkbox/uv-checkbox.vue
New file
@@ -0,0 +1,370 @@
<template>
    <view
      class="uv-checkbox"
      :style="[checkboxStyle]"
      @tap.stop="wrapperClickHandler"
      :class="[`uv-checkbox-label--${parentData.iconPlacement}`, parentData.borderBottom && parentData.placement === 'column' && 'uv-border-bottom']"
    >
        <view
          class="uv-checkbox__icon-wrap"
          @tap.stop="iconClickHandler"
          :class="iconClasses"
          :style="[iconWrapStyle]"
        >
            <slot name="icon">
                <uv-icon
                  class="uv-checkbox__icon-wrap__icon"
                  name="checkbox-mark"
                  :size="elIconSize"
                  :color="elIconColor"
                />
            </slot>
        </view>
        <view
            class="uv-checkbox__label-wrap"
            @tap.stop="labelClickHandler">
            <slot>
                <text
                  :style="{
                        color: elDisabled ? elInactiveColor : elLabelColor,
                        fontSize: elLabelSize,
                        lineHeight: elLabelSize
                    }"
                >{{label}}</text>
            </slot>
        </view>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * checkbox  复选框
     * @description 复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便
     * @tutorial https://www.uvui.cn/components/checkbox.html
     * @property {String | Number | Boolean}    name            checkbox组件的标示符
     * @property {String}                       shape           形状,square为方形,circle为圆型
     * @property {String | Number}              size            整体的大小
     * @property {Boolean}                      checked         是否默认选中
     * @property {String | Boolean}             disabled        是否禁用
     * @property {String}                       activeColor     选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值
     * @property {String}                       inactiveColor   未选中的颜色
     * @property {String | Number}              iconSize        图标的大小,单位px
     * @property {String}                       iconColor       图标颜色
     * @property {String | Number}              label           label提示文字,因为nvue下,直接slot进来的文字,由于特殊的结构,无法修改样式
     * @property {String}                       labelColor      label的颜色
     * @property {String | Number}              labelSize       label的字体大小,px单位
     * @property {String | Boolean}             labelDisabled   是否禁止点击提示语选中复选框
     * @property {Object}                       customStyle     定义需要用到的外部样式
     *
     * @event {Function}    change  任一个checkbox状态发生变化时触发,回调为一个对象
     * @example <uv-checkbox v-model="checked" :disabled="false">天涯</uv-checkbox>
     */
    export default {
        name: "uv-checkbox",
        mixins: [mpMixin, mixin, props],
        data() {
            return {
                isChecked: false,
                // 父组件的默认值,因为头条小程序不支持在computed中使用this.parent.shape的形式
                // 故只能使用如此方法
                parentData: {
                    iconSize: 12,
                    labelDisabled: null,
                    disabled: null,
                    shape: 'square',
                    activeColor: null,
                    inactiveColor: null,
                    size: 18,
                    value: null,
                    modelValue: null,
                    iconColor: null,
                    placement: 'row',
                    borderBottom: false,
                    iconPlacement: 'left',
                    labelSize: 14,
                    labelColor: '#303133'
                }
            }
        },
        computed: {
            // 是否禁用,如果父组件uv-raios-group禁用的话,将会忽略子组件的配置
            elDisabled() {
                return this.disabled !== '' ? this.disabled : this.parentData.disabled !== null ? this.parentData.disabled : false;
            },
            // 是否禁用label点击
            elLabelDisabled() {
                return this.labelDisabled !== '' ? this.labelDisabled : this.parentData.labelDisabled !== null ? this.parentData.labelDisabled :
                    false;
            },
            // 组件尺寸,对应size的值,默认值为21px
            elSize() {
                return this.size ? this.size : (this.parentData.size ? this.parentData.size : 21);
            },
            // 组件的勾选图标的尺寸,默认12px
            elIconSize() {
                return this.iconSize ? this.iconSize : (this.parentData.iconSize ? this.parentData.iconSize : 12);
            },
            // 组件选中激活时的颜色
            elActiveColor() {
                return this.activeColor ? this.activeColor : (this.parentData.activeColor ? this.parentData.activeColor : '#2979ff');
            },
            // 组件选未中激活时的颜色
            elInactiveColor() {
                return this.inactiveColor ? this.inactiveColor : (this.parentData.inactiveColor ? this.parentData.inactiveColor :
                    '#c8c9cc');
            },
            // label的颜色
            elLabelColor() {
                return this.labelColor ? this.labelColor : (this.parentData.labelColor ? this.parentData.labelColor : '#606266')
            },
            // 组件的形状
            elShape() {
                return this.shape ? this.shape : (this.parentData.shape ? this.parentData.shape : 'circle');
            },
            // label大小
            elLabelSize() {
                return this.$uv.addUnit(this.labelSize ? this.labelSize : (this.parentData.labelSize ? this.parentData.labelSize :
                    '15'))
            },
            elIconColor() {
                const iconColor = this.iconColor ? this.iconColor : (this.parentData.iconColor ? this.parentData.iconColor :
                    '#ffffff');
                // 图标的颜色
                if (this.elDisabled) {
                    // disabled状态下,已勾选的checkbox图标改为elInactiveColor
                    return this.isChecked ? this.elInactiveColor : 'transparent'
                } else {
                    return this.isChecked ? iconColor : 'transparent'
                }
            },
            iconClasses() {
                let classes = []
                // 组件的形状
                classes.push('uv-checkbox__icon-wrap--' + this.elShape)
                if (this.elDisabled) {
                    classes.push('uv-checkbox__icon-wrap--disabled')
                }
                if (this.isChecked && this.elDisabled) {
                    classes.push('uv-checkbox__icon-wrap--disabled--checked')
                }
                // 支付宝,头条小程序无法动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效
                // #ifdef MP-ALIPAY || MP-TOUTIAO
                classes = classes.join(' ')
                // #endif
                return classes
            },
            iconWrapStyle() {
                // checkbox的整体样式
                const style = {}
                style.backgroundColor = this.isChecked && !this.elDisabled ? this.elActiveColor : '#ffffff'
                style.borderColor = this.isChecked && !this.elDisabled ? this.elActiveColor : this.elInactiveColor
                style.width = this.$uv.addUnit(this.elSize)
                style.height = this.$uv.addUnit(this.elSize)
                // 如果是图标在右边的话,移除它的右边距
                if (this.parentData.iconPlacement === 'right') {
                    style.marginRight = 0
                }
                return style
            },
            checkboxStyle() {
                const style = {}
                if (this.parentData.borderBottom && this.parentData.placement === 'row') {
                    this.$uv.error('检测到您将borderBottom设置为true,需要同时将uv-checkbox-group的placement设置为column才有效')
                }
                // 当父组件设置了显示下边框并且排列形式为纵向时,给内容和边框之间加上一定间隔
                if (this.parentData.borderBottom && this.parentData.placement === 'column') {
                    style.paddingBottom = '8px'
                }
                return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
            }
        },
        created() {
            this.init()
        },
        methods: {
            init() {
                // 支付宝小程序不支持provide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环引用
                this.updateParentData()
                if (!this.parent) {
                    this.$uv.error('uv-checkbox必须搭配uv-checkbox-group组件使用')
                }
                this.$nextTick(()=>{
                    let parentValue = [];
                    if(this.parentData.value.length) {
                        parentValue = this.parentData.value;
                    } else if (this.parentData.modelValue.length){
                        parentValue = this.parentData.modelValue;
                    }
                    // 设置初始化时,是否默认选中的状态,父组件uv-checkbox-group的value可能是array,所以额外判断
                    if (this.checked) {
                        this.isChecked = true
                    } else if (this.$uv.test.array(parentValue)) {
                        // 查找数组是是否存在this.name元素值
                        this.isChecked = parentValue.some(item => {
                            return item === this.name
                        })
                    }
                })
            },
            updateParentData() {
                this.getParentData('uv-checkbox-group')
            },
            // 横向两端排列时,点击组件即可触发选中事件
            wrapperClickHandler(e) {
                this.parentData.iconPlacement === 'right' && this.iconClickHandler(e)
            },
            // 点击图标
            iconClickHandler(e) {
                this.preventEvent(e)
                // 如果整体被禁用,不允许被点击
                if (!this.elDisabled) {
                    this.setRadioCheckedStatus()
                }
            },
            // 点击label
            labelClickHandler(e) {
                this.preventEvent(e)
                // 如果按钮整体被禁用或者label被禁用,则不允许点击文字修改状态
                if (!this.elLabelDisabled && !this.elDisabled) {
                    this.setRadioCheckedStatus()
                }
            },
            emitEvent() {
                this.$emit('change', this.isChecked)
                // 尝试调用uv-form的验证方法,进行一定延迟,否则微信小程序更新可能会不及时
                this.$nextTick(() => {
                    this.$uv.formValidate(this, 'change')
                })
            },
            // 改变组件选中状态
            // 这里的改变的依据是,更改本组件的checked值为true,同时通过父组件遍历所有uv-checkbox实例
            // 将本组件外的其他uv-checkbox的checked都设置为false(都被取消选中状态),因而只剩下一个为选中状态
            setRadioCheckedStatus() {
                // 将本组件标记为与原来相反的状态
                this.isChecked = !this.isChecked
                this.emitEvent()
                typeof this.parent.unCheckedOther === 'function' && this.parent.unCheckedOther(this)
            }
        },
        watch:{
            checked(){
                this.isChecked = this.checked
            }
        }
    }
</script>
<style lang="scss" scoped>
    $show-border: 1;
    $show-border-bottom: 1;
    @import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    $uv-checkbox-label-wrap-padding-right:6px !default;
    $uv-checkbox-icon-wrap-font-size:6px !default;
    $uv-checkbox-icon-wrap-border-width:1px !default;
    $uv-checkbox-icon-wrap-border-color:#c8c9cc !default;
    $uv-checkbox-icon-wrap-icon-line-height:0 !default;
    $uv-checkbox-icon-wrap-circle-border-radius:100% !default;
    $uv-checkbox-icon-wrap-square-border-radius:3px !default;
    $uv-checkbox-icon-wrap-checked-color:#fff !default;
    $uv-checkbox-icon-wrap-checked-background-color:red !default;
    $uv-checkbox-icon-wrap-checked-border-color:#2979ff !default;
    $uv-checkbox-icon-wrap-disabled-background-color:#ebedf0 !default;
    $uv-checkbox-icon-wrap-disabled-checked-color:#c8c9cc !default;
    $uv-checkbox-label-margin-left:5px !default;
    $uv-checkbox-label-margin-right:12px !default;
    $uv-checkbox-label-color:$uv-content-color !default;
    $uv-checkbox-label-font-size:15px !default;
    $uv-checkbox-label-disabled-color:#c8c9cc !default;
    .uv-checkbox {
        /* #ifndef APP-NVUE */
        @include flex(row);
        /* #endif */
        overflow: hidden;
        flex-direction: row;
        align-items: center;
        &-label--left {
            flex-direction: row
        }
        &-label--right {
            flex-direction: row-reverse;
            justify-content: space-between
        }
        &__icon-wrap {
            /* #ifndef APP-NVUE */
            box-sizing: border-box;
            // nvue下,border-color过渡有问题
            transition-property: border-color, background-color, color;
            transition-duration: 0.2s;
            /* #endif */
            color: $uv-content-color;
            @include flex;
            align-items: center;
            justify-content: center;
            color: transparent;
            text-align: center;
            font-size: $uv-checkbox-icon-wrap-font-size;
            border-width: $uv-checkbox-icon-wrap-border-width;
            border-color: $uv-checkbox-icon-wrap-border-color;
            border-style: solid;
            /* #ifdef MP-TOUTIAO */
            // 头条小程序兼容性问题,需要设置行高为0,否则图标偏下
            &__icon {
                line-height: $uv-checkbox-icon-wrap-icon-line-height;
            }
            /* #endif */
            &--circle {
                border-radius: $uv-checkbox-icon-wrap-circle-border-radius;
            }
            &--square {
                border-radius: $uv-checkbox-icon-wrap-square-border-radius;
            }
            &--checked {
                color: $uv-checkbox-icon-wrap-checked-color;
                background-color: $uv-checkbox-icon-wrap-checked-background-color;
                border-color: $uv-checkbox-icon-wrap-checked-border-color;
            }
            &--disabled {
                background-color: $uv-checkbox-icon-wrap-disabled-background-color !important;
            }
            &--disabled--checked {
                color: $uv-checkbox-icon-wrap-disabled-checked-color !important;
            }
        }
        &__label {
            /* #ifndef APP-NVUE */
            word-wrap: break-word;
            /* #endif */
            margin-left: $uv-checkbox-label-margin-left;
            margin-right: $uv-checkbox-label-margin-right;
            color: $uv-checkbox-label-color;
            font-size: $uv-checkbox-label-font-size;
            &--disabled {
                color: $uv-checkbox-label-disabled-color;
            }
        }
        &__label-wrap {
            flex: 1;
            padding-left: $uv-checkbox-label-wrap-padding-right;
        }
    }
</style>
ledApp/uni_modules/uv-checkbox/package.json
New file
@@ -0,0 +1,88 @@
{
  "id": "uv-checkbox",
  "displayName": "uv-checkbox 复选框 全面兼容vue3+2、app、h5、小程序等多端",
  "version": "1.0.14",
  "description": "复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便。",
  "keywords": [
    "uv-checkbox",
    "uvui",
    "uv-ui",
    "checkbox",
    "复选框"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools",
            "uv-icon"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-checkbox/readme.md
New file
@@ -0,0 +1,19 @@
## Checkbox 复选框
> **组件名:uv-checkbox**
复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便。可配合 `uv-form` 组件进行表单验证等场景使用。
# <a href="https://www.uvui.cn/components/checkbox.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>(请不要 下载插件ZIP)</small>
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
</a>
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-code-input/changelog.md
New file
@@ -0,0 +1,13 @@
## 1.0.5(2023-08-05)
在vue2模式下,v-model设置为0时不生效的BUG
## 1.0.4(2023-07-13)
1. 修复value/v-model更改不生效的BUG
## 1.0.3(2023-06-28)
修复:使用:disabledKeyboard="true"属性,事件全部失效的BUG
## 1.0.2(2023-06-23)
优化下边框
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-code-input 验证码输入
ledApp/uni_modules/uv-code-input/components/uv-code-input/props.js
New file
@@ -0,0 +1,83 @@
export default {
    props: {
        value: {
            type: [String, Number],
            default: ''
        },
        modelValue: {
            type: [String, Number],
            default: ''
        },
        // 键盘弹起时,是否自动上推页面
        adjustPosition: {
            type: Boolean,
            default: true
        },
        // 最大输入长度
        maxlength: {
            type: [String, Number],
            default: 6
        },
        // 是否用圆点填充
        dot: {
            type: Boolean,
            default: false
        },
        // 显示模式,box-盒子模式,line-底部横线模式
        mode: {
            type: String,
            default: 'box'
        },
        // 是否细边框
        hairline: {
            type: Boolean,
            default: false
        },
        // 字符间的距离
        space: {
            type: [String, Number],
            default: 10
        },
        // 是否自动获取焦点
        focus: {
            type: Boolean,
            default: false
        },
        // 字体是否加粗
        bold: {
            type: Boolean,
            default: false
        },
        // 字体颜色
        color: {
            type: String,
            default: '#606266'
        },
        // 字体大小
        fontSize: {
            type: [String, Number],
            default: 18
        },
        // 输入框的大小,宽等于高
        size: {
            type: [String, Number],
            default: 35
        },
        // 是否隐藏原生键盘,如果想用自定义键盘的话,需设置此参数为true
        disabledKeyboard: {
            type: Boolean,
            default: false
        },
        // 边框和线条颜色
        borderColor: {
            type: String,
            default: '#c9cacc'
        },
        // 是否禁止输入"."符号
        disabledDot: {
            type: Boolean,
            default: true
        },
        ...uni.$uv?.props?.codeInput
    }
}
ledApp/uni_modules/uv-code-input/components/uv-code-input/uv-code-input.vue
New file
@@ -0,0 +1,272 @@
<template>
    <view class="uv-code-input">
        <view
            class="uv-code-input__item"
            :style="[itemStyle(index)]"
            v-for="(item, index) in codeLength"
            :key="index"
        >
            <view
                class="uv-code-input__item__dot"
                v-if="dot && codeArray.length > index"
            ></view>
            <text
                v-else
                :style="{
                    fontSize: $uv.addUnit(fontSize),
                    fontWeight: bold ? 'bold' : 'normal',
                    color: color
                }"
            >{{codeArray[index]}}</text>
            <view
                class="uv-code-input__item__line"
                v-if="mode === 'line'"
                :style="[lineStyle]"
            ></view>
            <!-- #ifndef APP-PLUS -->
            <view v-if="isFocus && codeArray.length === index" :style="{backgroundColor: color}" class="uv-code-input__item__cursor"></view>
            <!-- #endif -->
        </view>
        <input
            :disabled="disabledKeyboard"
            type="number"
            :focus="focus"
            :value="inputValue"
            :maxlength="maxlength"
            :adjustPosition="adjustPosition"
            class="uv-code-input__input"
            @input="inputHandler"
            :style="{
                height: $uv.addUnit(size)
            }"
            @focus="isFocus = true"
            @blur="isFocus = false"
        />
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * CodeInput 验证码输入
     * @description 该组件一般用于验证用户短信验证码的场景,也可以结合uvui的键盘组件使用
     * @tutorial https://www.uvui.cn/components/codeInput.html
     * @property {String | Number}  value / v-model             预置值
     * @property {String | Number}  maxlength           最大输入长度 (默认 6 )
     * @property {Boolean}          dot                 是否用圆点填充 (默认 false )
     * @property {String}           mode                显示模式,box-盒子模式,line-底部横线模式 (默认 'box' )
     * @property {Boolean}          hairline            是否细边框 (默认 false )
     * @property {String | Number}  space               字符间的距离 (默认 10 )
     * @property {Boolean}          focus               是否自动获取焦点 (默认 false )
     * @property {Boolean}          bold                字体和输入横线是否加粗 (默认 false )
     * @property {String}           color               字体颜色 (默认 '#606266' )
     * @property {String | Number}  fontSize            字体大小,单位px (默认 18 )
     * @property {String | Number}  size                输入框的大小,宽等于高 (默认 35 )
     * @property {Boolean}          disabledKeyboard    是否隐藏原生键盘,如果想用自定义键盘的话,需设置此参数为true (默认 false )
     * @property {String}           borderColor         边框和线条颜色 (默认 '#c9cacc' )
     * @property {Boolean}          disabledDot         是否禁止输入"."符号 (默认 true )
     *
     * @event {Function}    change  输入内容发生改变时触发,具体见上方说明         value:当前输入的值
     * @event {Function}    finish  输入字符个数达maxlength值时触发,见上方说明  value:当前输入的值
     * @example <uv-code-input v-model="value4" :focus="true"></uv-code-input>
     */
    export default {
        name: 'uv-code-input',
        mixins: [mpMixin, mixin, props],
        data() {
            return {
                inputValue: '',
                isFocus: this.focus
            }
        },
        created() {
            const value = String(this.value) || String(this.modelValue);
            this.inputValue = String(value).substring(0, this.maxlength);
        },
        watch: {
            value(newVal) {
                // 转为字符串,超出部分截掉
                this.inputValue = String(newVal).substring(0, this.maxlength);
                if (this.disabledKeyboard) {
                    this.customInput();
                }
            },
            modelValue(newVal) {
                // 转为字符串,超出部分截掉
                this.inputValue = String(newVal).substring(0, this.maxlength);
                if (this.disabledKeyboard) {
                    this.customInput();
                }
            }
        },
        computed: {
            // 根据长度,循环输入框的个数,因为头条小程序数值不能用于v-for
            codeLength() {
                return new Array(Number(this.maxlength))
            },
            // 循环item的样式
            itemStyle() {
                return index => {
                    const addUnit = this.$uv.addUnit
                    const style = {
                        width: addUnit(this.size),
                        height: addUnit(this.size)
                    }
                    // 盒子模式下,需要额外进行处理
                    if (this.mode === 'box') {
                        // 设置盒子的边框,如果是细边框,则设置为0.5px宽度
                        style.border = `${this.hairline ? 0.5 : 1}px solid ${this.borderColor}`
                        // 如果盒子间距为0的话
                        if (this.$uv.getPx(this.space) === 0) {
                            // 给第一和最后一个盒子设置圆角
                            if (index === 0) {
                                style.borderTopLeftRadius = '3px'
                                style.borderBottomLeftRadius = '3px'
                            }
                            if (index === this.codeLength.length - 1) {
                                style.borderTopRightRadius = '3px'
                                style.borderBottomRightRadius = '3px'
                            }
                            // 最后一个盒子的右边框需要保留
                            if (index !== this.codeLength.length - 1) {
                                style.borderRight = 'none'
                            }
                        }
                    }
                    if (index !== this.codeLength.length - 1) {
                        // 设置验证码字符之间的距离,通过margin-right设置,最后一个字符,无需右边框
                        style.marginRight = addUnit(this.space)
                    } else {
                        // 最后一个盒子的有边框需要保留
                        style.marginRight = 0
                    }
                    return style
                }
            },
            // 将输入的值,转为数组,给item历遍时,根据当前的索引显示数组的元素
            codeArray() {
                return String(this.inputValue).split('')
            },
            // 下划线模式下,横线的样式
            lineStyle() {
                const style = {}
                style.height = this.hairline ? '1px' : '4px'
                style.width = this.$uv.addUnit(this.size)
                // 线条模式下,背景色即为边框颜色
                style.backgroundColor = this.borderColor
                return style
            }
        },
        methods: {
            // 监听输入框的值发生变化
            inputHandler(e) {
                const value = e.detail.value
                this.inputValue = value
                // 是否允许输入“.”符号
                if (this.disabledDot) {
                    this.$nextTick(() => {
                        this.inputValue = value.replace('.', '')
                    })
                }
                // 未达到maxlength之前,发送change事件,达到后发送finish事件
                this.$emit('change', value)
                // 修改通过v-model双向绑定的值
                this.$emit('input', value)
                this.$emit('update:modelValue', value)
                // 达到用户指定输入长度时,发出完成事件
                if (String(value).length >= Number(this.maxlength)) {
                    this.$emit('finish', value)
                }
            },
            // 自定义键盘输入值监听
            customInput() {
                const value = this.inputValue;
                // 是否允许输入“.”符号
                if (this.disabledDot) {
                    this.$nextTick(() => {
                        this.inputValue = value.replace('.', '')
                    })
                }
                // 未达到maxlength之前,发送change事件,达到后发送finish事件
                this.$emit('change', value)
                // 达到用户指定输入长度时,发出完成事件
                if (String(value).length >= Number(this.maxlength)) {
                    this.$emit('finish', value)
                }
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    $uv-code-input-cursor-width: 1px;
    $uv-code-input-cursor-height: 40%;
    $uv-code-input-cursor-animation-duration: 1s;
    $uv-code-input-cursor-animation-name: uv-cursor-flicker;
    .uv-code-input {
        @include flex;
        position: relative;
        overflow: hidden;
        &__item {
            @include flex;
            justify-content: center;
            align-items: center;
            position: relative;
            &__text {
                font-size: 15px;
                color: $uv-content-color;
            }
            &__dot {
                width: 7px;
                height: 7px;
                border-radius: 100px;
                background-color: $uv-content-color;
            }
            &__line {
                position: absolute;
                bottom: 0;
                height: 4px;
                border-radius: 100px;
                width: 40px;
                background-color: $uv-content-color;
            }
            /* #ifndef APP-PLUS */
            &__cursor {
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                width: $uv-code-input-cursor-width;
                height: $uv-code-input-cursor-height;
                animation: $uv-code-input-cursor-animation-duration uv-cursor-flicker infinite;
            }
            /* #endif */
        }
        &__input {
            // 之所以需要input输入框,是因为有它才能唤起键盘
            // 这里将它设置为两倍的屏幕宽度,再将左边的一半移出屏幕,为了不让用户看到输入的内容
            position: absolute;
            left: -750rpx;
            width: 1500rpx;
            top: 0;
            background-color: transparent;
            text-align: left;
        }
    }
    /* #ifndef APP-PLUS */
    @keyframes uv-cursor-flicker {
        0% {
            opacity: 0;
        }
        50% {
            opacity: 1;
        }
        100% {
            opacity: 0;
        }
    }
    /* #endif */
</style>
ledApp/uni_modules/uv-code-input/package.json
New file
@@ -0,0 +1,87 @@
{
  "id": "uv-code-input",
  "displayName": "uv-code-input 验证码输入 全面兼容vue3+2、app、h5、小程序等多端",
  "version": "1.0.5",
  "description": "验证码输入组件一般用于验证用户短信验证码的场景,输入框或横线多种模式可选。",
  "keywords": [
    "uv-code-input",
    "uvui",
    "uv-ui",
    "code",
    "验证码输入"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-code-input/readme.md
New file
@@ -0,0 +1,19 @@
## CodeInput 验证码输入框
> **组件名:uv-code-input**
该组件一般用于验证用户短信验证码的场景,输入框或横线多种模式可选。
# <a href="https://www.uvui.cn/components/codeInput.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>(请不要 下载插件ZIP)</small>
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
</a>
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-code/changelog.md
New file
@@ -0,0 +1,9 @@
## 1.0.3(2023-10-13)
1. 优化
## 1.0.2(2023-10-13)
1. unmounted兼容vue3
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-code 验证码倒计时
ledApp/uni_modules/uv-code/components/uv-code/props.js
New file
@@ -0,0 +1,35 @@
export default {
    props: {
        // 倒计时总秒数
        seconds: {
            type: [String, Number],
            default: 60
        },
        // 尚未开始时提示
        startText: {
            type: String,
            default: '获取验证码'
        },
        // 正在倒计时中的提示
        changeText: {
            type: String,
            default: 'X秒重新获取'
        },
        // 倒计时结束时的提示
        endText: {
            type: String,
            default: '重新获取'
        },
        // 是否在H5刷新或各端返回再进入时继续倒计时
        keepRunning: {
            type: Boolean,
            default: false
        },
        // 为了区分多个页面,或者一个页面多个倒计时组件本地存储的继续倒计时变了
        uniqueKey: {
            type: String,
            default: ''
        },
        ...uni.$uv?.props?.code
    }
}
ledApp/uni_modules/uv-code/components/uv-code/uv-code.vue
New file
@@ -0,0 +1,136 @@
<template>
    <view class="uv-code">
        <!-- 此组件功能由js完成,无需写html逻辑 -->
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * Code 验证码倒计时
     * @description 考虑到用户实际发送验证码的场景,可能是一个按钮,也可能是一段文字,提示语各有不同,所以本组件不提供界面显示,只提供倒计时文本,由用户将文本嵌入到具体的场景
     * @tutorial https://www.uvui.cn/components/code.html
     * @property {String | Number}  seconds         倒计时所需的秒数(默认 60 )
     * @property {String}           startText       开始前的提示语,见官网说明(默认 '获取验证码' )
     * @property {String}           changeText      倒计时期间的提示语,必须带有字母"x",见官网说明(默认 'X秒重新获取' )
     * @property {String}           endText         倒计结束的提示语,见官网说明(默认 '重新获取' )
     * @property {Boolean}          keepRunning     是否在H5刷新或各端返回再进入时继续倒计时( 默认false )
     * @property {String}           uniqueKey       为了区分多个页面,或者一个页面多个倒计时组件本地存储的继续倒计时变了
     *
     * @event {Function}    change  倒计时期间,每秒触发一次
     * @event {Function}    start   开始倒计时触发
     * @event {Function}    end     结束倒计时触发
     * @example <uv-code ref="uCode" @change="codeChange" seconds="20"></uv-code>
     */
    export default {
        name: "uv-code",
        mixins: [mpMixin, mixin, props],
        data() {
            return {
                secNum: this.seconds,
                timer: null,
                canGetCode: true, // 是否可以执行验证码操作
            }
        },
        mounted() {
            this.checkKeepRunning()
        },
        watch: {
            seconds: {
                immediate: true,
                handler(n) {
                    this.secNum = n
                }
            }
        },
        methods: {
            checkKeepRunning() {
                // 获取上一次退出页面(H5还包括刷新)时的时间戳,如果没有上次的保存,此值可能为空
                let lastTimestamp = Number(uni.getStorageSync(this.uniqueKey + '_$uCountDownTimestamp'))
                if (!lastTimestamp) return this.changeEvent(this.startText)
                // 当前秒的时间戳
                let nowTimestamp = Math.floor((+new Date()) / 1000)
                // 判断当前的时间戳,是否小于上一次的本该按设定结束,却提前结束的时间戳
                if (this.keepRunning && lastTimestamp && lastTimestamp > nowTimestamp) {
                    // 剩余尚未执行完的倒计秒数
                    this.secNum = lastTimestamp - nowTimestamp
                    // 清除本地保存的变量
                    uni.removeStorageSync(this.uniqueKey + '_$uCountDownTimestamp')
                    // 开始倒计时
                    this.start()
                } else {
                    // 如果不存在需要继续上一次的倒计时,执行正常的逻辑
                    this.changeEvent(this.startText)
                }
            },
            // 开始倒计时
            start() {
                // 防止快速点击获取验证码的按钮而导致内部产生多个定时器导致混乱
                if (this.timer) {
                    clearInterval(this.timer)
                    this.timer = null
                }
                this.$emit('start')
                this.canGetCode = false
                // 这里放这句,是为了一开始时就提示,否则要等setInterval的1秒后才会有提示
                this.changeEvent(this.changeText.replace(/x|X/, this.secNum))
                this.timer = setInterval(() => {
                    if (--this.secNum) {
                        // 用当前倒计时的秒数替换提示字符串中的"x"字母
                        this.changeEvent(this.changeText.replace(/x|X/, this.secNum))
                    } else {
                        clearInterval(this.timer)
                        this.timer = null
                        this.changeEvent(this.endText)
                        this.secNum = this.seconds
                        this.$emit('end')
                        this.canGetCode = true
                    }
                }, 1000)
                this.setTimeToStorage()
            },
            // 重置,可以让用户再次获取验证码
            reset() {
                this.canGetCode = true
                clearInterval(this.timer)
                this.secNum = this.seconds
                this.changeEvent(this.endText)
            },
            changeEvent(text) {
                this.$emit('change', text)
            },
            // 保存时间戳,为了防止倒计时尚未结束,H5刷新或者各端的右上角返回上一页再进来
            setTimeToStorage() {
                if (!this.keepRunning || !this.timer) return
                // 记录当前的时间戳,为了下次进入页面,如果还在倒计时内的话,继续倒计时
                // 倒计时尚未结束,结果大于0;倒计时已经开始,就会小于初始值,如果等于初始值,说明没有开始倒计时,无需处理
                if (this.secNum > 0 && this.secNum <= this.seconds) {
                    // 获取当前时间戳(+ new Date()为特殊写法),除以1000变成秒,再去除小数部分
                    let nowTimestamp = Math.floor((+new Date()) / 1000)
                    // 将本该结束时候的时间戳保存起来 => 当前时间戳 + 剩余的秒数
                    uni.setStorage({
                        key: this.uniqueKey + '_$uCountDownTimestamp',
                        data: nowTimestamp + Number(this.secNum)
                    })
                }
            }
        },
        // #ifdef VUE2
        // 组件销毁的时候,清除定时器,否则定时器会继续存在,系统不会自动清除
        beforeDestroy() {
            this.setTimeToStorage()
            clearTimeout(this.timer)
            this.timer = null
        },
        // #endif
        // #ifdef VUE3
        // 组件销毁,兼容vue3
        unmounted() {
            this.setTimeToStorage()
            clearTimeout(this.timer)
            this.timer = null
        }
        // #endif
    }
</script>
ledApp/uni_modules/uv-code/package.json
New file
@@ -0,0 +1,87 @@
{
  "id": "uv-code",
  "displayName": "uv-code 验证码倒计时 全面兼容小程序、nvue、vue2、vue3等多端",
  "version": "1.0.3",
  "description": "考虑到用户实际发送验证码的场景,可能是一个按钮,也可能是一段文字,提示语各有不同,所以本组件不提供界面显示,只提供倒计时文本,由用户将文本嵌入到具体的场景。",
  "keywords": [
    "uv-code",
    "uvui",
    "uv-ui",
    "code",
    "验证码倒计时"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-code/readme.md
New file
@@ -0,0 +1,11 @@
## Code 验证码输入框
> **组件名:uv-code**
考虑到用户实际发送验证码的场景,可能是一个按钮,也可能是一段文字,提示语各有不同,所以本组件不提供界面显示,只提供倒计时文本,由用户将文本嵌入到具体的场景。
### <a href="https://www.uvui.cn/components/code.html" target="_blank">查看文档</a>
### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)
#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-collapse/changelog.md
New file
@@ -0,0 +1,5 @@
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-collapse 折叠面板
ledApp/uni_modules/uv-collapse/components/uv-collapse-item/props.js
New file
@@ -0,0 +1,60 @@
export default {
    props: {
        // 标题
        title: {
            type: String,
            default: ''
        },
        // 标题右侧内容
        value: {
            type: String,
            default: ''
        },
        // 标题下方的描述信息
        label: {
            type: String,
            default: ''
        },
        // 是否禁用折叠面板
        disabled: {
            type: Boolean,
            default: false
        },
        // 是否展示右侧箭头并开启点击反馈
        isLink: {
            type: Boolean,
            default: true
        },
        // 是否开启点击反馈
        clickable: {
            type: Boolean,
            default: true
        },
        // 是否显示内边框
        border: {
            type: Boolean,
            default: true
        },
        // 标题的对齐方式
        align: {
            type: String,
            default: 'left'
        },
        // 唯一标识符
        name: {
            type: [String, Number],
            default: ''
        },
        // 标题左侧图片,可为绝对路径的图片或内置图标
        icon: {
            type: String,
            default: ''
        },
        // 面板展开收起的过渡时间,单位ms
        duration: {
            type: Number,
            default: 300
        },
        ...uni.$uv?.props?.collapseItem
    }
}
ledApp/uni_modules/uv-collapse/components/uv-collapse-item/uv-collapse-item.vue
New file
@@ -0,0 +1,229 @@
<template>
    <view class="uv-collapse-item">
        <uv-cell
            :title="title"
            :value="value"
            :label="label"
            :icon="icon"
            :isLink="isLink"
            :clickable="clickable"
            :border="parentData.border && showBorder"
            @click="clickHandler"
            :arrowDirection="expanded ? 'up' : 'down'"
            :disabled="disabled"
        >
            <!-- #ifndef MP-WEIXIN -->
            <!-- 微信小程序不支持,因为微信中不支持 <slot name="title" slot="title" />的写法 -->
            <template slot="title">
                <slot name="title"></slot>
            </template>
            <template slot="icon">
                <slot name="icon"></slot>
            </template>
            <template slot="value">
                <slot name="value"></slot>
            </template>
            <template slot="right-icon">
                <slot name="right-icon"></slot>
            </template>
            <!-- #endif -->
        </uv-cell>
        <view
            class="uv-collapse-item__content"
            :animation="animationData"
            ref="animation"
        >
            <view
                class="uv-collapse-item__content__text content-class"
                :id="elId"
                :ref="elId"
            ><slot /></view>
        </view>
        <uv-line v-if="parentData.border"></uv-line>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    // #ifdef APP-NVUE
    const animation = uni.requireNativePlugin('animation')
    const dom = uni.requireNativePlugin('dom')
    // #endif
    /**
     * collapseItem 折叠面板Item
     * @description 通过折叠面板收纳内容区域(搭配uv-collapse使用)
     * @tutorial https://www.uvui.cn/components/collapse.html
     * @property {String}           title       标题
     * @property {String}           value       标题右侧内容
     * @property {String}           label       标题下方的描述信息
     * @property {Boolean}          disbled     是否禁用折叠面板 ( 默认 false )
     * @property {Boolean}          isLink      是否展示右侧箭头并开启点击反馈 ( 默认 true )
     * @property {Boolean}          clickable   是否开启点击反馈 ( 默认 true )
     * @property {Boolean}          border      是否显示内边框 ( 默认 true )
     * @property {String}           align       标题的对齐方式 ( 默认 'left' )
     * @property {String | Number}  name        唯一标识符
     * @property {String}           icon        标题左侧图片,可为绝对路径的图片或内置图标
     * @event {Function}            change          某个item被打开或者收起时触发
     * @example <uv-collapse-item :title="item.head" v-for="(item, index) in itemList" :key="index">{{item.body}}</uv-collapse-item>
     */
    export default {
        name: "uv-collapse-item",
        mixins: [mpMixin, mixin, props],
        data() {
            return {
                elId: '',
                // uni.createAnimation的导出数据
                animationData: {},
                // 是否展开状态
                expanded: false,
                // 根据expanded确定是否显示border,为了控制展开时,cell的下划线更好的显示效果,进行一定时间的延时
                showBorder: false,
                // 是否动画中,如果是则不允许继续触发点击
                animating: false,
                // 父组件uv-collapse的参数
                parentData: {
                    accordion: false,
                    border: false
                }
            };
        },
        watch: {
            expanded(n) {
                clearTimeout(this.timer)
                this.timer = null
                // 这里根据expanded的值来进行一定的延时,是为了cell的下划线更好的显示效果
                this.timer = setTimeout(() => {
                    this.showBorder = n
                }, n ? 10 : 290)
            }
        },
        created() {
            this.elId = this.$uv.guid();
        },
        mounted() {
            this.init()
        },
        methods: {
            // 异步获取内容,或者动态修改了内容时,需要重新初始化
            init() {
                // 初始化数据
                this.updateParentData()
                if (!this.parent) {
                    return this.$uv.error('uv-collapse-item必须要搭配uv-collapse组件使用')
                }
                const {
                    value,
                    accordion,
                    children = []
                } = this.parent
                if (accordion) {
                    if (this.$uv.test.array(value)) {
                        return this.$uv.error('手风琴模式下,uv-collapse组件的value参数不能为数组')
                    }
                    this.expanded = this.name == value
                } else {
                    if (!this.$uv.test.array(value) && value !== null) {
                        return this.$uv.error('非手风琴模式下,uv-collapse组件的value参数必须为数组')
                    }
                    this.expanded = (value || []).some(item => item == this.name)
                }
                // 设置组件的展开或收起状态
                this.$nextTick(function() {
                    this.setContentAnimate()
                })
            },
            updateParentData() {
                // 此方法在mixin中
                this.getParentData('uv-collapse')
            },
            async setContentAnimate() {
                // 每次面板打开或者收起时,都查询元素尺寸
                // 好处是,父组件从服务端获取内容后,变更折叠面板后可以获得最新的高度
                const rect = await this.queryRect()
                const height = this.expanded ? rect.height : 0
                this.animating = true
                // #ifdef APP-NVUE
                const ref = this.$refs['animation'].ref
                animation.transition(ref, {
                    styles: {
                        height: height + 'px'
                    },
                    duration: this.duration,
                    // 必须设置为true,否则会到面板收起或展开时,页面其他元素不会随之调整它们的布局
                    needLayout: true,
                    timingFunction: 'ease-in-out',
                }, () => {
                    this.animating = false
                })
                // #endif
                // #ifndef APP-NVUE
                const animation = uni.createAnimation({
                    timingFunction: 'ease-in-out',
                });
                animation
                    .height(height)
                    .step({
                        duration: this.duration,
                    })
                    .step()
                // 导出动画数据给面板的animationData值
                this.animationData = animation.export()
                // 标识动画结束
                this.$uv.sleep(this.duration).then(() => {
                    this.animating = false
                })
                // #endif
            },
            // 点击collapsehead头部
            clickHandler() {
                if (this.disabled && this.animating) return
                // 设置本组件为相反的状态
                this.parent && this.parent.onChange(this)
            },
            // 查询内容高度
            queryRect() {
                // #ifndef APP-NVUE
                // 组件内部一般用this.$uvGetRect,对外的为getRect,二者功能一致,名称不同
                return new Promise(resolve => {
                    this.$uvGetRect(`#${this.elId}`).then(size => {
                        resolve(size)
                    })
                })
                // #endif
                // #ifdef APP-NVUE
                // nvue下,使用dom模块查询元素高度
                // 返回一个promise,让调用此方法的主体能使用then回调
                return new Promise(resolve => {
                    dom.getComponentRect(this.$refs[this.elId], res => {
                        resolve(res.size)
                    })
                })
                // #endif
            }
        },
    };
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    .uv-collapse-item {
        &__content {
            overflow: hidden;
            height: 0;
            &__text {
                padding: 12px 15px;
                color: $uv-content-color;
                font-size: 14px;
                line-height: 18px;
            }
        }
    }
</style>
ledApp/uni_modules/uv-collapse/components/uv-collapse/props.js
New file
@@ -0,0 +1,20 @@
export default {
    props: {
        // 当前展开面板的name,非手风琴模式:[<string | number>],手风琴模式:string | number
        value: {
            type: [String, Number, Array, null],
            default: null
        },
        // 是否手风琴模式
        accordion: {
            type: Boolean,
            default: false
        },
        // 是否显示外边框
        border: {
            type: Boolean,
            default: true
        },
        ...uni.$uv?.props?.collapse
    }
}
ledApp/uni_modules/uv-collapse/components/uv-collapse/uv-collapse.vue
New file
@@ -0,0 +1,86 @@
<template>
    <view class="uv-collapse">
        <uv-line v-if="border"></uv-line>
        <slot />
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * collapse 折叠面板
     * @description 通过折叠面板收纳内容区域
     * @tutorial https://www.uvui.cn/components/collapse.html
     * @property {String | Number | Array}  value       当前展开面板的name,非手风琴模式:[<string | number>],手风琴模式:string | number
     * @property {Boolean}                  accordion   是否手风琴模式( 默认 false )
     * @property {Boolean}                  border      是否显示外边框 ( 默认 true )
     * @event {Function}    change      当前激活面板展开时触发(如果是手风琴模式,参数activeNames类型为String,否则为Array)
     * @example <uv-collapse></uv-collapse>
     */
    export default {
        name: "uv-collapse",
        mixins: [mpMixin, mixin, props],
        watch: {
            needInit() {
                this.init()
            },
            // 当父组件需要子组件需要共享的参数发生了变化,手动通知子组件
            parentData() {
                if (this.children.length) {
                    this.children.map(child => {
                        // 判断子组件(uv-checkbox)如果有updateParentData方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
                        typeof(child.updateParentData) === 'function' && child.updateParentData()
                    })
                }
            }
        },
        created() {
            this.children = []
        },
        computed: {
            needInit() {
                // 通过computed,同时监听accordion和value值的变化
                // 再通过watch去执行init()方法,进行再一次的初始化
                return [this.accordion, this.value]
            }
        },
        methods: {
            // 重新初始化一次内部的所有子元素
            init() {
                this.children.map(child => {
                    child.init()
                })
            },
            /**
             * collapse-item被点击时触发,由collapse统一处理各子组件的状态
             * @param {Object} target 被操作的面板的实例
             */
            onChange(target) {
                let changeArr = []
                this.children.map((child, index) => {
                    // 如果是手风琴模式,将其他的折叠面板收起来
                    if (this.accordion) {
                        child.expanded = child === target ? !target.expanded : false
                        child.setContentAnimate()
                    } else {
                        if(child === target) {
                            child.expanded = !child.expanded
                            child.setContentAnimate()
                        }
                    }
                    // 拼接change事件中,数组元素的状态
                    changeArr.push({
                        // 如果没有定义name属性,则默认返回组件的index索引
                        name: child.name || index,
                        status: child.expanded ? 'open' : 'close'
                    })
                })
                this.$emit('change', changeArr)
                this.$emit(target.expanded ? 'open' : 'close', target.name)
            }
        }
    }
</script>
ledApp/uni_modules/uv-collapse/package.json
New file
@@ -0,0 +1,89 @@
{
  "id": "uv-collapse",
  "displayName": "uv-collapse 折叠面板 全面兼容小程序、nvue、vue2、vue3等多端",
  "version": "1.0.1",
  "description": "折叠面板组件,通过折叠面板收纳内容区域,点击可展开收起,多功能参数可配置。",
  "keywords": [
    "uv-collapse",
    "uvui",
    "uv-ui",
    "collapse",
    "折叠面板"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools",
            "uv-line",
            "uv-cell"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-collapse/readme.md
New file
@@ -0,0 +1,11 @@
## Collapse 折叠面板
> **组件名:uv-collapse**
通过折叠面板收纳内容区域,点击可展开收起,多功能参数可配置。
### <a href="https://www.uvui.cn/components/collapse.html" target="_blank">查看文档</a>
### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)
#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-count-down/changelog.md
New file
@@ -0,0 +1,9 @@
## 1.0.3(2023-10-13)
1. unmounted兼容vue3
## 1.0.2(2023-06-20)
1. 增加外部样式customStyle参数
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-count-down 倒计时
ledApp/uni_modules/uv-count-down/components/uv-count-down/props.js
New file
@@ -0,0 +1,25 @@
export default {
    props: {
        // 倒计时时长,单位ms
        time: {
            type: [String, Number],
            default: 0
        },
        // 时间格式,DD-日,HH-时,mm-分,ss-秒,SSS-毫秒
        format: {
            type: String,
            default: 'HH:mm:ss'
        },
        // 是否自动开始倒计时
        autoStart: {
            type: Boolean,
            default: true
        },
        // 是否展示毫秒倒计时
        millisecond: {
            type: Boolean,
            default: false
        },
        ...uni.$uv?.props?.countDown
    }
}
ledApp/uni_modules/uv-count-down/components/uv-count-down/utils.js
New file
@@ -0,0 +1,62 @@
// 补0,如1 -> 01
function padZero(num, targetLength = 2) {
    let str = `${num}`
    while (str.length < targetLength) {
        str = `0${str}`
    }
    return str
}
const SECOND = 1000
const MINUTE = 60 * SECOND
const HOUR = 60 * MINUTE
const DAY = 24 * HOUR
export function parseTimeData(time) {
    const days = Math.floor(time / DAY)
    const hours = Math.floor((time % DAY) / HOUR)
    const minutes = Math.floor((time % HOUR) / MINUTE)
    const seconds = Math.floor((time % MINUTE) / SECOND)
    const milliseconds = Math.floor(time % SECOND)
    return {
        days,
        hours,
        minutes,
        seconds,
        milliseconds
    }
}
export function parseFormat(format, timeData) {
    let {
        days,
        hours,
        minutes,
        seconds,
        milliseconds
    } = timeData
    // 如果格式化字符串中不存在DD(天),则将天的时间转为小时中去
    if (format.indexOf('DD') === -1) {
        hours += days * 24
    } else {
        // 对天补0
        format = format.replace('DD', padZero(days))
    }
    // 其他同理于DD的格式化处理方式
    if (format.indexOf('HH') === -1) {
        minutes += hours * 60
    } else {
        format = format.replace('HH', padZero(hours))
    }
    if (format.indexOf('mm') === -1) {
        seconds += minutes * 60
    } else {
        format = format.replace('mm', padZero(minutes))
    }
    if (format.indexOf('ss') === -1) {
        milliseconds += seconds * 1000
    } else {
        format = format.replace('ss', padZero(seconds))
    }
    return format.replace('SSS', padZero(milliseconds, 3))
}
export function isSameSecond(time1, time2) {
    return Math.floor(time1 / 1000) === Math.floor(time2 / 1000)
}
ledApp/uni_modules/uv-count-down/components/uv-count-down/uv-count-down.vue
New file
@@ -0,0 +1,169 @@
<template>
    <view
        class="uv-count-down"
        :style="[$uv.addStyle(customStyle)]">
        <slot>
            <text class="uv-count-down__text">{{ formattedTime }}</text>
        </slot>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    import {
        isSameSecond,
        parseFormat,
        parseTimeData
    } from './utils';
    /**
     * uv-count-down 倒计时
     * @description 该组件一般使用于某个活动的截止时间上,通过数字的变化,给用户明确的时间感受,提示用户进行某一个行为操作。
     * @tutorial https://www.uvui.cn/components/countDown.html
     * @property {String | Number}  time        倒计时时长,单位ms (默认 0 )
     * @property {String}           format      时间格式,DD-日,HH-时,mm-分,ss-秒,SSS-毫秒  (默认 'HH:mm:ss' )
     * @property {Boolean}          autoStart   是否自动开始倒计时 (默认 true )
     * @property {Boolean}          millisecond 是否展示毫秒倒计时 (默认 false )
     * @event {Function} finish 倒计时结束时触发
     * @event {Function} change 倒计时变化时触发
     * @event {Function} start  开始倒计时
     * @event {Function} pause  暂停倒计时
     * @event {Function} reset  重设倒计时,若 auto-start 为 true,重设后会自动开始倒计时
     * @example <uv-count-down :time="time"></uv-count-down>
     */
    export default {
        name: 'uv-count-down',
        mixins: [mpMixin, mixin, props],
        data() {
            return {
                timer: null,
                // 各单位(天,时,分等)剩余时间
                timeData: parseTimeData(0),
                // 格式化后的时间,如"03:23:21"
                formattedTime: '0',
                // 倒计时是否正在进行中
                runing: false,
                endTime: 0, // 结束的毫秒时间戳
                remainTime: 0, // 剩余的毫秒时间
            }
        },
        watch: {
            time(n) {
                this.reset()
            }
        },
        mounted() {
            this.init()
        },
        methods: {
            init() {
                this.reset()
            },
            // 开始倒计时
            start() {
                if (this.runing) return
                // 标识为进行中
                this.runing = true
                // 结束时间戳 = 此刻时间戳 + 剩余的时间
                this.endTime = Date.now() + this.remainTime
                this.toTick()
            },
            // 根据是否展示毫秒,执行不同操作函数
            toTick() {
                if (this.millisecond) {
                    this.microTick()
                } else {
                    this.macroTick()
                }
            },
            macroTick() {
                this.clearTimeout()
                // 每隔一定时间,更新一遍定时器的值
                // 同时此定时器的作用也能带来毫秒级的更新
                this.timer = setTimeout(() => {
                    // 获取剩余时间
                    const remain = this.getRemainTime()
                    // 重设剩余时间
                    if (!isSameSecond(remain, this.remainTime) || remain === 0) {
                        this.setRemainTime(remain)
                    }
                    // 如果剩余时间不为0,则继续检查更新倒计时
                    if (this.remainTime !== 0) {
                        this.macroTick()
                    }
                }, 30)
            },
            microTick() {
                this.clearTimeout()
                this.timer = setTimeout(() => {
                    this.setRemainTime(this.getRemainTime())
                    if (this.remainTime !== 0) {
                        this.microTick()
                    }
                }, 50)
            },
            // 获取剩余的时间
            getRemainTime() {
                // 取最大值,防止出现小于0的剩余时间值
                return Math.max(this.endTime - Date.now(), 0)
            },
            // 设置剩余的时间
            setRemainTime(remain) {
                this.remainTime = remain
                // 根据剩余的毫秒时间,得出该有天,小时,分钟等的值,返回一个对象
                const timeData = parseTimeData(remain)
                this.$emit('change', timeData)
                // 得出格式化后的时间
                this.formattedTime = parseFormat(this.format, timeData)
                // 如果时间已到,停止倒计时
                if (remain <= 0) {
                    this.pause()
                    this.$emit('finish')
                }
            },
            // 重置倒计时
            reset() {
                this.pause()
                this.remainTime = this.time
                this.setRemainTime(this.remainTime)
                if (this.autoStart) {
                    this.start()
                }
            },
            // 暂停倒计时
            pause() {
                this.runing = false;
                this.clearTimeout()
            },
            // 清空定时器
            clearTimeout() {
                clearTimeout(this.timer)
                this.timer = null
            }
        },
        // #ifdef VUE2
        beforeDestroy() {
            this.clearTimeout()
        },
        // #endif
        // #ifdef VUE3
        unmounted() {
            this.clearTimeout()
        }
        // #endif
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    $uv-count-down-text-color: $uv-content-color !default;
    $uv-count-down-text-font-size: 15px !default;
    $uv-count-down-text-line-height: 22px !default;
    .uv-count-down {
        &__text {
            color: $uv-count-down-text-color;
            font-size: $uv-count-down-text-font-size;
            line-height: $uv-count-down-text-line-height;
        }
    }
</style>
ledApp/uni_modules/uv-count-down/package.json
New file
@@ -0,0 +1,87 @@
{
  "id": "uv-count-down",
  "displayName": "uv-count-down 倒计时 全面兼容小程序、nvue、vue2、vue3等多端",
  "version": "1.0.3",
  "description": "该倒计时组件一般使用于某个活动的截止时间上,通过数字的变化,给用户明确的时间感受,提示用户进行某一个行为操作。",
  "keywords": [
    "uv-count-down",
    "uvui",
    "uv-ui",
    "countDown",
    "倒计时"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-count-down/readme.md
New file
@@ -0,0 +1,11 @@
## CountDown 倒计时
> **组件名:uv-count-down**
该组件一般使用于某个活动的截止时间上,通过数字的变化,给用户明确的时间感受,提示用户进行某一个行为操作。
### <a href="https://www.uvui.cn/components/countDown.html" target="_blank">查看文档</a>
### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)
#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-count-to/changelog.md
New file
@@ -0,0 +1,13 @@
## 1.0.4(2023-06-20)
1. 优化
## 1.0.3(2023-06-20)
1. 修复继续滚动的函数
2. 修复其他
## 1.0.2(2023-06-20)
1. 适配px和rpx的单位
2. 适配customStyle参数
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-count-to 数字滚动
ledApp/uni_modules/uv-count-to/components/uv-count-to/props.js
New file
@@ -0,0 +1,60 @@
export default {
    props: {
        // 开始的数值,默认从0增长到某一个数
        startVal: {
            type: [String, Number],
            default: 0
        },
        // 要滚动的目标数值,必须
        endVal: {
            type: [String, Number],
            default: 0
        },
        // 滚动到目标数值的动画持续时间,单位为毫秒(ms)
        duration: {
            type: [String, Number],
            default: 2000
        },
        // 设置数值后是否自动开始滚动
        autoplay: {
            type: Boolean,
            default: true
        },
        // 要显示的小数位数
        decimals: {
            type: [String, Number],
            default: 0
        },
        // 是否在即将到达目标数值的时候,使用缓慢滚动的效果
        useEasing: {
            type: Boolean,
            default: true
        },
        // 十进制分割
        decimal: {
            type: [String, Number],
            default: '.'
        },
        // 字体颜色
        color: {
            type: String,
            default: '#606266'
        },
        // 字体大小
        fontSize: {
            type: [String, Number],
            default: 22
        },
        // 是否加粗字体
        bold: {
            type: Boolean,
            default: false
        },
        // 千位分隔符,类似金额的分割(¥23,321.05中的",")
        separator: {
            type: String,
            default: ''
        },
        ...uni.$uv?.props?.countTo
    }
}
ledApp/uni_modules/uv-count-to/components/uv-count-to/uv-count-to.vue
New file
@@ -0,0 +1,187 @@
<template>
    <text
        class="uv-count-num"
        :style="[{
            fontSize: $uv.addUnit(fontSize),
            fontWeight: bold ? 'bold' : 'normal',
            color: color
        },$uv.addStyle(customStyle)]"
    >{{ displayValue }}</text>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
/**
 * countTo 数字滚动
 * @description 该组件一般用于需要滚动数字到某一个值的场景,目标要求是一个递增的值。
 * @tutorial https://www.uvui.cn/components/countTo.html
 * @property {String | Number}  startVal    开始的数值,默认从0增长到某一个数(默认 0 )
 * @property {String | Number}  endVal      要滚动的目标数值,必须 (默认 0 )
 * @property {String | Number}  duration    滚动到目标数值的动画持续时间,单位为毫秒(ms) (默认 2000 )
 * @property {Boolean}          autoplay    设置数值后是否自动开始滚动 (默认 true )
 * @property {String | Number}  decimals    要显示的小数位数,见官网说明(默认 0 )
 * @property {Boolean}          useEasing   滚动结束时,是否缓动结尾,见官网说明(默认 true )
 * @property {String}           decimal     十进制分割 ( 默认 "." )
 * @property {String}           color       字体颜色( 默认 '#606266' )
 * @property {String | Number}  fontSize    字体大小,单位px( 默认 22 )
 * @property {Boolean}          bold        字体是否加粗(默认 false )
 * @property {String}           separator   千位分隔符,见官网说明
 * @event {Function} end 数值滚动到目标值时触发
 * @example <uv-count-to ref="uCountTo" :end-val="endVal" :autoplay="autoplay"></uv-count-to>
 */
export default {
    name: 'uv-count-to',
    data() {
        return {
            localStartVal: this.startVal,
            displayValue: this.formatNumber(this.startVal),
            printVal: null,
            paused: false, // 是否暂停
            localDuration: Number(this.duration),
            startTime: null, // 开始的时间
            timestamp: null, // 时间戳
            remaining: null, // 停留的时间
            rAF: null,
            lastTime: 0 // 上一次的时间
        };
    },
    mixins: [mpMixin, mixin, props],
    computed: {
        countDown() {
            return this.startVal > this.endVal;
        }
    },
    watch: {
        startVal() {
            this.autoplay && this.start();
        },
        endVal() {
            this.autoplay && this.start();
        }
    },
    mounted() {
        this.autoplay && this.start();
    },
    methods: {
        easingFn(t, b, c, d) {
            return (c * (-Math.pow(2, (-10 * t) / d) + 1) * 1024) / 1023 + b;
        },
        requestAnimationFrame(callback) {
            const currTime = new Date().getTime();
            // 为了使setTimteout的尽可能的接近每秒60帧的效果
            const timeToCall = Math.max(0, 16 - (currTime - this.lastTime));
            const id = setTimeout(() => {
                callback(currTime + timeToCall);
            }, timeToCall);
            this.lastTime = currTime + timeToCall;
            return id;
        },
        cancelAnimationFrame(id) {
            clearTimeout(id);
        },
        // 开始滚动数字
        start() {
            this.localStartVal = this.startVal;
            this.startTime = null;
            this.localDuration = this.duration;
            this.paused = false;
            this.rAF = this.requestAnimationFrame(this.count);
        },
        // 暂定状态,从暂停状态开始滚动;或者滚动状态下,暂停
        restart() {
            if (this.paused) {
                this.resume();
                this.paused = false;
            } else {
                this.stop();
                this.paused = true;
            }
        },
        // 暂停
        stop() {
            this.cancelAnimationFrame(this.rAF);
            this.paused = true;
        },
        // 重新开始(暂停的情况下)
        resume() {
            if (!this.remaining) return;
            this.startTime = 0;
            this.localDuration = this.remaining;
            this.localStartVal = this.printVal;
            this.requestAnimationFrame(this.count);
        },
        // 重置
        reset() {
            this.startTime = null;
            this.cancelAnimationFrame(this.rAF);
            this.displayValue = this.formatNumber(this.startVal);
        },
        count(timestamp) {
            if (!this.startTime) this.startTime = timestamp;
            this.timestamp = timestamp;
            const progress = timestamp - this.startTime;
            this.remaining = this.localDuration - progress;
            if (this.useEasing) {
                if (this.countDown) {
                    this.printVal = this.localStartVal - this.easingFn(progress, 0, this.localStartVal - this.endVal, this.localDuration);
                } else {
                    this.printVal = this.easingFn(progress, this.localStartVal, this.endVal - this.localStartVal, this.localDuration);
                }
            } else {
                if (this.countDown) {
                    this.printVal = this.localStartVal - (this.localStartVal - this.endVal) * (progress / this.localDuration);
                } else {
                    this.printVal = this.localStartVal + (this.endVal - this.localStartVal) * (progress / this.localDuration);
                }
            }
            if (this.countDown) {
                this.printVal = this.printVal < this.endVal ? this.endVal : this.printVal;
            } else {
                this.printVal = this.printVal > this.endVal ? this.endVal : this.printVal;
            }
            this.displayValue = this.formatNumber(this.printVal) || 0;
            if (progress < this.localDuration) {
                this.rAF = this.requestAnimationFrame(this.count);
            } else {
                this.$emit('end');
            }
        },
        // 判断是否数字
        isNumber(val) {
            return !isNaN(parseFloat(val));
        },
        formatNumber(num) {
            // 将num转为Number类型,因为其值可能为字符串数值,调用toFixed会报错
            num = Number(num);
            num = num.toFixed(Number(this.decimals));
            num += '';
            const x = num.split('.');
            let x1 = x[0];
            const x2 = x.length > 1 ? `${this.decimal}${x[1]}` : '';
            const rgx = /(\d+)(\d{3})/;
            if (this.separator && !this.isNumber(this.separator)) {
                while (rgx.test(x1)) {
                    x1 = x1.replace(rgx, '$1' + this.separator + '$2');
                }
            }
            return x1 + x2;
        },
        destroyed() {
            this.cancelAnimationFrame(this.rAF);
        }
    }
};
</script>
<style lang="scss" scoped>
@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
.uv-count-num {
    /* #ifndef APP-NVUE */
    display: inline-flex;
    /* #endif */
    text-align: center;
}
</style>
ledApp/uni_modules/uv-count-to/package.json
New file
@@ -0,0 +1,87 @@
{
  "id": "uv-count-to",
  "displayName": "uv-count-to 数字滚动 全面兼容小程序、nvue、vue2、vue3等多端",
  "version": "1.0.4",
  "description": "该数字滚动组件一般用于需要滚动数字到某一个值的场景,目标要求是一个递增的值,一种数字上升的视觉冲击效果。",
  "keywords": [
    "countTo",
    "uvui",
    "uv-ui",
    "数字滚动",
    "数字变化"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-count-to/readme.md
New file
@@ -0,0 +1,11 @@
## CountTo 数字滚动
> **组件名:uv-count-to**
该组件一般用于需要滚动数字到某一个值的场景,目标要求是一个递增的值。
### <a href="https://www.uvui.cn/components/countTo.html" target="_blank">查看文档</a>
### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)
#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-datetime-picker/changelog.md
New file
@@ -0,0 +1,34 @@
## 1.0.15(2024-06-14)
1. 修复上次更改引出的BUG
## 1.0.14(2024-05-31)
1. 修复设置maxDate后存在选择不准确的BUG
## 1.0.13(2024-03-22)
1. 修复VUE3中出现的BUG
## 1.0.12(2023-11-27)
1. 增加round圆角属性
## 1.0.11(2023-10-11)
1. 修复设置minDate出现选择错乱的BUG
## 1.0.10(2023-09-01)
1. 增加clearDate参数,是否清除上次选择,默认false
## 1.0.9(2023-08-31)
1. 增加mode="year",方便只选择年
## 1.0.8(2023-07-17)
1. 优化文档
2. 优化其他
## 1.0.7(2023-07-13)
1. 修复 uv-datetime-picker 设置value属性不生效的BUG
## 1.0.6(2023-07-05)
修复vue3模式下,动态修改v-model绑定的值无效的BUG
## 1.0.5(2023-07-02)
uv-datetime-picker  由于弹出层uv-popup的修改,打开和关闭方法更改,详情参考文档:https://www.uvui.cn/components/datetimePicker.html
## 1.0.4(2023-06-29)
1. 修复抖音小程序报错的BUG
## 1.0.3(2023-06-07)
1.  取消defaultIndex参数,传该值没实际意义,后续更新文档
## 1.0.2(2023-06-02)
1. 修复v-model重新赋值不更新的BUG
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-datetime-picker 时间选择器
ledApp/uni_modules/uv-datetime-picker/components/uv-datetime-picker/props.js
New file
@@ -0,0 +1,130 @@
export default {
    props: {
        value: {
            type: [String, Number],
            default: ''
        },
        modelValue: {
            type: [String, Number],
            default: ''
        },
        // 是否打开组件
        show: {
            type: Boolean,
            default: false
        },
        // 是否展示顶部的操作栏
        showToolbar: {
            type: Boolean,
            default: true
        },
        // 顶部标题
        title: {
            type: String,
            default: ''
        },
        // 展示格式,mode=date为日期选择,mode=time为时间选择,mode=year-month为年月选择,mode=datetime为日期时间选择
        mode: {
            type: String,
            default: 'datetime'
        },
        // 可选的最大时间
        maxDate: {
            type: Number,
            // 最大默认值为后10年
            default: new Date(new Date().getFullYear() + 10, 0, 1).getTime()
        },
        // 可选的最小时间
        minDate: {
            type: Number,
            // 最小默认值为前10年
            default: new Date(new Date().getFullYear() - 10, 0, 1).getTime()
        },
        // 可选的最小小时,仅mode=time有效
        minHour: {
            type: Number,
            default: 0
        },
        // 可选的最大小时,仅mode=time有效
        maxHour: {
            type: Number,
            default: 23
        },
        // 可选的最小分钟,仅mode=time有效
        minMinute: {
            type: Number,
            default: 0
        },
        // 可选的最大分钟,仅mode=time有效
        maxMinute: {
            type: Number,
            default: 59
        },
        // 选项过滤函数
        filter: {
            type: [Function, null],
            default: null
        },
        // 选项格式化函数
        formatter: {
            type: [Function, null],
            default: null
        },
        // 是否显示加载中状态
        loading: {
            type: Boolean,
            default: false
        },
        // 各列中,单个选项的高度
        itemHeight: {
            type: [String, Number],
            default: 44
        },
        // 取消按钮的文字
        cancelText: {
            type: String,
            default: '取消'
        },
        // 确认按钮的文字
        confirmText: {
            type: String,
            default: '确认'
        },
        // 取消按钮的颜色
        cancelColor: {
            type: String,
            default: '#909193'
        },
        // 确认按钮的颜色
        confirmColor: {
            type: String,
            default: '#3c9cff'
        },
        // 每列中可见选项的数量
        visibleItemCount: {
            type: [String, Number],
            default: 5
        },
        // 是否允许点击遮罩关闭选择器
        closeOnClickOverlay: {
            type: Boolean,
            default: true
        },
        // 是否允许点击确认关闭选择器
        closeOnClickConfirm: {
            type: Boolean,
            default: true
        },
        // 是否清空上次选择内容
        clearDate: {
            type: Boolean,
            default: false
        },
        // 圆角
        round: {
            type: [String, Number],
            default: 0
        },
        ...uni.$uv?.props?.datetimePicker
    }
}
ledApp/uni_modules/uv-datetime-picker/components/uv-datetime-picker/uv-datetime-picker.vue
New file
@@ -0,0 +1,360 @@
<template>
    <uv-picker
        ref="picker"
        :closeOnClickOverlay="closeOnClickOverlay"
        :closeOnClickConfirm="closeOnClickConfirm"
        :columns="columns"
        :title="title"
        :itemHeight="itemHeight"
        :showToolbar="showToolbar"
        :visibleItemCount="visibleItemCount"
        :defaultIndex="innerDefaultIndex"
        :cancelText="cancelText"
        :confirmText="confirmText"
        :cancelColor="cancelColor"
        :confirmColor="confirmColor"
        :round="round"
        @close="close"
        @cancel="cancel"
        @confirm="confirm"
        @change="change"
    >
    </uv-picker>
</template>
<script>
    function times(n, iteratee) {
        let index = -1
        const result = Array(n < 0 ? 0 : n)
        while (++index < n) {
            result[index] = iteratee(index)
        }
        return result
    }
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    import dayjs from '@/uni_modules/uv-ui-tools/libs/util/dayjs.js'
    /**
     * DatetimePicker 时间日期选择器
     * @description 此选择器用于时间日期
     * @tutorial https://www.uvui.cn/components/datetimePicker.html
     * @property {Boolean}          showToolbar         是否显示顶部的操作栏  ( 默认 true )
     * @property {String | Number}  value               绑定值
     * @property {String}           title               顶部标题
     * @property {String}           mode                展示格式 mode=date为日期选择,mode=time为时间选择,mode=year-month为年月选择,mode=datetime为日期时间选择  ( 默认 ‘datetime )
     * @property {Number}           maxDate             可选的最大时间  默认值为后10年
     * @property {Number}           minDate             可选的最小时间  默认值为前10年
     * @property {Number}           minHour             可选的最小小时,仅mode=time有效   ( 默认 0 )
     * @property {Number}           maxHour             可选的最大小时,仅mode=time有效      ( 默认 23 )
     * @property {Number}           minMinute           可选的最小分钟,仅mode=time有效      ( 默认 0 )
     * @property {Number}           maxMinute           可选的最大分钟,仅mode=time有效   ( 默认 59 )
     * @property {Function}         filter              选项过滤函数
     * @property {Function}         formatter           选项格式化函数
     * @property {Boolean}          loading             是否显示加载中状态   ( 默认 false )
     * @property {String | Number}  itemHeight          各列中,单个选项的高度   ( 默认 44 )
     * @property {String}           cancelText          取消按钮的文字  ( 默认 '取消' )
     * @property {String}           confirmText         确认按钮的文字  ( 默认 '确认' )
     * @property {String}           cancelColor         取消按钮的颜色  ( 默认 '#909193' )
     * @property {String}           confirmColor        确认按钮的颜色  ( 默认 '#3c9cff' )
     * @property {String | Number}  visibleItemCount    每列中可见选项的数量  ( 默认 5 )
     * @property {Boolean}          closeOnClickOverlay 是否允许点击遮罩关闭选择器  ( 默认 true )
     * @property {String | Number}  round   圆角  ( 默认 0 )
     * @event {Function} close 关闭选择器时触发
     * @event {Function} confirm 点击确定按钮,返回当前选择的值
     * @event {Function} change 当选择值变化时触发
     * @event {Function} cancel 点击取消按钮
     * @example  <uv-datetime-picker ref="datetimepicker" :value="value1"  mode="datetime" ></uv-datetime-picker>
     */
    export default {
        name: 'uv-datetime-picker',
        emits: ['close', 'cancel', 'confirm', 'input', 'change', 'update:modelValue'],
        mixins: [mpMixin, mixin, props],
        data() {
            return {
                columns: [],
                innerDefaultIndex: [],
                innerFormatter: (type, value) => value
            }
        },
        watch: {
            propsChange() {
                this.$uv.sleep(100).then(res=>{
                    this.init()
                })
            }
        },
        computed: {
            // 如果以下这些变量发生了变化,意味着需要重新初始化各列的值
            propsChange() {
                const propsValue = this.value || this.modelValue;
                return [this.mode, this.maxDate, this.minDate, this.minHour, this.maxHour, this.minMinute, this.maxMinute, this.filter, propsValue]
            }
        },
        mounted() {
            this.init()
        },
        methods: {
            init() {
                this.getValue();
                this.updateColumnValue(this.innerValue)
            },
            getValue() {
                const propsValue = this.value || this.modelValue;
                this.innerValue = this.correctValue(propsValue)
            },
            // 在微信小程序中,不支持将函数当做props参数,故只能通过ref形式调用
            setFormatter(e) {
                this.innerFormatter = e
            },
            open() {
                this.$refs.picker.open();
                // 解决打开的前一次和当前日期错乱的BUG
                setTimeout(()=>{
                    this.getValue();
                    this.updateColumnValue(this.innerValue);
                },10)
            },
            close() {
                this.$emit('close');
            },
            // 点击工具栏的取消按钮
            cancel() {
                this.$emit('cancel')
            },
            // 点击工具栏的确定按钮
            confirm() {
                this.$emit('confirm', {
                    value: this.innerValue,
                    mode: this.mode
                })
                if(!this.clearDate) {
                    this.$emit('input', this.innerValue)
                    this.$emit('update:modelValue', this.innerValue)
                }
            },
            //用正则截取输出值,当出现多组数字时,抛出错误
            intercept(e, type) {
                let judge = e.match(/\d+/g)
                //判断是否掺杂数字
                if (judge.length > 1) {
                    this.$uv.error("请勿在过滤或格式化函数时添加数字")
                    return 0
                } else if (type && judge[0].length == 4) { //判断是否是年份
                    return judge[0]
                } else if (judge[0].length > 2) {
                    this.$uv.error("请勿在过滤或格式化函数时添加数字")
                    return 0
                } else {
                    return judge[0]
                }
            },
            // 列发生变化时触发
            change(e) {
                const { indexs, values } = e
                let selectValue = ''
                if (this.mode === 'time') {
                    // 根据value各列索引,从各列数组中,取出当前时间的选中值
                    selectValue = `${this.intercept(values[0][indexs[0]])}:${this.intercept(values[1][indexs[1]])}`
                } else if (this.mode === 'year') {
                    const year = parseInt(this.intercept(values[0][indexs[0]], 'year'));
                    selectValue = Number(new Date(year, 0));
                } else {
                    // 将选择的值转为数值,比如'03'转为数值的3,'2019'转为数值的2019
                    const year = parseInt(this.intercept(values[0][indexs[0]], 'year'))
                    const month = parseInt(this.intercept(values[1][indexs[1]]))
                    let date = parseInt(values[2] ? this.intercept(values[2][indexs[2]]) : 1)
                    let hour = 0,
                        minute = 0
                    // 此月份的最大天数
                    const maxDate = dayjs(`${year}-${month}`).daysInMonth()
                    // year-month模式下,date不会出现在列中,设置为1,为了符合后边需要减1的需求
                    if (this.mode === 'year-month') {
                        date = 1
                    }
                    // 不允许超过maxDate值
                    date = Math.min(maxDate, date)
                    if (this.mode === 'datetime') {
                        hour = parseInt(this.intercept(values[3][indexs[3]]))
                        minute = parseInt(this.intercept(values[4][indexs[4]]))
                    }
                    // 转为时间模式
                    selectValue = Number(new Date(year, month - 1, date, hour, minute))
                }
                // 取出准确的合法值,防止超越边界的情况
                selectValue = this.correctValue(selectValue)
                this.innerValue = selectValue
                this.updateColumnValue(selectValue)
                // 发出change时间,value为当前选中的时间戳
                this.$emit('change', {
                    value: selectValue,
                    mode: this.mode
                })
            },
            // 更新各列的值,进行补0、格式化等操作
            updateColumnValue(value) {
                this.innerValue = value
                this.updateColumns()
                this.updateIndexs(value)
            },
            // 更新索引
            updateIndexs(value) {
                let values = []
                const formatter = this.formatter || this.innerFormatter;
                if (this.mode === 'time') {
                    // 将time模式的时间用:分隔成数组
                    const timeArr = value.split(':')
                    // 使用formatter格式化方法进行管道处理
                    values = [formatter('hour', timeArr[0]), formatter('minute', timeArr[1])]
                } else {
                    const date = new Date(value)
                    values = [
                        formatter('year', `${dayjs(value).year()}`),
                        // 月份补0
                        formatter('month', this.$uv.padZero(dayjs(value).month() + 1))
                    ]
                    if (this.mode === 'date') {
                        // date模式,需要添加天列
                        values.push(formatter('day', this.$uv.padZero(dayjs(value).date())))
                    }
                    if (this.mode === 'datetime') {
                        // 数组的push方法,可以写入多个参数
                        values.push(formatter('day', this.$uv.padZero(dayjs(value).date())), formatter('hour', this.$uv.padZero(dayjs(value).hour())), formatter('minute', this.$uv.padZero(dayjs(value).minute())))
                    }
                }
                // 根据当前各列的所有值,从各列默认值中找到默认值在各列中的索引
                const indexs = this.columns.map((column, index) => {
                    // 通过取大值,可以保证不会出现找不到索引的-1情况
                    return Math.max(0, column.findIndex(item => item === values[index]))
                })
                this.$nextTick(()=>{
                    this.$uv.sleep(100).then(res=>{
                        this.$refs.picker.setIndexs(indexs,true);
                    })
                })
            },
            // 更新各列的值
            updateColumns() {
                const formatter = this.formatter || this.innerFormatter
                // 获取各列的值,并且map后,对各列的具体值进行补0操作
                const results = this.getOriginColumns().map((column) => column.values.map((value) => formatter(column.type, value)))
                this.columns = results
            },
            getOriginColumns() {
                // 生成各列的值
                const results = this.getRanges().map(({ type, range }) => {
                    let values = times(range[1] - range[0] + 1, (index) => {
                        let value = range[0] + index
                        value = type === 'year' ? `${value}` : this.$uv.padZero(value)
                        return value
                    })
                    // 进行过滤
                    if (this.filter) {
                        values = this.filter(type, values)
                    }
                    return { type, values }
                })
                return results
            },
            // 通过最大值和最小值生成数组
            generateArray(start, end) {
                return Array.from(new Array(end + 1).keys()).slice(start)
            },
            // 得出合法的时间
            correctValue(value) {
                const isDateMode = this.mode !== 'time'
                if (isDateMode && !this.$uv.test.date(value)) {
                    // 如果是日期类型,但是又没有设置合法的当前时间的话,使用最小时间为当前时间
                    value = this.minDate
                } else if (!isDateMode && !value) {
                    // 如果是时间类型,而又没有默认值的话,就用最小时间
                    value = `${this.$uv.padZero(this.minHour)}:${this.$uv.padZero(this.minMinute)}`
                }
                // 时间类型
                if (!isDateMode) {
                    if (String(value).indexOf(':') === -1) return this.$uv.error('时间错误,请传递如12:24的格式')
                    let [hour, minute] = value.split(':')
                    // 对时间补零,同时控制在最小值和最大值之间
                    hour = this.$uv.padZero(this.$uv.range(this.minHour, this.maxHour, Number(hour)))
                    minute = this.$uv.padZero(this.$uv.range(this.minMinute, this.maxMinute, Number(minute)))
                    return `${ hour }:${ minute }`
                } else {
                    // 如果是日期格式,控制在最小日期和最大日期之间
                    value = dayjs(value).isBefore(dayjs(this.minDate)) ? this.minDate : value
                    value = dayjs(value).isAfter(dayjs(this.maxDate)) ? this.maxDate : value
                    return value
                }
            },
            // 获取每列的最大和最小值
            getRanges() {
                if (this.mode === 'time') {
                    return [{
                        type: 'hour',
                        range: [this.minHour, this.maxHour],
                    }, {
                        type: 'minute',
                        range: [this.minMinute, this.maxMinute],
                    }, ];
                }
                const { maxYear, maxDate, maxMonth, maxHour, maxMinute, } = this.getBoundary('max', this.innerValue);
                const { minYear, minDate, minMonth, minHour, minMinute, } = this.getBoundary('min', this.innerValue);
                const result = [{
                    type: 'year',
                    range: [minYear, maxYear],
                }, {
                    type: 'month',
                    range: [minMonth, maxMonth],
                }, {
                    type: 'day',
                    range: [minDate, maxDate],
                }, {
                    type: 'hour',
                    range: [minHour, maxHour],
                }, {
                    type: 'minute',
                    range: [minMinute, maxMinute],
                }, ];
                if (this.mode === 'date') result.splice(3, 2);
                if (this.mode === 'year-month') result.splice(2, 3);
                if (this.mode === 'year') result.splice(1, 4);
                return result;
            },
            // 根据minDate、maxDate、minHour、maxHour等边界值,判断各列的开始和结束边界值
            getBoundary(type, innerValue) {
                const value = new Date(innerValue)
                const boundary = new Date(this[`${type}Date`])
                const year = dayjs(boundary).year()
                let month = 1
                let date = 1
                let hour = 0
                let minute = 0
                if (type === 'max') {
                    month = 12
                    // 月份的天数
                    date = dayjs(value).daysInMonth()
                    hour = 23
                    minute = 59
                }
                // 获取边界值,逻辑是:当年达到了边界值(最大或最小年),就检查月允许的最大和最小值,以此类推
                if (dayjs(value).year() === year) {
                    month = dayjs(boundary).month() + 1
                    if (dayjs(value).month() + 1 === month) {
                        date = dayjs(boundary).date()
                        if (dayjs(value).date() === date) {
                            hour = dayjs(boundary).hour()
                            if (dayjs(value).hour() === hour) {
                                minute = dayjs(boundary).minute()
                            }
                        }
                    }
                }
                return {
                    [`${type}Year`]: year,
                    [`${type}Month`]: month,
                    [`${type}Date`]: date,
                    [`${type}Hour`]: hour,
                    [`${type}Minute`]: minute
                }
            },
        },
    }
</script>
ledApp/uni_modules/uv-datetime-picker/package.json
New file
@@ -0,0 +1,89 @@
{
  "id": "uv-datetime-picker",
  "displayName": "uv-datetime-picker 时间选择器 全面兼容vue3+2、app、h5、小程序等多端",
  "version": "1.0.15",
  "description": "时间选择器组件用于时间日期,主要用于年月日时分的选择,具体选择的精确度由参数控制。",
  "keywords": [
    "datetime-picker",
    "uvui",
    "uv-ui",
    "datetime",
    "时间选择"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools",
            "uv-picker"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y",
                "alipay": "n"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-datetime-picker/readme.md
New file
@@ -0,0 +1,19 @@
## DatetimePicker 时间选择器
> **组件名:uv-datetime-picker**
此选择器用于时间日期,主要用于年月日时分的选择,具体选择的精确度由参数控制。
# <a href="https://www.uvui.cn/components/datetimePicker.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>(请不要 下载插件ZIP)</small>
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
</a>
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-divider/changelog.md
New file
@@ -0,0 +1,11 @@
## 1.0.4(2023-12-06)
1. 优化
## 1.0.3(2023-12-06)
1. 阻止事件冒泡问题
## 1.0.2(2023-06-01)
1. 修复点击触发两次事件的BUG
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-divider 分割线
ledApp/uni_modules/uv-divider/components/uv-divider/props.js
New file
@@ -0,0 +1,45 @@
export default {
    props: {
        // 是否虚线
        dashed: {
            type: Boolean,
            default: false
        },
        // 是否细线
        hairline: {
            type: Boolean,
            default: true
        },
        // 是否以点替代文字,优先于text字段起作用
        dot: {
            type: Boolean,
            default: false
        },
        // 内容文本的位置,left-左边,center-中间,right-右边
        textPosition: {
            type: String,
            default: 'center'
        },
        // 文本内容
        text: {
            type: [String, Number],
            default: ''
        },
        // 文本大小
        textSize: {
            type: [String, Number],
            default: 14
        },
        // 文本颜色
        textColor: {
            type: String,
            default: '#909399'
        },
        // 线条颜色
        lineColor: {
            type: String,
            default: '#dcdfe6'
        },
        ...uni.$uv?.props?.divider
    }
}
ledApp/uni_modules/uv-divider/components/uv-divider/uv-divider.vue
New file
@@ -0,0 +1,113 @@
<template>
    <view
        class="uv-divider"
        :style="[$uv.addStyle(customStyle)]"
        @tap="click"
        >
        <uv-line
            :color="lineColor"
            :customStyle="leftLineStyle"
            :hairline="hairline"
            :dashed="dashed"></uv-line>
        <text
            v-if="dot"
            class="uv-divider__dot"
        >●</text>
        <text
            v-else-if="text"
            class="uv-divider__text"
            :style="[textStyle]"
        >{{text}}</text>
        <uv-line
            :color="lineColor"
            :customStyle="rightLineStyle"
            :hairline="hairline"
            :dashed="dashed"
        ></uv-line>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * divider 分割线
     * @description 区隔内容的分割线,一般用于页面底部"没有更多"的提示。
     * @tutorial https://www.uvui.cn/components/divider.html
     * @property {Boolean}          dashed          是否虚线 (默认 false )
     * @property {Boolean}          hairline        是否细线 (默认  true )
     * @property {Boolean}          dot             是否以点替代文字,优先于text字段起作用 (默认 false )
     * @property {String}           textPosition    内容文本的位置,left-左边,center-中间,right-右边 (默认 'center' )
     * @property {String | Number}  text            文本内容
     * @property {String | Number}  textSize        文本大小 (默认 14)
     * @property {String}           textColor       文本颜色 (默认 '#909399' )
     * @property {String}           lineColor       线条颜色 (默认 '#dcdfe6' )
     * @property {Object}           customStyle     定义需要用到的外部样式
     *
     * @event {Function}    click   divider组件被点击时触发
     * @example <uv-divider :color="color">锦瑟无端五十弦</uv-divider>
     */
    export default {
        name: 'uv-divider',
        mixins: [mpMixin, mixin, props],
        emits: ['click'],
        computed: {
            textStyle() {
                const style = {}
                style.fontSize = this.$uv.addUnit(this.textSize)
                style.color = this.textColor
                return style
            },
            // 左边线条的的样式
            leftLineStyle() {
                const style = {}
                // 如果是在左边,设置左边的宽度为固定值
                if (this.textPosition === 'left') {
                    style.width = '80rpx'
                } else {
                    style.flex = 1
                }
                return style
            },
            // 右边线条的的样式
            rightLineStyle() {
                const style = {}
                // 如果是在右边,设置右边的宽度为固定值
                if (this.textPosition === 'right') {
                    style.width = '80rpx'
                } else {
                    style.flex = 1
                }
                return style
            }
        },
        methods: {
            // divider组件被点击时触发
            click() {
                this.$emit('click');
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    $uv-divider-margin: 15px 0 !default;
    $uv-divider-text-margin: 0 15px !default;
    $uv-divider-dot-font-size: 12px !default;
    $uv-divider-dot-margin: 0 12px !default;
    $uv-divider-dot-color: #c0c4cc !default;
    .uv-divider {
        @include flex;
        flex-direction: row;
        align-items: center;
        margin: $uv-divider-margin;
        &__text {
            margin: $uv-divider-text-margin;
        }
        &__dot {
            font-size: $uv-divider-dot-font-size;
            margin: $uv-divider-dot-margin;
            color: $uv-divider-dot-color;
        }
    }
</style>
ledApp/uni_modules/uv-divider/package.json
New file
@@ -0,0 +1,88 @@
{
  "id": "uv-divider",
  "displayName": "uv-divider 分割线 全面兼容小程序、nvue、vue2、vue3等多端",
  "version": "1.0.4",
  "description": "区隔内容的分割线,一般用于页面底部没有更多的提示。",
  "keywords": [
    "divider",
    "uvui",
    "uv-ui",
    "分割线",
    "没有更多"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools",
            "uv-line"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-divider/readme.md
New file
@@ -0,0 +1,11 @@
## Divider 分割线
> **组件名:uv-divider**
区隔内容的分割线,一般用于页面底部"没有更多"的提示。
### <a href="https://www.uvui.cn/components/divider.html" target="_blank">查看文档</a>
### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)
#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-drop-down/changelog.md
New file
@@ -0,0 +1,13 @@
## 1.0.5(2024-01-02)
1. 修复parentData不变的BUG
## 1.0.4(2023-09-28)
1. 增加uv-sticky依赖
## 1.0.3(2023-08-29)
1. 修复自定义内容,点击自定义内容时会自动关闭弹窗的问题
## 1.0.2(2023-08-22)
1. 优化
## 1.0.1(2023-08-22)
1. 增加@change回调,返回弹窗关闭状态
2. 增加init方法,方便位置改变进行调整
## 1.0.0(2023-07-30)
新增uv-drop-down 下拉筛选组件
ledApp/uni_modules/uv-drop-down/components/uv-drop-down-item/uv-drop-down-item.vue
New file
@@ -0,0 +1,169 @@
<template>
    <view class="uv-drop-down-item" @click="clickHandler">
        <uv-text :text="label" :size="getTextStyle.size" :color="getTextStyle.color" lines="1" :custom-style="{marginRight: '10rpx',maxWidth:'200rpx'}"></uv-text>
        <uv-icon :name="getDownIcon.name" :size="getDownIcon.size" :color="getDownIcon.color" v-if="[1,'1'].indexOf(type)==-1"></uv-icon>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
    /**
     * DropDown 下拉框
     * @description 下拉筛选
     * @tutorial https://ext.dcloud.net.cn/plugin?name=uv-drop-down
     * @property {String | Number} name 字段标识
     * @property {String | Number} type 类型 1 没有筛选项,直接进行选中和不选中  2 有多个选项
     * @property {String | Number} label 筛选项的文本
     * @property {Boolean} isDrop 该项是否打开
     */
    export default {
        name: 'uv-drop-down-item',
        mixins: [mpMixin, mixin],
        emits: ['click'],
        props: {
            name: {
                type: [String, Number],
                default: ''
            },
            // 类型 1 没有筛选项,直接进行选中和不选中  2 有多个选项
            type: {
                type: [String, Number],
                default: '2'
            },
            // 筛选的文本
            label: {
                type: [String],
                default: ''
            },
            // 筛选值
            value: {
                type: [String, Number, null],
                default: ''
            },
            // 是否下拉菜单打开
            isDrop: {
                type: Boolean,
                default: false
            }
        },
        data() {
            return {
                parentData: {
                    defaultValue: [0, '0', 'all'],
                    textSize: '30rpx',
                    textColor: '#333',
                    textActiveSize: '30rpx',
                    textActiveColor: '#3c9cff',
                    extraIcon: {},
                    extraActiveIcon: {},
                    sign: '',
                    clickHandler: Function
                },
                active: false,
                isDroped: false,
                elId: ''
            }
        },
        watch: {
            isDrop: {
                handler(newVal) {
                    this.isDroped = newVal;
                },
                immediate: true
            },
            value: {
                handler(newVal) {
                    this.$nextTick(()=>{
                        this.active = this.parentData.defaultValue.indexOf(newVal) == -1;
                    })
                },
                immediate: true
            }
        },
        computed: {
            getDownIcon() {
                const style = {
                    size: '30rpx',
                    color: '#333',
                    ...this.parentData.extraIcon
                }
                if (this.active || this.isDroped) {
                    style.color = this.parentData.extraActiveIcon?.color ? this.parentData.extraActiveIcon?.color : '#3c9cff';
                    style.size = this.parentData.extraActiveIcon?.size ? this.parentData.extraActiveIcon?.size : '30rpx';
                }
                if (this.isDroped) {
                    style.name = this.parentData.extraActiveIcon?.name;
                }
                return style;
            },
            getTextStyle() {
                const style = {
                    size: this.parentData.textSize,
                    color: this.parentData.textColor
                };
                if (this.active || this.isDroped) {
                    style.size = this.parentData.textActiveSize;
                    style.color = this.parentData.textActiveColor;
                }
                return style;
            }
        },
        created() {
            this.init();
        },
        methods: {
            init() {
                this.elId = this.$uv.guid();
                this.getParentData('uv-drop-down');
                if (!this.parent) {
                    this.$uv.error('uv-drop-down必须搭配uv-drop-down-item组件使用');
                }
                uni.$on('HANDLE_DROPDOWN_ONE', id => {
                    if (this.isDroped && this.elId != id) {
                        this.isDroped = false;
                    }
                })
                uni.$on(`${this.parentData.sign}_CLOSEPOPUP`, async () => {
                    if (this.isDroped) {
                        this.isDroped = false;
                    }
                })
            },
            async clickHandler() {
                let data = {};
                uni.$emit('HANDLE_DROPDOWN_ONE', this.elId);
                switch (+this.type) {
                    case 1:
                        this.active = !this.active;
                        data = {
                            name: this.name,
                            active: this.active,
                            type: this.type
                        };
                        break;
                    case 2:
                        this.isDroped = !this.isDroped;
                        data = {
                            name: this.name,
                            active: this.isDroped,
                            type: this.type
                        };
                        break;
                }
                this.parentData.clickHandler(data);
                this.$emit('click', data);
                uni.$emit(`${this.parentData.sign}_CLICKMENU`, {
                    show: +this.type > 1 && this.isDroped
                });
            }
        }
    }
</script>
<style scoped lang="scss">
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    .uv-drop-down-item {
        @include flex;
        align-items: center;
        padding: 20rpx;
    }
</style>
ledApp/uni_modules/uv-drop-down/components/uv-drop-down-popup/uv-drop-down-popup.vue
New file
@@ -0,0 +1,242 @@
<template>
    <view class="uv-drop-down-popup">
        <uv-transition :show="show" mode="fade" :duration="300" :custom-style="overlayStyle" @click="clickOverlay">
            <view class="uv-dp__container" ref="uvDPContainer" :style="{height: `${height}px`}" @click.stop="blockClick">
                <view class="uv-dp__container__list" ref="uvDPList">
                    <slot>
                        <view class="uv-dp__container__list--item" v-for="(item,index) in list" :key="index" @click="clickHandler(item,index)" :style="[itemCustomStyle(index)]">
                            <uv-text :text="item[keyName]" :size="getTextSize(index)" :color="getTextColor(index)"></uv-text>
                        </view>
                    </slot>
                </view>
            </view>
        </uv-transition>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
    // #ifdef APP-NVUE
    const animation = uni.requireNativePlugin('animation');
    const dom = uni.requireNativePlugin('dom');
    // #endif
    /**
     * DropDownPopup 下拉框
     * @description 下拉筛选框
     * @tutorial https://ext.dcloud.net.cn/plugin?name=uv-drop-down
     * @property {String | Number} name 字段标识
     * @property {String | Number} zIndex 弹出层的层级
     * @property {String | Number} opacity 遮罩层的透明度
     * @property {Boolean} clickOverlayOnClose 是否允许点击遮罩层关闭弹窗
     * @property {Object} currentDropItem 当前下拉筛选菜单对象
     * @property {String} keyName 指定从当前下拉筛选菜单对象元素中读取哪个属性作为文本展示
     */
    export default {
        name: 'uv-drop-down-popup',
        mixins: [mpMixin, mixin],
        props: {
            sign: {
                type: [String, Number],
                default: 'UVDROPDOWN'
            },
            zIndex: {
                type: [Number, String],
                default: 999
            },
            opacity: {
                type: [Number, String],
                default: 0.5
            },
            clickOverlayOnClose: {
                type: Boolean,
                default: true
            },
            // 当前下拉选项对象
            currentDropItem: {
                type: Object,
                default () {
                    return {
                        activeIndex: 0,
                        child: []
                    }
                }
            },
            keyName: {
                type: String,
                default: 'label'
            }
        },
        data() {
            return {
                show: false,
                rect: {},
                height: 0
            }
        },
        computed: {
            overlayStyle() {
                let { height = 0, top = 0 } = this.rect;
                // #ifdef H5
                top += this.$uv.sys().windowTop;
                // #endif
                const style = {
                    position: 'fixed',
                    top: `${top+height}px`,
                    left: 0,
                    right: 0,
                    zIndex: this.zIndex,
                    bottom: 0,
                    'background-color': `rgba(0, 0, 0, ${this.opacity})`
                }
                return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
            },
            list() {
                try {
                    return Array.isArray(this.currentDropItem.child) ? this.currentDropItem.child : [];
                } catch (e) {
                    return [];
                }
            },
            getTextColor(index) {
                return index => {
                    const active = this.currentDropItem.activeIndex == index;
                    const color = this.currentDropItem.color;
                    const activeColor = this.currentDropItem.activeColor;
                    if (active) {
                        return activeColor ? activeColor : '#3c9cff';
                    }
                    return color ? color : '#333';
                }
            },
            getTextSize(index) {
                return index => {
                    const active = this.currentDropItem.activeIndex == index;
                    const size = this.currentDropItem.size;
                    const activeSize = this.currentDropItem.activeSize;
                    if (active) {
                        return activeSize ? activeSize : '30rpx';
                    }
                    return size ? size : '30rpx';
                }
            },
            itemCustomStyle() {
                return index => {
                    const active = this.currentDropItem.activeIndex == index;
                    const style = {};
                    if (active && this.currentDropItem.itemActiveCustomStyle) {
                        return this.$uv.deepMerge(style, this.$uv.addStyle(this.currentDropItem.itemActiveCustomStyle));
                    }
                    if (this.currentDropItem.itemCustomStyle) {
                        return this.$uv.deepMerge(style, this.$uv.addStyle(this.currentDropItem.itemCustomStyle))
                    }
                    return style;
                }
            }
        },
        created() {
            this.init();
        },
        methods: {
            blockClick() {},
            clickHandler(item, index) {
                this.currentDropItem.activeIndex = index;
                this.$emit('clickItem', item);
                this.close();
            },
            init() {
                uni.$off(`${this.sign}_GETRECT`);
                uni.$on(`${this.sign}_GETRECT`, rect => {
                    this.rect = rect;
                })
                uni.$off(`${this.sign}_CLICKMENU`);
                uni.$on(`${this.sign}_CLICKMENU`, async res => {
                    if (res.show) {
                        this.open();
                    } else {
                        this.close();
                    }
                })
            },
            open() {
                this.show = true;
                this.$nextTick(async () => {
                    // #ifndef H5 || MP-WEIXIN
                    await this.$uv.sleep(60);
                    // #endif
                    const res = await this.queryRect();
                    // #ifndef APP-NVUE
                    this.height = res.height;
                    // #endif
                    // #ifdef APP-NVUE
                    this.animation(res.height);
                    // #endif
                    this.$emit('popupChange', { show: true });
                })
            },
            close() {
                if(!this.show) return;
                this.height = 0;
                // #ifndef APP-NVUE
                this.height = 0;
                // #endif
                // #ifdef APP-NVUE
                this.animation(0);
                // #endif
                this.show = false;
                uni.$emit(`${this.sign}_CLOSEPOPUP`);
                this.$emit('popupChange', { show: false });
            },
            clickOverlay() {
                if (this.clickOverlayOnClose) {
                    this.close();
                }
            },
            // 查询内容高度
            queryRect() {
                // #ifndef APP-NVUE
                // 组件内部一般用this.$uvGetRect,对外的为getRect,二者功能一致,名称不同
                return new Promise(resolve => {
                    this.$uvGetRect(`.uv-dp__container__list`).then(size => {
                        resolve(size)
                    })
                })
                // #endif
                // #ifdef APP-NVUE
                // nvue下,使用dom模块查询元素高度
                // 返回一个promise,让调用此方法的主体能使用then回调
                return new Promise(resolve => {
                    dom.getComponentRect(this.$refs.uvDPList, res => {
                        resolve(res.size)
                    })
                })
                // #endif
            },
            // nvue下设置高度
            animation(height, duration = 200) {
                // #ifdef APP-NVUE
                const ref = this.$refs['uvDPContainer'];
                animation.transition(ref, {
                    styles: {
                        height: `${height}px`
                    },
                    duration
                })
                // #endif
            }
        }
    }
</script>
<style scoped lang="scss">
    .uv-dp__container {
        /* #ifndef APP-NVUE */
        overflow: hidden;
        transition: all .15s;
        /* #endif */
        background-color: #fff;
    }
    .uv-dp__container__list {
        &--item {
            padding: 20rpx 60rpx;
        }
    }
</style>
ledApp/uni_modules/uv-drop-down/components/uv-drop-down/uv-drop-down.vue
New file
@@ -0,0 +1,135 @@
<template>
    <uv-sticky :disabled="!isSticky">
        <view ref="dropDownRef" class="uv-drop-down" :style="[$uv.addStyle(customStyle)]">
            <slot></slot>
        </view>
    </uv-sticky>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
    // #ifdef APP-NVUE
    const dom = uni.requireNativePlugin('dom');
    // #endif
    /**
     * DropDown 下拉框
     * @description 下拉筛选
     * @tutorial https://ext.dcloud.net.cn/plugin?name=uv-drop-down
     * @property {String | Number} sign 组件唯一标识,需要手动传
     * @property {Boolean} is-sticky = [true|false] 是否吸顶
     * @property {Array} default-value 默认值,表示参数value属于这里面的值,就说明是未选中即是默认展示的值。eg:上面示例中的{label: '全部',value: 'all'} 即是默认值。后续处理逻辑也可以根据是否是其中值进行过滤。
     * @property {String} textSize 每项字体大小
     * @property {String} textColor 每项文本颜色
     * @property {String} textActiveSize 每项选中状态字体大小
     * @property {String} textActiveColor 每项选中状态文本颜色
     * @property {Object} extraIcon 每项右侧图标
     * @property {Object} extraActiveIcon 每项选中后右侧图标
     */
    export default {
        name: 'uv-drop-down',
        mixins: [mpMixin, mixin],
        emits: ['click'],
        props: {
            isSticky: {
                type: Boolean,
                default: true
            },
            sign: {
                type: [String, Number],
                default: 'UVDROPDOWN'
            },
            defaultValue: {
                type: Array,
                default: () => [0, '0', 'all']
            },
            textSize: {
                type: String,
                default: '30rpx'
            },
            textColor: {
                type: String,
                default: '#333'
            },
            textActiveSize: {
                type: String,
                default: '30rpx'
            },
            textActiveColor: {
                type: String,
                default: '#3c9cff'
            },
            extraIcon: {
                type: Object,
                default () {
                    return {
                        name: 'arrow-down',
                        size: '30rpx',
                        color: '#333'
                    }
                }
            },
            extraActiveIcon: {
                type: Object,
                default () {
                    return {
                        name: 'arrow-up',
                        size: '30rpx',
                        color: '#3c9cff'
                    }
                }
            }
        },
        computed: {
            parentData() {
                return [this.defaultValue, this.textSize, this.textColor, this.textActiveColor, this.textActiveSize, this.extraIcon, this.extraActiveIcon, this.sign, this.clickHandler];
            }
        },
        mounted() {
            this.init();
        },
        methods: {
            init() {
                uni.$emit(`${this.sign}_CLICKMENU`, {
                    show: false
                });
                this.$nextTick(async () => {
                    const rect = await this.queryRect();
                    uni.$emit(`${this.sign}_GETRECT`, rect);
                })
            },
            // 查询内容高度
            queryRect() {
                // #ifndef APP-NVUE
                // 组件内部一般用this.$uvGetRect,对外的为getRect,二者功能一致,名称不同
                return new Promise(resolve => {
                    this.$uvGetRect(`.uv-drop-down`).then(size => {
                        resolve(size)
                    })
                })
                // #endif
                // #ifdef APP-NVUE
                // nvue下,使用dom模块查询元素高度
                // 返回一个promise,让调用此方法的主体能使用then回调
                return new Promise(resolve => {
                    dom.getComponentRect(this.$refs.dropDownRef, res => {
                        res.size.top = res.size.top <= 0 ? 0 : res.size.top;
                        resolve(res.size)
                    })
                })
                // #endif
            },
            clickHandler(data) {
                this.$emit('click', data);
            }
        }
    }
</script>
<style scoped lang="scss">
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    .uv-drop-down {
        @include flex;
        justify-content: space-between;
        background-color: #fff;
        border-bottom: 1px solid #dadbde;
    }
</style>
ledApp/uni_modules/uv-drop-down/package.json
New file
@@ -0,0 +1,91 @@
{
    "id": "uv-drop-down",
    "displayName": "uv-drop-down 下拉筛选 全面兼容vue3+2、app、h5、小程序等多端",
    "version": "1.0.5",
    "description": "该组件主要提供筛选下拉筛选框,内置基础筛选功能,可以根据自己的需求自定义筛选项",
    "keywords": [
        "uv-drop-down",
        "uvui",
        "uv-ui",
        "下拉筛选",
        "筛选"
    ],
    "repository": "",
    "engines": {
        "HBuilderX": "^3.1.0"
    },
    "dcloudext": {
        "type": "component-vue",
        "sale": {
            "regular": {
                "price": "0.00"
            },
            "sourcecode": {
                "price": "0.00"
            }
        },
        "contact": {
            "qq": ""
        },
        "declaration": {
            "ads": "无",
            "data": "插件不采集任何数据",
            "permissions": "无"
        },
        "npmurl": ""
    },
    "uni_modules": {
        "dependencies": [
            "uv-ui-tools",
            "uv-icon",
            "uv-text",
            "uv-transition",
            "uv-sticky"
        ],
        "encrypt": [],
        "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
    }
}
ledApp/uni_modules/uv-drop-down/readme.md
New file
@@ -0,0 +1,23 @@
## DropDown 下拉筛选
> **组件名:uv-drop-down**
该组件主要提供筛选下拉筛选框,内置基础筛选功能,可以根据自己的需求自定义筛选项。
为了兼容app-nvue,需要内置三个组件进行配合使用,uv-drop-down属于菜单项(其实还包括子组件uv-drop-down-item),uv-drop-down-popup属于筛选框。
只需要做简单的约定式配置,即可使用该功能,兼容性良好,已经在多端进行了多次测试。
# <a href="https://www.uvui.cn/components/dropDown.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>(请不要 下载插件ZIP)</small>
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
</a>
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-empty/changelog.md
New file
@@ -0,0 +1,13 @@
## 1.0.5(2023-12-20)
1. 优化
## 1.0.4(2023-08-04)
1. icon支持base64图片
## 1.0.3(2023-07-17)
1. 修复  uv-empty 恢复设置mode属性的内置图标
## 1.0.2(2023-07-03)
去除插槽判断,避免某些平台不显示的BUG
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-empty 内容为空
ledApp/uni_modules/uv-empty/components/uv-empty/props.js
New file
@@ -0,0 +1,60 @@
export default {
    props: {
        // 内置图标名称,或图片路径,建议绝对路径
        icon: {
            type: String,
            default: ''
        },
        // 提示文字
        text: {
            type: String,
            default: ''
        },
        // 文字颜色
        textColor: {
            type: String,
            default: '#c0c4cc'
        },
        // 文字大小
        textSize: {
            type: [String, Number],
            default: 14
        },
        // 图标的颜色
        iconColor: {
            type: String,
            default: '#c0c4cc'
        },
        // 图标的大小
        iconSize: {
            type: [String, Number],
            default: 90
        },
        // 选择预置的图标类型
        mode: {
            type: String,
            default: 'data'
        },
        //  图标宽度,单位px
        width: {
            type: [String, Number],
            default: 160
        },
        // 图标高度,单位px
        height: {
            type: [String, Number],
            default: 160
        },
        // 是否显示组件
        show: {
            type: Boolean,
            default: true
        },
        // 组件距离上一个元素之间的距离,默认px单位
        marginTop: {
            type: [String, Number],
            default: 0
        },
        ...uni.$uv?.props?.empty
    }
}
ledApp/uni_modules/uv-empty/components/uv-empty/uv-empty.vue
New file
@@ -0,0 +1,126 @@
<template>
    <view
      class="uv-empty"
      :style="[emptyStyle]"
      v-if="show"
    >
        <uv-icon
          v-if="!isImg"
          :name="mode === 'message' ? 'chat' : `empty-${mode}`"
          :size="iconSize"
          :color="iconColor"
          margin-top="14"
        ></uv-icon>
        <image
          v-else
          :style="{
                width: $uv.addUnit(width),
                height: $uv.addUnit(height)
            }"
          :src="icon"
          mode="widthFix"
        ></image>
        <text
          class="uv-empty__text"
          :style="[textStyle]"
        >{{text ? text : icons[mode]}}</text>
        <view class="uv-empty__wrap">
            <slot />
        </view>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * empty 内容为空
     * @description 该组件用于需要加载内容,但是加载的第一页数据就为空,提示一个"没有内容"的场景, 我们精心挑选了十几个场景的图标,方便您使用。
     * @tutorial https://www.uvui.cn/components/empty.html
     * @property {String}           icon        内置图标名称,或图片路径,建议绝对路径
     * @property {String}           text        提示文字
     * @property {String}           textColor   文字颜色 (默认 '#c0c4cc' )
     * @property {String | Number}  textSize    文字大小 (默认 14 )
     * @property {String}           iconColor   图标的颜色 (默认 '#c0c4cc' )
     * @property {String | Number}  iconSize    图标的大小 (默认 90 )
     * @property {String}           mode        选择预置的图标类型 (默认 'data' )
     * @property {String | Number}  width       图标宽度,单位px (默认 160 )
     * @property {String | Number}  height      图标高度,单位px (默认 160 )
     * @property {Boolean}          show        是否显示组件 (默认 true )
     * @property {String | Number}  marginTop   组件距离上一个元素之间的距离,默认px单位 (默认 0 )
     * @property {Object}           customStyle 定义需要用到的外部样式
     *
     * @event {Function} click 点击组件时触发
     * @event {Function} close 点击关闭按钮时触发
     * @example <uv-empty text="所谓伊人,在水一方" mode="list"></uv-empty>
     */
    export default {
        name: "uv-empty",
        mixins: [mpMixin, mixin, props],
        data() {
            return {
                icons: {
                    car: '购物车为空',
                    page: '页面不存在',
                    search: '没有搜索结果',
                    address: '没有收货地址',
                    'wifi-off': '没有WiFi',
                    order: '订单为空',
                    coupon: '没有优惠券',
                    favor: '暂无收藏',
                    permission: '无权限',
                    history: '无历史记录',
                    news: '无新闻列表',
                    message: '消息列表为空',
                    list: '列表为空',
                    data: '数据为空',
                    comment: '暂无评论',
                }
            }
        },
        computed: {
            // 组件样式
            emptyStyle() {
                const style = {}
                style.marginTop = this.$uv.addUnit(this.marginTop)
                // 合并customStyle样式,此参数通过mixin中的props传递
                return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
            },
            // 文本样式
            textStyle() {
                const style = {}
                style.color = this.textColor
                style.fontSize = this.$uv.addUnit(this.textSize)
                return style
            },
            // 判断icon是否图片路径
            isImg() {
                const isBase64 = this.icon.indexOf('data:') > -1 && this.icon.indexOf('base64') > -1;
                return this.icon.indexOf('/') !== -1 || isBase64;
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    $uv-empty-text-margin-top: 20rpx !default;
    $uv-empty-slot-margin-top: 20rpx !default;
    .uv-empty {
        @include flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        &__text {
            @include flex;
            justify-content: center;
            align-items: center;
            margin-top: $uv-empty-text-margin-top;
        }
    }
    .uv-slot-wrap {
        @include flex;
        justify-content: center;
        align-items: center;
        margin-top: $uv-empty-slot-margin-top;
    }
</style>
ledApp/uni_modules/uv-empty/package.json
New file
@@ -0,0 +1,88 @@
{
  "id": "uv-empty",
  "displayName": "uv-empty 内容为空 全面兼容vue3+2、app、h5、小程序等多端",
  "version": "1.0.5",
  "description": "该组件用于需要加载内容,但是加载的第一页数据就为空,提示一个 没有内容 的场景, 我们精心挑选了十几个场景的图标,方便您使用。",
  "keywords": [
    "empty",
    "uvui",
    "uv-ui",
    "空数据",
    "暂无数据"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools",
            "uv-icon"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-empty/readme.md
New file
@@ -0,0 +1,19 @@
## Empty 内容为空
> **组件名:uv-empty**
该组件用于需要加载内容,但是加载的第一页数据就为空,提示一个"没有内容"的场景, 我们精心挑选了十几个场景的图标,方便您使用。
# <a href="https://www.uvui.cn/components/empty.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>(请不要 下载插件ZIP)</small>
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
</a>
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-form/changelog.md
New file
@@ -0,0 +1,23 @@
## 1.0.9(2023-08-14)
1. 修复设置labelWidth属性时,节点渲染有闪动的BUG
## 1.0.8(2023-08-13)
1. 修复未设置rules的情况下报错的BUG
2. 优化错误提示
## 1.0.7(2023-08-10)
1. 修复在vue3+setup语法糖中错误文字动画错乱
## 1.0.6(2023-07-17)
1. 优化文档
2. 优化其他
## 1.0.5(2023-07-03)
去除插槽判断,避免某些平台不显示的BUG
## 1.0.4(2023-07-02)
uv-form  由于弹出层uv-transition的修改,组件内部做了相应的修改,参数不变。
## 1.0.3(2023-06-18)
1. 修改某些情况下的BUG
## 1.0.2(2023-06-15)
1.  修复支付宝报错的BUG
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-form 表单
ledApp/uni_modules/uv-form/components/uv-form-item/props.js
New file
@@ -0,0 +1,49 @@
export default {
    props: {
        // input的label提示语
        label: {
            type: String,
            default: ''
        },
        // 绑定的值
        prop: {
            type: String,
            default: ''
        },
        // 是否显示表单域的下划线边框
        borderBottom: {
            type: [Boolean],
            default: false
        },
        // label的位置,left-左边,top-上边
        labelPosition: {
            type: String,
            default: ''
        },
        // label的宽度,单位px
        labelWidth: {
            type: [String, Number],
            default: ''
        },
        // 右侧图标
        rightIcon: {
            type: String,
            default: ''
        },
        // 左侧图标
        leftIcon: {
            type: String,
            default: ''
        },
        // 是否显示左边的必填星号,只作显示用,具体校验必填的逻辑,请在rules中配置
        required: {
            type: Boolean,
            default: false
        },
        leftIconStyle: {
            type: [String, Object],
            default: ''
        },
        ...uni.$uv?.props?.formItem
    }
}
ledApp/uni_modules/uv-form/components/uv-form-item/uv-form-item.vue
New file
@@ -0,0 +1,226 @@
<template>
    <view class="uv-form-item">
        <view
            class="uv-form-item__body"
            @tap="clickHandler"
            :style="[$uv.addStyle(customStyle), {
                flexDirection: (labelPosition || parentData.labelPosition) === 'left' ? 'row' : 'column'
            }]"
        >
            <!-- 微信小程序中,将一个参数设置空字符串,结果会变成字符串"true" -->
            <slot name="label">
                <view
                    class="uv-form-item__body__left"
                    v-if="required || leftIcon || label"
                    :style="{
                        width: $uv.addUnit(labelWidth || parentData.labelWidth),
                        marginBottom: parentData.labelPosition === 'left' ? 0 : '5px',
                    }"
                >
                    <!-- 为了块对齐 -->
                    <view class="uv-form-item__body__left__content">
                        <!-- nvue不支持伪元素before -->
                        <text
                            v-if="required"
                            class="uv-form-item__body__left__content__required"
                        >*</text>
                        <view
                            class="uv-form-item__body__left__content__icon"
                            v-if="leftIcon"
                        >
                            <uv-icon
                                :name="leftIcon"
                                :custom-style="leftIconStyle"
                            ></uv-icon>
                        </view>
                        <text
                            class="uv-form-item__body__left__content__label"
                            :style="[parentData.labelStyle, {
                                justifyContent: parentData.labelAlign === 'left' ? 'flex-start' : parentData.labelAlign === 'center' ? 'center' : 'flex-end'
                            }]"
                        >{{ label }}</text>
                    </view>
                </view>
            </slot>
            <view class="uv-form-item__body__right">
                <view class="uv-form-item__body__right__content">
                    <view class="uv-form-item__body__right__content__slot">
                        <slot />
                    </view>
                    <view class="item__body__right__content__icon">
                        <slot name="right" />
                    </view>
                </view>
            </view>
        </view>
        <slot name="error">
            <uv-transition
            :show="true"
            :duration="100"
            mode="fade"
            v-if="!!message && parentData.errorType === 'message'"
        >
                <text
                    class="uv-form-item__body__right__message"
                    :style="{
                        marginLeft:  $uv.addUnit(parentData.labelPosition === 'top' ? 0 : (labelWidth || parentData.labelWidth))
                    }"
                >{{ message }}</text>
            </uv-transition>
        </slot>
        <uv-line
            v-if="borderBottom"
            :color="message && parentData.errorType === 'border-bottom' ? '#f56c6c' : '#d6d7d9'"
        ></uv-line>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * Form 表单
     * @description 此组件一般用于表单场景,可以配置Input输入框,Select弹出框,进行表单验证等。
     * @tutorial https://www.uvui.cn/components/form.html
     * @property {String}           label           input的label提示语
     * @property {String}           prop            绑定的值
     * @property {String | Boolean} borderBottom    是否显示表单域的下划线边框
     * @property {String | Number}  labelWidth      label的宽度,单位px
     * @property {String}           rightIcon       右侧图标
     * @property {String}           leftIcon        左侧图标
     * @property {String | Object} leftIconStyle 左侧图标的样式
     * @property {Boolean}          required        是否显示左边的必填星号,只作显示用,具体校验必填的逻辑,请在rules中配置 (默认 false )
     *
     * @example <uv-form-item label="姓名" prop="userInfo.name" borderBottom ref="item1"></uv-form-item>
     */
    export default {
        name: 'uv-form-item',
        emits: ['click'],
        mixins: [mpMixin, mixin, props],
        data() {
            return {
                // 错误提示语
                message: '',
                parentData: {
                    // 提示文本的位置
                    labelPosition: 'left',
                    // 提示文本对齐方式
                    labelAlign: 'left',
                    // 提示文本的样式
                    labelStyle: {},
                    // 提示文本的宽度
                    labelWidth: 45,
                    // 错误提示方式
                    errorType: 'message'
                }
            }
        },
        created() {
            this.init()
        },
        methods: {
            init() {
                // 父组件的实例
                this.updateParentData()
                if (!this.parent) {
                    this.$uv.error('uv-form-item需要结合uv-form组件使用')
                }
            },
            // 获取父组件的参数
            updateParentData() {
                // 此方法写在mixin中
                this.getParentData('uv-form');
            },
            // 移除uv-form-item的校验结果
            clearValidate() {
                this.message = null
            },
            // 清空当前的组件的校验结果,并重置为初始值
            resetField() {
                // 找到原始值
                const value = this.$uv.getProperty(this.parent.originalModel, this.prop)
                // 将uv-form的model的prop属性链还原原始值
                this.$uv.setProperty(this.parent.model, this.prop, value)
                // 移除校验结果
                this.message = null
            },
            // 点击组件
            clickHandler() {
                this.$emit('click')
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    .uv-form-item {
        @include flex(column);
        font-size: 14px;
        color: $uv-main-color;
        &__body {
            @include flex;
            padding: 10px 0;
            &__left {
                @include flex;
                align-items: center;
                &__content {
                    position: relative;
                    @include flex;
                    align-items: center;
                    padding-right: 10rpx;
                    flex: 1;
                    &__icon {
                        margin-right: 8rpx;
                    }
                    &__required {
                        position: absolute;
                        left: -9px;
                        color: $uv-error;
                        line-height: 20px;
                        font-size: 20px;
                        top: 3px;
                    }
                    &__label {
                        @include flex;
                        align-items: center;
                        flex: 1;
                        color: $uv-main-color;
                        font-size: 15px;
                    }
                }
            }
            &__right {
                flex: 1;
                &__content {
                    @include flex;
                    align-items: center;
                    flex: 1;
                    &__slot {
                        flex: 1;
                        /* #ifndef MP */
                        @include flex;
                        align-items: center;
                        /* #endif */
                    }
                    &__icon {
                        margin-left: 10rpx;
                        color: $uv-light-color;
                        font-size: 30rpx;
                    }
                }
                &__message__box {
                    height: 16px;
                    line-height: 16px;
                }
                &__message {
                    margin-top: -6px;
                    line-height: 24px;
                    font-size: 12px;
                    color: $uv-error;
                }
            }
        }
    }
</style>
ledApp/uni_modules/uv-form/components/uv-form/props.js
New file
@@ -0,0 +1,46 @@
export default {
    props: {
        // 当前form的需要验证字段的集合
        model: {
            type: Object,
            default: () => ({})
        },
        // 验证规则
        rules: {
            type: [Object, Function, Array],
            default: () => ({})
        },
        // 有错误时的提示方式,message-提示信息,toast-进行toast提示
        // border-bottom-下边框呈现红色,none-无提示
        errorType: {
            type: String,
            default: 'message'
        },
        // 是否显示表单域的下划线边框
        borderBottom: {
            type: Boolean,
            default: true
        },
        // label的位置,left-左边,top-上边
        labelPosition: {
            type: String,
            default: 'left'
        },
        // label的宽度,单位px
        labelWidth: {
            type: [String, Number],
            default: 45
        },
        // lable字体的对齐方式
        labelAlign: {
            type: String,
            default: 'left'
        },
        // lable的样式,对象形式
        labelStyle: {
            type: Object,
            default: () => ({})
        },
        ...uni.$uv?.props?.form
    }
}
ledApp/uni_modules/uv-form/components/uv-form/uv-form.vue
New file
@@ -0,0 +1,209 @@
<template>
    <view class="uv-form">
        <slot />
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from "./props.js";
    import Schema from "./valid.js";
    // 去除警告信息
    Schema.warning = function() {};
    /**
     * Form 表单
     * @description 此组件一般用于表单场景,可以配置Input输入框,Select弹出框,进行表单验证等。
     * @tutorial https://www.uvui.cn/components/form.html
     * @property {Object}                       model           当前form的需要验证字段的集合
     * @property {Object | Function | Array}    rules           验证规则
     * @property {String}                       errorType       错误的提示方式,见上方说明 ( 默认 message )
     * @property {Boolean}                      borderBottom    是否显示表单域的下划线边框   ( 默认 true )
     * @property {String}                       labelPosition   表单域提示文字的位置,left-左侧,top-上方 ( 默认 'left' )
     * @property {String | Number}              labelWidth      提示文字的宽度,单位px  ( 默认 45 )
     * @property {String}                       labelAlign      lable字体的对齐方式   ( 默认 ‘left' )
     * @property {Object}                       labelStyle      lable的样式,对象形式
     * @example <uv-form labelPosition="left" :model="model1" :rules="rules" ref="form1"></uv-form>
     */
    export default {
        name: "uv-form",
        mixins: [mpMixin, mixin, props],
        provide() {
            return {
                uForm: this,
            };
        },
        data() {
            return {
                formRules: {},
                // 规则校验器
                validator: {},
                // 原始的model快照,用于resetFields方法重置表单时使用
                originalModel: null,
            };
        },
        watch: {
            // 监听规则的变化
            rules: {
                immediate: true,
                handler(n) {
                    this.setRules(n);
                },
            },
            // 监听属性的变化,通知子组件uv-form-item重新获取信息
            propsChange(n) {
                if (this.children?.length) {
                    this.children.map((child) => {
                        // 判断子组件(uv-form-item)如果有updateParentData方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
                        typeof child.updateParentData == "function" &&
                            child.updateParentData();
                    });
                }
            },
            // 监听model的初始值作为重置表单的快照
            model: {
                immediate: true,
                handler(n) {
                    if (!this.originalModel) {
                        this.originalModel = this.$uv.deepClone(n);
                    }
                },
            },
        },
        computed: {
            propsChange() {
                return [
                    this.errorType,
                    this.borderBottom,
                    this.labelPosition,
                    this.labelWidth,
                    this.labelAlign,
                    this.labelStyle,
                ];
            },
        },
        created() {
            // 存储当前form下的所有uv-form-item的实例
            // 不能定义在data中,否则微信小程序会造成循环引用而报错
            this.children = [];
        },
        methods: {
            // 手动设置校验的规则,如果规则中有函数的话,微信小程序中会过滤掉,所以只能手动调用设置规则
            setRules(rules) {
                // 判断是否有规则
                if (Object.keys(rules).length === 0) return;
                if (process.env.NODE_ENV === 'development' && Object.keys(this.model).length === 0) {
                    this.$uv.error('设置rules,model必须设置!如果已经设置,请刷新页面。');
                    return;
                };
                this.formRules = rules;
                // 重新将规则赋予Validator
                this.validator = new Schema(rules);
            },
            // 清空所有uv-form-item组件的内容,本质上是调用了uv-form-item组件中的resetField()方法
            resetFields() {
                this.resetModel();
            },
            // 重置model为初始值的快照
            resetModel(obj) {
                // 历遍所有uv-form-item,根据其prop属性,还原model的原始快照
                this.children.map((child) => {
                    const prop = child?.prop;
                    const value = this.$uv.getProperty(this.originalModel, prop);
                    this.$uv.setProperty(this.model, prop, value);
                });
            },
            // 清空校验结果
            clearValidate(props) {
                props = [].concat(props);
                this.children.map((child) => {
                    // 如果uv-form-item的prop在props数组中,则清除对应的校验结果信息
                    if (props[0] === undefined || props.includes(child.prop)) {
                        child.message = null;
                    }
                });
            },
            // 对部分表单字段进行校验
            async validateField(value, callback, event = null) {
                // $nextTick是必须的,否则model的变更,可能会延后于此方法的执行
                this.$nextTick(() => {
                    // 校验错误信息,返回给回调方法,用于存放所有form-item的错误信息
                    const errorsRes = [];
                    // 如果为字符串,转为数组
                    value = [].concat(value);
                    // 历遍children所有子form-item
                    this.children.map((child) => {
                        // 用于存放form-item的错误信息
                        const childErrors = [];
                        if (value.includes(child.prop)) {
                            // 获取对应的属性,通过类似'a.b.c'的形式
                            const propertyVal = this.$uv.getProperty(
                                this.model,
                                child.prop
                            );
                            // 属性链数组
                            const propertyChain = child.prop.split(".");
                            const propertyName =
                                propertyChain[propertyChain.length - 1];
                            const rule = this.formRules[child.prop];
                            // 如果不存在对应的规则,直接返回,否则校验器会报错
                            if (!rule) return;
                            // rule规则可为数组形式,也可为对象形式,此处拼接成为数组
                            const rules = [].concat(rule);
                            // 对rules数组进行校验
                            for (let i = 0; i < rules.length; i++) {
                                const ruleItem = rules[i];
                                // 将uv-form-item的触发器转为数组形式
                                const trigger = [].concat(ruleItem?.trigger);
                                // 如果是有传入触发事件,但是此form-item却没有配置此触发器的话,不执行校验操作
                                if (event && !trigger.includes(event)) continue;
                                // 实例化校验对象,传入构造规则
                                const validator = new Schema({
                                    [propertyName]: ruleItem,
                                });
                                validator.validate({
                                        [propertyName]: propertyVal,
                                    },
                                    (errors, fields) => {
                                        if (this.$uv.test.array(errors)) {
                                            errorsRes.push(...errors);
                                            childErrors.push(...errors);
                                        }
                                        this.$nextTick(() => {
                                            child.message = childErrors[0]?.message ? childErrors[0]?.message : null;
                                        })
                                    }
                                );
                            }
                        }
                    });
                    // 执行回调函数
                    typeof callback === "function" && callback(errorsRes);
                });
            },
            // 校验全部数据
            validate(callback) {
                return new Promise((resolve, reject) => {
                    // $nextTick是必须的,否则model的变更,可能会延后于validate方法
                    this.$nextTick(() => {
                        // 获取所有form-item的prop,交给validateField方法进行校验
                        const formItemProps = this.children.map(
                            (item) => item.prop
                        );
                        this.validateField(formItemProps, (errors) => {
                            if (errors.length) {
                                // 如果错误提示方式为toast,则进行提示
                                this.errorType === 'toast' && this.$uv.toast(errors[0].message)
                                reject(errors)
                            } else {
                                resolve(true)
                            }
                        });
                    });
                });
            },
        },
    };
</script>
ledApp/uni_modules/uv-form/components/uv-form/valid.js
New file
@@ -0,0 +1,1343 @@
function _extends() {
    _extends = Object.assign || function (target) {
        for (let i = 1; i < arguments.length; i++) {
            const source = arguments[i]
            for (const key in source) {
                if (Object.prototype.hasOwnProperty.call(source, key)) {
                    target[key] = source[key]
                }
            }
        }
        return target
    }
    return _extends.apply(this, arguments)
}
/* eslint no-console:0 */
const formatRegExp = /%[sdj%]/g
let warning = function warning() {} // don't print warning message when in production env or node runtime
if (typeof process !== 'undefined' && process.env && process.env.NODE_ENV !== 'production' && typeof window
    !== 'undefined' && typeof document !== 'undefined') {
    warning = function warning(type, errors) {
        if (typeof console !== 'undefined' && console.warn) {
            if (errors.every((e) => typeof e === 'string')) {
                console.warn(type, errors)
            }
        }
    }
}
function convertFieldsError(errors) {
    if (!errors || !errors.length) return null
    const fields = {}
    errors.forEach((error) => {
        const { field } = error
        fields[field] = fields[field] || []
        fields[field].push(error)
    })
    return fields
}
function format() {
    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
        args[_key] = arguments[_key]
    }
    let i = 1
    const f = args[0]
    const len = args.length
    if (typeof f === 'function') {
        return f.apply(null, args.slice(1))
    }
    if (typeof f === 'string') {
        let str = String(f).replace(formatRegExp, (x) => {
            if (x === '%%') {
                return '%'
            }
            if (i >= len) {
                return x
            }
            switch (x) {
            case '%s':
                return String(args[i++])
            case '%d':
                return Number(args[i++])
            case '%j':
                try {
                    return JSON.stringify(args[i++])
                } catch (_) {
                    return '[Circular]'
                }
                break
            default:
                return x
            }
        })
        for (let arg = args[i]; i < len; arg = args[++i]) {
            str += ` ${arg}`
        }
        return str
    }
    return f
}
function isNativeStringType(type) {
    return type === 'string' || type === 'url' || type === 'hex' || type === 'email' || type === 'pattern'
}
function isEmptyValue(value, type) {
    if (value === undefined || value === null) {
        return true
    }
    if (type === 'array' && Array.isArray(value) && !value.length) {
        return true
    }
    if (isNativeStringType(type) && typeof value === 'string' && !value) {
        return true
    }
    return false
}
function asyncParallelArray(arr, func, callback) {
    const results = []
    let total = 0
    const arrLength = arr.length
    function count(errors) {
        results.push.apply(results, errors)
        total++
        if (total === arrLength) {
            callback(results)
        }
    }
    arr.forEach((a) => {
        func(a, count)
    })
}
function asyncSerialArray(arr, func, callback) {
    let index = 0
    const arrLength = arr.length
    function next(errors) {
        if (errors && errors.length) {
            callback(errors)
            return
        }
        const original = index
        index += 1
        if (original < arrLength) {
            func(arr[original], next)
        } else {
            callback([])
        }
    }
    next([])
}
function flattenObjArr(objArr) {
    const ret = []
    Object.keys(objArr).forEach((k) => {
        ret.push.apply(ret, objArr[k])
    })
    return ret
}
function asyncMap(objArr, option, func, callback) {
    if (option.first) {
        const _pending = new Promise((resolve, reject) => {
            const next = function next(errors) {
                callback(errors)
                return errors.length ? reject({
                    errors,
                    fields: convertFieldsError(errors)
                }) : resolve()
            }
            const flattenArr = flattenObjArr(objArr)
            asyncSerialArray(flattenArr, func, next)
        })
        _pending.catch((e) => e)
        return _pending
    }
    let firstFields = option.firstFields || []
    if (firstFields === true) {
        firstFields = Object.keys(objArr)
    }
    const objArrKeys = Object.keys(objArr)
    const objArrLength = objArrKeys.length
    let total = 0
    const results = []
    const pending = new Promise((resolve, reject) => {
        const next = function next(errors) {
            results.push.apply(results, errors)
            total++
            if (total === objArrLength) {
                callback(results)
                return results.length ? reject({
                    errors: results,
                    fields: convertFieldsError(results)
                }) : resolve()
            }
        }
        if (!objArrKeys.length) {
            callback(results)
            resolve()
        }
        objArrKeys.forEach((key) => {
            const arr = objArr[key]
            if (firstFields.indexOf(key) !== -1) {
                asyncSerialArray(arr, func, next)
            } else {
                asyncParallelArray(arr, func, next)
            }
        })
    })
    pending.catch((e) => e)
    return pending
}
function complementError(rule) {
    return function (oe) {
        if (oe && oe.message) {
            oe.field = oe.field || rule.fullField
            return oe
        }
        return {
            message: typeof oe === 'function' ? oe() : oe,
            field: oe.field || rule.fullField
        }
    }
}
function deepMerge(target, source) {
    if (source) {
        for (const s in source) {
            if (source.hasOwnProperty(s)) {
                const value = source[s]
                if (typeof value === 'object' && typeof target[s] === 'object') {
                    target[s] = { ...target[s], ...value }
                } else {
                    target[s] = value
                }
            }
        }
    }
    return target
}
/**
 *  Rule for validating required fields.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param source The source object being validated.
 *  @param errors An array of errors that this rule may add
 *  validation errors to.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function required(rule, value, source, errors, options, type) {
    if (rule.required && (!source.hasOwnProperty(rule.field) || isEmptyValue(value, type || rule.type))) {
        errors.push(format(options.messages.required, rule.fullField))
    }
}
/**
 *  Rule for validating whitespace.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param source The source object being validated.
 *  @param errors An array of errors that this rule may add
 *  validation errors to.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function whitespace(rule, value, source, errors, options) {
    if (/^\s+$/.test(value) || value === '') {
        errors.push(format(options.messages.whitespace, rule.fullField))
    }
}
/* eslint max-len:0 */
const pattern = {
    // http://emailregex.com/
    email: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
    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'
    ),
    hex: /^#?([a-f0-9]{6}|[a-f0-9]{3})$/i
}
var types = {
    integer: function integer(value) {
        return /^(-)?\d+$/.test(value);
    },
    float: function float(value) {
        return /^(-)?\d+(\.\d+)?$/.test(value);
    },
    array: function array(value) {
        return Array.isArray(value)
    },
    regexp: function regexp(value) {
        if (value instanceof RegExp) {
            return true
        }
        try {
            return !!new RegExp(value)
        } catch (e) {
            return false
        }
    },
    date: function date(value) {
        return typeof value.getTime === 'function' && typeof value.getMonth === 'function' && typeof value.getYear
            === 'function'
    },
    number: function number(value) {
        if (isNaN(value)) {
            return false
        }
        // 修改源码,将字符串数值先转为数值
        return typeof +value === 'number'
    },
    object: function object(value) {
        return typeof value === 'object' && !types.array(value)
    },
    method: function method(value) {
        return typeof value === 'function'
    },
    email: function email(value) {
        return typeof value === 'string' && !!value.match(pattern.email) && value.length < 255
    },
    url: function url(value) {
        return typeof value === 'string' && !!value.match(pattern.url)
    },
    hex: function hex(value) {
        return typeof value === 'string' && !!value.match(pattern.hex)
    }
}
/**
 *  Rule for validating the type of a value.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param source The source object being validated.
 *  @param errors An array of errors that this rule may add
 *  validation errors to.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function type(rule, value, source, errors, options) {
    if (rule.required && value === undefined) {
        required(rule, value, source, errors, options)
        return
    }
    const custom = ['integer', 'float', 'array', 'regexp', 'object', 'method', 'email', 'number', 'date', 'url', 'hex']
    const ruleType = rule.type
    if (custom.indexOf(ruleType) > -1) {
        if (!types[ruleType](value)) {
            errors.push(format(options.messages.types[ruleType], rule.fullField, rule.type))
        } // straight typeof check
    } else if (ruleType && typeof value !== rule.type) {
        errors.push(format(options.messages.types[ruleType], rule.fullField, rule.type))
    }
}
/**
 *  Rule for validating minimum and maximum allowed values.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param source The source object being validated.
 *  @param errors An array of errors that this rule may add
 *  validation errors to.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function range(rule, value, source, errors, options) {
    const len = typeof rule.len === 'number'
    const min = typeof rule.min === 'number'
    const max = typeof rule.max === 'number' // 正则匹配码点范围从U+010000一直到U+10FFFF的文字(补充平面Supplementary Plane)
    const spRegexp = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g
    let val = value
    let key = null
    const num = typeof value === 'number'
    const str = typeof value === 'string'
    const arr = Array.isArray(value)
    if (num) {
        key = 'number'
    } else if (str) {
        key = 'string'
    } else if (arr) {
        key = 'array'
    } // if the value is not of a supported type for range validation
    // the validation rule rule should use the
    // type property to also test for a particular type
    if (!key) {
        return false
    }
    if (arr) {
        val = value.length
    }
    if (str) {
        // 处理码点大于U+010000的文字length属性不准确的bug,如"𠮷𠮷𠮷".lenght !== 3
        val = value.replace(spRegexp, '_').length
    }
    if (len) {
        if (val !== rule.len) {
            errors.push(format(options.messages[key].len, rule.fullField, rule.len))
        }
    } else if (min && !max && val < rule.min) {
        errors.push(format(options.messages[key].min, rule.fullField, rule.min))
    } else if (max && !min && val > rule.max) {
        errors.push(format(options.messages[key].max, rule.fullField, rule.max))
    } else if (min && max && (val < rule.min || val > rule.max)) {
        errors.push(format(options.messages[key].range, rule.fullField, rule.min, rule.max))
    }
}
const ENUM = 'enum'
/**
 *  Rule for validating a value exists in an enumerable list.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param source The source object being validated.
 *  @param errors An array of errors that this rule may add
 *  validation errors to.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function enumerable(rule, value, source, errors, options) {
    rule[ENUM] = Array.isArray(rule[ENUM]) ? rule[ENUM] : []
    if (rule[ENUM].indexOf(value) === -1) {
        errors.push(format(options.messages[ENUM], rule.fullField, rule[ENUM].join(', ')))
    }
}
/**
 *  Rule for validating a regular expression pattern.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param source The source object being validated.
 *  @param errors An array of errors that this rule may add
 *  validation errors to.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function pattern$1(rule, value, source, errors, options) {
    if (rule.pattern) {
        if (rule.pattern instanceof RegExp) {
            // if a RegExp instance is passed, reset `lastIndex` in case its `global`
            // flag is accidentally set to `true`, which in a validation scenario
            // is not necessary and the result might be misleading
            rule.pattern.lastIndex = 0
            if (!rule.pattern.test(value)) {
                errors.push(format(options.messages.pattern.mismatch, rule.fullField, value, rule.pattern))
            }
        } else if (typeof rule.pattern === 'string') {
            const _pattern = new RegExp(rule.pattern)
            if (!_pattern.test(value)) {
                errors.push(format(options.messages.pattern.mismatch, rule.fullField, value, rule.pattern))
            }
        }
    }
}
const rules = {
    required,
    whitespace,
    type,
    range,
    enum: enumerable,
    pattern: pattern$1
}
/**
 *  Performs validation for string types.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function string(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)
    if (validate) {
        if (isEmptyValue(value, 'string') && !rule.required) {
            return callback()
        }
        rules.required(rule, value, source, errors, options, 'string')
        if (!isEmptyValue(value, 'string')) {
            rules.type(rule, value, source, errors, options)
            rules.range(rule, value, source, errors, options)
            rules.pattern(rule, value, source, errors, options)
            if (rule.whitespace === true) {
                rules.whitespace(rule, value, source, errors, options)
            }
        }
    }
    callback(errors)
}
/**
 *  Validates a function.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function method(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)
    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }
        rules.required(rule, value, source, errors, options)
        if (value !== undefined) {
            rules.type(rule, value, source, errors, options)
        }
    }
    callback(errors)
}
/**
 *  Validates a number.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function number(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)
    if (validate) {
        if (value === '') {
            value = undefined
        }
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }
        rules.required(rule, value, source, errors, options)
        if (value !== undefined) {
            rules.type(rule, value, source, errors, options)
            rules.range(rule, value, source, errors, options)
        }
    }
    callback(errors)
}
/**
 *  Validates a boolean.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function _boolean(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)
    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }
        rules.required(rule, value, source, errors, options)
        if (value !== undefined) {
            rules.type(rule, value, source, errors, options)
        }
    }
    callback(errors)
}
/**
 *  Validates the regular expression type.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function regexp(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)
    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }
        rules.required(rule, value, source, errors, options)
        if (!isEmptyValue(value)) {
            rules.type(rule, value, source, errors, options)
        }
    }
    callback(errors)
}
/**
 *  Validates a number is an integer.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function integer(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)
    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }
        rules.required(rule, value, source, errors, options)
        if (value !== undefined) {
            rules.type(rule, value, source, errors, options)
            rules.range(rule, value, source, errors, options)
        }
    }
    callback(errors)
}
/**
 *  Validates a number is a floating point number.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function floatFn(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)
    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }
        rules.required(rule, value, source, errors, options)
        if (value !== undefined) {
            rules.type(rule, value, source, errors, options)
            rules.range(rule, value, source, errors, options)
        }
    }
    callback(errors)
}
/**
 *  Validates an array.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function array(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)
    if (validate) {
        if (isEmptyValue(value, 'array') && !rule.required) {
            return callback()
        }
        rules.required(rule, value, source, errors, options, 'array')
        if (!isEmptyValue(value, 'array')) {
            rules.type(rule, value, source, errors, options)
            rules.range(rule, value, source, errors, options)
        }
    }
    callback(errors)
}
/**
 *  Validates an object.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function object(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)
    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }
        rules.required(rule, value, source, errors, options)
        if (value !== undefined) {
            rules.type(rule, value, source, errors, options)
        }
    }
    callback(errors)
}
const ENUM$1 = 'enum'
/**
 *  Validates an enumerable list.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function enumerable$1(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)
    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }
        rules.required(rule, value, source, errors, options)
        if (value !== undefined) {
            rules[ENUM$1](rule, value, source, errors, options)
        }
    }
    callback(errors)
}
/**
 *  Validates a regular expression pattern.
 *
 *  Performs validation when a rule only contains
 *  a pattern property but is not declared as a string type.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function pattern$2(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)
    if (validate) {
        if (isEmptyValue(value, 'string') && !rule.required) {
            return callback()
        }
        rules.required(rule, value, source, errors, options)
        if (!isEmptyValue(value, 'string')) {
            rules.pattern(rule, value, source, errors, options)
        }
    }
    callback(errors)
}
function date(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)
    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }
        rules.required(rule, value, source, errors, options)
        if (!isEmptyValue(value)) {
            let dateObject
            if (typeof value === 'number') {
                dateObject = new Date(value)
            } else {
                dateObject = value
            }
            rules.type(rule, dateObject, source, errors, options)
            if (dateObject) {
                rules.range(rule, dateObject.getTime(), source, errors, options)
            }
        }
    }
    callback(errors)
}
function required$1(rule, value, callback, source, options) {
    const errors = []
    const type = Array.isArray(value) ? 'array' : typeof value
    rules.required(rule, value, source, errors, options, type)
    callback(errors)
}
function type$1(rule, value, callback, source, options) {
    const ruleType = rule.type
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)
    if (validate) {
        if (isEmptyValue(value, ruleType) && !rule.required) {
            return callback()
        }
        rules.required(rule, value, source, errors, options, ruleType)
        if (!isEmptyValue(value, ruleType)) {
            rules.type(rule, value, source, errors, options)
        }
    }
    callback(errors)
}
/**
 *  Performs validation for any type.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */
function any(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)
    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }
        rules.required(rule, value, source, errors, options)
    }
    callback(errors)
}
const validators = {
    string,
    method,
    number,
    boolean: _boolean,
    regexp,
    integer,
    float: floatFn,
    array,
    object,
    enum: enumerable$1,
    pattern: pattern$2,
    date,
    url: type$1,
    hex: type$1,
    email: type$1,
    required: required$1,
    any
}
function newMessages() {
    return {
        default: 'Validation error on field %s',
        required: '%s is required',
        enum: '%s must be one of %s',
        whitespace: '%s cannot be empty',
        date: {
            format: '%s date %s is invalid for format %s',
            parse: '%s date could not be parsed, %s is invalid ',
            invalid: '%s date %s is invalid'
        },
        types: {
            string: '%s is not a %s',
            method: '%s is not a %s (function)',
            array: '%s is not an %s',
            object: '%s is not an %s',
            number: '%s is not a %s',
            date: '%s is not a %s',
            boolean: '%s is not a %s',
            integer: '%s is not an %s',
            float: '%s is not a %s',
            regexp: '%s is not a valid %s',
            email: '%s is not a valid %s',
            url: '%s is not a valid %s',
            hex: '%s is not a valid %s'
        },
        string: {
            len: '%s must be exactly %s characters',
            min: '%s must be at least %s characters',
            max: '%s cannot be longer than %s characters',
            range: '%s must be between %s and %s characters'
        },
        number: {
            len: '%s must equal %s',
            min: '%s cannot be less than %s',
            max: '%s cannot be greater than %s',
            range: '%s must be between %s and %s'
        },
        array: {
            len: '%s must be exactly %s in length',
            min: '%s cannot be less than %s in length',
            max: '%s cannot be greater than %s in length',
            range: '%s must be between %s and %s in length'
        },
        pattern: {
            mismatch: '%s value %s does not match pattern %s'
        },
        clone: function clone() {
            const cloned = JSON.parse(JSON.stringify(this))
            cloned.clone = this.clone
            return cloned
        }
    }
}
const messages = newMessages()
/**
 *  Encapsulates a validation schema.
 *
 *  @param descriptor An object declaring validation rules
 *  for this schema.
 */
function Schema(descriptor) {
    this.rules = null
    this._messages = messages
    this.define(descriptor)
}
Schema.prototype = {
    messages: function messages(_messages) {
        if (_messages) {
            this._messages = deepMerge(newMessages(), _messages)
        }
        return this._messages
    },
    define: function define(rules) {
        if (!rules) {
            throw new Error('Cannot configure a schema with no rules')
        }
        if (typeof rules !== 'object' || Array.isArray(rules)) {
            throw new Error('Rules must be an object')
        }
        this.rules = {}
        let z
        let item
        for (z in rules) {
            if (rules.hasOwnProperty(z)) {
                item = rules[z]
                this.rules[z] = Array.isArray(item) ? item : [item]
            }
        }
    },
    validate: function validate(source_, o, oc) {
        const _this = this
        if (o === void 0) {
            o = {}
        }
        if (oc === void 0) {
            oc = function oc() {}
        }
        let source = source_
        let options = o
        let callback = oc
        if (typeof options === 'function') {
            callback = options
            options = {}
        }
        if (!this.rules || Object.keys(this.rules).length === 0) {
            if (callback) {
                callback()
            }
            return Promise.resolve()
        }
        function complete(results) {
            let i
            let errors = []
            let fields = {}
            function add(e) {
                if (Array.isArray(e)) {
                    let _errors
                    errors = (_errors = errors).concat.apply(_errors, e)
                } else {
                    errors.push(e)
                }
            }
            for (i = 0; i < results.length; i++) {
                add(results[i])
            }
            if (!errors.length) {
                errors = null
                fields = null
            } else {
                fields = convertFieldsError(errors)
            }
            callback(errors, fields)
        }
        if (options.messages) {
            let messages$1 = this.messages()
            if (messages$1 === messages) {
                messages$1 = newMessages()
            }
            deepMerge(messages$1, options.messages)
            options.messages = messages$1
        } else {
            options.messages = this.messages()
        }
        let arr
        let value
        const series = {}
        const keys = options.keys || Object.keys(this.rules)
        keys.forEach((z) => {
            arr = _this.rules[z]
            value = source[z]
            arr.forEach((r) => {
                let rule = r
                if (typeof rule.transform === 'function') {
                    if (source === source_) {
                        source = { ...source }
                    }
                    value = source[z] = rule.transform(value)
                }
                if (typeof rule === 'function') {
                    rule = {
                        validator: rule
                    }
                } else {
                    rule = { ...rule }
                }
                rule.validator = _this.getValidationMethod(rule)
                rule.field = z
                rule.fullField = rule.fullField || z
                rule.type = _this.getType(rule)
                if (!rule.validator) {
                    return
                }
                series[z] = series[z] || []
                series[z].push({
                    rule,
                    value,
                    source,
                    field: z
                })
            })
        })
        const errorFields = {}
        return asyncMap(series, options, (data, doIt) => {
            const { rule } = data
            let deep = (rule.type === 'object' || rule.type === 'array') && (typeof rule.fields === 'object' || typeof rule.defaultField
                === 'object')
            deep = deep && (rule.required || !rule.required && data.value)
            rule.field = data.field
            function addFullfield(key, schema) {
                return { ...schema, fullField: `${rule.fullField}.${key}` }
            }
            function cb(e) {
                if (e === void 0) {
                    e = []
                }
                let errors = e
                if (!Array.isArray(errors)) {
                    errors = [errors]
                }
                if (!options.suppressWarning && errors.length) {
                    Schema.warning('async-validator:', errors)
                }
                if (errors.length && rule.message) {
                    errors = [].concat(rule.message)
                }
                errors = errors.map(complementError(rule))
                if (options.first && errors.length) {
                    errorFields[rule.field] = 1
                    return doIt(errors)
                }
                if (!deep) {
                    doIt(errors)
                } else {
                    // if rule is required but the target object
                    // does not exist fail at the rule level and don't
                    // go deeper
                    if (rule.required && !data.value) {
                        if (rule.message) {
                            errors = [].concat(rule.message).map(complementError(rule))
                        } else if (options.error) {
                            errors = [options.error(rule, format(options.messages.required, rule.field))]
                        } else {
                            errors = []
                        }
                        return doIt(errors)
                    }
                    let fieldsSchema = {}
                    if (rule.defaultField) {
                        for (const k in data.value) {
                            if (data.value.hasOwnProperty(k)) {
                                fieldsSchema[k] = rule.defaultField
                            }
                        }
                    }
                    fieldsSchema = { ...fieldsSchema, ...data.rule.fields }
                    for (const f in fieldsSchema) {
                        if (fieldsSchema.hasOwnProperty(f)) {
                            const fieldSchema = Array.isArray(fieldsSchema[f]) ? fieldsSchema[f] : [fieldsSchema[f]]
                            fieldsSchema[f] = fieldSchema.map(addFullfield.bind(null, f))
                        }
                    }
                    const schema = new Schema(fieldsSchema)
                    schema.messages(options.messages)
                    if (data.rule.options) {
                        data.rule.options.messages = options.messages
                        data.rule.options.error = options.error
                    }
                    schema.validate(data.value, data.rule.options || options, (errs) => {
                        const finalErrors = []
                        if (errors && errors.length) {
                            finalErrors.push.apply(finalErrors, errors)
                        }
                        if (errs && errs.length) {
                            finalErrors.push.apply(finalErrors, errs)
                        }
                        doIt(finalErrors.length ? finalErrors : null)
                    })
                }
            }
            let res
            if (rule.asyncValidator) {
                res = rule.asyncValidator(rule, data.value, cb, data.source, options)
            } else if (rule.validator) {
                res = rule.validator(rule, data.value, cb, data.source, options)
                if (res === true) {
                    cb()
                } else if (res === false) {
                    cb(rule.message || `${rule.field} fails`)
                } else if (res instanceof Array) {
                    cb(res)
                } else if (res instanceof Error) {
                    cb(res.message)
                }
            }
            if (res && res.then) {
                res.then(() => cb(), (e) => cb(e))
            }
        }, (results) => {
            complete(results)
        })
    },
    getType: function getType(rule) {
        if (rule.type === undefined && rule.pattern instanceof RegExp) {
            rule.type = 'pattern'
        }
        if (typeof rule.validator !== 'function' && rule.type && !validators.hasOwnProperty(rule.type)) {
            throw new Error(format('Unknown rule type %s', rule.type))
        }
        return rule.type || 'string'
    },
    getValidationMethod: function getValidationMethod(rule) {
        if (typeof rule.validator === 'function') {
            return rule.validator
        }
        const keys = Object.keys(rule)
        const messageIndex = keys.indexOf('message')
        if (messageIndex !== -1) {
            keys.splice(messageIndex, 1)
        }
        if (keys.length === 1 && keys[0] === 'required') {
            return validators.required
        }
        return validators[this.getType(rule)] || false
    }
}
Schema.register = function register(type, validator) {
    if (typeof validator !== 'function') {
        throw new Error('Cannot register a validator by type, validator is not a function')
    }
    validators[type] = validator
}
Schema.warning = warning
Schema.messages = messages
export default Schema
// # sourceMappingURL=index.js.map
ledApp/uni_modules/uv-form/package.json
New file
@@ -0,0 +1,93 @@
{
  "id": "uv-form",
  "displayName": "uv-form 表单 全面兼容vue3+2、app、h5、小程序等多端",
  "version": "1.0.9",
  "description": "此组件一般用于表单场景,可以配置Input输入框,Textarea文本域,Checkbox复选框,Radio单选框,开关选择器等,进行表单验证等。",
  "keywords": [
    "form",
    "uvui",
    "uv-ui",
    "表单",
    "表单验证"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools",
            "uv-icon",
            "uv-line",
            "uv-transition",
            "uv-action-sheet",
            "uv-input",
            "uv-button"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-form/readme.md
New file
@@ -0,0 +1,19 @@
## Form 表单
> **组件名:uv-form**
此组件一般用于表单场景,可以配置`Input`输入框,`Textarea`文本域,`Checkbox`复选框,`Radio`单选框,开关选择器等,进行表单验证等。
# <a href="https://www.uvui.cn/components/form.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small style="font-size:14px;font-weight:700;">(请不要 下载插件ZIP)</small>
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
</a>
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-gap/changelog.md
New file
@@ -0,0 +1,5 @@
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
1. 新增间隔槽组件
ledApp/uni_modules/uv-gap/components/uv-gap/props.js
New file
@@ -0,0 +1,25 @@
export default {
    props: {
        // 背景颜色(默认transparent)
        bgColor: {
            type: String,
            default: 'transparent'
        },
        // 分割槽高度,单位px(默认20)
        height: {
            type: [String, Number],
            default: 20
        },
        // 与上一个组件的距离
        marginTop: {
            type: [String, Number],
            default: 0
        },
        // 与下一个组件的距离
        marginBottom: {
            type: [String, Number],
            default: 0
        },
        ...uni.$uv?.props?.gap
    }
}
ledApp/uni_modules/uv-gap/components/uv-gap/uv-gap.vue
New file
@@ -0,0 +1,36 @@
<template>
    <view class="uv-gap" :style="[gapStyle]"></view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * gap 间隔槽
     * @description 该组件一般用于内容块之间的用一个灰色块隔开的场景,方便用户风格统一,减少工作量
     * @tutorial https://www.uvui.cn/components/gap.html
     * @property {String}           bgColor         背景颜色 (默认 'transparent' )
     * @property {String | Number}  height          分割槽高度,单位px (默认 20 )
     * @property {String | Number}  marginTop       与前一个组件的距离,单位px( 默认 0 )
     * @property {String | Number}  marginBottom    与后一个组件的距离,单位px (默认 0 )
     * @property {Object}           customStyle     定义需要用到的外部样式
     *
     * @example <uv-gap height="80" bg-color="#bbb"></uv-gap>
     */
    export default {
        name: "uv-gap",
        mixins: [mpMixin, mixin,props],
        computed: {
            gapStyle() {
                const style = {
                    backgroundColor: this.bgColor,
                    height: this.$uv.addUnit(this.height),
                    marginTop: this.$uv.addUnit(this.marginTop),
                    marginBottom: this.$uv.addUnit(this.marginBottom),
                }
                return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
            }
        }
    };
</script>
ledApp/uni_modules/uv-gap/package.json
New file
@@ -0,0 +1,87 @@
{
  "id": "uv-gap",
  "displayName": "uv-gap 间隔槽 全面兼容小程序、nvue、vue2、vue3等多端",
  "version": "1.0.1",
  "description": "该组件一般用于内容块之间的用一个灰色块隔开的场景,方便用户风格统一,减少工作量。",
  "keywords": [
    "gap",
    "uvui",
    "uv-ui",
    "间隔槽",
    "内容块"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-gap/readme.md
New file
@@ -0,0 +1,12 @@
## Gap 间隔槽
> **组件名:uv-gap**
该组件一般用于内容块之间的用一个灰色块隔开的场景,方便用户风格统一,减少工作量。
### <a href="https://www.uvui.cn/components/gap.html" target="_blank">查看文档</a>
### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)
#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-grid/changelog.md
New file
@@ -0,0 +1,21 @@
## 1.0.9(2023-12-06)
1. 优化
## 1.0.8(2023-12-06)
1. 阻止事件冒泡问题
## 1.0.7(2023-10-13)
1. unmounted兼容vue3
## 1.0.6(2023-08-14)
1. 修复初始的时候闪动的BUG
## 1.0.5(2023-06-22)
1. 优化修改
## 1.0.4(2023-06-21)
1. 修复BUG
## 1.0.3(2023-06-01)
1. 修复点击触发两次事件的BUG
## 1.0.2(2023-05-23)
1. 优化
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-grid 宫格布局
ledApp/uni_modules/uv-grid/components/uv-grid-item/props.js
New file
@@ -0,0 +1,15 @@
export default {
    props: {
        // 宫格的name
        name: {
            type: [String, Number, null],
            default: null
        },
        // 背景颜色
        bgColor: {
            type: String,
            default: 'transparent'
        },
        ...uni.$uv?.props?.gridItem
    }
}
ledApp/uni_modules/uv-grid/components/uv-grid-item/uv-grid-item.vue
New file
@@ -0,0 +1,226 @@
<template>
    <!-- #ifndef APP-NVUE -->
    <view
        class="uv-grid-item"
        hover-class="uv-grid-item--hover-class"
        :hover-stay-time="200"
        @tap="clickHandler"
        :class="classes"
        :style="[itemStyle]"
    >
        <slot />
    </view>
    <!-- #endif -->
    <!-- #ifdef APP-NVUE -->
    <view
        class="uv-grid-item"
        :hover-stay-time="200"
        @tap="clickHandler"
        :class="classes"
        :style="[itemStyle]"
    >
        <slot />
    </view>
    <!-- #endif -->
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * gridItem 提示
     * @description 宫格组件一般用于同时展示多个同类项目的场景,可以给宫格的项目设置徽标组件(badge),或者图标等,也可以扩展为左右滑动的轮播形式。搭配uv-grid使用
     * @tutorial https://www.uvui.cn/components/grid.html
     * @property {String | Number}  name        宫格的name ( 默认 null )
     * @property {String}           bgColor     宫格的背景颜色 (默认 'transparent' )
     * @property {Object}           customStyle 自定义样式,对象形式
     * @event {Function} click 点击宫格触发
     * @example <uv-grid-item></uv-grid-item>
     */
    export default {
        name: "uv-grid-item",
        mixins: [mpMixin, mixin, props],
        emits: ['$uvGridItem','click'],
        data() {
            return {
                parentData: {
                    col: 3, // 父组件划分的宫格数
                    border: true, // 是否显示边框,根据父组件决定
                },
                // #ifdef APP-NVUE
                width: 0, // nvue下才这么计算,vue下放到computed中,否则会因为延时造成闪烁
                // #endif
                classes: [], // 类名集合,用于判断是否显示右边和下边框
            };
        },
        created() {
            // 父组件的实例
            this.updateParentData()
        },
        mounted() {
            this.init()
        },
        computed: {
            // #ifndef APP-NVUE
            // vue下放到computed中,否则会因为延时造成闪烁
            width() {
                return 100 / Number(this.parentData.col) + '%'
            },
            // #endif
            itemStyle() {
                const style = {
                    background: this.bgColor,
                    width: this.width
                }
                return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
            }
        },
        methods: {
            init() {
                // 用于在父组件uv-grid的children中被添加入子组件时,
                // 重新计算item的边框
                uni.$on('$uvGridItem', () => {
                    this.gridItemClasses()
                })
                // #ifdef APP-NVUE
                // 获取元素该有的长度,nvue下要延时才准确
                this.$nextTick(function(){
                    this.getItemWidth()
                })
                // #endif
                // 发出事件,通知所有的grid-item都重新计算自己的边框
                uni.$emit('$uvGridItem')
                this.gridItemClasses()
            },
            // 获取父组件的参数
            updateParentData() {
                // 此方法写在mixin中
                this.getParentData('uv-grid');
            },
            clickHandler() {
                let name = this.name
                // 如果没有设置name属性,历遍父组件的children数组,判断当前的元素是否和本实例this相等,找出当前组件的索引
                const children = this.parent?.children
                if(children && this.name === null) {
                    name = children.findIndex(child => child === this)
                }
                // 调用父组件方法,发出事件
                this.parent && this.parent.childClick(name)
                this.$emit('click', name)
            },
            async getItemWidth() {
                // 如果是nvue,不能使用百分比,只能使用固定宽度
                let width = 0
                if(this.parent) {
                    // 获取父组件宽度后,除以栅格数,得出每个item的宽度
                    const parentWidth = await this.getParentWidth()
                    width = parentWidth / Number(this.parentData.col) + 'px'
                }
                this.width = width
            },
            // 获取父元素的尺寸
            getParentWidth() {
                // #ifdef APP-NVUE
                // 返回一个promise,让调用者可以用await同步获取
                const dom = uni.requireNativePlugin('dom')
                return new Promise(resolve => {
                    // 调用父组件的ref
                    dom.getComponentRect(this.parent.$refs['uv-grid'], res => {
                        resolve(res.size.width)
                    })
                })
                // #endif
            },
            gridItemClasses() {
                if(this.parentData.border) {
                    let classes = []
                    this.parent.children.map((child, index) =>{
                        if(this === child) {
                            const len = this.parent.children.length
                            // 贴近右边屏幕边沿的child,并且最后一个(比如只有横向2个的时候),无需右边框
                            if((index + 1) % this.parentData.col !== 0 && index + 1 !== len) {
                                classes.push('uv-border-right')
                            }
                            // 总的宫格数量对列数取余的值
                            // 如果取余后,值为0,则意味着要将最后一排的宫格,都不需要下边框
                            const lessNum = len % this.parentData.col === 0 ? this.parentData.col : len % this.parentData.col
                            // 最下面的一排child,无需下边框
                            if(index < len - lessNum) {
                                classes.push('uv-border-bottom')
                            }
                        }
                    })
                    // 支付宝,头条小程序无法动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效
                    // #ifdef MP-ALIPAY || MP-TOUTIAO
                    classes = classes.join(' ')
                    // #endif
                    this.classes = classes
                }
            }
        },
        // #ifdef VUE2
        beforeDestroy() {
            // 移除事件监听,释放性能
            uni.$off('$uvGridItem')
        },
        // #endif
        // #ifdef VUE3
        unmounted() {
            // 移除事件监听,释放性能
            uni.$off('$uvGridItem')
        }
        // #endif
    };
</script>
<style lang="scss" scoped>
    $show-border: 1;
    $show-border-right: 1;
    $show-border-bottom: 1;
    @import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    $uv-grid-item-hover-class-opcatiy:.5 !default;
    $uv-grid-item-margin-top:1rpx !default;
    $uv-grid-item-border-right-width:0.5px !default;
    $uv-grid-item-border-bottom-width:0.5px !default;
    $uv-grid-item-border-right-color:$uv-border-color !default;
    $uv-grid-item-border-bottom-color:$uv-border-color !default;
    .uv-grid-item {
        align-items: center;
        justify-content: center;
        position: relative;
        flex-direction: column;
        /* #ifndef APP-NVUE */
        box-sizing: border-box;
        display: flex;
        /* #endif */
        /* #ifdef MP */
        position: relative;
        float: left;
        /* #endif */
        /* #ifdef MP-WEIXIN */
        margin-top:$uv-grid-item-margin-top;
        /* #endif */
        &--hover-class {
            opacity:$uv-grid-item-hover-class-opcatiy;
        }
    }
    /* #ifdef APP-NVUE */
    // 由于nvue不支持组件内引入app.vue中再引入的样式,所以需要写在这里
    .uv-border-right {
        border-right-width:$uv-grid-item-border-right-width;
        border-color: $uv-grid-item-border-right-color;
    }
    .uv-border-bottom {
        border-bottom-width:$uv-grid-item-border-bottom-width;
        border-color:$uv-grid-item-border-bottom-color;
    }
    /* #endif */
</style>
ledApp/uni_modules/uv-grid/components/uv-grid/props.js
New file
@@ -0,0 +1,20 @@
export default {
    props: {
        // 分成几列
        col: {
            type: [String, Number],
            default: 3
        },
        // 是否显示边框
        border: {
            type: Boolean,
            default: false
        },
        // 宫格对齐方式,表现为数量少的时候,靠左,居中,还是靠右
        align: {
            type: String,
            default: 'left'
        },
        ...uni.$uv?.props?.grid
    }
}
ledApp/uni_modules/uv-grid/components/uv-grid/uv-grid.vue
New file
@@ -0,0 +1,100 @@
<template>
    <view
        class="uv-grid"
        ref='uv-grid'
        :style="[gridStyle]"
    >
        <slot />
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * grid 宫格布局
     * @description 宫格组件一般用于同时展示多个同类项目的场景,可以给宫格的项目设置徽标组件(badge),或者图标等,也可以扩展为左右滑动的轮播形式。
     * @tutorial https://www.uvui.cn/components/grid.html
     * @property {String | Number}  col         宫格的列数(默认 3 )
     * @property {Boolean}          border      是否显示宫格的边框(默认 false )
     * @property {String}           align       宫格对齐方式,表现为数量少的时候,靠左,居中,还是靠右 (默认 'left' )
     * @property {Object}           customStyle 定义需要用到的外部样式
     * @event {Function} click 点击宫格触发
     * @example <uv-grid :col="3" @click="click"></uv-grid>
     */
    export default {
        name: 'uv-grid',
        mixins: [mpMixin, mixin, props],
        emits: ['click'],
        data() {
            return {
                index: 0,
                width: 0
            }
        },
        watch: {
            // 当父组件需要子组件需要共享的参数发生了变化,手动通知子组件
            parentData() {
                if (this.children.length) {
                    this.children.map(child => {
                        // 判断子组件(uv-radio)如果有updateParentData方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
                        typeof(child.updateParentData) == 'function' && child.updateParentData();
                    })
                }
            },
        },
        created() {
            // 如果将children定义在data中,在微信小程序会造成循环引用而报错
            this.children = []
        },
        computed: {
            // 计算父组件的值是否发生变化
            parentData() {
                return [this.hoverClass, this.col, this.size, this.border];
            },
            // 宫格对齐方式
            gridStyle() {
                let style = {};
                switch (this.align) {
                    case 'left':
                        style.justifyContent = 'flex-start';
                        break;
                    case 'center':
                        style.justifyContent = 'center';
                        break;
                    case 'right':
                        style.justifyContent = 'flex-end';
                        break;
                    default:
                        style.justifyContent = 'flex-start';
                };
                return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle));
            }
        },
        methods: {
            // 此方法由uv-grid-item触发,用于在uv-grid发出事件
            childClick(name) {
                this.$emit('click', name)
            }
        }
    };
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
     $uv-grid-width:100% !default;
    .uv-grid {
        /* #ifdef MP */
        width: $uv-grid-width;
        position: relative;
        box-sizing: border-box;
        overflow: hidden;
        display: block;
        /* #endif */
        justify-content: center;
        @include flex;
        flex-wrap: wrap;
        align-items: center;
    }
</style>
ledApp/uni_modules/uv-grid/package.json
New file
@@ -0,0 +1,88 @@
{
  "id": "uv-grid",
  "displayName": "uv-grid 宫格布局 全面兼容vue3+2、app、h5、小程序等多端",
  "version": "1.0.9",
  "description": "uv-grid 宫格组件一般用于同时展示多个同类项目的场景,可以给宫格的项目设置徽标组件(badge),或者图标等,也可以扩展为左右滑动的轮播形式。",
  "keywords": [
    "uv-grid",
    "uvui",
    "uv-ui",
    "宫格布局",
    "grid"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools",
            "uv-icon"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-grid/readme.md
New file
@@ -0,0 +1,17 @@
## Grid 宫格布局
> **组件名:uv-grid**
宫格组件一般用于同时展示多个同类项目的场景,可以给宫格的项目设置徽标组件(badge),或者图标等,也可以扩展为左右滑动的轮播形式。
# <a href="https://www.uvui.cn/components/grid.html" target="_blank">查看文档</a>
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
</a>
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-icon/changelog.md
New file
@@ -0,0 +1,31 @@
## 1.0.13(2023-12-06)
1. 优化
## 1.0.12(2023-12-06)
1. 阻止事件冒泡处理
## 1.0.11(2023-10-29)
1. imgMode默认值改成aspectFit
## 1.0.10(2023-08-13)
1. 优化nvue,方便自定义图标
## 1.0.9(2023-07-28)
1. 修改几个对应错误图标的BUG
## 1.0.8(2023-07-24)
1. 优化 支持base64图片
## 1.0.7(2023-07-17)
1. 修复  uv-icon 恢复uv-empty相关的图标
## 1.0.6(2023-07-13)
1. 修复icon设置name属性对应图标错误的BUG
## 1.0.5(2023-07-04)
1. 更新图标,删除一些不常用的图标
2. 删除base64,修改成ttf文件引入读取图标
3. 自定义图标文档说明:https://www.uvui.cn/guide/customIcon.html
## 1.0.4(2023-07-03)
1. 修复主题颜色在APP不生效的BUG
## 1.0.3(2023-05-24)
1. 将线上ttf字体包替换成base64,避免加载时或者网络差时候显示白色方块
## 1.0.2(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.1(2023-05-10)
1. 修复小程序中异常显示
## 1.0.0(2023-05-04)
新发版
ledApp/uni_modules/uv-icon/components/uv-icon/icons.js
New file
@@ -0,0 +1,160 @@
export default {
    'uvicon-level': 'e68f',
    'uvicon-checkbox-mark': 'e659',
    'uvicon-folder': 'e694',
    'uvicon-movie': 'e67c',
    'uvicon-star-fill': 'e61e',
    'uvicon-star': 'e618',
    'uvicon-phone-fill': 'e6ac',
    'uvicon-phone': 'e6ba',
    'uvicon-apple-fill': 'e635',
    'uvicon-backspace': 'e64d',
    'uvicon-attach': 'e640',
    'uvicon-empty-data': 'e671',
    'uvicon-empty-address': 'e68a',
    'uvicon-empty-favor': 'e662',
    'uvicon-empty-car': 'e657',
    'uvicon-empty-order': 'e66b',
    'uvicon-empty-list': 'e672',
    'uvicon-empty-search': 'e677',
    'uvicon-empty-permission': 'e67d',
    'uvicon-empty-news': 'e67e',
    'uvicon-empty-history': 'e685',
    'uvicon-empty-coupon': 'e69b',
    'uvicon-empty-page': 'e60e',
    'uvicon-empty-wifi-off': 'e6cc',
    'uvicon-reload': 'e627',
    'uvicon-order': 'e695',
    'uvicon-server-man': 'e601',
    'uvicon-search': 'e632',
    'uvicon-more-dot-fill': 'e66f',
    'uvicon-scan': 'e631',
    'uvicon-map': 'e665',
    'uvicon-map-fill': 'e6a8',
    'uvicon-tags': 'e621',
    'uvicon-tags-fill': 'e613',
    'uvicon-eye': 'e664',
    'uvicon-eye-fill': 'e697',
    'uvicon-eye-off': 'e69c',
    'uvicon-eye-off-outline': 'e688',
    'uvicon-mic': 'e66d',
    'uvicon-mic-off': 'e691',
    'uvicon-calendar': 'e65c',
    'uvicon-trash': 'e623',
    'uvicon-trash-fill': 'e6ce',
    'uvicon-play-left': 'e6bf',
    'uvicon-play-right': 'e6b3',
    'uvicon-minus': 'e614',
    'uvicon-plus': 'e625',
    'uvicon-info-circle': 'e69f',
    'uvicon-info-circle-fill': 'e6a7',
    'uvicon-question-circle': 'e622',
    'uvicon-question-circle-fill': 'e6bc',
    'uvicon-close': 'e65a',
    'uvicon-checkmark': 'e64a',
    'uvicon-checkmark-circle': 'e643',
    'uvicon-checkmark-circle-fill': 'e668',
    'uvicon-setting': 'e602',
    'uvicon-setting-fill': 'e6d0',
    'uvicon-heart': 'e6a2',
    'uvicon-heart-fill': 'e68b',
    'uvicon-camera': 'e642',
    'uvicon-camera-fill': 'e650',
    'uvicon-more-circle': 'e69e',
    'uvicon-more-circle-fill': 'e684',
    'uvicon-chat': 'e656',
    'uvicon-chat-fill': 'e63f',
    'uvicon-bag': 'e647',
    'uvicon-error-circle': 'e66e',
    'uvicon-error-circle-fill': 'e655',
    'uvicon-close-circle': 'e64e',
    'uvicon-close-circle-fill': 'e666',
    'uvicon-share': 'e629',
    'uvicon-share-fill': 'e6bb',
    'uvicon-share-square': 'e6c4',
    'uvicon-shopping-cart': 'e6cb',
    'uvicon-shopping-cart-fill': 'e630',
    'uvicon-bell': 'e651',
    'uvicon-bell-fill': 'e604',
    'uvicon-list': 'e690',
    'uvicon-list-dot': 'e6a9',
    'uvicon-zhifubao-circle-fill': 'e617',
    'uvicon-weixin-circle-fill': 'e6cd',
    'uvicon-weixin-fill': 'e620',
    'uvicon-qq-fill': 'e608',
    'uvicon-qq-circle-fill': 'e6b9',
    'uvicon-moments-circel-fill': 'e6c2',
    'uvicon-moments': 'e6a0',
    'uvicon-car': 'e64f',
    'uvicon-car-fill': 'e648',
    'uvicon-warning-fill': 'e6c7',
    'uvicon-warning': 'e6c1',
    'uvicon-clock-fill': 'e64b',
    'uvicon-clock': 'e66c',
    'uvicon-edit-pen': 'e65d',
    'uvicon-edit-pen-fill': 'e679',
    'uvicon-email': 'e673',
    'uvicon-email-fill': 'e683',
    'uvicon-minus-circle': 'e6a5',
    'uvicon-plus-circle': 'e603',
    'uvicon-plus-circle-fill': 'e611',
    'uvicon-file-text': 'e687',
    'uvicon-file-text-fill': 'e67f',
    'uvicon-pushpin': 'e6d1',
    'uvicon-pushpin-fill': 'e6b6',
    'uvicon-grid': 'e68c',
    'uvicon-grid-fill': 'e698',
    'uvicon-play-circle': 'e6af',
    'uvicon-play-circle-fill': 'e62a',
    'uvicon-pause-circle-fill': 'e60c',
    'uvicon-pause': 'e61c',
    'uvicon-pause-circle': 'e696',
    'uvicon-gift-fill': 'e6b0',
    'uvicon-gift': 'e680',
    'uvicon-kefu-ermai': 'e660',
    'uvicon-server-fill': 'e610',
    'uvicon-coupon-fill': 'e64c',
    'uvicon-coupon': 'e65f',
    'uvicon-integral': 'e693',
    'uvicon-integral-fill': 'e6b1',
    'uvicon-home-fill': 'e68e',
    'uvicon-home': 'e67b',
    'uvicon-account': 'e63a',
    'uvicon-account-fill': 'e653',
    'uvicon-thumb-down-fill': 'e628',
    'uvicon-thumb-down': 'e60a',
    'uvicon-thumb-up': 'e612',
    'uvicon-thumb-up-fill': 'e62c',
    'uvicon-lock-fill': 'e6a6',
    'uvicon-lock-open': 'e68d',
    'uvicon-lock-opened-fill': 'e6a1',
    'uvicon-lock': 'e69d',
    'uvicon-red-packet': 'e6c3',
    'uvicon-photo-fill': 'e6b4',
    'uvicon-photo': 'e60d',
    'uvicon-volume-off-fill': 'e6c8',
    'uvicon-volume-off': 'e6bd',
    'uvicon-volume-fill': 'e624',
    'uvicon-volume': 'e605',
    'uvicon-download': 'e670',
    'uvicon-arrow-up-fill': 'e636',
    'uvicon-arrow-down-fill': 'e638',
    'uvicon-play-left-fill': 'e6ae',
    'uvicon-play-right-fill': 'e6ad',
    'uvicon-arrow-downward': 'e634',
    'uvicon-arrow-leftward': 'e63b',
    'uvicon-arrow-rightward': 'e644',
    'uvicon-arrow-upward': 'e641',
    'uvicon-arrow-down': 'e63e',
    'uvicon-arrow-right': 'e63c',
    'uvicon-arrow-left': 'e646',
    'uvicon-arrow-up': 'e633',
    'uvicon-skip-back-left': 'e6c5',
    'uvicon-skip-forward-right': 'e61f',
    'uvicon-arrow-left-double': 'e637',
    'uvicon-man': 'e675',
    'uvicon-woman': 'e626',
    'uvicon-en': 'e6b8',
    'uvicon-twitte': 'e607',
    'uvicon-twitter-circle-fill': 'e6cf'
}
ledApp/uni_modules/uv-icon/components/uv-icon/props.js
New file
@@ -0,0 +1,90 @@
export default {
    props: {
        // 图标类名
        name: {
            type: String,
            default: ''
        },
        // 图标颜色,可接受主题色
        color: {
            type: String,
            default: '#606266'
        },
        // 字体大小,单位px
        size: {
            type: [String, Number],
            default: '16px'
        },
        // 是否显示粗体
        bold: {
            type: Boolean,
            default: false
        },
        // 点击图标的时候传递事件出去的index(用于区分点击了哪一个)
        index: {
            type: [String, Number],
            default: null
        },
        // 触摸图标时的类名
        hoverClass: {
            type: String,
            default: ''
        },
        // 自定义扩展前缀,方便用户扩展自己的图标库
        customPrefix: {
            type: String,
            default: 'uvicon'
        },
        // 图标右边或者下面的文字
        label: {
            type: [String, Number],
            default: ''
        },
        // label的位置,只能右边或者下边
        labelPos: {
            type: String,
            default: 'right'
        },
        // label的大小
        labelSize: {
            type: [String, Number],
            default: '15px'
        },
        // label的颜色
        labelColor: {
            type: String,
            default: '#606266'
        },
        // label与图标的距离
        space: {
            type: [String, Number],
            default: '3px'
        },
        // 图片的mode
        imgMode: {
            type: String,
            default: 'aspectFit'
        },
        // 用于显示图片小图标时,图片的宽度
        width: {
            type: [String, Number],
            default: ''
        },
        // 用于显示图片小图标时,图片的高度
        height: {
            type: [String, Number],
            default: ''
        },
        // 用于解决某些情况下,让图标垂直居中的用途
        top: {
            type: [String, Number],
            default: 0
        },
        // 是否阻止事件传播
        stop: {
            type: Boolean,
            default: false
        },
        ...uni.$uv?.props?.icon
    }
}
ledApp/uni_modules/uv-icon/components/uv-icon/uv-icon.vue
New file
@@ -0,0 +1,226 @@
<template>
    <view
      class="uv-icon"
      @tap="clickHandler"
      :class="['uv-icon--' + labelPos]"
    >
        <image
          class="uv-icon__img"
          v-if="isImg"
          :src="name"
          :mode="imgMode"
          :style="[imgStyle, $uv.addStyle(customStyle)]"
        ></image>
        <text
          v-else
          class="uv-icon__icon"
          :class="uClasses"
          :style="[iconStyle, $uv.addStyle(customStyle)]"
          :hover-class="hoverClass"
        >{{icon}}</text>
        <!-- 这里进行空字符串判断,如果仅仅是v-if="label",可能会出现传递0的时候,结果也无法显示 -->
        <text
          v-if="label !== ''"
          class="uv-icon__label"
          :style="{
            color: labelColor,
            fontSize: $uv.addUnit(labelSize),
            marginLeft: labelPos == 'right' ? $uv.addUnit(space) : 0,
            marginTop: labelPos == 'bottom' ? $uv.addUnit(space) : 0,
            marginRight: labelPos == 'left' ? $uv.addUnit(space) : 0,
            marginBottom: labelPos == 'top' ? $uv.addUnit(space) : 0
        }"
        >{{ label }}</text>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    // #ifdef APP-NVUE
    // nvue通过weex的dom模块引入字体,相关文档地址如下:
    // https://weex.apache.org/zh/docs/modules/dom.html#addrule
    import iconUrl from './uvicons.ttf';
    const domModule = weex.requireModule('dom')
    domModule.addRule('fontFace', {
        'fontFamily': "uvicon-iconfont",
        'src': "url('" + iconUrl + "')"
    })
    // #endif
    // 引入图标名称,已经对应的unicode
    import icons from './icons';
    import props from './props.js';
    /**
     * icon 图标
     * @description 基于字体的图标集,包含了大多数常见场景的图标。
     * @tutorial https://www.uvui.cn/components/icon.html
     * @property {String}           name            图标名称,见示例图标集
     * @property {String}           color           图标颜色,可接受主题色 (默认 color['uv-content-color'] )
     * @property {String | Number}  size            图标字体大小,单位px (默认 '16px' )
     * @property {Boolean}          bold            是否显示粗体 (默认 false )
     * @property {String | Number}  index           点击图标的时候传递事件出去的index(用于区分点击了哪一个)
     * @property {String}           hoverClass      图标按下去的样式类,用法同uni的view组件的hoverClass参数,详情见官网
     * @property {String}           customPrefix    自定义扩展前缀,方便用户扩展自己的图标库 (默认 'uicon' )
     * @property {String | Number}  label           图标右侧的label文字
     * @property {String}           labelPos        label相对于图标的位置,只能right或bottom (默认 'right' )
     * @property {String | Number}  labelSize       label字体大小,单位px (默认 '15px' )
     * @property {String}           labelColor      图标右侧的label文字颜色 ( 默认 color['uv-content-color'] )
     * @property {String | Number}  space           label与图标的距离,单位px (默认 '3px' )
     * @property {String}           imgMode         图片的mode
     * @property {String | Number}  width           显示图片小图标时的宽度
     * @property {String | Number}  height          显示图片小图标时的高度
     * @property {String | Number}  top             图标在垂直方向上的定位 用于解决某些情况下,让图标垂直居中的用途  (默认 0 )
     * @property {Boolean}          stop            是否阻止事件传播 (默认 false )
     * @property {Object}           customStyle     icon的样式,对象形式
     * @event {Function} click 点击图标时触发
     * @event {Function} touchstart 事件触摸时触发
     * @example <uv-icon name="photo" color="#2979ff" size="28"></uv-icon>
     */
    export default {
        name: 'uv-icon',
        emits: ['click'],
        mixins: [mpMixin, mixin, props],
        data() {
            return {
                colorType: [
                    'primary',
                    'success',
                    'info',
                    'error',
                    'warning'
                ]
            }
        },
        computed: {
            uClasses() {
                let classes = []
                classes.push(this.customPrefix)
                classes.push(this.customPrefix + '-' + this.name)
                // 主题色,通过类配置
                if (this.color && this.colorType.includes(this.color)) classes.push('uv-icon__icon--' + this.color)
                // 阿里,头条,百度小程序通过数组绑定类名时,无法直接使用[a, b, c]的形式,否则无法识别
                // 故需将其拆成一个字符串的形式,通过空格隔开各个类名
                //#ifdef MP-ALIPAY || MP-TOUTIAO || MP-BAIDU
                classes = classes.join(' ')
                //#endif
                return classes
            },
            iconStyle() {
                let style = {}
                style = {
                    fontSize: this.$uv.addUnit(this.size),
                    lineHeight: this.$uv.addUnit(this.size),
                    fontWeight: this.bold ? 'bold' : 'normal',
                    // 某些特殊情况需要设置一个到顶部的距离,才能更好的垂直居中
                    top: this.$uv.addUnit(this.top)
                }
                // 非主题色值时,才当作颜色值
                if (this.color && !this.colorType.includes(this.color)) style.color = this.color
                return style
            },
            // 判断传入的name属性,是否图片路径,只要带有"/"均认为是图片形式
            isImg() {
                const isBase64 = this.name.indexOf('data:') > -1 && this.name.indexOf('base64') > -1;
                return this.name.indexOf('/') !== -1 || isBase64;
            },
            imgStyle() {
                let style = {}
                // 如果设置width和height属性,则优先使用,否则使用size属性
                style.width = this.width ? this.$uv.addUnit(this.width) : this.$uv.addUnit(this.size)
                style.height = this.height ? this.$uv.addUnit(this.height) : this.$uv.addUnit(this.size)
                return style
            },
            // 通过图标名,查找对应的图标
            icon() {
                // 如果内置的图标中找不到对应的图标,就直接返回name值,因为用户可能传入的是unicode代码
                const code = icons['uvicon-' + this.name];
                // #ifdef APP-NVUE
                if(!code) {
                    return code ? unescape(`%u${code}`) : ['uvicon'].indexOf(this.customPrefix) > -1 ? unescape(`%u${this.name}`) : '';
                }
                // #endif
                return code ? unescape(`%u${code}`) : ['uvicon'].indexOf(this.customPrefix) > -1 ? this.name : '';
            }
        },
        methods: {
            clickHandler(e) {
                this.$emit('click', this.index)
                // 是否阻止事件冒泡
                this.stop && this.preventEvent(e)
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    // 变量定义
    $uv-icon-primary: $uv-primary !default;
    $uv-icon-success: $uv-success !default;
    $uv-icon-info: $uv-info !default;
    $uv-icon-warning: $uv-warning !default;
    $uv-icon-error: $uv-error !default;
    $uv-icon-label-line-height: 1 !default;
    /* #ifndef APP-NVUE */
    // 非nvue下加载字体
    @font-face {
        font-family: 'uvicon-iconfont';
        src: url('./uvicons.ttf') format('truetype');
    }
    /* #endif */
    .uv-icon {
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        align-items: center;
        &--left {
            flex-direction: row-reverse;
            align-items: center;
        }
        &--right {
            flex-direction: row;
            align-items: center;
        }
        &--top {
            flex-direction: column-reverse;
            justify-content: center;
        }
        &--bottom {
            flex-direction: column;
            justify-content: center;
        }
        &__icon {
            font-family: uvicon-iconfont;
            position: relative;
            @include flex;
            align-items: center;
            &--primary {
                color: $uv-icon-primary;
            }
            &--success {
                color: $uv-icon-success;
            }
            &--error {
                color: $uv-icon-error;
            }
            &--warning {
                color: $uv-icon-warning;
            }
            &--info {
                color: $uv-icon-info;
            }
        }
        &__img {
            /* #ifndef APP-NVUE */
            height: auto;
            will-change: transform;
            /* #endif */
        }
        &__label {
            /* #ifndef APP-NVUE */
            line-height: $uv-icon-label-line-height;
            /* #endif */
        }
    }
</style>
ledApp/uni_modules/uv-icon/components/uv-icon/uvicons.ttf
Binary files differ
ledApp/uni_modules/uv-icon/package.json
New file
@@ -0,0 +1,83 @@
{
  "id": "uv-icon",
  "displayName": "uv-icon 图标 全面兼容vue3+2、app、h5、小程序等多端",
  "version": "1.0.13",
  "description": "基于字体的图标集,包含了大多数常见场景的图标,支持自定义,支持自定义图片图标等。可自定义颜色、大小。",
  "keywords": [
    "uv-ui,uvui,uv-icon,icon,图标,字体图标"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
      "ads": "无",
      "data": "插件不采集任何数据",
      "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools"
        ],
    "encrypt": [],
    "platforms": {
      "cloud": {
        "tcb": "y",
        "aliyun": "y"
      },
      "client": {
        "Vue": {
          "vue2": "y",
          "vue3": "y"
        },
        "App": {
          "app-vue": "y",
          "app-nvue": "y"
        },
        "H5-mobile": {
          "Safari": "y",
          "Android Browser": "y",
          "微信浏览器(Android)": "y",
          "QQ浏览器(Android)": "y"
        },
        "H5-pc": {
          "Chrome": "y",
          "IE": "y",
          "Edge": "y",
          "Firefox": "y",
          "Safari": "y"
        },
        "小程序": {
          "微信": "y",
          "阿里": "y",
          "百度": "y",
          "字节跳动": "y",
          "QQ": "y",
          "钉钉": "u",
          "快手": "u",
          "飞书": "u",
          "京东": "u"
        },
        "快应用": {
          "华为": "u",
          "联盟": "u"
        }
      }
    }
  }
}
ledApp/uni_modules/uv-icon/readme.md
New file
@@ -0,0 +1,15 @@
## uv-icon 图标库
> **组件名:uv-icon**
基于字体的图标集,包含了大多数常见场景的图标,支持自定义,支持自定义图片图标等。
# <a href="https://www.uvui.cn/components/icon.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui)
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-image/changelog.md
New file
@@ -0,0 +1,36 @@
## 1.0.16(2023-12-21)
1. 修复设置show-menu-by-longpress不生效的BUG
## 1.0.15(2023-12-06)
1. 优化
## 1.0.14(2023-12-06)
1. 阻止事件冒泡问题
## 1.0.13(2023-11-15)
1. 修复webp之前未使用的BUG
## 1.0.12(2023-10-11)
1. 修复懒加载报错:https://gitee.com/climblee/uv-ui/issues/I869JS
## 1.0.11(2023-08-31)
1. 修复设置widthFix时出现显示不全的BUG
2. 修复抖音等平台在width和height属性改变时出现不显示的BUG
## 1.0.10(2023-08-29)
1. 修复异步修改宽高不生效的问题,问题来源:https://gitee.com/climblee/uv-ui/issues/I7WUQ3
## 1.0.9(2023-08-21)
1. 修复设置宽高为百分比不生效的BUG
## 1.0.8(2023-07-24)
1. 优化 nvue模式下增加cellChild参数,是否在list中cell节点下,nvue中cell下建议设置成true
## 1.0.7(2023-07-02)
修复VUE3模式下可能不显示的BUG
## 1.0.6(2023-07-02)
优化修改
## 1.0.5(2023-06-28)
修复duration属性不生效的BUG
## 1.0.4(2023-05-27)
1. 修复可能报错的问题
## 1.0.3(2023-05-24)
1. 去掉template中存在的this.导致头条小程序编译警告
## 1.0.2(2023-05-23)
1. 优化
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-image 图片
ledApp/uni_modules/uv-image/components/uv-image/props.js
New file
@@ -0,0 +1,95 @@
export default {
    props: {
        // 图片地址
        src: {
            type: String,
            default: ''
        },
        // 裁剪模式
        mode: {
            type: String,
            default: 'aspectFill'
        },
        // 宽度,单位任意
        width: {
            type: [String, Number],
            default: '300'
        },
        // 高度,单位任意
        height: {
            type: [String, Number],
            default: '225'
        },
        // 图片形状,circle-圆形,square-方形
        shape: {
            type: String,
            default: 'square'
        },
        // 圆角,单位任意
        radius: {
            type: [String, Number],
            default: 0
        },
        // 是否懒加载,微信小程序、App、百度小程序、字节跳动小程序
        lazyLoad: {
            type: Boolean,
            default: true
        },
        // 是否开启observer懒加载,nvue不生效
        observeLazyLoad: {
            type: Boolean,
            default: false
        },
        // 开启长按图片显示识别微信小程序码菜单
        showMenuByLongpress: {
            type: Boolean,
            default: true
        },
        // 加载中的图标,或者小图片
        loadingIcon: {
            type: String,
            default: 'photo'
        },
        // 加载失败的图标,或者小图片
        errorIcon: {
            type: String,
            default: 'error-circle'
        },
        // 是否显示加载中的图标或者自定义的slot
        showLoading: {
            type: Boolean,
            default: true
        },
        // 是否显示加载错误的图标或者自定义的slot
        showError: {
            type: Boolean,
            default: true
        },
        // 是否需要淡入效果
        fade: {
            type: Boolean,
            default: true
        },
        // 只支持网络资源,只对微信小程序有效
        webp: {
            type: Boolean,
            default: false
        },
        // 过渡时间,单位ms
        duration: {
            type: [String, Number],
            default: 500
        },
        // 背景颜色,用于深色页面加载图片时,为了和背景色融合
        bgColor: {
            type: String,
            default: '#f3f4f6'
        },
        // nvue模式下 是否直接显示,在uv-list等cell下面使用就需要设置
        cellChild: {
            type: Boolean,
            default: false
        },
        ...uni.$uv?.props?.image
    }
}
ledApp/uni_modules/uv-image/components/uv-image/uv-image.vue
New file
@@ -0,0 +1,287 @@
<template>
    <uv-transition
        v-if="show"
        :show="show"
        mode="fade"
        :duration="fade ? duration : 0"
        :cell-child="cellChild"
        :custom-style="wrapStyle"
    >
        <view
            class="uv-image"
            :class="[`uv-image--${elIndex}`]"
            @tap="onClick"
            :style="[wrapStyle, backgroundStyle]"
        >
            <image
                v-if="!isError && observeShow"
                :src="src"
                :mode="mode"
                @error="onErrorHandler"
                @load="onLoadHandler"
                :show-menu-by-longpress="showMenuByLongpress"
                :lazy-load="lazyLoad"
                class="uv-image__image"
                :style="[imageStyle]"
                :webp="webp"
            ></image>
            <view
                v-if="showLoading && loading"
                class="uv-image__loading"
                :style="{
                    borderRadius: shape == 'circle' ? '50%' : $uv.addUnit(radius),
                    backgroundColor: bgColor,
                    width: $uv.addUnit(width),
                    height: $uv.addUnit(height)
                }"
            >
                <slot name="loading">
                    <uv-icon
                        :name="loadingIcon"
                        :width="width"
                        :height="height"
                    ></uv-icon>
                </slot>
            </view>
            <view
                v-if="showError && isError && !loading"
                class="uv-image__error"
                :style="{
                    borderRadius: shape == 'circle' ? '50%' : $uv.addUnit(radius),
                    width: $uv.addUnit(width),
                    height: $uv.addUnit(height)
                }"
            >
                <slot name="error">
                    <uv-icon
                        :name="errorIcon"
                        :width="width"
                        :height="height"
                    ></uv-icon>
                </slot>
            </view>
        </view>
    </uv-transition>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * Image 图片
     * @description 此组件为uni-app的image组件的加强版,在继承了原有功能外,还支持淡入动画、加载中、加载失败提示、圆角值和形状等。
     * @tutorial https://www.uvui.cn/components/image.html
     * @property {String}           src                 图片地址
     * @property {String}           mode                裁剪模式,见官网说明 (默认 'aspectFill' )
     * @property {String | Number}  width               宽度,单位任意,如果为数值,则为px单位 (默认 '300' )
     * @property {String | Number}  height              高度,单位任意,如果为数值,则为px单位 (默认 '225' )
     * @property {String}           shape               图片形状,circle-圆形,square-方形 (默认 'square' )
     * @property {String | Number}  radius              圆角值,单位任意,如果为数值,则为px单位 (默认 0 )
     * @property {Boolean}          lazyLoad            是否懒加载,仅微信小程序、App、百度小程序、字节跳动小程序有效 (默认 true )
     * @property {Boolean}          showMenuByLongpress 是否开启长按图片显示识别小程序码菜单,仅微信小程序有效 (默认 true )
     * @property {String}           loadingIcon         加载中的图标,或者小图片 (默认 'photo' )
     * @property {String}           errorIcon           加载失败的图标,或者小图片 (默认 'error-circle' )
     * @property {Boolean}          showLoading         是否显示加载中的图标或者自定义的slot (默认 true )
     * @property {Boolean}          showError           是否显示加载错误的图标或者自定义的slot (默认 true )
     * @property {Boolean}          fade                是否需要淡入效果 (默认 true )
     * @property {Boolean}          webp                只支持网络资源,只对微信小程序有效 (默认 false )
     * @property {String | Number}  duration            搭配fade参数的过渡时间,单位ms (默认 500 )
     * @property {String}           bgColor             背景颜色,用于深色页面加载图片时,为了和背景色融合  (默认 '#f3f4f6' )
     * @property {Object}           customStyle         定义需要用到的外部样式
     * @event {Function}    click   点击图片时触发
     * @event {Function}    error   图片加载失败时触发
     * @event {Function} load 图片加载成功时触发
     * @example <uv-image width="100%" height="300px" :src="src"></uv-image>
     */
    export default {
        name: 'uv-image',
        emits: ['click','load','error'],
        mixins: [mpMixin, mixin, props],
        data() {
            return {
                // 图片是否加载错误,如果是,则显示错误占位图
                isError: false,
                // 初始化组件时,默认为加载中状态
                loading: true,
                // 图片加载完成时,去掉背景颜色,因为如果是png图片,就会显示灰色的背景
                backgroundStyle: {},
                // 用于fade模式的控制组件显示与否
                show: false,
                // 是否开启图片出现在可视范围进行加载(另一种懒加载)
                observeShow: !this.observeLazyLoad,
                elIndex: '',
                // 因为props的值无法修改,故需要一个中间值
                imgWidth: this.width,
                // 因为props的值无法修改,故需要一个中间值
                imgHeight: this.height,
                thresholdValue: 50
            };
        },
        watch: {
            src: {
                immediate: true,
                handler(n) {
                    if (!n) {
                        // 如果传入null或者'',或者false,或者undefined,标记为错误状态
                        this.isError = true
                    } else {
                        this.isError = false;
                        this.loading = true;
                    }
                }
            },
            width(newVal){
                // 这样做的目的是避免在更新时候,某些平台动画会恢复关闭状态
                this.show = false;
                this.$uv.sleep(2).then(res=>{
                    this.show = true;
                });
                this.imgWidth = newVal;
            },
            height(newVal){
                // 这样做的目的是避免在更新时候,某些平台动画会恢复关闭状态
                this.show = false;
                this.$uv.sleep(2).then(res=>{
                    this.show = true;
                });
                this.imgHeight = newVal;
            }
        },
        computed: {
            wrapStyle() {
                let style = {};
                // 通过调用addUnit()方法,如果有单位,如百分比,px单位等,直接返回,如果是纯粹的数值,则加上rpx单位
                if(this.mode !== 'heightFix') {
                    style.width = this.$uv.addUnit(this.imgWidth);
                }
                if(this.mode !== 'widthFix') {
                    style.height = this.$uv.addUnit(this.imgHeight);
                }
                // 如果是显示圆形,设置一个很多的半径值即可
                style.borderRadius = this.shape == 'circle' ? '10000px' : this.$uv.addUnit(this.radius)
                // 如果设置圆角,必须要有hidden,否则可能圆角无效
                style.overflow = this.radius > 0 ? 'hidden' : 'visible'
                return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle));
            },
            imageStyle() {
                let style = {};
                style.borderRadius = this.shape == 'circle' ? '10000px' : this.$uv.addUnit(this.radius);
                // #ifdef APP-NVUE
                style.width = this.$uv.addUnit(this.imgWidth);
                style.height = this.$uv.addUnit(this.imgHeight);
                // #endif
                return style;
            }
        },
        created() {
            this.elIndex = this.$uv.guid();
            this.observer = {}
            this.observerName = 'lazyLoadContentObserver'
        },
        mounted() {
            this.show = true;
            this.$nextTick(()=>{
                if(this.observeLazyLoad) this.observerFn();
            })
        },
        methods: {
            // 点击图片
            onClick() {
                this.$emit('click')
            },
            // 图片加载失败
            onErrorHandler(err) {
                this.loading = false
                this.isError = true
                this.$emit('error', err)
            },
            // 图片加载完成,标记loading结束
            onLoadHandler(event) {
                if(this.mode == 'widthFix') this.imgHeight = 'auto'
                if(this.mode == 'heightFix') this.imgWidth = 'auto'
                this.loading = false
                this.isError = false
                this.$emit('load', event)
                this.removeBgColor()
            },
            // 移除图片的背景色
            removeBgColor() {
                // 淡入动画过渡完成后,将背景设置为透明色,否则png图片会看到灰色的背景
                this.backgroundStyle = {
                    backgroundColor: 'transparent'
                };
            },
            // 观察图片是否在可见视口
            observerFn(){
                // 在需要用到懒加载的页面,在触发底部的时候触发tOnLazyLoadReachBottom事件,保证所有图片进行加载
                this.$nextTick(() => {
                    uni.$once('onLazyLoadReachBottom', () => {
                        if (!this.observeShow) this.observeShow = true
                    })
                })
                setTimeout(() => {
                    // #ifndef APP-NVUE
                    this.disconnectObserver(this.observerName)
                    const contentObserver = uni.createIntersectionObserver(this)
                    contentObserver.relativeToViewport({
                        bottom: this.thresholdValue
                    }).observe(`.uv-image--${this.elIndex}`, (res) => {
                        if (res.intersectionRatio > 0) {
                            // 懒加载状态改变
                            this.observeShow = true
                            // 如果图片已经加载,去掉监听,减少性能消耗
                            this.disconnectObserver(this.observerName)
                        }
                    })
                    this[this.observerName] = contentObserver
                    // #endif
                    // #ifdef APP-NVUE
                    this.observeShow = true;
                    // #endif
                }, 50)
            },
            disconnectObserver(observerName) {
                const observer = this[observerName]
                observer && observer.disconnect()
            }
        }
    };
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    $uv-image-error-top:0px !default;
    $uv-image-error-left:0px !default;
    $uv-image-error-width:100% !default;
    $uv-image-error-hight:100% !default;
    $uv-image-error-background-color:$uv-bg-color !default;
    $uv-image-error-color:$uv-tips-color !default;
    $uv-image-error-font-size: 46rpx !default;
    .uv-image {
        position: relative;
        transition: opacity 0.5s ease-in-out;
        &__image {
            width: 100%;
            height: 100%;
        }
        &__loading,
        &__error {
            position: absolute;
            top: $uv-image-error-top;
            left: $uv-image-error-left;
            width: $uv-image-error-width;
            height: $uv-image-error-hight;
            @include flex;
            align-items: center;
            justify-content: center;
            background-color: $uv-image-error-background-color;
            color: $uv-image-error-color;
            font-size: $uv-image-error-font-size;
        }
    }
</style>
ledApp/uni_modules/uv-image/package.json
New file
@@ -0,0 +1,89 @@
{
  "id": "uv-image",
  "displayName": "uv-image 图片 全面兼容vue3+2、app、h5、小程序等多端",
  "version": "1.0.16",
  "description": "uv-image 此组件为uni-app的image组件的加强版,在继承了原有功能外,增加observer懒加载功能,还支持淡入动画、加载中、加载失败提示、圆角值和形状等。",
  "keywords": [
    "uv-image",
    "uvui",
    "uv-ui",
    "image",
    "图片"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools",
            "uv-transition",
            "uv-icon"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-image/readme.md
New file
@@ -0,0 +1,15 @@
## Image 图片
> **组件名:uv-image**
此组件为`uni-app`的`image`组件的加强版,在继承了原有功能外,增加`observer`懒加载功能,还支持淡入动画、加载中、加载失败提示、圆角值和形状等。
# <a href="https://www.uvui.cn/components/image.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui)
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-index-list/changelog.md
New file
@@ -0,0 +1,18 @@
## 1.0.7(2023-11-07)
1. 修复sticky属性不生效的BUG
## 1.0.6(2023-09-01)
1. 修复设置customNavHeight导致定位不准确的BUG
## 1.0.5(2023-08-23)
1. 修复ios端快速滑动+点击右侧导航会出现白屏的BUG
## 1.0.4(2023-07-25)
1. 修复全局设置成rpx存在的高度BUG
2. 修复其他BUG
## 1.0.3(2023-07-03)
去除插槽判断,避免某些平台不显示的BUG
## 1.0.2(2023-05-27)
1. select事件修复
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-index-list 索引列表
ledApp/uni_modules/uv-index-list/components/uv-index-anchor/props.js
New file
@@ -0,0 +1,30 @@
export default {
    props: {
        // 列表锚点文本内容
        text: {
            type: [String, Number],
            default: ''
        },
        // 列表锚点文字颜色
        color: {
            type: String,
            default: '#606266'
        },
        // 列表锚点文字大小,单位默认px
        size: {
            type: [String, Number],
            default: 14
        },
        // 列表锚点背景颜色
        bgColor: {
            type: String,
            default: '#dedede'
        },
        // 列表锚点高度,单位默认px
        height: {
            type: [String, Number],
            default: 32
        },
        ...uni.$uv?.props?.indexAnchor
    }
}
ledApp/uni_modules/uv-index-list/components/uv-index-anchor/uv-index-anchor.vue
New file
@@ -0,0 +1,98 @@
<template>
    <!-- #ifdef APP-NVUE -->
    <header>
    <!-- #endif -->
    <view
      :class="['uv-index-anchor',{'uv-index-anchor-sticky': parentData.sticky}]"
        :ref="`uv-index-anchor-${text}`"
      :style="{
            height: $uv.addUnit(height),
            backgroundColor: bgColor
        }"
    >
        <text
          class="uv-index-anchor__text"
          :style="{
                fontSize: $uv.addUnit(size),
                color: color
            }"
        >{{ text }}</text>
    </view>
    <!-- #ifdef APP-NVUE -->
    </header>
    <!-- #endif -->
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    // #ifdef APP-NVUE
    const dom = uni.requireNativePlugin('dom')
    // #endif
    /**
     * IndexAnchor 列表锚点
     * @description
     * @tutorial https://www.uvui.cn/components/indexList.html
     * @property {String | Number}  text    列表锚点文本内容
     * @property {String}           color   列表锚点文字颜色 ( 默认 '#606266' )
     * @property {String | Number}  size    列表锚点文字大小,单位默认px ( 默认 14 )
     * @property {String}           bgColor 列表锚点背景颜色 ( 默认 '#dedede' )
     * @property {String | Number}  height  列表锚点高度,单位默认px ( 默认 32 )
     * @example <uv-index-anchor :text="indexList[index]"></uv-index-anchor>
     */
    export default {
        name: 'uv-index-anchor',
        mixins: [mpMixin, mixin, props],
        data() {
            return {
                parentData: {
                    sticky: true
                }
            }
        },
        created() {
            this.init()
        },
        methods: {
            init() {
                // 此处会活动父组件实例,并赋值给实例的parent属性
                const indexList = this.$uv.$parent.call(this, 'uv-index-list')
                if (!indexList) {
                    return this.$uv.error('uv-index-anchor必须要搭配uv-index-list组件使用')
                }
                this.parentData.sticky = indexList.sticky;
                // 将当前实例放入到uv-index-list中
                indexList.anchors.push(this)
                const indexListItem = this.$uv.$parent.call(this, 'uv-index-item')
                // #ifndef APP-NVUE
                // 只有在非nvue下,uv-index-anchor才是嵌套在uv-index-item中的
                if (!indexListItem) {
                    return this.$uv.error('uv-index-anchor必须要搭配uv-index-item组件使用')
                }
                // 设置uv-index-item的id为anchor的text标识符,因为非nvue下滚动列表需要依赖scroll-view滚动到元素的特性
                indexListItem.id = this.text.charCodeAt(0)
                // #endif
            }
        },
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    .uv-index-anchor {
        @include flex;
        align-items: center;
        padding-left: 15px;
        z-index: 1;
        &-sticky {
            position: sticky;
            top: 0;
        }
        &__text {
            @include flex;
            align-items: center;
        }
    }
</style>
ledApp/uni_modules/uv-index-list/components/uv-index-item/uv-index-item.vue
New file
@@ -0,0 +1,87 @@
<template>
    <!-- #ifdef APP-NVUE -->
    <cell ref="uv-index-item">
        <!-- #endif -->
        <view
            class="uv-index-item"
            :id="`uv-index-item-${id}`"
            :class="[`uv-index-item-${id}`]"
        >
            <slot />
        </view>
        <!-- #ifdef APP-NVUE -->
    </cell>
    <!-- #endif -->
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    // #ifdef APP-NVUE
    // 由于weex为阿里的KPI业绩考核的产物,所以不支持百分比单位,这里需要通过dom查询组件的宽度
    const dom = uni.requireNativePlugin('dom')
    // #endif
    /**
     * IndexItem
     * @description
     * @tutorial https://www.uvui.cn/components/indexList.html
     * @property {String}
     * @event {Function}
     * @example
     */
    export default {
        name: 'uv-index-item',
        mixins: [mpMixin, mixin],
        data() {
            return {
                // 本组件到滚动条顶部的距离
                top: 0,
                height: 0,
                id: ''
            }
        },
        created() {
            // 子组件uv-index-anchor的实例
            this.anchor = {}
        },
        mounted() {
            this.init()
        },
        methods: {
            init() {
                // 此处会活动父组件实例,并赋值给实例的parent属性
                this.getParentData('uv-index-list')
                if (!this.parent) {
                    return this.$uv.error('uv-index-item必须要搭配uv-index-list组件使用')
                }
                this.$uv.sleep().then(() =>{
                    this.getIndexItemRect().then(size => {
                        // 由于对象的引用特性,此处会同时生效到父组件的children数组的本实例的top属性中,供父组件判断读取
                        this.top = Math.ceil(size.top)
                        this.height = Math.ceil(size.height)
                    })
                })
            },
            getIndexItemRect() {
                return new Promise(resolve => {
                    // #ifndef APP-NVUE
                    this.$uvGetRect('.uv-index-item').then(size => {
                        resolve(size)
                    })
                    // #endif
                    // #ifdef APP-NVUE
                    const ref = this.$refs['uv-index-item']
                    dom.getComponentRect(ref, res => {
                        resolve(res.size)
                    })
                    // #endif
                })
            }
        },
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
</style>
ledApp/uni_modules/uv-index-list/components/uv-index-list/props.js
New file
@@ -0,0 +1,30 @@
export default {
    props: {
        // 右边锚点非激活的颜色
        inactiveColor: {
            type: String,
            default: '#606266'
        },
        // 右边锚点激活的颜色
        activeColor: {
            type: String,
            default: '#5677fc'
        },
        // 索引字符列表,数组形式
        indexList: {
            type: Array,
            default: () => []
        },
        // 是否开启锚点自动吸顶
        sticky: {
            type: Boolean,
            default: true
        },
        // 自定义导航栏的高度
        customNavHeight: {
            type: [String, Number],
            default: 0
        },
        ...uni.$uv?.props?.indexList
    }
}
ledApp/uni_modules/uv-index-list/components/uv-index-list/uv-index-list.vue
New file
@@ -0,0 +1,461 @@
<template>
    <view class="uv-index-list">
        <!-- #ifdef APP-NVUE -->
        <list
            :scrollTop="scrollTop"
            enable-back-to-top
            :offset-accuracy="1"
            :style="{
                maxHeight: $uv.addUnit(scrollViewHeight,'px')
            }"
            @scroll="scrollHandler"
            ref="uvList"
        >
            <cell ref="header">
                <slot name="header" />
            </cell>
            <slot />
            <cell>
                <slot name="footer" />
            </cell>
        </list>
        <!-- #endif -->
        <!-- #ifndef APP-NVUE -->
        <scroll-view
            :scrollTop="scrollTop"
            :scrollIntoView="scrollIntoView"
            :offset-accuracy="1"
            :style="{
                maxHeight: $uv.addUnit(scrollViewHeight,'px')
            }"
            scroll-y
            @scroll="scrollHandler"
            ref="uvList"
        >
            <view>
                <slot name="header" />
            </view>
            <slot />
            <view>
                <slot name="footer" />
            </view>
        </scroll-view>
        <!-- #endif -->
        <view
            class="uv-index-list__letter"
            ref="uv-index-list__letter"
            :style="{ top: $uv.addUnit(letterInfo.top || 100 ,'px') }"
            @touchstart="touchStart"
            @touchmove.stop.prevent="touchMove"
            @touchend.stop.prevent="touchEnd"
            @touchcancel.stop.prevent="touchEnd"
        >
            <view
                class="uv-index-list__letter__item"
                v-for="(item, index) in uIndexList"
                :key="index"
                :style="{
                    backgroundColor: activeIndex === index ? activeColor : 'transparent'
                }"
            >
                <text
                    class="uv-index-list__letter__item__index"
                    :style="{color: activeIndex === index ? '#fff' : inactiveColor}"
                >{{ item }}</text>
            </view>
        </view>
        <uv-transition
            mode="fade"
            :show="touching"
            :customStyle="{
                position: 'fixed',
                right: '40px',
                top: $uv.addUnit(indicatorTop,'px'),
                zIndex: 2
            }"
        >
            <view class="uv-index-list__indicator__box">
                <view
                    class="uv-index-list__indicator"
                    :class="['uv-index-list__indicator--show']"
                    :style="{
                        height: $uv.addUnit(indicatorHeight,'px'),
                        width: $uv.addUnit(indicatorHeight,'px')
                    }"
                >
                    <text class="uv-index-list__indicator__text">{{ uIndexList[activeIndex] }}</text>
                </view>
            </view>
        </uv-transition>
    </view>
</template>
<script>
    const indexList = () => {
        const indexList = [];
        const charCodeOfA = 'A'.charCodeAt(0);
        for (let i = 0; i < 26; i++) {
            indexList.push(String.fromCharCode(charCodeOfA + i));
        }
        return indexList;
    }
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    // #ifdef APP-NVUE
    // 由于weex为阿里的KPI业绩考核的产物,所以不支持百分比单位,这里需要通过dom查询组件的宽度
    const dom = uni.requireNativePlugin('dom')
    // #endif
    /**
     * IndexList 索引列表
     * @description  通过折叠面板收纳内容区域
     * @tutorial https://www.uvui.cn/components/indexList.html
     * @property {String}           inactiveColor   右边锚点非激活的颜色 ( 默认 '#606266' )
     * @property {String}           activeColor     右边锚点激活的颜色 ( 默认 '#5677fc' )
     * @property {Array}            indexList       索引字符列表,数组形式
     * @property {Boolean}          sticky          是否开启锚点自动吸顶 ( 默认 true )
     * @property {String | Number}  customNavHeight 自定义导航栏的高度 ( 默认 0 )
     * */
    export default {
        name: 'uv-index-list',
        mixins: [mpMixin, mixin, props],
        // #ifdef MP-WEIXIN
        // 将自定义节点设置成虚拟的,更加接近Vue组件的表现,能更好的使用flex属性
        options: {
            virtualHost: true
        },
        // #endif
        data() {
            return {
                // 当前正在被选中的字母索引
                activeIndex: -1,
                touchmoveIndex: 1,
                // 索引字母的信息
                letterInfo: {
                    height: 0,
                    itemHeight: 0,
                    top: 0
                },
                // 设置字母指示器的高度,后面为了让指示器跟随字母,并将尖角部分指向字母的中部,需要依赖此值
                indicatorHeight: 50,
                // 字母放大指示器的top值,为了让其指向当前激活的字母
                // indicatorTop: 0
                // 当前是否正在被触摸状态
                touching: false,
                // 滚动条顶部top值
                scrollTop: 0,
                // scroll-view的高度
                scrollViewHeight: 0,
                // 系统信息
                sys: '',
                scrolling: false,
                scrollIntoView: '',
                hasHeight: 0,
                timer: 0,
                disTap: false
            }
        },
        computed: {
            // 如果有传入外部的indexList锚点数组则使用,否则使用内部生成A-Z字母
            uIndexList() {
                return this.indexList.length ? this.indexList : indexList()
            },
            // 字母放大指示器的top值,为了让其指向当前激活的字母
            indicatorTop() {
                const {
                    top,
                    itemHeight
                } = this.letterInfo
                return Math.floor(top + itemHeight * this.activeIndex + itemHeight / 2 - this.indicatorHeight / 2) - 8
            }
        },
        watch: {
            // 监听字母索引的变化,重新设置尺寸
            uIndexList: {
                immediate: true,
                handler() {
                    this.$uv.sleep().then(() => {
                        this.setIndexListLetterInfo()
                    })
                }
            }
        },
        created() {
            this.sys = this.$uv.sys()
            this.children = []
            this.anchors = []
            this.init()
        },
        mounted() {
            this.setIndexListLetterInfo()
        },
        methods: {
            init() {
                // 设置列表的高度为整个屏幕的高度
                //减去this.customNavHeight,并将this.scrollViewHeight设置为maxHeight
                //解决当uv-index-list组件放在tabbar页面时,scroll-view内容较少时,还能滚动
                this.scrollViewHeight = this.sys.windowHeight - this.$uv.getPx(this.customNavHeight)
            },
            // 索引列表被触摸
            touchStart(e) {
                // 获取触摸点信息
                const touchStart = e.changedTouches[0]
                if (!touchStart || this.disTap) return
                this.touching = true
                const {
                    pageY
                } = touchStart
                // 根据当前触摸点的坐标,获取当前触摸的为第几个字母
                const currentIndex = this.getIndexListLetter(pageY)
                this.setValueForTouch(currentIndex)
            },
            // 索引字母列表被触摸滑动中
            touchMove(e) {
                // 获取触摸点信息
                let touchMove = e.changedTouches[0]
                if (!touchMove || this.disTap) return;
                // 滑动结束后迅速开始第二次滑动时候 touching 为 false 造成不显示 indicator 问题
                if (!this.touching) {
                    this.touching = true
                }
                const {
                    pageY
                } = touchMove
                const currentIndex = this.getIndexListLetter(pageY)
                this.setValueForTouch(currentIndex)
            },
            // 触摸结束
            touchEnd(e) {
                // 延时一定时间后再隐藏指示器,为了让用户看的更直观,同时也是为了消除快速切换uv-transition的show带来的影响
                this.$uv.sleep(300).then(() => {
                    this.touching = false
                })
                this.$emit('select',this.activeIndex);
            },
            // 获取索引列表的尺寸以及单个字符的尺寸信息
            getIndexListLetterRect() {
                return new Promise(resolve => {
                    // 延时一定时间,以获取dom尺寸
                    // #ifndef APP-NVUE
                    this.$uvGetRect('.uv-index-list__letter').then(size => {
                        resolve(size)
                    })
                    // #endif
                    // #ifdef APP-NVUE
                    const ref = this.$refs['uv-index-list__letter']
                    dom.getComponentRect(ref, res => {
                        resolve(res.size)
                    })
                    // #endif
                })
            },
            // 设置indexList索引的尺寸信息
            setIndexListLetterInfo() {
                this.getIndexListLetterRect().then(size => {
                    const {
                        top,
                        height
                    } = size
                    const windowHeight = this.$uv.sys().windowHeight;
                    let customNavHeight = 0
                    // 消除各端导航栏非原生和原生导致的差异,让索引列表字母对屏幕垂直居中
                    if (this.customNavHeight == 0) {
                        // #ifdef H5
                        customNavHeight = this.$uv.sys().windowTop
                        // #endif
                        // #ifndef H5
                        // 在非H5中,为原生导航栏,其高度不算在windowHeight内,这里设置为负值,后面相加时变成减去其高度的一半
                        customNavHeight = 0
                        // #endif
                    } else {
                        customNavHeight = this.$uv.getPx(this.customNavHeight)
                    }
                    this.letterInfo = {
                        height,
                        // 为了让字母列表对屏幕绝对居中,让其对导航栏进行修正,也即往上偏移导航栏的一半高度
                        top: (windowHeight - height) / 2 + customNavHeight / 2,
                        itemHeight: Math.floor(height / this.uIndexList.length)
                    }
                })
            },
            // 获取当前被触摸的索引字母
            getIndexListLetter(pageY) {
                const {
                    top,
                    height,
                    itemHeight
                } = this.letterInfo
                // 对H5的pageY进行修正,这是由于uni-app自作多情在H5中将触摸点的坐标跟H5的导航栏结合导致的问题
                // #ifdef H5
                pageY += this.$uv.sys().windowTop
                // #endif
                // #ifdef APP-NVUE
                pageY += top
                // #endif
                // 对第一和最后一个字母做边界处理,因为用户可能在字母列表上触摸到两端的尽头后依然继续滑动
                if (pageY < top) {
                    return 0
                } else if (pageY >= top + height) {
                    // 如果超出了,取最后一个字母
                    return this.uIndexList.length - 1
                } else {
                    // 将触摸点的Y轴偏移值,减去索引字母的top值,除以每个字母的高度,即可得到当前触摸点落在哪个字母上
                    return Math.floor((pageY - top) / itemHeight);
                }
            },
            // 设置各项由触摸而导致变化的值
            setValueForTouch(currentIndex) {
                // 如果偏移量太小,前后得出的会是同一个索引字母,为了防抖,进行返回
                if (currentIndex === this.activeIndex) return
                this.activeIndex = currentIndex
                // #ifndef APP-NVUE || MP-WEIXIN
                // 在非nvue中,由于anchor和item都在uv-index-item中,所以需要对index-item进行偏移
                this.scrollIntoView = `uv-index-item-${this.uIndexList[currentIndex].charCodeAt(0)}`
                // #endif
                // #ifdef MP-WEIXIN
                // 微信小程序下,scroll-view的scroll-into-view属性无法对slot中的内容的id生效,只能通过设置scrollTop的形式去移动滚动条
                this.scrollTop = this.children[currentIndex].top
                // #endif
                // #ifdef APP-NVUE
                // 在nvue中,由于cell和header为同级元素,所以实际是需要对header(anchor)进行偏移
                const anchor = `uv-index-anchor-${this.uIndexList[currentIndex]}`
                dom.scrollToElement(this.anchors[currentIndex].$refs[anchor], {
                    offset: 0,
                    animated: false
                })
                // #endif
            },
            getHeaderRect() {
                // 获取header slot的高度,因为list组件中获取元素的尺寸是没有top值的
                return new Promise(resolve => {
                    dom.getComponentRect(this.$refs.header, res => {
                        resolve(res.size)
                    })
                })
            },
            // scroll-view的滚动事件
            async scrollHandler(e) {
                if (this.touching || this.scrolling) return
                // 每过一定时间取样一次,减少资源损耗以及可能带来的卡顿
                this.scrolling = true
                this.disTap = true;
                clearTimeout(this.timer);
                this.timer = setTimeout(()=>{
                    this.disTap = false;
                },200)
                this.$uv.sleep(30).then(() => {
                    this.scrolling = false
                })
                let scrollTop = 0
                const len = this.children.length
                let children = this.children
                const anchors = this.anchors
                const customNavHeight = this.$uv.getPx(this.customNavHeight);
                // #ifdef APP-NVUE
                // nvue下获取的滚动条偏移为负数,需要转为正数
                scrollTop = Math.abs(e.contentOffset.y)
                // 获取header slot的尺寸信息
                const header = await this.getHeaderRect()
                // item的top值,在nvue下,模拟出的anchor的top,类似非nvue下的index-item的top
                let top = header.height
                // 由于list组件无法获取cell的top值,这里通过header slot和各个item之间的height,模拟出类似非nvue下的位置信息
                children = this.children.map((item, index) => {
                    if(item.height>0) this.hasHeight = item.height;
                    item.height = item.height>0?item.height:this.hasHeight;
                    const child = {
                        height: item.height,
                        top
                    }
                    // 进行累加,给下一个item提供计算依据
                    top += item.height + anchors[index].height
                    return child
                })
                // #endif
                // #ifndef APP-NVUE
                // 非nvue通过detail获取滚动条位移
                scrollTop = e.detail.scrollTop
                // #endif
                for (let i = 0; i < len; i++) {
                    const item = children[i],
                        nextItem = children[i + 1]
                    // 如果滚动条高度小于第一个item的top值,此时无需设置任意字母为高亮
                    if (scrollTop + customNavHeight <= children[0].top || scrollTop >= children[len - 1].top + children[len -
                            1].height) {
                        this.activeIndex = -1
                        break
                    } else if (!nextItem) {
                        // 当不存在下一个item时,意味着历遍到了最后一个
                        this.activeIndex = len - 1
                        break
                    } else if (scrollTop + customNavHeight > item.top && scrollTop + customNavHeight < nextItem.top) {
                        this.activeIndex = i
                        break
                    }
                }
            },
        },
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    .uv-index-list {
        &__letter {
            position: fixed;
            right: 0;
            text-align: center;
            z-index: 3;
            padding: 0 6px;
            &__item {
                width: 16px;
                height: 16px;
                border-radius: 100px;
                margin: 1px 0;
                @include flex;
                align-items: center;
                justify-content: center;
                &--active {
                    background-color: $uv-primary;
                }
                &__index {
                    font-size: 12px;
                    text-align: center;
                    line-height: 12px;
                }
            }
        }
        &__indicator__box {
            width: 65px;
            height: 65px;
            padding: 6px;
            transform: rotate(-45deg);
        }
        &__indicator {
            width: 50px;
            height: 50px;
            border-radius: 100px 100px 0 100px;
            text-align: center;
            color: #ffffff;
            background-color: #c9c9c9;
            @include flex;
            justify-content: center;
            align-items: center;
            &__text {
                font-size: 28px;
                line-height: 28px;
                font-weight: bold;
                color: #fff;
                transform: rotate(45deg);
                text-align: center;
            }
        }
    }
</style>
ledApp/uni_modules/uv-index-list/package.json
New file
@@ -0,0 +1,88 @@
{
  "id": "uv-index-list",
  "displayName": "uv-index-list 索引列表 全面兼容vue3+2、app、h5、小程序等多端",
  "version": "1.0.7",
  "description": "该组件用于展示索引列表,右侧带索引的列表,方便快速定位到具体内容,通常用于城市/机场选择等场景。类似于微信通讯录页面",
  "keywords": [
    "uv-index-list",
    "uvui",
    "uv-ui",
    "index-list",
    "索引列表"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools",
            "uv-transition"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-index-list/readme.md
New file
@@ -0,0 +1,19 @@
## IndexList 索引列表
> **组件名:uv-index-list**
用于展示索引列表,右侧带索引的列表,方便快速定位到具体内容,通常用于城市/机场选择等场景,类似于微信通讯录页面。
# <a href="https://www.uvui.cn/components/indexList.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>(请不要 下载插件ZIP)</small>
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
</a>
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-input/changelog.md
New file
@@ -0,0 +1,29 @@
## 1.0.13(2023-12-06)
1. 优化
## 1.0.12(2023-12-06)
1. 阻止事件冒泡问题
## 1.0.11(2023-11-10)
1. 调整清除按钮样式的marginLeft,避免微信上多数情况触发不了的BUG
## 1.0.10(2023-10-07)
1. 修复搜狗输入法下存在不可清空的情况
## 1.0.9(2023-09-14)
1. 修复H5等情况设置禁用或可读情况下,点击事件无效的问题
## 1.0.8(2023-08-22)
1. 修复无法@keyboardheightchange无法获取键盘高度的BUG
## 1.0.7(2023-08-18)
1. 修复ios端不能输入的BUG
## 1.0.6(2023-08-05)
1. 修复在vue2模式下,v-model设置为0时不生效的BUG
## 1.0.5(2023-07-18)
1. 修复在微信小程序端清除内容存在不能清除的BUG
## 1.0.4(2023-07-13)
1.  修复value/v-model更改不生效的BUG
## 1.0.3(2023-07-03)
去除插槽判断,避免某些平台不显示的BUG
## 1.0.2(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.1(2023-05-12)
1. 修复vue3双向绑定的BUG
## 1.0.0(2023-05-10)
uv-input 输入框
ledApp/uni_modules/uv-input/components/uv-input/props.js
New file
@@ -0,0 +1,175 @@
export default {
    props: {
        value: {
            type: [String, Number],
            default: ''
        },
        modelValue: {
            type: [String, Number],
            default: ''
        },
        // 输入框类型
        // number-数字输入键盘,app-vue下可以输入浮点数,app-nvue和小程序平台下只能输入整数
        // idcard-身份证输入键盘,微信、支付宝、百度、QQ小程序
        // digit-带小数点的数字键盘,App的nvue页面、微信、支付宝、百度、头条、QQ小程序
        // text-文本输入键盘
        type: {
            type: String,
            default: 'text'
        },
        // 是否禁用输入框
        disabled: {
            type: Boolean,
            default: false
        },
        // 禁用状态时的背景色
        disabledColor: {
            type: String,
            default: '#f5f7fa'
        },
        // 是否显示清除控件
        clearable: {
            type: Boolean,
            default: false
        },
        // 是否密码类型
        password: {
            type: Boolean,
            default: false
        },
        // 最大输入长度,设置为 -1 的时候不限制最大长度
        maxlength: {
            type: [String, Number],
            default: -1
        },
        //  输入框为空时的占位符
        placeholder: {
            type: String,
            default: null
        },
        // 指定placeholder的样式类,注意页面或组件的style中写了scoped时,需要在类名前写/deep/
        placeholderClass: {
            type: String,
            default: 'input-placeholder'
        },
        // 指定placeholder的样式
        placeholderStyle: {
            type: [String, Object],
            default: 'color: #c0c4cc'
        },
        // 设置右下角按钮的文字,有效值:send|search|next|go|done,兼容性详见uni-app文档
        // https://uniapp.dcloud.io/component/input
        // https://uniapp.dcloud.io/component/textarea
        confirmType: {
            type: String,
            default: 'done'
        },
        // 点击键盘右下角按钮时是否保持键盘不收起,H5无效
        confirmHold: {
            type: Boolean,
            default: false
        },
        // focus时,点击页面的时候不收起键盘,微信小程序有效
        holdKeyboard: {
            type: Boolean,
            default: false
        },
        // 自动获取焦点
        // 在 H5 平台能否聚焦以及软键盘是否跟随弹出,取决于当前浏览器本身的实现。nvue 页面不支持,需使用组件的 focus()、blur() 方法控制焦点
        focus: {
            type: Boolean,
            default: false
        },
        // 键盘收起时,是否自动失去焦点,目前仅App3.0.0+有效
        autoBlur: {
            type: Boolean,
            default: false
        },
        // 指定focus时光标的位置
        cursor: {
            type: [String, Number],
            default: -1
        },
        // 输入框聚焦时底部与键盘的距离
        cursorSpacing: {
            type: [String, Number],
            default: 30
        },
        // 光标起始位置,自动聚集时有效,需与selection-end搭配使用
        selectionStart: {
            type: [String, Number],
            default: -1
        },
        // 光标结束位置,自动聚集时有效,需与selection-start搭配使用
        selectionEnd: {
            type: [String, Number],
            default: -1
        },
        // 键盘弹起时,是否自动上推页面
        adjustPosition: {
            type: Boolean,
            default: true
        },
        // 输入框内容对齐方式,可选值为:left|center|right
        inputAlign: {
            type: String,
            default: 'left'
        },
        // 输入框字体的大小
        fontSize: {
            type: [String, Number],
            default: '14px'
        },
        // 输入框字体颜色
        color: {
            type: String,
            default: '#303133'
        },
        // 输入框前置图标
        prefixIcon: {
            type: String,
            default: ''
        },
        // 前置图标样式,对象或字符串
        prefixIconStyle: {
            type: [String, Object],
            default: ''
        },
        // 输入框后置图标
        suffixIcon: {
            type: String,
            default: ''
        },
        // 后置图标样式,对象或字符串
        suffixIconStyle: {
            type: [String, Object],
            default: ''
        },
        // 边框类型,surround-四周边框,bottom-底部边框,none-无边框
        border: {
            type: String,
            default: 'surround'
        },
        // 是否只读,与disabled不同之处在于disabled会置灰组件,而readonly则不会
        readonly: {
            type: Boolean,
            default: false
        },
        // 输入框形状,circle-圆形,square-方形
        shape: {
            type: String,
            default: 'square'
        },
        // 用于处理或者过滤输入框内容的方法
        formatter: {
            type: [Function, null],
            default: null
        },
        // 是否忽略组件内对文本合成系统事件的处理
        ignoreCompositionEvent: {
            type: Boolean,
            default: true
        },
        ...uni.$uv?.props?.input
    }
}
ledApp/uni_modules/uv-input/components/uv-input/uv-input.vue
New file
@@ -0,0 +1,348 @@
<template>
    <view class="uv-input" :class="inputClass" :style="[wrapperStyle]">
      <view class="uv-input__content">
        <view class="uv-input__content__prefix-icon">
          <slot name="prefix">
            <uv-icon
                            v-if="prefixIcon"
              :name="prefixIcon"
              size="18"
              :customStyle="prefixIconStyle"
            ></uv-icon>
          </slot>
        </view>
        <view class="uv-input__content__field-wrapper" @click="clickHandler">
                <!-- 根据uni-app的input组件文档,H5和APP中只要声明了password参数(无论true还是false),type均失效,此时
                为了防止type=number时,又存在password属性,type无效,此时需要设置password为undefined
             -->
            <input
              class="uv-input__content__field-wrapper__field"
              :style="[inputStyle]"
              :type="type"
              :focus="focus"
              :cursor="cursor"
              :value="innerValue"
              :auto-blur="autoBlur"
              :disabled="disabled || readonly"
              :maxlength="maxlength"
              :placeholder="placeholder"
              :placeholder-style="placeholderStyle"
              :placeholder-class="placeholderClass"
              :confirm-type="confirmType"
              :confirm-hold="confirmHold"
              :hold-keyboard="holdKeyboard"
              :cursor-spacing="cursorSpacing"
              :adjust-position="adjustPosition"
              :selection-end="selectionEnd"
              :selection-start="selectionStart"
              :password="password || type === 'password' || undefined"
            :ignoreCompositionEvent="ignoreCompositionEvent"
              @input="onInput"
              @blur="onBlur"
              @focus="onFocus"
              @confirm="onConfirm"
              @keyboardheightchange="onkeyboardheightchange"
            />
        </view>
        <view
          class="uv-input__content__clear"
          v-if="isShowClear"
          @tap="onClear"
        >
          <uv-icon
            name="close"
            size="11"
            color="#ffffff"
            customStyle="line-height: 12px"
          ></uv-icon>
        </view>
        <view class="uv-input__content__subfix-icon">
          <slot name="suffix">
            <uv-icon
                            v-if="suffixIcon"
              :name="suffixIcon"
              size="18"
              :customStyle="suffixIconStyle"
            ></uv-icon>
          </slot>
        </view>
      </view>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from "./props.js";
    /**
     * Input 输入框
     * @description  此组件为一个输入框,默认没有边框和样式,是专门为配合表单组件uv-form而设计的,利用它可以快速实现表单验证,输入内容,下拉选择等功能。
     * @tutorial https://www.uvui.cn/components/input.html
     * @property {String | Number}  value                   输入的值
     * @property {String}           type                    输入框类型,见上方说明 ( 默认 'text' )
     * @property {Boolean}          fixed                   如果 textarea 是在一个 position:fixed 的区域,需要显示指定属性 fixed 为 true,兼容性:微信小程序、百度小程序、字节跳动小程序、QQ小程序 ( 默认 false )
     * @property {Boolean}          disabled                是否禁用输入框 ( 默认 false )
     * @property {String}           disabledColor           禁用状态时的背景色( 默认 '#f5f7fa' )
     * @property {Boolean}          clearable               是否显示清除控件 ( 默认 false )
     * @property {Boolean}          password                是否密码类型 ( 默认 false )
     * @property {String | Number}  maxlength               最大输入长度,设置为 -1 的时候不限制最大长度 ( 默认 -1 )
     * @property {String}           placeholder             输入框为空时的占位符
     * @property {String}           placeholderClass        指定placeholder的样式类,注意页面或组件的style中写了scoped时,需要在类名前写/deep/ ( 默认 'input-placeholder' )
     * @property {String | Object}  placeholderStyle        指定placeholder的样式,字符串/对象形式,如"color: red;"
     * @property {Boolean}          showWordLimit           是否显示输入字数统计,只在 type ="text"或type ="textarea"时有效 ( 默认 false )
     * @property {String}           confirmType             设置右下角按钮的文字,兼容性详见uni-app文档 ( 默认 'done' )
     * @property {Boolean}          confirmHold             点击键盘右下角按钮时是否保持键盘不收起,H5无效 ( 默认 false )
     * @property {Boolean}          holdKeyboard            focus时,点击页面的时候不收起键盘,微信小程序有效 ( 默认 false )
     * @property {Boolean}          focus                   自动获取焦点,在 H5 平台能否聚焦以及软键盘是否跟随弹出,取决于当前浏览器本身的实现。nvue 页面不支持,需使用组件的 focus()、blur() 方法控制焦点 ( 默认 false )
     * @property {Boolean}          autoBlur                键盘收起时,是否自动失去焦点,目前仅App3.0.0+有效 ( 默认 false )
     * @property {Boolean}          disableDefaultPadding   是否去掉 iOS 下的默认内边距,仅微信小程序,且type=textarea时有效 ( 默认 false )
     * @property {String | Number}  cursor                  指定focus时光标的位置( 默认 -1 )
     * @property {String | Number}  cursorSpacing           输入框聚焦时底部与键盘的距离 ( 默认 30 )
     * @property {String | Number}  selectionStart          光标起始位置,自动聚集时有效,需与selection-end搭配使用 ( 默认 -1 )
     * @property {String | Number}  selectionEnd            光标结束位置,自动聚集时有效,需与selection-start搭配使用 ( 默认 -1 )
     * @property {Boolean}          adjustPosition          键盘弹起时,是否自动上推页面 ( 默认 true )
     * @property {String}           inputAlign              输入框内容对齐方式( 默认 'left' )
     * @property {String | Number}  fontSize                输入框字体的大小 ( 默认 '15px' )
     * @property {String}           color                   输入框字体颜色 ( 默认 '#303133' )
     * @property {Function}         formatter               内容式化函数
     * @property {String}           prefixIcon              输入框前置图标
     * @property {String | Object}  prefixIconStyle         前置图标样式,对象或字符串
     * @property {String}           suffixIcon              输入框后置图标
     * @property {String | Object}  suffixIconStyle         后置图标样式,对象或字符串
     * @property {String}           border                  边框类型,surround-四周边框,bottom-底部边框,none-无边框 ( 默认 'surround' )
     * @property {Boolean}          readonly                是否只读,与disabled不同之处在于disabled会置灰组件,而readonly则不会 ( 默认 false )
     * @property {String}           shape                   输入框形状,circle-圆形,square-方形 ( 默认 'square' )
     * @property {Object}           customStyle             定义需要用到的外部样式
     * @property {Boolean}          ignoreCompositionEvent  是否忽略组件内对文本合成系统事件的处理。
     * @example <uv-input v-model="value" :password="true" suffix-icon="lock-fill" />
     */
    export default {
        name: "uv-input",
        mixins: [mpMixin, mixin, props],
        data() {
            return {
                // 输入框的值
                innerValue: "",
                // 是否处于获得焦点状态
                focused: false,
                // 过滤处理方法
                innerFormatter: value => value
            }
        },
        created() {
            // #ifdef VUE2
            this.innerValue = this.value;
            // #endif
            // #ifdef VUE3
            this.innerValue = this.modelValue;
            // #endif
        },
        watch: {
            value(newVal){
                this.innerValue = newVal;
            },
            modelValue(newVal){
                this.innerValue = newVal;
            }
        },
        computed: {
            // 是否显示清除控件
            isShowClear() {
                const { clearable, readonly, focused, innerValue } = this;
                return !!clearable && !readonly && !!focused && innerValue !== "";
            },
            // 组件的类名
            inputClass() {
                let classes = [],
                    { border, disabled, shape } = this;
                border === "surround" &&
                    (classes = classes.concat(["uv-border", "uv-input--radius"]));
                classes.push(`uv-input--${shape}`);
                border === "bottom" &&
                    (classes = classes.concat([
                        "uv-border-bottom",
                        "uv-input--no-radius",
                    ]));
                return classes.join(" ");
            },
            // 组件的样式
            wrapperStyle() {
                const style = {};
                // 禁用状态下,被背景色加上对应的样式
                if (this.disabled) {
                    style.backgroundColor = this.disabledColor;
                }
                // 无边框时,去除内边距
                if (this.border === "none") {
                    style.padding = "0";
                } else {
                    // 由于uni-app的iOS开发者能力有限,导致需要分开写才有效
                    style.paddingTop = "6px";
                    style.paddingBottom = "6px";
                    style.paddingLeft = "9px";
                    style.paddingRight = "9px";
                }
                return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle));
            },
            // 输入框的样式
            inputStyle() {
                const style = {
                    color: this.color,
                    fontSize: this.$uv.addUnit(this.fontSize),
                    textAlign: this.inputAlign
                };
                // #ifndef APP-NVUE
                if(this.disabled || this.readonly) {
                    style['pointer-events'] = 'none';
                }
                // #endif
                return style;
            }
        },
        methods: {
            // 在微信小程序中,不支持将函数当做props参数,故只能通过ref形式调用
            setFormatter(e) {
                this.innerFormatter = e
            },
            // 当键盘输入时,触发input事件
            onInput(e) {
                let { value = "" } = e.detail || {};
                // 格式化过滤方法
                const formatter = this.formatter || this.innerFormatter
                const formatValue = formatter(value)
                // 为了避免props的单向数据流特性,需要先将innerValue值设置为当前值,再在$nextTick中重新赋予设置后的值才有效
                this.innerValue = value
                this.$nextTick(() => {
                    this.innerValue = formatValue;
                    this.valueChange();
                })
            },
            // 输入框失去焦点时触发
            onBlur(event) {
                this.$emit("blur", event.detail.value);
                // H5端的blur会先于点击清除控件的点击click事件触发,导致focused
                // 瞬间为false,从而隐藏了清除控件而无法被点击到
                this.$uv.sleep(100).then(() => {
                    this.focused = false;
                });
                // 尝试调用uv-form的验证方法
                this.$uv.formValidate(this, "blur");
            },
            // 输入框聚焦时触发
            onFocus(event) {
                this.focused = true;
                this.$emit("focus");
            },
            // 点击完成按钮时触发
            onConfirm(event) {
                this.$emit("confirm", this.innerValue);
            },
            // 键盘高度发生变化的时候触发此事件
            // 兼容性:微信小程序2.7.0+、App 3.1.0+
            onkeyboardheightchange(e) {
                this.$emit("keyboardheightchange",e);
            },
            // 内容发生变化,进行处理
            valueChange() {
                if(this.isClear) this.innerValue = '';
                const value = this.innerValue;
                this.$nextTick(() => {
                    this.$emit("input", value);
                    this.$emit("update:modelValue", value);
                    this.$emit("change", value);
                    // 尝试调用uv-form的验证方法
                    this.$uv.formValidate(this, "change");
                });
            },
            // 点击清除控件
            onClear() {
                this.innerValue = "";
                this.isClear = true;
                this.$uv.sleep(200).then(res=>{
                    this.isClear = false;
                })
                this.$nextTick(() => {
                    this.$emit("clear");
                    this.valueChange();
                });
            },
            /**
             * 在安卓nvue上,事件无法冒泡
             * 在某些时间,我们希望监听uv-from-item的点击事件,此时会导致点击uv-form-item内的uv-input后
             * 无法触发uv-form-item的点击事件,这里通过手动调用uv-form-item的方法进行触发
             */
            clickHandler() {
                // #ifdef APP-NVUE
                if (this.$uv.os() === "android") {
                    const formItem = this.$uv.$parent.call(this, "uv-form-item");
                    if (formItem) {
                        formItem.clickHandler();
                    }
                }
                // #endif
            }
        }
    }
</script>
<style lang="scss" scoped>
    $show-border: 1;
    $show-border-surround: 1;
    $show-border-bottom: 1;
    @import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    .uv-input {
        @include flex(row);
        align-items: center;
        justify-content: space-between;
        flex: 1;
        &--radius,
        &--square {
            border-radius: 4px;
        }
        &--no-radius {
            border-radius: 0;
        }
        &--circle {
            border-radius: 100px;
        }
        &__content {
            flex: 1;
            @include flex(row);
            align-items: center;
            justify-content: space-between;
            &__field-wrapper {
                position: relative;
                @include flex(row);
                margin: 0;
                flex: 1;
                &__field {
                    line-height: 26px;
                    text-align: left;
                    color: $uv-main-color;
                    height: 24px;
                    font-size: 15px;
                    flex: 1;
                }
            }
            &__clear {
                width: 20px;
                height: 20px;
                border-radius: 100px;
                background-color: #c6c7cb;
                @include flex(row);
                align-items: center;
                justify-content: center;
                transform: scale(0.82);
                margin-left: 15px;
            }
            &__subfix-icon {
                margin-left: 4px;
            }
            &__prefix-icon {
                margin-right: 4px;
            }
        }
    }
</style>
ledApp/uni_modules/uv-input/package.json
New file
@@ -0,0 +1,88 @@
{
  "id": "uv-input",
  "displayName": "uv-input 输入框 全面兼容vue3+2、app、h5、小程序等多端",
  "version": "1.0.13",
  "description": "uv-input 该组件为一个输入框,默认没有边框和样式,是专门为配合表单组件uv-form而设计的,利用它可以快速实现表单验证,输入内容,下拉选择等功能。",
  "keywords": [
    "uv-input",
    "uvui",
    "uv-ui",
    "input",
    "输入框"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools",
            "uv-icon"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-input/readme.md
New file
@@ -0,0 +1,19 @@
## Input 输入框
> **组件名:uv-input**
此组件为一个输入框,默认没有边框和样式,是专门为配合表单组件uv-form而设计的,利用它可以快速实现表单验证,输入内容,下拉选择等功能。
# <a href="https://www.uvui.cn/components/input.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>(请不要 下载插件ZIP)</small>
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
</a>
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-keyboard/changelog.md
New file
@@ -0,0 +1,17 @@
## 1.0.5(2023-10-12)
1. 增加disKeys参数,mode = "car"下,被禁用的键,如:['I','O']
2. 增加customabc参数,mode = "car"下,是否启用自定义中英文切换内容模式,为了兼容支付宝等小程序不兼容嵌套插槽,导致同时显示自定义内容和原始内容
3. 增加ref方法changeCarMode,mode = "car"下, 调用此方法可以切换中英文模式
4. 增加@changeCarInputMode,mode = "car"下,调用此方法可以进行切换中英文
5. 增加插槽abc,mode = "car"下,自定义中英文切换内容,具体参考[车牌键盘自定义中英文切换及禁用键等设置](https://www.uvui.cn/components/keyboard.html#车牌键盘自定义中英文切换及禁用键等设置)
## 1.0.4(2023-09-04)
1. 优化,修改文件名称
## 1.0.3(2023-09-04)
1. 修复键盘change回调事件产生冲突的BUG
## 1.0.2(2023-07-02)
uv-keyboard  由于弹出层uv-popup的修改,打开和关闭方法更改,详情参考文档:https://www.uvui.cn/components/keyboard.html
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-keyboard 键盘
ledApp/uni_modules/uv-keyboard/components/uv-keyboard-car/props.js
New file
@@ -0,0 +1,24 @@
export default {
    props: {
        // 是否打乱键盘按键的顺序
        random: {
            type: Boolean,
            default: false
        },
        // 输入一个中文后,是否自动切换到英文
        autoChange: {
            type: Boolean,
            default: false
        },
        // 被禁用的键
        disKeys: {
            type: Array,
            default: ()=>[]
        },
        // 是否自定义abc
        customabc: {
            type: Boolean,
            default: false
        }
    }
}
ledApp/uni_modules/uv-keyboard/components/uv-keyboard-car/uv-keyboard-car.vue
New file
@@ -0,0 +1,347 @@
<template>
    <view
        class="uv-keyboard"
        @touchmove.stop.prevent="noop"
    >
        <view
            v-for="(group, i) in abc ? engKeyBoardList : areaList"
            :key="i"
            class="uv-keyboard__button"
            :index="i"
            :class="[i + 1 === 4 && 'uv-keyboard__button--center']"
        >
            <view
                v-if="i === 3"
                class="uv-keyboard__button__inner-wrapper"
            >
                <view
                    class="uv-keyboard__button__inner-wrapper__left"
                    hover-class="uv-hover-class"
                    :hover-stay-time="200"
                    @tap="changeCarInputMode"
                >
                    <slot>
                        <template v-if="!customabc">
                            <text
                                class="uv-keyboard__button__inner-wrapper__left__lang"
                                :class="[!abc && 'uv-keyboard__button__inner-wrapper__left__lang--active']"
                            >中</text>
                            <text class="uv-keyboard__button__inner-wrapper__left__line">/</text>
                            <text
                                class="uv-keyboard__button__inner-wrapper__left__lang"
                                :class="[abc && 'uv-keyboard__button__inner-wrapper__left__lang--active']"
                            >英</text>
                        </template>
                    </slot>
                </view>
            </view>
            <view
                class="uv-keyboard__button__inner-wrapper"
                v-for="(item, j) in group"
                :key="j"
            >
                <view
                    :class="['uv-keyboard__button__inner-wrapper__inner',{'uv-keyboard__button__inner-wrapper__inner--disabled': isDisabled(i,j)}]"
                    :hover-stay-time="200"
                    @tap="carInputClick(i, j)"
                    :hover-class="isDisabled(i,j)?'none':'uv-hover-class'"
                >
                    <text class="uv-keyboard__button__inner-wrapper__inner__text">{{ item }}</text>
                </view>
                <view class="uv-keyboard__button__inner-wrapper__disabled--mask" v-if="isDisabled(i,j)"></view>
            </view>
            <view
                v-if="i === 3"
                @touchstart="backspaceClick"
                @touchend="clearTimer"
                class="uv-keyboard__button__inner-wrapper"
            >
                <view
                    class="uv-keyboard__button__inner-wrapper__right"
                    hover-class="uv-hover-class"
                    :hover-stay-time="200"
                >
                    <uv-icon
                        size="28"
                        name="backspace"
                        color="#303133"
                    ></uv-icon>
                </view>
            </view>
        </view>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * keyboard 键盘组件
     * @description 此为uvui自定义的键盘面板,内含了数字键盘,车牌号键,身份证号键盘3种模式,都有可以打乱按键顺序的选项。
     * @tutorial https://www.uvui.cn/components/keyboard.html
     * @property {Boolean} random 是否打乱键盘的顺序
     * @event {Function} change 点击键盘触发
     * @event {Function} backspace 点击退格键触发
     * @example <uv-keyboard ref="uKeyboard" mode="car" v-model="show"></uv-keyboard>
     */
    export default {
        name: "uv-keyboard",
        mixins: [mpMixin, mixin, props],
        emits: ['backspace','change','changeCarInputMode'],
        data() {
            return {
                // 车牌输入时,abc=true为输入车牌号码,bac=false为输入省份中文简称
                abc: false
            };
        },
        computed: {
            areaList() {
                let data = [
                    '京',
                    '沪',
                    '粤',
                    '津',
                    '冀',
                    '豫',
                    '云',
                    '辽',
                    '黑',
                    '湘',
                    '皖',
                    '鲁',
                    '苏',
                    '浙',
                    '赣',
                    '鄂',
                    '桂',
                    '甘',
                    '晋',
                    '陕',
                    '蒙',
                    '吉',
                    '闽',
                    '贵',
                    '渝',
                    '川',
                    '青',
                    '琼',
                    '宁',
                    '挂',
                    '藏',
                    '港',
                    '澳',
                    '新',
                    '使',
                    '学'
                ];
                let tmp = [];
                // 打乱顺序
                if (this.random) data = this.$uv.randomArray(data);
                // 切割成二维数组
                tmp[0] = data.slice(0, 10);
                tmp[1] = data.slice(10, 20);
                tmp[2] = data.slice(20, 30);
                tmp[3] = data.slice(30, 36);
                return tmp;
            },
            engKeyBoardList() {
                let data = [
                    1,
                    2,
                    3,
                    4,
                    5,
                    6,
                    7,
                    8,
                    9,
                    0,
                    'Q',
                    'W',
                    'E',
                    'R',
                    'T',
                    'Y',
                    'U',
                    'I',
                    'O',
                    'P',
                    'A',
                    'S',
                    'D',
                    'F',
                    'G',
                    'H',
                    'J',
                    'K',
                    'L',
                    'Z',
                    'X',
                    'C',
                    'V',
                    'B',
                    'N',
                    'M'
                ];
                let tmp = [];
                if (this.random) data = this.$uv.randomArray(data);
                tmp[0] = data.slice(0, 10);
                tmp[1] = data.slice(10, 20);
                tmp[2] = data.slice(20, 30);
                tmp[3] = data.slice(30, 36);
                return tmp;
            },
            isDisabled(i,j) {
                return (i,j)=>{
                    let value = '';
                    if (this.abc) value = this.engKeyBoardList[i][j];
                    else value = this.areaList[i][j];
                    return this.disKeys.indexOf(value) > -1;
                }
            }
        },
        methods: {
            // 点击键盘按钮
            carInputClick(i, j) {
                if(this.isDisabled(i,j)) return;
                let value = '';
                // 不同模式,获取不同数组的值
                if (this.abc) value = this.engKeyBoardList[i][j];
                else value = this.areaList[i][j];
                // 如果允许自动切换,则将中文状态切换为英文
                if (!this.abc && this.autoChange) this.$uv.sleep(200).then(() => this.abc = true)
                this.$emit('change', value);
            },
            // 修改汽车牌键盘的输入模式,中文|英文
            changeCarInputMode() {
                this.abc = !this.abc;
                this.$emit('changeCarInputMode',this.abc);
            },
            // 点击退格键
            backspaceClick() {
                this.$emit('backspace');
                clearInterval(this.timer); //再次清空定时器,防止重复注册定时器
                this.timer = null;
                this.timer = setInterval(() => {
                    this.$emit('backspace');
                }, 250);
            },
            clearTimer() {
                clearInterval(this.timer);
                this.timer = null;
            },
        }
    };
</script>
<style lang="scss" scoped>
    $show-hover: 1;
    @import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    $uv-car-keyboard-background-color: rgb(224, 228, 230) !default;
    $uv-car-keyboard-padding:6px 0 6px !default;
    $uv-car-keyboard-button-inner-width:64rpx !default;
    $uv-car-keyboard-button-inner-background-color:#FFFFFF !default;
    $uv-car-keyboard-button-height:80rpx !default;
    $uv-car-keyboard-button-inner-box-shadow:0 1px 0px #999992 !default;
    $uv-car-keyboard-button-border-radius:4px !default;
    $uv-car-keyboard-button-inner-margin:8rpx 5rpx !default;
    $uv-car-keyboard-button-text-font-size:16px !default;
    $uv-car-keyboard-button-text-color:$uv-main-color !default;
    $uv-car-keyboard-center-inner-margin: 0 4rpx !default;
    $uv-car-keyboard-special-button-width:134rpx !default;
    $uv-car-keyboard-lang-font-size:16px !default;
    $uv-car-keyboard-lang-color:$uv-main-color !default;
    $uv-car-keyboard-active-color:$uv-primary !default;
    $uv-car-keyboard-line-font-size:15px !default;
    $uv-car-keyboard-line-color:$uv-main-color !default;
    $uv-car-keyboard-line-margin:0 1px !default;
    $uv-car-keyboard-uv-hover-class-background-color:#BBBCC6 !default;
    .uv-keyboard {
        @include flex(column);
        justify-content: space-around;
        background-color: $uv-car-keyboard-background-color;
        align-items: stretch;
        padding: $uv-car-keyboard-padding;
        &__button {
            @include flex;
            justify-content: center;
            flex: 1;
            /* #ifndef APP-NVUE */
            /* #endif */
            &__inner-wrapper {
                position: relative;
                box-shadow: $uv-car-keyboard-button-inner-box-shadow;
                margin: $uv-car-keyboard-button-inner-margin;
                border-radius: $uv-car-keyboard-button-border-radius;
                &__disabled--mask {
                    position: absolute;
                    left: 0;
                    top: 0;
                    bottom: 0;
                    right: 0;
                    width: $uv-car-keyboard-button-inner-width;
                    height: $uv-car-keyboard-button-height;
                }
                &__inner {
                    @include flex;
                    justify-content: center;
                    align-items: center;
                    width: $uv-car-keyboard-button-inner-width;
                    background-color: $uv-car-keyboard-button-inner-background-color;
                    height: $uv-car-keyboard-button-height;
                    border-radius: $uv-car-keyboard-button-border-radius;
                    &--disabled {
                        opacity: 0.5;
                    }
                    &__text {
                        font-size: $uv-car-keyboard-button-text-font-size;
                        color: $uv-car-keyboard-button-text-color;
                    }
                }
                &__left,
                &__right {
                    border-radius: $uv-car-keyboard-button-border-radius;
                    width: $uv-car-keyboard-special-button-width;
                    height: $uv-car-keyboard-button-height;
                    background-color: $uv-car-keyboard-uv-hover-class-background-color;
                    @include flex;
                    justify-content: center;
                    align-items: center;
                    box-shadow: $uv-car-keyboard-button-inner-box-shadow;
                }
                &__left {
                    &__line {
                        font-size: $uv-car-keyboard-line-font-size;
                        color: $uv-car-keyboard-line-color;
                        margin: $uv-car-keyboard-line-margin;
                    }
                    &__lang {
                        font-size: $uv-car-keyboard-lang-font-size;
                        color: $uv-car-keyboard-lang-color;
                        &--active {
                            color: $uv-car-keyboard-active-color;
                        }
                    }
                }
            }
        }
    }
    .uv-hover-class {
        background-color: $uv-car-keyboard-uv-hover-class-background-color;
    }
</style>
ledApp/uni_modules/uv-keyboard/components/uv-keyboard-number/props.js
New file
@@ -0,0 +1,19 @@
export default {
    props: {
        // 键盘的类型,number-数字键盘,card-身份证键盘
        mode: {
            type: String,
            default: 'number'
        },
        // 是否显示键盘的"."符号
        dotDisabled: {
            type: Boolean,
            default: false
        },
        // 是否打乱键盘按键的顺序
        random: {
            type: Boolean,
            default: false
        }
    }
}
ledApp/uni_modules/uv-keyboard/components/uv-keyboard-number/uv-keyboard-number.vue
New file
@@ -0,0 +1,201 @@
<template>
    <view
        class="uv-keyboard"
        @touchmove.stop.prevent="noop"
    >
        <view
            class="uv-keyboard__button-wrapper"
            v-for="(item, index) in numList"
            :key="index"
        >
            <view
                class="uv-keyboard__button-wrapper__button"
                :style="[itemStyle(index)]"
                @tap="keyboardClick(item)"
                hover-class="uv-hover-class"
                :hover-stay-time="200"
            >
                <text class="uv-keyboard__button-wrapper__button__text">{{ item }}</text>
            </view>
        </view>
        <view
            class="uv-keyboard__button-wrapper"
        >
            <view
                class="uv-keyboard__button-wrapper__button uv-keyboard__button-wrapper__button--gray"
                hover-class="uv-hover-class"
                :hover-stay-time="200"
                @touchstart.stop="backspaceClick"
                @touchend="clearTimer"
            >
                <uv-icon
                    name="backspace"
                    color="#303133"
                    size="28"
                ></uv-icon>
            </view>
        </view>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * keyboard 键盘组件
     * @description
     * @tutorial
     * @property {String}   mode        键盘的类型,number-数字键盘,card-身份证键盘
     * @property {Boolean}  dotDisabled 是否显示键盘的"."符号
     * @property {Boolean}  random      是否打乱键盘按键的顺序
     * @event {Function} change     点击键盘触发
     * @event {Function} backspace  点击退格键触发
     * @example
     */
    export default {
        mixins: [mpMixin, mixin, props],
        emits: ['backspace','change'],
        data() {
            return {
                backspace: 'backspace', // 退格键内容
                dot: '.', // 点
                timer: null, // 长按多次删除的事件监听
                cardX: 'X' // 身份证的X符号
            };
        },
        computed: {
            // 键盘需要显示的内容
            numList() {
                let tmp = [];
                if (this.dotDisabled && this.mode == 'number') {
                    if (!this.random) {
                        return [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
                    } else {
                        return this.$uv.randomArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
                    }
                } else if (!this.dotDisabled && this.mode == 'number') {
                    if (!this.random) {
                        return [1, 2, 3, 4, 5, 6, 7, 8, 9, this.dot, 0];
                    } else {
                        return this.$uv.randomArray([1, 2, 3, 4, 5, 6, 7, 8, 9, this.dot, 0]);
                    }
                } else if (this.mode == 'card') {
                    if (!this.random) {
                        return [1, 2, 3, 4, 5, 6, 7, 8, 9, this.cardX, 0];
                    } else {
                        return this.$uv.randomArray([1, 2, 3, 4, 5, 6, 7, 8, 9, this.cardX, 0]);
                    }
                }
            },
            // 按键的样式,在非乱序&&数字键盘&&不显示点按钮时,index为9时,按键占位两个空间
            itemStyle() {
                return index => {
                    let style = {};
                    if (this.mode == 'number' && this.dotDisabled && index == 9) style.width = '464rpx';
                    return style;
                };
            },
            // 是否让按键显示灰色,只在非乱序&&数字键盘&&且允许点按键的时候
            btnBgGray() {
                return index => {
                    if (!this.random && index == 9 && (this.mode != 'number' || (this.mode == 'number' && !this
                            .dotDisabled))) return true;
                    else return false;
                };
            },
        },
        created() {
        },
        methods: {
            // 点击退格键
            backspaceClick() {
                this.$emit('backspace');
                clearInterval(this.timer); //再次清空定时器,防止重复注册定时器
                this.timer = null;
                this.timer = setInterval(() => {
                    this.$emit('backspace');
                }, 250);
            },
            clearTimer() {
                clearInterval(this.timer);
                this.timer = null;
            },
            // 获取键盘显示的内容
            keyboardClick(val) {
                // 允许键盘显示点模式和触发非点按键时,将内容转为数字类型
                if (!this.dotDisabled && val != this.dot && val != this.cardX) val = Number(val);
                this.$emit('change', val);
            }
        }
    };
</script>
<style lang="scss" scoped>
    $show-hover: 1;
    @import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    $uv-number-keyboard-background-color:rgb(224, 228, 230) !default;
    $uv-number-keyboard-padding:8px 10rpx 8px 10rpx !default;
    $uv-number-keyboard-button-width:222rpx !default;
    $uv-number-keyboard-button-margin:4px 6rpx !default;
    $uv-number-keyboard-button-border-top-left-radius:4px !default;
    $uv-number-keyboard-button-border-top-right-radius:4px !default;
    $uv-number-keyboard-button-border-bottom-left-radius:4px !default;
    $uv-number-keyboard-button-border-bottom-right-radius:4px !default;
    $uv-number-keyboard-button-height: 90rpx!default;
    $uv-number-keyboard-button-background-color:#FFFFFF !default;
    $uv-number-keyboard-button-box-shadow:0 2px 0px #BBBCBE !default;
    $uv-number-keyboard-text-font-size:20px !default;
    $uv-number-keyboard-text-font-weight:500 !default;
    $uv-number-keyboard-text-color:$uv-main-color !default;
    $uv-number-keyboard-gray-background-color:rgb(200, 202, 210) !default;
    $uv-number-keyboard-uv-hover-class-background-color: #BBBCC6 !default;
    .uv-keyboard {
        @include flex;
        flex-direction: row;
        justify-content: space-around;
        background-color: $uv-number-keyboard-background-color;
        flex-wrap: wrap;
        padding: $uv-number-keyboard-padding;
        &__button-wrapper {
            box-shadow: $uv-number-keyboard-button-box-shadow;
            margin: $uv-number-keyboard-button-margin;
            border-top-left-radius: $uv-number-keyboard-button-border-top-left-radius;
            border-top-right-radius: $uv-number-keyboard-button-border-top-right-radius;
            border-bottom-left-radius: $uv-number-keyboard-button-border-bottom-left-radius;
            border-bottom-right-radius: $uv-number-keyboard-button-border-bottom-right-radius;
            &__button {
                width: $uv-number-keyboard-button-width;
                height: $uv-number-keyboard-button-height;
                background-color: $uv-number-keyboard-button-background-color;
                @include flex;
                justify-content: center;
                align-items: center;
                border-top-left-radius: $uv-number-keyboard-button-border-top-left-radius;
                border-top-right-radius: $uv-number-keyboard-button-border-top-right-radius;
                border-bottom-left-radius: $uv-number-keyboard-button-border-bottom-left-radius;
                border-bottom-right-radius: $uv-number-keyboard-button-border-bottom-right-radius;
                &__text {
                    font-size: $uv-number-keyboard-text-font-size;
                    font-weight: $uv-number-keyboard-text-font-weight;
                    color: $uv-number-keyboard-text-color;
                }
                &--gray {
                    background-color: $uv-number-keyboard-gray-background-color;
                }
            }
        }
    }
    .uv-hover-class {
        background-color: $uv-number-keyboard-uv-hover-class-background-color;
    }
</style>
ledApp/uni_modules/uv-keyboard/components/uv-keyboard/props.js
New file
@@ -0,0 +1,95 @@
export default {
    props: {
        // 键盘的类型,number-数字键盘,card-身份证键盘,car-车牌号键盘
        mode: {
            type: String,
            default: 'number'
        },
        // 是否显示键盘的"."符号
        dotDisabled: {
            type: Boolean,
            default: false
        },
        // 是否显示顶部工具条
        tooltip: {
            type: Boolean,
            default: true
        },
        // 是否显示工具条中间的提示
        showTips: {
            type: Boolean,
            default: true
        },
        // 工具条中间的提示文字
        tips: {
            type: String,
            default: ''
        },
        // 是否显示工具条左边的"取消"按钮
        showCancel: {
            type: Boolean,
            default: true
        },
        // 是否显示工具条右边的"完成"按钮
        showConfirm: {
            type: Boolean,
            default: true
        },
        // 是否打乱键盘按键的顺序
        random: {
            type: Boolean,
            default: false
        },
        // 是否开启底部安全区适配,开启的话,会在iPhoneX机型底部添加一定的内边距
        safeAreaInsetBottom: {
            type: Boolean,
            default: true
        },
        // 是否允许通过点击遮罩关闭键盘
        closeOnClickOverlay: {
            type: Boolean,
            default: true
        },
        // 是否允许点击确认按钮关闭组件
        closeOnClickConfirm: {
            type: Boolean,
            default: true
        },
        // 是否显示遮罩,某些时候数字键盘时,用户希望看到自己的数值,所以可能不想要遮罩
        overlay: {
            type: Boolean,
            default: true
        },
        // z-index值
        zIndex: {
            type: [String, Number],
            default: 10075
        },
        // 取消按钮的文字
        cancelText: {
            type: String,
            default: '取消'
        },
        // 确认按钮的文字
        confirmText: {
            type: String,
            default: '确定'
        },
        // 输入一个中文后,是否自动切换到英文
        autoChange: {
            type: Boolean,
            default: false
        },
        // 被禁用的键
        disKeys: {
            type: Array,
            default: ()=>[]
        },
        // 是否自定义abc
        customabc: {
            type: Boolean,
            default: false
        },
        ...uni.$uv?.props?.keyboard
    }
}
ledApp/uni_modules/uv-keyboard/components/uv-keyboard/uv-keyboard.vue
New file
@@ -0,0 +1,180 @@
<template>
    <uv-popup
        ref="keyboardPopup"
        mode="bottom"
      :overlay="overlay"
      :closeOnClickOverlay="closeOnClickOverlay"
      :safeAreaInsetBottom="safeAreaInsetBottom"
      :zIndex="zIndex"
      :customStyle="{ backgroundColor: 'rgb(214, 218, 220)' }"
        @change="popupChange"
    >
        <view class="uv-keyboard">
            <slot />
            <view
              class="uv-keyboard__tooltip"
              v-if="tooltip"
            >
                <view
                  hover-class="uv-hover-class"
                  :hover-stay-time="100"
                >
                    <text
                      class="uv-keyboard__tooltip__item uv-keyboard__tooltip__cancel"
                      v-if="showCancel"
                      @tap="onCancel"
                    >{{showCancel && cancelText}}</text>
                </view>
                <view>
                    <text
                      v-if="showTips"
                      class="uv-keyboard__tooltip__item uv-keyboard__tooltip__tips"
                    >{{tips ? tips : mode == 'number' ? '数字键盘' : mode == 'card' ? '身份证键盘' : '车牌号键盘'}}</text>
                </view>
                <view
                  hover-class="uv-hover-class"
                  :hover-stay-time="100"
                >
                    <text
                      v-if="showConfirm"
                      @tap="onConfirm"
                      class="uv-keyboard__tooltip__item uv-keyboard__tooltip__submit"
                      hover-class="uv-hover-class"
                    >{{showConfirm && confirmText}}</text>
                </view>
            </view>
            <template v-if="mode == 'number' || mode == 'card'">
                <uv-keyboard-number
                  :random="random"
                  @backspace="backspace"
                  @change="change"
                  :mode="mode"
                  :dotDisabled="dotDisabled"
                ></uv-keyboard-number>
            </template>
            <template v-else>
                <uv-keyboard-car
                    ref="uvKeyboardCarRef"
                  :random="random"
                    :autoChange="autoChange"
                    :disKeys="disKeys"
                    :customabc="customabc"
                  @backspace="backspace"
                  @change="change"
                    @changeCarInputMode="changeCarInputMode"
                >
                    <slot name="abc"></slot>
                </uv-keyboard-car>
            </template>
        </view>
    </uv-popup>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * keyboard 键盘
     * @description 此为uViw自定义的键盘面板,内含了数字键盘,车牌号键,身份证号键盘3中模式,都有可以打乱按键顺序的选项。
     * @tutorial https://www.uvui.cn/components/keyboard.html
     * @property {String}           mode                键盘类型,见官网基本使用的说明 (默认 'number' )
     * @property {Boolean}          dotDisabled         是否显示"."按键,只在mode=number时有效 (默认 false )
     * @property {Boolean}          tooltip             是否显示键盘顶部工具条 (默认 true )
     * @property {Boolean}          showTips            是否显示工具条中间的提示 (默认 true )
     * @property {String}           tips                工具条中间的提示文字,见上方基本使用的说明,如不需要,请传""空字符
     * @property {Boolean}          showCancel          是否显示工具条左边的"取消"按钮 (默认 true )
     * @property {Boolean}          showConfirm         是否显示工具条右边的"完成"按钮( 默认 true )
     * @property {Boolean}          random              是否打乱键盘按键的顺序 (默认 false )
     * @property {Boolean}          safeAreaInsetBottom 是否开启底部安全区适配 (默认 true )
     * @property {Boolean}          closeOnClickOverlay 是否允许点击遮罩收起键盘 (默认 true )
     * @property {Boolean}          show                控制键盘的弹出与收起(默认 false )
     * @property {Boolean}          overlay             是否显示遮罩 (默认 true )
     * @property {String | Number}  zIndex              弹出键盘的z-index值 (默认 1075 )
     * @property {String}           cancelText          取消按钮的文字 (默认 '取消' )
     * @property {String}           confirmText         确认按钮的文字 (默认 '确认' )
     * @property {Object}           customStyle         自定义样式,对象形式
     * @event {Function} change 按键被点击(不包含退格键被点击)
     * @event {Function} cancel 键盘顶部工具条左边的"取消"按钮被点击
     * @event {Function} confirm 键盘顶部工具条右边的"完成"按钮被点击
     * @event {Function} backspace 键盘退格键被点击
     * @example <uv-keyboard mode="number" v-model="show"></uv-keyboard>
     */
    export default {
        name: "uv-keyboard",
        mixins: [mpMixin, mixin, props],
        emits: ['close','change','confirm','cancel','backspace','changeCarInputMode'],
        methods: {
            open() {
                this.$refs.keyboardPopup.open();
            },
            close() {
                this.$refs.keyboardPopup.close();
            },
            popupChange(e) {
                if(!e.show) this.$emit('close');
            },
            change(e) {
                this.$emit('change', e);
            },
            // 输入完成
            onConfirm() {
                this.$emit('confirm');
                if(this.closeOnClickConfirm) this.close();
            },
            // 取消输入
            onCancel() {
                this.$emit('cancel');
                this.close();
            },
            // 退格键
            backspace() {
                this.$emit('backspace');
            },
            // car模式切换中文|英文方法
            changeCarInputMode(e) {
                this.$emit('changeCarInputMode',e);
            },
            changeCarMode() {
                this.$refs.uvKeyboardCarRef && this.$refs.uvKeyboardCarRef.changeCarInputMode();
            }
        }
    }
</script>
<style lang="scss" scoped>
    $show-hover: 1;
    @import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    .uv-keyboard {
        &__tooltip {
            @include flex;
            justify-content: space-between;
            background-color: #FFFFFF;
            padding: 14px 12px;
            &__item {
                color: #333333;
                flex: 1;
                text-align: center;
                font-size: 15px;
            }
            &__submit {
                text-align: right;
                color: $uv-primary;
            }
            &__cancel {
                text-align: left;
                color: #888888;
            }
            &__tips {
                color: $uv-tips-color;
            }
        }
    }
</style>
ledApp/uni_modules/uv-keyboard/package.json
New file
@@ -0,0 +1,89 @@
{
  "id": "uv-keyboard",
  "displayName": "uv-keyboard 键盘 全面兼容vue3+2、app、h5、小程序等多端",
  "version": "1.0.5",
  "description": "uv-keyboard 该组件为自定义的键盘面板,内含了数字键盘,车牌号键,身份证号键盘3种模式,都有可以打乱按键顺序的选项。",
  "keywords": [
    "uv-keyboard",
    "uvui",
    "uv-ui",
    "keyboard",
    "键盘"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools",
            "uv-popup",
            "uv-icon"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-keyboard/readme.md
New file
@@ -0,0 +1,19 @@
## Keyboard 键盘
> **组件名:uv-keyboard**
该组件为自定义的键盘面板,内含了数字键盘,车牌号键,身份证号键盘3种模式,都有可以打乱按键顺序的选项。
# <a href="https://www.uvui.cn/components/keyboard.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>(请不要 下载插件ZIP)</small>
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
</a>
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-line-progress/changelog.md
New file
@@ -0,0 +1,7 @@
## 1.0.2(2023-06-20)
1. 适配height参数携带单位
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-line-progress 线形进度条
ledApp/uni_modules/uv-line-progress/components/uv-line-progress/props.js
New file
@@ -0,0 +1,29 @@
export default {
    props: {
        // 激活部分的颜色
        activeColor: {
            type: String,
            default: '#19be6b'
        },
        inactiveColor: {
            type: String,
            default: '#ececec'
        },
        // 进度百分比,数值
        percentage: {
            type: [String, Number],
            default: 0
        },
        // 是否在进度条内部显示百分比的值
        showText: {
            type: Boolean,
            default: true
        },
        // 进度条的高度,单位px
        height: {
            type: [String, Number],
            default: 12
        },
        ...uni.$uv?.props?.lineProgress
    }
}
ledApp/uni_modules/uv-line-progress/components/uv-line-progress/uv-line-progress.vue
New file
@@ -0,0 +1,146 @@
<template>
    <view
        class="uv-line-progress"
        :style="[$uv.addStyle(customStyle)]"
    >
        <view
            class="uv-line-progress__background"
            ref="uv-line-progress__background"
            :style="[{
                backgroundColor: inactiveColor,
                height: $uv.addUnit($uv.getPx(height))
            }]"
        >
        </view>
        <view
            class="uv-line-progress__line"
            :style="[progressStyle]"
        >
            <slot>
                <text v-if="showText && percentage >= 10" class="uv-line-progress__text">{{innserPercentage + '%'}}</text>
            </slot>
        </view>
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    // #ifdef APP-NVUE
    const dom = uni.requireNativePlugin('dom')
    // #endif
    /**
     * lineProgress 线型进度条
     * @description 展示操作或任务的当前进度,比如上传文件,是一个线形的进度条。
     * @tutorial https://www.uvui.cn/components/lineProgress.html
     * @property {String}           activeColor     激活部分的颜色 ( 默认 '#19be6b' )
     * @property {String}           inactiveColor   背景色 ( 默认 '#ececec' )
     * @property {String | Number}  percentage      进度百分比,数值 ( 默认 0 )
     * @property {Boolean}          showText        是否在进度条内部显示百分比的值 ( 默认 true )
     * @property {String | Number}  height          进度条的高度,单位px ( 默认 12 )
     *
     * @example <uv-line-progress :percent="70" :show-percent="true"></uv-line-progress>
     */
    export default {
        name: "uv-line-progress",
        mixins: [mpMixin, mixin, props],
        data() {
            return {
                lineWidth: 0,
            }
        },
        watch: {
            percentage(n) {
                this.resizeProgressWidth()
            }
        },
        computed: {
            progressStyle() {
                let style = {}
                style.width = this.lineWidth
                style.backgroundColor = this.activeColor
                style.height = this.$uv.addUnit(this.$uv.getPx(this.height))
                return style
            },
            innserPercentage() {
                // 控制范围在0-100之间
                return this.$uv.range(0, 100, this.percentage)
            }
        },
        mounted() {
            this.init()
        },
        methods: {
            init() {
                this.$uv.sleep(20).then(() => {
                    this.resizeProgressWidth()
                })
            },
            getProgressWidth() {
                // #ifndef APP-NVUE
                return this.$uvGetRect('.uv-line-progress__background')
                // #endif
                // #ifdef APP-NVUE
                // 返回一个promise
                return new Promise(resolve => {
                    dom.getComponentRect(this.$refs['uv-line-progress__background'], (res) => {
                        resolve(res.size)
                    })
                })
                // #endif
            },
            resizeProgressWidth() {
                this.getProgressWidth().then(size => {
                    const {
                        width
                    } = size
                    // 通过设置的percentage值,计算其所占总长度的百分比
                    this.lineWidth = width * this.innserPercentage / 100 + 'px'
                })
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    .uv-line-progress {
        align-items: stretch;
        position: relative;
        @include flex(row);
        flex: 1;
        overflow: hidden;
        border-radius: 100px;
        &__background {
            background-color: #ececec;
            border-radius: 100px;
            flex: 1;
        }
        &__line {
            position: absolute;
            top: 0;
            left: 0;
            bottom: 0;
            align-items: center;
            @include flex(row);
            color: #ffffff;
            border-radius: 100px;
            transition: width 0.5s ease;
            justify-content: flex-end;
        }
        &__text {
            font-size: 10px;
            align-items: center;
            text-align: right;
            color: #FFFFFF;
            margin-right: 5px;
            transform: scale(0.9);
        }
    }
</style>
ledApp/uni_modules/uv-line-progress/package.json
New file
@@ -0,0 +1,87 @@
{
  "id": "uv-line-progress",
  "displayName": "uv-line-progress 线形进度条  全面兼容小程序、nvue、vue2、vue3等多端",
  "version": "1.0.2",
  "description": "uv-line-progress 该组件展示操作或任务的当前进度,比如上传文件,是一个线形的进度条。",
  "keywords": [
    "uv-line-progress",
    "uvui",
    "uv-ui",
    "progress",
    "进度条"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-line-progress/readme.md
New file
@@ -0,0 +1,11 @@
## LineProgress 线形进度条
> **组件名:uv-line-progress**
展示操作或任务的当前进度,比如上传文件,是一个线形的进度条。
### <a href="https://www.uvui.cn/components/lineProgress.html" target="_blank">查看文档</a>
### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)
#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-line/changelog.md
New file
@@ -0,0 +1,5 @@
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
1. 新增线条组件
ledApp/uni_modules/uv-line/components/uv-line/props.js
New file
@@ -0,0 +1,34 @@
export default {
    props: {
        color: {
            type: String,
            default: '#d6d7d9'
        },
        // 长度,竖向时表现为高度,横向时表现为长度,可以为百分比,带px单位的值等
        length: {
            type: [String, Number],
            default: '100%'
        },
        // 线条方向,col-竖向,row-横向
        direction: {
            type: String,
            default: 'row'
        },
        // 是否显示细边框
        hairline: {
            type: Boolean,
            default: true
        },
        // 线条与上下左右元素的间距,字符串形式,如"30px"、"20px 30px"
        margin: {
            type: [String, Number],
            default: 0
        },
        // 是否虚线,true-虚线,false-实线
        dashed: {
            type: Boolean,
            default: false
        },
        ...uni.$uv?.props?.line
    }
}
ledApp/uni_modules/uv-line/components/uv-line/uv-line.vue
New file
@@ -0,0 +1,60 @@
<template>
    <view
        class="uv-line"
        :style="[lineStyle]"
    >
    </view>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * line 线条
     * @description 此组件一般用于显示一根线条,用于分隔内容块,有横向和竖向两种模式,且能设置0.5px线条,使用也很简单
     * @tutorial https://www.uvui.cn/components/line.html
     * @property {String}           color       线条的颜色 ( 默认 '#d6d7d9' )
     * @property {String | Number}  length      长度,竖向时表现为高度,横向时表现为长度,可以为百分比,带px单位的值等 ( 默认 '100%' )
     * @property {String}           direction   线条的方向,row-横向,col-竖向 (默认 'row' )
     * @property {Boolean}          hairline    是否显示细线条 (默认 true )
     * @property {String | Number}  margin      线条与上下左右元素的间距,字符串形式,如"30px"  (默认 0 )
     * @property {Boolean}          dashed      是否虚线,true-虚线,false-实线 (默认 false )
     * @property {Object}           customStyle 定义需要用到的外部样式
     * @example <uv-line color="red"></uv-line>
     */
    export default {
        name: 'uv-line',
        mixins: [mpMixin, mixin, props],
        computed: {
            lineStyle() {
                const style = {}
                style.margin = this.margin
                // 如果是水平线条,边框高度为1px,再通过transform缩小一半,就是0.5px了
                if (this.direction === 'row') {
                    // 此处采用兼容分开写,兼容nvue的写法
                    style.borderBottomWidth = '1px'
                    style.borderBottomStyle = this.dashed ? 'dashed' : 'solid'
                    style.width = this.$uv.addUnit(this.length)
                    if (this.hairline) style.transform = 'scaleY(0.5)'
                } else {
                    // 如果是竖向线条,边框宽度为1px,再通过transform缩小一半,就是0.5px了
                    style.borderLeftWidth = '1px'
                    style.borderLeftStyle = this.dashed ? 'dashed' : 'solid'
                    style.height = this.$uv.addUnit(this.length)
                    if (this.hairline) style.transform = 'scaleX(0.5)'
                }
                style.borderColor = this.color
                return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
            }
        }
    }
</script>
<style lang="scss" scoped>
    .uv-line {
        /* #ifndef APP-NVUE */
        vertical-align: middle;
        /* #endif */
    }
</style>
ledApp/uni_modules/uv-line/package.json
New file
@@ -0,0 +1,87 @@
{
  "id": "uv-line",
  "displayName": "uv-line 线条  全面兼容小程序、nvue、vue2、vue3等多端",
  "version": "1.0.1",
  "description": "uv-line 此组件一般用于显示一根线条,用于分隔内容块,有横向和竖向两种模式,且能设置0.5px线条,使用也很简单。",
  "keywords": [
    "uv-line",
    "uvui",
    "uv-ui",
    "line",
    "线条"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-line/readme.md
New file
@@ -0,0 +1,11 @@
## Line 线条
> **组件名:uv-line**
此组件一般用于显示一根线条,用于分隔内容块,有横向和竖向两种模式,且能设置0.5px线条,使用也很简单。
### <a href="https://www.uvui.cn/components/line.html" target="_blank">查看文档</a>
### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)
#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-link/changelog.md
New file
@@ -0,0 +1,7 @@
## 1.0.2(2023-08-13)
1. 修复报错的BUG
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-link 超链接组件
ledApp/uni_modules/uv-link/components/uv-link/props.js
New file
@@ -0,0 +1,40 @@
export default {
    props: {
        // 文字颜色
        color: {
            type: String,
            default: ''
        },
        // 字体大小,单位px
        fontSize: {
            type: [String, Number],
            default: 14
        },
        // 是否显示下划线
        underLine: {
            type: Boolean,
            default: false
        },
        // 要跳转的链接
        href: {
            type: String,
            default: ''
        },
        // 小程序中复制到粘贴板的提示语
        mpTips: {
            type: String,
            default: '链接已复制,请在浏览器打开'
        },
        // 下划线颜色
        lineColor: {
            type: String,
            default: ''
        },
        // 超链接的问题,不使用slot形式传入,是因为nvue下无法修改颜色
        text: {
            type: String,
            default: ''
        },
        ...uni.$uv?.props?.link
    }
}
ledApp/uni_modules/uv-link/components/uv-link/uv-link.vue
New file
@@ -0,0 +1,83 @@
<template>
    <text
        class="uv-link"
        @tap.stop="openLink"
        :style="[linkStyle, $uv.addStyle(customStyle)]"
    >{{text}}</text>
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    import props from './props.js';
    /**
     * link 超链接
     * @description 该组件为超链接组件,在不同平台有不同表现形式:在APP平台会通过plus环境打开内置浏览器,在小程序中把链接复制到粘贴板,同时提示信息,在H5中通过window.open打开链接。
     * @tutorial https://www.uvui.cn/components/link.html
     * @property {String}           color       文字颜色 (默认 color['uv-primary'] )
     * @property {String | Number}  fontSize    字体大小,单位px (默认 15 )
     * @property {Boolean}          underLine   是否显示下划线 (默认 false )
     * @property {String}           href        跳转的链接,要带上http(s)
     * @property {String}           mpTips      各个小程序平台把链接复制到粘贴板后的提示语(默认“链接已复制,请在浏览器打开”)
     * @property {String}           lineColor   下划线颜色,默认同color参数颜色
     * @property {String}           text        超链接的问题,不使用slot形式传入,是因为nvue下无法修改颜色
     * @property {Object}           customStyle 定义需要用到的外部样式
     *
     * @example <uv-link href="http://www.uvui.cn">蜀道难,难于上青天</uv-link>
     */
    export default {
        name: "uv-link",
        emits:['click'],
        mixins: [mpMixin, mixin, props],
        computed: {
            linkStyle() {
                const style = {
                    color: this.color,
                    fontSize: this.$uv.addUnit(this.fontSize),
                    // line-height设置为比字体大小多2px
                    lineHeight: this.$uv.addUnit(this.$uv.getPx(this.fontSize) + 2),
                    textDecoration: this.underLine ? 'underline' : 'none'
                }
                return style
            }
        },
        methods: {
            openLink() {
                // #ifdef APP-PLUS
                plus.runtime.openURL(this.href)
                // #endif
                // #ifdef H5
                window.open(this.href)
                // #endif
                // #ifdef MP
                uni.setClipboardData({
                    data: this.href,
                    success: () => {
                        uni.hideToast();
                        this.$nextTick(() => {
                            this.$uv.toast(this.mpTips);
                        })
                    }
                });
                // #endif
                this.$emit('click')
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
    $uv-link-line-height:1 !default;
    .uv-link {
        /* #ifndef APP-NVUE */
        line-height: $uv-link-line-height;
        /* #endif */
        @include flex;
        flex-wrap: wrap;
        flex: 1;
        color: $uv-primary;
    }
</style>
ledApp/uni_modules/uv-link/package.json
New file
@@ -0,0 +1,87 @@
{
  "id": "uv-link",
  "displayName": "uv-link 超链接  全面兼容小程序、nvue、vue2、vue3等多端",
  "version": "1.0.2",
  "description": "uv-link 该组件为超链接组件",
  "keywords": [
    "uv-link",
    "uvui",
    "uv-ui",
    "link",
    "超链接"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
        "ads": "无",
        "data": "插件不采集任何数据",
        "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
            "uv-ui-tools"
        ],
    "encrypt": [],
    "platforms": {
            "cloud": {
                "tcb": "y",
                "aliyun": "y"
            },
            "client": {
                "Vue": {
                    "vue2": "y",
                    "vue3": "y"
                },
                "App": {
                    "app-vue": "y",
                    "app-nvue": "y"
                },
                "H5-mobile": {
                    "Safari": "y",
                    "Android Browser": "y",
                    "微信浏览器(Android)": "y",
                    "QQ浏览器(Android)": "y"
                },
                "H5-pc": {
                    "Chrome": "y",
                    "IE": "y",
                    "Edge": "y",
                    "Firefox": "y",
                    "Safari": "y"
                },
                "小程序": {
                    "微信": "y",
                    "阿里": "y",
                    "百度": "y",
                    "字节跳动": "y",
                    "QQ": "y",
                    "钉钉": "u",
                    "快手": "u",
                    "飞书": "u",
                    "京东": "u"
                },
                "快应用": {
                    "华为": "u",
                    "联盟": "u"
                }
            }
        }
  }
}
ledApp/uni_modules/uv-link/readme.md
New file
@@ -0,0 +1,11 @@
## Link 超链接
> **组件名:uv-link**
该组件为超链接组件,在不同平台有不同表现形式。
### <a href="https://www.uvui.cn/components/link.html" target="_blank">查看文档</a>
### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)
#### 如使用过程中有任何问题,或者您对uv-ui有一些好的建议,欢迎加入 uv-ui 交流群:<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
ledApp/uni_modules/uv-list/changelog.md
New file
@@ -0,0 +1,25 @@
## 1.0.9(2023-11-10)
1. 修复设置ellipsis不生效的BUG
## 1.0.8(2023-09-20)
1. listItem优化可使用customStyle变量进行样式控制
## 1.0.7(2023-08-29)
1. 修复边框的BUG
## 1.0.6(2023-08-16)
1. 修复switch开关返回undefined的问题
2. 优化初始化可能导致的闪动
## 1.0.5(2023-08-07)
1. 修复分包页面在ios端,nvue编译不能滚动的BUG
## 1.0.4(2023-08-04)
1. nvue修复  触底不触发事件的BUG
2. 更新文档说明事件触发
## 1.0.3(2023-07-28)
1. 修改可能造成样式污染的BUG
## 1.0.2(2023-07-26)
1. 全面重构,用法与之前保持一致,参数全部变化
2. 新增多个功能参数,方便一键构建列表
3. List列表组件,包含基本列表样式、默认插槽机制、可扩展插槽机制、长列表性能优化、多端兼容。
## 1.0.1(2023-05-16)
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
2. 优化部分功能
## 1.0.0(2023-05-10)
uv-list 列表
ledApp/uni_modules/uv-list/components/uv-list-item/uv-list-item.vue
New file
@@ -0,0 +1,535 @@
<template>
    <!-- #ifdef APP-NVUE -->
    <cell :keep-scroll-position="keepScrollPosition">
        <!-- #endif -->
        <view
            :class="{ 'uv-list-item--disabled': disabled }"
            :style="[$uv.addStyle(customStyle),{'background-color':customStyle.backgroundColor?customStyle.backgroundColor:'#fff'}]"
            :hover-class="(!clickable && !link) || disabled || showSwitch ? '' : 'uv-list-item--hover'"
            class="uv-list-item" @click="onClick">
            <view v-if="!isFirstChild" class="border--left" :class="{ 'uv-list--border': border }"></view>
            <view class="uv-list-item__wrapper">
                <slot>
                    <view class="uv-list-item__container"
                        :class="{ 'container--right': showArrow || link, 'flex--direction': directionData === 'column'}"
                        :style="{paddingTop:padding.top,paddingLeft:padding.left,paddingRight:padding.right,paddingBottom:padding.bottom}">
                        <slot name="header">
                            <view class="uv-list-item__header">
                                <view v-if="thumb" class="uv-list-item__icon">
                                    <image :src="thumb" class="uv-list-item__icon-img" :class="['uv-list--' + thumbSize]" />
                                </view>
                                <view v-else-if="showExtraIcon" class="uv-list-item__icon">
                                    <uv-icon :name="extraIcon.icon" :customPrefix="extraIcon.customPrefix" :color="extraIcon.color" :size="extraIcon.size" />
                                </view>
                            </view>
                        </slot>
                        <slot name="body">
                            <view class="uv-list-item__content"
                                :class="{ 'uv-list-item__content--center': thumb || showExtraIcon || showBadge || showSwitch }">
                                <text v-if="title" class="uv-list-item__content-title"
                                    :class="[ellipsis && `uv-line-${ellipsis}`]">{{ title }}</text>
                                <text v-if="note" class="uv-list-item__content-note">{{ note }}</text>
                            </view>
                        </slot>
                        <slot name="footer">
                            <view v-if="rightText || showBadge || showSwitch" class="uv-list-item__extra"
                                :class="{ 'flex--justify': directionData === 'column' }">
                                <text v-if="rightText" class="uv-list-item__extra-text">{{ rightText }}</text>
                                <uv-badge
                                    v-if="showBadge"
                                    :show="!!(badge.show || badge.isDot || badge.value)"
                                    :isDot="badge.isDot"
                                    :value="badge.value"
                                    :max="badge.max"
                                    :type="badge.type"
                                    :showZero="badge.showZero"
                                    :bgColor="badge.bgColor"
                                    :color="badge.color"
                                    :shape="badge.shape"
                                    :numberType="badge.numberType"
                                    :inverted="badge.inverted"
                                    customStyle="margin-left: 4px;"
                                ></uv-badge>
                                <uv-switch v-if="showSwitch" :value="switchChecked" :disabled="disabled" @change="onSwitchChange"></uv-switch>
                            </view>
                        </slot>
                    </view>
                </slot>
            </view>
            <uv-icon v-if="showArrow || link" size="34rpx" class="uv-icon-wrapper" color="#bbb" name="arrow-right" />
        </view>
        <!-- #ifdef APP-NVUE -->
    </cell>
    <!-- #endif -->
</template>
<script>
    import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
    import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
    /**
     * 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}   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 {Object}   badge  扩展数字角标的参数,格式为 :badge="{value: 122}"
     * @property {Boolean}  showSwitch = [true|false]       是否显示Switch
     * @property {Boolean}  switchChecked = [true|false]    Switch是否被选中
     * @property {Boolean}  showExtraIcon = [true|false]    左侧是否显示扩展图标
     * @property {Object}   extraIcon                       扩展图标参数,格式为 :extraIcon="{icon: 'photo',size: '30px'}"
     * @property {String}   direction = [row|column]        排版方向
     * @value row           水平排列
     * @value column        垂直排列
     * @event {Function}    click                           点击 uniListItem 触发事件
     * @event {Function}    switchChange                    点击切换 Switch 时触发
     */
    export default {
        name: 'uv-list-item',
        mixins: [mpMixin, mixin],
        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: ''
            },
            showSwitch: {
                type: [Boolean, String],
                default: false
            },
            switchChecked: {
                type: [Boolean, String],
                default: false
            },
            showBadge: {
                type: [Boolean, String],
                default: false
            },
            badge: {
                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 {
                        name: '',
                        color: '#000000',
                        size: 20,
                        customPrefix: ''
                    };
                }
            },
            border: {
                type: Boolean,
                default: false
            },
            customStyle: {
                type: Object,
                default () {
                    return {
                        padding: '',
                        backgroundColor: '#FFFFFF'
                    }
                }
            },
            keepScrollPosition: {
                type: Boolean,
                default: false
            }
        },
        computed: {
            directionData(){
                return this.direction ? this.direction : (this.parentData.direction ? this.parentData.direction : 'row');
            }
        },
        watch: {
            'customStyle.padding': {
                handler(padding) {
                    if(padding) this.setPadding(padding);
                },
                immediate: true
            }
        },
        data() {
            return {
                isFirstChild: false,
                padding: {
                    top: "",
                    right: "",
                    bottom: "",
                    left: ""
                },
                parentData: {
                    direction: 'row',
                    padding: 0
                }
            };
        },
        created() {
            this.updateParentData();
        },
        mounted() {
            this.init();
            this.list = this.getForm()
            // 判断是否存在 uv-list 组件
            if (this.list) {
                if (!this.list.firstChildAppend) {
                    this.list.firstChildAppend = true;
                    this.isFirstChild = true;
                }
            }
        },
        methods: {
            init(){
                if (!this.parent) {
                    this.$uv.error('uv-list-item必须搭配uv-list组件使用');
                }
                this.$nextTick(()=>{
                    if(!(this.padding.top || this.padding.right|| this.padding.bottom|| this.padding.left)){
                        this.setPadding(this.parentData.padding);
                    }
                })
            },
            updateParentData() {
                this.getParentData('uv-list');
            },
            setPadding(padding){
                if(typeof padding == 'number'){
                    padding += ''
                }
                let paddingArr = padding.split(' ')
                if (paddingArr.length === 1) {
                    const allPadding = paddingArr[0]
                    this.padding = {
                        "top": allPadding,
                        "right": allPadding,
                        "bottom": allPadding,
                        "left": allPadding
                    }
                } else if (paddingArr.length === 2) {
                    const [verticalPadding, horizontalPadding] = paddingArr;
                    this.padding = {
                        "top": verticalPadding,
                        "right": horizontalPadding,
                        "bottom": verticalPadding,
                        "left": horizontalPadding
                    }
                } else if (paddingArr.length === 4) {
                        const [topPadding, rightPadding, bottomPadding, leftPadding] = paddingArr;
                        this.padding = {
                            "top": topPadding,
                            "right": rightPadding,
                            "bottom": bottomPadding,
                            "left": leftPadding
                        }
                }
            },
            /**
             * 获取父元素实例
             */
            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);
            },
            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" scoped>
    $show-lines: 1;
    @import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
    @import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
    $uv-font-size-sm:12px;
    $uv-font-size-base:14px;
    $uv-font-size-lg:16px;
    $uv-spacing-col-lg: 12px;
    $uv-spacing-row-lg: 15px;
    $uv-img-size-sm:20px;
    $uv-img-size-base:26px;
    $uv-img-size-lg:40px;
    $uv-border-color:#e5e5e5;
    $uv-bg-color-hover:#f1f1f1;
    $uv-text-color-grey:#999;
    $list-item-pd: $uv-spacing-col-lg $uv-spacing-row-lg;
    .uv-list-item {
        @include flex(row);
        font-size: $uv-font-size-lg;
        position: relative;
        justify-content: space-between;
        align-items: center;
        background-color: #fff;
        /* #ifdef H5 */
        cursor: pointer;
        /* #endif */
    }
    .uv-list-item--disabled {
        opacity: 0.3;
    }
    .uv-list-item--hover {
        background-color: $uv-bg-color-hover !important;
    }
    .uv-list-item__wrapper {
        @include flex(column);
        flex: 1;
    }
    .uv-list-item__container {
        position: relative;
        @include flex(row);
        padding: $list-item-pd;
        padding-left: $uv-spacing-row-lg;
        flex: 1;
        overflow: hidden;
    }
    .container--right {
        padding-right: 0;
    }
    .uv-list--border {
        position: absolute;
        top: 0;
        right: 0;
        left: 0;
        /* #ifdef APP-NVUE */
        border-top-color: $uv-border-color;
        border-top-style: solid;
        border-top-width: 0.5px;
        /* #endif */
    }
    /* #ifndef APP-NVUE */
    .uv-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: $uv-border-color;
    }
    /* #endif */
    .uv-list-item__content {
        @include flex(column);
        padding-right: 8px;
        flex: 1;
        color: #3b4144;
        justify-content: space-between;
        overflow: hidden;
    }
    .uv-list-item__content--center {
        justify-content: center;
    }
    .uv-list-item__content-title {
        font-size: $uv-font-size-base;
        color: #3b4144;
        overflow: hidden;
    }
    .uv-list-item__content-note {
        margin-top: 6rpx;
        color: $uv-text-color-grey;
        font-size: $uv-font-size-sm;
        overflow: hidden;
    }
    .uv-list-item__extra {
        @include flex(row);
        justify-content: flex-end;
        align-items: center;
    }
    .uv-list-item__header {
        @include flex(row);
        align-items: center;
    }
    .uv-list-item__icon {
        margin-right: 18rpx;
        flex-direction: row;
        justify-content: center;
        align-items: center;
    }
    .uv-list-item__icon-img {
        /* #ifndef APP-NVUE */
        display: block;
        /* #endif */
        height: $uv-img-size-base;
        width: $uv-img-size-base;
        margin-right: 10px;
    }
    .uv-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 */
    }
    .uv-list--lg {
        height: $uv-img-size-lg;
        width: $uv-img-size-lg;
    }
    .uv-list--base {
        height: $uv-img-size-base;
        width: $uv-img-size-base;
    }
    .uv-list--sm {
        height: $uv-img-size-sm;
        width: $uv-img-size-sm;
    }
    .uv-list-item__extra-text {
        color: $uv-text-color-grey;
        font-size: $uv-font-size-sm;
    }
</style>
Diff truncated after the above file
ledApp/uni_modules/uv-list/components/uv-list/uv-list.vue ledApp/uni_modules/uv-list/package.json ledApp/uni_modules/uv-list/readme.md ledApp/uni_modules/uv-load-more/changelog.md ledApp/uni_modules/uv-load-more/components/uv-load-more/props.js ledApp/uni_modules/uv-load-more/components/uv-load-more/uv-load-more.vue ledApp/uni_modules/uv-load-more/package.json ledApp/uni_modules/uv-load-more/readme.md ledApp/uni_modules/uv-loading-icon/changelog.md ledApp/uni_modules/uv-loading-icon/components/uv-loading-icon/props.js ledApp/uni_modules/uv-loading-icon/components/uv-loading-icon/uv-loading-icon.vue ledApp/uni_modules/uv-loading-icon/package.json ledApp/uni_modules/uv-loading-icon/readme.md ledApp/uni_modules/uv-loading-page/changelog.md ledApp/uni_modules/uv-loading-page/components/uv-loading-page/props.js ledApp/uni_modules/uv-loading-page/components/uv-loading-page/uv-loading-page.vue ledApp/uni_modules/uv-loading-page/package.json ledApp/uni_modules/uv-loading-page/readme.md ledApp/uni_modules/uv-modal/changelog.md ledApp/uni_modules/uv-modal/components/uv-modal/props.js ledApp/uni_modules/uv-modal/components/uv-modal/uv-modal.vue ledApp/uni_modules/uv-modal/package.json ledApp/uni_modules/uv-modal/readme.md ledApp/uni_modules/uv-navbar/changelog.md ledApp/uni_modules/uv-navbar/components/uv-navbar/props.js ledApp/uni_modules/uv-navbar/components/uv-navbar/uv-navbar.vue ledApp/uni_modules/uv-navbar/package.json ledApp/uni_modules/uv-navbar/readme.md ledApp/uni_modules/uv-no-network/changelog.md ledApp/uni_modules/uv-no-network/components/uv-no-network/props.js ledApp/uni_modules/uv-no-network/components/uv-no-network/uv-no-network.vue ledApp/uni_modules/uv-no-network/package.json ledApp/uni_modules/uv-no-network/readme.md ledApp/uni_modules/uv-notice-bar/changelog.md ledApp/uni_modules/uv-notice-bar/components/uv-column-notice/props.js ledApp/uni_modules/uv-notice-bar/components/uv-column-notice/uv-column-notice.vue ledApp/uni_modules/uv-notice-bar/components/uv-notice-bar/props.js ledApp/uni_modules/uv-notice-bar/components/uv-notice-bar/uv-notice-bar.vue ledApp/uni_modules/uv-notice-bar/components/uv-row-notice/props.js ledApp/uni_modules/uv-notice-bar/components/uv-row-notice/uv-row-notice.vue ledApp/uni_modules/uv-notice-bar/package.json ledApp/uni_modules/uv-notice-bar/readme.md ledApp/uni_modules/uv-notify/changelog.md ledApp/uni_modules/uv-notify/components/uv-notify/props.js ledApp/uni_modules/uv-notify/components/uv-notify/uv-notify.vue ledApp/uni_modules/uv-notify/package.json ledApp/uni_modules/uv-notify/readme.md ledApp/uni_modules/uv-number-box/changelog.md ledApp/uni_modules/uv-number-box/components/uv-number-box/props.js ledApp/uni_modules/uv-number-box/components/uv-number-box/uv-number-box.vue ledApp/uni_modules/uv-number-box/package.json ledApp/uni_modules/uv-number-box/readme.md ledApp/uni_modules/uv-overlay/changelog.md ledApp/uni_modules/uv-overlay/components/uv-overlay/props.js ledApp/uni_modules/uv-overlay/components/uv-overlay/uv-overlay.vue ledApp/uni_modules/uv-overlay/package.json ledApp/uni_modules/uv-overlay/readme.md ledApp/uni_modules/uv-parse/changelog.md ledApp/uni_modules/uv-parse/components/uv-parse/node/node.vue ledApp/uni_modules/uv-parse/components/uv-parse/parser.js ledApp/uni_modules/uv-parse/components/uv-parse/uv-parse.vue ledApp/uni_modules/uv-parse/package.json ledApp/uni_modules/uv-parse/readme.md ledApp/uni_modules/uv-parse/static/app-plus/uv-parse/js/handler.js ledApp/uni_modules/uv-parse/static/app-plus/uv-parse/js/uni.webview.min.js ledApp/uni_modules/uv-parse/static/app-plus/uv-parse/local.html ledApp/uni_modules/uv-pick-color/changelog.md ledApp/uni_modules/uv-pick-color/components/uv-pick-color/colors.js ledApp/uni_modules/uv-pick-color/components/uv-pick-color/props.js ledApp/uni_modules/uv-pick-color/components/uv-pick-color/uv-pick-color.vue ledApp/uni_modules/uv-pick-color/package.json ledApp/uni_modules/uv-pick-color/readme.md ledApp/uni_modules/uv-picker/changelog.md ledApp/uni_modules/uv-picker/components/uv-picker/props.js ledApp/uni_modules/uv-picker/components/uv-picker/uv-picker.vue ledApp/uni_modules/uv-picker/package.json ledApp/uni_modules/uv-picker/readme.md ledApp/uni_modules/uv-popup/changelog.md ledApp/uni_modules/uv-popup/components/uv-popup/keypress.js ledApp/uni_modules/uv-popup/components/uv-popup/uv-popup.vue ledApp/uni_modules/uv-popup/package.json ledApp/uni_modules/uv-popup/readme.md ledApp/uni_modules/uv-qrcode/changelog.md ledApp/uni_modules/uv-qrcode/components/uv-qrcode/cache.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/bridge/bridge-weex.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-2d/FillStyleLinearGradient.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-2d/FillStylePattern.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-2d/FillStyleRadialGradient.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-2d/RenderingContext.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/ActiveInfo.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Buffer.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Framebuffer.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/GLenum.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/GLmethod.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/GLtype.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Program.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Renderbuffer.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/RenderingContext.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Shader.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/ShaderPrecisionFormat.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Texture.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/UniformLocation.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/classUtils.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/env/canvas.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/env/image.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/env/tool.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/index.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/props.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/qrcode.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/queue.js ledApp/uni_modules/uv-qrcode/components/uv-qrcode/uv-qrcode.vue ledApp/uni_modules/uv-qrcode/package.json ledApp/uni_modules/uv-qrcode/readme.md ledApp/uni_modules/uv-radio/changelog.md ledApp/uni_modules/uv-radio/components/uv-radio-group/props.js ledApp/uni_modules/uv-radio/components/uv-radio-group/uv-radio-group.vue ledApp/uni_modules/uv-radio/components/uv-radio/props.js ledApp/uni_modules/uv-radio/components/uv-radio/uv-radio.vue ledApp/uni_modules/uv-radio/package.json ledApp/uni_modules/uv-radio/readme.md ledApp/uni_modules/uv-rate/changelog.md ledApp/uni_modules/uv-rate/components/uv-rate/props.js ledApp/uni_modules/uv-rate/components/uv-rate/uv-rate.vue ledApp/uni_modules/uv-rate/package.json ledApp/uni_modules/uv-rate/readme.md ledApp/uni_modules/uv-read-more/changelog.md ledApp/uni_modules/uv-read-more/components/uv-read-more/props.js ledApp/uni_modules/uv-read-more/components/uv-read-more/uv-read-more.vue ledApp/uni_modules/uv-read-more/package.json ledApp/uni_modules/uv-read-more/readme.md ledApp/uni_modules/uv-row/changelog.md ledApp/uni_modules/uv-row/components/uv-col/props.js ledApp/uni_modules/uv-row/components/uv-col/uv-col.vue ledApp/uni_modules/uv-row/components/uv-row/props.js ledApp/uni_modules/uv-row/components/uv-row/uv-row.vue ledApp/uni_modules/uv-row/package.json ledApp/uni_modules/uv-row/readme.md ledApp/uni_modules/uv-safe-bottom/changelog.md ledApp/uni_modules/uv-safe-bottom/components/uv-safe-bottom/uv-safe-bottom.vue ledApp/uni_modules/uv-safe-bottom/package.json ledApp/uni_modules/uv-safe-bottom/readme.md ledApp/uni_modules/uv-scroll-list/changelog.md ledApp/uni_modules/uv-scroll-list/components/uv-scroll-list/nvue.js ledApp/uni_modules/uv-scroll-list/components/uv-scroll-list/props.js ledApp/uni_modules/uv-scroll-list/components/uv-scroll-list/scrollWxs.wxs ledApp/uni_modules/uv-scroll-list/components/uv-scroll-list/uv-scroll-list.vue ledApp/uni_modules/uv-scroll-list/package.json ledApp/uni_modules/uv-scroll-list/readme.md ledApp/uni_modules/uv-search/changelog.md ledApp/uni_modules/uv-search/components/uv-search/props.js ledApp/uni_modules/uv-search/components/uv-search/uv-search.vue ledApp/uni_modules/uv-search/package.json ledApp/uni_modules/uv-search/readme.md ledApp/uni_modules/uv-skeleton/changelog.md ledApp/uni_modules/uv-skeleton/components/uv-skeleton/props.js ledApp/uni_modules/uv-skeleton/components/uv-skeleton/uv-skeleton.vue ledApp/uni_modules/uv-skeleton/package.json ledApp/uni_modules/uv-skeleton/readme.md ledApp/uni_modules/uv-skeletons/changelog.md ledApp/uni_modules/uv-skeletons/components/uv-skeletons/uv-skeletons.vue ledApp/uni_modules/uv-skeletons/package.json ledApp/uni_modules/uv-skeletons/readme.md ledApp/uni_modules/uv-slider/changelog.md ledApp/uni_modules/uv-slider/components/uv-slider/props.js ledApp/uni_modules/uv-slider/components/uv-slider/uv-slider.vue ledApp/uni_modules/uv-slider/package.json ledApp/uni_modules/uv-slider/readme.md ledApp/uni_modules/uv-status-bar/changelog.md ledApp/uni_modules/uv-status-bar/components/uv-status-bar/props.js ledApp/uni_modules/uv-status-bar/components/uv-status-bar/uv-status-bar.vue ledApp/uni_modules/uv-status-bar/package.json ledApp/uni_modules/uv-status-bar/readme.md ledApp/uni_modules/uv-steps/changelog.md ledApp/uni_modules/uv-steps/components/uv-steps-item/props.js ledApp/uni_modules/uv-steps/components/uv-steps-item/uv-steps-item.vue ledApp/uni_modules/uv-steps/components/uv-steps/props.js ledApp/uni_modules/uv-steps/components/uv-steps/uv-steps.vue ledApp/uni_modules/uv-steps/package.json ledApp/uni_modules/uv-steps/readme.md ledApp/uni_modules/uv-sticky/changelog.md ledApp/uni_modules/uv-sticky/components/uv-sticky/props.js ledApp/uni_modules/uv-sticky/components/uv-sticky/uv-sticky.vue ledApp/uni_modules/uv-sticky/package.json ledApp/uni_modules/uv-sticky/readme.md ledApp/uni_modules/uv-subsection/changelog.md ledApp/uni_modules/uv-subsection/components/uv-subsection/props.js ledApp/uni_modules/uv-subsection/components/uv-subsection/uv-subsection.vue ledApp/uni_modules/uv-subsection/package.json ledApp/uni_modules/uv-subsection/readme.md ledApp/uni_modules/uv-swipe-action/changelog.md ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action-item/index - backup.wxs ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action-item/index.wxs ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action-item/nvue - backup.js ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action-item/nvue.js ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action-item/props.js ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action-item/uv-swipe-action-item.vue ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action-item/wxs.js ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action/props.js ledApp/uni_modules/uv-swipe-action/components/uv-swipe-action/uv-swipe-action.vue ledApp/uni_modules/uv-swipe-action/package.json ledApp/uni_modules/uv-swipe-action/readme.md ledApp/uni_modules/uv-swiper/changelog.md ledApp/uni_modules/uv-swiper/components/uv-swiper-indicator/props.js ledApp/uni_modules/uv-swiper/components/uv-swiper-indicator/uv-swiper-indicator.vue ledApp/uni_modules/uv-swiper/components/uv-swiper/props.js ledApp/uni_modules/uv-swiper/components/uv-swiper/uv-swiper.vue ledApp/uni_modules/uv-swiper/package.json ledApp/uni_modules/uv-swiper/readme.md ledApp/uni_modules/uv-switch/changelog.md ledApp/uni_modules/uv-switch/components/uv-switch/props.js ledApp/uni_modules/uv-switch/components/uv-switch/uv-switch.vue ledApp/uni_modules/uv-switch/package.json ledApp/uni_modules/uv-switch/readme.md ledApp/uni_modules/uv-tabbar/changelog.md ledApp/uni_modules/uv-tabbar/components/uv-tabbar-item/props.js ledApp/uni_modules/uv-tabbar/components/uv-tabbar-item/uv-tabbar-item.vue ledApp/uni_modules/uv-tabbar/components/uv-tabbar/props.js ledApp/uni_modules/uv-tabbar/components/uv-tabbar/uv-tabbar.vue ledApp/uni_modules/uv-tabbar/package.json ledApp/uni_modules/uv-tabbar/readme.md ledApp/uni_modules/uv-tabs/changelog.md ledApp/uni_modules/uv-tabs/components/uv-tabs/props.js ledApp/uni_modules/uv-tabs/components/uv-tabs/uv-tabs.vue ledApp/uni_modules/uv-tabs/package.json ledApp/uni_modules/uv-tabs/readme.md ledApp/uni_modules/uv-tags/changelog.md ledApp/uni_modules/uv-tags/components/uv-tags/props.js ledApp/uni_modules/uv-tags/components/uv-tags/uv-tags.vue ledApp/uni_modules/uv-tags/package.json ledApp/uni_modules/uv-tags/readme.md ledApp/uni_modules/uv-text/changelog.md ledApp/uni_modules/uv-text/components/uv-text/props.js ledApp/uni_modules/uv-text/components/uv-text/uv-text.vue ledApp/uni_modules/uv-text/components/uv-text/value.js ledApp/uni_modules/uv-text/package.json ledApp/uni_modules/uv-text/readme.md ledApp/uni_modules/uv-textarea/changelog.md ledApp/uni_modules/uv-textarea/components/uv-textarea/props.js ledApp/uni_modules/uv-textarea/components/uv-textarea/uv-textarea.vue ledApp/uni_modules/uv-textarea/package.json ledApp/uni_modules/uv-textarea/readme.md ledApp/uni_modules/uv-toast/changelog.md ledApp/uni_modules/uv-toast/components/uv-toast/uv-toast.vue ledApp/uni_modules/uv-toast/package.json ledApp/uni_modules/uv-toast/readme.md ledApp/uni_modules/uv-toolbar/changelog.md ledApp/uni_modules/uv-toolbar/components/uv-toolbar/props.js ledApp/uni_modules/uv-toolbar/components/uv-toolbar/uv-toolbar.vue ledApp/uni_modules/uv-toolbar/package.json ledApp/uni_modules/uv-toolbar/readme.md ledApp/uni_modules/uv-tooltip/changelog.md ledApp/uni_modules/uv-tooltip/components/uv-tooltip/props.js ledApp/uni_modules/uv-tooltip/components/uv-tooltip/uv-tooltip.vue ledApp/uni_modules/uv-tooltip/package.json ledApp/uni_modules/uv-tooltip/readme.md ledApp/uni_modules/uv-transition/changelog.md ledApp/uni_modules/uv-transition/components/uv-transition/createAnimation.js ledApp/uni_modules/uv-transition/components/uv-transition/props.js ledApp/uni_modules/uv-transition/components/uv-transition/uv-transition.vue ledApp/uni_modules/uv-transition/package.json ledApp/uni_modules/uv-transition/readme.md ledApp/uni_modules/uv-ui-tools/changelog.md ledApp/uni_modules/uv-ui-tools/components/uv-ui-tools/uv-ui-tools.vue ledApp/uni_modules/uv-ui-tools/index.js ledApp/uni_modules/uv-ui-tools/index.scss ledApp/uni_modules/uv-ui-tools/libs/config/config.js ledApp/uni_modules/uv-ui-tools/libs/css/color.scss ledApp/uni_modules/uv-ui-tools/libs/css/common.scss ledApp/uni_modules/uv-ui-tools/libs/css/components.scss ledApp/uni_modules/uv-ui-tools/libs/css/variable.scss ledApp/uni_modules/uv-ui-tools/libs/css/vue.scss ledApp/uni_modules/uv-ui-tools/libs/function/colorGradient.js ledApp/uni_modules/uv-ui-tools/libs/function/debounce.js ledApp/uni_modules/uv-ui-tools/libs/function/digit.js ledApp/uni_modules/uv-ui-tools/libs/function/index.js ledApp/uni_modules/uv-ui-tools/libs/function/platform.js ledApp/uni_modules/uv-ui-tools/libs/function/test.js ledApp/uni_modules/uv-ui-tools/libs/function/throttle.js ledApp/uni_modules/uv-ui-tools/libs/luch-request/adapters/index.js ledApp/uni_modules/uv-ui-tools/libs/luch-request/core/InterceptorManager.js ledApp/uni_modules/uv-ui-tools/libs/luch-request/core/Request.js ledApp/uni_modules/uv-ui-tools/libs/luch-request/core/buildFullPath.js ledApp/uni_modules/uv-ui-tools/libs/luch-request/core/defaults.js ledApp/uni_modules/uv-ui-tools/libs/luch-request/core/dispatchRequest.js ledApp/uni_modules/uv-ui-tools/libs/luch-request/core/mergeConfig.js ledApp/uni_modules/uv-ui-tools/libs/luch-request/core/settle.js ledApp/uni_modules/uv-ui-tools/libs/luch-request/helpers/buildURL.js ledApp/uni_modules/uv-ui-tools/libs/luch-request/helpers/combineURLs.js ledApp/uni_modules/uv-ui-tools/libs/luch-request/helpers/isAbsoluteURL.js ledApp/uni_modules/uv-ui-tools/libs/luch-request/index.d.ts ledApp/uni_modules/uv-ui-tools/libs/luch-request/index.js ledApp/uni_modules/uv-ui-tools/libs/luch-request/utils.js ledApp/uni_modules/uv-ui-tools/libs/luch-request/utils/clone.js ledApp/uni_modules/uv-ui-tools/libs/mixin/button.js ledApp/uni_modules/uv-ui-tools/libs/mixin/mixin.js ledApp/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js ledApp/uni_modules/uv-ui-tools/libs/mixin/mpShare.js ledApp/uni_modules/uv-ui-tools/libs/mixin/openType.js ledApp/uni_modules/uv-ui-tools/libs/mixin/touch.js ledApp/uni_modules/uv-ui-tools/libs/util/dayjs.js ledApp/uni_modules/uv-ui-tools/libs/util/route.js ledApp/uni_modules/uv-ui-tools/package.json ledApp/uni_modules/uv-ui-tools/readme.md ledApp/uni_modules/uv-ui-tools/theme.scss ledApp/uni_modules/uv-ui/changelog.md ledApp/uni_modules/uv-ui/components/uv-ui/uv-ui.vue ledApp/uni_modules/uv-ui/package.json ledApp/uni_modules/uv-ui/readme.md ledApp/uni_modules/uv-upload/changelog.md ledApp/uni_modules/uv-upload/components/uv-preview-video/uv-preview-video.vue ledApp/uni_modules/uv-upload/components/uv-upload/mixin.js ledApp/uni_modules/uv-upload/components/uv-upload/props.js ledApp/uni_modules/uv-upload/components/uv-upload/utils.js ledApp/uni_modules/uv-upload/components/uv-upload/uv-upload.vue ledApp/uni_modules/uv-upload/package.json ledApp/uni_modules/uv-upload/readme.md ledApp/uni_modules/uv-vtabs/changelog.md ledApp/uni_modules/uv-vtabs/components/uv-vtabs-item/uv-vtabs-item.vue ledApp/uni_modules/uv-vtabs/components/uv-vtabs/props.js ledApp/uni_modules/uv-vtabs/components/uv-vtabs/uv-vtabs.vue ledApp/uni_modules/uv-vtabs/package.json ledApp/uni_modules/uv-vtabs/readme.md ledApp/uni_modules/uv-waterfall/changelog.md ledApp/uni_modules/uv-waterfall/components/uv-waterfall/props.js ledApp/uni_modules/uv-waterfall/components/uv-waterfall/uv-waterfall.vue ledApp/uni_modules/uv-waterfall/package.json ledApp/uni_modules/uv-waterfall/readme.md ledApp/uni_modules/x-color-picker/changelog.md ledApp/uni_modules/x-color-picker/components/x-color-picker/x-color-picker.vue ledApp/uni_modules/x-color-picker/package.json ledApp/uni_modules/x-color-picker/readme.md