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.
- package/LICENSE +1 -1
- package/attributes.json +1 -1
- package/components/common/abstracts/variable.scss +40 -4
- package/components/common/util.ts +44 -0
- package/components/composables/index.ts +1 -0
- package/components/composables/useVirtualScroll.ts +172 -0
- package/components/oxy-checkbox/index.scss +36 -6
- package/components/oxy-checkbox/oxy-checkbox.vue +5 -4
- package/components/oxy-checkbox/types.ts +2 -1
- package/components/oxy-col-picker/index.scss +18 -15
- package/components/oxy-col-picker/oxy-col-picker.vue +28 -3
- package/components/oxy-col-picker/types.ts +12 -0
- package/components/oxy-corner/index.scss +258 -0
- package/components/oxy-corner/oxy-corner.vue +67 -0
- package/components/oxy-corner/types.ts +50 -0
- package/components/oxy-drop-menu/index.scss +4 -0
- package/components/oxy-drop-menu/oxy-drop-menu.vue +5 -3
- package/components/oxy-drop-menu/types.ts +1 -1
- package/components/oxy-drop-menu-item/index.scss +4 -4
- package/components/oxy-drop-menu-item/oxy-drop-menu-item.vue +2 -0
- package/components/oxy-file-list/index.scss +83 -0
- package/components/oxy-file-list/oxy-file-list.vue +213 -0
- package/components/oxy-file-list/types.ts +54 -0
- package/components/oxy-list/index.scss +5 -0
- package/components/oxy-list/oxy-list.vue +206 -0
- package/components/oxy-list/types.ts +38 -0
- package/components/oxy-slider/index.scss +2 -2
- package/components/oxy-swiper/index.scss +1 -2
- package/components/oxy-textarea/oxy-textarea.vue +0 -4
- package/components/oxy-tree/components/tree-node-content.vue +72 -0
- package/components/oxy-tree/index.scss +83 -0
- package/components/oxy-tree/index.ts +51 -0
- package/components/oxy-tree/oxy-tree.vue +406 -0
- package/components/oxy-tree/types.ts +85 -0
- package/components/oxy-tree/utils.ts +51 -0
- package/components/oxy-upload/images/audio.png +0 -0
- package/components/oxy-upload/images/excle.png +0 -0
- package/components/oxy-upload/images/other.png +0 -0
- package/components/oxy-upload/images/pdf.png +0 -0
- package/components/oxy-upload/images/pic.png +0 -0
- package/components/oxy-upload/images/txt.png +0 -0
- package/components/oxy-upload/images/video.png +0 -0
- package/components/oxy-upload/images/word.png +0 -0
- package/components/oxy-upload/index.scss +50 -0
- package/components/oxy-upload/oxy-upload.vue +93 -7
- package/components/oxy-upload/types.ts +22 -1
- package/components/oxy-virtual-scroll/index.scss +35 -0
- package/components/oxy-virtual-scroll/oxy-virtual-scroll.vue +143 -0
- package/components/oxy-virtual-scroll/types.ts +155 -0
- package/components/oxy-virtual-scroll/virtual-scroll.ts +81 -0
- package/global.d.ts +3 -0
- package/locale/lang/ar-SA.ts +2 -1
- package/locale/lang/en-US.ts +10 -9
- package/locale/lang/zh-CN.ts +7 -6
- package/package.json +1 -1
- package/tags.json +1 -1
- 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,
|
|
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,
|
|
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
|
*/
|
|
@@ -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
|
|
2
|
-
@import
|
|
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
|
-
|
|
5
|
-
} ${
|
|
6
|
-
|
|
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
|
-
|
|
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
|
*/
|