oxy-uni-ui 1.1.0 → 1.2.3

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 (123) hide show
  1. package/attributes.json +1 -1
  2. package/components/common/abstracts/variable.scss +59 -1
  3. package/components/common/path.ts +9 -0
  4. package/components/common/util.ts +42 -0
  5. package/components/composables/index.ts +1 -0
  6. package/components/composables/useGlobalLoading.ts +42 -0
  7. package/components/composables/useGlobalMessage.ts +48 -0
  8. package/components/composables/useGlobalToast.ts +84 -0
  9. package/components/composables/useVirtualScroll.ts +173 -0
  10. package/components/oxy-cell/oxy-cell.vue +15 -2
  11. package/components/oxy-cell/types.ts +4 -0
  12. package/components/oxy-checkbox/index.scss +1 -1
  13. package/components/oxy-checkbox/oxy-checkbox.vue +2 -2
  14. package/components/oxy-col-picker/oxy-col-picker.vue +3 -0
  15. package/components/oxy-col-picker/types.ts +5 -1
  16. package/components/oxy-corner/index.scss +121 -1
  17. package/components/oxy-corner/oxy-corner.vue +18 -5
  18. package/components/oxy-corner/types.ts +24 -3
  19. package/components/oxy-date-strip/index.scss +10 -0
  20. package/components/oxy-date-strip/oxy-date-strip.vue +198 -0
  21. package/components/oxy-date-strip/types.ts +98 -0
  22. package/components/oxy-date-strip/utils.ts +67 -0
  23. package/components/oxy-date-strip-item/index.scss +94 -0
  24. package/components/oxy-date-strip-item/oxy-date-strip-item.vue +102 -0
  25. package/components/oxy-date-strip-item/types.ts +53 -0
  26. package/components/oxy-datetime-picker/oxy-datetime-picker.vue +3 -1
  27. package/components/oxy-datetime-picker/types.ts +5 -1
  28. package/components/oxy-echarts/index.scss +17 -0
  29. package/components/oxy-echarts/index.ts +1 -0
  30. package/components/oxy-echarts/oxy-echarts.vue +32 -0
  31. package/components/oxy-echarts/types.ts +12 -0
  32. package/components/oxy-file-list/index.scss +26 -0
  33. package/components/oxy-file-list/oxy-file-list.vue +208 -34
  34. package/components/oxy-file-list/types.ts +58 -2
  35. package/components/oxy-global-loading/oxy-global-loading.vue +53 -0
  36. package/components/oxy-global-message/oxy-global-message.vue +64 -0
  37. package/components/oxy-global-toast/oxy-global-toast.vue +53 -0
  38. package/components/oxy-img-lazy/index.scss +17 -0
  39. package/components/oxy-img-lazy/oxy-img-lazy.vue +332 -0
  40. package/components/oxy-img-lazy/types.ts +69 -0
  41. package/components/oxy-link/index.scss +57 -0
  42. package/components/oxy-link/oxy-link.vue +130 -0
  43. package/components/oxy-link/types.ts +81 -0
  44. package/components/oxy-list/index.scss +8 -1
  45. package/components/oxy-list/oxy-list.vue +121 -40
  46. package/components/oxy-list/types.ts +3 -15
  47. package/components/oxy-picker/oxy-picker.vue +3 -0
  48. package/components/oxy-picker/types.ts +5 -1
  49. package/components/oxy-radio/index.scss +3 -3
  50. package/components/oxy-radio/oxy-radio.vue +1 -1
  51. package/components/oxy-rich-text/icon/emjio.svg +1 -0
  52. package/components/oxy-rich-text/icon/quote.svg +1 -0
  53. package/components/oxy-rich-text/icon/text.svg +1 -0
  54. package/components/oxy-rich-text/icon/title.svg +1 -0
  55. package/components/oxy-rich-text/index.scss +159 -0
  56. package/components/oxy-rich-text/mp-html/card/card.vue +122 -0
  57. package/components/oxy-rich-text/mp-html/card/index.js +7 -0
  58. package/components/oxy-rich-text/mp-html/editable/config.js +15 -0
  59. package/components/oxy-rich-text/mp-html/editable/index.js +553 -0
  60. package/components/oxy-rich-text/mp-html/emoji/index.js +203 -0
  61. package/components/oxy-rich-text/mp-html/highlight/config.js +5 -0
  62. package/components/oxy-rich-text/mp-html/highlight/index.js +96 -0
  63. package/components/oxy-rich-text/mp-html/highlight/prism.css +1 -0
  64. package/components/oxy-rich-text/mp-html/highlight/prism.min.js +7 -0
  65. package/components/oxy-rich-text/mp-html/img-cache/index.js +138 -0
  66. package/components/oxy-rich-text/mp-html/latex/index.js +80 -0
  67. package/components/oxy-rich-text/mp-html/latex/katex.css +1 -0
  68. package/components/oxy-rich-text/mp-html/latex/katex.min.js +1 -0
  69. package/components/oxy-rich-text/mp-html/markdown/index.js +50 -0
  70. package/components/oxy-rich-text/mp-html/markdown/marked.min.js +71 -0
  71. package/components/oxy-rich-text/mp-html/mp-html.d.ts +184 -0
  72. package/components/oxy-rich-text/mp-html/mp-html.vue +675 -0
  73. package/components/oxy-rich-text/mp-html/node/node.vue +1161 -0
  74. package/components/oxy-rich-text/mp-html/parser.js +1428 -0
  75. package/components/oxy-rich-text/mp-html/search/index.js +132 -0
  76. package/components/oxy-rich-text/mp-html/style/index.js +129 -0
  77. package/components/oxy-rich-text/mp-html/style/parser.js +175 -0
  78. package/components/oxy-rich-text/mp-html/template/index.js +67 -0
  79. package/components/oxy-rich-text/mp-html/txv-video/index.js +46 -0
  80. package/components/oxy-rich-text/oxy-rich-text.vue +642 -0
  81. package/components/oxy-rich-text/types.ts +71 -0
  82. package/components/oxy-select/index.scss +255 -0
  83. package/components/oxy-select/oxy-select.vue +421 -0
  84. package/components/oxy-select/types.ts +71 -0
  85. package/components/oxy-select-picker/oxy-select-picker.vue +3 -0
  86. package/components/oxy-select-picker/types.ts +5 -1
  87. package/components/oxy-stream-render/index.scss +6 -0
  88. package/components/oxy-stream-render/oxy-stream-render.vue +204 -0
  89. package/components/oxy-stream-render/types.ts +5 -0
  90. package/components/oxy-tree/index.scss +43 -5
  91. package/components/oxy-tree/oxy-tree.vue +233 -35
  92. package/components/oxy-tree/types.ts +54 -7
  93. package/components/oxy-tree/utils.ts +51 -0
  94. package/components/oxy-virtual-scroll/index.scss +1 -1
  95. package/components/oxy-virtual-scroll/oxy-virtual-scroll.vue +69 -110
  96. package/components/oxy-virtual-scroll/types.ts +95 -5
  97. package/components/oxy-waterfall/index.scss +18 -0
  98. package/components/oxy-waterfall/oxy-waterfall.vue +218 -0
  99. package/components/oxy-waterfall/types.ts +90 -0
  100. package/components/oxy-waterfall-item/index.scss +8 -0
  101. package/components/oxy-waterfall-item/oxy-waterfall-item.vue +89 -0
  102. package/components/oxy-waterfall-item/types.ts +16 -0
  103. package/global.d.ts +7 -0
  104. package/index.ts +3 -0
  105. package/locale/lang/en-US.ts +35 -9
  106. package/locale/lang/zh-CN.ts +31 -5
  107. package/oxy-uni-ui.zip +0 -0
  108. package/package.json +1 -1
  109. package/tags.json +1 -1
  110. package/uni-echarts/changelog.md +2 -0
  111. package/uni-echarts/components/index.js +1 -0
  112. package/uni-echarts/components/uni-echarts/events.js +95 -0
  113. package/uni-echarts/components/uni-echarts/types.d.ts +183 -0
  114. package/uni-echarts/components/uni-echarts/types.js +1 -0
  115. package/uni-echarts/components/uni-echarts/uni-echarts.vue +530 -0
  116. package/uni-echarts/components/uni-echarts/uni-echarts.vue.d.ts +19 -0
  117. package/uni-echarts/global.d.ts +7 -0
  118. package/uni-echarts/index.d.ts +440 -0
  119. package/uni-echarts/index.js +2 -0
  120. package/uni-echarts/package.json +105 -0
  121. package/uni-echarts/shared-core.d.ts +269 -0
  122. package/uni-echarts/shared-core.js +900 -0
  123. package/web-types.json +1 -1
