@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.
- package/package.json +68 -0
- package/src/JztBackTop/index.vue +255 -0
- package/src/JztButtonList/index.vue +88 -0
- package/src/JztChart/index.vue +95 -0
- package/src/JztCharts/index.vue +317 -0
- package/src/JztClassTabs/index.vue +156 -0
- package/src/JztDateSelect/dateSelect.vue +186 -0
- package/src/JztDateSelect/dateType.vue +54 -0
- package/src/JztDateSelect/index.ts +135 -0
- package/src/JztDateSelect/interface/index.ts +13 -0
- package/src/JztDialog/index.vue +249 -0
- package/src/JztEllipsisTooltip/index.vue +61 -0
- package/src/JztEmpty/index.vue +45 -0
- package/src/JztErrorPage/403.vue +30 -0
- package/src/JztErrorPage/404.vue +19 -0
- package/src/JztErrorPage/500.vue +18 -0
- package/src/JztErrorPage/assets/401.png +0 -0
- package/src/JztErrorPage/assets/403.png +0 -0
- package/src/JztErrorPage/assets/404.png +0 -0
- package/src/JztErrorPage/assets/500.png +0 -0
- package/src/JztErrorPage/index.scss +35 -0
- package/src/JztErrorPage/index.vue +35 -0
- package/src/JztFilePreview/components/pdfViewer.vue +221 -0
- package/src/JztFilePreview/hooks/useImageMethod.ts +256 -0
- package/src/JztFilePreview/index.scss +171 -0
- package/src/JztFilePreview/index.vue +68 -0
- package/src/JztFilePreview/interface/index.ts +18 -0
- package/src/JztFilePreview/previewFile.vue +371 -0
- package/src/JztFormGrid/README.md +520 -0
- package/src/JztFormGrid/components/formItem.vue +209 -0
- package/src/JztFormGrid/components/formItemValue.vue +384 -0
- package/src/JztFormGrid/components/showDetailForm.vue +172 -0
- package/src/JztFormGrid/index.scss +60 -0
- package/src/JztFormGrid/index.vue +513 -0
- package/src/JztFormGrid/interface/index.ts +106 -0
- package/src/JztGrid/components/GridItem.vue +68 -0
- package/src/JztGrid/index.vue +179 -0
- package/src/JztGrid/interface/index.ts +6 -0
- package/src/JztImportExcel/assets/delete.png +0 -0
- package/src/JztImportExcel/index.scss +46 -0
- package/src/JztImportExcel/index.vue +430 -0
- package/src/JztImportExcel/interface/index.ts +25 -0
- package/src/JztLabelTitle/index.vue +65 -0
- package/src/JztLeftRightMode/components/CollapseButton.vue +80 -0
- package/src/JztLeftRightMode/components/LeftCard.vue +203 -0
- package/src/JztLeftRightMode/components/LeftLayout.vue +173 -0
- package/src/JztLeftRightMode/components/RightHeader.vue +186 -0
- package/src/JztLeftRightMode/components/RightLayout.vue +235 -0
- package/src/JztLeftRightMode/components/RightTableHeader.vue +43 -0
- package/src/JztLeftRightMode/hooks/useCollapse.ts +17 -0
- package/src/JztLeftRightMode/hooks/useDefaultProps.ts +19 -0
- package/src/JztLeftRightMode/hooks/useLeftLayout.ts +201 -0
- package/src/JztLeftRightMode/hooks/useMode.ts +20 -0
- package/src/JztLeftRightMode/hooks/usePrevNext.ts +60 -0
- package/src/JztLeftRightMode/hooks/useRightLayout.ts +215 -0
- package/src/JztLeftRightMode/hooks/useSlots.ts +15 -0
- package/src/JztLeftRightMode/index.ts +3 -0
- package/src/JztLeftRightMode/index.vue +494 -0
- package/src/JztLeftRightMode/types/index.ts +457 -0
- package/src/JztLoading/fullScreen.ts +45 -0
- package/src/JztLoading/index.scss +67 -0
- package/src/JztLoading/index.vue +18 -0
- package/src/JztLogin/components/LoginFooter.vue +17 -0
- package/src/JztLogin/components/LoginForm.vue +99 -0
- package/src/JztLogin/hooks/useLogin.ts +186 -0
- package/src/JztLogin/index.scss +142 -0
- package/src/JztLogin/index.vue +31 -0
- package/src/JztLogin/interface/index.ts +47 -0
- package/src/JztNumericalRange/index.vue +81 -0
- package/src/JztPageCard/comm/datePicker.vue +151 -0
- package/src/JztPageCard/comm/details.vue +60 -0
- package/src/JztPageCard/comm/export.vue +24 -0
- package/src/JztPageCard/comm/tabs.vue +94 -0
- package/src/JztPageCard/comm/tooltip.vue +31 -0
- package/src/JztPageCard/index.vue +287 -0
- package/src/JztPagination/index.vue +70 -0
- package/src/JztProductInfo/components/imagePreview.vue +275 -0
- package/src/JztProductInfo/components/qxUnique.vue +101 -0
- package/src/JztProductInfo/components/records.vue +265 -0
- package/src/JztProductInfo/hooks/useParams.ts +143 -0
- package/src/JztProductInfo/hooks/useQxUnique.tsx +466 -0
- package/src/JztProductInfo/images/defaultProduct.png +0 -0
- package/src/JztProductInfo/index.ts +116 -0
- package/src/JztProductInfo/index.vue +108 -0
- package/src/JztProductInfo/interface/index.ts +15 -0
- package/src/JztQueryDetailTable/index.scss +100 -0
- package/src/JztQueryDetailTable/index.vue +400 -0
- package/src/JztQueryDetailTable/interface/index.ts +10 -0
- package/src/JztQueryTable/QueryTable /345/212/237/350/203/275.md" +1580 -0
- package/src/JztQueryTable/README.md +567 -0
- package/src/JztQueryTable/components/ColSetting.vue +67 -0
- package/src/JztQueryTable/components/ColumnsSetting.vue +404 -0
- package/src/JztQueryTable/components/ColumnsSetting1.vue +220 -0
- package/src/JztQueryTable/components/DeployToAccountLevelSetting.vue +351 -0
- package/src/JztQueryTable/components/Pagination.vue +54 -0
- package/src/JztQueryTable/components/TableColumn.vue +109 -0
- package/src/JztQueryTable/const.ts +1 -0
- package/src/JztQueryTable/hooks/useQueryTable.ts +194 -0
- package/src/JztQueryTable/hooks/useSelection.ts +47 -0
- package/src/JztQueryTable/hooks/useTableSetting.ts +197 -0
- package/src/JztQueryTable/hooks/useTemplate.ts +127 -0
- package/src/JztQueryTable/index.scss +91 -0
- package/src/JztQueryTable/index.vue +1445 -0
- package/src/JztQueryTable/interface/index.ts +185 -0
- package/src/JztRegionSelect/index.vue +134 -0
- package/src/JztSearchForm/components/SearchFormItem.vue +473 -0
- package/src/JztSearchForm/index.vue +530 -0
- package/src/JztSearchForm/interface/index.ts +100 -0
- package/src/JztSelectFilter/index.scss +63 -0
- package/src/JztSelectFilter/index.vue +110 -0
- package/src/JztSelectTable/index.vue +257 -0
- package/src/JztTable/index.scss +72 -0
- package/src/JztTable/index.vue +353 -0
- package/src/JztTable/interface/index.ts +1 -0
- package/src/JztTime/comm/agencySelect.vue +112 -0
- package/src/JztTime/comm/collapseRow.vue +132 -0
- package/src/JztTime/comm/dateSelect.vue +292 -0
- package/src/JztTime/comm/deptSelect.vue +193 -0
- package/src/JztTime/comm/typeSelect.vue +97 -0
- package/src/JztTime/index.ts +216 -0
- package/src/JztTime/index.vue +303 -0
- package/src/JztTime/interface/index.ts +23 -0
- package/src/JztTreeFilter/index.scss +44 -0
- package/src/JztTreeFilter/index.vue +177 -0
- package/src/JztUploadFile/interface/index.ts +21 -0
- package/src/JztUploadFile/multiple.scss +215 -0
- package/src/JztUploadFile/multiple.vue +318 -0
- package/src/JztUploadFile/single.scss +226 -0
- package/src/JztUploadFile/single.vue +274 -0
- package/src/JztUploadImg/Img.vue +294 -0
- package/src/JztUploadImg/Imgs.vue +411 -0
- package/src/JztUploadImg/index.scss +138 -0
- package/src/JztUploadImg/interface/index.ts +22 -0
- package/src/SelectIcon/index.scss +39 -0
- package/src/SelectIcon/index.vue +106 -0
- package/src/SvgIcon/index.vue +22 -0
- package/src/hooks/useAuthButtons.ts +58 -0
- package/src/hooks/useFormByUserType.ts +90 -0
- package/src/hooks/useTableEvents.ts +30 -0
- package/src/hooks/useUploadFileHook.ts +262 -0
- package/src/index.ts +91 -0
- package/src/typings/global.d.ts +101 -0
- package/src/utils/index.ts +107 -0
- package/src/utils/tree.ts +57 -0
- package/tsconfig.json +45 -0
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="queryItemList && queryItemList.length" :class="[isShow ? 'show-form-content' : 'form-content-box']">
|
|
3
|
+
<el-form ref="formRef" :label-width="labelWidth" v-bind="formProps" :model="queryFrom" :disabled="disabled">
|
|
4
|
+
<el-row class="form_card_content">
|
|
5
|
+
<template v-for="(item, index) in queryItemList" :key="item.prop + 'group_' + index">
|
|
6
|
+
<!-- 表单分组 -->
|
|
7
|
+
<template v-if="item.groupTitle && item.children">
|
|
8
|
+
<div :class="[isCard ? 'group_card' : 'noTitle_card', border ? 'border_card' : '', 'form_card']">
|
|
9
|
+
<div class="flx-between-center group-header-box" @click="showCollapsed ? changeCollapse(item) : ''">
|
|
10
|
+
<JztLabelTitle :title="item.groupTitle" :isLabel="!isCard" v-bind="groupProps"/>
|
|
11
|
+
<!-- <div class="collapse-title flx-left-center">
|
|
12
|
+
<span class="label"></span>
|
|
13
|
+
<span>{{ item.groupTitle }}</span>
|
|
14
|
+
</div> -->
|
|
15
|
+
<div v-if="showCollapsed">
|
|
16
|
+
<el-icon :size="18">
|
|
17
|
+
<ArrowUp v-if="item.collapse" />
|
|
18
|
+
<ArrowDown v-else />
|
|
19
|
+
</el-icon>
|
|
20
|
+
</div>
|
|
21
|
+
<slot v-else name="header_right"></slot>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<el-row v-if="!item.collapse && item.children && item.children.length" class="form_child_card_content">
|
|
25
|
+
<slot :name="item.slotName"></slot>
|
|
26
|
+
<template v-for="(child, childIndex) in item.children" :key="String(child.prop) + index + childIndex">
|
|
27
|
+
<div v-if="child?.el === 'JztTable'" class="table-box">
|
|
28
|
+
<JztTable
|
|
29
|
+
ref="jztTableRef"
|
|
30
|
+
:table-data="ruleForm[item.prop as string] || []"
|
|
31
|
+
:table-config="child?.props?.tableConfig"
|
|
32
|
+
:pagination="false"
|
|
33
|
+
:toolButton="false"
|
|
34
|
+
/>
|
|
35
|
+
</div>
|
|
36
|
+
<form-item
|
|
37
|
+
v-else-if="child.hideFun ? !child.hideFun() : true"
|
|
38
|
+
:key="String(child.prop) + index + '_item_' + childIndex"
|
|
39
|
+
:item="child"
|
|
40
|
+
:ruleForm="queryFrom"
|
|
41
|
+
:props="props"
|
|
42
|
+
:isShow="isShow"
|
|
43
|
+
:border="border"
|
|
44
|
+
:is-detail="child.isDetail ?? isDetail"
|
|
45
|
+
:infoEmptyText="infoEmptyText"
|
|
46
|
+
:showOverflowTooltip="showOverflowTooltip"
|
|
47
|
+
@formOperationFn="formOperationFn"
|
|
48
|
+
@getCascaderValue="getCascaderValue"
|
|
49
|
+
>
|
|
50
|
+
<template #[child.slotName] :key="child.prop + index + '_template_' + childIndex">
|
|
51
|
+
<slot :name="child.slotName"></slot>
|
|
52
|
+
</template>
|
|
53
|
+
</form-item>
|
|
54
|
+
</template>
|
|
55
|
+
</el-row>
|
|
56
|
+
</div>
|
|
57
|
+
</template>
|
|
58
|
+
<!-- 表单无分组 -->
|
|
59
|
+
<template v-else-if="item.hideFun ? !item.hideFun() : true">
|
|
60
|
+
<form-item
|
|
61
|
+
:item="item"
|
|
62
|
+
:showOverflowTooltip="showOverflowTooltip"
|
|
63
|
+
:ruleForm="queryFrom"
|
|
64
|
+
:isShow="isShow"
|
|
65
|
+
:border="border"
|
|
66
|
+
:is-detail="item.isDetail ?? isDetail"
|
|
67
|
+
:infoEmptyText="infoEmptyText"
|
|
68
|
+
@formOperationFn="formOperationFn"
|
|
69
|
+
@getCascaderValue="getCascaderValue"
|
|
70
|
+
>
|
|
71
|
+
<template #[item.slotName] :key="item.props + index">
|
|
72
|
+
<slot :name="item.slotName"></slot>
|
|
73
|
+
</template>
|
|
74
|
+
</form-item>
|
|
75
|
+
</template>
|
|
76
|
+
</template>
|
|
77
|
+
</el-row>
|
|
78
|
+
</el-form>
|
|
79
|
+
<slot name="footer"></slot>
|
|
80
|
+
</div>
|
|
81
|
+
<div v-else></div>
|
|
82
|
+
</template>
|
|
83
|
+
<script setup lang="ts" name="SearchForm">
|
|
84
|
+
import { JztLabelTitle, JztTable } from '@jzt-spd/components'
|
|
85
|
+
import { isEmpty } from '@jzt-spd/utils'
|
|
86
|
+
import { GUIDNoneValue } from '@jzt-spd/utils/consts'
|
|
87
|
+
import type { FormInstance } from 'element-plus'
|
|
88
|
+
import { cloneDeep } from 'lodash-es'
|
|
89
|
+
import { computed, onMounted, provide, ref, watch } from 'vue'
|
|
90
|
+
import formItem from './components/formItem.vue'
|
|
91
|
+
import { FormItemsProps } from './interface/index'
|
|
92
|
+
// import JztTable
|
|
93
|
+
import { useSetCascaderEnumMap, useSetEnumMap } from '../hooks/useFormByUserType'
|
|
94
|
+
|
|
95
|
+
interface ProTableProps {
|
|
96
|
+
showOverflowTooltip?: boolean // 是否显示超出部分提示
|
|
97
|
+
queryItems: FormItemsProps[] // 搜索配置列
|
|
98
|
+
ruleForm?: { [key: string]: any } // 搜索参数
|
|
99
|
+
isShow?: boolean // 是否是查看模式
|
|
100
|
+
disabled?: boolean // 是否表单禁用
|
|
101
|
+
formProps?: Record<string, any>
|
|
102
|
+
infoEmptyText?: string
|
|
103
|
+
showCollapsed?: boolean
|
|
104
|
+
isCard?: boolean
|
|
105
|
+
isDetail?: boolean
|
|
106
|
+
border?: boolean // 是否显示边框
|
|
107
|
+
labelWidth?: number | string // 整体表单label宽度
|
|
108
|
+
// formDict?: Record<string, any>; // 表单枚举字典
|
|
109
|
+
groupProps?: { [key: string]: any }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 默认值
|
|
113
|
+
const props = withDefaults(defineProps<ProTableProps>(), {
|
|
114
|
+
queryItems: () => [],
|
|
115
|
+
ruleForm: () => ({}),
|
|
116
|
+
isShow: false, // 是否是查看模式
|
|
117
|
+
disabled: false, // 是否表单禁用
|
|
118
|
+
infoEmptyText: '-',
|
|
119
|
+
showCollapsed: true, // 是否需要折叠功能
|
|
120
|
+
isCard: false, // 是否需要阴影样式
|
|
121
|
+
border: false,
|
|
122
|
+
isDetail: false,
|
|
123
|
+
labelWidth: 'auto', // 整体表单label宽度
|
|
124
|
+
// formDict: () => ({}),
|
|
125
|
+
groupProps: () => ({}),
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
const queryItemList = ref<FormItemsProps[]>([])
|
|
129
|
+
// cloneDeep 是为了解决打开折叠 互相影响
|
|
130
|
+
onMounted(() => {
|
|
131
|
+
queryItemList.value = cloneDeep(props.queryItems)
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
// const emit = defineEmits(['formOperationFn', 'update:ruleForm'])
|
|
135
|
+
|
|
136
|
+
// 定义 enumMap 存储 enum 值(避免异步请求无法格式化单元格内容 || 无法填充搜索下拉选择)
|
|
137
|
+
const enumMap = ref(new Map<string, { [key: string]: any }[]>())
|
|
138
|
+
// watch(
|
|
139
|
+
// () => props.formDict,
|
|
140
|
+
// (val) => {
|
|
141
|
+
// console.log("val----->", val, isObject(val), !isEmpty(val));
|
|
142
|
+
// if (isObject(val) && !isEmpty(val)) {
|
|
143
|
+
// Object.keys(props.formDict).forEach((key) => {
|
|
144
|
+
// enumMap.value.set(key, props.formDict[key]);
|
|
145
|
+
// });
|
|
146
|
+
// }
|
|
147
|
+
// },
|
|
148
|
+
// { deep: true, immediate: true }
|
|
149
|
+
// );
|
|
150
|
+
|
|
151
|
+
// 查询表单实例
|
|
152
|
+
const formRef = ref()
|
|
153
|
+
|
|
154
|
+
// 获取枚举字典集合
|
|
155
|
+
// const setEnumMap = async ({ prop, isAwait, enum: enumValue, isSetFirstValue, fieldNames }: FormItemsProps) => {
|
|
156
|
+
// if (!enumValue) return
|
|
157
|
+
// if (isAwait) return
|
|
158
|
+
|
|
159
|
+
// // 如果当前 enumMap 存在相同的值 return
|
|
160
|
+
// if (enumMap.value.has(prop!) && (typeof enumValue === 'function' || enumMap.value.get(prop!) === enumValue)) return
|
|
161
|
+
|
|
162
|
+
// // 当前 enum 为静态数据,则直接存储到 enumMap
|
|
163
|
+
// if (typeof enumValue !== 'function') return enumMap.value.set(prop!, unref(enumValue!))
|
|
164
|
+
|
|
165
|
+
// // 为了防止接口执行慢,而存储慢,导致重复请求,所以预先存储为[],接口返回后再二次存储
|
|
166
|
+
// enumMap.value.set(prop!, [])
|
|
167
|
+
|
|
168
|
+
// // 当前 enum 为后台数据需要请求数据,则调用该请求接口,并存储到 enumMap
|
|
169
|
+
// const { data, result } = await enumValue()
|
|
170
|
+
// let list = data || result || []
|
|
171
|
+
// enumMap.value.set(prop!, list)
|
|
172
|
+
// if (useFormSetByUserType(isSetFirstValue, prop)) {
|
|
173
|
+
// setSelectFirstValue(prop, list[0], fieldNames)
|
|
174
|
+
// }
|
|
175
|
+
// }
|
|
176
|
+
// change 获取接口数据
|
|
177
|
+
// const setCascaderEnumMap = async (
|
|
178
|
+
// prop,
|
|
179
|
+
// { enum: enumValue, isSetFirstValue, fieldNames }: FormItemsProps,
|
|
180
|
+
// val: string
|
|
181
|
+
// ) => {
|
|
182
|
+
// if (!enumValue) return
|
|
183
|
+
|
|
184
|
+
// // 如果当前 enumMap 存在相同的值 也不return 根据change实时获取
|
|
185
|
+
// // 为了防止接口执行慢,而存储慢,导致重复请求,所以预先存储为[],接口返回后再二次存储
|
|
186
|
+
// if (typeof enumValue !== 'function') return enumMap.value.set(prop!, unref(enumValue!))
|
|
187
|
+
// enumMap.value.set(prop!, [])
|
|
188
|
+
|
|
189
|
+
// // 当前 enum 为后台数据需要请求数据,则调用该请求接口,并存储到 enumMap
|
|
190
|
+
// const { data, result } = await enumValue(val)
|
|
191
|
+
// let list = data || result || []
|
|
192
|
+
// enumMap.value.set(prop!, list)
|
|
193
|
+
// if (useFormSetByUserType(isSetFirstValue, prop)) {
|
|
194
|
+
// setSelectFirstValue(prop, list[0], fieldNames)
|
|
195
|
+
// }
|
|
196
|
+
// }
|
|
197
|
+
// 处理默认选中第一条数据
|
|
198
|
+
const setSelectFirstValue = (prop, firstItem, fieldNames) => {
|
|
199
|
+
if (prop && firstItem) {
|
|
200
|
+
const itemValue = fieldNames?.value || 'value'
|
|
201
|
+
props.ruleForm[prop] = firstItem[itemValue]
|
|
202
|
+
// emit('update:searchParam', props.ruleForm)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const allFlatQuery = ref<FormItemsProps[]>([])
|
|
206
|
+
|
|
207
|
+
/* 格式化初始化表单数据
|
|
208
|
+
1、 空值默认值 GUIDNoneValue,不展示
|
|
209
|
+
2、处理数组字段合并(例如时间范围)
|
|
210
|
+
*/
|
|
211
|
+
const queryFrom = computed(() => {
|
|
212
|
+
const form = props.ruleForm
|
|
213
|
+
allFlatQuery.value.forEach(item => {
|
|
214
|
+
if (item.isSetEmptyData && form[item.prop as keyof typeof form] === GUIDNoneValue) {
|
|
215
|
+
form[item.prop as keyof typeof form] = item.emptyNullValue ?? ''
|
|
216
|
+
}
|
|
217
|
+
if (item && item.startField && item.endField) {
|
|
218
|
+
const { startField, endField } = item
|
|
219
|
+
if (form[startField] || form[endField]) {
|
|
220
|
+
form[item.prop as keyof typeof form] = [form[startField] || '', form[endField] || '']
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
})
|
|
224
|
+
return form
|
|
225
|
+
})
|
|
226
|
+
/* 格式化处理数据
|
|
227
|
+
1、空值默认值 GUIDNoneValue
|
|
228
|
+
2、处理数组字段切割(例如时间范围)
|
|
229
|
+
*/
|
|
230
|
+
const getFormatForm = form => {
|
|
231
|
+
const endForm = cloneDeep(form)
|
|
232
|
+
allFlatQuery.value.forEach(item => {
|
|
233
|
+
if (item.isSetEmptyData && isEmpty(endForm[item.prop])) {
|
|
234
|
+
endForm[item.prop] = item.emptyNullValue || GUIDNoneValue
|
|
235
|
+
}
|
|
236
|
+
if (item && item.startField && item.endField) {
|
|
237
|
+
const { startField, endField } = item
|
|
238
|
+
const timeList = endForm[item.prop] || []
|
|
239
|
+
endForm[startField] = timeList[0] ?? ''
|
|
240
|
+
endForm[endField] = timeList[1] ?? ''
|
|
241
|
+
delete endForm[item.prop]
|
|
242
|
+
}
|
|
243
|
+
})
|
|
244
|
+
return endForm
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// 扁平化 columns 的方法 处理字典数据 、 过滤表格部分渲染数据
|
|
248
|
+
const flatColumnsFunc = (columns: FormItemsProps[], flatArr: FormItemsProps[] = []) => {
|
|
249
|
+
columns.forEach(async col => {
|
|
250
|
+
if (col.children?.length) {
|
|
251
|
+
flatArr.push(...flatColumnsFunc(col.children))
|
|
252
|
+
}
|
|
253
|
+
if (col.prop) {
|
|
254
|
+
flatArr.push(col)
|
|
255
|
+
// 设置 enumMap
|
|
256
|
+
// await setEnumMap(col)
|
|
257
|
+
// 数据回显的时候反向获取下拉数据
|
|
258
|
+
const index = columns.findIndex(cols => cols.cascader && cols.cascader.includes(col.prop))
|
|
259
|
+
let parentItem = {}
|
|
260
|
+
if (index > -1) {
|
|
261
|
+
parentItem = columns[index]
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
await useSetEnumMap({
|
|
265
|
+
queryItem: col,
|
|
266
|
+
enumMap,
|
|
267
|
+
callBack: setSelectFirstValue,
|
|
268
|
+
queryFrom: queryFrom.value,
|
|
269
|
+
parentItem: parentItem
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
return flatArr.filter(item => !item.children?.length)
|
|
275
|
+
}
|
|
276
|
+
allFlatQuery.value = flatColumnsFunc(props.queryItems)
|
|
277
|
+
|
|
278
|
+
// 操作列点击操作
|
|
279
|
+
const formOperationFn = async (item: any) => {
|
|
280
|
+
// 获取结果数据
|
|
281
|
+
if (item.id === 'confirm') {
|
|
282
|
+
await onConfirm(item.fun)
|
|
283
|
+
} else if (item.id === 'reset') {
|
|
284
|
+
await onReset(item.fun)
|
|
285
|
+
} else {
|
|
286
|
+
const form = getFormatForm(queryFrom.value)
|
|
287
|
+
item.fun(form)
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// 获取getCascader数据
|
|
292
|
+
const getCascaderValue = (val, isClear: boolean = false) => {
|
|
293
|
+
if (val.cascader && val.cascader.length) {
|
|
294
|
+
val.cascader?.forEach(cascader => {
|
|
295
|
+
if (isClear) {
|
|
296
|
+
// 递归处理需要清除的数据
|
|
297
|
+
clearNextItem(cascader)
|
|
298
|
+
} else if (props.ruleForm[val.prop]) {
|
|
299
|
+
const index = allFlatQuery.value.findIndex(item => item.prop === cascader)
|
|
300
|
+
if (index === -1) return
|
|
301
|
+
const queryItem = allFlatQuery.value[index]
|
|
302
|
+
// 有值才会去掉接口,处理clearable 不清空问题
|
|
303
|
+
useSetCascaderEnumMap({
|
|
304
|
+
prevProp: val.prop,
|
|
305
|
+
queryItem,
|
|
306
|
+
enumMap,
|
|
307
|
+
searchParam: props.ruleForm,
|
|
308
|
+
callBack: setSelectFirstValue
|
|
309
|
+
})
|
|
310
|
+
// setCascaderEnumMap(queryItem.prop, queryItem, props.ruleForm[val.prop])
|
|
311
|
+
}
|
|
312
|
+
})
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
// 递归处理需要清除的数据(例如省市区三级的情况,清空/更改省->清空:市与区)
|
|
316
|
+
const clearNextItem = cascader => {
|
|
317
|
+
if (!cascader || !cascader.length) return
|
|
318
|
+
const index = allFlatQuery.value.findIndex(item => item.prop === cascader)
|
|
319
|
+
if (index === -1) return
|
|
320
|
+
const queryItem = allFlatQuery.value[index]
|
|
321
|
+
props.ruleForm[queryItem.prop as keyof typeof queryItem] = null // 让下一级的表单数据为空
|
|
322
|
+
enumMap.value.set(queryItem.prop as keyof typeof queryItem, []) // 让下一级的下拉数据清空
|
|
323
|
+
if (queryItem.cascader && queryItem.cascader.length) {
|
|
324
|
+
queryItem.cascader.forEach(item => {
|
|
325
|
+
clearNextItem(item)
|
|
326
|
+
})
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
// 注入 enumMap
|
|
330
|
+
provide('fromEnumMap', enumMap)
|
|
331
|
+
// 确定提交
|
|
332
|
+
const onConfirm = async (callback?: (valid, form) => any) => {
|
|
333
|
+
try {
|
|
334
|
+
// 获取结果数据
|
|
335
|
+
const valid = await validateForm()
|
|
336
|
+
const endForm = getFormatForm(queryFrom.value)
|
|
337
|
+
return callback && callback(valid, endForm)
|
|
338
|
+
} catch (error) {
|
|
339
|
+
return false
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// 重置表单
|
|
344
|
+
const onReset = async (callback?: () => void) => {
|
|
345
|
+
const formEl = formRef.value as FormInstance | undefined
|
|
346
|
+
if (!formEl) return
|
|
347
|
+
formEl.resetFields()
|
|
348
|
+
callback && callback()
|
|
349
|
+
}
|
|
350
|
+
// 效验表单
|
|
351
|
+
const validateForm = async () => {
|
|
352
|
+
const formEl = formRef.value as FormInstance | undefined
|
|
353
|
+
if (!formEl) return true
|
|
354
|
+
try {
|
|
355
|
+
await formEl.validate()
|
|
356
|
+
return true
|
|
357
|
+
} catch (error) {
|
|
358
|
+
return false
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// 清除校验结果
|
|
363
|
+
const clearValidateForm = async () => {
|
|
364
|
+
const formEl = formRef.value as FormInstance | undefined
|
|
365
|
+
if (!formEl) return
|
|
366
|
+
formEl.clearValidate()
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// 效验表单的部分字段
|
|
370
|
+
const validateFields = async (fields: string | string[]) => {
|
|
371
|
+
if (!fields) return true
|
|
372
|
+
const formEl = formRef.value as FormInstance | undefined
|
|
373
|
+
if (!formEl) return true
|
|
374
|
+
try {
|
|
375
|
+
const valid = await formEl.validateField(fields)
|
|
376
|
+
return valid
|
|
377
|
+
} catch (error) {
|
|
378
|
+
return false
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
const changeCollapse = item => {
|
|
382
|
+
item.collapse = !item.collapse
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// 监听queryItems变化
|
|
386
|
+
watch(
|
|
387
|
+
() => props.queryItems,
|
|
388
|
+
newValue => {
|
|
389
|
+
queryItemList.value = cloneDeep(newValue)
|
|
390
|
+
},
|
|
391
|
+
{ deep: true }
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
defineExpose({
|
|
395
|
+
onConfirm,
|
|
396
|
+
onReset,
|
|
397
|
+
validateForm,
|
|
398
|
+
validateFields,
|
|
399
|
+
clearValidateForm,
|
|
400
|
+
formRef,
|
|
401
|
+
getFormatForm
|
|
402
|
+
})
|
|
403
|
+
</script>
|
|
404
|
+
|
|
405
|
+
<style lang="scss" scoped>
|
|
406
|
+
//展示样式
|
|
407
|
+
.show-form-content {
|
|
408
|
+
:deep(.el-form-item) {
|
|
409
|
+
margin-bottom: 0px !important;
|
|
410
|
+
height: 100%;
|
|
411
|
+
.el-form-item__label,
|
|
412
|
+
.el-space {
|
|
413
|
+
height: 100%;
|
|
414
|
+
height: unset !important;
|
|
415
|
+
}
|
|
416
|
+
.el-form-item__content {
|
|
417
|
+
line-height: 30px;
|
|
418
|
+
}
|
|
419
|
+
.el-space__item {
|
|
420
|
+
line-height: 30px;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
:deep(.group-header) {
|
|
424
|
+
flex: 1;
|
|
425
|
+
padding: 0 10px;
|
|
426
|
+
}
|
|
427
|
+
.noTitle_card {
|
|
428
|
+
margin-bottom: 8px;
|
|
429
|
+
}
|
|
430
|
+
.form_card_content .form_child_card_content {
|
|
431
|
+
margin-bottom: 0;
|
|
432
|
+
}
|
|
433
|
+
// 边框 展示样式
|
|
434
|
+
.border_card {
|
|
435
|
+
margin-bottom: 12px !important;
|
|
436
|
+
:deep(.group-header) {
|
|
437
|
+
flex: 1;
|
|
438
|
+
padding: 0 10px 10px 0;
|
|
439
|
+
}
|
|
440
|
+
:deep(.el-space__item) {
|
|
441
|
+
padding-left: 4px;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
.form-content-box {
|
|
446
|
+
:deep(.group-header) {
|
|
447
|
+
flex: 1;
|
|
448
|
+
padding: 4px 10px;
|
|
449
|
+
}
|
|
450
|
+
.form_card_content .form_child_card_content {
|
|
451
|
+
padding-bottom: 0;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
.form_card.border_card {
|
|
456
|
+
margin-bottom: 0;
|
|
457
|
+
.form_child_card_content {
|
|
458
|
+
padding: 0;
|
|
459
|
+
border-left: 1px solid #ebeef5;
|
|
460
|
+
border-top: 1px solid #ebeef5;
|
|
461
|
+
border-radius: 6px;
|
|
462
|
+
overflow: hidden;
|
|
463
|
+
}
|
|
464
|
+
.form_card {
|
|
465
|
+
margin-bottom: 0;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
.form_card_content {
|
|
469
|
+
width: 100%;
|
|
470
|
+
box-sizing: border-box;
|
|
471
|
+
// margin-bottom: 8px;
|
|
472
|
+
|
|
473
|
+
.form_child_card_content {
|
|
474
|
+
width: 100%;
|
|
475
|
+
box-sizing: border-box;
|
|
476
|
+
padding: 8px;
|
|
477
|
+
// margin-bottom: 12px;
|
|
478
|
+
|
|
479
|
+
.table-box {
|
|
480
|
+
width: 100%;
|
|
481
|
+
max-height: 400px;
|
|
482
|
+
}
|
|
483
|
+
.spd-card {
|
|
484
|
+
padding: 0;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
.form_card {
|
|
489
|
+
width: 100%;
|
|
490
|
+
border-radius: 4px;
|
|
491
|
+
// margin-bottom: 12px;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.noTitle_card {
|
|
495
|
+
width: calc(100% - 10px);
|
|
496
|
+
}
|
|
497
|
+
.group-header-box {
|
|
498
|
+
width: 100%;
|
|
499
|
+
padding-right: 6px;
|
|
500
|
+
box-sizing: border-box;
|
|
501
|
+
}
|
|
502
|
+
// 卡片模式
|
|
503
|
+
.group_card {
|
|
504
|
+
border: 1px solid #e9e9e9;
|
|
505
|
+
margin-bottom: 12px;
|
|
506
|
+
.group-header-box {
|
|
507
|
+
background: var(--el-fill-color-light);
|
|
508
|
+
}
|
|
509
|
+
:deep(.group-header) {
|
|
510
|
+
padding: 8px 10px;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
</style>
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Ref, VNode } from 'vue'
|
|
2
|
+
|
|
3
|
+
import { EnumProps } from '../../JztQueryTable/interface/index'
|
|
4
|
+
|
|
5
|
+
import type { FormInstance } from 'element-plus'
|
|
6
|
+
|
|
7
|
+
export type JztFormInstance = {
|
|
8
|
+
onConfirm(callback?: () => void): void
|
|
9
|
+
onReset(callback?: () => void): void
|
|
10
|
+
validateFields(fields: string | string[]): boolean
|
|
11
|
+
formRef: FormInstance
|
|
12
|
+
}
|
|
13
|
+
export type FieldNamesProps = {
|
|
14
|
+
label: string
|
|
15
|
+
value: string
|
|
16
|
+
children?: string
|
|
17
|
+
}
|
|
18
|
+
export type ElType =
|
|
19
|
+
| 'el-input'
|
|
20
|
+
| 'el-input-number'
|
|
21
|
+
| 'el-select'
|
|
22
|
+
| 'el-select-v2'
|
|
23
|
+
| 'el-tree-select'
|
|
24
|
+
| 'el-cascader'
|
|
25
|
+
| 'el-date-picker'
|
|
26
|
+
| 'el-time-picker'
|
|
27
|
+
| 'el-time-select'
|
|
28
|
+
| 'el-switch'
|
|
29
|
+
| 'el-slider'
|
|
30
|
+
| 'el-radio-group'
|
|
31
|
+
| 'el-checkbox-group'
|
|
32
|
+
| 'JztUploadMultipleImgs'
|
|
33
|
+
| 'JztUploadImg'
|
|
34
|
+
| 'JztUploadMultipleFiles'
|
|
35
|
+
| 'JztUploadSingleFile'
|
|
36
|
+
| 'JztDictionary'
|
|
37
|
+
| 'JztTable'
|
|
38
|
+
| 'JztRegionSelect'
|
|
39
|
+
|
|
40
|
+
export interface FormItemsProps<T = any> {
|
|
41
|
+
label?: string
|
|
42
|
+
key?: string
|
|
43
|
+
labelRender?: () => VNode | string // 自定义单元格标题渲染(tsx语法)
|
|
44
|
+
prop: keyof T
|
|
45
|
+
enumKey?: keyof T // 用于多字段公用同一个enum
|
|
46
|
+
formItemProps?: Record<string, any>
|
|
47
|
+
el?: ElType // 组件
|
|
48
|
+
span?: number // 列宽度
|
|
49
|
+
className?: string // className
|
|
50
|
+
// type?: TypeProps; // 列类型
|
|
51
|
+
// isHide?: boolean; // 是否隐藏
|
|
52
|
+
enum?: EnumProps[] | Ref<EnumProps[]> | ((params?: any) => Promise<any>) // 枚举字典
|
|
53
|
+
// enumCallBack?: (params?: any) => Promise<any>; // 处理接口返回的字典的回调
|
|
54
|
+
fieldNames?: FieldNamesProps // 指定 label && value && children 的 key 值
|
|
55
|
+
render?: () => VNode | string // 内容渲染(tsx语法)
|
|
56
|
+
showRender?: () => VNode | string // 内容渲染 isDetail 详情页使用 showRender>render
|
|
57
|
+
outerRender?: () => VNode | string // 外部在 formItem同层级渲染(tsx语法)
|
|
58
|
+
rightRender?: () => VNode | string // 内部右侧渲染 tsx语法)
|
|
59
|
+
rules?: any[]
|
|
60
|
+
btnLList?: any[]
|
|
61
|
+
// ! 注意: precision: true|数字值, 1️⃣ true:启用配置中的精度位数,2️⃣number:指定精度位数(数字值)
|
|
62
|
+
props?: any // 搜索项参数,根据 element plus 官方文档来传递,该属性所有值会透传到组件
|
|
63
|
+
events?:any; // 搜索项事件,根据 element plus 官方文档来传递,该属性所有值会透传到组件
|
|
64
|
+
// options?: any[] // 固定的下拉数据(废弃)
|
|
65
|
+
slotName?: string // 插槽、
|
|
66
|
+
tooltip?: string
|
|
67
|
+
groupTitle?: string // 表单分组标题
|
|
68
|
+
children?: FormItemsProps[]
|
|
69
|
+
collapse?: boolean // 是否折叠
|
|
70
|
+
/** 隐藏函数 */
|
|
71
|
+
hideFun?: Function //是否隐藏
|
|
72
|
+
disabledFn?: Function /** 禁用函数 */
|
|
73
|
+
cascader?: string[]
|
|
74
|
+
isAwait?: boolean // 是否需要等待请求接口
|
|
75
|
+
options?: Record<string, any>
|
|
76
|
+
dictType?: string | number // 字典ID
|
|
77
|
+
isSetEmptyData?: boolean // 是否设置空数据 适用场景例如:供应商 不选择时:页面为空,实际接口需要默认传 GUIDNoneValue: 00000000-0000-0000-0000-000000000000
|
|
78
|
+
emptyNullValue?: any // 空数据默认值,初始化默认是'', 结果默认值是GUIDNoneValue
|
|
79
|
+
startField?: string // 数组开始字段
|
|
80
|
+
endField?: string // 数组结束字段
|
|
81
|
+
change?: (scope: any) => any // change事件事件
|
|
82
|
+
isSetFirstValue?: boolean // 是否需要默认选中第一个数据
|
|
83
|
+
labelWidth?: string | number // labelWidth
|
|
84
|
+
allowCheckLevel?: number // 允许都选的长度层级,未达到的话,就说明此条数没有固定的子节点,场景: 医疗机构->仓库->科室,只允许选择科室,但是没有科室的医疗机构仓库 会正常返回,此时就不允许选择 第一层,第二层
|
|
85
|
+
fields?: string[] // 目前JztRegionSelect 专用 - [省 市 区]
|
|
86
|
+
hasCheckbox?: boolean // 是否显示全选反选
|
|
87
|
+
// field2?: string; // JztRegionSelect 专用 - 市
|
|
88
|
+
// field3?: string; // JztRegionSelect 专用 - 区
|
|
89
|
+
isDetail?: boolean // 是否是详情展示模式
|
|
90
|
+
detailProps?: DetailFormItemsProp
|
|
91
|
+
valueLeftRender?: () => VNode | string // 详情模式 value 内部右侧渲染 tsx语法)
|
|
92
|
+
valueRightRender?: () => VNode | string // 详情模式 value 内部右侧渲染 tsx语法
|
|
93
|
+
tooltipProps?: TooltipProps
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface DetailFormItemsProp {
|
|
97
|
+
showProp?: string // 展示时的字段key 如果没有就会取FormItemsProps.prop 这个是为了防止详情和编辑的时候的字段不一致,编辑是id 展示是name
|
|
98
|
+
showOverflowTooltip?: boolean // 详情模式 value 显示超出Tooltip
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface TooltipProps {
|
|
102
|
+
iconColor?: string
|
|
103
|
+
placement?: string
|
|
104
|
+
effect: string
|
|
105
|
+
content: string
|
|
106
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-show="isShow" :style="style">
|
|
3
|
+
<slot></slot>
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
<script setup lang="ts" name="GridItem">
|
|
7
|
+
import { ref, Ref, inject, watch, useAttrs, computed } from 'vue'
|
|
8
|
+
import { BreakPoint, Responsive } from '../interface/index'
|
|
9
|
+
|
|
10
|
+
type Props = {
|
|
11
|
+
offset?: number
|
|
12
|
+
span?: number
|
|
13
|
+
suffix?: boolean
|
|
14
|
+
xs?: Responsive
|
|
15
|
+
sm?: Responsive
|
|
16
|
+
md?: Responsive
|
|
17
|
+
lg?: Responsive
|
|
18
|
+
xl?: Responsive
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
22
|
+
offset: 0,
|
|
23
|
+
span: 1,
|
|
24
|
+
suffix: false,
|
|
25
|
+
xs: undefined,
|
|
26
|
+
sm: undefined,
|
|
27
|
+
md: undefined,
|
|
28
|
+
lg: undefined,
|
|
29
|
+
xl: undefined
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const attrs = useAttrs() as { index: string }
|
|
33
|
+
const isShow = ref(true)
|
|
34
|
+
|
|
35
|
+
// 注入断点
|
|
36
|
+
const breakPoint = inject<Ref<BreakPoint>>('breakPoint', ref('xl'))
|
|
37
|
+
const shouldHiddenIndex = inject<Ref<number>>('shouldHiddenIndex', ref(-1))
|
|
38
|
+
watch(
|
|
39
|
+
() => [shouldHiddenIndex.value, breakPoint.value],
|
|
40
|
+
n => {
|
|
41
|
+
if (!!attrs.index) {
|
|
42
|
+
isShow.value = !(n[0] !== -1 && parseInt(attrs.index) >= Number(n[0]))
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
{ immediate: true }
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
const gap = inject('gap', 0)
|
|
49
|
+
const cols = inject('cols', ref(4))
|
|
50
|
+
const style = computed(() => {
|
|
51
|
+
let span = props[breakPoint.value]?.span ?? props.span
|
|
52
|
+
let offset = props[breakPoint.value]?.offset ?? props.offset
|
|
53
|
+
if (props.suffix) {
|
|
54
|
+
return {
|
|
55
|
+
gridColumnStart: cols.value - span - offset + 1,
|
|
56
|
+
gridColumnEnd: `span ${span + offset}`,
|
|
57
|
+
marginLeft: offset !== 0 ? `calc(((100% + ${gap}px) / ${span + offset}) * ${offset})` : 'unset'
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
return {
|
|
61
|
+
gridColumn: `span ${span + offset > cols.value ? cols.value : span + offset}/span ${
|
|
62
|
+
span + offset > cols.value ? cols.value : span + offset
|
|
63
|
+
}`,
|
|
64
|
+
marginLeft: offset !== 0 ? `calc(((100% + ${gap}px) / ${span + offset}) * ${offset})` : 'unset'
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
</script>
|