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,165 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="fu-search-bar">
|
|
3
|
+
<div class="fu-search-bar__content">
|
|
4
|
+
<!-- :size="configSize" -->
|
|
5
|
+
<fu-complex-search ref="complex" :components="components" @change="change" v-if="showComplex" @close="closePopover">
|
|
6
|
+
<slot name="complex" />
|
|
7
|
+
</fu-complex-search>
|
|
8
|
+
<!-- :size="configSize" -->
|
|
9
|
+
<fu-search-conditions :conditions="conditions" @change="change" v-if="showComplex"/>
|
|
10
|
+
<!-- :size="configSize" -->
|
|
11
|
+
<fu-quick-search :use-icon="!showComplex" :placeholder="placeholder" v-model="quick"
|
|
12
|
+
@change="quickChange" v-if="useQuickSearch"/>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="fu-search-bar__buttons">
|
|
15
|
+
<slot name="buttons">
|
|
16
|
+
<!-- :size="configSize" -->
|
|
17
|
+
<fu-search-bar-button icon="Close" @click="clean" :tooltip="t('fu.search_bar.clean')"
|
|
18
|
+
v-if="showClean" />
|
|
19
|
+
<!-- :size="configSize" -->
|
|
20
|
+
<fu-search-bar-button icon="Refresh" @click="refresh"
|
|
21
|
+
:tooltip="t('fu.search_bar.refresh')" v-if="showRefresh" />
|
|
22
|
+
<slot />
|
|
23
|
+
</slot>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<script setup lang="ts">
|
|
29
|
+
import { ref, computed, useSlots } from "vue";
|
|
30
|
+
import FuQuickSearch from "./FuQuickSearch.vue";
|
|
31
|
+
import FuComplexSearch from "./FuComplexSearch.vue";
|
|
32
|
+
import FuSearchBarButton from "@/components/search-bar/FuSearchBarButton.vue";
|
|
33
|
+
import FuSearchConditions from "@/components/search-bar/FuSearchContions.vue";
|
|
34
|
+
import ComplexCondition from "@/components/search-bar/store";
|
|
35
|
+
import { useLocale } from "@/hooks"
|
|
36
|
+
defineOptions({ name: "FuSearchBar" });
|
|
37
|
+
const { t } = useLocale()
|
|
38
|
+
|
|
39
|
+
const slots = useSlots()
|
|
40
|
+
|
|
41
|
+
const props = defineProps({
|
|
42
|
+
quickKey: {
|
|
43
|
+
type: String,
|
|
44
|
+
default: "quick"
|
|
45
|
+
},
|
|
46
|
+
quickPlaceholder: String,
|
|
47
|
+
useCleanButton: { // 是否使用清除按钮
|
|
48
|
+
type: Boolean,
|
|
49
|
+
default: true
|
|
50
|
+
},
|
|
51
|
+
useRefreshButton: { // 是否使用刷新按钮
|
|
52
|
+
type: Boolean,
|
|
53
|
+
default: false
|
|
54
|
+
},
|
|
55
|
+
useQuickSearch: { // 是否使用快速搜索
|
|
56
|
+
type: Boolean,
|
|
57
|
+
default: true
|
|
58
|
+
},
|
|
59
|
+
components: Array,
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const emit = defineEmits(["close", "exec"])
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
const quick = ref("")
|
|
66
|
+
const conditions = ref([])
|
|
67
|
+
|
|
68
|
+
// refs
|
|
69
|
+
|
|
70
|
+
const complex = ref();
|
|
71
|
+
|
|
72
|
+
// target覆盖source相同的field
|
|
73
|
+
function merge(source: any, target: any) {
|
|
74
|
+
let conditions = source.concat(target)
|
|
75
|
+
let conditionMap = new Map()
|
|
76
|
+
|
|
77
|
+
for (let condition of conditions) {
|
|
78
|
+
conditionMap.set(condition.field, condition)
|
|
79
|
+
}
|
|
80
|
+
let result: any = [];
|
|
81
|
+
conditionMap.forEach(c => {
|
|
82
|
+
result.push(c)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
return result
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
function closePopover() {
|
|
92
|
+
emit("close")
|
|
93
|
+
}
|
|
94
|
+
function setConditions(conditions: any) {
|
|
95
|
+
conditions.value = complex.value.createConditions(conditions)
|
|
96
|
+
|
|
97
|
+
if (props.useQuickSearch && conditions[props.quickKey] !== undefined) {
|
|
98
|
+
quick.value = conditions[props.quickKey].value
|
|
99
|
+
quickChange(quick.value)
|
|
100
|
+
} else {
|
|
101
|
+
refresh()
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function quickChange(value: string, e?: any) {
|
|
105
|
+
if (value) {
|
|
106
|
+
const field = props.quickKey
|
|
107
|
+
const valueLabel = value
|
|
108
|
+
// *****此处有问题,待解决
|
|
109
|
+
conditions.value = merge(conditions.value, [new ComplexCondition({ field, value, valueLabel })])
|
|
110
|
+
exec(e)
|
|
111
|
+
quick.value = "";
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function change(conditions: any) {
|
|
115
|
+
conditions.value = merge(conditions.value, conditions)
|
|
116
|
+
exec()
|
|
117
|
+
}
|
|
118
|
+
function clean() {
|
|
119
|
+
quick.value = ""
|
|
120
|
+
conditions.value = []
|
|
121
|
+
emit("exec", conditions.value)
|
|
122
|
+
}
|
|
123
|
+
function refresh() {
|
|
124
|
+
complex.value.close()
|
|
125
|
+
exec()
|
|
126
|
+
}
|
|
127
|
+
function exec() {
|
|
128
|
+
// 只有快速搜索
|
|
129
|
+
if (!showComplex) {
|
|
130
|
+
emit("exec", quick.value )
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
emit("exec", condition.value )
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const placeholder = computed(() => {
|
|
137
|
+
return props.quickPlaceholder ? props.quickPlaceholder : t('fu.search_bar.search')
|
|
138
|
+
});
|
|
139
|
+
const showComplex = computed(() => {
|
|
140
|
+
if (slots?.complex) return true
|
|
141
|
+
return props.components?.length > 0;
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const showClean = computed(() => {
|
|
145
|
+
return props.useCleanButton && showComplex && (conditions.value.length > 0 || quick.value)
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const showRefresh = computed(() => {
|
|
149
|
+
return props.useRefreshButton && showComplex
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const condition = computed(() => {
|
|
153
|
+
const condition = {}
|
|
154
|
+
if (conditions.value.length > 0) {
|
|
155
|
+
conditions.value.forEach(c => {
|
|
156
|
+
const { field, operator, value } = c
|
|
157
|
+
condition[c.field] = { field, operator, value }
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return condition
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
</script>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-tooltip :content="tooltip" :disabled="!tooltip">
|
|
3
|
+
<!-- :size="configSize" -->
|
|
4
|
+
<el-button class="fu-search-bar-button" circle v-bind="$attrs" />
|
|
5
|
+
<!-- <slot></slot> -->
|
|
6
|
+
<!-- *****element问题 加上插槽 空的情况下渲染多出一个span标签问题 待考虑 -->
|
|
7
|
+
</el-tooltip>
|
|
8
|
+
</template>
|
|
9
|
+
<script setup lang="ts">
|
|
10
|
+
defineOptions({ name: "FuSearchBarButton" });
|
|
11
|
+
defineProps({
|
|
12
|
+
tooltip: String
|
|
13
|
+
});
|
|
14
|
+
</script>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- , 'fu-search-conditions--' + configSize -->
|
|
3
|
+
<div :class="['fu-search-conditions']">
|
|
4
|
+
<div class="fu-search-conditions__item" v-for="(condition, index) in conditions" :key="index">
|
|
5
|
+
<div v-if="condition.label">{{ condition.label }}</div>
|
|
6
|
+
<div v-if="condition.operatorLabel">{{ condition.operatorLabel }}</div>
|
|
7
|
+
<div class="condition-value">{{ condition.valueLabel }}</div>
|
|
8
|
+
<i class="el-icon-close condition-remove" @click="remove(index)" />
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script setup lang="ts">
|
|
14
|
+
const props = defineProps({
|
|
15
|
+
conditions: Array
|
|
16
|
+
})
|
|
17
|
+
const emit = defineEmits(["change"])
|
|
18
|
+
|
|
19
|
+
function remove(index: number) {
|
|
20
|
+
props.conditions.splice(index, 1)
|
|
21
|
+
emit("change", props.conditions)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
</script>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import FuSearchBar from "./FuSearchBar.vue"
|
|
2
|
+
import FuQuickSearch from "./FuQuickSearch.vue"
|
|
3
|
+
import FuSearchBarButton from "./FuSearchBarButton.vue"
|
|
4
|
+
// import FuComplexComponents from "./complex-components"
|
|
5
|
+
|
|
6
|
+
import type { App } from 'vue'
|
|
7
|
+
FuSearchBar.install = (app: App): void => {
|
|
8
|
+
app.component(FuSearchBar.name, FuSearchBar)
|
|
9
|
+
app.component(FuSearchBarButton.name, FuSearchBarButton)
|
|
10
|
+
app.component(FuQuickSearch.name, FuQuickSearch)
|
|
11
|
+
// app.use(FuComplexComponents.install)
|
|
12
|
+
};
|
|
13
|
+
export default FuSearchBar;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface Options {
|
|
2
|
+
field: string
|
|
3
|
+
label: string
|
|
4
|
+
operator?: string
|
|
5
|
+
operatorLabel: string
|
|
6
|
+
value: string
|
|
7
|
+
valueLabel: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default class ComplexCondition {
|
|
11
|
+
field: string
|
|
12
|
+
label: string
|
|
13
|
+
operator?: string
|
|
14
|
+
operatorLabel: string
|
|
15
|
+
value: string
|
|
16
|
+
valueLabel: string
|
|
17
|
+
constructor(options: Options) {
|
|
18
|
+
this.field = options.field
|
|
19
|
+
this.label = options.label
|
|
20
|
+
this.operator = options.operator
|
|
21
|
+
this.operatorLabel = options.operatorLabel
|
|
22
|
+
this.value = options.value
|
|
23
|
+
this.valueLabel = options.valueLabel || options.value
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- v-outside-click="outsideClickClose" -->
|
|
3
|
+
<div class="fu-speed-dial" :style="style">
|
|
4
|
+
<div class="fu-speed-dial__content">
|
|
5
|
+
<slot name="fab">
|
|
6
|
+
<fu-speed-dial-button v-bind="buttonProps" @click="click" @mousedown="mousedown" />
|
|
7
|
+
</slot>
|
|
8
|
+
<div :style="contentPosition">
|
|
9
|
+
<slot>
|
|
10
|
+
<fu-speed-dial-item v-for="(item, index) in items" :index="index" :key="index" v-bind="item"
|
|
11
|
+
@click="itemClick" />
|
|
12
|
+
</slot>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
<script setup lang="ts">
|
|
20
|
+
import { reactive, ref, watch, getCurrentInstance, onMounted, computed, provide, useSlots } from "vue";
|
|
21
|
+
import type { CSSProperties } from 'vue'
|
|
22
|
+
// import OutsideClick from "element-ui/src/utils/clickoutside"
|
|
23
|
+
// directives: { OutsideClick },
|
|
24
|
+
import FuSpeedDialButton from "@/components/speed-dial/FuSpeedDialButton.vue"
|
|
25
|
+
import FuSpeedDialItem from "@/components/speed-dial/FuSpeedDialItem.vue"
|
|
26
|
+
defineOptions({ name: "FuSpeedDial" });
|
|
27
|
+
const props = defineProps({
|
|
28
|
+
id: String,
|
|
29
|
+
value: Boolean,
|
|
30
|
+
type: {
|
|
31
|
+
type: String,
|
|
32
|
+
default: "primary"
|
|
33
|
+
},
|
|
34
|
+
items: Array,
|
|
35
|
+
size: {
|
|
36
|
+
type: String,
|
|
37
|
+
default: "default",
|
|
38
|
+
validator: (value: string) => ["big", "default", "medium", "small"].includes(value)
|
|
39
|
+
},
|
|
40
|
+
direction: {
|
|
41
|
+
type: String,
|
|
42
|
+
default: "top",
|
|
43
|
+
validator: (value: string) => ["top", "bottom", "left", "right"].includes(value)
|
|
44
|
+
},
|
|
45
|
+
icon: {
|
|
46
|
+
type: String,
|
|
47
|
+
default: "el-icon-plus"
|
|
48
|
+
},
|
|
49
|
+
activeIcon: {
|
|
50
|
+
type: String,
|
|
51
|
+
default: "el-icon-close"
|
|
52
|
+
},
|
|
53
|
+
movable: {
|
|
54
|
+
type: Boolean,
|
|
55
|
+
default: false
|
|
56
|
+
},
|
|
57
|
+
position: {
|
|
58
|
+
type: String,
|
|
59
|
+
validator: (value: string) => ["absolute", "fixed"].includes(value)
|
|
60
|
+
},
|
|
61
|
+
left: String,
|
|
62
|
+
top: String,
|
|
63
|
+
right: String,
|
|
64
|
+
bottom: String,
|
|
65
|
+
zIndex: {
|
|
66
|
+
type: [String, Number],
|
|
67
|
+
default: 99
|
|
68
|
+
},
|
|
69
|
+
itemClickClose: {
|
|
70
|
+
type: Boolean,
|
|
71
|
+
default: true
|
|
72
|
+
},
|
|
73
|
+
outsideClose: {
|
|
74
|
+
type: Boolean,
|
|
75
|
+
default: true
|
|
76
|
+
},
|
|
77
|
+
manual: {
|
|
78
|
+
type: Boolean,
|
|
79
|
+
default: false
|
|
80
|
+
},
|
|
81
|
+
localKey: String,
|
|
82
|
+
sizeOptions: {
|
|
83
|
+
type: Object,
|
|
84
|
+
default: () => {
|
|
85
|
+
return {
|
|
86
|
+
big: {
|
|
87
|
+
fab: { size: 56, fontSize: "18px" },
|
|
88
|
+
item: { size: 40, spacing: 0, titleFontSize: "14px", buttonFontSize: "18px" }
|
|
89
|
+
},
|
|
90
|
+
default: {
|
|
91
|
+
fab: { size: 40, fontSize: "16px" },
|
|
92
|
+
item: { size: 32, spacing: 0, titleFontSize: "14px", buttonFontSize: "16px" }
|
|
93
|
+
},
|
|
94
|
+
medium: {
|
|
95
|
+
fab: { size: 36, fontSize: "14px" },
|
|
96
|
+
item: { size: 28, spacing: 0, titleFontSize: "12px", buttonFontSize: "14px" }
|
|
97
|
+
},
|
|
98
|
+
small: {
|
|
99
|
+
fab: { size: 32, fontSize: "12px" },
|
|
100
|
+
item: { size: 24, spacing: 0, titleFontSize: "12px", buttonFontSize: "12px" }
|
|
101
|
+
},
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
const emit = defineEmits(["close", "outside-click", "click"])
|
|
108
|
+
|
|
109
|
+
const slots = useSlots()
|
|
110
|
+
const instance = getCurrentInstance()
|
|
111
|
+
|
|
112
|
+
const { zIndex, position, left, top, right, bottom } = props
|
|
113
|
+
|
|
114
|
+
const active = ref(false)
|
|
115
|
+
const moving = ref(false)
|
|
116
|
+
const style = reactive({ zIndex, position, left, top, right, bottom }) as any
|
|
117
|
+
const updateStyle = function () {
|
|
118
|
+
style.value = { zIndex, position, left, top, right, bottom }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
provide("FuSpeedDial", instance)
|
|
122
|
+
|
|
123
|
+
watch(() => props.value, (v) => {
|
|
124
|
+
active.value = v
|
|
125
|
+
})
|
|
126
|
+
watch(() => props.position, updateStyle)
|
|
127
|
+
watch(() => props.zIndex, updateStyle)
|
|
128
|
+
watch(() => props.left, updateStyle)
|
|
129
|
+
watch(() => props.right, updateStyle)
|
|
130
|
+
watch(() => props.top, updateStyle)
|
|
131
|
+
watch(() => props.bottom, updateStyle)
|
|
132
|
+
|
|
133
|
+
const saveKey = computed(() => {
|
|
134
|
+
return "Fu-SD-" + props.localKey
|
|
135
|
+
})
|
|
136
|
+
const hashChildren = computed(() => {
|
|
137
|
+
if (props.items && props.items.length > 0) {
|
|
138
|
+
return true
|
|
139
|
+
}
|
|
140
|
+
return slots && slots.default
|
|
141
|
+
})
|
|
142
|
+
const config = computed(() => {
|
|
143
|
+
return props.sizeOptions[props.size] || props.sizeOptions["default"]
|
|
144
|
+
})
|
|
145
|
+
const buttonProps = computed(() => {
|
|
146
|
+
let type = props.type
|
|
147
|
+
let rotate = true
|
|
148
|
+
let activeValue = active.value
|
|
149
|
+
let size = config.value.fab.size + "px"
|
|
150
|
+
let fontSize = config.value.fab.fontSize
|
|
151
|
+
let icon = props.activeIcon === props.icon ? props.icon : active.value ? props.activeIcon : props.icon
|
|
152
|
+
return { type, rotate, active: activeValue, size, fontSize, icon }
|
|
153
|
+
})
|
|
154
|
+
const spacing = computed(() => {
|
|
155
|
+
let spacing = config.value.item.spacing || 0
|
|
156
|
+
spacing += (config.value.fab.size - config.value.item.size) / 2
|
|
157
|
+
return spacing
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
const contentPosition = computed(() => {
|
|
161
|
+
let position = config.value.fab.size + spacing.value
|
|
162
|
+
if (["top", "left"].includes(props.direction)) {
|
|
163
|
+
position = -config.value.fab.size - spacing.value
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
let style: CSSProperties = { position: "absolute", zIndex: props.zIndex }
|
|
167
|
+
if (["top", "bottom"].includes(props.direction)) {
|
|
168
|
+
style.top = position + "px"
|
|
169
|
+
} else {
|
|
170
|
+
style.top = 0
|
|
171
|
+
style.left = position + "px"
|
|
172
|
+
}
|
|
173
|
+
return style
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
function toggle(active?: any) {
|
|
177
|
+
if (!moving.value && hashChildren.value) {
|
|
178
|
+
active.value = active === undefined ? !active.value : active
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// function outsideClickClose() {
|
|
183
|
+
// if (props.outsideClose && !props.manual) {
|
|
184
|
+
// toggle(false)
|
|
185
|
+
// }
|
|
186
|
+
// emit("outside-click", [props.id, active.value])
|
|
187
|
+
// }
|
|
188
|
+
function click(e: Event) {
|
|
189
|
+
if (!props.manual) {
|
|
190
|
+
toggle()
|
|
191
|
+
}
|
|
192
|
+
emit("click", [props.id, active.value], e)
|
|
193
|
+
}
|
|
194
|
+
function mousedown() {
|
|
195
|
+
if (moving.value) {
|
|
196
|
+
document.addEventListener('mousemove', mousemove)
|
|
197
|
+
document.addEventListener('mouseup', mouseup)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function mousemove(e: MouseEvent) {
|
|
201
|
+
moving.value = true
|
|
202
|
+
if (props.position === "fixed") {
|
|
203
|
+
const el = instance.vnode.el as HTMLElement
|
|
204
|
+
const rect = el.getBoundingClientRect()
|
|
205
|
+
let left = e.clientX - rect.width / 2
|
|
206
|
+
let top = e.clientY - rect.height / 2
|
|
207
|
+
style.value.left = left + 'px'
|
|
208
|
+
style.value.top = top + 'px'
|
|
209
|
+
delete style.value.right
|
|
210
|
+
delete style.value.bottom
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (props.position === "absolute") {
|
|
214
|
+
const { offsetLeft, offsetTop, clientWidth, clientHeight, offsetParent } = this.$el
|
|
215
|
+
const maxWidth = offsetParent.clientWidth - clientWidth
|
|
216
|
+
const maxHeight = offsetParent.clientHeight - clientHeight
|
|
217
|
+
|
|
218
|
+
let left = offsetLeft + e.movementX
|
|
219
|
+
let top = offsetTop + e.movementY
|
|
220
|
+
if (left > 0 && left < maxWidth) {
|
|
221
|
+
style.value.left = left + 'px'
|
|
222
|
+
delete style.value.right
|
|
223
|
+
}
|
|
224
|
+
if (top > 0 && top < maxHeight) {
|
|
225
|
+
style.value.top = top + 'px'
|
|
226
|
+
delete style.value.bottom
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function mouseup() {
|
|
231
|
+
writePosition()
|
|
232
|
+
document.removeEventListener('mousemove', mousemove)
|
|
233
|
+
document.removeEventListener('mouseup', mouseup)
|
|
234
|
+
setTimeout(() => moving.value = false)
|
|
235
|
+
}
|
|
236
|
+
function writePosition() {
|
|
237
|
+
if (props.localKey) {
|
|
238
|
+
localStorage.setItem(saveKey.value, JSON.stringify(style.value))
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function readPosition() {
|
|
242
|
+
// *******????
|
|
243
|
+
// if (this.savePosition) {
|
|
244
|
+
let position = localStorage.getItem(saveKey.value)
|
|
245
|
+
try {
|
|
246
|
+
localStorage.getItem(saveKey.value)
|
|
247
|
+
if (position) {
|
|
248
|
+
style.value = JSON.parse(position)
|
|
249
|
+
}
|
|
250
|
+
} catch (e) {
|
|
251
|
+
console.warn(saveKey.value + " error", e)
|
|
252
|
+
}
|
|
253
|
+
// }
|
|
254
|
+
}
|
|
255
|
+
function itemClick(arg: any, e: any) {
|
|
256
|
+
console.log(arg)
|
|
257
|
+
const { index } = arg
|
|
258
|
+
if (index !== undefined) {
|
|
259
|
+
const item = props.items[index];
|
|
260
|
+
if (item.click && typeof item.click === "function") return item.click(arg, e)
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function close() {
|
|
265
|
+
if (props.itemClickClose && !props.manual) {
|
|
266
|
+
toggle(false)
|
|
267
|
+
}
|
|
268
|
+
emit("close", [props.id, active.value])
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
onMounted(() => {
|
|
272
|
+
readPosition()
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
defineExpose({
|
|
277
|
+
close
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
</script>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="fu-speed-dial-action-button">
|
|
3
|
+
<div v-if="title" class="fu-speed-dial-action-button__title" :style="titleSize">
|
|
4
|
+
<slot name="title">
|
|
5
|
+
<div class="fu-speed-dial-action-button__text" :class="titleClass" :style="titleStyle" @click="click">{{
|
|
6
|
+
title }}
|
|
7
|
+
</div>
|
|
8
|
+
</slot>
|
|
9
|
+
</div>
|
|
10
|
+
<slot>
|
|
11
|
+
<fu-speed-dial-button :class="buttonClass" v-bind="buttonProps" :icon="icon" @click="click"/>
|
|
12
|
+
</slot>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script setup lang="ts">
|
|
17
|
+
import { inject, computed } from 'vue'
|
|
18
|
+
import type { CSSProperties } from 'vue'
|
|
19
|
+
import FuSpeedDialButton from "@/components/speed-dial/FuSpeedDialButton.vue";
|
|
20
|
+
|
|
21
|
+
const props = defineProps({
|
|
22
|
+
index: Number,
|
|
23
|
+
icon: {
|
|
24
|
+
type: String,
|
|
25
|
+
default: "el-icon-plus"
|
|
26
|
+
},
|
|
27
|
+
titleClass: String,
|
|
28
|
+
titleBgColor: String,
|
|
29
|
+
titleColor: String,
|
|
30
|
+
buttonClass: String,
|
|
31
|
+
bgColor: String,
|
|
32
|
+
color: String,
|
|
33
|
+
title: [String, Number]
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const emit = defineEmits(["click"])
|
|
37
|
+
const FuSpeedDial = inject('FuSpeedDial')
|
|
38
|
+
|
|
39
|
+
const config =computed(()=>{
|
|
40
|
+
return FuSpeedDial.config;
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
const direction =computed(()=>{
|
|
44
|
+
return FuSpeedDial.direction;
|
|
45
|
+
})
|
|
46
|
+
const clickClose =computed(()=>{
|
|
47
|
+
return FuSpeedDial.clickClose;
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const titleSize =computed(()=>{
|
|
51
|
+
let size = config.value.fab.size + "px";
|
|
52
|
+
let style: CSSProperties = {position: "absolute", height: size};
|
|
53
|
+
if (["top", "bottom"].includes(direction.value)) {
|
|
54
|
+
style['text-align'] = "right"
|
|
55
|
+
style['right'] = size
|
|
56
|
+
} else {
|
|
57
|
+
style['text-align'] = "center"
|
|
58
|
+
style['min-width'] = size
|
|
59
|
+
if (props.index % 2 === 0) {
|
|
60
|
+
style.top = size
|
|
61
|
+
} else {
|
|
62
|
+
style.top = "-" + size
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return style;
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
const titleStyle =computed(()=>{
|
|
69
|
+
let backgroundColor = props.titleBgColor;
|
|
70
|
+
let color = props.titleColor
|
|
71
|
+
let fontSize = config.value.item.titleFontSize
|
|
72
|
+
return {backgroundColor, color, fontSize}
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const buttonProps =computed(()=>{
|
|
76
|
+
let backgroundColor = props.bgColor;
|
|
77
|
+
let color = props.color
|
|
78
|
+
let fontSize = config.value.item.buttonFontSize
|
|
79
|
+
let size = config.value.item.size + "px";
|
|
80
|
+
return {backgroundColor, color, fontSize, size}
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
function click(e: Event) {
|
|
84
|
+
const {index, title} = props
|
|
85
|
+
emit("click", {index, title}, e);
|
|
86
|
+
FuSpeedDial.close();
|
|
87
|
+
}
|
|
88
|
+
</script>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="[
|
|
3
|
+
'fu-speed-dial-button',
|
|
4
|
+
'fu-speed-dial-button--' + type,
|
|
5
|
+
{
|
|
6
|
+
'fu-speed-dial-button--rotate': rotate,
|
|
7
|
+
'is-disabled': disabled,
|
|
8
|
+
'is-active': active,
|
|
9
|
+
}, ]"
|
|
10
|
+
:style="{
|
|
11
|
+
width: size,
|
|
12
|
+
height: size,
|
|
13
|
+
backgroundColor: backgroundColor,
|
|
14
|
+
color: color,
|
|
15
|
+
fontSize: fontSize }">
|
|
16
|
+
<slot>
|
|
17
|
+
<i :class="icon" />
|
|
18
|
+
</slot>
|
|
19
|
+
</div>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script setup lang="ts">
|
|
23
|
+
import { validateType } from "@/tools/theme"
|
|
24
|
+
const props = defineProps({
|
|
25
|
+
type: {
|
|
26
|
+
type: String,
|
|
27
|
+
default: "default",
|
|
28
|
+
validator: validateType
|
|
29
|
+
},
|
|
30
|
+
rotate: Boolean,
|
|
31
|
+
disabled: Boolean,
|
|
32
|
+
active: Boolean,
|
|
33
|
+
icon: String,
|
|
34
|
+
size: {
|
|
35
|
+
type: String,
|
|
36
|
+
default: "32px"
|
|
37
|
+
},
|
|
38
|
+
backgroundColor: String,
|
|
39
|
+
color: String,
|
|
40
|
+
fontSize: String
|
|
41
|
+
})
|
|
42
|
+
</script>
|