@@ -14,6 +14,9 @@
14
14
  width: 80px;
15
15
  height: 80px;
16
16
  overflow: hidden;
17
+ @include when(round) {
18
+ border-top-right-radius: $-corner-radius;
19
+ }
17
20
  @include when(primary) {
18
21
  .oxy-corner__text {
19
22
  @include corner-type-style($-corner-color, $-corner-primary-bg);
@@ -23,6 +26,11 @@
23
26
  @include corner-type-style($-corner-primary-color, $-corner-horizontal-primary-bg);
24
27
  }
25
28
  }
29
+ &.is-embedded {
30
+ .oxy-corner__text {
31
+ @include corner-type-style($-corner-primary-color, $-corner-embedded-primary-bg);
32
+ }
33
+ }
26
34
  }
27
35
  @include when(info) {
28
36
  .oxy-corner__text {
@@ -33,6 +41,11 @@
33
41
  @include corner-type-style($-corner-info-color, $-corner-horizontal-info-bg);
34
42
  }
35
43
  }
44
+ &.is-embedded {
45
+ .oxy-corner__text {
46
+ @include corner-type-style($-corner-info-color, $-corner-embedded-info-bg);
47
+ }
48
+ }
36
49
  }
37
50
  @include when(success) {
38
51
  .oxy-corner__text {
@@ -43,6 +56,11 @@
43
56
  @include corner-type-style($-corner-success-color, $-corner-horizontal-success-bg);
44
57
  }
45
58
  }
