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