fit2cloud-ui-plus 0.0.1-beta.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/LICENSE +674 -0
- package/README.md +16 -0
- package/lib/favicon.bmp +0 -0
- package/lib/fit2cloud-ui-plus.es.js +3796 -0
- package/lib/fit2cloud-ui-plus.umd.js +1 -0
- package/package.json +48 -0
- package/src/components/filter-bar/FuFilter.vue +175 -0
- package/src/components/filter-bar/FuFilterBar.vue +75 -0
- package/src/components/filter-bar/FuFilterConditions.vue +29 -0
- package/src/components/filter-bar/FuSearchInput.vue +31 -0
- package/src/components/filter-bar/filter-components/FuFilterDate.vue +62 -0
- package/src/components/filter-bar/filter-components/FuFilterDateTime.vue +65 -0
- package/src/components/filter-bar/filter-components/FuFilterOption.vue +38 -0
- package/src/components/filter-bar/filter-components/FuFilterSelect.vue +143 -0
- package/src/components/filter-bar/index.ts +19 -0
- package/src/components/filter-bar/types.ts +31 -0
- package/src/components/read-write-switch/FuInputRwSwitch.vue +44 -0
- package/src/components/read-write-switch/FuReadWriteSwitch.vue +91 -0
- package/src/components/read-write-switch/FuSelectRwSwitch.vue +53 -0
- package/src/components/read-write-switch/index.ts +13 -0
- package/src/components/search-bar/FuComplexSearch.vue +108 -0
- package/src/components/search-bar/FuQuickSearch.vue +43 -0
- package/src/components/search-bar/FuSearchBar.vue +165 -0
- package/src/components/search-bar/FuSearchBarButton.vue +14 -0
- package/src/components/search-bar/FuSearchContions.vue +24 -0
- package/src/components/search-bar/index.ts +13 -0
- package/src/components/search-bar/store.ts +25 -0
- package/src/components/speed-dial/FuSpeedDial.vue +280 -0
- package/src/components/speed-dial/FuSpeedDialActionButton.vue +88 -0
- package/src/components/speed-dial/FuSpeedDialButton.vue +42 -0
- package/src/components/speed-dial/FuSpeedDialItem.vue +88 -0
- package/src/components/speed-dial/index.ts +11 -0
- package/src/components/split-pane/FuSplitPane.vue +228 -0
- package/src/components/split-pane/index.ts +8 -0
- package/src/components/steps/FuHorizontalNavigation.vue +18 -0
- package/src/components/steps/FuHorizontalSteps.vue +94 -0
- package/src/components/steps/FuStep.vue +13 -0
- package/src/components/steps/FuSteps.vue +22 -0
- package/src/components/steps/FuStepsFooter.ts +79 -0
- package/src/components/steps/FuVerticalNavigation.vue +35 -0
- package/src/components/steps/FuVerticalSteps.vue +79 -0
- package/src/components/steps/Stepper.ts +188 -0
- package/src/components/steps/index.ts +11 -0
- package/src/components/table/FuTable.vue +145 -0
- package/src/components/table/FuTableBody.ts +40 -0
- package/src/components/table/FuTablePagination.vue +42 -0
- package/src/components/table/index.ts +15 -0
- package/src/components/table/table-column-dropdown/FuTableColumnDropdown.vue +102 -0
- package/src/components/table/table-column-dropdown/index.ts +7 -0
- package/src/components/table/table-column-select/FuTableColumnSelect.vue +22 -0
- package/src/components/table/table-column-select/FuTableColumnSelectDialog.vue +99 -0
- package/src/components/table/table-column-select/FuTableColumnSelectPopover.vue +80 -0
- package/src/components/table/table-column-select/index.ts +8 -0
- package/src/components/table/table-column-select/utils.ts +59 -0
- package/src/components/table/table-operations/FuTableButton.vue +19 -0
- package/src/components/table/table-operations/FuTableMoreButton.vue +52 -0
- package/src/components/table/table-operations/FuTableOperations.vue +88 -0
- package/src/components/table/table-operations/index.ts +12 -0
- package/src/components/tabs/FuTabs.vue +84 -0
- package/src/components/tabs/index.ts +8 -0
- package/src/components/virtual-scroller/FuVirtualHorizontalScroll.js +96 -0
- package/src/components/virtual-scroller/FuVirtualScroll.js +15 -0
- package/src/components/virtual-scroller/FuVirtualVerticalScroll.js +95 -0
- package/src/components/virtual-scroller/index.js +10 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/use-global-config/index.ts +32 -0
- package/src/hooks/use-locale/index.ts +47 -0
- package/src/index.ts +19 -0
- package/src/locale/index.ts +12 -0
- package/src/locale/lang/en.ts +58 -0
- package/src/locale/lang/zh-cn.ts +58 -0
- package/src/locale/lang/zh-tw.ts +58 -0
- package/src/styles/common/config.scss +5 -0
- package/src/styles/common/function.scss +81 -0
- package/src/styles/common/mixins.scss +85 -0
- package/src/styles/common/variables.scss +28 -0
- package/src/styles/components/filter-bar.scss +227 -0
- package/src/styles/components/read-write-switch.scss +6 -0
- package/src/styles/components/search-bar.scss +285 -0
- package/src/styles/components/speed-dial.scss +107 -0
- package/src/styles/components/split-pane.scss +111 -0
- package/src/styles/components/steps.scss +110 -0
- package/src/styles/components/table.scss +105 -0
- package/src/styles/components/tabs.scss +10 -0
- package/src/styles/components/virtual-scroller.scss +24 -0
- package/src/styles/index.scss +11 -0
- package/src/tools/theme.ts +23 -0
- package/src/tools/time.ts +30 -0
- package/src/tools/utils.ts +60 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { useLocale } from "@/hooks"
|
|
2
|
+
const { t } = useLocale()
|
|
3
|
+
|
|
4
|
+
interface StepperOptions {
|
|
5
|
+
steps: string
|
|
6
|
+
index: number
|
|
7
|
+
activeSet: any
|
|
8
|
+
isLoading?: string
|
|
9
|
+
cancelButtonText: string
|
|
10
|
+
finishButtonText: string
|
|
11
|
+
prevButtonText: string
|
|
12
|
+
nextButtonText: string
|
|
13
|
+
buttonSize: string
|
|
14
|
+
footerAlign: string
|
|
15
|
+
showCancel: any
|
|
16
|
+
beforeActive: Function
|
|
17
|
+
beforeLeave: Function
|
|
18
|
+
height: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class Stepper {
|
|
22
|
+
steps: string
|
|
23
|
+
index: number
|
|
24
|
+
activeSet: any
|
|
25
|
+
isLoading: string
|
|
26
|
+
cancelButtonText: string
|
|
27
|
+
finishButtonText: string
|
|
28
|
+
prevButtonText: string
|
|
29
|
+
nextButtonText: string
|
|
30
|
+
buttonSize: string
|
|
31
|
+
footerAlign: string
|
|
32
|
+
showCancel: any
|
|
33
|
+
beforeActive: Function
|
|
34
|
+
beforeLeave: Function
|
|
35
|
+
height: string
|
|
36
|
+
constructor(options?: StepperOptions) {
|
|
37
|
+
options = options || ({} as StepperOptions)
|
|
38
|
+
// 所有步骤节点(Step对象数组)
|
|
39
|
+
this.steps = options.steps
|
|
40
|
+
// 正在执行的节点的索引
|
|
41
|
+
this.index = options.index === undefined ? 0 : options.index
|
|
42
|
+
// 激活过的节点的索引
|
|
43
|
+
this.activeSet = new Set()
|
|
44
|
+
// loading状态
|
|
45
|
+
this.isLoading = options.isLoading
|
|
46
|
+
// footer 属性
|
|
47
|
+
this.cancelButtonText = options.cancelButtonText || t("fu.steps.cancel")
|
|
48
|
+
this.finishButtonText = options.finishButtonText || t("fu.steps.finish")
|
|
49
|
+
this.prevButtonText = options.prevButtonText || t("fu.steps.prev")
|
|
50
|
+
this.nextButtonText = options.nextButtonText || t("fu.steps.next")
|
|
51
|
+
this.buttonSize = options.buttonSize
|
|
52
|
+
this.footerAlign = options.footerAlign || 'flex'
|
|
53
|
+
// 是否显示取消按钮
|
|
54
|
+
this.showCancel = options.showCancel === undefined ? false : options.showCancel
|
|
55
|
+
// 激活前钩子
|
|
56
|
+
this.beforeActive = options.beforeActive
|
|
57
|
+
// 离开前钩子
|
|
58
|
+
this.beforeLeave = options.beforeLeave
|
|
59
|
+
// 高度
|
|
60
|
+
this.height = options.height
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// index是否为第一个节点
|
|
64
|
+
isFirst(index: number) {
|
|
65
|
+
return index === 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// index是否为最后一个节点
|
|
69
|
+
isLast(index: number) {
|
|
70
|
+
return index === this.steps.length - 1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// index的节点是否激活过
|
|
74
|
+
isActive(index: number) {
|
|
75
|
+
return this.activeSet.has(index);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// index的节点是否为正在激活的节点
|
|
79
|
+
isCurrent(index: number) {
|
|
80
|
+
return this.index === index
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 激活
|
|
84
|
+
active(index: number) {
|
|
85
|
+
// 在节点范围内,并且不等于当前节点
|
|
86
|
+
const isValid = index >= 0 && index < this.steps.length && this.index !== index
|
|
87
|
+
const forward = index > this.index
|
|
88
|
+
if (isValid) {
|
|
89
|
+
// 离开前钩子返回false,则不执行激活
|
|
90
|
+
if (this.executeHook("beforeLeave", this.index, forward) !== false) {
|
|
91
|
+
// 激活前钩子返回false,则不执行激活
|
|
92
|
+
if (this.executeHook("beforeActive", index, forward) !== false) {
|
|
93
|
+
// 激活
|
|
94
|
+
this.index = index
|
|
95
|
+
this.activeSet.add(index)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 反激活
|
|
102
|
+
inactive(index: number) {
|
|
103
|
+
this.activeSet.delete(index)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 下一步
|
|
107
|
+
next() {
|
|
108
|
+
if (!this.isLast(this.index)) {
|
|
109
|
+
this.active(this.index + 1)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 上一步
|
|
114
|
+
prev() {
|
|
115
|
+
if (!this.isFirst(this.index)) {
|
|
116
|
+
this.active(this.index - 1)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 使用索引获取Step对象
|
|
121
|
+
getStep(index: number) {
|
|
122
|
+
if (this.steps && this.steps.length > index) {
|
|
123
|
+
return this.steps[index]
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 使用ID获取节点索引
|
|
128
|
+
getIndex(id: string) {
|
|
129
|
+
if (this.steps) {
|
|
130
|
+
for (let i = 0; i < this.steps.length; i++) {
|
|
131
|
+
let step = this.steps[i];
|
|
132
|
+
if (id === step.id) {
|
|
133
|
+
return i;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return -1;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
executeHook(functionName: string, index: number, forward: boolean) {
|
|
141
|
+
const step: any = this.getStep(index)
|
|
142
|
+
// 如果节点定义了钩子方法,执行节点的
|
|
143
|
+
if (step[functionName]) {
|
|
144
|
+
return step[functionName](step, forward)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 节点没定义,则执行Steps的钩子方法
|
|
148
|
+
if (this[functionName]) {
|
|
149
|
+
return this[functionName](step, forward)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
interface StepOptions {
|
|
155
|
+
id: string
|
|
156
|
+
index: number
|
|
157
|
+
beforeActive: Function
|
|
158
|
+
beforeLeave: Function
|
|
159
|
+
title: string
|
|
160
|
+
description: string
|
|
161
|
+
icon: string
|
|
162
|
+
status: string
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export class Step {
|
|
166
|
+
id: string
|
|
167
|
+
index: number
|
|
168
|
+
beforeActive: Function
|
|
169
|
+
beforeLeave: Function
|
|
170
|
+
title: string
|
|
171
|
+
description: string
|
|
172
|
+
icon: string
|
|
173
|
+
status: string
|
|
174
|
+
constructor(options?: StepOptions) {
|
|
175
|
+
options = options || ({} as StepOptions)
|
|
176
|
+
this.id = options.id
|
|
177
|
+
this.index = options.index
|
|
178
|
+
// 激活前钩子
|
|
179
|
+
this.beforeActive = options.beforeActive
|
|
180
|
+
// 离开前钩子
|
|
181
|
+
this.beforeLeave = options.beforeLeave
|
|
182
|
+
// el-step 属性
|
|
183
|
+
this.title = options.title
|
|
184
|
+
this.description = options.description
|
|
185
|
+
this.icon = options.icon
|
|
186
|
+
this.status = options.status
|
|
187
|
+
}
|
|
188
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-table class="fu-table" v-bind="$attrs" :key="key" header-row-class-name="fu-table-header">
|
|
3
|
+
<fu-table-body name="table-body" :columns="columns">
|
|
4
|
+
<slot />
|
|
5
|
+
</fu-table-body>
|
|
6
|
+
</el-table>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script lang="ts" setup>
|
|
10
|
+
import { onMounted, useSlots, ref, watch, computed, onUpdated, provide } from "vue";
|
|
11
|
+
import FuTableBody from "@/components/table/FuTableBody";
|
|
12
|
+
defineOptions({ name: "FuTable" });
|
|
13
|
+
const props = defineProps({
|
|
14
|
+
columns: Array,
|
|
15
|
+
refresh: {
|
|
16
|
+
type: Boolean,
|
|
17
|
+
default: true,
|
|
18
|
+
},
|
|
19
|
+
localKey: String, // 如果需要记住选择的列,则这里添加一个唯一的Key
|
|
20
|
+
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const slots = useSlots()
|
|
24
|
+
|
|
25
|
+
const key = ref(0);
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
const prefix = "FU-T-"
|
|
29
|
+
|
|
30
|
+
const isFix = (node: any) => {
|
|
31
|
+
const includeTag = node.type.name.indexOf("FuTableColumnDropdown") >= 0
|
|
32
|
+
const { fix } = node.props
|
|
33
|
+
let { type } = node.props
|
|
34
|
+
return (fix !== undefined && fix !== false) || ["selection", "index", "expand"].includes(type) || includeTag
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const getLabel = (node: any) => {
|
|
38
|
+
if (node.props.label) return node.props.label
|
|
39
|
+
const includeTag = node.type.name.indexOf("FuTableColumnDropdown") >= 0
|
|
40
|
+
let { label, type } = node.props
|
|
41
|
+
if (includeTag) label = prefix + "dropdown"
|
|
42
|
+
label ??= node.props.label
|
|
43
|
+
label ??= prefix + type
|
|
44
|
+
return label;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const cleanColumns = (columns: any) => {
|
|
48
|
+
columns.splice(0, columns.length)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const updateNodes = (nodes: any) => {
|
|
52
|
+
nodes.forEach((node: any) => {
|
|
53
|
+
if (!node.type.key) {
|
|
54
|
+
node.type.key = getLabel(node)
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const initColumns = (nodes: any, columns: any) => {
|
|
60
|
+
nodes.forEach((node: any) => {
|
|
61
|
+
const label = getLabel(node)
|
|
62
|
+
const fix = isFix(node);
|
|
63
|
+
const { show } = node.props
|
|
64
|
+
if (!label && !fix) {
|
|
65
|
+
throw new Error("unfixed column's label is required.")
|
|
66
|
+
}
|
|
67
|
+
columns.push({ label, show, fix })
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const copyColumns = (source: any, target: any) => {
|
|
72
|
+
source.forEach((col: any) => {
|
|
73
|
+
target.push(col)
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const updateColumns = (nodes: any, columns: any) => {
|
|
78
|
+
if (columns === undefined) return
|
|
79
|
+
// 如果保存的列跟实际的列冲突则以实际的为准
|
|
80
|
+
if (nodes.length !== columns.length) {
|
|
81
|
+
cleanColumns(columns)
|
|
82
|
+
initColumns(nodes, columns)
|
|
83
|
+
}
|
|
84
|
+
if (columns.some((col: any) => col.label === undefined)) {
|
|
85
|
+
columns.forEach((col: any, i: any) => {
|
|
86
|
+
col.label ??= getLabel(nodes[i])
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
const columnsKey = computed(() => {
|
|
93
|
+
return prefix + props.localKey
|
|
94
|
+
})
|
|
95
|
+
// 去掉v-if=false的node
|
|
96
|
+
const children = slots.default?.().filter((c: any) => c.type.name !== undefined)
|
|
97
|
+
watch(() => props.columns,
|
|
98
|
+
() => {
|
|
99
|
+
// 设置refresh,可以避免抖动或闪烁,但是table会更新一次
|
|
100
|
+
if (props.refresh) {
|
|
101
|
+
key.value++;
|
|
102
|
+
}
|
|
103
|
+
if (props.localKey) {
|
|
104
|
+
localStorage.setItem(columnsKey.value, JSON.stringify(props.columns));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
},
|
|
108
|
+
{ deep: true }
|
|
109
|
+
)
|
|
110
|
+
// 之前的created
|
|
111
|
+
onMounted(() => {
|
|
112
|
+
updateNodes(children)
|
|
113
|
+
// 表格没有内容或者不需要选列
|
|
114
|
+
if (!children || !props.columns) return
|
|
115
|
+
|
|
116
|
+
// 需要读取localStorage
|
|
117
|
+
if (props.localKey) {
|
|
118
|
+
let str = localStorage.getItem(columnsKey.value)
|
|
119
|
+
if (str) {
|
|
120
|
+
try {
|
|
121
|
+
const columns = JSON.parse(str)
|
|
122
|
+
cleanColumns(props.columns)
|
|
123
|
+
copyColumns(columns, props.columns)
|
|
124
|
+
updateColumns(children, props.columns)
|
|
125
|
+
return
|
|
126
|
+
} catch (e) {
|
|
127
|
+
console.error("get columns error", e)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (props.columns.length === 0) {
|
|
133
|
+
initColumns(children, props.columns)
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
provide("localKey", props.localKey)
|
|
139
|
+
|
|
140
|
+
onUpdated(() => {
|
|
141
|
+
updateNodes(children)
|
|
142
|
+
updateColumns(children, props.columns)
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
</script>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { h } from 'vue'
|
|
2
|
+
|
|
3
|
+
const isFix = (node: any) => {
|
|
4
|
+
const includeTag = node.type.name.indexOf("FuTableColumnDropdown") >= 0
|
|
5
|
+
const { fix } = node.props
|
|
6
|
+
let { type } = node.props
|
|
7
|
+
return (fix !== undefined && fix !== false) || ["selection", "index", "expand"].includes(type) || includeTag
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const getLabel = (node: any) => {
|
|
11
|
+
if (node.props.label) return node.props.label
|
|
12
|
+
const prefix = "FU-T-"
|
|
13
|
+
const includeTag = node.type.name.indexOf("FuTableColumnDropdown") >= 0
|
|
14
|
+
let { label, type } = node.props
|
|
15
|
+
if (includeTag) label = prefix + "dropdown"
|
|
16
|
+
label ??= node.props.label
|
|
17
|
+
label ??= prefix + type
|
|
18
|
+
return label;
|
|
19
|
+
}
|
|
20
|
+
const FuTableBody = (props: any, context: any) => {
|
|
21
|
+
const slots = context.slots.default()
|
|
22
|
+
const nodes: any = [];
|
|
23
|
+
let { columns } = props
|
|
24
|
+
const children = slots[0].children.filter((c: any) => c.type.name !== undefined)
|
|
25
|
+
if (!children) return nodes
|
|
26
|
+
if (!columns || columns?.length === 0) return children
|
|
27
|
+
columns.forEach((col: any) => {
|
|
28
|
+
let node = children.find((child: any) => {
|
|
29
|
+
return col.label === getLabel(child)
|
|
30
|
+
})
|
|
31
|
+
if (node && (isFix(node) || col.show !== false)) {
|
|
32
|
+
nodes.push(node);
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
return nodes
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default FuTableBody;
|
|
39
|
+
|
|
40
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage"
|
|
3
|
+
:page-sizes="pageSizes" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
|
4
|
+
</el-pagination>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script lang="ts" setup>
|
|
8
|
+
defineOptions({ name: "FuTablePagination" });
|
|
9
|
+
const props = defineProps({
|
|
10
|
+
currentPage: {
|
|
11
|
+
type: Number,
|
|
12
|
+
default: 1
|
|
13
|
+
},
|
|
14
|
+
pageSize: {
|
|
15
|
+
type: Number,
|
|
16
|
+
default: 5
|
|
17
|
+
},
|
|
18
|
+
pageSizes: {
|
|
19
|
+
type: Array,
|
|
20
|
+
default: function () {
|
|
21
|
+
return [5, 10, 20, 50, 100]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
total: {
|
|
25
|
+
type: Number,
|
|
26
|
+
default: 0
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
});
|
|
30
|
+
const emit = defineEmits(["size-change", "current-change", "change", "update:pageSize", "update:currentPage"])
|
|
31
|
+
|
|
32
|
+
function handleSizeChange(size: number) {
|
|
33
|
+
emit('update:pageSize', size)
|
|
34
|
+
emit("size-change");
|
|
35
|
+
emit("change"); // 兼容历史版本
|
|
36
|
+
}
|
|
37
|
+
function handleCurrentChange(current: number) {
|
|
38
|
+
emit('update:currentPage', current)
|
|
39
|
+
emit("current-change");
|
|
40
|
+
emit("change"); // 兼容历史版本
|
|
41
|
+
}
|
|
42
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import FuTable from "./FuTable.vue"
|
|
2
|
+
import FuTableColumnSelect from "./table-column-select"
|
|
3
|
+
import FuTablePagination from "./FuTablePagination.vue"
|
|
4
|
+
import FuTableOperations from "./table-operations"
|
|
5
|
+
import FuTableColumnDropdown from "./table-column-dropdown"
|
|
6
|
+
|
|
7
|
+
import type { App } from 'vue'
|
|
8
|
+
FuTable.install = (app: App): void => {
|
|
9
|
+
app.component(FuTable.name, FuTable);
|
|
10
|
+
app.component(FuTablePagination.name, FuTablePagination)
|
|
11
|
+
app.use(FuTableOperations.install)
|
|
12
|
+
app.use(FuTableColumnSelect.install)
|
|
13
|
+
app.use(FuTableColumnDropdown.install)
|
|
14
|
+
};
|
|
15
|
+
export default FuTable;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-table-column class-name="fu-table-column-dropdown" :width="width" :resizable="false" align="center"
|
|
3
|
+
v-bind="$attrs">
|
|
4
|
+
<template #default="scope">
|
|
5
|
+
<el-dropdown @command="handleCommand" :trigger="trigger" :class="showType === 'hover' ? 'fu-show-icon' : ''"
|
|
6
|
+
v-if="isShow(scope.row)" placement="bottom" :ref="`dropdown${scope.$index}`">
|
|
7
|
+
<span class="fu-dropdown-link">
|
|
8
|
+
<slot name="icon">
|
|
9
|
+
<el-icon class="fu-icon-more">
|
|
10
|
+
<MoreFilled />
|
|
11
|
+
</el-icon>
|
|
12
|
+
</slot>
|
|
13
|
+
</span>
|
|
14
|
+
<template #dropdown>
|
|
15
|
+
<el-dropdown-menu>
|
|
16
|
+
<slot name="title">
|
|
17
|
+
<div class="fu-table-column-dropdown__title" v-if="title">
|
|
18
|
+
{{ title }}
|
|
19
|
+
</div>
|
|
20
|
+
</slot>
|
|
21
|
+
<slot v-bind="scope">
|
|
22
|
+
<el-dropdown-item v-for="(item, i) in menus" :key="i" :icon="item.icon"
|
|
23
|
+
:disabled="disabled(item, scope.row)" :divided="item.divided" :command="composeValue(item, scope.row)">
|
|
24
|
+
{{ item.label }}
|
|
25
|
+
</el-dropdown-item>
|
|
26
|
+
</slot>
|
|
27
|
+
</el-dropdown-menu>
|
|
28
|
+
</template>
|
|
29
|
+
</el-dropdown>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
</el-table-column>
|
|
33
|
+
</template>
|
|
34
|
+
<script lang="ts" setup>
|
|
35
|
+
import { computed, getCurrentInstance } from "vue";
|
|
36
|
+
defineOptions({ name: "FuTableColumnDropdown" });
|
|
37
|
+
const props = defineProps({
|
|
38
|
+
showType: {
|
|
39
|
+
type: String,
|
|
40
|
+
default: "always",
|
|
41
|
+
validator: (value: string) => ["always", "hover", "selected"].includes(value),
|
|
42
|
+
},
|
|
43
|
+
menus: {
|
|
44
|
+
type: Array,
|
|
45
|
+
default: () => [],
|
|
46
|
+
},
|
|
47
|
+
title: String,
|
|
48
|
+
trigger: {
|
|
49
|
+
type: String,
|
|
50
|
+
default: "click",
|
|
51
|
+
},
|
|
52
|
+
width: {
|
|
53
|
+
type: String,
|
|
54
|
+
default: "40",
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const instance = getCurrentInstance()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
const isShow = computed(() => {
|
|
63
|
+
return function (row: any) {
|
|
64
|
+
if (props.showType === "selected") {
|
|
65
|
+
const selection = instance?.parent?.parent?.store?.getSelectionRows()
|
|
66
|
+
return selection.includes(row) && true;
|
|
67
|
+
} else {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const disabled = computed(() => {
|
|
74
|
+
return function (item: any, row: any) {
|
|
75
|
+
return typeof item.disabled === "function"
|
|
76
|
+
? item.disabled(row)
|
|
77
|
+
: item.disabled;
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
function handleCommand({ item, row }: any) {
|
|
83
|
+
item.click(row);
|
|
84
|
+
}
|
|
85
|
+
function composeValue(item: any, row: any) {
|
|
86
|
+
return {
|
|
87
|
+
item,
|
|
88
|
+
row,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function show(index: number) {
|
|
93
|
+
instance.refs[`dropdown${index}`].handleOpen();
|
|
94
|
+
}
|
|
95
|
+
function hide(index: number) {
|
|
96
|
+
instance.refs[`dropdown${index}`].handleClose();
|
|
97
|
+
}
|
|
98
|
+
defineExpose({
|
|
99
|
+
show,
|
|
100
|
+
hide
|
|
101
|
+
})
|
|
102
|
+
</script>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { defineComponent, h } from 'vue'
|
|
3
|
+
import FuTableColumnSelectPopover from "./FuTableColumnSelectPopover.vue";
|
|
4
|
+
import FuTableColumnSelectDialog from "./FuTableColumnSelectDialog.vue";
|
|
5
|
+
|
|
6
|
+
export default defineComponent({
|
|
7
|
+
name: 'FuTableColumnSelect',
|
|
8
|
+
props: ["type"],
|
|
9
|
+
setup(props, context) {
|
|
10
|
+
const { type } = props
|
|
11
|
+
return () => {
|
|
12
|
+
if (type === "dialog") {
|
|
13
|
+
return h(FuTableColumnSelectDialog, context.attrs, context.slots)
|
|
14
|
+
} else {
|
|
15
|
+
return h(FuTableColumnSelectPopover, context.attrs, context.slots)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
})
|
|
21
|
+
</script>
|
|
22
|
+
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div style="display: inline-block">
|
|
3
|
+
<!-- :size="configSize" -->
|
|
4
|
+
<el-button class="fu-search-bar-button" :icon="icon" @click="visible = true">{{t('fu.table.custom_table_rows')}}</el-button>
|
|
5
|
+
<el-dialog custom-class="fu-table-column-select-dialog" v-model="visible" @open="open" append-to-body>
|
|
6
|
+
<template #title>
|
|
7
|
+
<h3>
|
|
8
|
+
{{ t('fu.table.custom_table_fields') }}
|
|
9
|
+
</h3>
|
|
10
|
+
<el-alert :title="t('fu.table.custom_table_fields_desc')" type="info" :closable="false"/>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<el-checkbox v-for="(c, i) in cloneColumns" :key="i" v-model="c.show" :checked="c.show !== false" draggable="true"
|
|
14
|
+
@dragstart="dragstart($event, i)" @dragenter="dragenter" @dragleave="dragleave"
|
|
15
|
+
@dragover.prevent @dragend="dragend" @drop="drop($event, cloneColumns, i)" v-show="!c.fix">
|
|
16
|
+
{{ c.label }}
|
|
17
|
+
</el-checkbox>
|
|
18
|
+
|
|
19
|
+
<template #footer>
|
|
20
|
+
<el-button @click="reset" v-if="columnsKey">
|
|
21
|
+
{{ t('fu.table.reset') }}
|
|
22
|
+
</el-button>
|
|
23
|
+
<el-button type="primary" @click="ok">
|
|
24
|
+
{{ t('fu.table.ok') }}
|
|
25
|
+
</el-button>
|
|
26
|
+
</template>
|
|
27
|
+
</el-dialog>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script setup lang="ts">
|
|
33
|
+
import {ref, inject} from "vue";
|
|
34
|
+
import {tableColumnSelect} from "./utils"
|
|
35
|
+
import {useLocale} from "@/hooks"
|
|
36
|
+
|
|
37
|
+
const props = defineProps({
|
|
38
|
+
icon: {
|
|
39
|
+
type: String,
|
|
40
|
+
default: "Setting"
|
|
41
|
+
},
|
|
42
|
+
trigger: {
|
|
43
|
+
type: String,
|
|
44
|
+
default: "hover",
|
|
45
|
+
validator: (value: string) => ['click', 'hover'].includes(value)
|
|
46
|
+
},
|
|
47
|
+
columns: {
|
|
48
|
+
type: Array,
|
|
49
|
+
default: () => []
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
const localKey = inject("localKey")
|
|
55
|
+
|
|
56
|
+
const {t} = useLocale()
|
|
57
|
+
|
|
58
|
+
const cloneColumn = (source: any, target: any) => {
|
|
59
|
+
source.forEach((col: any) => {
|
|
60
|
+
target.push(Object.assign({}, col))
|
|
61
|
+
})
|
|
62
|
+
return target
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
const {
|
|
67
|
+
columnsKey,
|
|
68
|
+
dragstart,
|
|
69
|
+
dragenter,
|
|
70
|
+
dragleave,
|
|
71
|
+
dragend,
|
|
72
|
+
drop
|
|
73
|
+
} = tableColumnSelect(localKey)
|
|
74
|
+
|
|
75
|
+
const cloneColumns = ref([])
|
|
76
|
+
const visible = ref(false)
|
|
77
|
+
|
|
78
|
+
function open() {
|
|
79
|
+
cloneColumns.value = []
|
|
80
|
+
cloneColumn(props.columns, cloneColumns.value)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function ok() {
|
|
84
|
+
props.columns.splice(0, props.columns.length)
|
|
85
|
+
cloneColumns.value.forEach(c => {
|
|
86
|
+
props.columns.push(c)
|
|
87
|
+
})
|
|
88
|
+
visible.value = false
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function reset() {
|
|
92
|
+
if (columnsKey) {
|
|
93
|
+
localStorage.removeItem(columnsKey.value)
|
|
94
|
+
}
|
|
95
|
+
props.columns.splice(0, props.columns.length)
|
|
96
|
+
visible.value = false
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
</script>
|