jobsys-explore 4.2.4 → 4.2.6
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/.changeset/chatty-donkeys-grin.md +5 -0
- package/.changeset/ten-needles-wait.md +5 -0
- package/CHANGELOG.md +21 -0
- package/components/form/ExSelect.jsx +90 -6
- package/components/search/ExSearch.jsx +21 -30
- package/dist/jobsys-explore.cjs +6 -6
- package/dist/jobsys-explore.cjs.map +1 -1
- package/dist/jobsys-explore.js +1110 -1065
- package/dist/jobsys-explore.js.map +1 -1
- package/package.json +1 -1
- package/playground/App.vue +2 -2
- package/playground/TestForm.vue +18 -35
- package/playground/TestPagination.vue +16 -7
- package/playground/TestSearch.vue +16 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# jobsys-explore
|
|
2
2
|
|
|
3
|
+
## 4.2.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- select
|
|
8
|
+
- d
|
|
9
|
+
- useFormFormat
|
|
10
|
+
- rate default null
|
|
11
|
+
- use Dayjs
|
|
12
|
+
- select
|
|
13
|
+
|
|
14
|
+
## 4.2.5
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- select
|
|
19
|
+
- d
|
|
20
|
+
- useFormFormat
|
|
21
|
+
- rate default null
|
|
22
|
+
- use Dayjs
|
|
23
|
+
|
|
3
24
|
## 4.2.4
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { computed, defineComponent, ref, watch } from "vue"
|
|
2
2
|
import PickerWrapper, { pickerSlots } from "./PickerWrapper.jsx"
|
|
3
|
-
import { Button, Picker } from "vant"
|
|
3
|
+
import { Button, Picker, Search } from "vant"
|
|
4
4
|
import { defaultFieldProps, defaultOptionsProps } from "../utils"
|
|
5
5
|
import { useFetch } from "../../hooks"
|
|
6
|
-
import { find, isArray, isFunction, isString } from "lodash-es"
|
|
6
|
+
import { cloneDeep, find, isArray, isFunction, isString } from "lodash-es"
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* ExSelect 下拉选择
|
|
@@ -31,13 +31,31 @@ export default defineComponent({
|
|
|
31
31
|
* 是否把选项的值返回到modelValue
|
|
32
32
|
*/
|
|
33
33
|
textInValue: { type: Boolean, default: false },
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 是否可以搜索
|
|
37
|
+
*/
|
|
38
|
+
filtable: { type: Boolean, default: false },
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 搜索链接
|
|
42
|
+
*/
|
|
43
|
+
filterUrl: { type: String, default: "" },
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 自定义渲染选项
|
|
47
|
+
*/
|
|
48
|
+
optionRender: { type: Function, default: null },
|
|
34
49
|
},
|
|
35
50
|
emits: ["update:modelValue", "change"],
|
|
36
51
|
setup(props, { emit, slots, expose }) {
|
|
37
52
|
const componentValue = ref([])
|
|
38
53
|
const options = ref([])
|
|
54
|
+
const recordOptions = ref([]) // 缓存 options
|
|
39
55
|
let columns = 1 //根据子项的数组数来确定 Picker 的列数,默认为1列
|
|
40
56
|
const pickerRef = ref()
|
|
57
|
+
const keyword = ref("")
|
|
58
|
+
const fetcher = ref({ loading: false })
|
|
41
59
|
|
|
42
60
|
const setModelValue = () => {
|
|
43
61
|
let value = isArray(props.modelValue) ? props.modelValue : [props.modelValue]
|
|
@@ -54,7 +72,7 @@ export default defineComponent({
|
|
|
54
72
|
)
|
|
55
73
|
|
|
56
74
|
const displayText = computed(() => {
|
|
57
|
-
if (!props.modelValue
|
|
75
|
+
if (!props.modelValue || (isArray(props.modelValue) && !props.modelValue.length)) {
|
|
58
76
|
return ""
|
|
59
77
|
}
|
|
60
78
|
let modelValue = isArray(props.modelValue) ? props.modelValue : [props.modelValue]
|
|
@@ -101,22 +119,39 @@ export default defineComponent({
|
|
|
101
119
|
|
|
102
120
|
return isString(option) ? { value: option, label: option, text: option } : { text: option.label, ...option }
|
|
103
121
|
})
|
|
122
|
+
|
|
123
|
+
recordOptions.value = cloneDeep(options)
|
|
124
|
+
|
|
104
125
|
return options
|
|
105
126
|
}
|
|
106
127
|
|
|
107
|
-
prepareOptions(props.options).then((opts) =>
|
|
128
|
+
prepareOptions(props.options).then((opts) => {
|
|
129
|
+
options.value = opts
|
|
130
|
+
})
|
|
108
131
|
|
|
109
132
|
watch(
|
|
110
133
|
() => props.options,
|
|
111
134
|
() => prepareOptions(props.options).then((opts) => (options.value = opts)),
|
|
112
135
|
)
|
|
113
136
|
|
|
137
|
+
const filterOnlineDataByKeyword = async () => {
|
|
138
|
+
let res = await useFetch(fetcher.value).get(props.filterUrl, { params: { keyword: keyword.value } })
|
|
139
|
+
if (props.afterFetched) {
|
|
140
|
+
res = props.afterFetched(res)
|
|
141
|
+
}
|
|
142
|
+
prepareOptions(res).then((opts) => (options.value = opts))
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const filterLocalDataByKeyword = () => {
|
|
146
|
+
options.value = recordOptions.value.filter((item) => item.text.includes(keyword.value))
|
|
147
|
+
}
|
|
148
|
+
|
|
114
149
|
// @hack
|
|
115
150
|
// 由于在 Picker 清除 model value 后再次打开 Picker 在不重新选择新选项的情况下无法选中之前的选项
|
|
116
151
|
// 所以这里手动重新赋一次值给 model value
|
|
117
152
|
const onOpenWrapper = () => {
|
|
118
153
|
if (columns === 1 && !componentValue.value?.[0]) {
|
|
119
|
-
componentValue.value = [options.value[0]
|
|
154
|
+
componentValue.value = [options.value[0]?.value]
|
|
120
155
|
}
|
|
121
156
|
}
|
|
122
157
|
|
|
@@ -128,6 +163,30 @@ export default defineComponent({
|
|
|
128
163
|
pickerRef.value.close()
|
|
129
164
|
}
|
|
130
165
|
|
|
166
|
+
const onSearch = () => {
|
|
167
|
+
if (keyword.value) {
|
|
168
|
+
if (props.filterUrl) {
|
|
169
|
+
filterOnlineDataByKeyword()
|
|
170
|
+
} else {
|
|
171
|
+
filterLocalDataByKeyword()
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
if (props.filterUrl) {
|
|
175
|
+
filterOnlineDataByKeyword()
|
|
176
|
+
} else {
|
|
177
|
+
filterLocalDataByKeyword()
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const onSearchClear = () => {
|
|
183
|
+
if (props.filterUrl) {
|
|
184
|
+
filterOnlineDataByKeyword()
|
|
185
|
+
} else {
|
|
186
|
+
filterLocalDataByKeyword()
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
131
190
|
const onClear = () => {
|
|
132
191
|
const value = columns === 1 ? null : []
|
|
133
192
|
emit("change", value)
|
|
@@ -137,6 +196,28 @@ export default defineComponent({
|
|
|
137
196
|
|
|
138
197
|
expose({ displayText })
|
|
139
198
|
|
|
199
|
+
/********** render **********/
|
|
200
|
+
|
|
201
|
+
const pickerSlotElem = () => {
|
|
202
|
+
const elem = {}
|
|
203
|
+
if (props.filtable) {
|
|
204
|
+
elem["columns-top"] = () => (
|
|
205
|
+
<Search
|
|
206
|
+
shape={"round"}
|
|
207
|
+
placeholder={"搜索"}
|
|
208
|
+
v-model={keyword.value}
|
|
209
|
+
onSearch={onSearch}
|
|
210
|
+
onClear={onSearchClear}
|
|
211
|
+
style={{ width: "100%" }}
|
|
212
|
+
></Search>
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
if (props.optionRender) {
|
|
216
|
+
elem["option"] = (option, index) => props.optionRender(option, index)
|
|
217
|
+
}
|
|
218
|
+
return elem
|
|
219
|
+
}
|
|
220
|
+
|
|
140
221
|
return () => (
|
|
141
222
|
<PickerWrapper ref={pickerRef} closeable={false} onOpen={onOpenWrapper} disabled={props.readonly || props.disabled}>
|
|
142
223
|
{{
|
|
@@ -146,9 +227,12 @@ export default defineComponent({
|
|
|
146
227
|
v-model={componentValue.value}
|
|
147
228
|
columns={options.value}
|
|
148
229
|
onConfirm={onConfirm}
|
|
230
|
+
loading={fetcher.value.loading}
|
|
149
231
|
onCancel={() => pickerRef.value.close()}
|
|
150
232
|
{...props.defaultProps}
|
|
151
|
-
|
|
233
|
+
>
|
|
234
|
+
{pickerSlotElem()}
|
|
235
|
+
</Picker>,
|
|
152
236
|
props.clearable ? (
|
|
153
237
|
<div class={"ex-field-popup__clear-btn"}>
|
|
154
238
|
<Button block type={"primary"} plain={true} round={true} onClick={onClear}>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isArray, isFunction } from "lodash-es"
|
|
2
2
|
import { Button, Icon, Popup, Search } from "vant"
|
|
3
|
-
import {
|
|
3
|
+
import { computed, defineComponent, nextTick, reactive, ref, watch } from "vue"
|
|
4
|
+
import ExGrid from "../grid/ExGrid.jsx"
|
|
4
5
|
import { createExpand, createField, createQuick } from "./components"
|
|
5
6
|
import "./index.less"
|
|
6
|
-
import ExGrid from "../grid/ExGrid.jsx"
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* ExSearch 搜索组件
|
|
@@ -83,9 +83,6 @@ export default defineComponent({
|
|
|
83
83
|
|
|
84
84
|
const state = reactive({
|
|
85
85
|
queryForm: {}, // 搜索表单
|
|
86
|
-
quickColumns: [], //快速检索项
|
|
87
|
-
fieldColumns: [], //表单搜索项
|
|
88
|
-
|
|
89
86
|
showFilterPopup: false,
|
|
90
87
|
})
|
|
91
88
|
|
|
@@ -108,26 +105,20 @@ export default defineComponent({
|
|
|
108
105
|
return value
|
|
109
106
|
}
|
|
110
107
|
|
|
108
|
+
//快速检索项
|
|
109
|
+
const quickColumns = computed(() => {
|
|
110
|
+
return props.columns.filter((item) => item.quick)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
//表单搜索项
|
|
114
|
+
const fieldColumns = computed(() => {
|
|
115
|
+
return props.columns.filter((item) => !item.quick)
|
|
116
|
+
})
|
|
117
|
+
|
|
111
118
|
const initQueryForm = () => {
|
|
112
119
|
const form = {}
|
|
113
120
|
props.columns.forEach((item) => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (item.quick && !find(state.quickColumns, { key: item.key })) {
|
|
117
|
-
state.quickColumns.push(item)
|
|
118
|
-
} else {
|
|
119
|
-
if (item.expandable) {
|
|
120
|
-
if (!item.options) {
|
|
121
|
-
console.error(`expandable 为 true 时,必须提供 options 属性`)
|
|
122
|
-
return
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (!find(state.fieldColumns, { key: item.key })) {
|
|
127
|
-
state.fieldColumns.push(item)
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
form[item.key] = value
|
|
121
|
+
form[item.key] = searchItemDefaultValue(item)
|
|
131
122
|
})
|
|
132
123
|
state.queryForm = form
|
|
133
124
|
}
|
|
@@ -176,16 +167,16 @@ export default defineComponent({
|
|
|
176
167
|
}
|
|
177
168
|
|
|
178
169
|
const onClearFields = () => {
|
|
179
|
-
|
|
170
|
+
fieldColumns.value.forEach((item) => {
|
|
180
171
|
state.queryForm[item.key] = searchItemDefaultValue(item)
|
|
181
172
|
})
|
|
182
173
|
}
|
|
183
174
|
|
|
184
175
|
const reset = () => {
|
|
185
|
-
|
|
176
|
+
fieldColumns.value.forEach((item) => {
|
|
186
177
|
state.queryForm[item.key] = searchItemDefaultValue(item)
|
|
187
178
|
})
|
|
188
|
-
|
|
179
|
+
quickColumns.value.forEach((item) => {
|
|
189
180
|
state.queryForm[item.key] = searchItemDefaultValue(item)
|
|
190
181
|
})
|
|
191
182
|
componentValue.value = ""
|
|
@@ -196,7 +187,7 @@ export default defineComponent({
|
|
|
196
187
|
/******************* render *********************/
|
|
197
188
|
|
|
198
189
|
const quickElems = () => {
|
|
199
|
-
return
|
|
190
|
+
return quickColumns.value.map((item) => createQuick(item, state.queryForm, onSearch))
|
|
200
191
|
}
|
|
201
192
|
|
|
202
193
|
const popupHeaderElem = () => (
|
|
@@ -214,7 +205,7 @@ export default defineComponent({
|
|
|
214
205
|
|
|
215
206
|
const fieldElems = () => (
|
|
216
207
|
<div class={"ex-search-popup__content"}>
|
|
217
|
-
{
|
|
208
|
+
{fieldColumns.value.map((item) => (item.expandable ? createExpand(item, state.queryForm) : createField(item, state.queryForm)))}
|
|
218
209
|
</div>
|
|
219
210
|
)
|
|
220
211
|
|
|
@@ -236,13 +227,13 @@ export default defineComponent({
|
|
|
236
227
|
)
|
|
237
228
|
|
|
238
229
|
const quickBarElem = () => {
|
|
239
|
-
if (!
|
|
230
|
+
if (!quickColumns.value?.length && !fieldColumns.value?.length) {
|
|
240
231
|
return null
|
|
241
232
|
}
|
|
242
233
|
return (
|
|
243
234
|
<div class={"ex-search__quick-bar"}>
|
|
244
235
|
<div class={"ex-search__quick-container"}>{quickElems()}</div>
|
|
245
|
-
{
|
|
236
|
+
{fieldColumns.value?.length ? (
|
|
246
237
|
<div class={"ex-search__filter"} onClick={onOpenFilter}>
|
|
247
238
|
筛选<Icon name={"filter-o"}></Icon>
|
|
248
239
|
</div>
|