refactor: use setup
parent
0df27a39bc
commit
b808fceb5f
|
|
@ -1,22 +1,9 @@
|
||||||
<!--
|
<!--
|
||||||
* @Description: 组件属性控件
|
* @Description: 组件属性控件
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import {
|
import { Checkbox, Col, Empty, Form, FormItem, Select } from 'ant-design-vue'
|
||||||
Checkbox,
|
import { computed, ref, watch } from 'vue'
|
||||||
Col,
|
|
||||||
Empty,
|
|
||||||
Form,
|
|
||||||
FormItem,
|
|
||||||
Input,
|
|
||||||
InputNumber,
|
|
||||||
RadioGroup,
|
|
||||||
Row,
|
|
||||||
Select,
|
|
||||||
Switch,
|
|
||||||
} from 'ant-design-vue'
|
|
||||||
import RadioButtonGroup from '/@/components/Form/src/components/RadioButtonGroup.vue'
|
|
||||||
import { computed, defineComponent, ref, watch } from 'vue'
|
|
||||||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||||
import {
|
import {
|
||||||
baseComponentAttrs,
|
baseComponentAttrs,
|
||||||
|
|
@ -28,145 +15,116 @@ import { formItemsForEach, remove } from '../../../utils'
|
||||||
import type { IBaseFormAttrs } from '../config/formItemPropsConfig'
|
import type { IBaseFormAttrs } from '../config/formItemPropsConfig'
|
||||||
import FormOptions from './FormOptions.vue'
|
import FormOptions from './FormOptions.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
const { formConfig } = useFormDesignState()
|
||||||
name: 'ComponentProps',
|
// 让compuated属性自动更新
|
||||||
components: {
|
const allOptions = ref([] as Omit<IBaseFormAttrs, 'tag'>[])
|
||||||
FormOptions,
|
function showControlAttrs(includes: string[] | undefined) {
|
||||||
Empty,
|
if (!includes)
|
||||||
Input,
|
return true
|
||||||
Form,
|
return includes.includes(formConfig.value.currentItem!.component)
|
||||||
FormItem,
|
}
|
||||||
Switch,
|
|
||||||
Checkbox,
|
if (formConfig.value.currentItem) {
|
||||||
Select,
|
formConfig.value.currentItem.componentProps
|
||||||
InputNumber,
|
= formConfig.value.currentItem.componentProps || {}
|
||||||
RadioGroup,
|
}
|
||||||
RadioButtonGroup,
|
|
||||||
Col,
|
watch(
|
||||||
Row,
|
() => formConfig.value.currentItem?.field,
|
||||||
|
(_newValue, oldValue) => {
|
||||||
|
formConfig.value.schemas
|
||||||
|
&& formItemsForEach(formConfig.value.schemas, (item) => {
|
||||||
|
if (item.link) {
|
||||||
|
const index = item.link.findIndex(linkItem => linkItem === oldValue)
|
||||||
|
index !== -1 && remove(item.link, index)
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
setup() {
|
)
|
||||||
// 让compuated属性自动更新
|
|
||||||
|
|
||||||
const allOptions = ref([] as Omit<IBaseFormAttrs, 'tag'>[])
|
watch(
|
||||||
const showControlAttrs = (includes: string[] | undefined) => {
|
() => formConfig.value.currentItem && formConfig.value.currentItem.component,
|
||||||
if (!includes)
|
() => {
|
||||||
return true
|
allOptions.value = []
|
||||||
return includes.includes(formConfig.value.currentItem!.component)
|
baseComponentControlAttrs.forEach((item) => {
|
||||||
}
|
item.category = 'control'
|
||||||
|
if (!item.includes) {
|
||||||
|
// 如果属性没有include,所有的控件都适用
|
||||||
|
|
||||||
const { formConfig } = useFormDesignState()
|
allOptions.value.push(item)
|
||||||
|
}
|
||||||
|
else if (item.includes.includes(formConfig.value.currentItem!.component)) {
|
||||||
|
// 如果有include,检查是否包含了当前控件类型
|
||||||
|
allOptions.value.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
if (formConfig.value.currentItem) {
|
baseComponentCommonAttrs.forEach((item) => {
|
||||||
formConfig.value.currentItem.componentProps
|
item.category = 'input'
|
||||||
= formConfig.value.currentItem.componentProps || {}
|
if (item.includes) {
|
||||||
}
|
if (item.includes.includes(formConfig.value.currentItem!.component))
|
||||||
|
allOptions.value.push(item)
|
||||||
watch(
|
}
|
||||||
() => formConfig.value.currentItem?.field,
|
else if (item.exclude) {
|
||||||
(_newValue, oldValue) => {
|
if (!item.exclude.includes(formConfig.value.currentItem!.component))
|
||||||
formConfig.value.schemas
|
allOptions.value.push(item)
|
||||||
&& formItemsForEach(formConfig.value.schemas, (item) => {
|
}
|
||||||
if (item.link) {
|
else {
|
||||||
const index = item.link.findIndex(linkItem => linkItem === oldValue)
|
allOptions.value.push(item)
|
||||||
index !== -1 && remove(item.link, index)
|
}
|
||||||
}
|
})
|
||||||
})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => formConfig.value.currentItem && formConfig.value.currentItem.component,
|
|
||||||
() => {
|
|
||||||
allOptions.value = []
|
|
||||||
baseComponentControlAttrs.forEach((item) => {
|
|
||||||
item.category = 'control'
|
|
||||||
if (!item.includes) {
|
|
||||||
// 如果属性没有include,所有的控件都适用
|
|
||||||
|
|
||||||
|
baseComponentAttrs[formConfig.value.currentItem!.component]
|
||||||
|
&& baseComponentAttrs[formConfig.value.currentItem!.component].forEach(async (item) => {
|
||||||
|
if (item.component) {
|
||||||
|
if (['Switch', 'Checkbox', 'Radio'].includes(item.component)) {
|
||||||
|
item.category = 'control'
|
||||||
allOptions.value.push(item)
|
allOptions.value.push(item)
|
||||||
}
|
}
|
||||||
else if (item.includes.includes(formConfig.value.currentItem!.component)) {
|
|
||||||
// 如果有include,检查是否包含了当前控件类型
|
|
||||||
allOptions.value.push(item)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
baseComponentCommonAttrs.forEach((item) => {
|
|
||||||
item.category = 'input'
|
|
||||||
if (item.includes) {
|
|
||||||
if (item.includes.includes(formConfig.value.currentItem!.component))
|
|
||||||
allOptions.value.push(item)
|
|
||||||
}
|
|
||||||
else if (item.exclude) {
|
|
||||||
if (!item.exclude.includes(formConfig.value.currentItem!.component))
|
|
||||||
allOptions.value.push(item)
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
|
item.category = 'input'
|
||||||
allOptions.value.push(item)
|
allOptions.value.push(item)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
baseComponentAttrs[formConfig.value.currentItem!.component]
|
|
||||||
&& baseComponentAttrs[formConfig.value.currentItem!.component].forEach(async (item) => {
|
|
||||||
if (item.component) {
|
|
||||||
if (['Switch', 'Checkbox', 'Radio'].includes(item.component)) {
|
|
||||||
item.category = 'control'
|
|
||||||
allOptions.value.push(item)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
item.category = 'input'
|
|
||||||
allOptions.value.push(item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
immediate: true,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
// 控制性的选项
|
|
||||||
const controlOptions = computed(() => {
|
|
||||||
return allOptions.value.filter((item) => {
|
|
||||||
return item.category === 'control'
|
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
// 非控制性选择
|
|
||||||
const inputOptions = computed(() => {
|
|
||||||
return allOptions.value.filter((item) => {
|
|
||||||
return item.category === 'input'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => formConfig.value.currentItem!.componentProps,
|
|
||||||
() => {
|
|
||||||
const func = componentPropsFuncs[formConfig.value.currentItem!.component]
|
|
||||||
if (func)
|
|
||||||
func(formConfig.value.currentItem!.componentProps, allOptions.value)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
immediate: true,
|
|
||||||
deep: true,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
const linkOptions = computed(() => {
|
|
||||||
return (
|
|
||||||
formConfig.value.schemas
|
|
||||||
&& formConfig.value.schemas
|
|
||||||
.filter(item => item.key !== formConfig.value.currentItem!.key)
|
|
||||||
.map(({ label, field }) => ({ label: `${label}/${field}`, value: field }))
|
|
||||||
)
|
|
||||||
})
|
|
||||||
return {
|
|
||||||
formConfig,
|
|
||||||
showControlAttrs,
|
|
||||||
linkOptions,
|
|
||||||
controlOptions,
|
|
||||||
inputOptions,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
// 控制性的选项
|
||||||
|
const controlOptions = computed(() => {
|
||||||
|
return allOptions.value.filter((item) => {
|
||||||
|
return item.category === 'control'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 非控制性选择
|
||||||
|
const inputOptions = computed(() => {
|
||||||
|
return allOptions.value.filter((item) => {
|
||||||
|
return item.category === 'input'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => formConfig.value.currentItem!.componentProps,
|
||||||
|
() => {
|
||||||
|
const func = componentPropsFuncs[formConfig.value.currentItem!.component]
|
||||||
|
if (func)
|
||||||
|
func(formConfig.value.currentItem!.componentProps, allOptions.value)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
const linkOptions = computed(() => {
|
||||||
|
return (
|
||||||
|
formConfig.value.schemas
|
||||||
|
&& formConfig.value.schemas
|
||||||
|
.filter(item => item.key !== formConfig.value.currentItem!.key)
|
||||||
|
.map(({ label, field }) => ({ label: `${label}/${field}`, value: field }))
|
||||||
|
)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -184,27 +142,20 @@ export default defineComponent({
|
||||||
|
|
||||||
<div v-if="item.children">
|
<div v-if="item.children">
|
||||||
<component
|
<component
|
||||||
v-bind="child.componentProps"
|
v-bind="child.componentProps" :is="child.component" v-for="(child, index) of item.children"
|
||||||
:is="child.component"
|
:key="index" v-model:value="formConfig.currentItem.componentProps[item.name][index]"
|
||||||
v-for="(child, index) of item.children"
|
|
||||||
:key="index"
|
|
||||||
v-model:value="formConfig.currentItem.componentProps[item.name][index]"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- 如果不是数组,则正常处理属性值 -->
|
<!-- 如果不是数组,则正常处理属性值 -->
|
||||||
<component
|
<component
|
||||||
v-bind="item.componentProps"
|
v-bind="item.componentProps" :is="item.component" v-else
|
||||||
:is="item.component"
|
v-model:value="formConfig.currentItem.componentProps[item.name]" class="component-prop"
|
||||||
v-else
|
|
||||||
v-model:value="formConfig.currentItem.componentProps[item.name]"
|
|
||||||
class="component-prop"
|
|
||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem label="控制属性">
|
<FormItem label="控制属性">
|
||||||
<Col v-for="item in controlOptions" :key="item.name">
|
<Col v-for="item in controlOptions" :key="item.name">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
v-if="showControlAttrs(item.includes)"
|
v-if="showControlAttrs(item.includes)" v-bind="item.componentProps"
|
||||||
v-bind="item.componentProps"
|
|
||||||
v-model:checked="formConfig.currentItem.componentProps[item.name]"
|
v-model:checked="formConfig.currentItem.componentProps[item.name]"
|
||||||
>
|
>
|
||||||
{{ item.label }}
|
{{ item.label }}
|
||||||
|
|
@ -213,25 +164,19 @@ export default defineComponent({
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</div>
|
</div>
|
||||||
<FormItem label="关联字段">
|
<FormItem label="关联字段">
|
||||||
<Select
|
<Select v-model:value="formConfig.currentItem.link" mode="multiple" :options="linkOptions" />
|
||||||
v-model:value="formConfig.currentItem.link"
|
|
||||||
mode="multiple"
|
|
||||||
:options="linkOptions"
|
|
||||||
/>
|
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|
||||||
<FormItem
|
<FormItem
|
||||||
v-if="
|
v-if="[
|
||||||
[
|
'Select',
|
||||||
'Select',
|
'CheckboxGroup',
|
||||||
'CheckboxGroup',
|
'RadioGroup',
|
||||||
'RadioGroup',
|
'TreeSelect',
|
||||||
'TreeSelect',
|
'Cascader',
|
||||||
'Cascader',
|
'AutoComplete',
|
||||||
'AutoComplete',
|
].includes(formConfig.currentItem.component)
|
||||||
].includes(formConfig.currentItem.component)
|
" label="选项"
|
||||||
"
|
|
||||||
label="选项"
|
|
||||||
>
|
>
|
||||||
<FormOptions />
|
<FormOptions />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,20 @@
|
||||||
<!--
|
<!--
|
||||||
* @Description: 表单项属性
|
* @Description: 表单项属性
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue'
|
import { Empty, Form, FormItem } from 'ant-design-vue'
|
||||||
import { Checkbox, Empty, Form, FormItem, Input, Select, Slider, Switch } from 'ant-design-vue'
|
|
||||||
import { isArray } from 'lodash-es'
|
import { isArray } from 'lodash-es'
|
||||||
import { baseItemColumnProps } from '../config/formItemPropsConfig'
|
import { baseItemColumnProps } from '../config/formItemPropsConfig'
|
||||||
|
|
||||||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||||
import RuleProps from './RuleProps.vue'
|
|
||||||
|
|
||||||
export default defineComponent({
|
const { formConfig } = useFormDesignState()
|
||||||
name: 'FormItemProps',
|
function showProps(exclude: string[] | undefined) {
|
||||||
components: {
|
if (!exclude)
|
||||||
RuleProps,
|
return true
|
||||||
Empty,
|
|
||||||
Input,
|
|
||||||
Form,
|
|
||||||
FormItem,
|
|
||||||
Switch,
|
|
||||||
Checkbox,
|
|
||||||
Select,
|
|
||||||
Slider,
|
|
||||||
},
|
|
||||||
// props: {} as PropsOptions,
|
|
||||||
|
|
||||||
setup() {
|
return isArray(exclude) ? !exclude.includes(formConfig.value.currentItem!.component) : true
|
||||||
const { formConfig } = useFormDesignState()
|
}
|
||||||
const showProps = (exclude: string[] | undefined) => {
|
|
||||||
if (!exclude)
|
|
||||||
return true
|
|
||||||
|
|
||||||
return isArray(exclude) ? !exclude.includes(formConfig.value.currentItem!.component) : true
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
baseItemColumnProps,
|
|
||||||
formConfig,
|
|
||||||
showProps,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -50,11 +25,8 @@ export default defineComponent({
|
||||||
<div v-for="item of baseItemColumnProps" :key="item.name">
|
<div v-for="item of baseItemColumnProps" :key="item.name">
|
||||||
<FormItem v-if="showProps(item.exclude)" :label="item.label">
|
<FormItem v-if="showProps(item.exclude)" :label="item.label">
|
||||||
<component
|
<component
|
||||||
v-bind="item.componentProps"
|
v-bind="item.componentProps" :is="item.component" v-if="formConfig.currentItem.colProps"
|
||||||
:is="item.component"
|
v-model:value="formConfig.currentItem.colProps[item.name]" class="component-props"
|
||||||
v-if="formConfig.currentItem.colProps"
|
|
||||||
v-model:value="formConfig.currentItem.colProps[item.name]"
|
|
||||||
class="component-props"
|
|
||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<!--
|
<!--
|
||||||
* @Description: 表单项属性,控件属性面板
|
* @Description: 表单项属性,控件属性面板
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { computed, defineComponent, watch } from 'vue'
|
import { computed, watch } from 'vue'
|
||||||
import {
|
import {
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Col,
|
Col,
|
||||||
|
|
@ -10,9 +10,6 @@ import {
|
||||||
Form,
|
Form,
|
||||||
FormItem,
|
FormItem,
|
||||||
Input,
|
Input,
|
||||||
RadioGroup,
|
|
||||||
Select,
|
|
||||||
Slider,
|
|
||||||
Switch,
|
Switch,
|
||||||
} from 'ant-design-vue'
|
} from 'ant-design-vue'
|
||||||
import { isArray } from 'lodash-es'
|
import { isArray } from 'lodash-es'
|
||||||
|
|
@ -26,61 +23,32 @@ import {
|
||||||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||||
import RuleProps from './RuleProps.vue'
|
import RuleProps from './RuleProps.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
const { formConfig } = useFormDesignState()
|
||||||
name: 'FormItemProps',
|
|
||||||
components: {
|
|
||||||
RuleProps,
|
|
||||||
Empty,
|
|
||||||
Input,
|
|
||||||
Form,
|
|
||||||
FormItem,
|
|
||||||
Switch,
|
|
||||||
Checkbox,
|
|
||||||
Select,
|
|
||||||
Slider,
|
|
||||||
Col,
|
|
||||||
RadioGroup,
|
|
||||||
},
|
|
||||||
// props: {} as PropsOptions,
|
|
||||||
|
|
||||||
setup() {
|
watch(
|
||||||
const { formConfig } = useFormDesignState()
|
() => formConfig.value,
|
||||||
|
() => {
|
||||||
watch(
|
if (formConfig.value.currentItem) {
|
||||||
() => formConfig.value,
|
formConfig.value.currentItem.itemProps = formConfig.value.currentItem.itemProps || {}
|
||||||
() => {
|
formConfig.value.currentItem.itemProps.labelCol
|
||||||
if (formConfig.value.currentItem) {
|
|
||||||
formConfig.value.currentItem.itemProps = formConfig.value.currentItem.itemProps || {}
|
|
||||||
formConfig.value.currentItem.itemProps.labelCol
|
|
||||||
= formConfig.value.currentItem.itemProps.labelCol || {}
|
= formConfig.value.currentItem.itemProps.labelCol || {}
|
||||||
formConfig.value.currentItem.itemProps.wrapperCol
|
formConfig.value.currentItem.itemProps.wrapperCol
|
||||||
= formConfig.value.currentItem.itemProps.wrapperCol || {}
|
= formConfig.value.currentItem.itemProps.wrapperCol || {}
|
||||||
}
|
|
||||||
},
|
|
||||||
{ deep: true, immediate: true },
|
|
||||||
)
|
|
||||||
const showProps = (exclude: string[] | undefined) => {
|
|
||||||
if (!exclude)
|
|
||||||
return true
|
|
||||||
|
|
||||||
return isArray(exclude) ? !exclude.includes(formConfig.value.currentItem!.component) : true
|
|
||||||
}
|
|
||||||
|
|
||||||
const controlPropsList = computed(() => {
|
|
||||||
return baseFormItemControlAttrs.filter((item) => {
|
|
||||||
return showProps(item.exclude)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
baseFormItemProps,
|
|
||||||
advanceFormItemProps,
|
|
||||||
advanceFormItemColProps,
|
|
||||||
formConfig,
|
|
||||||
controlPropsList,
|
|
||||||
showProps,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{ deep: true, immediate: true },
|
||||||
|
)
|
||||||
|
function showProps(exclude: string[] | undefined) {
|
||||||
|
if (!exclude)
|
||||||
|
return true
|
||||||
|
|
||||||
|
return isArray(exclude) ? !exclude.includes(formConfig.value.currentItem!.component) : true
|
||||||
|
}
|
||||||
|
|
||||||
|
const controlPropsList = computed(() => {
|
||||||
|
return baseFormItemControlAttrs.filter((item) => {
|
||||||
|
return showProps(item.exclude)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,29 @@
|
||||||
<!--
|
<!--
|
||||||
* @Description: 拖拽节点控件
|
* @Description: 拖拽节点控件
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import { defineComponent, reactive, toRefs } from 'vue'
|
|
||||||
import type { IVFormComponent } from '../../../typings/v-form-component'
|
import type { IVFormComponent } from '../../../typings/v-form-component'
|
||||||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||||
import VFormItem from '../../VFormItem/index.vue'
|
import VFormItem from '../../VFormItem/index.vue'
|
||||||
import FormNodeOperate from './FormNodeOperate.vue'
|
import FormNodeOperate from './FormNodeOperate.vue'
|
||||||
|
|
||||||
// import VFormItem from '../../VFormItem/vFormItem.vue';
|
const props = defineProps(
|
||||||
export default defineComponent({
|
{
|
||||||
name: 'FormNode',
|
|
||||||
components: {
|
|
||||||
VFormItem,
|
|
||||||
FormNodeOperate,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
schema: {
|
schema: {
|
||||||
type: Object as PropType<IVFormComponent>,
|
type: Object as PropType<IVFormComponent>,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
|
||||||
const { formConfig, formDesignMethods } = useFormDesignState()
|
)
|
||||||
const state = reactive({})
|
|
||||||
// 获取 formDesignMethods
|
const { formConfig, formDesignMethods } = useFormDesignState()
|
||||||
const handleSelectItem = () => {
|
// 获取 formDesignMethods
|
||||||
// 调用 formDesignMethods
|
function handleSelectItem() {
|
||||||
formDesignMethods.handleSetSelectItem(props.schema)
|
// 调用 formDesignMethods
|
||||||
}
|
formDesignMethods.handleSetSelectItem(props.schema)
|
||||||
return {
|
}
|
||||||
...toRefs(state),
|
|
||||||
handleSelectItem,
|
|
||||||
formConfig,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@
|
||||||
* 千万不要在template下面的第一行加注释,因为这里拖动的第一个元素
|
* 千万不要在template下面的第一行加注释,因为这里拖动的第一个元素
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import { computed, defineComponent, reactive, toRefs } from 'vue'
|
import { computed } from 'vue'
|
||||||
import draggable from 'vuedraggable'
|
import draggable from 'vuedraggable'
|
||||||
import { Col, Row } from 'ant-design-vue'
|
import { Col, Row } from 'ant-design-vue'
|
||||||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||||
|
|
@ -13,16 +13,8 @@ import type { IVFormComponent } from '../../../typings/v-form-component'
|
||||||
import FormNode from './FormNode.vue'
|
import FormNode from './FormNode.vue'
|
||||||
import FormNodeOperate from './FormNodeOperate.vue'
|
import FormNodeOperate from './FormNodeOperate.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps(
|
||||||
name: 'LayoutItem',
|
{
|
||||||
components: {
|
|
||||||
FormNode,
|
|
||||||
FormNodeOperate,
|
|
||||||
Draggable: draggable,
|
|
||||||
Row,
|
|
||||||
Col,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
schema: {
|
schema: {
|
||||||
type: Object as PropType<IVFormComponent>,
|
type: Object as PropType<IVFormComponent>,
|
||||||
required: true,
|
required: true,
|
||||||
|
|
@ -32,33 +24,23 @@ export default defineComponent({
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
emits: ['dragStart', 'handleColAdd', 'handle-copy', 'handle-delete'],
|
)
|
||||||
setup(props) {
|
|
||||||
const {
|
|
||||||
formDesignMethods: { handleSetSelectItem },
|
|
||||||
formConfig,
|
|
||||||
} = useFormDesignState()
|
|
||||||
const state = reactive({})
|
|
||||||
const colPropsComputed = computed(() => {
|
|
||||||
const { colProps = {} } = props.schema
|
|
||||||
return colProps
|
|
||||||
})
|
|
||||||
|
|
||||||
const list1 = computed(() => props.schema.columns)
|
const emit = defineEmits(['dragStart', 'handleColAdd', 'handle-copy', 'handle-delete'])
|
||||||
|
|
||||||
// 计算布局元素,水平模式下为ACol,非水平模式下为div
|
const Draggable = draggable
|
||||||
const layoutTag = computed(() => {
|
|
||||||
return formConfig.value.layout === 'horizontal' ? 'Col' : 'div'
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
const { formDesignMethods: { handleSetSelectItem }, formConfig } = useFormDesignState()
|
||||||
...toRefs(state),
|
const colPropsComputed = computed(() => {
|
||||||
colPropsComputed,
|
const { colProps = {} } = props.schema
|
||||||
handleSetSelectItem,
|
return colProps
|
||||||
layoutTag,
|
})
|
||||||
list1,
|
|
||||||
}
|
const list1 = computed(() => props.schema.columns)
|
||||||
},
|
|
||||||
|
// 计算布局元素,水平模式下为ACol,非水平模式下为div
|
||||||
|
const layoutTag = computed(() => {
|
||||||
|
return formConfig.value.layout === 'horizontal' ? 'Col' : 'div'
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -87,8 +69,8 @@ export default defineComponent({
|
||||||
class="drag-move"
|
class="drag-move"
|
||||||
:schema="element"
|
:schema="element"
|
||||||
:current-item="currentItem"
|
:current-item="currentItem"
|
||||||
@handle-copy="$emit('handle-copy')"
|
@handle-copy="emit('handle-copy')"
|
||||||
@handle-delete="$emit('handle-delete')"
|
@handle-delete="emit('handle-delete')"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</Draggable>
|
</Draggable>
|
||||||
|
|
@ -102,8 +84,8 @@ export default defineComponent({
|
||||||
:key="schema.key"
|
:key="schema.key"
|
||||||
:schema="schema"
|
:schema="schema"
|
||||||
:current-item="currentItem"
|
:current-item="currentItem"
|
||||||
@handle-copy="$emit('handle-copy')"
|
@handle-copy="emit('handle-copy')"
|
||||||
@handle-delete="$emit('handle-delete')"
|
@handle-delete="emit('handle-delete')"
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,12 @@
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, reactive, ref, toRefs, unref } from 'vue'
|
import { ref, unref } from 'vue'
|
||||||
import { CodeEditor, MODE } from '@/components/CodeEditor'
|
import { CodeEditor, MODE } from '@/components/CodeEditor'
|
||||||
|
|
||||||
import { useCopyToClipboard } from '@/hooks/web/useCopyToClipboard'
|
import { useCopyToClipboard } from '@/hooks/web/useCopyToClipboard'
|
||||||
import { useMessage } from '@/hooks/web/useMessage'
|
import { useMessage } from '@/hooks/web/useMessage'
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps(
|
||||||
name: 'PreviewCode',
|
{
|
||||||
components: {
|
|
||||||
CodeEditor,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
fileFormat: {
|
fileFormat: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'json',
|
default: 'json',
|
||||||
|
|
@ -20,51 +16,37 @@ export default defineComponent({
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
)
|
||||||
const state = reactive({
|
|
||||||
open: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
const myEditor = ref(null)
|
const myEditor = ref(null)
|
||||||
|
|
||||||
const exportData = (data: string, fileName = `file.${props.fileFormat}`) => {
|
function exportData(data: string, fileName = `file.${props.fileFormat}`) {
|
||||||
let content = 'data:text/csv;charset=utf-8,'
|
let content = 'data:text/csv;charset=utf-8,'
|
||||||
content += data
|
content += data
|
||||||
const encodedUri = encodeURI(content)
|
const encodedUri = encodeURI(content)
|
||||||
const actions = document.createElement('a')
|
const actions = document.createElement('a')
|
||||||
actions.setAttribute('href', encodedUri)
|
actions.setAttribute('href', encodedUri)
|
||||||
actions.setAttribute('download', fileName)
|
actions.setAttribute('download', fileName)
|
||||||
actions.click()
|
actions.click()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleExportJson = () => {
|
function handleExportJson() {
|
||||||
exportData(props.editorJson)
|
exportData(props.editorJson)
|
||||||
}
|
}
|
||||||
const { clipboardRef, copiedRef } = useCopyToClipboard()
|
const { clipboardRef, copiedRef } = useCopyToClipboard()
|
||||||
const { createMessage } = useMessage()
|
const { createMessage } = useMessage()
|
||||||
|
|
||||||
const handleCopyJson = () => {
|
function handleCopyJson() {
|
||||||
// 复制数据
|
// 复制数据
|
||||||
const value = props.editorJson
|
const value = props.editorJson
|
||||||
if (!value) {
|
if (!value) {
|
||||||
createMessage.warning('代码为空!')
|
createMessage.warning('代码为空!')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
clipboardRef.value = value
|
clipboardRef.value = value
|
||||||
if (unref(copiedRef))
|
if (unref(copiedRef))
|
||||||
createMessage.warning('复制成功!')
|
createMessage.warning('复制成功!')
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
myEditor,
|
|
||||||
exportData,
|
|
||||||
handleCopyJson,
|
|
||||||
handleExportJson,
|
|
||||||
MODE,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,13 @@
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, reactive } from 'vue'
|
|
||||||
import draggable from 'vuedraggable'
|
import draggable from 'vuedraggable'
|
||||||
import type { IVFormComponent } from '../../../typings/v-form-component'
|
import type { IVFormComponent } from '../../../typings/v-form-component'
|
||||||
import { Icon } from '@/components/Icon'
|
import { Icon } from '@/components/Icon'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps(
|
||||||
name: 'CollapseItem',
|
{
|
||||||
components: { Draggable: draggable, Icon },
|
|
||||||
props: {
|
|
||||||
list: {
|
list: {
|
||||||
type: [Array],
|
type: Array as unknown as any[],
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
handleListPush: {
|
handleListPush: {
|
||||||
|
|
@ -18,24 +15,23 @@ export default defineComponent({
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props, { emit }) {
|
)
|
||||||
const { prefixCls } = useDesign('form-design-collapse-item')
|
const emit = defineEmits(['start', 'add-attrs', 'handle-list-push'])
|
||||||
|
const Draggable = draggable
|
||||||
|
|
||||||
const state = reactive({})
|
const { prefixCls } = useDesign('form-design-collapse-item')
|
||||||
const handleStart = (e: any, list1: IVFormComponent[]) => {
|
|
||||||
emit('start', list1[e.oldIndex].component)
|
function handleStart(e: any, list1: IVFormComponent[]) {
|
||||||
}
|
emit('start', list1[e.oldIndex].component)
|
||||||
const handleAdd = (e: any) => {
|
}
|
||||||
console.log(e)
|
function handleAdd(e: any) {
|
||||||
}
|
console.log(e)
|
||||||
// https://github.com/SortableJS/vue.draggable.next
|
}
|
||||||
// https://github.com/SortableJS/vue.draggable.next/blob/master/example/components/custom-clone.vue
|
// https://github.com/SortableJS/vue.draggable.next
|
||||||
const cloneItem = (one) => {
|
// https://github.com/SortableJS/vue.draggable.next/blob/master/example/components/custom-clone.vue
|
||||||
return props.handleListPush(one)
|
function cloneItem(one) {
|
||||||
}
|
return props.handleListPush(one)
|
||||||
return { prefixCls, state, handleStart, handleAdd, cloneItem }
|
}
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -57,8 +53,8 @@ export default defineComponent({
|
||||||
<template #item="{ element, index }">
|
<template #item="{ element, index }">
|
||||||
<li
|
<li
|
||||||
class="bs-box text-ellipsis"
|
class="bs-box text-ellipsis"
|
||||||
@dragstart="$emit('add-attrs', list, index)"
|
@dragstart="emit('add-attrs', list, index)"
|
||||||
@click="$emit('handle-list-push', element)"
|
@click="emit('handle-list-push', element)"
|
||||||
>
|
>
|
||||||
<!-- <svg v-if="element.icon.indexOf('icon-') > -1" class="icon" aria-hidden="true">
|
<!-- <svg v-if="element.icon.indexOf('icon-') > -1" class="icon" aria-hidden="true">
|
||||||
<use :xlink:href="`#${element.icon}`" />
|
<use :xlink:href="`#${element.icon}`" />
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
* @Description: 中间表单布局面板
|
* @Description: 中间表单布局面板
|
||||||
* https://github.com/SortableJS/vue.draggable.next/issues/138
|
* https://github.com/SortableJS/vue.draggable.next/issues/138
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import draggable from 'vuedraggable'
|
import draggable from 'vuedraggable'
|
||||||
import { computed, defineComponent } from 'vue'
|
import { computed, defineComponent } from 'vue'
|
||||||
import { cloneDeep } from 'lodash-es'
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
|
@ -10,52 +10,37 @@ import { Empty, Form } from 'ant-design-vue'
|
||||||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||||
import LayoutItem from '../components/LayoutItem.vue'
|
import LayoutItem from '../components/LayoutItem.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
const emit = defineEmits(['handleSetSelectItem'])
|
||||||
name: 'FormComponentPanel',
|
|
||||||
components: {
|
|
||||||
LayoutItem,
|
|
||||||
Draggable: draggable,
|
|
||||||
Form,
|
|
||||||
Empty,
|
|
||||||
},
|
|
||||||
emits: ['handleSetSelectItem'],
|
|
||||||
setup(_, { emit }) {
|
|
||||||
const { formConfig } = useFormDesignState()
|
|
||||||
|
|
||||||
/**
|
const Draggable = draggable
|
||||||
* 拖拽完成事件
|
|
||||||
* @param newIndex
|
|
||||||
*/
|
|
||||||
const addItem = ({ newIndex }: any) => {
|
|
||||||
formConfig.value.schemas = formConfig.value.schemas || []
|
|
||||||
|
|
||||||
const schemas = formConfig.value.schemas
|
const { formConfig } = useFormDesignState()
|
||||||
schemas[newIndex] = cloneDeep(schemas[newIndex])
|
|
||||||
emit('handleSetSelectItem', schemas[newIndex])
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拖拽开始事件
|
* 拖拽完成事件
|
||||||
* @param e {Object} 事件对象
|
* @param newIndex
|
||||||
*/
|
*/
|
||||||
const handleDragStart = (e: any) => {
|
function addItem({ newIndex }: any) {
|
||||||
emit('handleSetSelectItem', formConfig.value.schemas[e.oldIndex])
|
formConfig.value.schemas = formConfig.value.schemas || []
|
||||||
}
|
|
||||||
|
|
||||||
// 获取祖先组件传递的currentItem
|
const schemas = formConfig.value.schemas
|
||||||
|
schemas[newIndex] = cloneDeep(schemas[newIndex])
|
||||||
|
emit('handleSetSelectItem', schemas[newIndex])
|
||||||
|
}
|
||||||
|
|
||||||
// 计算布局元素,水平模式下为ACol,非水平模式下为div
|
/**
|
||||||
const layoutTag = computed(() => {
|
* 拖拽开始事件
|
||||||
return formConfig.value.layout === 'horizontal' ? 'Col' : 'div'
|
* @param e {Object} 事件对象
|
||||||
})
|
*/
|
||||||
|
function handleDragStart(e: any) {
|
||||||
|
emit('handleSetSelectItem', formConfig.value.schemas[e.oldIndex])
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
// 获取祖先组件传递的currentItem
|
||||||
addItem,
|
|
||||||
handleDragStart,
|
// 计算布局元素,水平模式下为ACol,非水平模式下为div
|
||||||
formConfig,
|
const layoutTag = computed(() => {
|
||||||
layoutTag,
|
return formConfig.value.layout === 'horizontal' ? 'Col' : 'div'
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<!--
|
<!--
|
||||||
* @Description: 右侧属性配置面板
|
* @Description: 右侧属性配置面板
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { computed, defineComponent } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { TabPane, Tabs } from 'ant-design-vue'
|
import { TabPane, Tabs } from 'ant-design-vue'
|
||||||
import FormProps from '../components/FormProps.vue'
|
import FormProps from '../components/FormProps.vue'
|
||||||
import FormItemProps from '../components/FormItemProps.vue'
|
import FormItemProps from '../components/FormItemProps.vue'
|
||||||
|
|
@ -15,25 +15,11 @@ type ChangeTabKey = 1 | 2
|
||||||
export interface IPropsPanel {
|
export interface IPropsPanel {
|
||||||
changeTab: (key: ChangeTabKey) => void
|
changeTab: (key: ChangeTabKey) => void
|
||||||
}
|
}
|
||||||
export default defineComponent({
|
const { formConfig } = useFormDesignState()
|
||||||
name: 'PropsPanel',
|
const slotProps = computed(() => {
|
||||||
components: {
|
return customComponents.find(
|
||||||
FormProps,
|
item => item.component === formConfig.value.currentItem?.component,
|
||||||
FormItemProps,
|
)
|
||||||
ComponentProps,
|
|
||||||
ComponentColumnProps,
|
|
||||||
Tabs,
|
|
||||||
TabPane,
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
const { formConfig } = useFormDesignState()
|
|
||||||
const slotProps = computed(() => {
|
|
||||||
return customComponents.find(
|
|
||||||
item => item.component === formConfig.value.currentItem?.component,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
return { formConfig, customComponents, slotProps }
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<!--
|
<!--
|
||||||
* @Description: 工具栏
|
* @Description: 工具栏
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, inject, reactive, toRefs } from 'vue'
|
import { inject, reactive } from 'vue'
|
||||||
import type { UseRefHistoryReturn } from '@vueuse/core'
|
import type { UseRefHistoryReturn } from '@vueuse/core'
|
||||||
import { Divider, Tooltip } from 'ant-design-vue'
|
import { Divider, Tooltip } from 'ant-design-vue'
|
||||||
import type { IFormConfig } from '../../../typings/v-form-component'
|
import type { IFormConfig } from '../../../typings/v-form-component'
|
||||||
|
|
@ -15,62 +15,51 @@ interface IToolbarsConfig {
|
||||||
event: string
|
event: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
const state = reactive<{
|
||||||
name: 'OperatingArea',
|
toolbarsConfigs: IToolbarsConfig[]
|
||||||
components: {
|
}>({
|
||||||
Tooltip,
|
toolbarsConfigs: [
|
||||||
Icon,
|
{
|
||||||
Divider,
|
title: '预览-支持布局',
|
||||||
},
|
type: 'preview',
|
||||||
setup() {
|
event: 'handlePreview',
|
||||||
const state = reactive<{
|
icon: 'ant-design:chrome-filled',
|
||||||
toolbarsConfigs: IToolbarsConfig[]
|
},
|
||||||
}>({
|
{
|
||||||
toolbarsConfigs: [
|
title: '预览-不支持布局',
|
||||||
{
|
type: 'preview',
|
||||||
title: '预览-支持布局',
|
event: 'handlePreview2',
|
||||||
type: 'preview',
|
icon: 'ant-design:chrome-filled',
|
||||||
event: 'handlePreview',
|
},
|
||||||
icon: 'ant-design:chrome-filled',
|
{
|
||||||
},
|
title: '导入JSON',
|
||||||
{
|
type: 'importJson',
|
||||||
title: '预览-不支持布局',
|
event: 'handleOpenImportJsonModal',
|
||||||
type: 'preview',
|
icon: 'ant-design:import-outlined',
|
||||||
event: 'handlePreview2',
|
},
|
||||||
icon: 'ant-design:chrome-filled',
|
{
|
||||||
},
|
title: '生成JSON',
|
||||||
{
|
type: 'exportJson',
|
||||||
title: '导入JSON',
|
event: 'handleOpenJsonModal',
|
||||||
type: 'importJson',
|
icon: 'ant-design:export-outlined',
|
||||||
event: 'handleOpenImportJsonModal',
|
},
|
||||||
icon: 'ant-design:import-outlined',
|
{
|
||||||
},
|
title: '生成代码',
|
||||||
{
|
type: 'exportCode',
|
||||||
title: '生成JSON',
|
event: 'handleOpenCodeModal',
|
||||||
type: 'exportJson',
|
icon: 'ant-design:code-filled',
|
||||||
event: 'handleOpenJsonModal',
|
},
|
||||||
icon: 'ant-design:export-outlined',
|
{
|
||||||
},
|
title: '清空',
|
||||||
{
|
type: 'reset',
|
||||||
title: '生成代码',
|
event: 'handleClearFormItems',
|
||||||
type: 'exportCode',
|
icon: 'ant-design:clear-outlined',
|
||||||
event: 'handleOpenCodeModal',
|
},
|
||||||
icon: 'ant-design:code-filled',
|
],
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '清空',
|
|
||||||
type: 'reset',
|
|
||||||
event: 'handleClearFormItems',
|
|
||||||
icon: 'ant-design:clear-outlined',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
const historyRef = inject('historyReturn') as UseRefHistoryReturn<IFormConfig, IFormConfig>
|
|
||||||
|
|
||||||
const { undo, redo, canUndo, canRedo } = historyRef
|
|
||||||
return { ...toRefs(state), undo, redo, canUndo, canRedo }
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
const historyRef = inject('historyReturn') as UseRefHistoryReturn<IFormConfig, IFormConfig>
|
||||||
|
|
||||||
|
const { undo, redo, canUndo, canRedo } = historyRef
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -78,7 +67,7 @@ export default defineComponent({
|
||||||
<!-- 头部操作按钮区域 start -->
|
<!-- 头部操作按钮区域 start -->
|
||||||
<!-- 操作左侧区域 start -->
|
<!-- 操作左侧区域 start -->
|
||||||
<div class="left-btn-box">
|
<div class="left-btn-box">
|
||||||
<Tooltip v-for="item in toolbarsConfigs" :key="item.icon" :title="item.title">
|
<Tooltip v-for="item in state.toolbarsConfigs" :key="item.icon" :title="item.title">
|
||||||
<a class="toolbar-text" @click="$emit(item.event)">
|
<a class="toolbar-text" @click="$emit(item.event)">
|
||||||
<Icon :icon="item.icon" />
|
<Icon :icon="item.icon" />
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
import { BasicForm, useForm } from '@/components/Form'
|
import { BasicForm, useForm } from '@/components/Form'
|
||||||
import { BasicModal, useModalInner } from '@/components/Modal'
|
import { BasicModal, useModalInner } from '@/components/Modal'
|
||||||
import { useUserStore } from '@/store/modules/user'
|
import { useUserStore } from '@/store/modules/user'
|
||||||
|
|
@ -11,7 +10,6 @@ import headerImg from '@/assets/images/header.jpg'
|
||||||
defineOptions({ name: 'LockModal' })
|
defineOptions({ name: 'LockModal' })
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const { prefixCls } = useDesign('header-lock-modal')
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const lockStore = useLockStore()
|
const lockStore = useLockStore()
|
||||||
|
|
||||||
|
|
@ -52,18 +50,18 @@ const avatar = computed(() => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<BasicModal :footer="null" width="25%" :title="t('layout.header.lockScreen')" v-bind="$attrs" :class="prefixCls" @register="register">
|
<BasicModal :footer="null" width="25%" :title="t('layout.header.lockScreen')" v-bind="$attrs" @register="register">
|
||||||
<div :class="`${prefixCls}__entry`">
|
<div class="relative rounded-10 px-8 pb-8 pt-30">
|
||||||
<div :class="`${prefixCls}__header`">
|
<div class="absolute left-[calc(50%-45px)] top-0 w-auto text-center">
|
||||||
<img :src="avatar" :class="`${prefixCls}__header-img`">
|
<img :src="avatar" class="w-18 rounded-50%">
|
||||||
<p :class="`${prefixCls}__header-name`">
|
<p class="mt-2">
|
||||||
{{ getRealName }}
|
{{ getRealName }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<BasicForm @register="registerForm" />
|
<BasicForm @register="registerForm" />
|
||||||
|
|
||||||
<div :class="`${prefixCls}__footer`">
|
<div class="mt-4 text-center">
|
||||||
<a-button type="primary" block class="mt-2" @click="handleLock">
|
<a-button type="primary" block class="mt-2" @click="handleLock">
|
||||||
{{ t('layout.header.lockScreenBtn') }}
|
{{ t('layout.header.lockScreenBtn') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
|
|
@ -71,38 +69,3 @@ const avatar = computed(() => {
|
||||||
</div>
|
</div>
|
||||||
</BasicModal>
|
</BasicModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less">
|
|
||||||
@prefix-cls: ~'@{namespace}-header-lock-modal';
|
|
||||||
|
|
||||||
.@{prefix-cls} {
|
|
||||||
&__entry {
|
|
||||||
position: relative;
|
|
||||||
//height: 240px;
|
|
||||||
padding: 130px 30px 30px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__header {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: calc(50% - 45px);
|
|
||||||
width: auto;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
&-img {
|
|
||||||
width: 70px;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-name {
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__footer {
|
|
||||||
margin-top: 16px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import type { CSSProperties } from 'vue'
|
import type { CSSProperties } from 'vue'
|
||||||
import { computed, defineComponent, onMounted, ref, unref, watch } from 'vue'
|
import { computed, onMounted, ref, unref, watch } from 'vue'
|
||||||
import type { RouteLocationNormalized } from 'vue-router'
|
import type { RouteLocationNormalized } from 'vue-router'
|
||||||
|
import { onClickOutside } from '@vueuse/core'
|
||||||
import LayoutTrigger from '../trigger/index.vue'
|
import LayoutTrigger from '../trigger/index.vue'
|
||||||
import { useDragLine } from './useLayoutSider'
|
import { useDragLine } from './useLayoutSider'
|
||||||
import type { Menu } from '@/router/types'
|
import type { Menu } from '@/router/types'
|
||||||
|
|
@ -16,257 +17,220 @@ import { useDesign } from '@/hooks/web/useDesign'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { useGo } from '@/hooks/web/usePage'
|
import { useGo } from '@/hooks/web/usePage'
|
||||||
import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '@/enums/appEnum'
|
import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '@/enums/appEnum'
|
||||||
import clickOutside from '@/directives/clickOutside'
|
|
||||||
import { getChildrenMenus, getCurrentParentPath, getShallowMenus } from '@/router/menus'
|
import { getChildrenMenus, getCurrentParentPath, getShallowMenus } from '@/router/menus'
|
||||||
import { listenerRouteChange } from '@/logics/mitt/routeChange'
|
import { listenerRouteChange } from '@/logics/mitt/routeChange'
|
||||||
|
|
||||||
export default defineComponent({
|
const wrap = ref(null)
|
||||||
name: 'LayoutMixSider',
|
const menuModules = ref<Menu[]>([])
|
||||||
components: {
|
const activePath = ref('')
|
||||||
ScrollContainer,
|
const childrenMenus = ref<Menu[]>([])
|
||||||
AppLogo,
|
const openMenu = ref(false)
|
||||||
SimpleMenu,
|
const dragBarRef = ref<ElRef>(null)
|
||||||
Icon,
|
const sideRef = ref<ElRef>(null)
|
||||||
LayoutTrigger,
|
const currentRoute = ref<Nullable<RouteLocationNormalized>>(null)
|
||||||
SimpleMenuTag,
|
|
||||||
|
const { prefixCls } = useDesign('layout-mix-sider')
|
||||||
|
const go = useGo()
|
||||||
|
const { t } = useI18n()
|
||||||
|
const {
|
||||||
|
getMenuWidth,
|
||||||
|
getCanDrag,
|
||||||
|
getCloseMixSidebarOnChange,
|
||||||
|
getMenuTheme,
|
||||||
|
getMixSideTrigger,
|
||||||
|
getRealWidth,
|
||||||
|
getMixSideFixed,
|
||||||
|
mixSideHasChildren,
|
||||||
|
setMenuSetting,
|
||||||
|
getIsMixSidebar,
|
||||||
|
getCollapsed,
|
||||||
|
} = useMenuSetting()
|
||||||
|
|
||||||
|
const { title } = useGlobSetting()
|
||||||
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
|
useDragLine(sideRef, dragBarRef, true)
|
||||||
|
|
||||||
|
const getMenuStyle = computed((): CSSProperties => {
|
||||||
|
return {
|
||||||
|
width: unref(openMenu) ? `${unref(getMenuWidth)}px` : 0,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||||
|
left: `${unref(getMixSideWidth)}px`,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const getIsFixed = computed(() => {
|
||||||
|
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||||
|
mixSideHasChildren.value = unref(childrenMenus).length > 0
|
||||||
|
const isFixed = unref(getMixSideFixed) && unref(mixSideHasChildren)
|
||||||
|
if (isFixed)
|
||||||
|
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||||
|
openMenu.value = true
|
||||||
|
|
||||||
|
return isFixed
|
||||||
|
})
|
||||||
|
|
||||||
|
const getMixSideWidth = computed(() => {
|
||||||
|
return unref(getCollapsed) ? SIDE_BAR_MINI_WIDTH : SIDE_BAR_SHOW_TIT_MINI_WIDTH
|
||||||
|
})
|
||||||
|
|
||||||
|
const getDomStyle = computed((): CSSProperties => {
|
||||||
|
const fixedWidth = unref(getIsFixed) ? unref(getRealWidth) : 0
|
||||||
|
const width = `${unref(getMixSideWidth) + fixedWidth}px`
|
||||||
|
return getWrapCommonStyle(width)
|
||||||
|
})
|
||||||
|
|
||||||
|
const getWrapStyle = computed((): CSSProperties => {
|
||||||
|
const width = `${unref(getMixSideWidth)}px`
|
||||||
|
return getWrapCommonStyle(width)
|
||||||
|
})
|
||||||
|
|
||||||
|
const getMenuEvents = computed(() => {
|
||||||
|
return !unref(getMixSideFixed)
|
||||||
|
? {
|
||||||
|
onMouseleave: () => {
|
||||||
|
setActive(true)
|
||||||
|
closeMenu()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
const getShowDragBar = computed(() => unref(getCanDrag))
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
menuModules.value = await getShallowMenus()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Menu changes
|
||||||
|
watch(
|
||||||
|
[() => permissionStore.getLastBuildMenuTime, () => permissionStore.getBackMenuList],
|
||||||
|
async () => {
|
||||||
|
menuModules.value = await getShallowMenus()
|
||||||
},
|
},
|
||||||
directives: {
|
{
|
||||||
clickOutside,
|
immediate: true,
|
||||||
},
|
},
|
||||||
setup() {
|
)
|
||||||
const menuModules = ref<Menu[]>([])
|
|
||||||
const activePath = ref('')
|
|
||||||
const childrenMenus = ref<Menu[]>([])
|
|
||||||
const openMenu = ref(false)
|
|
||||||
const dragBarRef = ref<ElRef>(null)
|
|
||||||
const sideRef = ref<ElRef>(null)
|
|
||||||
const currentRoute = ref<Nullable<RouteLocationNormalized>>(null)
|
|
||||||
|
|
||||||
const { prefixCls } = useDesign('layout-mix-sider')
|
listenerRouteChange((route) => {
|
||||||
const go = useGo()
|
currentRoute.value = route
|
||||||
const { t } = useI18n()
|
setActive(true)
|
||||||
const {
|
if (unref(getCloseMixSidebarOnChange))
|
||||||
getMenuWidth,
|
closeMenu()
|
||||||
getCanDrag,
|
})
|
||||||
getCloseMixSidebarOnChange,
|
|
||||||
getMenuTheme,
|
|
||||||
getMixSideTrigger,
|
|
||||||
getRealWidth,
|
|
||||||
getMixSideFixed,
|
|
||||||
mixSideHasChildren,
|
|
||||||
setMenuSetting,
|
|
||||||
getIsMixSidebar,
|
|
||||||
getCollapsed,
|
|
||||||
} = useMenuSetting()
|
|
||||||
|
|
||||||
const { title } = useGlobSetting()
|
function getWrapCommonStyle(width: string): CSSProperties {
|
||||||
const permissionStore = usePermissionStore()
|
return {
|
||||||
|
width,
|
||||||
|
maxWidth: width,
|
||||||
|
minWidth: width,
|
||||||
|
flex: `0 0 ${width}`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
useDragLine(sideRef, dragBarRef, true)
|
// Process module menu click
|
||||||
|
async function handleModuleClick(path: string, hover = false) {
|
||||||
const getMenuStyle = computed((): CSSProperties => {
|
const children = await getChildrenMenus(path)
|
||||||
return {
|
if (unref(activePath) === path) {
|
||||||
width: unref(openMenu) ? `${unref(getMenuWidth)}px` : 0,
|
if (!hover) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
if (!unref(openMenu))
|
||||||
left: `${unref(getMixSideWidth)}px`,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const getIsFixed = computed(() => {
|
|
||||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
|
||||||
mixSideHasChildren.value = unref(childrenMenus).length > 0
|
|
||||||
const isFixed = unref(getMixSideFixed) && unref(mixSideHasChildren)
|
|
||||||
if (isFixed)
|
|
||||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
|
||||||
openMenu.value = true
|
openMenu.value = true
|
||||||
|
else
|
||||||
return isFixed
|
|
||||||
})
|
|
||||||
|
|
||||||
const getMixSideWidth = computed(() => {
|
|
||||||
return unref(getCollapsed) ? SIDE_BAR_MINI_WIDTH : SIDE_BAR_SHOW_TIT_MINI_WIDTH
|
|
||||||
})
|
|
||||||
|
|
||||||
const getDomStyle = computed((): CSSProperties => {
|
|
||||||
const fixedWidth = unref(getIsFixed) ? unref(getRealWidth) : 0
|
|
||||||
const width = `${unref(getMixSideWidth) + fixedWidth}px`
|
|
||||||
return getWrapCommonStyle(width)
|
|
||||||
})
|
|
||||||
|
|
||||||
const getWrapStyle = computed((): CSSProperties => {
|
|
||||||
const width = `${unref(getMixSideWidth)}px`
|
|
||||||
return getWrapCommonStyle(width)
|
|
||||||
})
|
|
||||||
|
|
||||||
const getMenuEvents = computed(() => {
|
|
||||||
return !unref(getMixSideFixed)
|
|
||||||
? {
|
|
||||||
onMouseleave: () => {
|
|
||||||
setActive(true)
|
|
||||||
closeMenu()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: {}
|
|
||||||
})
|
|
||||||
|
|
||||||
const getShowDragBar = computed(() => unref(getCanDrag))
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
menuModules.value = await getShallowMenus()
|
|
||||||
})
|
|
||||||
|
|
||||||
// Menu changes
|
|
||||||
watch(
|
|
||||||
[() => permissionStore.getLastBuildMenuTime, () => permissionStore.getBackMenuList],
|
|
||||||
async () => {
|
|
||||||
menuModules.value = await getShallowMenus()
|
|
||||||
},
|
|
||||||
{
|
|
||||||
immediate: true,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
listenerRouteChange((route) => {
|
|
||||||
currentRoute.value = route
|
|
||||||
setActive(true)
|
|
||||||
if (unref(getCloseMixSidebarOnChange))
|
|
||||||
closeMenu()
|
closeMenu()
|
||||||
})
|
|
||||||
|
|
||||||
function getWrapCommonStyle(width: string): CSSProperties {
|
|
||||||
return {
|
|
||||||
width,
|
|
||||||
maxWidth: width,
|
|
||||||
minWidth: width,
|
|
||||||
flex: `0 0 ${width}`,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
// Process module menu click
|
if (!unref(openMenu))
|
||||||
async function handleModuleClick(path: string, hover = false) {
|
|
||||||
const children = await getChildrenMenus(path)
|
|
||||||
if (unref(activePath) === path) {
|
|
||||||
if (!hover) {
|
|
||||||
if (!unref(openMenu))
|
|
||||||
openMenu.value = true
|
|
||||||
else
|
|
||||||
closeMenu()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!unref(openMenu))
|
|
||||||
openMenu.value = true
|
|
||||||
}
|
|
||||||
if (!unref(openMenu))
|
|
||||||
setActive()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
openMenu.value = true
|
openMenu.value = true
|
||||||
activePath.value = path
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!children || children.length === 0) {
|
|
||||||
if (!hover)
|
|
||||||
go(path)
|
|
||||||
childrenMenus.value = []
|
|
||||||
closeMenu()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
childrenMenus.value = children
|
|
||||||
}
|
}
|
||||||
|
if (!unref(openMenu))
|
||||||
|
setActive()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
openMenu.value = true
|
||||||
|
activePath.value = path
|
||||||
|
}
|
||||||
|
|
||||||
// Set the currently active menu and submenu
|
if (!children || children.length === 0) {
|
||||||
async function setActive(setChildren = false) {
|
if (!hover)
|
||||||
const path = currentRoute.value?.path
|
|
||||||
if (!path)
|
|
||||||
return
|
|
||||||
activePath.value = await getCurrentParentPath(path)
|
|
||||||
// hanldeModuleClick(parentPath);
|
|
||||||
if (unref(getIsMixSidebar)) {
|
|
||||||
const activeMenu = unref(menuModules).find(item => item.path === unref(activePath))
|
|
||||||
const p = activeMenu?.path
|
|
||||||
if (p) {
|
|
||||||
const children = await getChildrenMenus(p)
|
|
||||||
if (setChildren) {
|
|
||||||
childrenMenus.value = children
|
|
||||||
|
|
||||||
if (unref(getMixSideFixed))
|
|
||||||
openMenu.value = children.length > 0
|
|
||||||
}
|
|
||||||
if (children.length === 0)
|
|
||||||
childrenMenus.value = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleMenuClick(path: string) {
|
|
||||||
go(path)
|
go(path)
|
||||||
}
|
childrenMenus.value = []
|
||||||
|
closeMenu()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
childrenMenus.value = children
|
||||||
|
}
|
||||||
|
|
||||||
function handleClickOutside() {
|
// Set the currently active menu and submenu
|
||||||
setActive(true)
|
async function setActive(setChildren = false) {
|
||||||
closeMenu()
|
const path = currentRoute.value?.path
|
||||||
}
|
if (!path)
|
||||||
|
return
|
||||||
|
activePath.value = await getCurrentParentPath(path)
|
||||||
|
// hanldeModuleClick(parentPath);
|
||||||
|
if (unref(getIsMixSidebar)) {
|
||||||
|
const activeMenu = unref(menuModules).find(item => item.path === unref(activePath))
|
||||||
|
const p = activeMenu?.path
|
||||||
|
if (p) {
|
||||||
|
const children = await getChildrenMenus(p)
|
||||||
|
if (setChildren) {
|
||||||
|
childrenMenus.value = children
|
||||||
|
|
||||||
function getItemEvents(item: Menu) {
|
if (unref(getMixSideFixed))
|
||||||
if (unref(getMixSideTrigger) === 'hover') {
|
openMenu.value = children.length > 0
|
||||||
return {
|
|
||||||
onMouseenter: () => handleModuleClick(item.path, true),
|
|
||||||
onClick: async () => {
|
|
||||||
const children = await getChildrenMenus(item.path)
|
|
||||||
if (item.path && (!children || children.length === 0))
|
|
||||||
go(item.path)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
onClick: () => handleModuleClick(item.path),
|
|
||||||
}
|
}
|
||||||
|
if (children.length === 0)
|
||||||
|
childrenMenus.value = []
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleFixedMenu() {
|
function handleMenuClick(path: string) {
|
||||||
setMenuSetting({
|
go(path)
|
||||||
mixSideFixed: !unref(getIsFixed),
|
}
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close menu
|
function handleClickOutside() {
|
||||||
function closeMenu() {
|
setActive(true)
|
||||||
if (!unref(getIsFixed))
|
closeMenu()
|
||||||
openMenu.value = false
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
function getItemEvents(item: Menu) {
|
||||||
|
if (unref(getMixSideTrigger) === 'hover') {
|
||||||
return {
|
return {
|
||||||
t,
|
onMouseenter: () => handleModuleClick(item.path, true),
|
||||||
prefixCls,
|
onClick: async () => {
|
||||||
menuModules,
|
const children = await getChildrenMenus(item.path)
|
||||||
handleModuleClick,
|
if (item.path && (!children || children.length === 0))
|
||||||
activePath,
|
go(item.path)
|
||||||
childrenMenus,
|
},
|
||||||
getShowDragBar,
|
|
||||||
handleMenuClick,
|
|
||||||
getMenuStyle,
|
|
||||||
handleClickOutside,
|
|
||||||
sideRef,
|
|
||||||
dragBarRef,
|
|
||||||
title,
|
|
||||||
openMenu,
|
|
||||||
getMenuTheme,
|
|
||||||
getItemEvents,
|
|
||||||
getMenuEvents,
|
|
||||||
getDomStyle,
|
|
||||||
handleFixedMenu,
|
|
||||||
getMixSideFixed,
|
|
||||||
getWrapStyle,
|
|
||||||
getCollapsed,
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
return {
|
||||||
|
onClick: () => handleModuleClick(item.path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFixedMenu() {
|
||||||
|
setMenuSetting({
|
||||||
|
mixSideFixed: !unref(getIsFixed),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close menu
|
||||||
|
function closeMenu() {
|
||||||
|
if (!unref(getIsFixed))
|
||||||
|
openMenu.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickOutside(wrap, () => {
|
||||||
|
handleClickOutside()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="`${prefixCls}-dom`" :style="getDomStyle" />
|
<div :class="`${prefixCls}-dom`" :style="getDomStyle" />
|
||||||
<div
|
<div
|
||||||
v-click-outside="handleClickOutside"
|
ref="wrap"
|
||||||
:style="getWrapStyle"
|
:style="getWrapStyle"
|
||||||
:class="[
|
:class="[
|
||||||
prefixCls,
|
prefixCls,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue