jobsys-explore 4.6.21 → 4.7.0

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 (180) hide show
  1. package/.eslintignore +3 -3
  2. package/CHANGELOG.md +542 -542
  3. package/README.md +41 -41
  4. package/TODOs.md +8 -8
  5. package/business-components/survey/ExSurvey.jsx +193 -193
  6. package/business-components/survey/index.js +5 -5
  7. package/business-components/survey/index.less +36 -36
  8. package/components/button/ExButton.jsx +120 -120
  9. package/components/button/index.js +4 -4
  10. package/components/button/index.less +7 -7
  11. package/components/decorator/ExDecorator.jsx +31 -31
  12. package/components/decorator/index.js +5 -5
  13. package/components/decorator/index.less +76 -76
  14. package/components/form/ExAddress.jsx +195 -195
  15. package/components/form/ExCascader.jsx +171 -171
  16. package/components/form/ExCheckbox.jsx +59 -59
  17. package/components/form/ExDate.jsx +143 -143
  18. package/components/form/ExDatetime.jsx +166 -166
  19. package/components/form/ExField.jsx +138 -138
  20. package/components/form/ExFieldUploader.jsx +50 -50
  21. package/components/form/ExForm.jsx +544 -544
  22. package/components/form/ExMatrixCheckbox.jsx +99 -99
  23. package/components/form/ExMatrixRadio.jsx +86 -86
  24. package/components/form/ExMatrixScale.jsx +97 -97
  25. package/components/form/ExNumber.jsx +51 -51
  26. package/components/form/ExRadio.jsx +58 -58
  27. package/components/form/ExRate.jsx +51 -51
  28. package/components/form/ExSelect.jsx +251 -251
  29. package/components/form/ExSlider.jsx +55 -55
  30. package/components/form/ExSwitch.jsx +51 -51
  31. package/components/form/ExTime.jsx +99 -99
  32. package/components/form/FormItem.jsx +307 -307
  33. package/components/form/PickerWrapper.jsx +120 -120
  34. package/components/form/index.js +46 -46
  35. package/components/form/index.less +178 -178
  36. package/components/form/utils.js +62 -62
  37. package/components/grid/ExGrid.jsx +53 -53
  38. package/components/grid/index.js +4 -4
  39. package/components/grid/index.less +2 -2
  40. package/components/index.js +12 -12
  41. package/components/pagination/ExPagination.jsx +457 -440
  42. package/components/pagination/index.js +5 -5
  43. package/components/pagination/index.less +3 -3
  44. package/components/provider/ExProvider.jsx +173 -173
  45. package/components/qrcode/ExQrcode.jsx +86 -86
  46. package/components/qrcode/index.js +5 -5
  47. package/components/qrcode/index.less +8 -8
  48. package/components/result/ExResult.jsx +122 -122
  49. package/components/result/index.js +5 -5
  50. package/components/result/index.less +59 -59
  51. package/components/search/ExSearch.jsx +370 -326
  52. package/components/search/components/Expand.jsx +77 -77
  53. package/components/search/components/Field.jsx +27 -27
  54. package/components/search/components/Quick.jsx +57 -57
  55. package/components/search/components/index.js +5 -5
  56. package/components/search/index.js +5 -5
  57. package/components/search/index.less +118 -118
  58. package/components/search/utils.js +30 -30
  59. package/components/sector/ExSector.jsx +52 -52
  60. package/components/sector/README.md +26 -26
  61. package/components/sector/index.js +5 -5
  62. package/components/sector/index.less +122 -122
  63. package/components/theme/ExTheme.jsx +10 -10
  64. package/components/theme/index.js +4 -4
  65. package/components/theme/index.less +98 -98
  66. package/components/uploader/ExUploader.jsx +293 -293
  67. package/components/uploader/index.js +5 -5
  68. package/components/utils.js +187 -187
  69. package/directives/auth.js +113 -113
  70. package/directives/index.js +4 -4
  71. package/dist/cipher-98df1050.cjs.map +1 -1
  72. package/dist/cipher-f2ed5ee6.js.map +1 -1
  73. package/dist/directives.cjs.map +1 -1
  74. package/dist/directives.js.map +1 -1
  75. package/dist/hooks.cjs.map +1 -1
  76. package/dist/hooks.js.map +1 -1
  77. package/dist/jobsys-explore.cjs +6 -6
  78. package/dist/jobsys-explore.cjs.map +1 -1
  79. package/dist/jobsys-explore.js +464 -407
  80. package/dist/jobsys-explore.js.map +1 -1
  81. package/docgen.config.js +15 -15
  82. package/docs/.vuepress/.cache/deps/_metadata.json +52 -52
  83. package/docs/.vuepress/.cache/deps/lodash-es.js +8442 -8442
  84. package/docs/.vuepress/.cache/deps/lodash-es.js.map +7 -7
  85. package/docs/.vuepress/.temp/internal/clientConfigs.js +17 -17
  86. package/docs/.vuepress/.temp/internal/pagesComponents.js +24 -24
  87. package/docs/.vuepress/.temp/internal/pagesData.js +22 -22
  88. package/docs/.vuepress/.temp/internal/pagesRoutes.js +12 -12
  89. package/docs/.vuepress/.temp/internal/themeData.js +1 -1
  90. package/docs/.vuepress/.temp/pages/components/decorator/ExDecorator.html.js +1 -1
  91. package/docs/.vuepress/.temp/pages/components/decorator/ExDecorator.html.vue +37 -37
  92. package/docs/.vuepress/.temp/pages/components/sector/ExSector.html.js +1 -1
  93. package/docs/.vuepress/.temp/pages/components/sector/ExSector.html.vue +71 -71
  94. package/docs/.vuepress/.temp/styles/index.scss +1 -1
  95. package/docs/.vuepress/config.js +61 -61
  96. package/docs/.vuepress/dist/404.html +33 -33
  97. package/docs/.vuepress/dist/assets/404.html-a0ce2184.js +1 -1
  98. package/docs/.vuepress/dist/assets/ExButton.html-ad283101.js +1 -1
  99. package/docs/.vuepress/dist/assets/ExDecorator.html-42d09114.js +1 -1
  100. package/docs/.vuepress/dist/assets/ExDecorator.html-c82c5fe8.js +1 -1
  101. package/docs/.vuepress/dist/assets/ExForm.html-9e3f8000.js +1 -1
  102. package/docs/.vuepress/dist/assets/ExProvider.html-78fdc6cd.js +1 -1
  103. package/docs/.vuepress/dist/assets/ExSearch.html-103f6f34.js +1 -1
  104. package/docs/.vuepress/dist/assets/ExSector.html-a1e24c3a.js +7 -7
  105. package/docs/.vuepress/dist/assets/ExSector.html-cff3fefd.js +1 -1
  106. package/docs/.vuepress/dist/assets/ExUploader.html-8310e424.js +1 -1
  107. package/docs/.vuepress/dist/assets/app-29fe8d1e.js +10 -10
  108. package/docs/.vuepress/dist/assets/hooks.html-90ccbc1a.js +1 -1
  109. package/docs/.vuepress/dist/assets/index.html-85b79c97.js +43 -43
  110. package/docs/.vuepress/dist/assets/style-46d7e227.css +1 -1
  111. package/docs/.vuepress/dist/components/button/ExButton.html +33 -33
  112. package/docs/.vuepress/dist/components/decorator/ExDecorator.html +33 -33
  113. package/docs/.vuepress/dist/components/form/ExForm.html +33 -33
  114. package/docs/.vuepress/dist/components/provider/ExProvider.html +33 -33
  115. package/docs/.vuepress/dist/components/search/ExSearch.html +33 -33
  116. package/docs/.vuepress/dist/components/sector/ExSector.html +39 -39
  117. package/docs/.vuepress/dist/components/uploader/ExUploader.html +33 -33
  118. package/docs/.vuepress/dist/hooks.html +33 -33
  119. package/docs/.vuepress/dist/index.html +75 -75
  120. package/docs/.vuepress/styles/index.scss +7 -7
  121. package/docs/components/decorator/ExDecorator.md +14 -14
  122. package/docs/components/sector/ExSector.md +43 -43
  123. package/docs/index.md +82 -82
  124. package/hooks/cipher.js +44 -44
  125. package/hooks/datetime.js +69 -69
  126. package/hooks/form.js +188 -188
  127. package/hooks/utils.js +282 -282
  128. package/index.html +17 -17
  129. package/package.json +1 -1
  130. package/playground/App.vue +191 -191
  131. package/playground/TestButton.vue +61 -61
  132. package/playground/TestCascader.vue +2442 -2442
  133. package/playground/TestDecorator.vue +14 -14
  134. package/playground/TestForm.vue +429 -429
  135. package/playground/TestFormItem.vue +110 -110
  136. package/playground/TestGrid.vue +22 -22
  137. package/playground/TestPagination.vue +1250 -1248
  138. package/playground/TestQrcode.vue +7 -7
  139. package/playground/TestResult.vue +12 -12
  140. package/playground/TestSearch.vue +115 -115
  141. package/playground/TestSector.vue +15 -15
  142. package/playground/TestSurvey.vue +27 -27
  143. package/playground/TestUploader.vue +14 -14
  144. package/playground/main.js +22 -22
  145. package/utils/style.js +13 -13
  146. package/vite.config.js +54 -54
  147. package/.changeset/blue-spiders-roll.md +0 -5
  148. package/.changeset/cyan-monkeys-draw.md +0 -5
  149. package/.changeset/dry-feet-float.md +0 -5
  150. package/.changeset/empty-mice-share.md +0 -5
  151. package/.changeset/famous-yaks-doubt.md +0 -5
  152. package/.changeset/five-fans-type.md +0 -5
  153. package/.changeset/funny-hats-drop.md +0 -5
  154. package/.changeset/khaki-cobras-bathe.md +0 -5
  155. package/.changeset/khaki-forks-shave.md +0 -5
  156. package/.changeset/lazy-yaks-crash.md +0 -5
  157. package/.changeset/light-cycles-flow.md +0 -5
  158. package/.changeset/loud-mirrors-explain.md +0 -5
  159. package/.changeset/lovely-balloons-protect.md +0 -5
  160. package/.changeset/mean-pens-travel.md +0 -5
  161. package/.changeset/moody-doors-grow.md +0 -5
  162. package/.changeset/moody-laws-change.md +0 -5
  163. package/.changeset/nasty-goats-joke.md +0 -5
  164. package/.changeset/odd-forks-drop.md +0 -5
  165. package/.changeset/olive-windows-suffer.md +0 -5
  166. package/.changeset/popular-carpets-jog.md +0 -5
  167. package/.changeset/popular-planets-play.md +0 -5
  168. package/.changeset/rare-gorillas-boil.md +0 -5
  169. package/.changeset/rare-moose-teach.md +0 -5
  170. package/.changeset/sharp-tools-hope.md +0 -5
  171. package/.changeset/slimy-sloths-refuse.md +0 -5
  172. package/.changeset/slow-boats-search.md +0 -5
  173. package/.changeset/small-experts-bake.md +0 -5
  174. package/.changeset/smooth-horses-tie.md +0 -5
  175. package/.changeset/tame-feet-reply.md +0 -5
  176. package/.changeset/tidy-items-reflect.md +0 -5
  177. package/.changeset/weak-chicken-admire.md +0 -5
  178. package/.changeset/weak-rockets-compare.md +0 -5
  179. package/.changeset/wild-glasses-bathe.md +0 -5
  180. package/.changeset/wise-ears-turn.md +0 -5
