stellar-ui-v2 1.35.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 (141) hide show
  1. package/common/css/common.scss +61 -0
  2. package/components/ste-animate/README.md +117 -0
  3. package/components/ste-animate/animate.scss +247 -0
  4. package/components/ste-animate/ste-animate.vue +200 -0
  5. package/components/ste-badge/README.md +171 -0
  6. package/components/ste-badge/ste-badge.vue +238 -0
  7. package/components/ste-barcode/README.md +36 -0
  8. package/components/ste-barcode/encode2.js +317 -0
  9. package/components/ste-barcode/ste-barcode.vue +213 -0
  10. package/components/ste-button/README.md +129 -0
  11. package/components/ste-button/ste-button.vue +345 -0
  12. package/components/ste-calendar/README.md +304 -0
  13. package/components/ste-calendar/self-date.js +119 -0
  14. package/components/ste-calendar/ste-calendar.vue +578 -0
  15. package/components/ste-checkbox/README.md +297 -0
  16. package/components/ste-checkbox/ste-checkbox.vue +305 -0
  17. package/components/ste-checkbox-group/ste-checkbox-group.vue +133 -0
  18. package/components/ste-code-input/README.md +67 -0
  19. package/components/ste-code-input/ste-code-input.vue +302 -0
  20. package/components/ste-date-picker/README.md +135 -0
  21. package/components/ste-date-picker/ste-date-picker.vue +407 -0
  22. package/components/ste-drag/README.md +103 -0
  23. package/components/ste-drag/ste-drag.vue +203 -0
  24. package/components/ste-dropdown-menu/README.md +358 -0
  25. package/components/ste-dropdown-menu/ste-dropdown-menu.vue +405 -0
  26. package/components/ste-dropdown-menu-item/ste-dropdown-menu-item.vue +176 -0
  27. package/components/ste-icon/README.md +90 -0
  28. package/components/ste-icon/iconfont.css +8 -0
  29. package/components/ste-icon/ste-icon.vue +147 -0
  30. package/components/ste-image/README.md +154 -0
  31. package/components/ste-image/ste-image.vue +218 -0
  32. package/components/ste-index-item/ste-index-item.vue +96 -0
  33. package/components/ste-index-list/README.md +153 -0
  34. package/components/ste-index-list/ste-index-list.vue +128 -0
  35. package/components/ste-input/README.md +146 -0
  36. package/components/ste-input/ste-input.vue +480 -0
  37. package/components/ste-loading/README.md +81 -0
  38. package/components/ste-loading/ste-loading.vue +166 -0
  39. package/components/ste-media-preview/README.md +243 -0
  40. package/components/ste-media-preview/TouchScaleing.js +102 -0
  41. package/components/ste-media-preview/ste-media-preview.vue +267 -0
  42. package/components/ste-message-box/README.md +217 -0
  43. package/components/ste-message-box/ste-message-box.js +72 -0
  44. package/components/ste-message-box/ste-message-box.vue +380 -0
  45. package/components/ste-notice-bar/README.md +129 -0
  46. package/components/ste-notice-bar/ste-notice-bar.vue +331 -0
  47. package/components/ste-number-keyboard/README.md +246 -0
  48. package/components/ste-number-keyboard/keyboard.vue +140 -0
  49. package/components/ste-number-keyboard/ste-number-keyboard.vue +240 -0
  50. package/components/ste-picker/ste-picker.vue +258 -0
  51. package/components/ste-popup/README.md +148 -0
  52. package/components/ste-popup/ste-popup.vue +337 -0
  53. package/components/ste-price/README.md +129 -0
  54. package/components/ste-price/ste-price.vue +258 -0
  55. package/components/ste-progress/README.md +87 -0
  56. package/components/ste-progress/ste-progress.vue +200 -0
  57. package/components/ste-qrcode/README.md +50 -0
  58. package/components/ste-qrcode/ste-qrcode.vue +164 -0
  59. package/components/ste-qrcode/uqrcode.js +34 -0
  60. package/components/ste-radio/README.md +286 -0
  61. package/components/ste-radio/ste-radio.vue +293 -0
  62. package/components/ste-radio-group/ste-radio-group.vue +128 -0
  63. package/components/ste-rate/README.md +115 -0
  64. package/components/ste-rate/ste-rate.vue +202 -0
  65. package/components/ste-read-more/README.md +111 -0
  66. package/components/ste-read-more/ste-read-more.vue +133 -0
  67. package/components/ste-rich-text/README.md +31 -0
  68. package/components/ste-rich-text/ste-rich-text.vue +70 -0
  69. package/components/ste-scroll-to/README.md +68 -0
  70. package/components/ste-scroll-to/mixin.js +173 -0
  71. package/components/ste-scroll-to/ste-scroll-to.vue +45 -0
  72. package/components/ste-scroll-to-item/ste-scroll-to-item.vue +25 -0
  73. package/components/ste-search/README.md +262 -0
  74. package/components/ste-search/ste-search.vue +547 -0
  75. package/components/ste-select/README.md +434 -0
  76. package/components/ste-select/datapager.vue +62 -0
  77. package/components/ste-select/datetime.vue +106 -0
  78. package/components/ste-select/defaultDate.js +142 -0
  79. package/components/ste-select/ste-select.vue +843 -0
  80. package/components/ste-signature/README.md +105 -0
  81. package/components/ste-signature/ste-signature.vue +220 -0
  82. package/components/ste-slider/README.md +165 -0
  83. package/components/ste-slider/ste-slider.vue +544 -0
  84. package/components/ste-step/ste-step.vue +264 -0
  85. package/components/ste-stepper/README.md +170 -0
  86. package/components/ste-stepper/ste-stepper.vue +373 -0
  87. package/components/ste-steps/README.md +132 -0
  88. package/components/ste-steps/ste-steps.vue +65 -0
  89. package/components/ste-sticky/README.md +52 -0
  90. package/components/ste-sticky/ste-sticky.vue +127 -0
  91. package/components/ste-swipe-action/README.md +197 -0
  92. package/components/ste-swipe-action/ste-swipe-action.vue +303 -0
  93. package/components/ste-swipe-action-group/ste-swipe-action-group.vue +104 -0
  94. package/components/ste-swiper/README.md +173 -0
  95. package/components/ste-swiper/ste-swiper.vue +462 -0
  96. package/components/ste-swiper-item/ste-swiper-item.vue +41 -0
  97. package/components/ste-switch/README.md +110 -0
  98. package/components/ste-switch/ste-switch.vue +144 -0
  99. package/components/ste-tab/ste-tab.vue +87 -0
  100. package/components/ste-table/README.md +785 -0
  101. package/components/ste-table/common.js +8 -0
  102. package/components/ste-table/ste-table.vue +666 -0
  103. package/components/ste-table/utils.js +20 -0
  104. package/components/ste-table-column/checkbox-icon.vue +65 -0
  105. package/components/ste-table-column/common.scss +65 -0
  106. package/components/ste-table-column/radio-icon.vue +110 -0
  107. package/components/ste-table-column/ste-table-column.vue +255 -0
  108. package/components/ste-table-column/sub-table.vue +116 -0
  109. package/components/ste-table-column/table-popover.vue +204 -0
  110. package/components/ste-table-column/var.scss +1 -0
  111. package/components/ste-tabs/README.md +475 -0
  112. package/components/ste-tabs/props.js +212 -0
  113. package/components/ste-tabs/ste-tabs.vue +758 -0
  114. package/components/ste-text/README.md +66 -0
  115. package/components/ste-text/ste-text.vue +72 -0
  116. package/components/ste-toast/README.md +243 -0
  117. package/components/ste-toast/ste-toast.js +69 -0
  118. package/components/ste-toast/ste-toast.vue +231 -0
  119. package/components/ste-touch-swipe/README.md +104 -0
  120. package/components/ste-touch-swipe/TouchEvent.js +72 -0
  121. package/components/ste-touch-swipe/ste-touch-swipe.vue +327 -0
  122. package/components/ste-touch-swipe-item/ste-touch-swipe-item.vue +33 -0
  123. package/components/ste-tour/README.md +194 -0
  124. package/components/ste-tour/ste-tour.vue +355 -0
  125. package/components/ste-tree/README.md +240 -0
  126. package/components/ste-tree/ste-tree.vue +350 -0
  127. package/components/ste-upload/README.md +276 -0
  128. package/components/ste-upload/ReadFile.js +229 -0
  129. package/components/ste-upload/ste-upload.vue +526 -0
  130. package/components/ste-video/README.md +60 -0
  131. package/components/ste-video/props.js +149 -0
  132. package/components/ste-video/ste-video.vue +647 -0
  133. package/config/color.js +22 -0
  134. package/index.js +2 -0
  135. package/package.json +19 -0
  136. package/utils/Color.js +66 -0
  137. package/utils/System.js +110 -0
  138. package/utils/dayjs.min.js +1 -0
  139. package/utils/mixin.js +67 -0
  140. package/utils/store.js +7 -0
  141. package/utils/utils.js +604 -0
