@jzt-packages/components 1.0.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 (145) hide show
  1. package/package.json +68 -0
  2. package/src/JztBackTop/index.vue +255 -0
  3. package/src/JztButtonList/index.vue +88 -0
  4. package/src/JztChart/index.vue +95 -0
  5. package/src/JztCharts/index.vue +317 -0
  6. package/src/JztClassTabs/index.vue +156 -0
  7. package/src/JztDateSelect/dateSelect.vue +186 -0
  8. package/src/JztDateSelect/dateType.vue +54 -0
  9. package/src/JztDateSelect/index.ts +135 -0
  10. package/src/JztDateSelect/interface/index.ts +13 -0
  11. package/src/JztDialog/index.vue +249 -0
  12. package/src/JztEllipsisTooltip/index.vue +61 -0
  13. package/src/JztEmpty/index.vue +45 -0
  14. package/src/JztErrorPage/403.vue +30 -0
  15. package/src/JztErrorPage/404.vue +19 -0
  16. package/src/JztErrorPage/500.vue +18 -0
  17. package/src/JztErrorPage/assets/401.png +0 -0
  18. package/src/JztErrorPage/assets/403.png +0 -0
  19. package/src/JztErrorPage/assets/404.png +0 -0
  20. package/src/JztErrorPage/assets/500.png +0 -0
  21. package/src/JztErrorPage/index.scss +35 -0
  22. package/src/JztErrorPage/index.vue +35 -0
  23. package/src/JztFilePreview/components/pdfViewer.vue +221 -0
  24. package/src/JztFilePreview/hooks/useImageMethod.ts +256 -0
  25. package/src/JztFilePreview/index.scss +171 -0
  26. package/src/JztFilePreview/index.vue +68 -0
  27. package/src/JztFilePreview/interface/index.ts +18 -0
  28. package/src/JztFilePreview/previewFile.vue +371 -0
  29. package/src/JztFormGrid/README.md +520 -0
  30. package/src/JztFormGrid/components/formItem.vue +209 -0
  31. package/src/JztFormGrid/components/formItemValue.vue +384 -0
  32. package/src/JztFormGrid/components/showDetailForm.vue +172 -0
  33. package/src/JztFormGrid/index.scss +60 -0
  34. package/src/JztFormGrid/index.vue +513 -0
  35. package/src/JztFormGrid/interface/index.ts +106 -0
  36. package/src/JztGrid/components/GridItem.vue +68 -0
  37. package/src/JztGrid/index.vue +179 -0
  38. package/src/JztGrid/interface/index.ts +6 -0
  39. package/src/JztImportExcel/assets/delete.png +0 -0
  40. package/src/JztImportExcel/index.scss +46 -0
  41. package/src/JztImportExcel/index.vue +430 -0
  42. package/src/JztImportExcel/interface/index.ts +25 -0
  43. package/src/JztLabelTitle/index.vue +65 -0
  44. package/src/JztLeftRightMode/components/CollapseButton.vue +80 -0
  45. package/src/JztLeftRightMode/components/LeftCard.vue +203 -0
  46. package/src/JztLeftRightMode/components/LeftLayout.vue +173 -0
  47. package/src/JztLeftRightMode/components/RightHeader.vue +186 -0
  48. package/src/JztLeftRightMode/components/RightLayout.vue +235 -0
  49. package/src/JztLeftRightMode/components/RightTableHeader.vue +43 -0
  50. package/src/JztLeftRightMode/hooks/useCollapse.ts +17 -0
  51. package/src/JztLeftRightMode/hooks/useDefaultProps.ts +19 -0
  52. package/src/JztLeftRightMode/hooks/useLeftLayout.ts +201 -0
  53. package/src/JztLeftRightMode/hooks/useMode.ts +20 -0
  54. package/src/JztLeftRightMode/hooks/usePrevNext.ts +60 -0
  55. package/src/JztLeftRightMode/hooks/useRightLayout.ts +215 -0
  56. package/src/JztLeftRightMode/hooks/useSlots.ts +15 -0
  57. package/src/JztLeftRightMode/index.ts +3 -0
  58. package/src/JztLeftRightMode/index.vue +494 -0
  59. package/src/JztLeftRightMode/types/index.ts +457 -0
  60. package/src/JztLoading/fullScreen.ts +45 -0
  61. package/src/JztLoading/index.scss +67 -0
  62. package/src/JztLoading/index.vue +18 -0
  63. package/src/JztLogin/components/LoginFooter.vue +17 -0
  64. package/src/JztLogin/components/LoginForm.vue +99 -0
  65. package/src/JztLogin/hooks/useLogin.ts +186 -0
  66. package/src/JztLogin/index.scss +142 -0
  67. package/src/JztLogin/index.vue +31 -0
  68. package/src/JztLogin/interface/index.ts +47 -0
  69. package/src/JztNumericalRange/index.vue +81 -0
  70. package/src/JztPageCard/comm/datePicker.vue +151 -0
  71. package/src/JztPageCard/comm/details.vue +60 -0
  72. package/src/JztPageCard/comm/export.vue +24 -0
  73. package/src/JztPageCard/comm/tabs.vue +94 -0
  74. package/src/JztPageCard/comm/tooltip.vue +31 -0
  75. package/src/JztPageCard/index.vue +287 -0
  76. package/src/JztPagination/index.vue +70 -0
  77. package/src/JztProductInfo/components/imagePreview.vue +275 -0
  78. package/src/JztProductInfo/components/qxUnique.vue +101 -0
  79. package/src/JztProductInfo/components/records.vue +265 -0
  80. package/src/JztProductInfo/hooks/useParams.ts +143 -0
  81. package/src/JztProductInfo/hooks/useQxUnique.tsx +466 -0
  82. package/src/JztProductInfo/images/defaultProduct.png +0 -0
  83. package/src/JztProductInfo/index.ts +116 -0
  84. package/src/JztProductInfo/index.vue +108 -0
  85. package/src/JztProductInfo/interface/index.ts +15 -0
  86. package/src/JztQueryDetailTable/index.scss +100 -0
  87. package/src/JztQueryDetailTable/index.vue +400 -0
  88. package/src/JztQueryDetailTable/interface/index.ts +10 -0
  89. package/src/JztQueryTable/QueryTable /345/212/237/350/203/275.md" +1580 -0
  90. package/src/JztQueryTable/README.md +567 -0
  91. package/src/JztQueryTable/components/ColSetting.vue +67 -0
  92. package/src/JztQueryTable/components/ColumnsSetting.vue +404 -0
  93. package/src/JztQueryTable/components/ColumnsSetting1.vue +220 -0
  94. package/src/JztQueryTable/components/DeployToAccountLevelSetting.vue +351 -0
  95. package/src/JztQueryTable/components/Pagination.vue +54 -0
  96. package/src/JztQueryTable/components/TableColumn.vue +109 -0
  97. package/src/JztQueryTable/const.ts +1 -0
  98. package/src/JztQueryTable/hooks/useQueryTable.ts +194 -0
  99. package/src/JztQueryTable/hooks/useSelection.ts +47 -0
  100. package/src/JztQueryTable/hooks/useTableSetting.ts +197 -0
  101. package/src/JztQueryTable/hooks/useTemplate.ts +127 -0
  102. package/src/JztQueryTable/index.scss +91 -0
  103. package/src/JztQueryTable/index.vue +1445 -0
  104. package/src/JztQueryTable/interface/index.ts +185 -0
  105. package/src/JztRegionSelect/index.vue +134 -0
  106. package/src/JztSearchForm/components/SearchFormItem.vue +473 -0
  107. package/src/JztSearchForm/index.vue +530 -0
  108. package/src/JztSearchForm/interface/index.ts +100 -0
  109. package/src/JztSelectFilter/index.scss +63 -0
  110. package/src/JztSelectFilter/index.vue +110 -0
  111. package/src/JztSelectTable/index.vue +257 -0
  112. package/src/JztTable/index.scss +72 -0
  113. package/src/JztTable/index.vue +353 -0
  114. package/src/JztTable/interface/index.ts +1 -0
  115. package/src/JztTime/comm/agencySelect.vue +112 -0
  116. package/src/JztTime/comm/collapseRow.vue +132 -0
  117. package/src/JztTime/comm/dateSelect.vue +292 -0
  118. package/src/JztTime/comm/deptSelect.vue +193 -0
  119. package/src/JztTime/comm/typeSelect.vue +97 -0
  120. package/src/JztTime/index.ts +216 -0
  121. package/src/JztTime/index.vue +303 -0
  122. package/src/JztTime/interface/index.ts +23 -0
  123. package/src/JztTreeFilter/index.scss +44 -0
  124. package/src/JztTreeFilter/index.vue +177 -0
  125. package/src/JztUploadFile/interface/index.ts +21 -0
  126. package/src/JztUploadFile/multiple.scss +215 -0
  127. package/src/JztUploadFile/multiple.vue +318 -0
  128. package/src/JztUploadFile/single.scss +226 -0
  129. package/src/JztUploadFile/single.vue +274 -0
  130. package/src/JztUploadImg/Img.vue +294 -0
  131. package/src/JztUploadImg/Imgs.vue +411 -0
  132. package/src/JztUploadImg/index.scss +138 -0
  133. package/src/JztUploadImg/interface/index.ts +22 -0
  134. package/src/SelectIcon/index.scss +39 -0
  135. package/src/SelectIcon/index.vue +106 -0
  136. package/src/SvgIcon/index.vue +22 -0
  137. package/src/hooks/useAuthButtons.ts +58 -0
  138. package/src/hooks/useFormByUserType.ts +90 -0
  139. package/src/hooks/useTableEvents.ts +30 -0
  140. package/src/hooks/useUploadFileHook.ts +262 -0
  141. package/src/index.ts +91 -0
  142. package/src/typings/global.d.ts +101 -0
  143. package/src/utils/index.ts +107 -0
  144. package/src/utils/tree.ts +57 -0
  145. package/tsconfig.json +45 -0