@@ -1,326 +1,370 @@
1
- import { find, isArray, isBoolean, isFunction, isUndefined } from "lodash-es"
2
- import { Button, Icon, Popup, Search } from "vant"
3
- import { computed, defineComponent, nextTick, onMounted, reactive, ref, watch } from "vue"
4
- import ExGrid from "../grid/ExGrid.jsx"
5
- import { createExpand, createField, createQuick } from "./components"
6
- import "./index.less"
7
- import { useSm3, useCache } from "../../hooks"
8
-
9
- /**
10
- * ExSearch 搜索组件
11
- * @version 1.0.0
12
- */
13
- export default defineComponent({
14
- name: "ExSearch",
15
- props: {
16
- modelValue: { type: String, default: "" },
17
-
18
- /**
19
- * @typedef {Object} ExSearchItemConfig 搜索项
20
- * @property {string} key 搜索项的 key
21
- * @property {string} title 搜索项的标题
22
- * @property {string} type 搜索项的类型
23
- * @property {boolean} [quick] 为 true 展示为快速检索项
24
- * @property {boolean|Object} [expandable] 搜索项是否展开
25
- * @property {Array|Function} [options] 搜索项的选项
26
- * @property {Object} [inputProps] 搜索项的输入框属性
27
- * @property {Function} [beforeSubmit] 在提交前修改搜索项的值
28
- * @property {*} [defaultValue] 搜索项的值
29
- * @property {*} [_temp] 搜索项的临时值[内部使用]
30
- * */
31
-
32
- /**
33
- *
34
- * 搜索项的配置, 详见 [ExSearchItemConfig](#exsearchitemconfig-配置)
35
- *
36
- */
37
- columns: { type: Array, default: () => [] },
38
-
39
- /**
40
- * 占位提示文字
41
- */
42
- placeholder: { type: String, default: "请输入搜索关键词" },
43
-
44
- /**
45
- * 名称,作为提交表单时的标识符
46
- */
47
- keyword: { type: String, default: "keyword" },
48
-
49
- /**
50
- * 搜索框左侧文本
51
- */
52
- label: { type: String, default: "" },
53
-
54
- /**
55
- * 是否将输入框设为只读状态,只读状态下无法输入内容
56
- */
57
- readonly: { type: Boolean, default: false },
58
-
59
- /**
60
- * 是否禁用输入框
61
- */
62
- disabled: { type: Boolean, default: false },
63
-
64
- /**
65
- * 输入框内容对齐方式
66
- * @values left, right, center
67
- */
68
- inputAlign: { type: String, default: "left" },
69
-
70
- /**
71
- * 持久化,传入 localStorage 的 key,如果为 true, 将会以 URL Hash 为 key
72
- */
73
- persistence: { type: [Boolean, String], default: false },
74
-
75
- /**
76
- * [原生配置](https://vant-contrib.gitee.io/vant/#/zh-CN/search)
77
- */
78
- searchProps: { type: Object, default: () => ({}) },
79
- },
80
- emits: ["update:modelValue", "search"],
81
- setup(props, { expose, emit }) {
82
- const componentValue = ref(props.modelValue)
83
-
84
- watch(
85
- () => props.modelValue,
86
- () => {
87
- componentValue.value = props.modelValue
88
- },
89
- )
90
-
91
- const state = reactive({
92
- queryForm: {}, // 搜索表单
93
- showFilterPopup: false,
94
- })
95
-
96
- const genPersistenceKey = (prefix) => {
97
- if (!props.persistence) {
98
- return null
99
- }
100
- prefix = prefix || ""
101
- if (isBoolean(props.persistence)) {
102
- return `exSearch_${prefix}` + useSm3(location.href)
103
- }
104
-
105
- return `exSearch_${prefix}` + useSm3(location.pathname + "_" + props.persistence)
106
- }
107
-
108
- const searchItemDefaultValue = (item) => {
109
- let value = ""
110
- //如果是展开显示的,那么默认值为空字符串
111
- //如果展开为多选,那么默认值为 []
112
- if (item.expandable === "multiple" || item.type === "cascade") {
113
- value = []
114
- }
115
-
116
- if (item.defaultValue) {
117
- value = isFunction(item.defaultValue) ? item.defaultValue() : item.defaultValue
118
- }
119
-
120
- if ((item.type === "date" || item.type === "datetime") && !value) {
121
- return null
122
- }
123
-
124
- return value
125
- }
126
-
127
- //快速检索项
128
- const quickColumns = computed(() => {
129
- return props.columns.filter((item) => item.quick)
130
- })
131
-
132
- //表单搜索项
133
- const fieldColumns = computed(() => {
134
- return props.columns.filter((item) => !item.quick)
135
- })
136
-
137
- const initQueryForm = () => {
138
- const form = {}
139
-
140
- const persistenceSearchData = props.persistence ? useCache(genPersistenceKey()).get({}) : {}
141
-
142
- props.columns.forEach((item) => {
143
- let value
144
- if (!isUndefined(persistenceSearchData[item.key])) {
145
- value = persistenceSearchData[item.key]
146
- } else {
147
- value = searchItemDefaultValue(item)
148
- }
149
- form[item.key] = value
150
- })
151
- state.queryForm = form
152
- }
153
-
154
- initQueryForm()
155
-
156
- const onUpdateValue = (value) => {
157
- emit("update:modelValue", value)
158
- }
159
-
160
- const getQueryForm = () => {
161
- const form = {}
162
- Object.keys(state.queryForm).forEach((key) => {
163
- let value = state.queryForm[key]
164
-
165
- let filedItem = find(props.columns, { key })
166
- if (filedItem && filedItem.beforeSubmit && isFunction(filedItem.beforeSubmit)) {
167
- value = filedItem.beforeSubmit({
168
- value,
169
- queryForm: state.queryForm, //改成将 form 传出去,这样可以在 form 中添加参数
170
- })
171
- }
172
-
173
- if (value && (!isArray(value) || value.length)) {
174
- form[key] = value
175
- }
176
- })
177
-
178
- if (componentValue.value) {
179
- form[props.keyword] = componentValue.value
180
- }
181
-
182
- return form
183
- }
184
-
185
- const onOpenFilter = () => {
186
- state.showFilterPopup = true
187
- }
188
-
189
- const onCloseFilter = () => {
190
- state.showFilterPopup = false
191
- }
192
-
193
- const onSearch = () => {
194
- nextTick(() => {
195
- const form = getQueryForm()
196
- if (props.persistence) {
197
- useCache(genPersistenceKey()).set(form)
198
- }
199
- emit("search", form)
200
- })
201
- }
202
-
203
- const onFieldSearch = () => {
204
- state.showFilterPopup = false
205
- onSearch()
206
- }
207
-
208
- const onClearFields = () => {
209
- fieldColumns.value.forEach((item) => {
210
- state.queryForm[item.key] = searchItemDefaultValue(item)
211
- })
212
- }
213
-
214
- const reset = () => {
215
- fieldColumns.value.forEach((item) => {
216
- state.queryForm[item.key] = searchItemDefaultValue(item)
217
- })
218
- quickColumns.value.forEach((item) => {
219
- state.queryForm[item.key] = searchItemDefaultValue(item)
220
- })
221
- componentValue.value = ""
222
- }
223
-
224
- onMounted(() => {
225
- if (props.persistence) {
226
- emit("search", { persistence: true, ...getQueryForm() })
227
- }
228
- })
229
-
230
- expose({ reset, getQueryForm })
231
-
232
- /******************* render *********************/
233
-
234
- const quickElems = () => {
235
- return quickColumns.value.map((item) => createQuick(item, state.queryForm, onSearch))
236
- }
237
-
238
- const popupHeaderElem = () => (
239
- <div class={"ex-search-popup__header van-hairline--bottom"}>
240
- <h2 class={"ex-search-popup__title"}>{props.title}</h2>
241
- <span class={"ex-search-popup__closer"}>
242
- <Icon
243
- name={"cross"}
244
- class={"van-badge__wrapper van-popup__close-icon van-popup__close-icon--top-right van-haptics-feedback"}
245
- onClick={() => (state.showFilterPopup = false)}
246
- ></Icon>
247
- </span>
248
- </div>
249
- )
250
-
251
- const fieldElems = () => (
252
- <div class={"ex-search-popup__content"}>
253
- {fieldColumns.value.map((item) => (item.expandable ? createExpand(item, state.queryForm) : createField(item, state.queryForm)))}
254
- </div>
255
- )
256
-
257
- const popupFooterElem = () => (
258
- <div class={"ex-search-popup__footer van-hairline--top"}>
259
- <ExGrid>
260
- {{
261
- default: () => [
262
- <Button type={"default"} size={"small"} round={true} onClick={onClearFields}>
263
- 清除
264
- </Button>,
265
- <Button type={"primary"} size={"small"} round={true} onClick={onFieldSearch}>
266
- 搜索
267
- </Button>,
268
- ],
269
- }}
270
- </ExGrid>
271
- </div>
272
- )
273
-
274
- const quickBarElem = () => {
275
- if (!quickColumns.value?.length && !fieldColumns.value?.length) {
276
- return null
277
- }
278
- return (
279
- <div class={"ex-search__quick-bar"}>
280
- <div class={"ex-search__quick-container"}>{quickElems()}</div>
281
- {fieldColumns.value?.length ? (
282
- <div class={"ex-search__filter"} onClick={onOpenFilter}>
283
- 筛选<Icon name={"filter-o"}></Icon>
284
- </div>
285
- ) : null}
286
- </div>
287
- )
288
- }
289
-
290
- return () => (
291
- <div class="ex-search">
292
- <form action="/">
293
- <Search
294
- v-model={componentValue.value}
295
- name={props.keyword}
296
- shape={"round"}
297
- label={props.label}
298
- inputAlign={props.inputAlign}
299
- disabled={props.disabled}
300
- readonly={props.readonly}
301
- placeholder={props.placeholder}
302
- onUpdate:modelValue={onUpdateValue}
303
- onSearch={onSearch}
304
- {...props.searchProps}
305
- ></Search>
306
- </form>
307
- {quickBarElem()}
308
- <Popup
309
- v-model:show={state.showFilterPopup}
310
- closeable={false}
311
- position={"bottom"}
312
- round={true}
313
- teleport={"body"}
314
- closeOnPopstate={true}
315
- class={`ex-search-popup`}
316
- safeAreaInsetBottom={true}
317
- safeAreaInsetTop={true}
318
- onClickOverlay={onCloseFilter}
319
- onClickCloseIcon={onCloseFilter}
320
- >
321
- {{ default: () => [popupHeaderElem(), fieldElems(), popupFooterElem()] }}
322
- </Popup>
323
- </div>
324
- )
325
- },
326
- })
1
+ import { cloneDeep, find, isArray, isBoolean, isFunction, isUndefined } from "lodash-es"
2
+ import { Button, Icon, Popup, Search } from "vant"
3
+ import { computed, defineComponent, nextTick, onMounted, reactive, ref, watch } from "vue"
4
+ import ExGrid from "../grid/ExGrid.jsx"
5
+ import { createExpand, createField, createQuick } from "./components"
6
+ import "./index.less"
7
+ import { useSm3, useCache } from "../../hooks"
8
+
9
+ /**
10
+ * ExSearch 搜索组件
11
+ * @version 1.0.0
12
+ */
13
+ export default defineComponent({
14
+ name: "ExSearch",
15
+ props: {
16
+ modelValue: { type: String, default: "" },
17
+
18
+ /**
19
+ * @typedef {Object} ExSearchItemConfig 搜索项
20
+ * @property {string} key 搜索项的 key
21
+ * @property {string} title 搜索项的标题
22
+ * @property {string} type 搜索项的类型
23
+ * @property {boolean} [quick] 为 true 展示为快速检索项
24
+ * @property {boolean|Object} [expandable] 搜索项是否展开
25
+ * @property {Array|Function} [options] 搜索项的选项
26
+ * @property {Object} [inputProps] 搜索项的输入框属性
27
+ * @property {Function} [beforeSubmit] 在提交前修改搜索项的值
28
+ * @property {*} [defaultValue] 搜索项的值
29
+ * @property {*} [_temp] 搜索项的临时值[内部使用]
30
+ * */
31
+
32
+ /**
33
+ *
34
+ * 搜索项的配置, 详见 [ExSearchItemConfig](#exsearchitemconfig-配置)
35
+ *
36
+ */
37
+ columns: { type: Array, default: () => [] },
38
+
39
+ /**
40
+ * 占位提示文字
41
+ */
42
+ placeholder: { type: String, default: "请输入搜索关键词" },
43
+
44
+ /**
45
+ * 名称,作为提交表单时的标识符
46
+ */
47
+ keyword: { type: String, default: "keyword" },
48
+
49
+ /**
50
+ * 搜索框左侧文本
51
+ */
52
+ label: { type: String, default: "" },
53
+
54
+ /**
55
+ * 是否将输入框设为只读状态,只读状态下无法输入内容
56
+ */
57
+ readonly: { type: Boolean, default: false },
58
+
59
+ /**
60
+ * 是否禁用输入框
61
+ */
62
+ disabled: { type: Boolean, default: false },
63
+
64
+ /**
65
+ * 输入框内容对齐方式
66
+ * @values left, right, center
67
+ */
68
+ inputAlign: { type: String, default: "left" },
69
+
70
+ /**
71
+ * 持久化,传入 localStorage 的 key,如果为 true, 将会以 URL Hash 为 key
72
+ */
73
+ persistence: { type: [Boolean, String], default: false },
74
+
75
+ /**
76
+ * @typedef {Object} SearchFormData
77
+ * @property {Object} searchForm 搜索表单
78
+ *
79
+ *
80
+ * 搜索数据处理函数
81
+ * @param {SearchFormData} data
82
+ * @return {Boolean|Object} return false会阻止提交操作,return Object会替换提交的数据
83
+ */
84
+ beforeSearch: { type: Function, default: null },
85
+
86
+ /**
87
+ * 适配器,目前仅支持 newbie
88
+ * @values newbie
89
+ */
90
+ adapter: { type: String, default: null },
91
+
92
+ /**
93
+ * [原生配置](https://vant-contrib.gitee.io/vant/#/zh-CN/search)
94
+ */
95
+ searchProps: { type: Object, default: () => ({}) },
96
+ },
97
+ emits: ["update:modelValue", "search"],
98
+ setup(props, { expose, emit }) {
99
+ const componentValue = ref(props.modelValue)
100
+
101
+ watch(
102
+ () => props.modelValue,
103
+ () => {
104
+ componentValue.value = props.modelValue
105
+ },
106
+ )
107
+
108
+ const state = reactive({
109
+ queryForm: {}, // 搜索表单
110
+ showFilterPopup: false,
111
+ })
112
+
113
+ const genPersistenceKey = (prefix) => {
114
+ if (!props.persistence) {
115
+ return null
116
+ }
117
+ prefix = prefix || ""
118
+ if (isBoolean(props.persistence)) {
119
+ return `exSearch_${prefix}` + useSm3(location.href)
120
+ }
121
+
122
+ return `exSearch_${prefix}` + useSm3(location.pathname + "_" + props.persistence)
123
+ }
124
+
125
+ const searchItemDefaultValue = (item) => {
126
+ let value = ""
127
+ //如果是展开显示的,那么默认值为空字符串
128
+ //如果展开为多选,那么默认值为 []
129
+ if (item.expandable === "multiple" || item.type === "cascade") {
130
+ value = []
131
+ }
132
+
133
+ if (item.defaultValue) {
134
+ value = isFunction(item.defaultValue) ? item.defaultValue() : item.defaultValue
135
+ }
136
+
137
+ if ((item.type === "date" || item.type === "datetime") && !value) {
138
+ return null
139
+ }
140
+
141
+ return value
142
+ }
143
+
144
+ //快速检索项
145
+ const quickColumns = computed(() => {
146
+ return props.columns.filter((item) => item.quick)
147
+ })
148
+
149
+ //表单搜索项
150
+ const fieldColumns = computed(() => {
151
+ return props.columns.filter((item) => !item.quick)
152
+ })
153
+
154
+ const initQueryForm = () => {
155
+ const form = {}
156
+
157
+ const persistenceSearchData = props.persistence ? useCache(genPersistenceKey()).get({}) : {}
158
+
159
+ props.columns.forEach((item) => {
160
+ let value
161
+ if (!isUndefined(persistenceSearchData[item.key])) {
162
+ value = persistenceSearchData[item.key]
163
+ } else {
164
+ value = searchItemDefaultValue(item)
165
+ }
166
+ form[item.key] = value
167
+ })
168
+ state.queryForm = form
169
+ }
170
+
171
+ initQueryForm()
172
+
173
+ const onUpdateValue = (value) => {
174
+ emit("update:modelValue", value)
175
+ }
176
+
177
+ const getQueryForm = () => {
178
+ const form = {}
179
+ Object.keys(state.queryForm).forEach((key) => {
180
+ let value = state.queryForm[key]
181
+
182
+ let filedItem = find(props.columns, { key })
183
+ if (filedItem && filedItem.beforeSubmit && isFunction(filedItem.beforeSubmit)) {
184
+ value = filedItem.beforeSubmit({
185
+ value,
186
+ queryForm: state.queryForm, //改成将 form 传出去,这样可以在 form 中添加参数
187
+ })
188
+ }
189
+
190
+ if (value && (!isArray(value) || value.length)) {
191
+ form[key] = value
192
+ }
193
+ })
194
+
195
+ if (componentValue.value) {
196
+ form[props.keyword] = componentValue.value
197
+ }
198
+
199
+ return form
200
+ }
201
+
202
+ const onOpenFilter = () => {
203
+ state.showFilterPopup = true
204
+ }
205
+
206
+ const onCloseFilter = () => {
207
+ state.showFilterPopup = false
208
+ }
209
+
210
+ const onSearch = () => {
211
+ nextTick(() => {
212
+ debugger
213
+ let form = cloneDeep(getQueryForm())
214
+ if (props.persistence) {
215
+ useCache(genPersistenceKey()).set(form)
216
+ }
217
+
218
+ if (props.adapter === "newbie") {
219
+ const data = {}
220
+
221
+ Object.keys(form).forEach((key) => {
222
+ const column = find(props.columns, { key })
223
+ data[key] = {
224
+ //condition
225
+ c: key === props.keyword ? "in" : column?.condition || "=", //keyword 条件固定为 include(即 like), 其它的默认为 equal
226
+ //type
227
+ t: column?.type || "i", //默认为 input
228
+ //value
229
+ v: form[key],
230
+ }
231
+ })
232
+ form = { _q: data }
233
+ }
234
+
235
+ if (props.beforeSearch && isFunction(props.beforeSearch)) {
236
+ form = props.beforeSearch({ searchForm: form })
237
+ //如果为 false 则不触发搜索
238
+ if (form !== false) {
239
+ emit("search", form)
240
+ }
241
+ } else {
242
+ emit("search", form)
243
+ }
244
+ })
245
+ }
246
+
247
+ const onFieldSearch = () => {
248
+ state.showFilterPopup = false
249
+ onSearch()
250
+ }
251
+
252
+ const onClearFields = () => {
253
+ fieldColumns.value.forEach((item) => {
254
+ state.queryForm[item.key] = searchItemDefaultValue(item)
255
+ })
256
+ }
257
+
258
+ const reset = () => {
259
+ fieldColumns.value.forEach((item) => {
260
+ state.queryForm[item.key] = searchItemDefaultValue(item)
261
+ })
262
+ quickColumns.value.forEach((item) => {
263
+ state.queryForm[item.key] = searchItemDefaultValue(item)
264
+ })
265
+ componentValue.value = ""
266
+ }
267
+
268
+ onMounted(() => {
269
+ if (props.persistence) {
270
+ emit("search", { persistence: true, ...getQueryForm() })
271
+ }
272
+ })
273
+
274
+ expose({ reset, getQueryForm })
275
+
276
+ /******************* render *********************/
277
+
278
+ const quickElems = () => {
279
+ return quickColumns.value.map((item) => createQuick(item, state.queryForm, onSearch))
280
+ }
281
+
282
+ const popupHeaderElem = () => (
283
+ <div class={"ex-search-popup__header van-hairline--bottom"}>
284
+ <h2 class={"ex-search-popup__title"}>{props.title}</h2>
285
+ <span class={"ex-search-popup__closer"}>
286
+ <Icon
287
+ name={"cross"}
288
+ class={"van-badge__wrapper van-popup__close-icon van-popup__close-icon--top-right van-haptics-feedback"}
289
+ onClick={() => (state.showFilterPopup = false)}
290
+ ></Icon>
291
+ </span>
292
+ </div>
293
+ )
294
+
295
+ const fieldElems = () => (
296
+ <div class={"ex-search-popup__content"}>
297
+ {fieldColumns.value.map((item) => (item.expandable ? createExpand(item, state.queryForm) : createField(item, state.queryForm)))}
298
+ </div>
299
+ )
300
+
301
+ const popupFooterElem = () => (
302
+ <div class={"ex-search-popup__footer van-hairline--top"}>
303
+ <ExGrid>
304
+ {{
305
+ default: () => [
306
+ <Button type={"default"} size={"small"} round={true} onClick={onClearFields}>
307
+ 清除
308
+ </Button>,
309
+ <Button type={"primary"} size={"small"} round={true} onClick={onFieldSearch}>
310
+ 搜索
311
+ </Button>,
312
+ ],
313
+ }}
314
+ </ExGrid>
315
+ </div>
316
+ )
317
+
318
+ const quickBarElem = () => {
319
+ if (!quickColumns.value?.length && !fieldColumns.value?.length) {
320
+ return null
321
+ }
322
+ return (
323
+ <div class={"ex-search__quick-bar"}>
324
+ <div class={"ex-search__quick-container"}>{quickElems()}</div>
325
+ {fieldColumns.value?.length ? (
326
+ <div class={"ex-search__filter"} onClick={onOpenFilter}>
327
+ 筛选<Icon name={"filter-o"}></Icon>
328
+ </div>
329
+ ) : null}
330
+ </div>
331
+ )
332
+ }
333
+
334
+ return () => (
335
+ <div class="ex-search">
336
+ <form action="/">
337
+ <Search
338
+ v-model={componentValue.value}
339
+ name={props.keyword}
340
+ shape={"round"}
341
+ label={props.label}
342
+ inputAlign={props.inputAlign}
343
+ disabled={props.disabled}
344
+ readonly={props.readonly}
345
+ placeholder={props.placeholder}
346
+ onUpdate:modelValue={onUpdateValue}
347
+ onSearch={onSearch}
348
+ {...props.searchProps}
349
+ ></Search>
350
+ </form>
351
+ {quickBarElem()}
352
+ <Popup
353
+ v-model:show={state.showFilterPopup}
354
+ closeable={false}
355
+ position={"bottom"}
356
+ round={true}
357
+ teleport={"body"}
358
+ closeOnPopstate={true}
359
+ class={`ex-search-popup`}
360
+ safeAreaInsetBottom={true}
361
+ safeAreaInsetTop={true}
362
+ onClickOverlay={onCloseFilter}
363
+ onClickCloseIcon={onCloseFilter}
364
+ >
365
+ {{ default: () => [popupHeaderElem(), fieldElems(), popupFooterElem()] }}
366
+ </Popup>
367
+ </div>
368
+ )
369
+ },
370
+ })