oxy-uni-ui 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/LICENSE +1 -1
  2. package/attributes.json +1 -1
  3. package/components/common/abstracts/variable.scss +40 -4
  4. package/components/common/util.ts +44 -0
  5. package/components/composables/index.ts +1 -0
  6. package/components/composables/useVirtualScroll.ts +172 -0
  7. package/components/oxy-checkbox/index.scss +36 -6
  8. package/components/oxy-checkbox/oxy-checkbox.vue +5 -4
  9. package/components/oxy-checkbox/types.ts +2 -1
  10. package/components/oxy-col-picker/index.scss +18 -15
  11. package/components/oxy-col-picker/oxy-col-picker.vue +28 -3
  12. package/components/oxy-col-picker/types.ts +12 -0
  13. package/components/oxy-corner/index.scss +258 -0
  14. package/components/oxy-corner/oxy-corner.vue +67 -0
  15. package/components/oxy-corner/types.ts +50 -0
  16. package/components/oxy-drop-menu/index.scss +4 -0
  17. package/components/oxy-drop-menu/oxy-drop-menu.vue +5 -3
  18. package/components/oxy-drop-menu/types.ts +1 -1
  19. package/components/oxy-drop-menu-item/index.scss +4 -4
  20. package/components/oxy-drop-menu-item/oxy-drop-menu-item.vue +2 -0
  21. package/components/oxy-file-list/index.scss +83 -0
  22. package/components/oxy-file-list/oxy-file-list.vue +213 -0
  23. package/components/oxy-file-list/types.ts +54 -0
  24. package/components/oxy-list/index.scss +5 -0
  25. package/components/oxy-list/oxy-list.vue +206 -0
  26. package/components/oxy-list/types.ts +38 -0
  27. package/components/oxy-slider/index.scss +2 -2
  28. package/components/oxy-swiper/index.scss +1 -2
  29. package/components/oxy-textarea/oxy-textarea.vue +0 -4
  30. package/components/oxy-tree/components/tree-node-content.vue +72 -0
  31. package/components/oxy-tree/index.scss +83 -0
  32. package/components/oxy-tree/index.ts +51 -0
  33. package/components/oxy-tree/oxy-tree.vue +406 -0
  34. package/components/oxy-tree/types.ts +85 -0
  35. package/components/oxy-tree/utils.ts +51 -0
  36. package/components/oxy-upload/images/audio.png +0 -0
  37. package/components/oxy-upload/images/excle.png +0 -0
  38. package/components/oxy-upload/images/other.png +0 -0
  39. package/components/oxy-upload/images/pdf.png +0 -0
  40. package/components/oxy-upload/images/pic.png +0 -0
  41. package/components/oxy-upload/images/txt.png +0 -0
  42. package/components/oxy-upload/images/video.png +0 -0
  43. package/components/oxy-upload/images/word.png +0 -0
  44. package/components/oxy-upload/index.scss +50 -0
  45. package/components/oxy-upload/oxy-upload.vue +93 -7
  46. package/components/oxy-upload/types.ts +22 -1
  47. package/components/oxy-virtual-scroll/index.scss +35 -0
  48. package/components/oxy-virtual-scroll/oxy-virtual-scroll.vue +143 -0
  49. package/components/oxy-virtual-scroll/types.ts +155 -0
  50. package/components/oxy-virtual-scroll/virtual-scroll.ts +81 -0
  51. package/global.d.ts +3 -0
  52. package/locale/lang/ar-SA.ts +2 -1
  53. package/locale/lang/en-US.ts +10 -9
  54. package/locale/lang/zh-CN.ts +7 -6
  55. package/package.json +1 -1
  56. package/tags.json +1 -1
  57. package/web-types.json +1 -1
@@ -227,7 +227,7 @@ $-calendar-range-color: var(--oxy-calendar-range-color, rgba(#4d80f0, 0.09)) !de
227
227
  $-calendar-active-border: var(--oxy-calendar-active-border, 8px) !default;
228
228
  $-calendar-info-fs: var(--oxy-calendar-info-fs, 10px) !default;
229
229
  $-calendar-item-margin-bottom: var(--oxy-calendar-item-margin-bottom, 4px) !default;
230
-
230
+
231
231
 
232
232
  /* checkbox */
233
233
  $-checkbox-margin: var(--oxy-checkbox-margin, 10px) !default; // 多个复选框距离
@@ -361,7 +361,7 @@ $-textarea-color: var(--oxy-textarea-color, #262626) !default; // 文字颜色
361
361
  $-textarea-icon-color: var(--oxy-textarea-icon-color, #bfbfbf) !default; // 图标颜色
362
362
  $-textarea-clear-color: var(--oxy-textarea-clear-color, #585858) !default; // 关闭按钮颜色
363
363
  $-textarea-count-color: var(--oxy-textarea-count-color, #bfbfbf) !default; // 计数文字颜色
364
- $-textarea-count-current-color: var(--oxy-textarea-count-current-color, #262626) !default; // 当前长度颜色
364
+ $-textarea-count-current-color: var(--oxy-textarea-count-current-color, $default-theme) !default; // 当前长度颜色
365
365
  $-textarea-bg: var(--oxy-textarea-bg, $-color-white) !default; // 默认背景颜色
366
366
  $-textarea-cell-border-color: var(--oxy-textarea-cell-border-color, $-color-border-light) !default; // cell 类型边框颜色
367
367
  $-textarea-cell-padding: var(--oxy-textarea-cell-padding, 10px) !default; // cell 容器padding
@@ -641,6 +641,36 @@ $-tag-close-size: var(--oxy-tag-close-size, 14px) !default; // 关闭按钮字
641
641
  $-tag-close-color: var(--oxy-tag-close-color, $-tag-info-color) !default; // 关闭按钮颜色
642
642
  $-tag-close-active-color: var(--oxy-tag-close-active-color, rgba(0, 0, 0, 0.45)) !default; // 关闭按钮 active 颜色
643
643
 
644
+ /* corner */
645
+ $-corner-radius: var(--oxy-corner-radius, 12px) !default; // 圆角大小
646
+ $-corner-font-size: var(--oxy-corner-fs, $-fs-secondary) !default; // 字号
647
+ $-corner-font-weight: var(--oxy-corner-fs, 400) !default; // 字号
648
+ $-corner-color: var(--oxy-corner-color, $-color-white) !default; // 字体颜色
649
+ $-corner-primary-color: var(--oxy-corner-primary-color, $-color-theme) !default; // 主颜色
650
+ $-corner-info-color: var(--oxy-corner-info-color, #7e8fae) !default; // info 颜色
651
+ $-corner-success-color: var(--oxy-corner-success-color, $-color-success) !default; // success 颜色
652
+ $-corner-warning-color: var(--oxy-corner-warning-color, $-color-warning) !default; // warning 颜色
653
+ $-corner-danger-color: var(--oxy-corner-danger-color, $-color-danger) !default; // danger 颜色
654
+ $-corner-primary-bg: var(--oxy-corner-primary-bg, resultColor(90deg, $-color-theme, 'dark' 'light', #018cfc #5fb5fe, 0% 100%)) !default; // 主背景颜色
655
+ $-corner-info-bg: var(--oxy-corner-info-bg, resultColor(90deg, $-color-info, 'dark' 'light', #647ba7 #9aa8cb, 0% 100%)) !default; // info 背景颜色
656
+ $-corner-success-bg: var(--oxy-corner-success-bg, resultColor(90deg, $-color-success, 'dark' 'light', #19be6b #84e3ab, 0% 100%)) !default; // success 背景颜色
657
+ $-corner-warning-bg: var(--oxy-corner-warning-bg, resultColor(90deg, $-color-warning, 'dark' 'light', #ff8124 #ffb48f, 0% 100%)) !default; // warning 背景颜色
658
+ $-corner-danger-bg: var(--oxy-corner-danger-bg, resultColor(90deg, $-color-danger, 'dark' 'light', #fa4350 #fea1a8, 0% 100%)) !default; // danger 背景颜色
659
+ $-corner-horizontal-font-size: var(--oxy-corner-fs, $-fs-content) !default; // 字号
660
+ $-corner-horizontal-font-weight: var(--oxy-corner-fs, $-fw-semibold) !default; // 字号
661
+ $-corner-horizontal-primary-bg: var(--oxy-corner-primary-bg, resultColor(90deg, $-color-theme, 'light' 'dark', #ffffff #cceaff, 0% 100%)) !default; // 主背景颜色
662
+ $-corner-horizontal-info-bg: var(--oxy-corner-info-bg, resultColor(90deg, $-color-info, 'light' 'dark', #ffffff #adb6c6, 0% 100%)) !default; // info 背景颜色
663
+ $-corner-horizontal-success-bg: var(--oxy-corner-success-bg, resultColor(90deg, $-color-success, 'light' 'dark', #ffffff #b2ebcf, 0% 100%)) !default; // success 背景颜色
664
+ $-corner-horizontal-warning-bg: var(--oxy-corner-warning-bg, resultColor(90deg, $-color-warning, 'light' 'dark', #ffffff #fcedd6, 0% 100%)) !default; // warning 背景颜色
665
+ $-corner-horizontal-danger-bg: var(--oxy-corner-danger-bg, resultColor(90deg, $-color-danger, 'light' 'dark', #ffffff #ffd5d8, 0% 100%)) !default; // danger 背景颜色
666
+ $-corner-embedded-font-size: var(--oxy-corner-fs, $-fs-content) !default; // 字号
667
+ $-corner-embedded-font-weight: var(--oxy-corner-fs, 400) !default; // 字号
668
+ $-corner-embedded-primary-bg: var(--oxy-corner-primary-bg, #cceaff) !default; // 主背景颜色
669
+ $-corner-embedded-info-bg: var(--oxy-corner-info-bg, #eef4fc) !default; // info 背景颜色
670
+ $-corner-embedded-success-bg: var(--oxy-corner-success-bg, #b2ebcf) !default; // success 背景颜色
671
+ $-corner-embedded-warning-bg: var(--oxy-corner-warning-bg, #fcedd6) !default; // warning 背景颜色
672
+ $-corner-embedded-danger-bg: var(--oxy-corner-danger-bg, #ffd5d8) !default; // danger 背景颜色
673
+
644
674
  /* toast */
645
675
  $-toast-color: var(--oxy-toast-color, $-color-white) !default; // 文字颜色
646
676
  $-toast-padding: var(--oxy-toast-padding, 16px 24px) !default; // padding
@@ -728,7 +758,7 @@ $-upload-evoke-disabled-color: var(--oxy-upload-evoke-disabled-color, rgba(0, 0,
728
758
  $-upload-close-icon-size: var(--oxy-upload-close-icon-size, 16px) !default; // 移除按钮尺寸
729
759
  $-upload-close-icon-color: var(--oxy-upload-close-icon-color, rgba(0, 0, 0, 0.65)) !default; // 移除按钮颜色
730
760
  $-upload-progress-fs: var(--oxy-upload-progress-fs, 14px) !default; // 进度文字字号
731
- $-upload-file-fs: var(--oxy-upload-file-fs, 12px) !default; // 文件名字号
761
+ $-upload-file-fs: var(--oxy-upload-file-fs, 14px) !default; // 文件名字号
732
762
  $-upload-file-color: var(--oxy-upload-file-color, $-color-secondary) !default; // 文件名字颜色
733
763
  $-upload-preview-name-fs: var(--oxy-upload-preview-name-fs, 12px) !default; // 预览图片名字号
734
764
  $-upload-preview-icon-size: var(--oxy-upload-preview-icon-size, 24px) !default; // 预览内部图标尺寸
@@ -736,6 +766,9 @@ $-upload-preview-name-bg: var(--oxy-upload-preview-name-bg, rgba(0, 0, 0, 0.6))
736
766
  $-upload-preview-name-height: var(--oxy-upload-preview-name-height, 22px) !default; // 预览文件名背景高度
737
767
  $-upload-cover-icon-size: var(--oxy-upload-cover-icon-size, 22px) !default; // 视频/文件图标尺寸
738
768
 
769
+ /* file-list */
770
+ $-file-list-height: var(--oxy-file-list-height, 100px) !default; // 文件高度
771
+
739
772
  /* curtain */
740
773
  $-curtain-content-radius: var(--oxy-curtain-content-radius, 24px) !default; // 内容圆角
741
774
  $-curtain-content-close-color: var(--oxy-curtain-content-close-color, $-color-white) !default; // 关闭按钮颜色
@@ -971,4 +1004,7 @@ $-signature-footer-margin-top: var(--oxy-signature-footer-margin-top, 8px) !defa
971
1004
  $-signature-button-margin-left: var(--oxy-signature-button-margin-left, 8px) !default; // 底部按钮左边距
972
1005
 
973
1006
 
974
-
1007
+ /* tree */
1008
+ $-tree-node-current-bg:var(--oxy-tree-node-current-bg, var(--oxy-color-theme, #4d80ef1a));
1009
+ $-tree-node-current-color:var(--oxy-tree-node-current-color, $-text-primary-color);
1010
+ $-tree-node-disabled-color:var(--oxy-tree-node-disabled-color, $-color-icon-disabled);
@@ -720,6 +720,17 @@ export function isVideoUrl(url: string): boolean {
720
720
  return videoRegex.test(url)
721
721
  }
722
722
 
723
+ /**
724
+ * 检查提供的URL是否为音频文件。
725
+ * @param url 待检查的URL字符串。
726
+ * @returns 返回一个布尔值,如果URL是音频文件,则为true;否则为false。
727
+ */
728
+ export function isAudioUrl(url: string): boolean {
729
+ // 使用正则表达式匹配音频文件URL
730
+ const audioRegex = /\.(mp3|wav|ogg|flac|aac|m4a|wma|amr|aac)(?=$|[?#])/i
731
+ return audioRegex.test(url)
732
+ }
733
+
723
734
  /**
724
735
  * 检查提供的URL是否为图片URL。
725
736
  * @param url 待检查的URL字符串。
@@ -731,6 +742,39 @@ export function isImageUrl(url: string): boolean {
731
742
  return imageRegex.test(url)
732
743
  }
733
744
 
745
+ /**
746
+ * 检查提供的URL是否为PDF文件。
747
+ * @param url 待检查的URL字符串。
748
+ * @returns 返回一个布尔值,如果URL是PDF文件,则为true;否则为false。
749
+ */
750
+ export function isPdfUrl(url: string): boolean {
751
+ // 使用正则表达式匹配PDF文件URL
752
+ const pdfRegex = /\.(pdf)(?=$|[?#])/i
753
+ return pdfRegex.test(url)
754
+ }
755
+
756
+ /**
757
+ * 检查提供的URL是否为文档文件。
758
+ * @param url 待检查的URL字符串。
759
+ * @returns 返回一个布尔值,如果URL是文档文件,则为true;否则为false。
760
+ */
761
+ export function isDocUrl(url: string): boolean {
762
+ // 使用正则表达式匹配文档文件URL
763
+ const docRegex = /\.(doc|docx|ppt|pptx|odt|odp|ods|odg|odf|txt|rtf|tex|wpd|wps|wp)(?=$|[?#])/i
764
+ return docRegex.test(url)
765
+ }
766
+
767
+ /**
768
+ * 检查提供的URL是否为excel文件。
769
+ * @param url 待检查的URL字符串。
770
+ * @returns 返回一个布尔值,如果URL是excel文件,则为true;否则为false。
771
+ */
772
+ export function isExcelUrl(url: string): boolean {
773
+ // 使用正则表达式匹配excel文件URL
774
+ const excelRegex = /\.(xls|xlsx|xlsm|xlsb|xltx|xltm|xla|xlam|xll|xlw)(?=$|[?#])/i
775
+ return excelRegex.test(url)
776
+ }
777
+
734
778
  /**
735
779
  * 判断环境是否是H5
736
780
  */
@@ -9,3 +9,4 @@ export { useRaf } from './useRaf'
9
9
  export { useTouch } from './useTouch'
10
10
  export { useTranslate } from './useTranslate'
11
11
  export { useUpload } from './useUpload'
12
+ export { useVirtualScroll } from './useVirtualScroll'
@@ -0,0 +1,172 @@
1
+ /**
2
+ * 虚拟滚动组合式函数 - 用于复用虚拟滚动逻辑
3
+ */
4
+
5
+ import { ref, computed, watch, nextTick, type Ref } from 'vue'
6
+ import { VirtualScrollEngine } from '../oxy-virtual-scroll/virtual-scroll'
7
+
8
+ export interface UseVirtualScrollOptions {
9
+ data: Ref<any[]>
10
+ virtual: Ref<boolean>
11
+ height: Ref<string>
12
+ itemHeight: Ref<string>
13
+ idKey: Ref<string>
14
+ backToTopThreshold: Ref<string>
15
+ }
16
+
17
+ export interface UseVirtualScrollReturn {
18
+ // 响应式数据
19
+ scrollTop: Ref<number>
20
+ showBackTopBtn: Ref<boolean>
21
+ virtualData: Ref<any[]>
22
+ startIndex: Ref<number>
23
+ virtualOffsetY: Ref<number>
24
+ totalHeight: Ref<number>
25
+ displayData: Ref<any[]>
26
+
27
+ // 方法
28
+ initScrollData: () => void
29
+ initScrollEngine: () => void
30
+ updateVisibleData: () => void
31
+ scrollToTop: () => void
32
+ scrollToBottom: () => void
33
+ scrollToPosition: (position: number | string) => void
34
+ scrollToElement: (item: any) => void
35
+ scrollToElementById: (id: string | number) => void
36
+ onScroll: (scrollTopValue: number) => void
37
+ }
38
+
39
+ export function useVirtualScroll(options: UseVirtualScrollOptions): UseVirtualScrollReturn {
40
+ const { data, virtual, height, itemHeight, idKey, backToTopThreshold } = options
41
+
42
+ // 响应式数据
43
+ const scrollTop = ref<number>(0)
44
+ const showBackTopBtn = ref<boolean>(false)
45
+ const virtualData = ref<any[]>([])
46
+ const startIndex = ref<number>(0)
47
+ const virtualOffsetY = ref<number>(0)
48
+ const virtualEngine = ref<any>(null)
49
+
50
+ // 计算属性
51
+ const displayData = computed<any[]>(() => data.value)
52
+
53
+ const totalHeight = computed(() => {
54
+ return displayData.value.length * parseFloat(itemHeight.value)
55
+ })
56
+
57
+ // 监听数据变化
58
+ watch(
59
+ () => data.value,
60
+ () => {
61
+ nextTick(initScrollData)
62
+ },
63
+ {
64
+ immediate: true,
65
+ deep: true
66
+ }
67
+ )
68
+
69
+ // 初始化滚动数据
70
+ function initScrollData() {
71
+ if (!virtual.value) {
72
+ // 非虚拟滚动模式:直接使用全部数据
73
+ virtualData.value = displayData.value
74
+ virtualOffsetY.value = 0
75
+ return
76
+ }
77
+
78
+ virtualEngine.value = new VirtualScrollEngine({
79
+ containerHeight: parseFloat(height.value),
80
+ itemHeight: parseFloat(itemHeight.value),
81
+ data: displayData.value
82
+ })
83
+ updateVisibleData()
84
+ }
85
+
86
+ // 初始化滚动引擎
87
+ function initScrollEngine() {
88
+ if (!virtual.value) return
89
+
90
+ virtualEngine.value = new VirtualScrollEngine({
91
+ containerHeight: parseFloat(height.value),
92
+ itemHeight: parseFloat(itemHeight.value),
93
+ data: displayData.value
94
+ })
95
+ }
96
+
97
+ // 更新可见数据
98
+ function updateVisibleData() {
99
+ if (!virtual.value) return // 非虚拟模式不处理
100
+
101
+ if (virtualEngine.value) {
102
+ const { visibleData, offsetY } = virtualEngine.value.updateVisibleData(scrollTop.value || 0)
103
+ virtualData.value = visibleData
104
+ virtualOffsetY.value = offsetY
105
+ }
106
+ }
107
+
108
+ // 滚动事件处理
109
+ function onScroll(scrollTopValue: number) {
110
+ scrollTop.value = scrollTopValue
111
+ showBackTopBtn.value = scrollTopValue > parseFloat(backToTopThreshold.value)
112
+ updateVisibleData()
113
+ }
114
+
115
+ // 滚动到顶部
116
+ function scrollToTop() {
117
+ scrollTop.value = 0
118
+ nextTick(() => {
119
+ scrollTop.value = 0
120
+ })
121
+ }
122
+
123
+ // 滚动到底部
124
+ function scrollToBottom() {
125
+ scrollToPosition(totalHeight.value)
126
+ }
127
+
128
+ // 滚动到指定位置
129
+ function scrollToPosition(position: number | string) {
130
+ scrollTop.value = typeof position === 'number' ? position : parseFloat(position)
131
+ }
132
+
133
+ // 滚动到指定元素
134
+ function scrollToElement(item: any) {
135
+ const index = data.value.findIndex((o) => item[idKey.value] && o[idKey.value] && o[idKey.value] === item[idKey.value])
136
+ if (index > 0) {
137
+ const scrollDistance = parseFloat(itemHeight.value) * index
138
+ scrollToPosition(scrollDistance)
139
+ }
140
+ }
141
+
142
+ // 根据ID滚动到指定元素
143
+ function scrollToElementById(id: string | number) {
144
+ const index = data.value.findIndex((o) => id && o[idKey.value] && o[idKey.value] === id)
145
+ if (index > 0) {
146
+ const scrollDistance = parseFloat(itemHeight.value) * index
147
+ scrollToPosition(scrollDistance)
148
+ }
149
+ }
150
+
151
+ return {
152
+ // 响应式数据
153
+ scrollTop,
154
+ showBackTopBtn,
155
+ virtualData,
156
+ startIndex,
157
+ virtualOffsetY,
158
+ totalHeight,
159
+ displayData,
160
+
161
+ // 方法
162
+ initScrollData,
163
+ initScrollEngine,
164
+ updateVisibleData,
165
+ scrollToTop,
166
+ scrollToBottom,
167
+ scrollToPosition,
168
+ scrollToElement,
169
+ scrollToElementById,
170
+ onScroll
171
+ }
172
+ }
@@ -1,5 +1,5 @@
1
- @import "./../common/abstracts/_mixin.scss";
2
- @import "./../common/abstracts/variable.scss";
1
+ @import './../common/abstracts/_mixin.scss';
2
+ @import './../common/abstracts/variable.scss';
3
3
 
4
4
  .oxy-theme-dark {
5
5
  @include b(checkbox) {
@@ -38,7 +38,6 @@
38
38
  }
39
39
 
40
40
  @include when(button) {
41
-
42
41
  .oxy-checkbox__label {
43
42
  border-color: #c8c9cc;
44
43
  background: #3a3a3c;
@@ -66,7 +65,6 @@
66
65
  }
67
66
  }
68
67
  }
69
-
70
68
  }
71
69
  }
72
70
 
@@ -137,8 +135,35 @@
137
135
  transition: opacity 0.2s;
138
136
  }
139
137
 
138
+ @include edeep(indeterminate) {
139
+ color: $-checkbox-check-color;
140
+ font-size: $-checkbox-icon-size;
141
+ opacity: 0;
142
+ transition: opacity 0.2s;
143
+ }
144
+
145
+ @include when(indeterminate) {
146
+ .oxy-checkbox__shape {
147
+ color: $-checkbox-checked-color;
148
+ background: currentColor;
149
+ border-color: currentColor;
150
+ }
151
+
152
+ :deep(.oxy-checkbox__indeterminate) {
153
+ opacity: 1;
154
+ position: absolute;
155
+ left: 50%;
156
+ top: 50%;
157
+ transform: translate(-50%, -50%);
158
+ }
159
+ :deep(.oxy-checkbox__check) {
160
+ display: none;
161
+ }
162
+ }
163
+
140
164
  @include when(checked) {
141
165
  .oxy-checkbox__shape {
166
+ display: inline-block;
142
167
  color: $-checkbox-checked-color;
143
168
  background: currentColor;
144
169
  border-color: currentColor;
@@ -151,8 +176,13 @@
151
176
  top: 50%;
152
177
  transform: translate(-50%, -50%);
153
178
  }
179
+
180
+ :deep(.oxy-checkbox__indeterminate) {
181
+ display: none;
182
+ }
154
183
  }
155
184
 
185
+
156
186
  @include when(button) {
157
187
  display: inline-block;
158
188
  margin-bottom: 0;
@@ -265,7 +295,7 @@
265
295
  }
266
296
 
267
297
  &:last-child::after {
268
- content: "";
298
+ content: '';
269
299
  display: table;
270
300
  clear: both;
271
301
  }
@@ -282,4 +312,4 @@
282
312
  font-size: $-checkbox-large-label-fs;
283
313
  }
284
314
  }
285
- }
315
+ }
@@ -1,10 +1,10 @@
1
1
  <template>
2
2
  <view
3
3
  :class="`oxy-checkbox ${innerCell ? 'is-cell-box' : ''} ${innerShape === 'button' ? 'is-button-box' : ''} ${isChecked ? 'is-checked' : ''} ${
4
- isFirst ? 'is-first-child' : ''
5
- } ${isLast ? 'is-last-child' : ''} ${innerInline ? 'is-inline' : ''} ${innerShape === 'button' ? 'is-button' : ''} ${
6
- innerDisabled ? 'is-disabled' : ''
7
- } ${innerSize ? 'is-' + innerSize : ''} ${customClass}`"
4
+ indeterminate ? 'is-indeterminate' : ''
5
+ } ${isFirst ? 'is-first-child' : ''} ${isLast ? 'is-last-child' : ''} ${innerInline ? 'is-inline' : ''} ${
6
+ innerShape === 'button' ? 'is-button' : ''
7
+ } ${innerDisabled ? 'is-disabled' : ''} ${innerSize ? 'is-' + innerSize : ''} ${customClass}`"
8
8
  :style="customStyle"
9
9
  @click="toggle"
10
10
  >
@@ -14,6 +14,7 @@
14
14
  :class="`oxy-checkbox__shape ${innerShape === 'square' ? 'is-square' : ''} ${customShapeClass}`"
15
15
  :style="isChecked && !innerDisabled && innerCheckedColor ? 'color :' + innerCheckedColor : ''"
16
16
  >
17
+ <oxy-icon custom-class="oxy-checkbox__indeterminate" name="decrease" />
17
18
  <oxy-icon custom-class="oxy-checkbox__check" name="check-bold" />
18
19
  </view>
19
20
  <!--shape为button时只保留oxy-checkbox__label-->
@@ -1,5 +1,5 @@
1
1
  import type { ComponentPublicInstance, ExtractPropTypes, PropType } from 'vue'
2
- import { baseProps, makeStringProp } from '../common/props'
2
+ import { baseProps, makeBooleanProp, makeStringProp } from '../common/props'
3
3
 
4
4
  export type CheckShape = 'circle' | 'square' | 'button'
5
5
 
@@ -15,6 +15,7 @@ export const checkboxProps = {
15
15
  required: true,
16
16
  default: false
17
17
  },
18
+ indeterminate: makeBooleanProp(false),
18
19
  /**
19
20
  * 单选框形状,可选值:circle / square / button
20
21
  */
@@ -60,9 +60,8 @@
60
60
  color: $-input-placeholder-color;
61
61
  }
62
62
  }
63
-
64
63
  }
65
-
64
+
66
65
  @include edeep(arrow) {
67
66
  display: block;
68
67
  font-size: $-cell-icon-size;
@@ -76,13 +75,13 @@
76
75
  color: $-col-picker-selected-color;
77
76
  overflow: hidden;
78
77
  }
79
-
80
- @include e(selected-container){
78
+
79
+ @include e(selected-container) {
81
80
  position: relative;
82
81
  display: flex;
83
82
  user-select: none;
84
83
  }
85
-
84
+
86
85
  @include e(selected-item) {
87
86
  flex: 0 0 auto;
88
87
  height: $-col-picker-selected-height;
@@ -93,7 +92,7 @@
93
92
  font-weight: $-col-picker-selected-fw;
94
93
  }
95
94
  }
96
-
95
+
97
96
  @include e(selected-line) {
98
97
  position: absolute;
99
98
  bottom: 5px;
@@ -105,11 +104,11 @@
105
104
  border-radius: calc($-col-picker-line-height / 2);
106
105
  box-shadow: $-col-picker-line-box-shadow;
107
106
  }
108
-
109
- @include e(list-container){
107
+
108
+ @include e(list-container) {
110
109
  position: relative;
111
110
  }
112
-
111
+
113
112
  @include e(list) {
114
113
  height: $-col-picker-list-height;
115
114
  padding-bottom: $-col-picker-list-padding-bottom;
@@ -119,7 +118,7 @@
119
118
  font-size: $-col-picker-list-fs;
120
119
  -webkit-overflow-scrolling: touch;
121
120
  }
122
-
121
+
123
122
  @include e(list-item) {
124
123
  display: flex;
125
124
  padding: $-col-picker-list-item-padding;
@@ -136,17 +135,21 @@
136
135
  color: $-col-picker-list-color-disabled;
137
136
  }
138
137
  }
139
-
138
+
140
139
  @include e(list-item-label) {
141
140
  line-height: 1.285;
142
141
  }
143
-
142
+
144
143
  @include e(list-item-tip) {
145
144
  margin-top: 2px;
146
145
  font-size: $-col-picker-list-fs-tip;
147
146
  color: $-col-picker-list-color-tip;
148
147
  }
149
-
148
+
149
+ @include e(confirm) {
150
+ padding: 12px 25px 14px;
151
+ }
152
+
150
153
  @include edeep(checked) {
151
154
  display: block;
152
155
  margin-left: 4px;
@@ -154,7 +157,7 @@
154
157
  color: $-col-picker-list-color-checked;
155
158
  opacity: 0;
156
159
  }
157
-
160
+
158
161
  @include e(loading) {
159
162
  display: flex;
160
163
  position: absolute;
@@ -165,4 +168,4 @@
165
168
  align-items: center;
166
169
  justify-content: center;
167
170
  }
168
- }
171
+ }
@@ -83,6 +83,9 @@
83
83
  </view>
84
84
  </view>
85
85
  </view>
86
+ <view v-if="showConfirm" class="oxy-col-picker__confirm">
87
+ <oxy-button block @click="handleBtnConfirm">{{ confirmText || translate('confirm') }}</oxy-button>
88
+ </view>
86
89
  </oxy-action-sheet>
87
90
  </view>
88
91
  </template>
@@ -102,7 +105,7 @@ import OxyIcon from '../oxy-icon/oxy-icon.vue'
102
105
  import OxyLoading from '../oxy-loading/oxy-loading.vue'
103
106
  import OxyActionSheet from '../oxy-action-sheet/oxy-action-sheet.vue'
104
107
  import OxyCell from '../oxy-cell/oxy-cell.vue'
105
- import { computed, getCurrentInstance, onMounted, ref, watch, type CSSProperties, reactive } from 'vue'
108
+ import { computed, getCurrentInstance, onMounted, ref, watch, type CSSProperties, type ComponentPublicInstance, reactive } from 'vue'
106
109
  import { addUnit, debounce, getRect, isArray, isBoolean, isDef, isFunction, objToStyle } from '../common/util'
107
110
  import { useTranslate } from '../composables/useTranslate'
108
111
  import { colPickerProps, type ColPickerExpose } from './types'
@@ -314,7 +317,7 @@ function getSelectedItem(value: string | number, colIndex: number, selectList: R
314
317
  }
315
318
  }
316
319
 
317
- function chooseItem(colIndex: number, index: number) {
320
+ function chooseItem(colIndex: number, index: number, triggerColChange: boolean = true) {
318
321
  const item = selectList.value[colIndex][index]
319
322
  if (item.disabled) return
320
323
 
@@ -331,7 +334,9 @@ function chooseItem(colIndex: number, index: number) {
331
334
  updateLineAndScroll(true)
332
335
  }
333
336
 
334
- handleColChange(colIndex, item, index)
337
+ if (triggerColChange) {
338
+ handleColChange(colIndex, item, index)
339
+ }
335
340
  }
336
341
 
337
342
  function handleColChange(colIndex: number, item: Record<string, any>, index: number, callback?: () => void) {
@@ -396,6 +401,26 @@ function handleColChange(colIndex: number, item: Record<string, any>, index: num
396
401
  }
397
402
  })
398
403
  }
404
+ function handleBtnConfirm() {
405
+ const { beforeConfirm } = props
406
+ if (beforeConfirm) {
407
+ beforeConfirm(
408
+ pickerColSelected.value,
409
+ pickerColSelected.value.map((item, colIndex) => {
410
+ return getSelectedItem(item, colIndex, selectList.value)
411
+ }),
412
+ (isPass: boolean) => {
413
+ if (isPass) {
414
+ onConfirm()
415
+ } else {
416
+ loading.value = false
417
+ }
418
+ }
419
+ )
420
+ } else {
421
+ onConfirm()
422
+ }
423
+ }
399
424
  function onConfirm() {
400
425
  isChange.value = false
401
426
  loading.value = false
@@ -100,6 +100,18 @@ export const colPickerProps = {
100
100
  * 弹窗层级
101
101
  */
102
102
  zIndex: makeNumberProp(15),
103
+ /**
104
+ * 是否显示确定按钮
105
+ */
106
+ showConfirm: makeBooleanProp(false),
107
+ /**
108
+ * 多选时,添加按钮文字
109
+ */
110
+ addText: String,
111
+ /**
112
+ * 确定按钮文字
113
+ */
114
+ confirmText: String,
103
115
  /**
104
116
  * 弹出面板是否设置底部安全距离(iphone X 类型的机型)
105
117
  */