@@ -0,0 +1,530 @@
1
+ <template>
2
+ <div v-if="queryItemList.length" class="table-search" :class="[isCard ? 'spd-card' : 'noCardGap',validQuery ? 'validQueryForm' : '']">
3
+ <slot name="formTopSlot"></slot>
4
+ <el-form ref="formRef" :model="searchParam" label-width="auto">
5
+ <div v-if="customForm" style="display: flex; flex-wrap: wrap">
6
+ <div
7
+ v-for="(item, index) in queryItemList"
8
+ :key="item.prop"
9
+ v-bind="getResponsive(item)"
10
+ :index="index"
11
+ :style="{
12
+ display: 'inline-block',
13
+ width: item.search?.width ?? '350px',
14
+ marginRight:'15px',
15
+ ...item?.search?.style
16
+ }"
17
+ >
18
+ <el-form-item
19
+ :prop="item.prop"
20
+ :rules="item.rules"
21
+ :label-width="item.search?.labelWidth"
22
+ >
23
+ <template #label>
24
+ <el-space :size="4" style="height: 100%;">
25
+ <component v-if="item?.labelRender" :is="item?.labelRender" />
26
+ <span
27
+ v-else
28
+ style="line-height: 20px; text-align: right"
29
+ :style="{
30
+ 'max-width': item.search?.labelWidth
31
+ ? item.search?.labelWidth
32
+ : '106px',
33
+ width: item.search?.labelWidth
34
+ ? item.search?.labelWidth
35
+ : '',
36
+ }"
37
+ >{{ `${item.label}` }}</span
38
+ >
39
+ <!-- <span v-if="item?.label">:</span> -->
40
+ <el-tooltip
41
+ v-if="item.search?.tooltip"
42
+ effect="dark"
43
+ :content="item.search?.tooltip"
44
+ placement="top"
45
+ >
46
+ <el-icon><Warning /></el-icon>
47
+ </el-tooltip>
48
+ </el-space>
49
+ </template>
50
+ <SearchFormItem
51
+ :query-item="item"
52
+ :search-param="searchParam"
53
+ :show-param="showParam"
54
+ @getCascaderValue="getCascaderValue"
55
+ @handleItemClear="handleItemClear"
56
+ :teleported="false"
57
+ @handle-search="handleSearch"
58
+ />
59
+ </el-form-item>
60
+ </div>
61
+ <div class="mb8">
62
+ <slot name="rightBtn" class="rightBtn">
63
+ <div v-if="showQueryBtn || showResetBtn" class="operation mr5">
64
+ <el-button v-if="showQueryBtn" type="primary" @click="search">
65
+ 查询
66
+ </el-button>
67
+ <el-button v-if="showResetBtn" plain @click="reset">重置</el-button>
68
+ </div>
69
+ </slot>
70
+ </div>
71
+ </div>
72
+ <JztGrid
73
+ v-else
74
+ ref="gridRef"
75
+ :collapsed="allowCollapsed && isCollapsed"
76
+ :gap="[15, 0]"
77
+ :cols="searchCol"
78
+ @hiddenIndex="hiddenIndex"
79
+ >
80
+
81
+ <GridItem
82
+ v-for="(item, index) in queryItemList"
83
+ :key="item.prop"
84
+ v-bind="getResponsive(item)"
85
+ :index="index"
86
+ >
87
+
88
+ <el-form-item
89
+ :prop="item.prop"
90
+ :rules="item.rules"
91
+ :label-width="item.search?.labelWidth"
92
+ >
93
+
94
+ <template #label v-if="item.search?.isShowLabel!==false">
95
+ <el-space :size="4" style="height: 100%">
96
+ <component v-if="item?.labelRender" :is="item?.labelRender" />
97
+ <span
98
+ v-else
99
+ style="line-height: 20px; text-align: right"
100
+ :style="{
101
+ 'max-width': item.search?.labelWidth
102
+ ? item.search?.labelWidth
103
+ : '106px',
104
+ width: item.search?.labelWidth
105
+ ? item.search?.labelWidth
106
+ : '',
107
+ }"
108
+ >{{ `${item.label}` }}</span
109
+ >
110
+ <el-tooltip
111
+ v-if="item.search?.tooltip"
112
+ effect="dark"
113
+ :content="item.search?.tooltip"
114
+ placement="top"
115
+ >
116
+ <el-icon><Warning /></el-icon>
117
+ </el-tooltip>
118
+ </el-space>
119
+ </template>
120
+ <SearchFormItem
121
+ :query-item="item"
122
+ :search-param="searchParam"
123
+ :show-param="showParam"
124
+ @getCascaderValue="getCascaderValue"
125
+ @handleItemClear="handleItemClear"
126
+ @handle-search="handleSearch"
127
+ />
128
+ </el-form-item>
129
+ </GridItem>
130
+ <GridItem v-if="showQueryBtn || showResetBtn" :suffix="suffix">
131
+ <div class="operation mb8" :class="{ 'follow-btn': !suffix }">
132
+ <el-button v-if="showQueryBtn" type="primary" @click="search">查询</el-button>
133
+ <el-button v-if="showResetBtn" type="primary" plain @click="reset">重置</el-button>
134
+ <div v-if="slots.rightBtn" class="ml12">
135
+ <slot name="rightBtn"></slot>
136
+ </div>
137
+ <el-button
138
+ v-if="allowCollapsed && showCollapse"
139
+ type="primary"
140
+ link
141
+ class="search-isOpen"
142
+ @click="isCollapsed = !isCollapsed"
143
+ >
144
+ {{ isCollapsed ? "展开" : "收起" }}
145
+ <el-icon class="el-icon--right">
146
+ <component :is="isCollapsed ? ArrowDown : ArrowUp"></component>
147
+ </el-icon>
148
+ </el-button>
149
+ </div>
150
+ </GridItem>
151
+ </JztGrid>
152
+ </el-form>
153
+ </div>
154
+ </template>
155
+ <script setup lang="ts" name="SearchForm">
156
+ import { computed, ref, unref, provide, useSlots } from "vue";
157
+ import { QueryItemsProps } from "./interface";
158
+ import { BreakPoint } from "../JztGrid/interface";
159
+ import { ArrowDown, ArrowUp } from "@element-plus/icons-vue";
160
+ import SearchFormItem from "./components/SearchFormItem.vue";
161
+ import JztGrid from "../JztGrid/index.vue";
162
+ import GridItem from "../JztGrid/components/GridItem.vue";
163
+ import type { FormInstance } from "element-plus";
164
+ import { debounce } from 'lodash-es';
165
+ import {
166
+ useSetEnumMap,
167
+ useSetCascaderEnumMap,
168
+ } from "../hooks/useFormByUserType";
169
+
170
+ interface ProTableProps {
171
+ queryItems?: QueryItemsProps[]; // 搜索配置列
172
+ searchParam?: { [key: string]: any }; // 搜索参数
173
+ showParam?: { [key: string]: any }; // 查看参数
174
+ searchInitParam?: { [key: string]: any }; // 搜索默认参数
175
+ searchCol: number | Record<BreakPoint, number>;
176
+ search: () => void; // 搜索方法
177
+ reset: (params: any) => void; // 重置方法
178
+ allowCollapsed?: boolean; // 是否允许折叠
179
+ collapsed?: boolean; // 是否默认折叠
180
+ showQueryBtn?: boolean; // 是否展示查询重构按钮
181
+ showResetBtn?: boolean; // 是否展示重置按钮
182
+ customForm?: boolean;
183
+ suffix?: boolean; // 按钮是否总是在最后(不跟随)
184
+ isCard?: boolean // 是否需要card样式,某下弹框不需要的话 设置false
185
+ validQuery?: boolean // 是否需要校验表单
186
+ }
187
+
188
+ // 默认值
189
+ const props = withDefaults(defineProps<ProTableProps>(), {
190
+ queryItems: () => [],
191
+ searchParam: () => ({}),
192
+ searchInitParam: () => ({}),
193
+ allowCollapsed: true,
194
+ collapsed: true,
195
+ showQueryBtn: true,
196
+ showResetBtn: true,
197
+ customForm: false,
198
+ suffix: false,
199
+ isCard: true,
200
+ validQuery: false,
201
+ });
202
+ const slots = useSlots()
203
+ // 查询列表项
204
+ const queryItemList = computed(() => {
205
+ const list = [] as QueryItemsProps[];
206
+ props.queryItems.forEach(async (item: QueryItemsProps) => {
207
+ if (item.isShow !== false) {
208
+ list.push(item);
209
+ } else {
210
+ // 动态隐藏时 清空搜索参数
211
+ // props.searchParam[item.prop as keyof typeof props.searchParam] = null
212
+ // emit('update:searchParam', props.searchParam)
213
+ }
214
+ if (item.enum)
215
+ // 设置 enumMap 处理字典数据
216
+ // await setEnumMap(item)
217
+ await useSetEnumMap({
218
+ queryItem: item,
219
+ enumMap,
220
+ callBack: setSelectFirstValue,
221
+ isShow: false,
222
+ });
223
+ });
224
+ return list;
225
+ });
226
+
227
+ const isCollapsed = ref(props.collapsed);
228
+
229
+ // 定义 enumMap 存储 enum 值(避免异步请求无法格式化单元格内容 || 无法填充搜索下拉选择)
230
+ const enumMap = ref(new Map<string, { [key: string]: any }[]>());
231
+ // 扁平化 columns 的方法 处理字典数据
232
+ // const flatColumnsFunc = (queryItems: QueryItemsProps[]) => {
233
+ // queryItems.forEach(async item => {
234
+ // if (item.enum) {
235
+ // // 设置 enumMap
236
+ // await setEnumMap(item)
237
+ // }
238
+ // })
239
+ // }
240
+
241
+ // const setEnumMap = async ({ prop, isAwait, enum: enumValue, isSetFirstValue, fieldNames }: QueryItemsProps) => {
242
+ // if (!enumValue) return
243
+ // // 是否接口等待
244
+ // if (isAwait) return
245
+ // // 如果当前 enumMap 存在相同的值 return
246
+ // if (enumMap.value.has(prop!) && (typeof enumValue === 'function' || enumMap.value.get(prop!) === enumValue)) return
247
+ // // 当前 enum 为静态数据,则直接存储到 enumMap
248
+ // if (typeof enumValue !== 'function') return enumMap.value.set(prop!, unref(enumValue!))
249
+ // // 为了防止接口执行慢,而存储慢,导致重复请求,所以预先存储为[],接口返回后再二次存储
250
+ // enumMap.value.set(prop!, [])
251
+ // // 当前 enum 为后台数据需要请求数据,则调用该请求接口,并存储到 enumMap
252
+ // const { data, result } = await enumValue()
253
+ // let list = data || result || []
254
+ // enumMap.value.set(prop!, list)
255
+ // if (useFormSetByUserType(isSetFirstValue, prop)) {
256
+ // setSelectFirstValue(prop, list[0], fieldNames)
257
+ // }
258
+ // }
259
+ // change 获取接口数据
260
+ // const setCascaderEnumMap = async (
261
+ // prop,
262
+ // { enum: enumValue, isSetFirstValue, fieldNames }: QueryItemsProps,
263
+ // val: string
264
+ // ) => {
265
+ // if (!enumValue) return
266
+
267
+ // // 如果当前 enumMap 存在相同的值 也不return 根据change实时获取
268
+ // // 为了防止接口执行慢,而存储慢,导致重复请求,所以预先存储为[],接口返回后再二次存储
269
+ // if (typeof enumValue !== 'function') return enumMap.value.set(prop!, unref(enumValue!))
270
+ // enumMap.value.set(prop!, [])
271
+ // // 当前 enum 为后台数据需要请求数据,则调用该请求接口,并存储到 enumMap
272
+ // const { data, result } = await enumValue(val, props.searchParam)
273
+ // let list = data || result || []
274
+ // enumMap.value.set(prop!, list)
275
+ // if (useFormSetByUserType(isSetFirstValue, prop)) {
276
+ // setSelectFirstValue(prop, list[0], fieldNames)
277
+ // }
278
+ // }
279
+ // 注入 enumMap
280
+ provide("enumMap", enumMap);
281
+
282
+ const waitFirstValueCount = ref<number>(0) //需要等待的次数
283
+ // 处理默认选中第一条数据
284
+ const setSelectFirstValue = (prop, firstItem, fieldNames, queryItem) => {
285
+ if (prop && firstItem) {
286
+ const itemValue = fieldNames?.value || 'value'
287
+ if (queryItem.search?.props?.multiple) {
288
+ props.searchParam[prop] = [firstItem[itemValue]]
289
+ props.searchInitParam[prop] = [firstItem[itemValue]]
290
+ }else{
291
+ props.searchParam[prop] = firstItem[itemValue]
292
+ props.searchInitParam[prop] = firstItem[itemValue]
293
+ }
294
+ if (queryItem) {
295
+ if (queryItem.search?.props?.multiple) {
296
+ queryItem['defaultValue'] = queryItem?.['defaultValue'] || [firstItem[itemValue]]
297
+ } else {
298
+ queryItem['defaultValue'] = queryItem?.['defaultValue'] || firstItem[itemValue]
299
+ }
300
+ }
301
+ emit("update:searchParam", props.searchParam);
302
+ emit("update:searchInitParam", props.searchInitParam);
303
+ }
304
+ waitFirstValueCount.value++;
305
+ emit("setFirstValue", waitFirstValueCount.value);
306
+ };
307
+ const emit = defineEmits(["update:searchParam", "setFirstValue",'update:searchInitParam']);
308
+ // 获取getCascader数据
309
+ const getCascaderValue = (val, isClear: boolean = false) => {
310
+ const allFlatQuery = props.queryItems;
311
+ if (val.cascader && val.cascader.length) {
312
+ val.cascader.forEach((cascader) => {
313
+ if (isClear) {
314
+ // 递归处理需要清除的数据
315
+ clearNextItem(cascader, val)
316
+ // const index = allFlatQuery.findIndex(item => item.prop === cascader)
317
+ // if (index === -1) return
318
+ // const queryItem = allFlatQuery[index]
319
+ // props.searchParam[queryItem.prop] = null // 让下一级的表单数据为空
320
+ // enumMap.value.set(queryItem.prop, []) // 让下一级的下拉数据清空
321
+ } else if (props.searchParam[val.prop]) {
322
+ const index = allFlatQuery.findIndex((item) => item.prop === cascader);
323
+ if (index === -1) return;
324
+ const queryItem = allFlatQuery[index];
325
+ // 为了解决 在SearchFormItem中 监听也会触发,导致多次接口调用的问题
326
+ // if (queryItem.isAwait) {
327
+ // 有值才会去掉接口,处理clearable 不清空问题
328
+ useSetCascaderEnumMap({
329
+ prevProp: val.prop,
330
+ queryItem,
331
+ enumMap,
332
+ searchParam: props.searchParam,
333
+ callBack: setSelectFirstValue,
334
+ });
335
+ // setCascaderEnumMap(queryItem.prop, queryItem, props.searchParam[val.prop])
336
+ // }
337
+ }
338
+ });
339
+ }
340
+ emit("update:searchParam", props.searchParam);
341
+ };
342
+ // 递归处理需要清除的数据(例如省市区三级的情况,清空/更改省->清空:市与区)
343
+ const clearNextItem = (cascader) => {
344
+ if (!cascader || !cascader.length) return;
345
+ const allFlatQuery = props.queryItems;
346
+ const index = allFlatQuery.findIndex((item) => item.prop === cascader);
347
+ if (index === -1) return;
348
+ const queryItem = allFlatQuery[index];
349
+ props.searchParam[queryItem.prop] = null; // 让下一级的表单数据为空
350
+ enumMap.value.set(queryItem.prop, []); // 让下一级的下拉数据清空
351
+ if (queryItem.cascader && queryItem.cascader.length) {
352
+ queryItem.cascader.forEach(item => {
353
+ clearNextItem(item)
354
+ })
355
+ }
356
+ if (!queryItem.isAwait && queryItem.isClearSearch) {
357
+ // 说明 清空后 也需要查询,清空是空值查询
358
+ useSetCascaderEnumMap({
359
+ prevProp: val.prop,
360
+ queryItem,
361
+ enumMap,
362
+ searchParam: props.searchParam,
363
+ callBack: setSelectFirstValue
364
+ })
365
+ }
366
+ };
367
+ // flatColumnsFunc(props.queryItems);
368
+
369
+ // 清空也触发接口
370
+ const handleItemClear = val => {
371
+ const allFlatQuery = props.queryItems
372
+ val.cascader?.forEach(cascader => {
373
+ const index = allFlatQuery.findIndex(item => item.prop === cascader)
374
+ if (index === -1) return
375
+ const queryItem = allFlatQuery[index]
376
+ if (queryItem?.isClearSearch) {
377
+ useSetCascaderEnumMap({
378
+ prevProp: val.prop,
379
+ queryItem,
380
+ enumMap,
381
+ searchParam: props.searchParam,
382
+ callBack: setSelectFirstValue
383
+ })
384
+ }
385
+ })
386
+ }
387
+ // 获取响应式设置
388
+ const getResponsive = (item: QueryItemsProps) => {
389
+ return {
390
+ span: item.search?.span,
391
+ offset: item.search?.offset ?? 0,
392
+ xs: item.search?.xs,
393
+ sm: item.search?.sm,
394
+ md: item.search?.md,
395
+ lg: item.search?.lg,
396
+ xl: item.search?.xl,
397
+ };
398
+ };
399
+ // 查询表单实例
400
+ const formRef = ref();
401
+ // const searchHandler = async () => {
402
+ // const valid = await validateForm;
403
+ // if (!valid) return;
404
+ // props.search(props.searchParam);
405
+ // };
406
+
407
+ const validateForm = async () => {
408
+ // if (!props.queryItems || !props.queryItems.length) return true;
409
+ const formEl = formRef.value as FormInstance | undefined;
410
+ if (!formEl) return true;
411
+ try {
412
+ await formEl.validate();
413
+ return true;
414
+ } catch (error) {
415
+ console.log(error);
416
+ return false;
417
+ }
418
+ };
419
+
420
+ // 是否默认折叠搜索项
421
+ // const collapsed = ref(true);
422
+
423
+ // 获取响应式断点
424
+ const gridRef = ref();
425
+ // const breakPoint = computed<BreakPoint>(() => gridRef.value?.breakPoint);
426
+
427
+ const showCollapse = ref(false);
428
+
429
+ const hiddenIndex = (hiddenIndex) => {
430
+ showCollapse.value = hiddenIndex !== -1;
431
+ };
432
+ const handleSearch = debounce(() => {
433
+ props.search()
434
+ },
435
+ 500,
436
+ { leading: true }
437
+ )
438
+
439
+ // 判断是否显示 展开/合并 按钮
440
+ // const showCollapse = computed(() => {
441
+ // let show = false;
442
+ // props.queryItems.reduce((prev, current) => {
443
+ // prev +=
444
+ // (current.search![breakPoint.value]?.span ?? current.search?.span ?? 1) +
445
+ // (current.search![breakPoint.value]?.offset ??
446
+ // current.search?.offset ??
447
+ // 0);
448
+ // if (typeof props.searchCol !== "number") {
449
+ // if (prev >= props.searchCol[breakPoint.value]) show = true;
450
+ // } else {
451
+ // if (prev >= props.searchCol) show = true;
452
+ // }
453
+ // return prev;
454
+ // }, 0);
455
+ // return show;
456
+ // });
457
+
458
+ defineExpose({
459
+ validateForm,
460
+ });
461
+ </script>
462
+
463
+ <style lang="scss" scoped>
464
+ // :deep(.el-form-item__label) {
465
+ // text-align: center;
466
+ // height: 100%;
467
+ // }
468
+ .spd-card{
469
+ box-shadow: none !important;
470
+ }
471
+ /* // table-search 表格搜索样式 */
472
+ .table-search.validQueryForm {
473
+ .el-form .el-form-item {
474
+ margin-bottom: 13px;
475
+ }
476
+ }
477
+ .table-search {
478
+ padding: 12px 12px 4px;
479
+ margin-bottom: 10px;
480
+ .el-form {
481
+ .el-form-item__content > * {
482
+ width: 100%;
483
+ }
484
+ .el-form-item {
485
+ margin-bottom: 11px;
486
+ :deep(.el-form-item__label) {
487
+ .el-select__wrapper {
488
+ padding: 2px 6px;
489
+ .el-select__placeholder {
490
+ color: #333 !important;
491
+ }
492
+ }
493
+ }
494
+
495
+ // &.is-error {
496
+ // }
497
+ // &.is-required {
498
+ // [class*='__wrapper'] {
499
+ // background-color: #ffebea !important;
500
+ // }
501
+ // }
502
+ // .el-form-item__error {
503
+ // display: none;
504
+ // }
505
+ :deep(.el-form-item__error) {
506
+ display: none;
507
+ padding-top: 1px;
508
+ font-size: 12px;
509
+ }
510
+ }
511
+
512
+ // 去除时间选择器上下 padding
513
+ .el-range-editor.el-input__wrapper {
514
+ padding: 0 10px;
515
+ }
516
+ }
517
+ .operation {
518
+ display: flex;
519
+ align-items: center;
520
+ justify-content: flex-end;
521
+ &.follow-btn{
522
+ justify-content: flex-start;
523
+ }
524
+ }
525
+ }
526
+
527
+ .noCardGap{
528
+ margin-bottom: 0;
529
+ }
530
+ </style>
@@ -0,0 +1,100 @@
1
+ import { VNode, Ref } from "vue";
2
+ import { BreakPoint, Responsive } from "../../JztGrid/interface";
3
+ import { EnumProps } from "../../JztQueryTable/interface/index";
4
+ import { TableColumnCtx } from "element-plus/es/components/table/src/table-column/defaults";
5
+
6
+ export type SearchProps = {
7
+ el?: SearchType; // 当前项搜索框的类型
8
+ label?: string; // 当前项搜索框的 label
9
+ props?: any; // 搜索项参数,根据 element plus 官方文档来传递,该属性所有值会透传到组件
10
+ events?:any; // 搜索项事件,根据 element plus 官方文档来传递,该属性所有值会透传到组件
11
+ key?: string; // 当搜索项 key 不为 prop 属性时,可通过 key 指定
12
+ tooltip?: string; // 搜索提示
13
+ order?: number; // 搜索项排序(从大到小)
14
+ span?: number; // 搜索项所占用的列数,默认为 1 列
15
+ offset?: number; // 搜索字段左侧偏移列数
16
+ defaultValue?: string | number | boolean | any[] | Ref<any>; // 搜索项默认值
17
+ render?: (scope: SearchRenderScope) => VNode; // 自定义搜索内容渲染(tsx语法)
18
+ dictType?: string | number; // 字典ID
19
+ isSetEmptyData?: boolean; // 是否设置空数据 适用场景例如:供应商 不选择时:页面为空,实际接口需要默认传 GUIDNoneValue: 00000000-0000-0000-0000-000000000000
20
+ emptyNullValue?: any; // 空数据默认值,默认值是GUIDNoneValue
21
+ startField?: string; // 数组开始字段
22
+ endField?: string; // 数组结束字段
23
+ labelWidth?: string | number; // label宽度 -- 仅仅在特殊情况才建议使用
24
+ width?: string; // 当前项搜索框的宽度 -- 仅仅在特殊情况下才生效
25
+ allowCheckLevel?: number; // 允许都选的长度层级,未达到的话,就说明此条数没有固定的子节点,场景: 医疗机构->仓库->科室,只允许选择科室,但是没有科室的医疗机构仓库 会正常返回,此时就不允许选择 第一层,第二层
26
+ hasCheckbox?: boolean; // 是否显示全选反选
27
+ style?: object // 样式
28
+ isEnter?: boolean; // 是否开启回车搜索
29
+ } & Partial<Record<BreakPoint, Responsive>>;
30
+
31
+ export type appendSlotProps = {
32
+ show?: boolean; // 是否显示
33
+ type?: string; // 按钮类型 primary border
34
+ }
35
+ export interface QueryItemsProps<T = any> {
36
+ label?: string;
37
+ labelRender?: () => VNode | string; // 自定义单元格标题渲染(tsx语法)
38
+ rightRender?: () => VNode | string // 自定义单元格标题渲染(tsx语法)
39
+ prop: keyof T;
40
+ enumKey?: keyof T;
41
+ el?: string; // 组件
42
+ // type?: TypeProps; // 列类型
43
+ isShow?: boolean | Ref<boolean>; // 是否显示在表格当中
44
+ // isHide?: boolean | Ref<boolean>; // 是否隐藏
45
+ search?: SearchProps | undefined; // 搜索项配置
46
+ enum?:
47
+ | EnumProps[]
48
+ | Ref<EnumProps[]>
49
+ | ((val?: any, params?: any) => Promise<any>); // 枚举字典
50
+ fieldNames?: FieldNamesProps; // 指定 label && value && children 的 key 值
51
+ // render?: (scope: RenderScope<T>) => VNode | string; // 自定义单元格内容渲染(tsx语法)
52
+ rules?: any[];
53
+ // options?: any[];
54
+ cascader?: string[];
55
+ isAwait?: boolean; // 是否需要等待请求接口
56
+ change?: (scope: any) => any; // change事件事件
57
+ isSetFirstValue?: boolean; // 是否需要默认选中第一个数据
58
+ appendProps?: appendSlotProps // 输入框插槽
59
+ isOnlySetValue?: boolean; // 是否只有一个数据时,默认选中
60
+ isClearSearch?: boolean; // 是否为空时也请求接口(和cascader)搭配使用,一般用于不设置isAwait的场景,前一个参数为非必填
61
+ }
62
+
63
+ export type FieldNamesProps = {
64
+ label: string;
65
+ value: string;
66
+ children?: string;
67
+ };
68
+
69
+ export type SearchType =
70
+ | "el-input"
71
+ | "el-input-number"
72
+ | "el-select"
73
+ | "el-select-v2"
74
+ | "el-tree-select"
75
+ | "el-cascader"
76
+ | "el-date-picker"
77
+ | "el-time-picker"
78
+ | "el-time-select"
79
+ | "el-switch"
80
+ | "el-slider"
81
+ | "el-radio-group"
82
+ | "el-checkbox-group"
83
+ | "JztDictionary"
84
+ | 'JztDateType'
85
+ | 'JztDateSelect';
86
+
87
+ export type SearchRenderScope = {
88
+ searchParam: { [key: string]: any };
89
+ placeholder: string;
90
+ clearable: boolean;
91
+ options: EnumProps[];
92
+ data: EnumProps[];
93
+ };
94
+
95
+ export type RenderScope<T> = {
96
+ row: T;
97
+ $index: number;
98
+ column: TableColumnCtx<T>;
99
+ [key: string]: any;
100
+ };
@@ -0,0 +1,63 @@
1
+ .select-filter {
2
+ width: 100%;
3
+ .select-filter-item {
4
+ display: flex;
5
+ align-items: center;
6
+ border-bottom: 1px dashed var(--el-border-color-light);
7
+ &:last-child {
8
+ border-bottom: none;
9
+ }
10
+ .select-filter-item-title {
11
+ margin-top: -2px;
12
+ span {
13
+ font-size: 14px;
14
+ color: var(--el-text-color-regular);
15
+ white-space: nowrap;
16
+ }
17
+ }
18
+ .select-filter-notData {
19
+ margin: 18px 0;
20
+ font-size: 14px;
21
+ color: var(--el-text-color-regular);
22
+ }
23
+ .select-filter-list {
24
+ display: flex;
25
+ flex: 1;
26
+ padding: 0;
27
+ margin: 13px 0;
28
+ li {
29
+ display: flex;
30
+ align-items: center;
31
+ padding: 5px 15px;
32
+ margin-right: 16px;
33
+ font-size: 13px;
34
+ color: var(--el-color-primary);
35
+ list-style: none;
36
+ cursor: pointer;
37
+ background: var(--el-color-primary-light-9);
38
+ border: 1px solid var(--el-color-primary-light-5);
39
+ border-radius: 32px;
40
+ &:hover {
41
+ color: #ffffff;
42
+ background: var(--el-color-primary);
43
+ border-color: var(--el-color-primary);
44
+ transition: 0.1s;
45
+ }
46
+ &.active {
47
+ font-weight: bold;
48
+ color: #ffffff;
49
+ background: var(--el-color-primary);
50
+ border-color: var(--el-color-primary);
51
+ }
52
+ .el-icon {
53
+ margin-right: 4px;
54
+ font-size: 16px;
55
+ font-weight: bold;
56
+ }
57
+ span {
58
+ white-space: nowrap;
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }