jobsys-explore 4.2.3 → 4.2.5
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/smooth-emus-move.md +5 -0
- package/CHANGELOG.md +19 -0
- package/components/form/ExForm.jsx +7 -0
- package/components/form/ExNumber.jsx +1 -1
- package/components/form/ExRadio.jsx +1 -0
- package/components/form/ExRate.jsx +1 -1
- package/components/form/ExSelect.jsx +87 -5
- package/components/form/utils.js +1 -1
- 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 +1137 -1091
- package/dist/jobsys-explore.js.map +1 -1
- package/package.json +1 -1
- package/playground/App.vue +2 -2
- package/playground/TestForm.vue +49 -43
- package/playground/TestPagination.vue +16 -7
- package/playground/TestSearch.vue +16 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# jobsys-explore
|
|
2
2
|
|
|
3
|
+
## 4.2.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- select
|
|
8
|
+
- d
|
|
9
|
+
- useFormFormat
|
|
10
|
+
- rate default null
|
|
11
|
+
- use Dayjs
|
|
12
|
+
|
|
13
|
+
## 4.2.4
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- d
|
|
18
|
+
- useFormFormat
|
|
19
|
+
- rate default null
|
|
20
|
+
- use Dayjs
|
|
21
|
+
|
|
3
22
|
## 4.2.3
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
|
@@ -284,6 +284,13 @@ export default defineComponent({
|
|
|
284
284
|
let form = cloneDeep(state.submitForm)
|
|
285
285
|
|
|
286
286
|
formItems.value
|
|
287
|
+
.map((item) => {
|
|
288
|
+
if (item.match) {
|
|
289
|
+
// match 的属性需要在这里处理
|
|
290
|
+
return { ...item, ...item.match(form) }
|
|
291
|
+
}
|
|
292
|
+
return item
|
|
293
|
+
})
|
|
287
294
|
.filter((item) => item.beforeSubmit && isFunction(item.beforeSubmit))
|
|
288
295
|
.forEach((item) => {
|
|
289
296
|
form[item.key] = item.beforeSubmit({
|
|
@@ -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,6 +119,9 @@ 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
|
|
|
@@ -111,12 +132,24 @@ export default defineComponent({
|
|
|
111
132
|
() => prepareOptions(props.options).then((opts) => (options.value = opts)),
|
|
112
133
|
)
|
|
113
134
|
|
|
135
|
+
const filterOnlineDataByKeyword = async () => {
|
|
136
|
+
let res = await useFetch(fetcher).get(props.filterUrl, { params: { keyword: keyword.value } })
|
|
137
|
+
if (props.afterFetched) {
|
|
138
|
+
res = props.afterFetched(res)
|
|
139
|
+
}
|
|
140
|
+
options.value = res
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const filterLocalDataByKeyword = () => {
|
|
144
|
+
options.value = recordOptions.value.filter((item) => item.text.includes(keyword.value))
|
|
145
|
+
}
|
|
146
|
+
|
|
114
147
|
// @hack
|
|
115
148
|
// 由于在 Picker 清除 model value 后再次打开 Picker 在不重新选择新选项的情况下无法选中之前的选项
|
|
116
149
|
// 所以这里手动重新赋一次值给 model value
|
|
117
150
|
const onOpenWrapper = () => {
|
|
118
151
|
if (columns === 1 && !componentValue.value?.[0]) {
|
|
119
|
-
componentValue.value = [options.value[0]
|
|
152
|
+
componentValue.value = [options.value[0]?.value]
|
|
120
153
|
}
|
|
121
154
|
}
|
|
122
155
|
|
|
@@ -128,6 +161,30 @@ export default defineComponent({
|
|
|
128
161
|
pickerRef.value.close()
|
|
129
162
|
}
|
|
130
163
|
|
|
164
|
+
const onSearch = () => {
|
|
165
|
+
if (keyword.value) {
|
|
166
|
+
if (props.filterUrl) {
|
|
167
|
+
filterOnlineDataByKeyword()
|
|
168
|
+
} else {
|
|
169
|
+
filterLocalDataByKeyword()
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
if (props.filterUrl) {
|
|
173
|
+
filterOnlineDataByKeyword()
|
|
174
|
+
} else {
|
|
175
|
+
filterLocalDataByKeyword()
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const onSearchClear = () => {
|
|
181
|
+
if (props.filterUrl) {
|
|
182
|
+
filterOnlineDataByKeyword()
|
|
183
|
+
} else {
|
|
184
|
+
filterLocalDataByKeyword()
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
131
188
|
const onClear = () => {
|
|
132
189
|
const value = columns === 1 ? null : []
|
|
133
190
|
emit("change", value)
|
|
@@ -137,6 +194,28 @@ export default defineComponent({
|
|
|
137
194
|
|
|
138
195
|
expose({ displayText })
|
|
139
196
|
|
|
197
|
+
/********** render **********/
|
|
198
|
+
|
|
199
|
+
const pickerSlotElem = () => {
|
|
200
|
+
const elem = {}
|
|
201
|
+
if (props.filtable) {
|
|
202
|
+
elem["columns-top"] = () => (
|
|
203
|
+
<Search
|
|
204
|
+
shape={"round"}
|
|
205
|
+
placeholder={"搜索"}
|
|
206
|
+
v-model={keyword.value}
|
|
207
|
+
onSearch={onSearch}
|
|
208
|
+
onClear={onSearchClear}
|
|
209
|
+
style={{ width: "100%" }}
|
|
210
|
+
></Search>
|
|
211
|
+
)
|
|
212
|
+
}
|
|
213
|
+
if (props.optionRender) {
|
|
214
|
+
elem["option"] = (option, index) => props.optionRender(option, index)
|
|
215
|
+
}
|
|
216
|
+
return elem
|
|
217
|
+
}
|
|
218
|
+
|
|
140
219
|
return () => (
|
|
141
220
|
<PickerWrapper ref={pickerRef} closeable={false} onOpen={onOpenWrapper} disabled={props.readonly || props.disabled}>
|
|
142
221
|
{{
|
|
@@ -146,9 +225,12 @@ export default defineComponent({
|
|
|
146
225
|
v-model={componentValue.value}
|
|
147
226
|
columns={options.value}
|
|
148
227
|
onConfirm={onConfirm}
|
|
228
|
+
loading={fetcher.value.loading}
|
|
149
229
|
onCancel={() => pickerRef.value.close()}
|
|
150
230
|
{...props.defaultProps}
|
|
151
|
-
|
|
231
|
+
>
|
|
232
|
+
{pickerSlotElem()}
|
|
233
|
+
</Picker>,
|
|
152
234
|
props.clearable ? (
|
|
153
235
|
<div class={"ex-field-popup__clear-btn"}>
|
|
154
236
|
<Button block type={"primary"} plain={true} round={true} onClick={onClear}>
|
package/components/form/utils.js
CHANGED
|
@@ -25,7 +25,7 @@ const initItemDefaultValue = (item, existingData, submitForm, provider) => {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
if (item.type === "number" || item.type === "rate") {
|
|
28
|
-
value = value ? Number(value) :
|
|
28
|
+
value = value ? Number(value) : null
|
|
29
29
|
} else if (item.type === "slider") {
|
|
30
30
|
value = item.defaultProps && item.defaultProps.range ? value || [0, 100] : value ? Number(value) : 0
|
|
31
31
|
} else if (item.type === "switch") {
|
|
@@ -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>
|