59
+ &.is-embedded {
60
+ .oxy-corner__text {
61
+ @include corner-type-style($-corner-success-color, $-corner-embedded-success-bg);
62
+ }
63
+ }
46
64
  }
47
65
  @include when(warning) {
48
66
  .oxy-corner__text {
@@ -53,6 +71,11 @@
53
71
  @include corner-type-style($-corner-warning-color, $-corner-horizontal-warning-bg);
54
72
  }
55
73
  }
74
+ &.is-embedded {
75
+ .oxy-corner__text {
76
+ @include corner-type-style($-corner-warning-color, $-corner-embedded-warning-bg);
77
+ }
78
+ }
56
79
  }
57
80
  @include when(danger) {
58
81
  .oxy-corner__text {
@@ -63,12 +86,21 @@
63
86
  @include corner-type-style($-corner-danger-color, $-corner-horizontal-danger-bg);
64
87
  }
65
88
  }
89
+ &.is-embedded {
90
+ .oxy-corner__text {
91
+ @include corner-type-style($-corner-danger-color, $-corner-embedded-danger-bg);
92
+ }
93
+ }
66
94
  }
67
95
  &:not(.is-horizontal) {
68
96
  &.is-top-left{
69
97
  top: 0;
70
98
  left: 0;
71
99
  right: auto;
100
+ &.is-round {
101
+ border-top-right-radius: 0;
102
+ border-top-left-radius: $-corner-radius;
103
+ }
72
104
  .oxy-corner__text {
73
105
  transform: rotate(-45deg);
74
106
  top: 10px;
@@ -79,6 +111,10 @@
79
111
  bottom: 0;
80
112
  left: 0;
81
113
  top: auto;
114
+ &.is-round {
115
+ border-top-right-radius: 0;
116
+ border-bottom-left-radius: $-corner-radius;
117
+ }
82
118
  .oxy-corner__text {
83
119
  transform: rotate(-135deg);
84
120
  bottom: 10px;
@@ -94,6 +130,10 @@
94
130
  bottom: 0;
95
131
  right: 0;
96
132
  top: auto;
133
+ &.is-round {
134
+ border-top-right-radius: 0;
135
+ border-bottom-right-radius: $-corner-radius;
136
+ }
97
137
  .oxy-corner__text {
98
138
  transform: rotate(135deg);
99
139
  bottom: 10px;
@@ -105,6 +145,62 @@
105
145
  }
106
146
  }
107
147
  }
148
+ &.is-embedded {
149
+ &.is-top-left{
150
+ &::after {
151
+ left: auto;
152
+ right: -6px;
153
+ bottom: 0;
154
+ transform: skewX(-30deg);
155
+ }
156
+ .oxy-corner__text {
157
+ transform: none;
158
+ top: 0;
159
+ left: 0;
160
+ border-bottom-left-radius: 0;
161
+ border-bottom-right-radius: 32px;
162
+ padding-left: 0;
163
+ padding-right: 12px;
164
+ }
165
+ }
166
+ &.is-bottom-left{
167
+ &::after {
168
+ left: auto;
169
+ right: -6px;
170
+ bottom: 0;
171
+ transform: skewX(30deg);
172
+ }
173
+ .oxy-corner__text {
174
+ transform: none;
175
+ bottom: 0;
176
+ left: 0;
177
+ border-bottom-left-radius: 0;
178
+ border-top-right-radius: 32px;
179
+ padding-left: 0;
180
+ padding-right: 12px;
181
+ > span{
182
+ transform: none;
183
+ }
184
+ }
185
+ }
186
+ &.is-bottom-right{
187
+ &::after {
188
+ left: -6px;
189
+ bottom: 0;
190
+ transform: skewX(-30deg);
191
+ }
192
+ .oxy-corner__text {
193
+ transform: none;
194
+ bottom: 0;
195
+ right: 0;
196
+ border-bottom-left-radius: 0;
197
+ border-top-left-radius: 32px;
198
+ > span{
199
+ transform: none;
200
+ }
201
+ }
202
+ }
203
+ }
108
204
  .oxy-corner__text {
109
205
  width: 106px;
110
206
  height: 32px;
@@ -134,5 +230,29 @@
134
230
  text-align: right;
135
231
  }
136
232
  }
233
+ &.is-embedded {
234
+ width: 106px;
235
+ height: 32px;
236
+ &::after {
237
+ content: '';
238
+ position: absolute;
239
+ left: -6px;
240
+ bottom: 0;
241
+ width: 16px;
242
+ height: 32px;
243
+ background-color: #ffffff;
244
+ transform: skewX(30deg);
245
+ }
246
+ .oxy-corner__text {
247
+ right: 0;
248
+ top: 0;
249
+ transform: none;
250
+ padding-left: 12px;
251
+ box-sizing: border-box;
252
+ font-size: $-corner-embedded-font-size;
253
+ font-weight: $-corner-embedded-font-weight;
254
+ border-bottom-left-radius: 32px;
255
+ }
256
+ }
137
257
  }
