|
|
@@ -3,58 +3,110 @@
|
|
|
<el-card class="mb-12px" body-class="pr-0px!">
|
|
|
<template #header>
|
|
|
<div class="flex items-center justify-between">
|
|
|
- <span>选项卡</span>
|
|
|
- <span class="flex gap-4px">
|
|
|
- <LuPlus class="cursor-pointer" @click="handleAdd" size="14px" />
|
|
|
+ <span class="flex items-center gap-4px">
|
|
|
+ <span>菜单项</span>
|
|
|
+ <el-tooltip :content="inPage ? '退出到菜单' : '进入菜单页'">
|
|
|
+ <span
|
|
|
+ v-show="!sider"
|
|
|
+ class="flex items-center mr-4px cursor-pointer shrink-0"
|
|
|
+ @click.stop="handleChangeInPage"
|
|
|
+ >
|
|
|
+ <LuArrowLeftToLine v-if="inPage" size="14px" />
|
|
|
+ <LuArrowRightToLine v-else size="14px" />
|
|
|
+ </span>
|
|
|
+ </el-tooltip>
|
|
|
</span>
|
|
|
+ <el-tooltip content="添加菜单片段">
|
|
|
+ <span class="flex gap-4px">
|
|
|
+ <LuPlus class="cursor-pointer" @click="handleAddSection" size="14px" />
|
|
|
+ </span>
|
|
|
+ </el-tooltip>
|
|
|
</div>
|
|
|
</template>
|
|
|
<el-scrollbar height="120px">
|
|
|
<div
|
|
|
- v-for="(item, index) in props.values?.value.children || []"
|
|
|
+ v-for="(section, sectionIndex) in props.values?.value.children || []"
|
|
|
:key="v4()"
|
|
|
- class="flex items-center pr-12px"
|
|
|
- @click="handleEdit(item)"
|
|
|
+ class="border-border border-solid border-1px p-4px bg-gray-800 mb-12px mr-12px rounded-4px"
|
|
|
>
|
|
|
- <span class="flex-1 truncate text-#00ff00 cursor-pointer">{{ item.title.text }}</span>
|
|
|
- <LuTrash2 class="cursor-pointer shrink-0" @click.stop="handleDelete(index)" size="14px" />
|
|
|
+ <div class="flex items-center gap-8px">
|
|
|
+ <el-input
|
|
|
+ v-model="section.name"
|
|
|
+ type="textarea"
|
|
|
+ spellcheck="false"
|
|
|
+ :rows="1"
|
|
|
+ placeholder="子标题"
|
|
|
+ />
|
|
|
+ <el-tooltip content="添加菜单项">
|
|
|
+ <span class="flex gap-4px">
|
|
|
+ <LuPlus class="cursor-pointer" @click="handleAddItem(sectionIndex)" size="14px" />
|
|
|
+ </span>
|
|
|
+ </el-tooltip>
|
|
|
+ <LuTrash2
|
|
|
+ class="cursor-pointer shrink-0"
|
|
|
+ @click.stop="handleDeleteSection(sectionIndex)"
|
|
|
+ size="14px"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ v-for="(item, index) in section.children || []"
|
|
|
+ :key="v4()"
|
|
|
+ class="flex items-center justify-between"
|
|
|
+ @click="handleEdit(item)"
|
|
|
+ >
|
|
|
+ <span class="flex items-center">
|
|
|
+ <el-radio
|
|
|
+ v-model="activeIndex"
|
|
|
+ :value="`[${sectionIndex}].children.[${index}]`"
|
|
|
+ class="mr-0!"
|
|
|
+ @click.stop
|
|
|
+ />
|
|
|
+ <span class="flex-1 truncate text-#00ff00 cursor-pointer">{{ item.name }}</span>
|
|
|
+ </span>
|
|
|
+
|
|
|
+ <LuTrash2
|
|
|
+ class="cursor-pointer shrink-0"
|
|
|
+ @click.stop="handleDeleteItem(sectionIndex, index)"
|
|
|
+ size="14px"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</el-scrollbar>
|
|
|
</el-card>
|
|
|
<el-dialog v-model="dialogVisible" title="编辑" width="440px">
|
|
|
<el-form ref="formRef" :model="formData" label-position="left" label-width="60px">
|
|
|
<el-form-item label="类型">
|
|
|
- <el-select v-model="formData.type">
|
|
|
+ <el-select v-model="formData.titleIcon.type">
|
|
|
<el-option label="Symbol" value="symbol"></el-option>
|
|
|
<el-option label="Image" value="img"></el-option>
|
|
|
<el-option label="Text" value="text"></el-option>
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="文本">
|
|
|
- <el-input spellcheck="false" v-model="formData.text"></el-input>
|
|
|
+ <el-input spellcheck="false" v-model="formData.name"></el-input>
|
|
|
</el-form-item>
|
|
|
<el-form-item v-if="formData.type === 'symbol'" label="图标">
|
|
|
<el-input spellcheck="false" readonly @click="handleShowSymbolModal">
|
|
|
<template #prefix>
|
|
|
- <i class="lvgl-icon not-italic" v-html="getSymbol(formData.img_symbol)"></i>
|
|
|
+ <i class="lvgl-icon not-italic" v-html="getSymbol(formData.titleIcon.img_symbol)"></i>
|
|
|
</template>
|
|
|
</el-input>
|
|
|
</el-form-item>
|
|
|
- <template v-if="formData.type === 'img'">
|
|
|
+ <template v-if="formData.titleIcon.type === 'img'">
|
|
|
<el-form-item label="图片">
|
|
|
- <ImageSelect v-model="formData.img_id" />
|
|
|
+ <ImageSelect v-model="formData.titleIcon.img_id" />
|
|
|
</el-form-item>
|
|
|
<el-row :gutter="12">
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="尺寸">
|
|
|
- <input-number style="width: 100%" v-model="formData.img_width" :min="0">
|
|
|
+ <input-number style="width: 100%" v-model="formData.titleIcon.img_width" :min="0">
|
|
|
<template #prefix>宽度</template>
|
|
|
</input-number>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label-width="0">
|
|
|
- <input-number style="width: 100%" v-model="formData.img_height" :min="0">
|
|
|
+ <input-number style="width: 100%" v-model="formData.titleIcon.img_height" :min="0">
|
|
|
<template #prefix>高度</template>
|
|
|
</input-number>
|
|
|
</el-form-item>
|
|
|
@@ -65,20 +117,20 @@
|
|
|
use-type="pure"
|
|
|
picker-type="chrome"
|
|
|
format="hex8"
|
|
|
- v-model:pureColor="formData.img_recolor"
|
|
|
+ v-model:pureColor="formData.titleIcon.img_recolor"
|
|
|
/>
|
|
|
- <span class="text-text-active">{{ formData.img_recolor }}</span>
|
|
|
+ <span class="text-text-active">{{ formData.titleIcon.img_recolor }}</span>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="透明度" label-position="left" label-width="60px">
|
|
|
<div class="w-full flex gap-20px items-center">
|
|
|
<el-slider
|
|
|
- v-model="formData.img_alpha"
|
|
|
+ v-model="formData.titleIcon.img_alpha"
|
|
|
:max="255"
|
|
|
:min="0"
|
|
|
style="flex: 1"
|
|
|
></el-slider>
|
|
|
<span class="text-text-active inline w-30px cursor-pointer">
|
|
|
- {{ formData.img_alpha }}
|
|
|
+ {{ formData.titleIcon.img_alpha }}
|
|
|
</span>
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
@@ -95,10 +147,11 @@
|
|
|
<script setup lang="ts">
|
|
|
import type { MenuItem } from './data'
|
|
|
|
|
|
-import { type Ref, ref } from 'vue'
|
|
|
-import { LuPlus, LuTrash2 } from 'vue-icons-plus/lu'
|
|
|
+import { ref, computed, type Ref } from 'vue'
|
|
|
+import { LuPlus, LuTrash2, LuArrowRightToLine, LuArrowLeftToLine } from 'vue-icons-plus/lu'
|
|
|
import { v4 } from 'uuid'
|
|
|
import { symbols } from '@/constants'
|
|
|
+import { getNextIndex } from '@/utils'
|
|
|
|
|
|
import ImageSelect from '@/views/designer/config/property/components/ImageSelect.vue'
|
|
|
import SymbolSelectModal from '@/views/designer/config/property/components/SymbolSelectModal.vue'
|
|
|
@@ -109,25 +162,70 @@ const props = defineProps<{
|
|
|
|
|
|
const dialogVisible = ref(false)
|
|
|
const formData = ref<MenuItem>({
|
|
|
- text: '',
|
|
|
- img_id: '',
|
|
|
- type: 'symbol',
|
|
|
- img_width: 0,
|
|
|
- img_height: 0,
|
|
|
- img_alpha: 255,
|
|
|
- img_recolor: '#ffffff00',
|
|
|
- img_symbol: ''
|
|
|
+ name: '',
|
|
|
+ titleIcon: {
|
|
|
+ img_id: '',
|
|
|
+ type: 'symbol',
|
|
|
+ img_width: 0,
|
|
|
+ img_height: 0,
|
|
|
+ img_alpha: 255,
|
|
|
+ img_recolor: '#ffffff00',
|
|
|
+ img_symbol: ''
|
|
|
+ }
|
|
|
})
|
|
|
const symbolModalRef = ref<InstanceType<typeof SymbolSelectModal>>()
|
|
|
|
|
|
+// 当前激活
|
|
|
+const activeIndex = computed({
|
|
|
+ get() {
|
|
|
+ return props.values?.value?.props?.activeIndex
|
|
|
+ },
|
|
|
+ set(index: number) {
|
|
|
+ if (props.values?.value?.props) {
|
|
|
+ props.values.value.props.activeIndex = index
|
|
|
+ }
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const sider = computed(() => props.values?.value?.props?.sider)
|
|
|
+
|
|
|
+const inPage = computed({
|
|
|
+ get() {
|
|
|
+ return props.values?.value?.props?.inPage
|
|
|
+ },
|
|
|
+ set(value: boolean) {
|
|
|
+ if (props.values?.value?.props) {
|
|
|
+ props.values.value.props.inPage = value
|
|
|
+ }
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
/**
|
|
|
- * 添加文本项
|
|
|
+ * 添加片段
|
|
|
*/
|
|
|
-const handleAdd = () => {
|
|
|
+const handleAddSection = () => {
|
|
|
+ const newIndex = getNextIndex(props.values?.value.children, 'name')
|
|
|
props.values?.value.children?.push({
|
|
|
- title: {
|
|
|
+ name: `section_${newIndex}`,
|
|
|
+ type: 'menu-section',
|
|
|
+ children: []
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 删除菜单项
|
|
|
+ */
|
|
|
+const handleDeleteSection = (sectionIndex: number | string) => {
|
|
|
+ props.values?.value.children?.splice(sectionIndex, 1)
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 添加文本项
|
|
|
+ */
|
|
|
+const handleAddItem = (sectionIndex: number | string) => {
|
|
|
+ props.values?.value.children?.[sectionIndex]?.children?.push({
|
|
|
+ titleIcon: {
|
|
|
type: 'symbol',
|
|
|
- text: 'item',
|
|
|
img_id: '',
|
|
|
img_width: 20,
|
|
|
img_height: 20,
|
|
|
@@ -135,20 +233,25 @@ const handleAdd = () => {
|
|
|
img_recolor: '#ffffff00',
|
|
|
img_symbol: 'LV_SYMBOL_SETTINGS'
|
|
|
},
|
|
|
+ name: 'item',
|
|
|
type: 'menu',
|
|
|
children: []
|
|
|
})
|
|
|
}
|
|
|
|
|
|
-const getSymbol = (symbol: string) => {
|
|
|
- return symbols.find((item) => item.label === symbol)?.value
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* 删除菜单项
|
|
|
*/
|
|
|
-const handleDelete = (index: number | string) => {
|
|
|
- props.values?.value.children?.splice(index, 1)
|
|
|
+const handleDeleteItem = (sectionIndex: number | string, index: number | string) => {
|
|
|
+ props.values?.value.children?.[sectionIndex]?.children?.splice(index, 1)
|
|
|
+}
|
|
|
+
|
|
|
+const handleChangeInPage = () => {
|
|
|
+ inPage.value = !inPage.value
|
|
|
+}
|
|
|
+
|
|
|
+const getSymbol = (symbol: string) => {
|
|
|
+ return symbols.find((item) => item.label === symbol)?.value
|
|
|
}
|
|
|
|
|
|
const handleShowSymbolModal = () => {
|
|
|
@@ -159,11 +262,11 @@ const handleShowSymbolModal = () => {
|
|
|
* 选择图标
|
|
|
*/
|
|
|
const handleSelectSymbol = (val: string) => {
|
|
|
- formData.value.img_symbol = val
|
|
|
+ formData.value.titleIcon.img_symbol = val
|
|
|
}
|
|
|
|
|
|
-const handleEdit = (record: { title: MenuItem; [p: string]: any }) => {
|
|
|
- formData.value = record.title
|
|
|
+const handleEdit = (record: MenuItem) => {
|
|
|
+ formData.value = record
|
|
|
dialogVisible.value = true
|
|
|
}
|
|
|
</script>
|