Skip to content

Commit 7fee047

Browse files
authored
feat:多端基础下拉以及下拉表格开发 (#3871)
1 parent 6746608 commit 7fee047

File tree

18 files changed

+1204
-97
lines changed

18 files changed

+1204
-97
lines changed

packages/design/aurora/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import Pager from './src/pager'
2727
import Wizard from './src/wizard'
2828
import DialogBox from './src/dialog-box'
2929
import Popeditor from './src/popeditor'
30+
import BaseSelect from './src/base-select'
3031
import { version } from './package.json'
3132

3233
export default {
@@ -61,6 +62,7 @@ export default {
6162
Pager,
6263
Wizard,
6364
DialogBox,
64-
Popeditor
65+
Popeditor,
66+
BaseSelect
6567
}
6668
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { iconChevronDown } from '@opentiny/vue-icon'
2+
3+
export default {
4+
// 虚拟滚动的默认options不一致
5+
baseOpts: { optionHeight: 34, limit: 20 },
6+
icons: {
7+
dropdownIcon: iconChevronDown()
8+
},
9+
state: {
10+
sizeMap: {
11+
default: 30,
12+
mini: 24,
13+
small: 36,
14+
medium: 42
15+
},
16+
spacingHeight: 2,
17+
initialInputHeight: 30,
18+
// 显示清除等图标时,不隐藏下拉箭头时
19+
autoHideDownIcon: false,
20+
delayBlur: true
21+
},
22+
props: {
23+
tagType: 'info',
24+
stopPropagation: true
25+
},
26+
renderless: (props, hooks, { emit }, api) => {
27+
const state = api.state
28+
29+
return {
30+
// 兼容不同主题输入框尺寸对应标签尺寸不一致
31+
computedCollapseTagSize: () => {
32+
let size = 'small'
33+
34+
if (~['small', 'mini'].indexOf(state.selectSize)) {
35+
size = state.selectSize
36+
} else if (~['medium', 'default'].indexOf(state.selectSize)) {
37+
size = 'small'
38+
}
39+
40+
return size
41+
},
42+
// 兼容显示清除图标时,是否同时显示下拉图标
43+
computedShowDropdownIcon: () => {
44+
return !(props.remote && props.filterable && !props.remoteConfig.showIcon)
45+
},
46+
47+
// aui 的勾选未处理disabled的选项,故此放这里。
48+
toggleCheckAll: (filtered) => {
49+
const getEnabledValues = (options) => {
50+
let values = []
51+
52+
for (let i = 0; i < options.length; i++) {
53+
if (!options[i].state.disabled && !options[i].state.groupDisabled && options[i].state.visible) {
54+
values.push(options[i].value)
55+
}
56+
}
57+
58+
return values
59+
}
60+
61+
let value
62+
const enabledValues = getEnabledValues(state.options)
63+
64+
if (filtered) {
65+
if (state.filteredSelectCls === 'check' || state.filteredSelectCls === 'halfselect') {
66+
value = Array.from(new Set([...state.modelValue, ...enabledValues]))
67+
} else {
68+
value = state.modelValue.filter((val) => !enabledValues.includes(val))
69+
}
70+
} else {
71+
if (state.selectCls === 'check') {
72+
value = enabledValues
73+
} else if (state.selectCls === 'halfselect') {
74+
const unchecked = state.options.filter((item) => !item.state.disabled && item.state.selectCls === 'check')
75+
76+
unchecked.length ? (value = enabledValues) : (value = [])
77+
} else if (state.selectCls === 'checked-sur') {
78+
value = []
79+
}
80+
}
81+
82+
const requiredValue = []
83+
if (props.multiple) {
84+
state.options.forEach((opt) => {
85+
if (opt.required) requiredValue.push(opt.value)
86+
})
87+
}
88+
89+
if (Array.isArray(value)) {
90+
value = requiredValue.concat(value.filter((val) => !requiredValue.find((requireVal) => requireVal === val)))
91+
}
92+
93+
api.setSoftFocus()
94+
95+
state.isSilentBlur = true
96+
api.updateModelValue(value)
97+
api.directEmitChange(value)
98+
},
99+
// aurora 禁用和只展示的时候都是tagText,默认主题是 isDisplayOnly 才显示tagText
100+
computedShowTagText: () => {
101+
return state.isDisabled || state.isDisplayOnly
102+
},
103+
// aurora 禁用已选项无效果,必选不显示关闭图标
104+
isTagClosable: (item) => {
105+
return !item.required
106+
}
107+
}
108+
}
109+
}

packages/design/saas/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import Popeditor from './src/popeditor'
3030
import DialogSelect from './src/dialog-select'
3131
import DatePanel from './src/date-panel'
3232
import Cascader from './src/cascader'
33+
import BaseSelect from './src/base-select'
3334
import { version } from './package.json'
3435

3536
export default {
@@ -67,6 +68,7 @@ export default {
6768
DialogBox,
6869
DatePanel,
6970
DialogSelect,
70-
Cascader
71+
Cascader,
72+
BaseSelect
7173
}
7274
}
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { iconChevronDown, iconPlus } from '@opentiny/vue-icon'
2+
import loadingIcon from './icon-loading.svg'
3+
4+
export default {
5+
// 虚拟滚动的默认options不一致
6+
baseOpts: { optionHeight: 34, limit: 20 },
7+
icons: {
8+
dropdownIcon: iconChevronDown(),
9+
addIcon: iconPlus(),
10+
loadingIcon
11+
},
12+
state: {
13+
sizeMap: {
14+
default: 28,
15+
mini: 24,
16+
small: 28,
17+
medium: 32
18+
},
19+
spacingHeight: 4,
20+
initialInputHeight: 28,
21+
// 显示清除等图标时,不隐藏下拉箭头时
22+
autoHideDownIcon: false,
23+
delayBlur: true
24+
},
25+
props: {
26+
tagType: 'info',
27+
stopPropagation: true
28+
},
29+
renderless: (props, hooks, { emit }, api) => {
30+
const state = api.state
31+
32+
return {
33+
computedCollapseTagSize: () => {
34+
let size = 'small'
35+
36+
if (~['small', 'mini'].indexOf(state.selectSize)) {
37+
size = state.selectSize
38+
} else if (~['medium', 'default'].indexOf(state.selectSize)) {
39+
size = 'small'
40+
}
41+
42+
return size
43+
},
44+
// aui 的勾选未处理disabled的选项,故此放这里。
45+
toggleCheckAll: (filtered) => {
46+
const getEnabledValues = (options) => {
47+
let values = []
48+
49+
for (let i = 0; i < options.length; i++) {
50+
if (!options[i].state.disabled && !options[i].state.groupDisabled && options[i].state.visible) {
51+
values.push(options[i].value)
52+
}
53+
}
54+
55+
return values
56+
}
57+
58+
let value
59+
const enabledValues = getEnabledValues(state.options)
60+
61+
if (filtered) {
62+
if (state.filteredSelectCls === 'check' || state.filteredSelectCls === 'halfselect') {
63+
value = Array.from(new Set([...state.modelValue, ...enabledValues]))
64+
} else {
65+
value = state.modelValue.filter((val) => !enabledValues.includes(val))
66+
}
67+
} else {
68+
if (state.selectCls === 'check') {
69+
value = enabledValues
70+
} else if (state.selectCls === 'halfselect') {
71+
const unchecked = state.options.filter((item) => !item.state.disabled && item.state.selectCls === 'check')
72+
73+
unchecked.length ? (value = enabledValues) : (value = [])
74+
} else if (state.selectCls === 'checked-sur') {
75+
value = []
76+
}
77+
}
78+
79+
const requiredValue = []
80+
if (props.multiple) {
81+
state.options.forEach((opt) => {
82+
if (opt.required) requiredValue.push(opt.value)
83+
})
84+
}
85+
86+
if (Array.isArray(value)) {
87+
value = requiredValue.concat(value.filter((val) => !requiredValue.find((requireVal) => requireVal === val)))
88+
}
89+
90+
api.setSoftFocus()
91+
92+
state.isSilentBlur = true
93+
api.updateModelValue(value)
94+
api.directEmitChange(value)
95+
},
96+
// aurora 禁用和只展示的时候都是tagText,默认主题是 isDisplayOnly 才显示tagText
97+
computedShowTagText: () => {
98+
return state.isDisabled || state.isDisplayOnly
99+
},
100+
// aurora 禁用已选项无效果,必选不显示关闭图标
101+
isTagClosable: (item) => {
102+
return !item.required
103+
}
104+
}
105+
}
106+
}

packages/renderless/src/base-select/index.ts

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,11 @@ const getOptionOfSetSelected = ({ api, props }) => {
277277
option.state = {}
278278
}
279279

280+
// 如果 option 有 currentLabel 但没有设置到 state 中,则复制过去
281+
if (option.currentLabel !== undefined && option.state.currentLabel === undefined) {
282+
option.state.currentLabel = option.currentLabel
283+
}
284+
280285
if (option.created) {
281286
option.createdLabel = option.state.currentLabel
282287
option.createdSelected = true
@@ -285,7 +290,7 @@ const getOptionOfSetSelected = ({ api, props }) => {
285290
}
286291

287292
// tiny 新增
288-
if (!option.state.currentLabel) {
293+
if (!option.state.currentLabel && !option.currentLabel) {
289294
api.clearNoMatchValue('')
290295
}
291296

@@ -301,7 +306,8 @@ const getResultOfSetSelected = ({ state, api, props }) => {
301306
state.modelValue.forEach((value) => {
302307
// tiny 新增
303308
const option = api.getOption(value)
304-
if (!props.clearNoMatchValue || (props.clearNoMatchValue && option.label)) {
309+
const hasLabel = option?.label || option?.currentLabel || (option?.state && option.state.currentLabel)
310+
if (!props.clearNoMatchValue || (props.clearNoMatchValue && hasLabel)) {
305311
result.push(option)
306312
newModelValue.push(value)
307313
}
@@ -321,6 +327,10 @@ export const setSelected =
321327
state.selected = option
322328
state.selectedLabel = option.state.currentLabel || option.currentLabel
323329
;(props.filterable || props.searchable) && !props.shape && (state.query = state.selectedLabel)
330+
// 使用 panel 插槽且有选中值时,不显示 placeholder
331+
if (vm.$slots.panel && state.selectedLabel && (props.filterable || props.searchable)) {
332+
state.currentPlaceholder = ''
333+
}
324334
} else {
325335
const result = getResultOfSetSelected({ state, props, api })
326336
state.selectCls = result.length
@@ -334,6 +344,11 @@ export const setSelected =
334344
}
335345
state.selected.length && (state.selectedLabel = '')
336346

347+
// 使用 panel 插槽且有选中值时,不显示 placeholder
348+
if (vm.$slots.panel && result.length > 0 && (props.filterable || props.searchable)) {
349+
state.currentPlaceholder = ''
350+
}
351+
337352
state.tips = state.selected.map((item) => (item.state ? item.state.currentLabel : item.currentLabel)).join(',')
338353

339354
setFilteredSelectCls(nextTick, state, props)
@@ -1121,7 +1136,10 @@ export const watchValue =
11211136
if (props.multiple) {
11221137
api.resetInputHeight()
11231138

1124-
if ((value && value.length > 0) || (vm.$refs.input && state.query !== '')) {
1139+
// 使用 panel 插槽且有选中值时,不显示 placeholder
1140+
if (vm.$slots.panel && value && value.length > 0) {
1141+
state.currentPlaceholder = ''
1142+
} else if ((value && value.length > 0) || (vm.$refs.input && state.query !== '')) {
11251143
state.currentPlaceholder = ''
11261144
} else {
11271145
state.currentPlaceholder = state.cachedPlaceHolder
@@ -1196,7 +1214,7 @@ export const calcOverFlow =
11961214
}
11971215
}
11981216

1199-
const postOperOfToVisible = ({ props, state, constants }) => {
1217+
const postOperOfToVisible = ({ props, state, constants, vm }) => {
12001218
if (props.multiple) {
12011219
if (props.modelValue && props.modelValue.length && props.initLabel && !state.selected.length) {
12021220
state.selectedLabel = props.initLabel
@@ -1219,8 +1237,13 @@ const postOperOfToVisible = ({ props, state, constants }) => {
12191237
}
12201238
}
12211239

1240+
// 使用 panel 插槽且有选中值时,不显示 placeholder
12221241
if (props.filterable || props.searchable) {
1223-
state.currentPlaceholder = state.cachedPlaceHolder
1242+
if (vm.$slots.panel && state.selectedLabel) {
1243+
state.currentPlaceholder = ''
1244+
} else {
1245+
state.currentPlaceholder = state.cachedPlaceHolder
1246+
}
12241247
}
12251248

12261249
if (props.modelValue && props.initLabel && !state.selectedLabel) {
@@ -1255,7 +1278,7 @@ export const toVisible =
12551278
}
12561279
})
12571280

1258-
postOperOfToVisible({ props, state, constants })
1281+
postOperOfToVisible({ props, state, constants, vm })
12591282
}
12601283

12611284
export const toHide =

packages/renderless/src/grid-select/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,12 @@ export const syncGridSelection =
5656
vm.$refs.gridRef.clearRadioRow()
5757
if (rowToSelect) {
5858
vm.$refs.gridRef.setRadioRow(rowToSelect)
59+
// 确保 state.currentKey 与选中行同步,这样 buildRadioConfig 才能正确返回 checkRowKey
60+
state.currentKey = rowToSelect[props.valueField]
5961
}
6062
} else {
6163
vm.$refs.gridRef.clearRadioRow()
64+
state.currentKey = ''
6265
}
6366
}
6467
} catch (e) {
@@ -534,6 +537,8 @@ export const radioChange =
534537

535538
state.selected = row
536539
state.currentKey = row[props.valueField]
540+
// 更新 state.modelValue,确保与 props.modelValue 同步
541+
state.modelValue = row[props.valueField]
537542

538543
vm.$refs.baseSelectRef.hidePanel()
539544

packages/renderless/src/grid-select/vue.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export const renderless = (props, { reactive, computed, watch, onMounted, nextTi
124124
api.filter(state.previousQuery || '')
125125
}
126126
},
127-
{ deep: true }
127+
{ deep: true, immediate: false }
128128
)
129129

130130
// 监听面板打开,同步表格选中状态(通过事件处理)

0 commit comments

Comments
 (0)