138
- }
258
+ }
@@ -1,8 +1,8 @@
1
1
  <template>
2
- <view class="oxy-corner">
2
+ <view :class="`oxy-corner ${customClass}`" :style="customStyle">
3
3
  <slot />
4
4
  <view v-if="text || $slots.text" :class="textClass">
5
- <view class="oxy-corner__text">
5
+ <view class="oxy-corner__text" :style="textStyle">
6
6
  <slot name="text">
7
7
  <span>{{ text }}</span>
8
8
  </slot>
@@ -22,6 +22,7 @@ export default {
22
22
  }
23
23
  </script>
24
24
  <script lang="ts" setup>
25
+ import { objToStyle } from '../common/util'
25
26
  import { computed, ref, watch } from 'vue'
26
27
  import { cornerProps } from './types'
27
28
 
@@ -30,7 +31,7 @@ const props = defineProps(cornerProps)
30
31
  const cornerClass = ref<string>('')
31
32
 
32
33
  watch(
33
- [() => () => props.position, () => props.mode],
34
+ [() => () => props.position, () => props.mode, () => props.round],
34
35
  () => {
35
36
  computeCornerClass()
36
37
  },
@@ -49,15 +50,27 @@ watch(
49
50
  )
50
51
 
51
52
  const textClass = computed(() => {
52
- return `oxy-corner__box ${props.customClass} ${cornerClass.value}`
53
+ return `oxy-corner__box ${cornerClass.value}`
54
+ })
55
+
56
+ const textStyle = computed(() => {
57
+ const textStyle: Record<string, any> = {}
58
+ if (props.color) {
59
+ textStyle['color'] = props.color
60
+ }
61
+ if (props.bgColor) {
62
+ textStyle['background'] = props.bgColor
63
+ }
64
+ return objToStyle(textStyle)
53
65
  })
54
66
 
55
67
  function computeCornerClass() {
56
- const { type, position, mode } = props
68
+ const { type, position, mode, round } = props
57
69
  let cornerClassList: string[] = []
58
70
  type && cornerClassList.push(`is-${type}`)
59
71
  position && cornerClassList.push(`is-${position}`)
60
72
  mode && cornerClassList.push(`is-${mode}`)
73
+ round && cornerClassList.push('is-round')
61
74
  cornerClass.value = cornerClassList.join(' ')
62
75
  }
63
76
  </script>
@@ -3,7 +3,7 @@ import { baseProps, makeBooleanProp, makeStringProp } from '../common/props'
3
3
 
4
4
  export type CornerType = 'primary' | 'info' | 'success' | 'warning' | 'danger'
5
5
  export type CornerPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
6
- export type CornerMode = '' | 'horizontal'
6
+ export type CornerMode = '' | 'horizontal' | 'embedded'
7
7
 
8
8
  export const cornerProps = {
9
9
  ...baseProps,
@@ -24,10 +24,17 @@ export const cornerProps = {
24
24
  */
25
25
  position: makeStringProp<CornerPosition>('top-right'),
26
26
 
27
+ /**
28
+ * 圆角类型
29
+ * 类型:boolean
30
+ * 默认值:false
31
+ */
32
+ round: makeBooleanProp(false),
33
+
27
34
  /**
28
35
  * 角标模式
29
36
  * 类型:string
30
- * 可选值:'horizontal'
37
+ * 可选值:'horizontal' / 'embedded'
31
38
  * 默认值:''
32
39
  */
33
40
  mode: makeStringProp<CornerMode>(''),
@@ -37,7 +44,21 @@ export const cornerProps = {
37
44
  * 类型:string
38
45
  * 默认值:空字符串
39
46
  */
40
- text: makeStringProp('')
47
+ text: makeStringProp(''),
48
+
49
+ /**
50
+ * 文字颜色
51
+ * 类型:string
52
+ * 默认值:空字符串
53
+ */
54
+ color: makeStringProp(''),
55
+
56
+ /**
57
+ * 背景色和边框色
58
+ * 类型:string
59
+ * 默认值:空字符串
60
+ */
61
+ bgColor: makeStringProp('')
41
62
  }
42
63
 
43
64
  export type CornerProps = ExtractPropTypes<typeof cornerProps>
@@ -0,0 +1,10 @@
1
+ @import '../common/abstracts/variable';
2
+ @import '../common/abstracts/mixin';
3
+
4
+ @include b(date-strip) {
5
+ height: $-date-strip-height;
6
+ background-color: $-date-strip-bg-color;
7
+ @include e(scroll) {
8
+ flex-direction: row;
9
+ }
10
+ }
@@ -0,0 +1,198 @@
1
+ <template>
2
+ <scroll-view
3
+ :class="`oxy-date-strip oxy-date-strip__scroll ${customClass}`"
4
+ :scroll-x="true"
5
+ :scroll-left="scrollLeft"
6
+ :show-scrollbar="false"
7
+ direction="horizontal"
8
+ :style="rootStyle"
9
+ v-if="switchMode === 'none'"
10
+ >
11
+ <oxy-date-strip-item
12
+ :dates="displayWeeks[0].dates"
13
+ :color="color"
14
+ :activeBgColor="activeBgColor"
15
+ :activeColor="activeColor"
16
+ :bgColor="bgColor"
17
+ :radius="radius"
18
+ :switchMode="switchMode"
19
+ :shape="shape"
20
+ @click="onClick"
21
+ ></oxy-date-strip-item>
22
+ </scroll-view>
23
+ <swiper
24
+ v-else
25
+ :class="`oxy-date-strip ${customClass}`"
26
+ :style="rootStyle"
27
+ :current="currentWeekIndex"
28
+ :circular="swiperCircular"
29
+ @change="swiperChange"
30
+ >
31
+ <swiper-item v-for="(week, g) in displayWeeks" :key="g">
32
+ <oxy-date-strip-item
33
+ :dates="week.dates"
34
+ :color="color"
35
+ :activeBgColor="activeBgColor"
36
+ :activeColor="activeColor"
37
+ :bgColor="bgColor"
38
+ :radius="radius"
39
+ :switchMode="switchMode"
40
+ :shape="shape"
41
+ @click="onClick"
42
+ ></oxy-date-strip-item>
43
+ </swiper-item>
44
+ </swiper>
45
+ </template>
46
+
47
+ <script lang="ts">
48
+ export default {
49
+ name: 'oxy-date-strip',
50
+ options: {
51
+ addGlobalClass: true,
52
+ virtualHost: true,
53
+ styleIsolation: 'shared'
54
+ }
55
+ }
56
+ </script>
57
+
58
+ <script lang="ts" setup>
59
+ import OxyDateStripItem from '../oxy-date-strip-item/oxy-date-strip-item.vue'
60
+ import { ref, computed, watch, onMounted, nextTick, reactive } from 'vue'
61
+ import { objToStyle, unitConvert } from '../common/util'
62
+ import { getWeekRange, addDays, addWeeks, calcType, daysBetween } from './utils'
63
+ import { dateStripProps, type WeekDateCollection, type DateStriPDay } from './types'
64
+
65
+ const props = defineProps(dateStripProps)
66
+ const emit = defineEmits(['change', 'select', 'update:modelValue', 'input'])
67
+
68
+ // 当前选中的周索引
69
+ const currentWeekIndex = ref(0)
70
+ const scrollLeft = ref(0)
71
+ // 是否循环滚动
72
+ const swiperCircular = ref(true)
73
+ const selectedDate = ref<Date | null>(null)
74
+ // 计算一周的星期顺序
75
+ const firstDayOfWeek = computed((): number => Math.min(Math.max(props.firstDayOfWeek, 0), 6))
76
+
77
+ // 计算最小和最大日期
78
+ const today = new Date()
79
+ const minDate = computed((): Date => (props.minDate !== null ? new Date(props.minDate!) : today))
80
+ const maxDate = computed((): Date => (props.maxDate !== null ? new Date(props.maxDate!) : addDays(today, 31)))
81
+
82
+ const days = computed((): number => {
83
+ return daysBetween(maxDate.value, minDate.value)
84
+ })
85
+
86
+ const rootStyle = computed(() => {
87
+ const style: Record<string, any> = {}
88
+ if (props.height) {
89
+ style['height'] = props.height
90
+ }
91
+ if (props.bgColor) {
92
+ style['background'] = props.bgColor
93
+ }
94
+ return `${objToStyle(style)}${props.customStyle}`
95
+ })
96
+
97
+ const cache = new Map<number, WeekDateCollection>()
98
+ const createWeek = (currentStartDate: Date, length: number): WeekDateCollection => {
99
+ const dates: DateStriPDay[] = []
100
+ const time = currentStartDate.getTime()
101
+ if (cache.has(time)) {
102
+ return cache.get(time)!
103
+ }
104
+ for (let i = 0; i < length; i++) {
105
+ const date = new Date(time)
106
+ date.setDate(currentStartDate.getDate() + i)
107
+ const week = date.getDay()
108
+ const year = date.getFullYear()
109
+ const month = date.getMonth() + 1
110
+ const day = date.getDate()
111
+ const dateObj = reactive<DateStriPDay>({
112
+ key: `${year}-${month}-${day}`,
113
+ date,
114
+ year,
115
+ month,
116
+ day,
117
+ text: `${day}`.padStart(2, '0'),
118
+ type: calcType(date, minDate.value, maxDate.value, selectedDate.value, props.disableDate),
119
+ prefix: props.weekdays[week]
120
+ })
121
+ dates.push(props.format !== null ? props.format!(dateObj) : dateObj)
122
+ }
123
+ const obj: WeekDateCollection = {
124
+ start: new Date(dates[0].year, dates[0].month - 1, dates[0].day).getTime(),
125
+ end: new Date(dates[length - 1].year, dates[length - 1].month - 1, dates[length - 1].day).getTime(),
126
+ dates
127
+ } as WeekDateCollection
128
+ return obj
129
+ }
130
+
131
+ const currentDate = ref<Date>(today)
132
+
133
+ // 计算要显示的三周数据
134
+ const displayWeeks = computed((): WeekDateCollection[] => {
135
+ const weeks: WeekDateCollection[] = []
136
+ if (props.switchMode === 'week') {
137
+ const currentRange = getWeekRange(currentDate.value, firstDayOfWeek.value)
138
+ const offsetMap = new Map<number, number[]>([
139
+ [0, [0, 1, -1]],
140
+ [1, [-1, 0, 1]],
141
+ [2, [1, -1, 0]]
142
+ ])
143
+ let indices = offsetMap.get(currentWeekIndex.value)!
144
+ indices.forEach((i) => {
145
+ const weekDate = addWeeks(currentRange.start, i)
146
+ weeks.push(createWeek(weekDate, 7))
147
+ })
148
+ } else {
149
+ weeks.push(createWeek(minDate.value, days.value))
150
+ }
151
+ return weeks
152
+ })
153
+
154
+ const swiperChange = (event: any) => {
155
+ const delta = event.detail.current - currentWeekIndex.value
156
+ const newDate = addWeeks(currentDate.value, delta == 1 || delta == -2 ? 1 : -1)
157
+ currentDate.value = newDate
158
+ currentWeekIndex.value = event.detail.current
159
+ }
160
+
161
+ const onClick = (day: DateStriPDay) => {
162
+ if (day.type == 'disabled') return
163
+ selectedDate.value = day.date
164
+ const v = day.date.getTime()
165
+ emit('change', v)
166
+ emit('select', v)
167
+ emit('update:modelValue', v)
168
+ }
169
+
170
+ const scrollToDate = (date: Date) => {
171
+ currentDate.value = date
172
+ if (props.switchMode !== 'none') return
173
+ scrollLeft.value = unitConvert(props.gridWidth || 50) * daysBetween(date, minDate.value)
174
+ }
175
+
176
+ watch(
177
+ () => props.modelValue,
178
+ (value) => {
179
+ if (!value) return
180
+ selectedDate.value = new Date(value)
181
+ },
182
+ { deep: true, immediate: true }
183
+ )
184
+
185
+ onMounted(() => {
186
+ nextTick(() => {
187
+ scrollToDate(currentDate.value)
188
+ })
189
+ })
190
+
191
+ defineExpose({
192
+ scrollToDate
193
+ })
194
+ </script>
195
+
196
+ <style lang="scss" scoped>
197
+ @import './index.scss';
198
+ </style>
@@ -0,0 +1,98 @@
1
+ import type { ComponentPublicInstance, ExtractPropTypes, PropType } from 'vue'
2
+
3
+ import { baseProps, makeArrayProp, makeNumberProp, makeStringProp } from '../common/props'
4
+
5
+ export type DateType = 'selected' | 'disabled' | ''
6
+ export type DisableDate = (date: Date) => boolean
7
+ export type FormatDate = (day: DateStriPDay) => DateStriPDay
8
+
9
+ export type DateStripSwitchMode = 'week' | 'none'
10
+ export type DateStripShape = 'square' | 'circle' | 'none'
11
+
12
+ /**
13
+ * 定义一个表示周范围的类
14
+ */
15
+ export type WeekRange = {
16
+ start: Date
17
+ end: Date
18
+ }
19
+
20
+ export type DateStriPDay = {
21
+ date: Date
22
+ key: string
23
+ day: number
24
+ year: number
25
+ month: number
26
+ text: string
27
+ type: DateType
28
+ prefix: string
29
+ suffix?: string
30
+ }
31
+
32
+ export type WeekDateCollection = {
33
+ start: number
34
+ end: number
35
+ dates: DateStriPDay[]
36
+ }
37
+
38
+ export const dateStripProps = {
39
+ ...baseProps,
40
+ // 当前选择的日期
41
+ modelValue: {
42
+ type: [Number, null] as PropType<number | null>,
43
+ default: null
44
+ },
45
+ // 日期行高
46
+ height: makeStringProp(''),
47
+ // 第一天从星期几开始,默认 1 = 周一
48
+ firstDayOfWeek: makeNumberProp(0),
49
+ // 日期格式,可选
50
+ format: {
51
+ type: Function as PropType<FormatDate>,
52
+ default: null
53
+ },
54
+ // 最大可选日期,不传则默认半年后
55
+ maxDate: {
56
+ type: [Number, null] as PropType<number | null>,
57
+ default: null
58
+ },
59
+ // 最小可选日期,不传则默认今天
60
+ minDate: {
61
+ type: [Number, null] as PropType<number | null>,
62
+ default: null
63
+ },
64
+ // 网格宽度
65
+ gridWidth: makeStringProp(''),
66
+ // 主题色,对底部按钮和选中日期生效
67
+ color: makeStringProp(''),
68
+ // 选中日期的背景色
69
+ activeBgColor: makeStringProp(''),
70
+ // 选中日期的文字颜色
71
+ activeColor: makeStringProp(''),
72
+ // 背景色
73
+ bgColor: makeStringProp(''),
74
+ // 圆角半径
75
+ radius: makeStringProp(''),
76
+ // 切换模式,'week' 或 'none'
77
+ switchMode: makeStringProp<DateStripSwitchMode>('week'),
78
+ // 形状,'square'、'circle' 或 'none'
79
+ shape: makeStringProp<DateStripShape>('square'),
80
+ // 星期几的名称数组
81
+ weekdays: {
82
+ ...makeArrayProp<string>(),
83
+ default: () => ['日', '一', '二', '三', '四', '五', '六']
84
+ },
85
+ // 禁用日期函数
86
+ disableDate: {
87
+ type: Function as PropType<DisableDate>,
88
+ default: null
89
+ }
90
+ }
91
+
92
+ export type DateStripProps = ExtractPropTypes<typeof dateStripProps>
93
+
94
+ export type DateStripExpose = {
95
+ scrollToDate: (date: Date) => void
96
+ }
97
+
98
+ export type DateStripInstance = ComponentPublicInstance<DateStripProps, DateStripExpose>
@@ -0,0 +1,67 @@
1
+ import type { WeekRange, DateType, DisableDate } from './types'
2
+
3
+ /**
4
+ * 获取指定日期所在周的日期范围。
5
+ * @param {Date} date - 指定日期。
6
+ * @param {number} firstDayOfWeek - 一周的第一天,0 表示周日,1 表示周一,以此类推。
7
+ * @returns {WeekRange} 返回一个包含周起始和结束日期的对象。
8
+ */
9
+
10
+ export function getWeekRange(date: Date, firstDayOfWeek: number): WeekRange {
11
+ const start = new Date(date.getTime())
12
+ const dayOffset = (date.getDay() - firstDayOfWeek + 7) % 7
13
+ start.setDate(start.getDate() - dayOffset)
14
+
15
+ const end = new Date(start.getTime())
16
+ end.setDate(end.getDate() + 6)
17
+ return { start, end } as WeekRange
18
+ }
19
+
20
+ /**
21
+ * 向指定日期添加天数。
22
+ * @param {Date} date - 基础日期。
23
+ * @param {number} days - 要添加的天数,可以是正数或负数。
24
+ * @returns {Date} 返回一个新的日期对象,该对象是基础日期加上指定天数后的结果。
25
+ */
26
+ export function addDays(date: Date, days: number): Date {
27
+ const result = new Date(date.getTime())
28
+ result.setDate(result.getDate() + days)
29
+ return result
30
+ }
31
+
32
+ export function addWeeks(date: Date, weeks: number): Date {
33
+ const result = new Date(date.getTime())
34
+ result.setDate(result.getDate() + weeks * 7)
35
+ return result
36
+ }
37
+
38
+ /**
39
+ * 判断两个日期是否表示同一天(忽略时间部分)。
40
+ *
41
+ * @param date1 - 第一个日期。
42
+ * @param date2 - 第二个日期。
43
+ * @returns 如果两个日期是同一天,返回 true;否则返回 false。
44
+ */
45
+ function isSameDay(date1: Date, date2: Date): boolean {
46
+ return date1.getFullYear() == date2.getFullYear() && date1.getMonth() == date2.getMonth() && date1.getDate() == date2.getDate()
47
+ }
48
+ export function calcType(date: Date, minDate: Date, maxDate: Date, selectedDate: Date | null, disableDate?: DisableDate): DateType {
49
+ // 检查日期是否早于 minDate 或晚于 maxDate
50
+ if (date.getTime() < minDate.getTime() || date.getTime() > maxDate.getTime()) {
51
+ return 'disabled'
52
+ }
53
+ if (disableDate && disableDate(date)) {
54
+ return 'disabled'
55
+ }
56
+ // 如果 selectedDate 不为 null,检查日期是否等于 selectedDate
57
+ if (selectedDate != null && isSameDay(date, selectedDate)) {
58
+ return 'selected'
59
+ }
60
+ return ''
61
+ }
62
+
63
+ export function daysBetween(date1: Date, date2: Date): number {
64
+ // 将两个日期转换为毫秒
65
+ const diffInMilliseconds = Math.abs(date2.getTime() - date1.getTime())
66
+ return Math.floor(diffInMilliseconds / (1000 * 3600 * 24))
67
+ }