@@ -0,0 +1,843 @@
1
+ <template>
2
+ <view class="ste-select-root" :class="{ open: showOptions, disabled }" :style="[cmpRootStyle]">
3
+ <view class="select-mask" @click="clickMask" @touchmove.stop="stop">
4
+ <view class="select-content" :style="[contentStyle]" @click.stop="openOptions">
5
+ <slot>
6
+ <scroll-view scroll-x class="content-text" :class="{ multiple: cmpMultiple }">
7
+ <block v-if="cmpFilterable">
8
+ <block v-if="cmpMultiple">
9
+ <block v-for="(v, i) in cmpViewValue">
10
+ <view class="view-item" :key="v" v-if="v">
11
+ {{ v }}
12
+ </view>
13
+ </block>
14
+ </block>
15
+ <input
16
+ v-model="inputView"
17
+ class="filterable-input"
18
+ placeholder-class="placeholder-text"
19
+ :class="{ content: cmpMultiple && cmpViewValue.length }"
20
+ :disabled="disabled"
21
+ :placeholder="inputPlaceholder"
22
+ @input="onUserFilterable"
23
+ />
24
+ </block>
25
+ <block v-else>
26
+ <block v-if="confirmValue && confirmValue.length">
27
+ <block v-if="cmpMultiple">
28
+ <block v-for="(v, i) in cmpViewValue">
29
+ <view class="view-item" :key="v" v-if="v">
30
+ {{ v }}
31
+ </view>
32
+ </block>
33
+ </block>
34
+ <text v-else>{{ cmpViewValue }}</text>
35
+ </block>
36
+ <view class="placeholder-text" v-else>{{ placeholder }}</view>
37
+ </block>
38
+ </scroll-view>
39
+ </slot>
40
+ <view class="open-icon-event" @click.stop="clickOpenIcon">
41
+ <view class="open-icon">
42
+ <slot name="icon">
43
+ <view class="open-icon-transform">
44
+ <ste-icon code="&#xe676;" size="20" />
45
+ </view>
46
+ </slot>
47
+ </view>
48
+ </view>
49
+ <view class="clearable-icon" v-if="cmpShowClearable" @click.stop="clickClearable">
50
+ <ste-icon code="&#xe694;" color="#bbbbbb" size="34" />
51
+ </view>
52
+ </view>
53
+
54
+ <view class="options-content" :style="[optionsStyle]" @click.stop="stop">
55
+ <view class="select-options">
56
+ <DateTime
57
+ v-if="cmpShowDate"
58
+ v-model="selected"
59
+ :mode="mode"
60
+ :minDate="minDate"
61
+ :maxDate="maxDate"
62
+ :dateUnit="dateUnit"
63
+ />
64
+ <block v-else-if="dataOptions.length > 1">
65
+ <picker-view
66
+ style="height: 450rpx"
67
+ indicator-style="height: 43px"
68
+ :value="cmpMultiseriateValue"
69
+ @change="onMultiseriateChange"
70
+ >
71
+ <picker-view-column v-for="(col, index) in viewOptions" :key="index">
72
+ <view class="time-item" style="height: 43px" v-for="(item, i) in col" :key="item">
73
+ {{ item[labelKey] }}
74
+ </view>
75
+ </picker-view-column>
76
+ </picker-view>
77
+ </block>
78
+
79
+ <block v-else>
80
+ <view class="one-col-options">
81
+ <view class="options-col" v-for="(col, index) in viewOptions" :key="index">
82
+ <DatapagerVue :rootStyle="{ maxHeight: '450rpx' }" @loadMore="loadMore">
83
+ <view
84
+ class="options-item"
85
+ v-if="dataAllowCreate"
86
+ @click="onSelect(index, dataAllowCreate, true)"
87
+ >
88
+ {{ dataAllowCreate[labelKey] }}
89
+ </view>
90
+ <view
91
+ class="options-item"
92
+ v-for="(item, i) in col"
93
+ :key="item[valueKey]"
94
+ :class="{ active: active(index, item) }"
95
+ @click="onSelect(index, item)"
96
+ >
97
+ {{ item[labelKey] }}
98
+ </view>
99
+ <block v-if="!dataAllowCreate && !col.length">
100
+ <view class="options-empty">暂无数据</view>
101
+ </block>
102
+ </DatapagerVue>
103
+ </view>
104
+ </view>
105
+ </block>
106
+ </view>
107
+ <view class="options-btns" v-if="cmpShowDate || dataOptions.length > 1">
108
+ <view class="options-cancel" @click="clickCancel">取消</view>
109
+ <view class="options-confirm" @click="clickConfirm">确定</view>
110
+ </view>
111
+
112
+ <view class="loading-mark" v-if="loading">
113
+ <view class="loading-icon">
114
+ <slot name="loading-icon">
115
+ <view class="loading-icon-transform">
116
+ <ste-icon code="&#xe6a2;" size="60" color="#555"></ste-icon>
117
+ </view>
118
+ </slot>
119
+ </view>
120
+ </view>
121
+ </view>
122
+ </view>
123
+ </view>
124
+ </template>
125
+
126
+ <script>
127
+ import utils from '../../utils/utils';
128
+ import useColor from '../../config/color.js';
129
+ let color = useColor();
130
+ import { formatDate, getFormatStr } from './defaultDate';
131
+ import DateTime from './datetime.vue';
132
+ import DatapagerVue from './datapager.vue';
133
+
134
+ const isData = (d) => {
135
+ return d || d === 0 || d === '';
136
+ };
137
+ /**
138
+ * ste-select 下拉选
139
+ * @description 下拉选组件
140
+ * @tutorial https://stellar-ui.intecloud.com.cn/pc/index/index?name=ste-select
141
+ * @property {String} value 绑定的值,支持v-model双向绑定
142
+ * @property {Array} list 数据列表,支持一维数组,二维数组,树形结构
143
+ * @property {String} mode 选择模式
144
+ * @value default 默认
145
+ * @value filterable 可搜索(仅单列模式下生效)
146
+ * @value tree 当list为树形结构时生效
147
+ * @value date 时间选择器模式:日期选择(该模式下list属性不生效)
148
+ * @value time 时间选择器模式:时间选择(该模式下list属性不生效)
149
+ * @value datetime 时间选择器模式:日期时间选择(该模式下list属性不生效)
150
+ * @value month 时间选择器模式:年月选择器(该模式下list属性不生效)
151
+ * @value minute 时间选择器模式:时分选择器(该模式下list属性不生效)
152
+ * @property {String} minDate 最小日期(仅在时间选择器模式下生效)
153
+ * @property {String} maxDate 最大日期(仅在时间选择器模式下生效)
154
+ * @property {Boolean} dateUnit 是否显示中文单位(仅在时间选择器模式下生效)
155
+ * @property {String|Number} width 宽度,默认100%
156
+ * @property {String|Number} height 高度(不可使用相对值例如百分比等)单位RPX,默认64
157
+ * @property {String|Number} fontSize 字体大小,单位RPX,默认28
158
+ * @property {String} background 背景颜色,默认#fff
159
+ * @property {Boolean} maskClose 点击遮罩层是否关闭,默认true
160
+ * @property {String|Number} optionsWidth 选项框宽度,默认auto同width
161
+ * @property {String} placeholder 占位符
162
+ * @property {String} labelKey 数据列表中显示的键名,默认label
163
+ * @property {String} valueKey 数据列表中存储的键名,默认value
164
+ * @property {String} childrenKey 数据列表中子列表的键名,默认children(mode为tree时生效)
165
+ * @property {Boolean} multiple 是否多选,默认false,一维数组时生效
166
+ * @property {Boolean} allowCreate 是否允许创建,默认false
167
+ * @property {Boolean} autoFilterable 是否自动过滤条目,默认true
168
+ * @property {Boolean} loading 加载中状态,默认false
169
+ * @property {Number} total 数据总数
170
+ * @property {String} borderColor 边框颜色,若不要边框可设置为透明色
171
+ * @property {Number|String} borderRadius 圆角大小,单位RPX,默认8
172
+ * @property {String} optionsPosition 选项框位置
173
+ * @value auto 自动展示位置,默认
174
+ * @value bottom 在下方展示,左右自适应
175
+ * @value bottom-auto 在下方展示,左右自适应
176
+ * @value top 在上方展示,左右自适应
177
+ * @value top-auto 在上方展示,左右自适应
178
+ * @value auto-start 上下自适应,左侧对其
179
+ * @value auto-end 上下自适应,右侧对其
180
+ * @value bottom-start 下方展示,左侧对其
181
+ * @value top-start 上方展示,左侧对其
182
+ * @value bottom-end 下方展示,右侧对其
183
+ * @value top-end 上方展示,右侧对其
184
+ * @property {Boolean} disabled 禁用
185
+ * @property {Boolean} clearable 是否可清空内容
186
+ * @event {Function} change 选中值变化时触发
187
+ * @event {Function} cancel 取消选择时触发
188
+ * @event {Function} confirm 确定选择时触发
189
+ * @event {Function} inputFilterable 搜索输入内容触发
190
+ * @event {Function} loadMore 上拉触底触发
191
+ * @example <ste-select :list="list" v-model="value" @change="change" />
192
+ */
193
+ export default {
194
+ group: '表单组件',
195
+ title: 'Select 下拉选',
196
+ name: 'ste-select',
197
+ components: { DateTime, DatapagerVue },
198
+ props: {
199
+ value: { type: [Array, String, Number, null], default: () => [] },
200
+ list: { type: [Array, null], default: () => [] },
201
+ mode: { type: [String, null], default: () => 'default' },
202
+ minDate: { type: [Number, String, Date, null], default: () => null },
203
+ maxDate: { type: [Number, String, Date, null], default: () => null },
204
+ dateUnit: { type: [Boolean, null], default: () => true },
205
+ width: { type: [Number, String, null], default: () => '100%' },
206
+ height: { type: [Number, String, null], default: () => 64 },
207
+ fontSize: { type: [Number, String, null], default: () => 28 },
208
+ background: { type: [String, null], default: () => '#fff' },
209
+ maskClose: { type: [Boolean, null], default: () => true },
210
+ optionsWidth: { type: [Number, String, null], default: () => 'auto' },
211
+ placeholder: { type: [String, null], default: () => '请选择' },
212
+ labelKey: { type: [String, null], default: () => 'label' },
213
+ valueKey: { type: [String, null], default: () => 'value' },
214
+ childrenKey: { type: [String, null], default: () => 'children' },
215
+ multiple: { type: [Boolean, null], default: () => false },
216
+ allowCreate: { type: [Boolean, null], default: () => false },
217
+ autoFilterable: { type: [Boolean, null], default: () => true },
218
+ loading: { type: [Boolean, null], default: () => false },
219
+ borderColor: { type: [String, null], default: () => '#ebebeb' },
220
+ borderRadius: { type: [Number, String, null], default: () => 8 },
221
+ optionsPosition: { type: [String, null], default: () => 'auto' },
222
+ disabled: { type: [Boolean, null], default: () => false },
223
+ total: { type: [Number, null], default: () => 0 },
224
+ clearable: { type: [Boolean, null], default: () => false },
225
+ },
226
+ data() {
227
+ return {
228
+ inputView: '', // 输入框显示的内容
229
+ userFilterable: '', // 用户输入的筛选内容(仅筛选模式下生效)
230
+ inputPlaceholder: '',
231
+ filterableTime: null, // 防抖定时器
232
+ dataAllowCreate: null,
233
+ selected: [], // 当前选中的值
234
+ confirmValue: [], // 确定按钮的值,用于多选模式下保存选中的值,用于单选模式下保存选中的值(仅单列时生效)
235
+ showOptions: false, // 是否显示下拉选项
236
+ contentStyle: {},
237
+ optionsStyle: {}, // 选项框样式,用于控制选项框的宽度和高度等属性
238
+ dataOptions: [], // 数据列表,用于存储用户传入的列表数据(仅筛选模式下生效)
239
+ viewOptions: [],
240
+ };
241
+ },
242
+ computed: {
243
+ cmpInputPlaceholder() {
244
+ return this.confirmValue.length ? '' : this.placeholder;
245
+ },
246
+ // 是否是日期模式(包括日期、时间、日期时间、月份)
247
+ cmpShowDate() {
248
+ return ['date', 'datetime', 'time', 'month', 'minute'].includes(this.mode);
249
+ },
250
+ // 是否是筛选模式(包括筛选、筛选多列)
251
+ cmpFilterable() {
252
+ return this.mode === 'filterable' && this.dataOptions.length <= 1;
253
+ },
254
+ cmpAutoFilterable() {
255
+ return this.cmpFilterable && this.autoFilterable;
256
+ },
257
+ // 是否是多选模式(多列或者单列多选)
258
+ cmpMultiple() {
259
+ return !this.cmpShowDate && (this.dataOptions.length > 1 || this.multiple);
260
+ },
261
+ cmpAllowCreate() {
262
+ return this.allowCreate && this.cmpFilterable;
263
+ },
264
+ cmpRootStyle() {
265
+ return {
266
+ '--ste-select-font-size': utils.formatPx(this.fontSize),
267
+ '--ste-select-width': utils.formatPx(this.width),
268
+ '--ste-select-height': utils.formatPx(this.height),
269
+ '--ste-select-line-height': utils.formatPx(this.height, 'num') - 2 + 'px',
270
+ '--ste-select-multiple-placeholder-height': utils.formatPx(this.height, 'num') - 6 + 'px',
271
+ '--ste-select-multiple-line-height': utils.formatPx(this.height, 'num') - 8 + 'px',
272
+ '--ste-select-background': this.background,
273
+ '--ste-select-border': `1px solid ${this.borderColor}`,
274
+ '--ste-select-border-radius': utils.formatPx(this.borderRadius),
275
+ '--ste-theme-color': color.getColor().steThemeColor,
276
+ };
277
+ },
278
+
279
+ cmpMultiseriateValue() {
280
+ if (this.cmpShowDate) {
281
+ return [];
282
+ }
283
+ const value = [...this.selected];
284
+ return this.dataOptions.map((item, i) => {
285
+ const index = item.findIndex((v) => v[this.valueKey] === value[i]);
286
+ return index !== -1 ? index : 0;
287
+ });
288
+ },
289
+ cmpViewValue() {
290
+ if (this.cmpShowDate) {
291
+ let values = this.confirmValue;
292
+ const v = formatDate(values, this.mode);
293
+ return v ? v.format(getFormatStr(this.mode)) : '';
294
+ }
295
+
296
+ let view = [];
297
+ this.confirmValue.forEach((value, index) => {
298
+ let item = null;
299
+ if (this.mode === 'tree') {
300
+ item = utils.findTreeNode(this.list, value, this.valueKey, this.childrenKey);
301
+ } else if (this.multiple && this.dataOptions.length === 1) {
302
+ item = this.dataOptions[0]?.find((item) => item[this.valueKey] === value);
303
+ } else {
304
+ item = this.dataOptions[index]?.find((item) => item[this.valueKey] === value);
305
+ }
306
+ view.push(item?.[this.labelKey] || '');
307
+ });
308
+ return !this.cmpMultiple && view[0] ? view[0] : view;
309
+ },
310
+ cmpShowClearable() {
311
+ return this.clearable && this.confirmValue.length;
312
+ },
313
+ },
314
+ watch: {
315
+ list: {
316
+ handler(v) {
317
+ // 监听list变化,重新初始化数据。
318
+ this.initOptions();
319
+ },
320
+ immediate: true,
321
+ },
322
+ value: {
323
+ handler(v) {
324
+ if (Array.isArray(v)) {
325
+ this.confirmValue = v;
326
+ } else if (this.cmpShowDate) {
327
+ const str = ['date', 'datetime', 'month'].includes(this.mode) ? 'YYYY MM DD HH mm ss' : 'HH mm ss';
328
+ const value = v ? utils.dayjs(v).format('YYYY MM DD HH mm ss').split(' ') : [];
329
+ this.confirmValue = value.map((item) => Number(item));
330
+ } else {
331
+ if (this.dataOptions.length > 1 || this.multiple) {
332
+ console.error('ste-select: value必须为数组(单列单选模式value可以为string或number类型)');
333
+ }
334
+ this.confirmValue = isData(v) ? [v] : [];
335
+ }
336
+ this.selected = [...this.confirmValue];
337
+ },
338
+ immediate: true,
339
+ },
340
+ userFilterable() {
341
+ this.getViewOptions();
342
+ },
343
+ confirmValue: {
344
+ handler(v) {
345
+ this.onBlur();
346
+ },
347
+ immediate: true,
348
+ },
349
+ },
350
+ created() {},
351
+ methods: {
352
+ stop: () => {},
353
+ initOptions() {
354
+ if (this.cmpShowDate) {
355
+ return;
356
+ }
357
+ if (this.mode === 'tree') {
358
+ this.initTreeOptions();
359
+ return;
360
+ }
361
+
362
+ let list = this.list;
363
+ if (!list || !list.length) list = [[]];
364
+ if (list[0] && !Array.isArray(list[0])) {
365
+ list = [list];
366
+ }
367
+ this.dataOptions = list;
368
+ this.getViewOptions();
369
+ },
370
+ initTreeOptions() {
371
+ const options = utils.treeToTable(this.list, this.selected, this.valueKey, this.childrenKey);
372
+ this.dataOptions = options;
373
+ this.getViewOptions();
374
+ },
375
+ getViewOptions() {
376
+ this.$nextTick(() => {
377
+ let list = this.dataOptions;
378
+ if (this.cmpAutoFilterable && this.userFilterable) {
379
+ // 处理筛选数据
380
+ list = list.map((item) =>
381
+ item.filter((value) => value[this.labelKey].includes(this.userFilterable))
382
+ );
383
+ }
384
+ this.viewOptions = list;
385
+ });
386
+ },
387
+ initSelected(values) {
388
+ const result = [];
389
+ this.dataOptions.forEach((item, i) => {
390
+ const v = isData(values[i]) ? values[i] : item[0][this.valueKey];
391
+ result.push(v);
392
+ });
393
+ return result;
394
+ },
395
+
396
+ clickOpenIcon() {
397
+ if (this.showOptions) {
398
+ this.onCancel();
399
+ } else {
400
+ this.openOptions();
401
+ }
402
+ },
403
+ async openOptions() {
404
+ if (this.disabled) return;
405
+ if (this.selected.length < this.dataOptions.length) {
406
+ let selected = [];
407
+ if (this.dataOptions.length > 1) {
408
+ selected = this.initSelected(this.selected);
409
+ }
410
+ this.selected = selected;
411
+ }
412
+ const el = await utils.querySelector('.ste-select-root', this);
413
+ const { width, height, top, left, bottom, right } = el;
414
+ this.contentStyle = {
415
+ position: 'absolute',
416
+ left: `${left}px`,
417
+ top: `${top}px`,
418
+ width: `${width}px`,
419
+ height: `${height}px`,
420
+ };
421
+
422
+ const boundary = utils.System.getElementBoundary(el);
423
+ let [y = 'auto', x = 'auto'] = this.optionsPosition === 'auto' ? [] : this.optionsPosition.split('-');
424
+
425
+ if (y === 'auto') {
426
+ y = 'bottom';
427
+ if (boundary.top - boundary.bottom > 0) {
428
+ y = 'top';
429
+ }
430
+ }
431
+
432
+ if (x === 'auto') {
433
+ x = 'start';
434
+ if (boundary.right - boundary.left < 0) {
435
+ x = 'end';
436
+ }
437
+ }
438
+
439
+ const style = {
440
+ position: 'absolute',
441
+ display: 'block',
442
+ width: this.optionsWidth === 'auto' ? `${width}px` : utils.formatPx(this.optionsWidth),
443
+ };
444
+ switch (y) {
445
+ case 'top':
446
+ style.bottom = `${boundary.bottom + height + 8}px`;
447
+ break;
448
+ case 'bottom':
449
+ style.top = `${bottom + 8}px`;
450
+ break;
451
+ }
452
+
453
+ switch (x) {
454
+ case 'start':
455
+ style.left = `${left}px`;
456
+ break;
457
+ case 'end':
458
+ style.right = `${boundary.right}px`;
459
+ break;
460
+ }
461
+ this.optionsStyle = style;
462
+ this.onFocus();
463
+ this.showOptions = true; // 打开选项列表
464
+ },
465
+ clickMask() {
466
+ if (!this.maskClose) return;
467
+ this.clickCancel(); // 关闭选项列表。
468
+ },
469
+ clickCancel() {
470
+ this.onCancel();
471
+ this.$emit('cancel'); // 触发cancel事件。
472
+ },
473
+ clickConfirm() {
474
+ const value = this.onConfirm();
475
+ this.$emit('confirm', value);
476
+ this.$nextTick(() => this.onCancel());
477
+ },
478
+ onCancel() {
479
+ this.showOptions = false; // 关闭选项列表
480
+ this.contentStyle = {};
481
+ this.optionsStyle = {};
482
+ this.onBlur();
483
+ },
484
+ onConfirm() {
485
+ this.confirmValue = [...this.selected];
486
+ let value = this.confirmValue;
487
+
488
+ let objs = [];
489
+ if (this.dataOptions.length === 1) {
490
+ objs = this.dataOptions[0].filter((value) => this.confirmValue.includes(value[this.valueKey]));
491
+ } else {
492
+ objs = this.dataOptions.map((item, index) => {
493
+ return item.find((value) => value[this.valueKey] === this.confirmValue[index]);
494
+ });
495
+ }
496
+
497
+ if (this.cmpShowDate && !Array.isArray(this.value)) {
498
+ value = formatDate(this.confirmValue, this.mode).format(getFormatStr(this.mode));
499
+ } else if (!this.cmpMultiple && !Array.isArray(this.value)) {
500
+ value = this.confirmValue[0];
501
+ objs = objs[0];
502
+ }
503
+
504
+ this.$emit('input', value);
505
+ this.$emit('change', value, objs);
506
+ return value;
507
+ },
508
+ onSelect(col, item, isAllowCreate) {
509
+ if (this.multiple && this.dataOptions.length === 1) {
510
+ // 只有一列选项的时候,多选
511
+ const index = this.selected.findIndex((value) => value === item[this.valueKey]);
512
+ if (index > -1) this.selected.splice(index, 1);
513
+ else this.selected.push(item[this.valueKey]);
514
+ } else {
515
+ const selected = [...this.selected];
516
+ selected[col] = item[this.valueKey];
517
+ this.selected = selected;
518
+ }
519
+ if (this.cmpAllowCreate && isAllowCreate) {
520
+ this.dataOptions[0].unshift(this.dataAllowCreate);
521
+ this.dataAllowCreate = null;
522
+ this.getViewOptions();
523
+ }
524
+ this.onConfirm();
525
+ if (!this.multiple) this.$nextTick(() => this.onCancel());
526
+ },
527
+ active(index, item) {
528
+ if (this.dataOptions.length > 1) {
529
+ return this.selected[index] === item[this.valueKey];
530
+ } else {
531
+ return this.selected.includes(item[this.valueKey]);
532
+ }
533
+ },
534
+ onMultiseriateChange({ detail: { value } }) {
535
+ const result = [];
536
+ value.forEach((i, index) => {
537
+ const value = this.dataOptions[index][i];
538
+ result.push(value[this.valueKey]);
539
+ });
540
+ this.selected = result;
541
+
542
+ if (this.mode === 'tree') {
543
+ this.initTreeOptions();
544
+ this.$nextTick(() => {
545
+ this.selected = this.cmpMultiseriateValue.map((i, index) => {
546
+ const item = this.dataOptions[index][i];
547
+ return item ? item[this.valueKey] : null;
548
+ });
549
+ });
550
+ }
551
+ },
552
+ onUserFilterable(e) {
553
+ const value = this.inputView;
554
+ clearTimeout(this.filterableTime);
555
+ this.filterableTime = setTimeout(() => {
556
+ this.userFilterable = value;
557
+ if (e) this.$emit('inputFilterable', value);
558
+ if (this.cmpAllowCreate && value) {
559
+ this.dataAllowCreate = {
560
+ [this.valueKey]: value,
561
+ [this.labelKey]: value,
562
+ };
563
+ } else {
564
+ this.dataAllowCreate = null;
565
+ }
566
+ });
567
+ },
568
+ onFocus() {
569
+ if (!this.cmpAutoFilterable) return;
570
+ this.inputView = '';
571
+ const v = this.confirmValue;
572
+ let value = this.dataOptions[0]?.find((item) => item[this.valueKey] === v[0]);
573
+ this.inputPlaceholder = value && value[this.labelKey] ? value[this.labelKey] : this.cmpInputPlaceholder;
574
+ this.onUserFilterable();
575
+ },
576
+ onBlur() {
577
+ this.inputPlaceholder = this.cmpInputPlaceholder;
578
+ if (!this.cmpFilterable) return;
579
+ this.$nextTick(() => {
580
+ const v = this.confirmValue;
581
+ // 单选时将confirmValue赋值给输入框。
582
+ if (!this.cmpMultiple && isData(v[0])) {
583
+ let value = this.dataOptions[0]?.find((item) => item[this.valueKey] === v[0]);
584
+ this.inputView = value && value[this.labelKey] ? value[this.labelKey] : '';
585
+ this.onUserFilterable();
586
+ }
587
+ });
588
+ },
589
+ loadMore() {
590
+ if (this.total < 1 || this.list.length >= this.total) return;
591
+ this.$emit('loadMore');
592
+ },
593
+ clickClearable() {
594
+ this.confirmValue = [];
595
+ this.inputView = '';
596
+ this.selected = [];
597
+ this.onConfirm();
598
+ },
599
+ },
600
+ };
601
+ </script>
602
+
603
+ <style lang="scss" scoped>
604
+ .ste-select-root {
605
+ width: var(--ste-select-width);
606
+ height: var(--ste-select-height);
607
+ position: relative;
608
+ &.disabled .select-content {
609
+ background-color: #eee;
610
+ }
611
+ &.open {
612
+ .select-mask {
613
+ position: fixed;
614
+ width: 100vw;
615
+ height: 100vh;
616
+ top: 0;
617
+ left: 0;
618
+ background-color: rgba(0, 0, 0, 0.5);
619
+ z-index: 996;
620
+ .select-content {
621
+ .open-icon-event > .open-icon {
622
+ transform: rotate(180deg);
623
+ }
624
+ }
625
+ }
626
+ }
627
+ .select-mask {
628
+ width: var(--ste-select-width);
629
+ height: var(--ste-select-height);
630
+ }
631
+ .select-content {
632
+ width: var(--ste-select-width);
633
+ height: var(--ste-select-height);
634
+ line-height: var(--ste-select-line-height);
635
+ background-color: var(--ste-select-background);
636
+ border: var(--ste-select-border);
637
+ border-radius: var(--ste-select-border-radius);
638
+ padding-right: var(--ste-select-multiple-line-height);
639
+ position: relative;
640
+ z-index: 1;
641
+ padding-left: 20rpx; // 调整内边距,以适应不同的选项高度。
642
+ overflow: hidden;
643
+ .content-text {
644
+ width: 100%;
645
+ height: 100%;
646
+ white-space: nowrap;
647
+ font-size: var(--ste-select-font-size);
648
+ &.multiple {
649
+ padding: 2px 0;
650
+ .view-item {
651
+ max-width: 100%;
652
+ line-height: var(--ste-select-multiple-line-height);
653
+ display: inline-block;
654
+ padding: 0 12rpx;
655
+ border-radius: 6rpx;
656
+ border: 1px solid #eee;
657
+ margin-right: 8px;
658
+ font-size: 24rpx; // 设置字体大小
659
+ text-overflow: ellipsis;
660
+ white-space: nowrap; // 文本不换行,防止文字溢出
661
+ overflow: hidden; // 隐藏溢出内容,并显示省略号
662
+ }
663
+ .filterable-input {
664
+ height: var(--ste-select-multiple-placeholder-height);
665
+ display: inline-block;
666
+ &.content {
667
+ width: 50%;
668
+ }
669
+ }
670
+ .placeholder-text {
671
+ line-height: var(--ste-select-multiple-placeholder-height);
672
+ }
673
+ }
674
+ }
675
+ .filterable-input {
676
+ width: 100%;
677
+ height: 100%;
678
+ font-size: var(--ste-select-font-size);
679
+ }
680
+ .placeholder-text {
681
+ color: #999999;
682
+ font-size: var(--ste-select-font-size);
683
+ }
684
+ .open-icon-event {
685
+ width: var(--ste-select-multiple-line-height);
686
+ height: var(--ste-select-multiple-line-height);
687
+ position: absolute;
688
+ display: flex;
689
+ z-index: 100;
690
+ align-items: center;
691
+ justify-content: center;
692
+ right: 0;
693
+ top: 50%;
694
+ transform: translateY(-50%);
695
+ .open-icon {
696
+ width: 32rpx;
697
+ height: 32rpx;
698
+ display: flex;
699
+ align-items: center;
700
+ justify-content: center;
701
+ transition: 300ms;
702
+ .open-icon-transform {
703
+ width: 100%;
704
+ height: 100%;
705
+ background-color: #ebebeb; // 设置一个背景颜色,以便在开发过程中能够看到这个元素。
706
+ border-radius: 16rpx;
707
+ display: flex;
708
+ align-items: center;
709
+ justify-content: center;
710
+ transform: translateY(2rpx);
711
+ }
712
+ }
713
+ }
714
+
715
+ .clearable-icon {
716
+ width: 60rpx;
717
+ height: 100%;
718
+ display: flex;
719
+ align-items: center;
720
+ justify-content: center;
721
+ position: absolute;
722
+ right: 48rpx;
723
+ top: 50%;
724
+ z-index: 10;
725
+ transform: translateY(-50%);
726
+ }
727
+ }
728
+ .options-content {
729
+ display: none;
730
+ position: absolute;
731
+ z-index: 2;
732
+ border-radius: 8rpx;
733
+ background-color: #fff;
734
+ overflow: hidden;
735
+ .select-options {
736
+ width: 100%;
737
+ max-height: 546rpx;
738
+ .one-col-options {
739
+ padding: 20rpx 0;
740
+ }
741
+ .options-col {
742
+ padding: 0 16rpx;
743
+ height: 100%;
744
+ max-height: 450rpx;
745
+ .options-item {
746
+ width: 100%;
747
+ line-height: 42rpx;
748
+ padding: 20rpx 0;
749
+ font-size: var(--ste-select-font-size);
750
+ // 文本溢出省略号
751
+ text-overflow: ellipsis;
752
+ white-space: nowrap; // 文本不换行,防止文字溢出
753
+ overflow: hidden; // 隐藏溢出内容,并显示省略号
754
+
755
+ &.active {
756
+ color: var(--ste-theme-color);
757
+ }
758
+
759
+ & + .options-item {
760
+ border-top: 1px solid #f5f5f5;
761
+ }
762
+
763
+ &:nth-child(1) {
764
+ padding-top: 0;
765
+ }
766
+ &:nth-last-child(1) {
767
+ padding-bottom: 0;
768
+ }
769
+ }
770
+ .options-empty {
771
+ width: 100%;
772
+ height: 82rpx;
773
+ line-height: 82rpx;
774
+ text-align: center;
775
+ color: #999999;
776
+ }
777
+ }
778
+ .time-item {
779
+ width: 100%;
780
+ height: 100%;
781
+ display: flex;
782
+ align-items: center;
783
+ justify-content: center;
784
+ font-size: var(--ste-select-font-size);
785
+ }
786
+ }
787
+ .options-btns {
788
+ width: 100%;
789
+ height: 96rpx;
790
+ line-height: 96rpx;
791
+ display: flex;
792
+ align-items: center;
793
+ justify-content: space-between;
794
+ font-size: var(--ste-select-font-size);
795
+ .options-cancel {
796
+ color: #999999;
797
+ padding: 0 40rpx;
798
+ }
799
+ .options-confirm {
800
+ color: #0090ff;
801
+ padding: 0 40rpx;
802
+ }
803
+ }
804
+
805
+ .loading-mark {
806
+ position: absolute;
807
+ z-index: 100;
808
+ width: 100%;
809
+ height: 100%;
810
+ top: 0;
811
+ left: 0;
812
+ background-color: rgba(255, 255, 255, 0.8);
813
+ display: flex;
814
+ align-items: center;
815
+ justify-content: center;
816
+ .loading-icon {
817
+ width: 60rpx;
818
+ height: 60rpx;
819
+ display: flex;
820
+ align-items: center;
821
+ justify-content: center;
822
+ .loading-icon-transform {
823
+ width: 100%;
824
+ height: 100%;
825
+ border-radius: 16rpx;
826
+ display: flex;
827
+ align-items: center;
828
+ justify-content: center;
829
+ animation: loading 1s infinite linear;
830
+ @keyframes loading {
831
+ from {
832
+ transform: rotate(0deg);
833
+ }
834
+ to {
835
+ transform: rotate(360deg);
836
+ }
837
+ }
838
+ }
839
+ }
840
+ }
841
+ }
842
+ }
843
+ </style>