zyf-model-engine 0.0.1
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/.editorconfig +15 -0
- package/.env +13 -0
- package/.env.development +20 -0
- package/.env.production +25 -0
- package/.env.test +25 -0
- package/.eslintignore +15 -0
- package/.eslintrc-auto-import.json +65 -0
- package/.eslintrc.cjs +66 -0
- package/.husky/commit-msg +4 -0
- package/.husky/pre-commit +5 -0
- package/.prettierignore +9 -0
- package/.prettierrc.cjs +41 -0
- package/.stylelintignore +4 -0
- package/.stylelintrc.cjs +40 -0
- package/.vscode/extensions.json +14 -0
- package/.vscode/settings.json +92 -0
- package/CHANGELOG.md +246 -0
- package/LICENSE +21 -0
- package/README.md +205 -0
- package/auto-imports.d.ts +132 -0
- package/build/getEnv.ts +46 -0
- package/build/plugins.ts +138 -0
- package/build/proxy.ts +28 -0
- package/commitlint.config.cjs +84 -0
- package/components.d.ts +28 -0
- package/index.html +105 -0
- package/lint-staged.config.cjs +8 -0
- package/package.json +108 -0
- package/postcss.config.cjs +5 -0
- package/public/logo.png +0 -0
- package/src/App.vue +16 -0
- package/src/api/config/servicePort.ts +3 -0
- package/src/api/enums/httpEnum.ts +35 -0
- package/src/api/helper/axiosCancel.ts +50 -0
- package/src/api/helper/axiosFileCancel.ts +62 -0
- package/src/api/helper/checkStatus.ts +97 -0
- package/src/api/index.ts +142 -0
- package/src/api/interface/index.ts +27 -0
- package/src/assets/global-icons/icon-demo.svg +1 -0
- package/src/assets/iconfont/iconfont.scss +44 -0
- package/src/assets/iconfont/iconfont.ttf +0 -0
- package/src/assets/images/empty-img.png +0 -0
- package/src/assets/option-icons/add.svg +1 -0
- package/src/assets/option-icons/check.svg +1 -0
- package/src/assets/option-icons/config.svg +1 -0
- package/src/assets/option-icons/del.svg +1 -0
- package/src/assets/option-icons/detail.svg +1 -0
- package/src/assets/option-icons/edit.svg +2 -0
- package/src/assets/option-icons/export.svg +1 -0
- package/src/assets/option-icons/folder.svg +1 -0
- package/src/assets/option-icons/full-screen.svg +1 -0
- package/src/assets/option-icons/more.svg +1 -0
- package/src/assets/option-icons/return.svg +1 -0
- package/src/assets/option-icons/search.svg +1 -0
- package/src/components/CSvgIcon/index.scss +23 -0
- package/src/components/CSvgIcon/index.vue +74 -0
- package/src/components/CTree/index.scss +48 -0
- package/src/components/CTree/index.vue +176 -0
- package/src/components/CTree/interface/index.ts +6 -0
- package/src/components/Dialog/index.scss +74 -0
- package/src/components/Dialog/index.vue +87 -0
- package/src/components/Empty/index.scss +16 -0
- package/src/components/Empty/index.vue +43 -0
- package/src/components/Grid/components/GridItem.vue +68 -0
- package/src/components/Grid/index.vue +167 -0
- package/src/components/Grid/interface/index.ts +6 -0
- package/src/components/Loading/index.scss +67 -0
- package/src/components/Loading/index.vue +13 -0
- package/src/components/Overflow/index.vue +76 -0
- package/src/components/ProTable/components/ColSetting.vue +45 -0
- package/src/components/ProTable/components/Pagination.vue +29 -0
- package/src/components/ProTable/components/SearchForm/components/SearchFormItem.vue +93 -0
- package/src/components/ProTable/components/SearchForm/index.scss +12 -0
- package/src/components/ProTable/components/SearchForm/index.vue +91 -0
- package/src/components/ProTable/components/TableColumn.vue +56 -0
- package/src/components/ProTable/index.scss +14 -0
- package/src/components/ProTable/index.vue +274 -0
- package/src/components/ProTable/interface/index.ts +86 -0
- package/src/components/ScrollBox/index.vue +44 -0
- package/src/components/SvgIcon/index.vue +20 -0
- package/src/components/Tabs/index.vue +142 -0
- package/src/config/index.ts +12 -0
- package/src/config/nprogress.ts +12 -0
- package/src/config/piniaPersist.ts +19 -0
- package/src/config/serviceLoading.ts +45 -0
- package/src/enums/httpEnum.ts +24 -0
- package/src/hooks/interface/index.ts +32 -0
- package/src/hooks/useOnline.ts +27 -0
- package/src/hooks/useTable.ts +167 -0
- package/src/main.ts +35 -0
- package/src/plugins/button/button.vue +56 -0
- package/src/plugins/index.js +26 -0
- package/src/plugins/index.vue +24 -0
- package/src/plugins/msg/msg.vue +56 -0
- package/src/stores/commonStore.ts +9 -0
- package/src/stores/index.ts +8 -0
- package/src/stores/interface/index.ts +1 -0
- package/src/styles/common.scss +87 -0
- package/src/styles/element.scss +233 -0
- package/src/styles/reset.scss +20 -0
- package/src/styles/var.scss +2 -0
- package/src/typings/global.d.ts +37 -0
- package/src/typings/window.d.ts +8 -0
- package/src/utils/color.ts +59 -0
- package/src/utils/commonUtils.ts +175 -0
- package/src/utils/errorHandler.ts +28 -0
- package/src/utils/is.ts +147 -0
- package/src/utils/layoutUtils.ts +83 -0
- package/src/utils/localUtils.ts +42 -0
- package/src/utils/serviceDict.ts +9 -0
- package/src/vite-env.d.ts +6 -0
- package/tsconfig.json +50 -0
- package/vite.config.ts +76 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
.loading-box {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
align-items: center;
|
|
5
|
+
justify-content: center;
|
|
6
|
+
width: 100%;
|
|
7
|
+
height: 100%;
|
|
8
|
+
.loading-wrap {
|
|
9
|
+
display: flex;
|
|
10
|
+
align-items: center;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
padding: 98px;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
.dot {
|
|
16
|
+
position: relative;
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
display: inline-block;
|
|
19
|
+
width: 32px;
|
|
20
|
+
height: 32px;
|
|
21
|
+
font-size: 32px;
|
|
22
|
+
transform: rotate(45deg);
|
|
23
|
+
animation: ant-rotate 1.2s infinite linear;
|
|
24
|
+
}
|
|
25
|
+
.dot i {
|
|
26
|
+
position: absolute;
|
|
27
|
+
display: block;
|
|
28
|
+
width: 14px;
|
|
29
|
+
height: 14px;
|
|
30
|
+
background-color: var(--el-color-primary);
|
|
31
|
+
border-radius: 100%;
|
|
32
|
+
opacity: 0.3;
|
|
33
|
+
transform: scale(0.75);
|
|
34
|
+
transform-origin: 50% 50%;
|
|
35
|
+
animation: ant-spin-move 1s infinite linear alternate;
|
|
36
|
+
}
|
|
37
|
+
.dot i:nth-child(1) {
|
|
38
|
+
top: 0;
|
|
39
|
+
left: 0;
|
|
40
|
+
}
|
|
41
|
+
.dot i:nth-child(2) {
|
|
42
|
+
top: 0;
|
|
43
|
+
right: 0;
|
|
44
|
+
animation-delay: 0.4s;
|
|
45
|
+
}
|
|
46
|
+
.dot i:nth-child(3) {
|
|
47
|
+
right: 0;
|
|
48
|
+
bottom: 0;
|
|
49
|
+
animation-delay: 0.8s;
|
|
50
|
+
}
|
|
51
|
+
.dot i:nth-child(4) {
|
|
52
|
+
bottom: 0;
|
|
53
|
+
left: 0;
|
|
54
|
+
animation-delay: 1.2s;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@keyframes ant-rotate {
|
|
58
|
+
to {
|
|
59
|
+
transform: rotate(405deg);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@keyframes ant-spin-move {
|
|
64
|
+
to {
|
|
65
|
+
opacity: 1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="loading-box">
|
|
3
|
+
<div class="loading-wrap">
|
|
4
|
+
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
|
|
5
|
+
</div>
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script setup lang="ts" name="Loading"></script>
|
|
10
|
+
|
|
11
|
+
<style scoped lang="scss">
|
|
12
|
+
@import "./index.scss";
|
|
13
|
+
</style>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-tooltip
|
|
3
|
+
popper-class="custom-over-flow"
|
|
4
|
+
:visible="isShowTooltip"
|
|
5
|
+
:content="text.toString()"
|
|
6
|
+
effect="light"
|
|
7
|
+
placement="top"
|
|
8
|
+
:enterable="enterable"
|
|
9
|
+
:hide-after="100"
|
|
10
|
+
>
|
|
11
|
+
<div class="text" :style="customStyle" @mouseenter="e => showTooltip(e)" @mouseout="hideTooltip">
|
|
12
|
+
{{ text }}
|
|
13
|
+
</div>
|
|
14
|
+
</el-tooltip>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script setup lang="ts">
|
|
18
|
+
const props = defineProps({
|
|
19
|
+
text: {
|
|
20
|
+
type: [String, Number],
|
|
21
|
+
default: () => "-"
|
|
22
|
+
},
|
|
23
|
+
customStyle: {
|
|
24
|
+
type: [String, Object],
|
|
25
|
+
default: () => ""
|
|
26
|
+
},
|
|
27
|
+
enterable: {
|
|
28
|
+
type: Boolean,
|
|
29
|
+
default: () => true
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const isShowTooltip = ref(false);
|
|
34
|
+
|
|
35
|
+
const showTooltip = (e: any) => {
|
|
36
|
+
isShowTooltip.value = textRange(e.target);
|
|
37
|
+
};
|
|
38
|
+
const hideTooltip = () => {
|
|
39
|
+
isShowTooltip.value = false;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const textRange = (el: any) => {
|
|
43
|
+
const textContent = el;
|
|
44
|
+
const targetW = textContent.getBoundingClientRect().width;
|
|
45
|
+
const range = document.createRange();
|
|
46
|
+
range.setStart(textContent, 0);
|
|
47
|
+
range.setEnd(textContent, textContent.childNodes.length);
|
|
48
|
+
const rangeWidth = range.getBoundingClientRect().width;
|
|
49
|
+
return rangeWidth > targetW;
|
|
50
|
+
};
|
|
51
|
+
</script>
|
|
52
|
+
<style lang="scss" scoped>
|
|
53
|
+
.text {
|
|
54
|
+
box-sizing: border-box;
|
|
55
|
+
flex: 1;
|
|
56
|
+
max-width: 100%;
|
|
57
|
+
overflow: hidden;
|
|
58
|
+
text-overflow: ellipsis;
|
|
59
|
+
white-space: nowrap;
|
|
60
|
+
vertical-align: middle;
|
|
61
|
+
> * {
|
|
62
|
+
vertical-align: middle;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
p {
|
|
66
|
+
margin: 0;
|
|
67
|
+
}
|
|
68
|
+
</style>
|
|
69
|
+
<style lang="scss">
|
|
70
|
+
.custom-over-flow {
|
|
71
|
+
> span:nth-child(1) {
|
|
72
|
+
display: inline-block;
|
|
73
|
+
max-width: 800px !important;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
</style>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- 列设置 -->
|
|
3
|
+
<el-drawer v-model="drawerVisible" title="列设置" size="450px">
|
|
4
|
+
<div class="table-main">
|
|
5
|
+
<el-table :data="colSetting" :border="true" row-key="prop" default-expand-all :tree-props="{ children: '_children' }">
|
|
6
|
+
<el-table-column prop="label" align="center" label="列名" />
|
|
7
|
+
<el-table-column v-slot="scope" prop="isShow" align="center" label="显示">
|
|
8
|
+
<el-switch v-model="scope.row.isShow"></el-switch>
|
|
9
|
+
</el-table-column>
|
|
10
|
+
<el-table-column v-slot="scope" prop="sortable" align="center" label="排序">
|
|
11
|
+
<el-switch v-model="scope.row.sortable"></el-switch>
|
|
12
|
+
</el-table-column>
|
|
13
|
+
<template #empty>
|
|
14
|
+
<div class="table-empty">
|
|
15
|
+
<img src="@/assets/images/notData.png" alt="notData" />
|
|
16
|
+
<div>暂无可配置列</div>
|
|
17
|
+
</div>
|
|
18
|
+
</template>
|
|
19
|
+
</el-table>
|
|
20
|
+
</div>
|
|
21
|
+
</el-drawer>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script setup lang="ts" name="ColSetting">
|
|
25
|
+
import { ref } from "vue";
|
|
26
|
+
import { ColumnProps } from "@/components/ProTable/interface";
|
|
27
|
+
|
|
28
|
+
defineProps<{ colSetting: ColumnProps[] }>();
|
|
29
|
+
|
|
30
|
+
const drawerVisible = ref<boolean>(false);
|
|
31
|
+
|
|
32
|
+
const openColSetting = () => {
|
|
33
|
+
drawerVisible.value = true;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
defineExpose({
|
|
37
|
+
openColSetting
|
|
38
|
+
});
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<style scoped lang="scss">
|
|
42
|
+
.cursor-move {
|
|
43
|
+
cursor: move;
|
|
44
|
+
}
|
|
45
|
+
</style>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- 分页组件 -->
|
|
3
|
+
<el-pagination
|
|
4
|
+
:background="true"
|
|
5
|
+
:current-page="pageable.page"
|
|
6
|
+
:page-size="pageable.limit"
|
|
7
|
+
:page-sizes="[10, 25, 50, 100]"
|
|
8
|
+
:total="pageable.total"
|
|
9
|
+
layout="total, sizes, prev, pager, next, jumper"
|
|
10
|
+
@size-change="handleSizeChange"
|
|
11
|
+
@current-change="handleCurrentChange"
|
|
12
|
+
></el-pagination>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup lang="ts" name="Pagination">
|
|
16
|
+
interface Pageable {
|
|
17
|
+
page: number;
|
|
18
|
+
limit: number;
|
|
19
|
+
total: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface PaginationProps {
|
|
23
|
+
pageable: Pageable;
|
|
24
|
+
handleSizeChange: (size: number) => void;
|
|
25
|
+
handleCurrentChange: (currentPage: number) => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
defineProps<PaginationProps>();
|
|
29
|
+
</script>
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component
|
|
3
|
+
:is="_column.search?.render ?? `el-${_column.search?.el}`"
|
|
4
|
+
v-bind="{ ...handleSearchProps, ...placeholder, searchParam: _searchParam, clearable }"
|
|
5
|
+
v-model.trim="_searchParam[_column.search?.key ?? handleProp(_column.prop!)]"
|
|
6
|
+
:data="_column.search?.el === 'tree-select' ? columnEnum : []"
|
|
7
|
+
:options="['cascader', 'select-v2'].includes(_column.search?.el!) ? columnEnum : []"
|
|
8
|
+
>
|
|
9
|
+
<template v-if="_column.search?.el === 'cascader'" #default="{ data }">
|
|
10
|
+
<span>{{ data[fieldNames.label] }}</span>
|
|
11
|
+
</template>
|
|
12
|
+
<template v-if="_column.search?.el === 'select'">
|
|
13
|
+
<component
|
|
14
|
+
:is="`el-option`"
|
|
15
|
+
v-for="(col, index) in columnEnum"
|
|
16
|
+
:key="index"
|
|
17
|
+
:label="col[fieldNames.label]"
|
|
18
|
+
:value="col[fieldNames.value]"
|
|
19
|
+
></component>
|
|
20
|
+
</template>
|
|
21
|
+
<slot v-else></slot>
|
|
22
|
+
</component>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script setup lang="ts" name="SearchFormItem">
|
|
26
|
+
import { computed, inject, ref } from "vue";
|
|
27
|
+
import { handleProp } from "@/utils/layoutUtils";
|
|
28
|
+
import { ColumnProps } from "@/components/ProTable/interface";
|
|
29
|
+
|
|
30
|
+
interface SearchFormItem {
|
|
31
|
+
column: ColumnProps;
|
|
32
|
+
searchParam: { [key: string]: any };
|
|
33
|
+
}
|
|
34
|
+
const props = defineProps<SearchFormItem>();
|
|
35
|
+
|
|
36
|
+
// Re receive SearchParam
|
|
37
|
+
const _searchParam = computed(() => props.searchParam);
|
|
38
|
+
const _column = computed(() => props.column);
|
|
39
|
+
|
|
40
|
+
// 判断 fieldNames 设置 label && value && children 的 key 值
|
|
41
|
+
const fieldNames = computed(() => {
|
|
42
|
+
return {
|
|
43
|
+
label: props.column.fieldNames?.label ?? "name",
|
|
44
|
+
value: props.column.fieldNames?.value ?? "id",
|
|
45
|
+
children: props.column.fieldNames?.children ?? "children"
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// 接收 enumMap (el 为 select-v2 需单独处理 enumData)
|
|
50
|
+
const enumMap = inject("enumMap", ref(new Map()));
|
|
51
|
+
const columnEnum = computed(() => {
|
|
52
|
+
let enumData = enumMap.value.get(props.column.prop);
|
|
53
|
+
if (!enumData) return [];
|
|
54
|
+
if (props.column.search?.el === "select-v2" && props.column.fieldNames) {
|
|
55
|
+
enumData = enumData.map((item: { [key: string]: any }) => {
|
|
56
|
+
return { ...item, label: item[fieldNames.value.label], value: item[fieldNames.value.value] };
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return enumData;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// 处理透传的 searchProps (el 为 tree-select、cascader 的时候需要给下默认 label && value && children)
|
|
63
|
+
const handleSearchProps = computed(() => {
|
|
64
|
+
const label = fieldNames.value.label;
|
|
65
|
+
const value = fieldNames.value.value;
|
|
66
|
+
const children = fieldNames.value.children;
|
|
67
|
+
const searchEl = props.column.search?.el;
|
|
68
|
+
let searchProps = props.column.search?.props ?? {};
|
|
69
|
+
if (searchEl === "tree-select") {
|
|
70
|
+
searchProps = { ...searchProps, props: { ...searchProps.props, label, children }, nodeKey: value };
|
|
71
|
+
}
|
|
72
|
+
if (searchEl === "cascader") {
|
|
73
|
+
searchProps = { ...searchProps, props: { ...searchProps.props, label, value, children } };
|
|
74
|
+
}
|
|
75
|
+
return searchProps;
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// 处理默认 placeholder
|
|
79
|
+
const placeholder = computed(() => {
|
|
80
|
+
const search = props.column.search;
|
|
81
|
+
if (["datetimerange", "daterange", "monthrange"].includes(search?.props?.type) || search?.props?.isRange) {
|
|
82
|
+
return { rangeSeparator: "至", startPlaceholder: "开始时间", endPlaceholder: "结束时间" };
|
|
83
|
+
}
|
|
84
|
+
const placeholder = search?.props?.placeholder ?? (search?.el?.includes("input") ? "请输入" : "请选择") + props.column.label;
|
|
85
|
+
return { placeholder };
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// 是否有清除按钮 (当搜索项有默认值时,清除按钮不显示)
|
|
89
|
+
const clearable = computed(() => {
|
|
90
|
+
const search = props.column.search;
|
|
91
|
+
return search?.props?.clearable ?? (search?.defaultValue == null || search?.defaultValue == undefined);
|
|
92
|
+
});
|
|
93
|
+
</script>
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="columns.length" class="table-search" :class="{ card: useCard }">
|
|
3
|
+
<el-form ref="formRef" :model="searchParam">
|
|
4
|
+
<Grid ref="gridRef" :collapsed="collapsed" :gap="[20, 20]" :cols="searchCol">
|
|
5
|
+
<GridItem v-for="(item, index) in columns" :key="item.prop" v-bind="getResponsive(item)" :index="index">
|
|
6
|
+
<!-- :label="`${item.label} :`" -->
|
|
7
|
+
<el-form-item>
|
|
8
|
+
<SearchFormItem :column="item" :search-param="searchParam" />
|
|
9
|
+
</el-form-item>
|
|
10
|
+
</GridItem>
|
|
11
|
+
<GridItem suffix>
|
|
12
|
+
<div class="operation">
|
|
13
|
+
<el-button type="primary" :icon="Search" @click="search"> 搜索 </el-button>
|
|
14
|
+
<el-button :icon="Delete" @click="reset"> 重置 </el-button>
|
|
15
|
+
<el-button v-if="showCollapse" type="primary" link class="search-isOpen" @click="collapsed = !collapsed">
|
|
16
|
+
{{ collapsed ? "展开" : "合并" }}
|
|
17
|
+
<el-icon class="el-icon--right">
|
|
18
|
+
<component :is="collapsed ? ArrowDown : ArrowUp"></component>
|
|
19
|
+
</el-icon>
|
|
20
|
+
</el-button>
|
|
21
|
+
</div>
|
|
22
|
+
</GridItem>
|
|
23
|
+
</Grid>
|
|
24
|
+
</el-form>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
27
|
+
<script setup lang="ts" name="SearchForm">
|
|
28
|
+
import { computed, ref } from "vue";
|
|
29
|
+
import { ColumnProps } from "@/components/ProTable/interface";
|
|
30
|
+
import { BreakPoint } from "@/components/Grid/interface";
|
|
31
|
+
import { Delete, Search, ArrowDown, ArrowUp } from "@element-plus/icons-vue";
|
|
32
|
+
import SearchFormItem from "./components/SearchFormItem.vue";
|
|
33
|
+
import Grid from "@/components/Grid/index.vue";
|
|
34
|
+
import GridItem from "@/components/Grid/components/GridItem.vue";
|
|
35
|
+
|
|
36
|
+
interface ProTableProps {
|
|
37
|
+
useCard?: boolean; // 是否启用卡片样式
|
|
38
|
+
columns?: ColumnProps[]; // 搜索配置列
|
|
39
|
+
searchParam?: { [key: string]: any }; // 搜索参数
|
|
40
|
+
searchCol: number | Record<BreakPoint, number>;
|
|
41
|
+
search: (params: any) => void; // 搜索方法
|
|
42
|
+
reset: (params: any) => void; // 重置方法
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 默认值
|
|
46
|
+
const props = withDefaults(defineProps<ProTableProps>(), {
|
|
47
|
+
useCard: true,
|
|
48
|
+
columns: () => [],
|
|
49
|
+
searchParam: () => ({})
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// 获取响应式设置
|
|
53
|
+
const getResponsive = (item: ColumnProps) => {
|
|
54
|
+
return {
|
|
55
|
+
span: item.search?.span,
|
|
56
|
+
offset: item.search?.offset ?? 0,
|
|
57
|
+
xs: item.search?.xs,
|
|
58
|
+
sm: item.search?.sm,
|
|
59
|
+
md: item.search?.md,
|
|
60
|
+
lg: item.search?.lg,
|
|
61
|
+
xl: item.search?.xl
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// 是否默认折叠搜索项
|
|
66
|
+
const collapsed = ref(true);
|
|
67
|
+
|
|
68
|
+
// 获取响应式断点
|
|
69
|
+
const gridRef = ref();
|
|
70
|
+
const breakPoint = computed<BreakPoint>(() => gridRef.value?.breakPoint);
|
|
71
|
+
|
|
72
|
+
// 判断是否显示 展开/合并 按钮
|
|
73
|
+
const showCollapse = computed(() => {
|
|
74
|
+
let show = false;
|
|
75
|
+
props.columns.reduce((prev, current) => {
|
|
76
|
+
prev +=
|
|
77
|
+
(current.search![breakPoint.value]?.span ?? current.search?.span ?? 1) +
|
|
78
|
+
(current.search![breakPoint.value]?.offset ?? current.search?.offset ?? 0);
|
|
79
|
+
if (typeof props.searchCol !== "number") {
|
|
80
|
+
if (prev >= props.searchCol[breakPoint.value]) show = true;
|
|
81
|
+
} else {
|
|
82
|
+
if (prev >= props.searchCol) show = true;
|
|
83
|
+
}
|
|
84
|
+
return prev;
|
|
85
|
+
}, 0);
|
|
86
|
+
return show;
|
|
87
|
+
});
|
|
88
|
+
</script>
|
|
89
|
+
<style lang="scss" scoped>
|
|
90
|
+
@import "./index.scss";
|
|
91
|
+
</style>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<RenderTableColumn v-bind="{ ..._column }" />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script setup lang="tsx" name="TableColumn">
|
|
6
|
+
import { inject, ref, useSlots } from "vue";
|
|
7
|
+
import { ColumnProps, RenderScope, HeaderRenderScope } from "@/components/ProTable/interface";
|
|
8
|
+
import { filterEnum, formatValue, handleProp, handleRowAccordingToProp } from "@/utils/layoutUtils";
|
|
9
|
+
|
|
10
|
+
const props = defineProps<{ column: ColumnProps }>();
|
|
11
|
+
const _column = computed(() => props.column);
|
|
12
|
+
const slots = useSlots();
|
|
13
|
+
|
|
14
|
+
const enumMap = inject("enumMap", ref(new Map()));
|
|
15
|
+
|
|
16
|
+
// 渲染表格数据
|
|
17
|
+
const renderCellData = (item: ColumnProps, scope: RenderScope<any>) => {
|
|
18
|
+
return enumMap.value.get(item.prop) && item.isFilterEnum
|
|
19
|
+
? filterEnum(handleRowAccordingToProp(scope.row, item.prop!), enumMap.value.get(item.prop)!, item.fieldNames)
|
|
20
|
+
: formatValue(handleRowAccordingToProp(scope.row, item.prop!));
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// 获取 tag 类型
|
|
24
|
+
const getTagType = (item: ColumnProps, scope: RenderScope<any>) => {
|
|
25
|
+
return filterEnum(handleRowAccordingToProp(scope.row, item.prop!), enumMap.value.get(item.prop), item.fieldNames, "tag");
|
|
26
|
+
};
|
|
27
|
+
// 渲染表格行
|
|
28
|
+
const RenderTableColumn = (item: ColumnProps) => {
|
|
29
|
+
return (
|
|
30
|
+
<>
|
|
31
|
+
{item.isShow && (
|
|
32
|
+
<el-table-column
|
|
33
|
+
{...item}
|
|
34
|
+
align={item.align ?? "center"}
|
|
35
|
+
showOverflowTooltip={item.showOverflowTooltip ?? item.prop !== "operation"}
|
|
36
|
+
>
|
|
37
|
+
{{
|
|
38
|
+
default: (scope: RenderScope<any>) => {
|
|
39
|
+
if (item._children) return item._children.map(child => RenderTableColumn(child));
|
|
40
|
+
if (item.render) return item.render(scope);
|
|
41
|
+
if (slots[handleProp(item.prop!)]) return slots[handleProp(item.prop!)]!(scope);
|
|
42
|
+
if (item.tag) return <el-tag type={getTagType(item, scope)}>{renderCellData(item, scope)}</el-tag>;
|
|
43
|
+
return renderCellData(item, scope);
|
|
44
|
+
},
|
|
45
|
+
header: (scope: HeaderRenderScope<any>) => {
|
|
46
|
+
if (item.headerRender) return item.headerRender(scope);
|
|
47
|
+
if (slots[`${handleProp(item.prop!)}Header`]) return slots[`${handleProp(item.prop!)}Header`]!(scope);
|
|
48
|
+
return item.label;
|
|
49
|
+
}
|
|
50
|
+
}}
|
|
51
|
+
</el-table-column>
|
|
52
|
+
)}
|
|
53
|
+
</>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
</script>
|