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,65 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="fu-filter-component">
|
|
3
|
+
<div class="fu-filter-component__label">{{ label }}</div>
|
|
4
|
+
<div class="fu-filter-component__content">
|
|
5
|
+
<!-- :size="configSize" -->
|
|
6
|
+
<el-date-picker class="fu-filter-date" v-model="value" v-bind="$attrs"
|
|
7
|
+
:placeholder="t('fu.search_bar.select_date_time')" type="datetimerange"
|
|
8
|
+
:value-format="valueFormat"
|
|
9
|
+
:start-placeholder="t('fu.search_bar.start_date_time')"
|
|
10
|
+
:end-placeholder="t('fu.search_bar.end_date_time')">
|
|
11
|
+
</el-date-picker>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script setup lang="ts">
|
|
17
|
+
import {ref, computed, inject} from "vue";
|
|
18
|
+
import {FilterCondition, ReferenceContext, referenceKey} from "../types";
|
|
19
|
+
import {datetimeFormat} from "@/tools/time";
|
|
20
|
+
import {useLocale} from "@/hooks"
|
|
21
|
+
defineOptions({ name: "FuFilterDateTime" });
|
|
22
|
+
const {t} = useLocale()
|
|
23
|
+
|
|
24
|
+
const props = defineProps({
|
|
25
|
+
label: String,
|
|
26
|
+
field: {
|
|
27
|
+
type: String,
|
|
28
|
+
required: true
|
|
29
|
+
},
|
|
30
|
+
valueFormat: {
|
|
31
|
+
type: String,
|
|
32
|
+
default: "x",
|
|
33
|
+
},
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const value = ref('')
|
|
37
|
+
|
|
38
|
+
const valueLabel = computed(() => {
|
|
39
|
+
return (
|
|
40
|
+
datetimeFormat(value.value[0]) +
|
|
41
|
+
" - " +
|
|
42
|
+
datetimeFormat(value.value[1])
|
|
43
|
+
);
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
function getCondition(): FilterCondition | undefined {
|
|
47
|
+
if (!String(value.value)) return;
|
|
48
|
+
let {field, label} = props
|
|
49
|
+
return {field, label, value: value.value, valueLabel: valueLabel.value}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function init(v: any) {
|
|
53
|
+
value.value = v !== undefined ? v : ''
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const references = inject(referenceKey)
|
|
57
|
+
const field = props.field
|
|
58
|
+
const reference: ReferenceContext = {field, init, getCondition}
|
|
59
|
+
references?.value.push(reference)
|
|
60
|
+
|
|
61
|
+
defineExpose({
|
|
62
|
+
getCondition,
|
|
63
|
+
init
|
|
64
|
+
})
|
|
65
|
+
</script>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="fu-filter-option" :class="{ 'is-selected': selected, 'is-disabled': disabled }" @click.stop="click">
|
|
3
|
+
{{ label || value }}
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup lang="ts">
|
|
8
|
+
import {computed, inject} from "vue";
|
|
9
|
+
import {selectKey} from "@/components/filter-bar/types";
|
|
10
|
+
|
|
11
|
+
const props = defineProps({
|
|
12
|
+
value: {
|
|
13
|
+
type: [String, Number],
|
|
14
|
+
required: true
|
|
15
|
+
},
|
|
16
|
+
label: [String, Number],
|
|
17
|
+
disabled: {
|
|
18
|
+
type: Boolean,
|
|
19
|
+
default: false
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const select = inject(selectKey)
|
|
24
|
+
|
|
25
|
+
const selected = computed(() => {
|
|
26
|
+
if (!select) return false
|
|
27
|
+
if (Array.isArray(select.selection.value)) {
|
|
28
|
+
return select.selection.value.includes(props.value)
|
|
29
|
+
} else {
|
|
30
|
+
return select.selection.value === props.value
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
function click() {
|
|
35
|
+
select?.setSelected(props.value, selected.value)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
</script>
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="fu-filter-component">
|
|
3
|
+
<div class="fu-filter-component__label">{{ label }}</div>
|
|
4
|
+
<div class="fu-filter-component__content">
|
|
5
|
+
<fu-filter-option :label="o.label" :value="o.value" v-for="o in showOptions" :key="o.value"/>
|
|
6
|
+
<el-popover popper-class="fu-filter-component-popover" :show-arrow="false" placement="bottom-start"
|
|
7
|
+
trigger="click" width="240">
|
|
8
|
+
<el-select v-model="selection" v-bind="$attrs" :multiple="multiple" @change="change" :teleported="false"
|
|
9
|
+
:placeholder="t('fu.search_bar.please_select')">
|
|
10
|
+
<el-option value="" v-if="useSelectAll && multiple">
|
|
11
|
+
<div @click="selectAll">{{ t('fu.filter_bar.select_all') }}</div>
|
|
12
|
+
</el-option>
|
|
13
|
+
<el-option :label="o.label" :value="o.value" v-for="o in options" :key="o.value"/>
|
|
14
|
+
</el-select>
|
|
15
|
+
<template #reference>
|
|
16
|
+
<div class="fu-filter-option">
|
|
17
|
+
<el-icon>
|
|
18
|
+
<Plus/>
|
|
19
|
+
</el-icon>
|
|
20
|
+
{{ t('fu.filter_bar.more') }}
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
23
|
+
</el-popover>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<script setup lang="ts">
|
|
29
|
+
import {ref, provide, computed, PropType, Ref, inject} from "vue";
|
|
30
|
+
import FuFilterOption from "./FuFilterOption.vue";
|
|
31
|
+
import {FilterCondition, OptionProps, ReferenceContext, referenceKey, selectKey} from "../types";
|
|
32
|
+
|
|
33
|
+
import {useLocale} from "@/hooks"
|
|
34
|
+
defineOptions({ name: "FuFilterSelect" });
|
|
35
|
+
const {t} = useLocale()
|
|
36
|
+
|
|
37
|
+
const props = defineProps({
|
|
38
|
+
multiple: {
|
|
39
|
+
type: Boolean,
|
|
40
|
+
default: false
|
|
41
|
+
},
|
|
42
|
+
showLimit: {
|
|
43
|
+
type: Number,
|
|
44
|
+
default: 3 // -1 全显示
|
|
45
|
+
},
|
|
46
|
+
useSelectAll: {
|
|
47
|
+
type: Boolean,
|
|
48
|
+
default: false
|
|
49
|
+
},
|
|
50
|
+
label: String,
|
|
51
|
+
field: {
|
|
52
|
+
type: String,
|
|
53
|
+
required: true
|
|
54
|
+
},
|
|
55
|
+
options: {
|
|
56
|
+
type: Array as PropType<OptionProps[]>,
|
|
57
|
+
default: []
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
const emit = defineEmits(["change"])
|
|
61
|
+
|
|
62
|
+
const selection: Ref<Array<string | number> | string | number> = ref(props.multiple ? [] : '')
|
|
63
|
+
|
|
64
|
+
const showOptions = computed(() => {
|
|
65
|
+
return props.options.filter((o, i) => {
|
|
66
|
+
let show = props.showLimit < 0 ? true : i < props.showLimit
|
|
67
|
+
if (Array.isArray(selection.value)) {
|
|
68
|
+
return show || selection.value.includes(o.value)
|
|
69
|
+
} else {
|
|
70
|
+
return show || selection.value === o.value
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const valueLabel = computed(() => {
|
|
76
|
+
if (Array.isArray(selection.value)) {
|
|
77
|
+
let values: any = []
|
|
78
|
+
selection.value.forEach((v: any) => {
|
|
79
|
+
values.push(getValueLabel(v))
|
|
80
|
+
})
|
|
81
|
+
return values.join(", ");
|
|
82
|
+
}
|
|
83
|
+
return getValueLabel(selection.value);
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
function change(v: string) {
|
|
87
|
+
if (v.includes("")) {
|
|
88
|
+
selection.value = props.options.map(o => o.value)
|
|
89
|
+
}
|
|
90
|
+
emit("change", selection.value)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function setSelected(value: string | number, selected: boolean) {
|
|
94
|
+
if (!Array.isArray(selection.value)) {
|
|
95
|
+
selection.value = selected ? '' : value
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
if (selected) {
|
|
99
|
+
let index = selection.value.indexOf(value)
|
|
100
|
+
selection.value.splice(index, 1)
|
|
101
|
+
} else {
|
|
102
|
+
selection.value.push(value)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function selectAll() {
|
|
107
|
+
selection.value = props.options.map(o => o.value)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function getValueLabel(value: string | number) {
|
|
111
|
+
for (let o of props.options) {
|
|
112
|
+
if (o.value === value) {
|
|
113
|
+
return o.label
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return value
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function getCondition(): FilterCondition | undefined {
|
|
120
|
+
if (!selection.value || (Array.isArray(selection.value) && selection.value.length === 0)) return;
|
|
121
|
+
let {field, label} = props
|
|
122
|
+
return {field, label, value: selection.value, valueLabel: valueLabel.value}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function init(v: any) {
|
|
126
|
+
selection.value = v !== undefined ? v : props.multiple ? [] : ''
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
provide(selectKey, {
|
|
130
|
+
setSelected,
|
|
131
|
+
selection: selection,
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
const references = inject(referenceKey)
|
|
135
|
+
const field = props.field
|
|
136
|
+
const reference: ReferenceContext = {field, init, getCondition}
|
|
137
|
+
references?.value.push(reference)
|
|
138
|
+
|
|
139
|
+
defineExpose({
|
|
140
|
+
getCondition,
|
|
141
|
+
init,
|
|
142
|
+
})
|
|
143
|
+
</script>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import FuSearchInput from "./FuSearchInput.vue"
|
|
2
|
+
import FuFilterBar from "./FuFilterBar.vue";
|
|
3
|
+
import FuFilter from "./FuFilter.vue";
|
|
4
|
+
import FuFilterSelect from "./filter-components/FuFilterSelect.vue";
|
|
5
|
+
import FuFilterDate from "./filter-components/FuFilterDate.vue";
|
|
6
|
+
import FuFilterDateTime from "./filter-components/FuFilterDateTime.vue";
|
|
7
|
+
|
|
8
|
+
import type {App} from 'vue'
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
install: (app: App): void => {
|
|
12
|
+
app.component(FuFilterBar.name, FuFilterBar)
|
|
13
|
+
app.component(FuFilter.name, FuFilter)
|
|
14
|
+
app.component(FuSearchInput.name, FuSearchInput)
|
|
15
|
+
app.component(FuFilterSelect.name, FuFilterSelect)
|
|
16
|
+
app.component(FuFilterDate.name, FuFilterDate)
|
|
17
|
+
app.component(FuFilterDateTime.name, FuFilterDateTime)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {InjectionKey, Ref} from "vue";
|
|
2
|
+
|
|
3
|
+
export const selectKey = Symbol('SelectKey') as unknown as InjectionKey<SelectContext>
|
|
4
|
+
|
|
5
|
+
export interface SelectContext {
|
|
6
|
+
selection: Ref<Array<string | number> | string | number>
|
|
7
|
+
|
|
8
|
+
setSelected(value: string | number, selected: boolean): void
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const referenceKey = Symbol('ReferenceKey') as unknown as InjectionKey<Ref<ReferenceContext[]>>
|
|
12
|
+
|
|
13
|
+
export interface ReferenceContext {
|
|
14
|
+
field: string,
|
|
15
|
+
|
|
16
|
+
init(v: any): void
|
|
17
|
+
|
|
18
|
+
getCondition(): FilterCondition | undefined
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface OptionProps {
|
|
22
|
+
label: string
|
|
23
|
+
value: string | number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface FilterCondition {
|
|
27
|
+
field: string
|
|
28
|
+
label?: string
|
|
29
|
+
value: any
|
|
30
|
+
valueLabel?: string
|
|
31
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<fu-read-write-switch :write-trigger="writeTrigger" :data="data">
|
|
3
|
+
<template #default="{ read }">
|
|
4
|
+
<el-input v-model="data" v-bind="$attrs" @input="input" @blur="blur(read, $event)"
|
|
5
|
+
@keydown="keydown(read, $event)" />
|
|
6
|
+
</template>
|
|
7
|
+
</fu-read-write-switch>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script setup lang="ts">
|
|
11
|
+
|
|
12
|
+
import { ref, watch } from "vue";
|
|
13
|
+
defineOptions({ name: "FuInputRwSwitch" });
|
|
14
|
+
const props = defineProps({
|
|
15
|
+
value: [String, Number],
|
|
16
|
+
writeTrigger: {
|
|
17
|
+
type: String,
|
|
18
|
+
default: "click",
|
|
19
|
+
validator: (value: string) => {
|
|
20
|
+
return ['click', 'dblclick'].includes(value)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
const emit = defineEmits(["input", "blur"])
|
|
25
|
+
|
|
26
|
+
const data = ref(props.value)
|
|
27
|
+
|
|
28
|
+
watch(() => props.value, (v) => {
|
|
29
|
+
data.value = v
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
function input(e: Event) {
|
|
33
|
+
emit("input", data.value, e)
|
|
34
|
+
}
|
|
35
|
+
function blur(read: Function, e: Event) {
|
|
36
|
+
emit("blur", data.value, e)
|
|
37
|
+
read()
|
|
38
|
+
}
|
|
39
|
+
function keydown(read: Function, e: KeyboardEvent) {
|
|
40
|
+
if (e.key === "Enter") {
|
|
41
|
+
read()
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
</script>
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { ref, watch, defineComponent, h, nextTick } from 'vue'
|
|
3
|
+
import { uuid } from "@/tools/utils"
|
|
4
|
+
|
|
5
|
+
const TRIGGERS = ['manual', 'click', 'dblclick']
|
|
6
|
+
|
|
7
|
+
export default defineComponent({
|
|
8
|
+
name: "FuReadWriteSwitch",
|
|
9
|
+
props: {
|
|
10
|
+
value: Boolean,
|
|
11
|
+
data: [String, Number, Boolean],
|
|
12
|
+
writeTrigger: {
|
|
13
|
+
type: String,
|
|
14
|
+
default: "click",
|
|
15
|
+
validator: (value: string) => {
|
|
16
|
+
return TRIGGERS.includes(value)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
setup(props, { slots, emit }) {
|
|
22
|
+
const id = ref(uuid())
|
|
23
|
+
const write = ref(props.value === undefined ? false : props.value)
|
|
24
|
+
watch(() => props.value, (v) => {
|
|
25
|
+
console.log(v)
|
|
26
|
+
if (v === write.value) return
|
|
27
|
+
|
|
28
|
+
if (v) {
|
|
29
|
+
switchWrite()
|
|
30
|
+
} else {
|
|
31
|
+
switchRead()
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
function change() {
|
|
36
|
+
emit("input", write.value)
|
|
37
|
+
emit("change", [props.data, write.value])
|
|
38
|
+
}
|
|
39
|
+
function switchWrite() {
|
|
40
|
+
write.value = true
|
|
41
|
+
|
|
42
|
+
nextTick(() => {
|
|
43
|
+
// 目前只支持input和textarea自动获取焦点
|
|
44
|
+
const nid = document.getElementById(id.value)
|
|
45
|
+
const input = nid?.querySelector("input")
|
|
46
|
+
input?.click() // el-select等组件自动展开
|
|
47
|
+
input?.focus()
|
|
48
|
+
const textarea = nid?.querySelector("textarea")
|
|
49
|
+
textarea?.focus()
|
|
50
|
+
|
|
51
|
+
// 可以在change事件自定义获取焦点
|
|
52
|
+
change()
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
function switchRead() {
|
|
56
|
+
write.value = false
|
|
57
|
+
change()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const context: any = {
|
|
61
|
+
class: "fu-read-write-switch",
|
|
62
|
+
attrs: { id: id.value },
|
|
63
|
+
on: {}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 读状态添加触发写状态的事件
|
|
67
|
+
if (!write.value && props.writeTrigger !== TRIGGERS[0]) {
|
|
68
|
+
context.on[props.writeTrigger] = switchWrite
|
|
69
|
+
}
|
|
70
|
+
// 没有slot时显示文本数据
|
|
71
|
+
let children: any = props.data
|
|
72
|
+
|
|
73
|
+
// 读状态内容,提供切换到写状态的方法
|
|
74
|
+
if (!write.value && slots.read) {
|
|
75
|
+
children = slots.read({
|
|
76
|
+
write: switchWrite
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 写状态内容,提供切换到读状态的方法
|
|
81
|
+
if (write.value && slots.default) {
|
|
82
|
+
children = slots.default({
|
|
83
|
+
read: switchRead
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return () => h("div", context, children)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
})
|
|
91
|
+
</script>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<fu-read-write-switch :write-trigger="writeTrigger" :data="data">
|
|
3
|
+
<template #read>
|
|
4
|
+
<slot name="read">
|
|
5
|
+
{{ data }}
|
|
6
|
+
</slot>
|
|
7
|
+
</template>
|
|
8
|
+
<template #default="{ read }">
|
|
9
|
+
<el-select v-model="data" v-bind="$attrs" @input="input" @blur="blur(read, $event)"
|
|
10
|
+
@change="change(read, $event)">
|
|
11
|
+
<slot>
|
|
12
|
+
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
|
|
13
|
+
</slot>
|
|
14
|
+
</el-select>
|
|
15
|
+
</template>
|
|
16
|
+
</fu-read-write-switch>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script setup lang="ts">
|
|
20
|
+
import { ref, watch } from "vue";
|
|
21
|
+
defineOptions({ name: "FuSelectRwSwitch" });
|
|
22
|
+
const props = defineProps({
|
|
23
|
+
value: [String, Number],
|
|
24
|
+
options: Array,
|
|
25
|
+
writeTrigger: {
|
|
26
|
+
type: String,
|
|
27
|
+
default: "click",
|
|
28
|
+
validator: (value: string) => {
|
|
29
|
+
return ['click', 'dblclick'].includes(value)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
const emit = defineEmits(["input", "blur", "change"])
|
|
34
|
+
const data = ref(props.value)
|
|
35
|
+
|
|
36
|
+
watch(() => props.value, (v) => {
|
|
37
|
+
data.value = v
|
|
38
|
+
})
|
|
39
|
+
function input(e: Event) {
|
|
40
|
+
emit("input", data.value, e)
|
|
41
|
+
}
|
|
42
|
+
function blur(read: Function, e: Event) {
|
|
43
|
+
setTimeout(() => {
|
|
44
|
+
read()
|
|
45
|
+
}, 100)
|
|
46
|
+
emit("blur", data.value, e)
|
|
47
|
+
}
|
|
48
|
+
function change(read: Function, e: Event) {
|
|
49
|
+
emit("change", data.value, e)
|
|
50
|
+
read()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
</script>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import FuReadWriteSwitch from "./FuReadWriteSwitch.vue"
|
|
2
|
+
import FuInputRwSwitch from "./FuInputRwSwitch.vue"
|
|
3
|
+
import FuSelectRwSwitch from "./FuSelectRwSwitch.vue"
|
|
4
|
+
|
|
5
|
+
import type { App } from 'vue'
|
|
6
|
+
|
|
7
|
+
FuReadWriteSwitch.install = (app: App): void => {
|
|
8
|
+
app.component(FuReadWriteSwitch.name, FuReadWriteSwitch)
|
|
9
|
+
app.component(FuInputRwSwitch.name, FuInputRwSwitch)
|
|
10
|
+
app.component(FuSelectRwSwitch.name, FuSelectRwSwitch)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default FuReadWriteSwitch;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="fu-complex-search">
|
|
3
|
+
<el-popover trigger="manual" v-model="active" :show-arrow="false" @hide="closePopover"
|
|
4
|
+
popper-class="fu-complex-components">
|
|
5
|
+
|
|
6
|
+
<div class="fu-complex-components__body">
|
|
7
|
+
<slot>
|
|
8
|
+
<!-- :size="configSize" -->
|
|
9
|
+
<component v-for="(c, i) in components" :key="i" :is="c.component" v-bind="c" :ref="c.field" v-on="c" />
|
|
10
|
+
</slot>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="fu-complex-components__footer">
|
|
13
|
+
<!-- :size="configSize" -->
|
|
14
|
+
<el-button @click="active = false">{{ t('fu.search_bar.cancel') }}</el-button>
|
|
15
|
+
<el-button type="primary" @click="ok">{{ t('fu.search_bar.ok') }}</el-button>
|
|
16
|
+
</div>
|
|
17
|
+
<template #reference>
|
|
18
|
+
<!-- :size="configSize" -->
|
|
19
|
+
<fu-search-bar-button icon="ArrowRight" @click="toggle"
|
|
20
|
+
:class="['fu-complex-search__trigger', { 'is-active': active }]" :tooltip="t('fu.search_bar.adv_search')" />
|
|
21
|
+
</template>
|
|
22
|
+
</el-popover>
|
|
23
|
+
</div>
|
|
24
|
+
</template>
|
|
25
|
+
|
|
26
|
+
<script setup lang="ts">
|
|
27
|
+
import { ref, computed, useSlots, getCurrentInstance } from "vue";
|
|
28
|
+
import FuSearchBarButton from "@/components/search-bar/FuSearchBarButton.vue";
|
|
29
|
+
import { useLocale } from "@/hooks"
|
|
30
|
+
|
|
31
|
+
const slots = useSlots()
|
|
32
|
+
const instance = getCurrentInstance()
|
|
33
|
+
|
|
34
|
+
const props = defineProps({
|
|
35
|
+
components: Array,
|
|
36
|
+
});
|
|
37
|
+
const emit = defineEmits(["close", "change"])
|
|
38
|
+
const { t } = useLocale()
|
|
39
|
+
const active = ref(false)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
function closePopover() {
|
|
43
|
+
emit("close")
|
|
44
|
+
}
|
|
45
|
+
function toggle() {
|
|
46
|
+
active.value = !active.value
|
|
47
|
+
refs.value.forEach((r: any) => {
|
|
48
|
+
// *****r.init 有问题
|
|
49
|
+
if (r?.init) {
|
|
50
|
+
r.init()
|
|
51
|
+
} else {
|
|
52
|
+
console.warn("init undefined", r)
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function close() {
|
|
58
|
+
active.value = false
|
|
59
|
+
}
|
|
60
|
+
function ok() {
|
|
61
|
+
active.value = false
|
|
62
|
+
let conditions: any = [];
|
|
63
|
+
refs.value.forEach((r: any) => {
|
|
64
|
+
let condition
|
|
65
|
+
if (r.getCondition) {
|
|
66
|
+
condition = r.getCondition()
|
|
67
|
+
} else {
|
|
68
|
+
console.warn("getCondition undefined", r)
|
|
69
|
+
}
|
|
70
|
+
if (condition && condition.value !== undefined) {
|
|
71
|
+
conditions.push(condition)
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
emit("change", conditions)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function createConditions(conditions: any) {
|
|
78
|
+
let result: any = []
|
|
79
|
+
if (conditions) {
|
|
80
|
+
Object.keys(conditions).forEach(key => {
|
|
81
|
+
let c = conditions[key]
|
|
82
|
+
refs.value.forEach((r: any) => {
|
|
83
|
+
if (r.field === key) {
|
|
84
|
+
result.push(r.createCondition(c.value, c.operator))
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
return result
|
|
90
|
+
}
|
|
91
|
+
const refs = computed(() => {
|
|
92
|
+
let refs: any = [];
|
|
93
|
+
if (slots.default?.()[0].children.length) {
|
|
94
|
+
// 使用slot
|
|
95
|
+
slots.default?.().forEach((component: any) => {
|
|
96
|
+
refs.push(component.componentInstance)
|
|
97
|
+
})
|
|
98
|
+
} else {
|
|
99
|
+
// 使用components
|
|
100
|
+
props.components.forEach((c: any) => {
|
|
101
|
+
refs.push(instance.refs[c.field][0])
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
return refs
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
</script>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- , 'fu-quick-search--' + configSize -->
|
|
3
|
+
<div :class="['fu-quick-search']">
|
|
4
|
+
<el-icon v-if="useIcon">
|
|
5
|
+
<Search />
|
|
6
|
+
</el-icon>
|
|
7
|
+
<label>
|
|
8
|
+
<input :placeholder="placeholder" v-model="quick" @input="input" @blur="blur" @keydown="keydown" />
|
|
9
|
+
</label>
|
|
10
|
+
</div>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script setup lang="ts">
|
|
14
|
+
import { ref, watch } from "vue";
|
|
15
|
+
defineOptions({ name: "FuQuickSearch" });
|
|
16
|
+
const props = defineProps({
|
|
17
|
+
value: String,
|
|
18
|
+
placeholder: String,
|
|
19
|
+
useIcon: {
|
|
20
|
+
type: Boolean,
|
|
21
|
+
default: true
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const emit = defineEmits(["input", "change"])
|
|
26
|
+
const quick = ref("")
|
|
27
|
+
|
|
28
|
+
watch(() => props.value, (val: any) => {
|
|
29
|
+
quick.value = val
|
|
30
|
+
})
|
|
31
|
+
function input(e: Event) {
|
|
32
|
+
emit("input", quick.value, e)
|
|
33
|
+
}
|
|
34
|
+
function blur(e: Event) {
|
|
35
|
+
emit("change", quick.value, e)
|
|
36
|
+
}
|
|
37
|
+
function keydown(e: Event) {
|
|
38
|
+
const event = e as KeyboardEvent
|
|
39
|
+
if (event.key === "Enter") {
|
|
40
|
+
emit("change", quick.value, e)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
</script>
|