8 changed files with 1158 additions and 184 deletions
@ -0,0 +1,594 @@ |
|||||
|
<!-- |
||||
|
@ 作者: 袁纪菲 |
||||
|
@ 时间: 2024.4.16 |
||||
|
@ 备注: 新建应用 |
||||
|
--> |
||||
|
<script lang="ts" setup> |
||||
|
import { ref , onMounted } from 'vue'; |
||||
|
import { ElMessage, ElMessageBox } from 'element-plus'; |
||||
|
interface Menu { |
||||
|
id: number; |
||||
|
name: string; |
||||
|
type: string; // 区分分组和表单 |
||||
|
parentId?: number | undefined; //表示当前分组或表单所属的父分组ID |
||||
|
children?: Menu[]; //表示当前分组下的子分组和表单 |
||||
|
expanded?: boolean;// 分组展开状态,默认为 true |
||||
|
order?: number; // 添加 order 属性用于记录菜单项的顺序 |
||||
|
} |
||||
|
// 转换原始menu数据为新的数据结构 |
||||
|
function transformMenu(menuItems: Menu[], parentId?: number): Menu[] { |
||||
|
const transformedItems: Menu[] = []; |
||||
|
let order = 0; // 记录顺序 |
||||
|
for (const item of menuItems) { |
||||
|
const newItem: Menu = { ...item, parentId, order: order++ }; // 设置顺序 |
||||
|
if (item.type === 'group') { |
||||
|
const childItems = menuItems.filter((m) => m.parentId === item.id); |
||||
|
newItem.children = transformMenu(childItems, item.id); |
||||
|
} |
||||
|
transformedItems.push(newItem); |
||||
|
} |
||||
|
return transformedItems; |
||||
|
} |
||||
|
// 初始化菜单数据 |
||||
|
const initialMenu = [ |
||||
|
{ id: 1, name: '分组A', type: 'group' , expanded: true }, |
||||
|
{ id: 2, name: '表单1', type: 'form', parentId: 1 }, |
||||
|
{ id: 3, name: '分组B', type: 'group', parentId: 1 , expanded: true }, |
||||
|
{ id: 4, name: '表单2', type: 'form', parentId: 3 }, |
||||
|
]; |
||||
|
const menu = ref<Menu[]>(transformMenu(initialMenu)); // 将 transformMenu 的结果直接赋值给 menu |
||||
|
const appName = ref(''); |
||||
|
const createFormVisible = ref(false); |
||||
|
const createGroupVisible = ref(false); |
||||
|
const moveToVisible = ref(false); |
||||
|
const renameVisible = ref(false); |
||||
|
const newFormName = ref(''); |
||||
|
const newGroupName = ref(''); |
||||
|
const renameValue = ref(''); |
||||
|
// 用于临时存储待修改的表单或分组及其原始名称 |
||||
|
let renameItem: Menu | null = null; |
||||
|
let originalName: string = ''; |
||||
|
|
||||
|
const selectedParentId = ref<number | undefined>(undefined); |
||||
|
//用于存储待移动分组的 ID |
||||
|
const selectedGroupId = ref<number | null>(null); |
||||
|
//用于存储新建子表单或子分组时对应的父分组ID |
||||
|
const currentParentForNewForm = ref<number | undefined>(undefined); |
||||
|
const currentParentForNewGroup = ref<number | undefined>(undefined); |
||||
|
// 页面加载完成后初始化应用名称 |
||||
|
onMounted(() => { |
||||
|
appName.value = localStorage.getItem('appName') || '未命名应用'; |
||||
|
}); |
||||
|
// 保存应用名称 |
||||
|
const saveAppName = () => { |
||||
|
localStorage.setItem('appName', appName.value); |
||||
|
} |
||||
|
// 打开新建表单对话框 |
||||
|
const openCreateFormDialog = () =>{ |
||||
|
createFormVisible.value = true; |
||||
|
} |
||||
|
//保存新建表单 |
||||
|
const saveNewForm = () =>{ |
||||
|
if (!newFormName.value.trim()) { |
||||
|
ElMessage.error('表单名称不能为空'); |
||||
|
return; |
||||
|
} |
||||
|
const newForm: Menu = { |
||||
|
id: menu.value.length + 1, // 假设使用递增的ID |
||||
|
name: newFormName.value, |
||||
|
type: 'form', |
||||
|
parentId: currentParentForNewForm.value, // 根据当前设置的父分组ID |
||||
|
}; |
||||
|
// 判断是否为子表单,如果是,则添加到父分组的children数组中 |
||||
|
if (currentParentForNewForm.value !== undefined) { |
||||
|
const parent = menu.value.find((item) => item.id === currentParentForNewForm.value); |
||||
|
if (parent && parent.children) { |
||||
|
parent.children.push(newForm); |
||||
|
} |
||||
|
} else { |
||||
|
// 不是子表单,按照原有逻辑作为顶级表单添加到menu数组末尾 |
||||
|
menu.value.push(newForm); |
||||
|
} |
||||
|
ElMessage.success('新建成功'); |
||||
|
createFormVisible.value = false; |
||||
|
newFormName.value = ''; |
||||
|
} |
||||
|
//打开新建分组对话框 |
||||
|
const openCreateGroupDialog = () =>{ |
||||
|
createGroupVisible.value = true; |
||||
|
} |
||||
|
//保存新建分组 |
||||
|
const saveNewGroup = () =>{ |
||||
|
if (!newGroupName.value.trim()) { |
||||
|
ElMessage.error('分组名称不能为空'); |
||||
|
return; |
||||
|
} |
||||
|
const newGroup: Menu = { |
||||
|
id: menu.value.length + 1, // 假设使用递增的ID |
||||
|
name: newGroupName.value, |
||||
|
type: 'group', |
||||
|
parentId: currentParentForNewGroup.value, // 根据当前设置的父分组ID |
||||
|
}; |
||||
|
// 判断是否为子分组,如果是,则添加到父分组的children数组中 |
||||
|
if (currentParentForNewGroup.value !== undefined) { |
||||
|
const parent = menu.value.find((item) => item.id === currentParentForNewGroup.value); |
||||
|
if (parent && parent.children) { |
||||
|
parent.children.push(newGroup); |
||||
|
} |
||||
|
} else { |
||||
|
// 不是子分组,按照原有逻辑作为顶级分组添加到menu数组末尾 |
||||
|
menu.value.push(newGroup); |
||||
|
} |
||||
|
createGroupVisible.value = false; |
||||
|
newGroupName.value = ''; |
||||
|
} |
||||
|
//子表单弹窗 |
||||
|
const openCreateChildFormDialog = (parent: Menu) => { |
||||
|
// 显示新建表单对话框,并将父分组信息传入,以便保存时使用 |
||||
|
createFormVisible.value = true; |
||||
|
// 设置新建表单的初始父分组ID |
||||
|
currentParentForNewForm.value = parent.id; |
||||
|
}; |
||||
|
//子分组弹窗 |
||||
|
const openCreateChildGroupDialog = (parent: Menu) => { |
||||
|
// 显示新建分组对话框,并将父分组信息传入,以便保存时使用 |
||||
|
createGroupVisible.value = true; |
||||
|
// 设置新建分组的初始父分组ID |
||||
|
currentParentForNewGroup.value = parent.id; |
||||
|
}; |
||||
|
// 删除表单或分组 |
||||
|
const confirmDelete = (item: Menu) => { |
||||
|
const isParentGroup = item.children && item.children.length > 0 && item.type === 'group' && item.parentId === selectedParentId.value; // 确保是包含子元素的分组且为当前选中父分组的子分组 |
||||
|
if (isParentGroup) { |
||||
|
// 弹出确认删除对话框,包含子元素提示 |
||||
|
ElMessageBox.confirm( |
||||
|
`确定要删除分组 "${item.name}" 及其所有子分组和表单吗?`, |
||||
|
'警告', |
||||
|
{ |
||||
|
confirmButtonText: '确定删除', |
||||
|
cancelButtonText: '取消', |
||||
|
type: 'warning' |
||||
|
} |
||||
|
).then(() => { |
||||
|
deleteMenuRecursively(item); // 用户确认后,递归删除该分组及其所有子分组和表单 |
||||
|
}).catch(() => {}); // 用户取消时不执行任何操作 |
||||
|
} else { |
||||
|
// 弹出确认删除对话框,无子元素提示 |
||||
|
ElMessageBox.confirm( |
||||
|
`确定要删除 ${item.type === 'group' ? '分组' : '表单'} "${item.name}" 吗?`, |
||||
|
'警告', |
||||
|
{ |
||||
|
confirmButtonText: '确定删除', |
||||
|
cancelButtonText: '取消', |
||||
|
type: 'warning' |
||||
|
} |
||||
|
).then(() => { |
||||
|
removeSingleItem(item); // 用户确认后,删除当前分组或表单 |
||||
|
}).catch(() => {}); // 用户取消时不执行任何操作 |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// 递归删除指定分组及其所有子分组和表单 |
||||
|
const deleteMenuRecursively = (parent: Menu) => { |
||||
|
// 遍历当前分组的子元素 |
||||
|
for (const child of parent.children ?? []) { |
||||
|
if (child.children) { |
||||
|
deleteMenuRecursively(child); // 递归删除子分组及其子元素 |
||||
|
} |
||||
|
const childIndex = menu.value.findIndex((i) => i.id === child.id); |
||||
|
if (childIndex !== -1) { |
||||
|
menu.value.splice(childIndex, 1); // 从菜单数组中删除子表单 |
||||
|
} |
||||
|
} |
||||
|
const parentIndex = menu.value.findIndex((i) => i.id === parent.id); |
||||
|
if (parentIndex !== -1) { |
||||
|
menu.value.splice(parentIndex, 1); // 从菜单数组中删除父分组 |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// 删除单个分组或表单,不影响父分组 |
||||
|
const removeSingleItem = (item: Menu) => { |
||||
|
const itemIndex = menu.value.findIndex((i) => i.id === item.id); |
||||
|
if (itemIndex !== -1) { |
||||
|
menu.value.splice(itemIndex, 1); // 从菜单数组中删除当前分组或表单 |
||||
|
} |
||||
|
|
||||
|
// 如果被删除的是子分组或子表单,需要从其父分组的children数组中移除 |
||||
|
if (item.parentId !== undefined) { |
||||
|
const parent = menu.value.find((i) => i.id === item.parentId); |
||||
|
if (parent && parent.children) { |
||||
|
const childIndex = parent.children.findIndex((c) => c.id === item.id); |
||||
|
if (childIndex !== -1) { |
||||
|
parent.children.splice(childIndex, 1); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
//打开修改名称对话框 |
||||
|
const showRenameDialog = (item: Menu) => { |
||||
|
renameItem = item; |
||||
|
originalName = item.name; |
||||
|
renameVisible.value = true; |
||||
|
// 更新对应item的name属性,并保存到菜单数组中 |
||||
|
}; |
||||
|
// 关闭修改名称对话框 |
||||
|
const handleRenameClose = () => { |
||||
|
renameItem = null; |
||||
|
originalName = ''; |
||||
|
renameVisible.value = false; |
||||
|
}; |
||||
|
// 取消修改名称操作 |
||||
|
const handleRenameCancel = () => { |
||||
|
handleRenameClose(); |
||||
|
renameValue.value = originalName; |
||||
|
}; |
||||
|
// 保存修改名称操作 |
||||
|
const handleRenameSave = () => { |
||||
|
if (!renameValue.value.trim()) { |
||||
|
ElMessage.error('名称不能为空'); |
||||
|
return; |
||||
|
} |
||||
|
if (renameItem) { |
||||
|
renameItem.name = renameValue.value; |
||||
|
ElMessage.success('重命名成功'); |
||||
|
} |
||||
|
handleRenameClose(); |
||||
|
}; |
||||
|
//打开移动对话框 |
||||
|
const showMoveToDialog = (item: Menu) => { |
||||
|
selectedGroupId.value = item.id; |
||||
|
moveToVisible.value = true; |
||||
|
}; |
||||
|
//关闭移动对话框 |
||||
|
const handleMoveToClose = () => { |
||||
|
selectedGroupId.value = null; |
||||
|
moveToVisible.value = false; |
||||
|
}; |
||||
|
//取消移动操作 |
||||
|
const handleMoveToCancel = () => { |
||||
|
handleMoveToClose(); |
||||
|
}; |
||||
|
//保存移动操作 |
||||
|
const handleMoveToSave = () => { |
||||
|
if (!selectedParentId.value) { |
||||
|
ElMessage.error('请选择目标分组'); |
||||
|
return; |
||||
|
} |
||||
|
const movingItemIndex = menu.value.findIndex((item) => item.id === selectedGroupId.value); |
||||
|
if (movingItemIndex === -1) { |
||||
|
ElMessage.error('移动失败,找不到待移动的项'); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
const movingItem = menu.value[movingItemIndex]; |
||||
|
const targetGroup = menu.value.find((item) => item.id === selectedParentId.value); |
||||
|
if (!targetGroup || targetGroup.type !== 'group') { |
||||
|
ElMessage.error('移动失败,找不到目标分组'); |
||||
|
return; |
||||
|
} |
||||
|
// 更新待移动项的parentId并移除原位置 |
||||
|
const movedItem = menu.value.splice(movingItemIndex, 1)[0]; |
||||
|
movedItem.parentId = targetGroup.id; |
||||
|
// 将移动后的项插入到目标分组的children中,并保持正确的排序 |
||||
|
if (!targetGroup.children) { |
||||
|
targetGroup.children = []; |
||||
|
} |
||||
|
const insertIndex = targetGroup.children.findIndex((child) => child.id > movedItem.id); |
||||
|
targetGroup.children.splice(insertIndex >= 0 ? insertIndex : targetGroup.children.length, 0, movedItem); |
||||
|
|
||||
|
ElMessage.success('移动成功'); |
||||
|
handleMoveToClose(); |
||||
|
}; |
||||
|
//定义一个 toggleExpand 方法,用于切换分组的 expanded 状态。 |
||||
|
const toggleExpand = (group: Menu) => { |
||||
|
group.expanded = !group.expanded; |
||||
|
}; |
||||
|
</script> |
||||
|
<template> |
||||
|
<div class="common-layout"> |
||||
|
<!-- 顶部导航栏 --> |
||||
|
<el-header> |
||||
|
<div> |
||||
|
<el-input |
||||
|
v-model="appName" |
||||
|
class="header-input" |
||||
|
clearable |
||||
|
placeholder="未命名应用" |
||||
|
@clear="saveAppName" |
||||
|
@blur="saveAppName" |
||||
|
></el-input> |
||||
|
</div> |
||||
|
<div class="header-btn"> |
||||
|
<el-button type="primary" >编辑表单</el-button> |
||||
|
</div> |
||||
|
</el-header> |
||||
|
<!-- 主体布局容器 --> |
||||
|
<el-container> |
||||
|
<!-- 左侧侧边栏 --> |
||||
|
<el-aside> |
||||
|
<div class="sidebar-upper"> |
||||
|
<!-- 搜索框 --> |
||||
|
<el-input placeholder="搜索" class="search-input" /> |
||||
|
<!-- 新增按钮 --> |
||||
|
<el-dropdown trigger="click"> |
||||
|
<el-button type="primary" plain class="add-btn"> |
||||
|
<el-icon><Plus /></el-icon> |
||||
|
</el-button> |
||||
|
<template #dropdown> |
||||
|
<el-dropdown-menu> |
||||
|
<el-dropdown-item @click="() => openCreateFormDialog()"><el-icon><DocumentAdd /></el-icon>新建表单</el-dropdown-item> |
||||
|
<el-dropdown-item @click="() => openCreateGroupDialog()"><el-icon><FolderAdd /></el-icon>新建分组</el-dropdown-item> |
||||
|
</el-dropdown-menu> |
||||
|
</template> |
||||
|
</el-dropdown> |
||||
|
</div> |
||||
|
<!-- 侧边栏下半部区域 --> |
||||
|
<div class="sidebar-lower"> |
||||
|
<ul class="sidebar-menu"> |
||||
|
<template v-for="(item) in menu"> |
||||
|
<template v-if="item.type === 'group'"> |
||||
|
<!-- 分组 --> |
||||
|
<li :key="item.id"> |
||||
|
<div class="menu-item" :class="{ 'is-collapsed': !item.expanded }" @click="toggleExpand(item)"> |
||||
|
<span><el-icon><Folder /></el-icon>{{ item.name }}</span> |
||||
|
<el-dropdown trigger="click" placement="bottom-end"> |
||||
|
<el-icon><MoreFilled /></el-icon> |
||||
|
<template #dropdown> |
||||
|
<el-dropdown-menu> |
||||
|
<el-dropdown-item @click="openCreateChildFormDialog(item)"><el-icon><DocumentAdd /></el-icon>新建子表单</el-dropdown-item> |
||||
|
<el-dropdown-item @click="openCreateChildGroupDialog(item)"><el-icon><FolderAdd /></el-icon>新建子分组</el-dropdown-item> |
||||
|
<el-dropdown-item @click="confirmDelete(item)"><el-icon><Delete /></el-icon>删除</el-dropdown-item> |
||||
|
<el-dropdown-item @click="showRenameDialog(item)"><el-icon><EditPen /></el-icon>修改名称</el-dropdown-item> |
||||
|
<el-dropdown-item @click="showMoveToDialog(item)"><el-icon><FolderRemove /></el-icon>移动到</el-dropdown-item> |
||||
|
</el-dropdown-menu> |
||||
|
</template> |
||||
|
</el-dropdown> |
||||
|
</div> |
||||
|
<!-- 分组展开后显示子表单/子分组 --> |
||||
|
<transition name="expand-collapse"> |
||||
|
<ul v-if="item.children && item.expanded"> |
||||
|
<li v-for="child in item.children" :key="child.id"> |
||||
|
<!-- 对子表单和子分组再次进行类型判断,递归渲染 --> |
||||
|
<template v-if="child.type === 'group'"> |
||||
|
<!-- 子分组模板 --> |
||||
|
<div class="menu-item-child"> |
||||
|
<span @click="toggleExpand(child)"><el-icon><Folder /></el-icon>{{ child.name }}</span> |
||||
|
<el-dropdown trigger="click" placement="bottom-end"> |
||||
|
<el-icon><MoreFilled /></el-icon> |
||||
|
<template #dropdown> |
||||
|
<el-dropdown-menu> |
||||
|
<el-dropdown-item @click="openCreateChildFormDialog(item)"><el-icon><DocumentAdd /></el-icon>新建子表单</el-dropdown-item> |
||||
|
<el-dropdown-item @click="openCreateChildGroupDialog(item)"><el-icon><FolderAdd /></el-icon>新建子分组</el-dropdown-item> |
||||
|
<el-dropdown-item @click="confirmDelete(item)"><el-icon><Delete /></el-icon>删除</el-dropdown-item> |
||||
|
<el-dropdown-item @click="showRenameDialog(item)"><el-icon><EditPen /></el-icon>修改名称</el-dropdown-item> |
||||
|
<el-dropdown-item @click="showMoveToDialog(item)"><el-icon><FolderRemove /></el-icon>移动到</el-dropdown-item> |
||||
|
</el-dropdown-menu> |
||||
|
</template> |
||||
|
</el-dropdown> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template v-else-if="child.type === 'form'"> |
||||
|
<!-- 子表单模板 --> |
||||
|
<div class="menu-item-child"> |
||||
|
<span><el-icon><Document /></el-icon>{{ child.name }}</span> |
||||
|
<el-dropdown trigger="click" placement="bottom-end"> |
||||
|
<el-icon><MoreFilled /></el-icon> |
||||
|
<template #dropdown> |
||||
|
<el-dropdown-menu> |
||||
|
<el-dropdown-item @click="confirmDelete(item)"><el-icon><Delete /></el-icon>删除</el-dropdown-item> |
||||
|
<el-dropdown-item @click="showRenameDialog(item)"><el-icon><EditPen /></el-icon>修改名称</el-dropdown-item> |
||||
|
<el-dropdown-item @click="showMoveToDialog(item)"><el-icon><FolderRemove /></el-icon>移动到</el-dropdown-item> |
||||
|
</el-dropdown-menu> |
||||
|
</template> |
||||
|
</el-dropdown> |
||||
|
</div> |
||||
|
</template> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</transition> |
||||
|
</li> |
||||
|
</template> |
||||
|
<!-- 表单 --> |
||||
|
<template v-else-if="item.type === 'form'"> |
||||
|
<!-- 表单模板 --> |
||||
|
<li :key="item.id" class="menu-item"> |
||||
|
<span><el-icon><Document /></el-icon>{{ item.name }}</span> |
||||
|
<el-dropdown trigger="click" placement="bottom-end"> |
||||
|
<el-icon><MoreFilled /></el-icon> |
||||
|
<template #dropdown> |
||||
|
<el-dropdown-menu> |
||||
|
<el-dropdown-item @click="confirmDelete(item)"><el-icon><Delete /></el-icon>删除</el-dropdown-item> |
||||
|
<el-dropdown-item @click="showRenameDialog(item)"><el-icon><EditPen /></el-icon>修改名称</el-dropdown-item> |
||||
|
<el-dropdown-item @click="showMoveToDialog(item)"><el-icon><FolderRemove /></el-icon>移动到</el-dropdown-item> |
||||
|
</el-dropdown-menu> |
||||
|
</template> |
||||
|
</el-dropdown> |
||||
|
</li> |
||||
|
</template> |
||||
|
</template> |
||||
|
</ul> |
||||
|
</div> |
||||
|
</el-aside> |
||||
|
<!-- 主要内容区域 --> |
||||
|
<el-main> |
||||
|
表单预览 |
||||
|
</el-main> |
||||
|
</el-container> |
||||
|
</div> |
||||
|
<!-- 新建表单对话框 --> |
||||
|
<el-dialog v-model="createFormVisible" title="新建表单" > |
||||
|
<el-form label-width="80px"> |
||||
|
<el-form-item label="表单名称"> |
||||
|
<el-input v-model="newFormName" /> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<div class="dialog-footer"> |
||||
|
<el-button @click="createFormVisible = false">取消</el-button> |
||||
|
<el-button type="primary" @click="saveNewForm">保存</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
<!-- 新建分组对话框 --> |
||||
|
<el-dialog v-model="createGroupVisible" title="新建分组"> |
||||
|
<el-form label-width="80px"> |
||||
|
<el-form-item label="分组名称"> |
||||
|
<el-input v-model="newGroupName" /> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<div class="dialog-footer"> |
||||
|
<el-button @click="createGroupVisible = false">取消</el-button> |
||||
|
<el-button type="primary" @click="saveNewGroup">保存</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
<!-- 修改名称对话框 --> |
||||
|
<el-dialog v-model="renameVisible" title="修改名称" @close="handleRenameClose"> |
||||
|
<el-form label-width="80px"> |
||||
|
<el-form-item label="名称"> |
||||
|
<el-input v-model="renameValue" /> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<div class="dialog-footer"> |
||||
|
<el-button @click="handleRenameCancel">取消</el-button> |
||||
|
<el-button type="primary" @click="handleRenameSave">保存</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
<!-- 移动分组对话框 --> |
||||
|
<el-dialog |
||||
|
v-model="moveToVisible" |
||||
|
title="移动分组" |
||||
|
@close="handleMoveToClose"> |
||||
|
<el-select |
||||
|
v-model="selectedParentId" |
||||
|
placeholder="选择目标分组" |
||||
|
> |
||||
|
<el-option |
||||
|
v-for="(group, index) in menu.filter((m) => m.type === 'group' && m.id !== selectedGroupId)" |
||||
|
:key="index" |
||||
|
:label="group.name" |
||||
|
:value="group.id" |
||||
|
/> |
||||
|
</el-select> |
||||
|
<div class="dialog-footer"> |
||||
|
<el-button @click="handleMoveToCancel">取消</el-button> |
||||
|
<el-button type="primary" @click="handleMoveToSave">保存</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
</template> |
||||
|
<style scoped> |
||||
|
.common-layout { |
||||
|
height: 100vh; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
.el-header { |
||||
|
height: 50px; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
} |
||||
|
/* 应用名称 */ |
||||
|
.header-input { |
||||
|
width: 100px; |
||||
|
margin-top: 10px; |
||||
|
} |
||||
|
/* 编辑表单按钮 */ |
||||
|
.header-btn{ |
||||
|
margin-top: 10px; |
||||
|
} |
||||
|
/* 侧边栏整体 */ |
||||
|
.el-aside { |
||||
|
background-color: #f5f7fa; |
||||
|
width: 250px; |
||||
|
min-height: 100vh; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
position: relative; |
||||
|
} |
||||
|
/* 侧边栏上部区域 */ |
||||
|
.sidebar-upper { |
||||
|
display: flex; |
||||
|
padding: 20px; |
||||
|
border-bottom: 1px solid #ebeef5; |
||||
|
} |
||||
|
/* 搜索框 */ |
||||
|
.search-input{ |
||||
|
width: 200px; |
||||
|
margin-right: 10px; |
||||
|
} |
||||
|
/* 新建按钮 */ |
||||
|
.add-btn{ |
||||
|
cursor: pointer; |
||||
|
height: 30px; |
||||
|
width: 30px; |
||||
|
margin-top: 2px; |
||||
|
} |
||||
|
/* 侧边栏下半部分菜单样式 */ |
||||
|
.sidebar-lower { |
||||
|
overflow-y: auto; |
||||
|
padding: 5px 0; |
||||
|
} |
||||
|
.sidebar-menu { |
||||
|
list-style: none; |
||||
|
margin: 0; |
||||
|
padding: 0; |
||||
|
} |
||||
|
/* 父分组/表单 */ |
||||
|
.menu-item { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
padding: 8px 16px; |
||||
|
font-size: 14px; |
||||
|
line-height: 1.5; |
||||
|
color: #222222; |
||||
|
cursor: pointer; |
||||
|
transition: background-color 0.2s ease; |
||||
|
} |
||||
|
.menu-item:hover, |
||||
|
.menu-item:focus { |
||||
|
background-color: #cacbcc; |
||||
|
} |
||||
|
/* 子分组/表单 */ |
||||
|
.menu-item-child{ |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
padding: 8px 16px 8px 35px; |
||||
|
font-size: 14px; |
||||
|
line-height: 1.5; |
||||
|
color: #222222; |
||||
|
cursor: pointer; |
||||
|
transition: background-color 0.2s ease; |
||||
|
} |
||||
|
.menu-item-child:hover, |
||||
|
.menu-item-child:focus { |
||||
|
background-color: #cacbcc; |
||||
|
} |
||||
|
/* 定义展开/折叠动画的通用样式 */ |
||||
|
.expand-collapse-enter-active, |
||||
|
.expand-collapse-leave-active { |
||||
|
transition: max-height 0.3s ease, opacity 0.3s ease; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
/* 定义展开动画 */ |
||||
|
.expand-collapse-enter-from { |
||||
|
max-height: 0; |
||||
|
opacity: 0; |
||||
|
} |
||||
|
/* 定义折叠动画 */ |
||||
|
.expand-collapse-leave-to { |
||||
|
max-height: 0; |
||||
|
opacity: 0; |
||||
|
} |
||||
|
/* 下拉菜单样式 */ |
||||
|
.el-dropdown-menu { |
||||
|
padding: 0; |
||||
|
min-width: 100px; |
||||
|
} |
||||
|
/* 表单预览 */ |
||||
|
.el-main { |
||||
|
flex: 1; |
||||
|
padding: 20px; |
||||
|
background-color: #ffffff; |
||||
|
} |
||||
|
/* 对话框样式 */ |
||||
|
.dialog-footer { |
||||
|
text-align:right; |
||||
|
margin-top: 20px; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,106 @@ |
|||||
|
<!-- |
||||
|
@ 作者: 袁纪菲 |
||||
|
@ 时间: 2024.4.16 |
||||
|
@ 备注: 编辑应用 |
||||
|
--> |
||||
|
<script lang="ts" setup> |
||||
|
import { reactive, ref , computed } from 'vue' |
||||
|
import { ElMessage} from 'element-plus'; |
||||
|
|
||||
|
const props = defineProps({ |
||||
|
// eslint-disable-next-line vue/prop-name-casing |
||||
|
Visible:Boolean |
||||
|
}); |
||||
|
const emits = defineEmits(["update:Visible", "data"]); |
||||
|
//标签宽度 |
||||
|
const formLabelWidth = ref('140px') |
||||
|
const form = reactive({ |
||||
|
data: { |
||||
|
id: '', |
||||
|
name: '', |
||||
|
icon: '', |
||||
|
}, |
||||
|
visible: computed({ |
||||
|
get(){ |
||||
|
return props.Visible |
||||
|
}, |
||||
|
set(val) { |
||||
|
emits('update:Visible', val) |
||||
|
} |
||||
|
}) |
||||
|
}) |
||||
|
// 图片预览地址 |
||||
|
const previewImageUrl = ref<string>(''); //初始化为空字符串 |
||||
|
// 图片上传前的钩子函数 |
||||
|
const beforeUpload = (file: any) => { |
||||
|
const isJPG = file.type === 'image/jpeg' || file.type === 'image/png'; |
||||
|
if (!isJPG) { |
||||
|
ElMessage.error('只能上传 JPG 或 PNG 格式的图片'); |
||||
|
return false; |
||||
|
} |
||||
|
const isLt2M = file.size / 1024 / 1024 < 2; |
||||
|
if (!isLt2M) { |
||||
|
ElMessage.error('图片大小不能超过 2MB'); |
||||
|
return false; |
||||
|
} |
||||
|
// 如果验证通过,则可以将本地图片转为 URL 显示预览 |
||||
|
const reader = new FileReader(); |
||||
|
reader.readAsDataURL(file); |
||||
|
reader.onload = (e: ProgressEvent<FileReader>) => { |
||||
|
if (e.target?.result) { |
||||
|
previewImageUrl.value = e.target.result as string; |
||||
|
form.data.icon = e.target.result as string;// 同样需要确保非null |
||||
|
} else { |
||||
|
// 处理读取失败的情况,例如: |
||||
|
previewImageUrl.value = ''; |
||||
|
ElMessage.error('无法预览图片,请重新上传'); |
||||
|
} |
||||
|
}; |
||||
|
return isJPG && isLt2M; |
||||
|
}; |
||||
|
//保存 |
||||
|
const submitForm = () => { |
||||
|
emits('data', form.data); // 发送更新后的卡片数据给父组件 |
||||
|
emits('update:Visible', false); // 关闭对话框 |
||||
|
}; |
||||
|
</script> |
||||
|
<template> |
||||
|
<div class="edit-container"> |
||||
|
<el-dialog |
||||
|
:model-value="props.Visible" |
||||
|
title="编辑应用" |
||||
|
width="500"> |
||||
|
<el-form :model="form"> |
||||
|
<el-form-item label="应用名称" :label-width="formLabelWidth"> |
||||
|
<el-input v-model="form.data.name" placeholder="请输入应用名称" autocomplete="off" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="应用图标" :label-width=formLabelWidth> |
||||
|
<el-upload |
||||
|
class="picture-uploader" |
||||
|
action="" |
||||
|
:auto-upload="false" |
||||
|
:before-upload="beforeUpload" |
||||
|
list-type="picture-card"> |
||||
|
<i class="el-icon-plus"></i> |
||||
|
</el-upload> |
||||
|
<!-- 预览区域 --> |
||||
|
<div v-if="form.data.icon" class="preview-image"> |
||||
|
<img :src="form.data.icon" alt="预览图片" /> |
||||
|
</div> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<template #footer> |
||||
|
<div class="dialog-footer"> |
||||
|
<el-button @click="emits('update:Visible', false)">取消</el-button> |
||||
|
<el-button type="primary" @click="submitForm"> |
||||
|
保存 |
||||
|
</el-button> |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped> |
||||
|
|
||||
|
</style> |
||||
@ -1,213 +1,251 @@ |
|||||
<!-- |
<!-- |
||||
@ 作者: 袁纪菲 |
@ 作者: 袁纪菲 |
||||
@ 时间: 2024.3.18 |
@ 时间: 2024.4.16 |
||||
@ 备注: 应用管理父组件 |
@ 备注: 应用管理 |
||||
--> |
--> |
||||
<script lang = "ts" setup> |
<script lang="ts" setup> |
||||
import cardedit from './cardedit.vue'; |
import editpage from './editpage.vue'; |
||||
import cardadd from './cardadd.vue'; |
import { ref , onMounted } from 'vue'; |
||||
import {ref,onMounted,onUnmounted,watch} from 'vue'; |
import { useRouter } from 'vue-router'; |
||||
import {Delete,Edit,View,MoreFilled} from '@element-plus/icons-vue' |
|
||||
|
|
||||
// 弹窗状态 |
//页面跳转 |
||||
const props = defineProps({ |
const router = useRouter(); |
||||
visible:Boolean |
const goToCreatePage = () => { |
||||
}); |
try { |
||||
const drawerRefadd = ref(false); |
router.push({ name: 'create' }); |
||||
const drawerRefedit = ref(false) |
} catch (error) { |
||||
|
console.error("导航到创建页面时发生错误:", error); |
||||
// 卡片数据 |
} |
||||
interface cardDatass { |
|
||||
id: number; |
|
||||
name: string; |
|
||||
imageUrl: '', |
|
||||
} |
|
||||
const cardData = ref<cardDatass[]>([]); |
|
||||
const emits = defineEmits(["update:visible", "data"]); |
|
||||
//添加 |
|
||||
const opencardadd = () => { |
|
||||
drawerRefadd.value = true; |
|
||||
cardadd.value.onSubmit = handleAddCard; |
|
||||
}; |
|
||||
// 新增卡片数据的接收与处理 |
|
||||
const handleAddCard = (newCard: cardDatass) => { |
|
||||
cardData.value.push(newCard); |
|
||||
}; |
}; |
||||
//编辑 |
const dialogRefedit = ref(false); |
||||
const opencardedit = (index: number) => { |
interface cardDatas { |
||||
drawerRefedit.value = true; |
id: number; |
||||
// 将当前卡片的数据传给cardedit组件 |
name: string; |
||||
cardedit.value.cardData = cardData.value[index]; |
icon: string; |
||||
cardedit.value.onSubmit = handleEditCard; |
} |
||||
|
//初始化应用卡片数据 |
||||
|
const cardData = ref<cardDatas[]>([]); |
||||
|
const emits = defineEmits(["update:Visible", "data"]); |
||||
|
|
||||
|
onMounted(() => { |
||||
|
if (!cardData.value.length) { |
||||
|
for (let i = 0; i < 9; i++) { |
||||
|
cardData.value.push({ |
||||
|
id: i, |
||||
|
name: '标题' + i, |
||||
|
icon: 'https://img.zcool.cn/community/01f3fb5a66a75ea80120a123a9f582.jpg@2o.jpg' |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
//编辑应用 |
||||
|
const showEditPage = (index: number) => { |
||||
|
dialogRefedit.value = true; |
||||
|
editpage.value.cardData = cardData.value[index]; |
||||
|
editpage.value.onSubmit = handleEdit; |
||||
}; |
}; |
||||
// 编辑卡片数据的接收与处理 |
//编辑应用数据的接受与处理 |
||||
const handleEditCard = (newCard: cardDatass) => { |
const handleEdit = (newCard: cardDatas) => { |
||||
cardData.value.splice(0,1,newCard); |
cardData.value.splice(0, 1, newCard); |
||||
}; |
}; |
||||
//删除 |
//删除卡片 |
||||
const deleteCard = (index: number) => { |
const deleteCard = (index: number) => { |
||||
cardData.value.splice(index, 1); |
cardData.value.splice(index, 1); |
||||
emits('data', cardData.value); |
|
||||
}; |
}; |
||||
//监听子组件发来的 'data' 事件 |
|
||||
watch(() => props.visible, () => { |
|
||||
}, |
|
||||
{ immediate: true } |
|
||||
); |
|
||||
// 监听子组件返回的新卡片数据 |
|
||||
const handleNewCard = (newCard: cardDatass) => { |
|
||||
cardData.value.push(newCard); |
|
||||
}; |
|
||||
|
|
||||
onMounted(() => { |
|
||||
for(let i = 0;i<9;i++){ |
|
||||
cardData.value.push({ |
|
||||
id: i, |
|
||||
name: '卡片' + i, |
|
||||
imageUrl: '' |
|
||||
}); |
|
||||
} |
|
||||
}); |
|
||||
</script> |
</script> |
||||
<template> |
<template> |
||||
<cardadd v-model:visible="drawerRefadd" :keyval="props.visible" @data="handleNewCard"/> |
<editpage v-model:Visible="dialogRefedit" @data="handleEdit" /> |
||||
<cardedit v-model:visible="drawerRefedit" :keyval="props.visible" @data="handleNewCard"/> |
<div class="common-layout"> |
||||
<el-row :gutter="10"> |
<el-container> |
||||
<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6"> |
<el-container> |
||||
<div class="grid-content ep-bg-purple" > |
<el-main class="layout-content"> |
||||
<el-card class="cardlarge"> |
<el-header class="content-header"> |
||||
<template #header> |
<el-button class="create-btn" @click="goToCreatePage"> |
||||
<div class="cardhead-large"> |
<el-icon><Plus /></el-icon> |
||||
<el-row class="block-col-2"> |
新建应用 |
||||
<el-col style="text-align: right;"> |
</el-button> |
||||
<el-dropdown> |
</el-header> |
||||
<span class="el-dropdown-link"> |
<el-main> |
||||
<el-icon><MoreFilled /></el-icon> |
<el-scrollbar class="scrollbar"> |
||||
</span> |
<div class="xiangying"> |
||||
<template #dropdown> |
<el-col v-for="(card) in cardData" :key="card.id"> |
||||
<el-dropdown-menu> |
<el-card class="cardpattern" shadow="hover" > |
||||
<el-dropdown-item @click="opencardadd" >添加</el-dropdown-item> |
<div class="button"> |
||||
<el-dropdown-item >编辑</el-dropdown-item> |
<img :src="card.icon" class="picture" /> |
||||
<el-dropdown-item >删除</el-dropdown-item> |
<span>自定义卡片</span> |
||||
</el-dropdown-menu> |
<el-icon class="star"> |
||||
</template> |
<Star /> |
||||
</el-dropdown> |
</el-icon> |
||||
</el-col> |
<el-dropdown class="xiala" trigger="click"> |
||||
<el-col style="text-align: left;"> |
<el-icon> |
||||
<span>标题一</span> |
<MoreFilled /> |
||||
</el-col> |
</el-icon> |
||||
</el-row> |
<template #dropdown> |
||||
</div> |
<el-dropdown-menu> |
||||
</template> |
<el-dropdown-item @click = "() => showEditPage">编辑应用</el-dropdown-item> |
||||
<div class="grid-content ep-bg-purple" > |
<el-dropdown-item @click = "() => deleteCard">删除</el-dropdown-item> |
||||
<el-row :gutter="10" > |
</el-dropdown-menu> |
||||
<el-col v-for="(card, index) in cardData" :key="card.id" :xs="8" :sm="12" :md="8" :lg="8" :xl="8"> |
</template> |
||||
<el-card class="cardpattern"> |
</el-dropdown> |
||||
<img |
</div> |
||||
v-if="card.imageUrl" |
<div class="cardhead"> |
||||
src="card.imageUrl" |
<span>{{ card.name }}</span> |
||||
title="示例图片" |
</div> |
||||
class="picture" |
</el-card> |
||||
/> |
</el-col> |
||||
<div class="cardhead"> |
</div> |
||||
<span>{{ card.name }}</span> |
</el-scrollbar> |
||||
</div> |
</el-main> |
||||
<div class="bottom"> |
</el-main> |
||||
<el-button size="small" circle class="button" :icon="View"></el-button> |
</el-container> |
||||
<el-button size="small" circle class="button" :icon="Edit" @click="() => opencardedit(index)"></el-button> |
</el-container> |
||||
<el-button size="small" circle class="button" :icon="Delete" @click="() => deleteCard(index)"></el-button> |
|
||||
</div> |
|
||||
</el-card> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
</div> |
|
||||
</el-card> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
|
|
||||
<!-- 分页 --> |
|
||||
<div class="example-pagination-block"> |
|
||||
<div class="example-demonstration"></div> |
|
||||
<el-pagination layout="prev, pager, next" :total="50" /> |
|
||||
</div> |
</div> |
||||
|
|
||||
</template> |
</template> |
||||
<style scoped> |
<style scoped> |
||||
/* 小卡片 */ |
.common-layout { |
||||
.cardpattern{ |
width: 100%; |
||||
padding-bottom: 0px; |
height: 100%; |
||||
margin-bottom: 10px; |
.el-container { |
||||
min-width: 100px; |
height: 100%; |
||||
|
/* 不折叠的时候宽度是200px,折叠的时候宽度自适应 */ |
||||
|
} |
||||
|
} |
||||
|
svg { |
||||
|
width: 1.5em; |
||||
|
margin-right: 5px; |
||||
|
} |
||||
|
.el-menu-vertical-demo:not(.el-menu--collapse) { |
||||
|
width: 200px; |
||||
|
min-height: 400px; |
||||
} |
} |
||||
/* 小卡片标题 */ |
.el-aside { |
||||
.cardhead{ |
width: auto; |
||||
padding: 10px; |
|
||||
font-size: 15px; |
|
||||
} |
} |
||||
/* 大卡片 */ |
.el-menu-vertical-demo { |
||||
.cardlarge{ |
border-right: none; |
||||
max-width: 480px; |
margin-top: 0; |
||||
|
height: 100%; |
||||
|
background-color: #586177; |
||||
|
color: #fff; |
||||
} |
} |
||||
/* 大卡片标题 */ |
.el-menu-item { |
||||
.cardhead-large{ |
color: #ffffff; |
||||
font-size: 20px; |
|
||||
} |
} |
||||
|
/* 侧边栏标题 */ |
||||
/* 按钮整体 */ |
.side-header { |
||||
.bottom { |
height: 64px; |
||||
margin-top: 20px; |
padding: 0; |
||||
line-height: 10px; |
|
||||
display: flex; |
display: flex; |
||||
justify-content: space-evenly; |
|
||||
align-items: center; |
align-items: center; |
||||
|
justify-content: center; |
||||
} |
} |
||||
/* 单个按钮 */ |
/* 右侧上方标题 */ |
||||
.button { |
.up-header { |
||||
padding: 0px; |
display: flex; |
||||
min-height: auto; |
align-items : center; |
||||
margin-bottom: 1px; |
justify-content:left; |
||||
|
background-color: #fff; |
||||
|
padding: 0; |
||||
} |
} |
||||
/* 图片 */ |
/* 缩放侧边栏按钮 */ |
||||
.picture { |
.trigger { |
||||
height: 100%; |
font-size: 18px; |
||||
min-height: 50px; |
line-height: 64px; |
||||
max-height: 100px; |
padding: 0 24px; |
||||
display: block; |
cursor: pointer; |
||||
width: 100%; |
|
||||
min-width: 50px; |
|
||||
} |
} |
||||
|
.el-main { |
||||
.el-col { |
overflow-y: auto; |
||||
border-radius: 4px; |
padding-right: 0; /* 取消内外边距以免影响滚动区域 */ |
||||
} |
} |
||||
|
/* 内容框 */ |
||||
.grid-content { |
.layout-content{ |
||||
border-radius: 4px; |
padding: 15px; |
||||
min-height: 36px; |
background: #f5f5f5; |
||||
|
min-height: 280px; |
||||
} |
} |
||||
|
/* 新建按钮框 */ |
||||
.app_box{ |
.content-header { |
||||
margin: 15px 0 0 0px; |
display: flex; |
||||
|
justify-content: space-between; |
||||
|
text-align: right; |
||||
|
font-size: 12px; |
||||
|
height: 40px; |
||||
} |
} |
||||
|
/* 新建按钮 */ |
||||
.block-col-2 .demonstration { |
.create-btn { |
||||
display: block; |
margin-right: 10px; |
||||
color: var(--el-text-color-secondary); |
background-color: #1090ff; |
||||
font-size: 14px; |
color: #ffffff; |
||||
margin-bottom: 20px; |
} |
||||
|
/* 卡片整体所在区域 */ |
||||
|
.scrollbar{ |
||||
|
height: 700px; |
||||
|
overflow-y: auto; /* 自动显示垂直滚动条 */ |
||||
|
margin-right: 10px; |
||||
|
box-sizing: border-box; /* 保证高度计算包含内边距和边框 */ |
||||
|
|
||||
|
/* 当内容不够一屏时,禁用滚动条 */ |
||||
|
&::-webkit-scrollbar { |
||||
|
width: 0; |
||||
|
height: 0; |
||||
|
} |
||||
|
} |
||||
|
/* 内容部分卡片响应式 */ |
||||
|
.xiangying { |
||||
|
display: grid; |
||||
|
grid-auto-rows: minmax(160px, auto); /* 或者指定最大高度 */ |
||||
|
grid-gap: 1px; |
||||
|
grid-template-columns: repeat(auto-fit, 230px); |
||||
|
overflow-y: auto; /* 添加此行以允许卡片区域内部内容滚动 */ |
||||
|
} |
||||
|
/* 卡片 */ |
||||
|
.cardpattern { |
||||
|
padding: 0px; |
||||
|
margin-bottom: 10px; |
||||
|
width: 220px; |
||||
|
height: 150px; |
||||
|
transition: all 0.3s ease; |
||||
} |
} |
||||
|
|
||||
.block-col-2 .el-dropdown-link { |
/* 卡片标题 */ |
||||
display: flex; |
.cardhead { |
||||
align-items: center; |
margin-top: 50px; |
||||
|
font-size: 18px; |
||||
|
color: #000000; |
||||
|
font-weight: 500; |
||||
|
text-align: left; |
||||
|
font-family: PingFangSC-Regular; |
||||
|
line-height: 20px; |
||||
|
} |
||||
|
/* 收藏按钮与下拉框区域 */ |
||||
|
.button { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
margin-top: 3px; |
||||
} |
} |
||||
/* 分页 */ |
/* 收藏按钮 */ |
||||
.example-pagination-block + .example-pagination-block { |
.star { |
||||
margin-top: 10px; |
font-size: 20px; |
||||
|
margin-right: -5px; |
||||
} |
} |
||||
.example-pagination-block .example-demonstration { |
|
||||
margin-bottom: 16px; |
/* 占位元素 */ |
||||
|
.placeholder { |
||||
|
height:14px; |
||||
|
/* 设置为图标按钮组的高度 */ |
||||
|
width:100%; |
||||
|
/* 设置为图标按钮组的宽度 */ |
||||
|
visibility: hidden; |
||||
|
/* 或者 opacity: 0; 保证不会影响布局但不可见 */ |
||||
|
pointer-events: none; |
||||
|
/* 防止此元素捕获鼠标事件 */ |
||||
} |
} |
||||
|
/* 图片 */ |
||||
|
.picture { |
||||
|
width: 3cap; |
||||
|
margin: 1px; |
||||
|
} |
||||
|
|
||||
</style> |
</style> |
||||
|
|||||
@ -0,0 +1,213 @@ |
|||||
|
<!-- |
||||
|
@ 作者: 袁纪菲 |
||||
|
@ 时间: 2024.3.18 |
||||
|
@ 备注: 应用管理父组件 |
||||
|
--> |
||||
|
<script lang = "ts" setup> |
||||
|
import cardedit from './cardedit.vue'; |
||||
|
import cardadd from './cardadd.vue'; |
||||
|
import {ref,onMounted,onUnmounted,watch} from 'vue'; |
||||
|
import {Delete,Edit,View,MoreFilled} from '@element-plus/icons-vue' |
||||
|
|
||||
|
// 弹窗状态 |
||||
|
const props = defineProps({ |
||||
|
visible:Boolean |
||||
|
}); |
||||
|
const drawerRefadd = ref(false); |
||||
|
const drawerRefedit = ref(false) |
||||
|
|
||||
|
// 卡片数据 |
||||
|
interface cardDatass { |
||||
|
id: number; |
||||
|
name: string; |
||||
|
imageUrl: '', |
||||
|
} |
||||
|
const cardData = ref<cardDatass[]>([]); |
||||
|
const emits = defineEmits(["update:visible", "data"]); |
||||
|
//添加 |
||||
|
const opencardadd = () => { |
||||
|
drawerRefadd.value = true; |
||||
|
cardadd.value.onSubmit = handleAddCard; |
||||
|
}; |
||||
|
// 新增卡片数据的接收与处理 |
||||
|
const handleAddCard = (newCard: cardDatass) => { |
||||
|
cardData.value.push(newCard); |
||||
|
}; |
||||
|
//编辑 |
||||
|
const opencardedit = (index: number) => { |
||||
|
drawerRefedit.value = true; |
||||
|
// 将当前卡片的数据传给cardedit组件 |
||||
|
cardedit.value.cardData = cardData.value[index]; |
||||
|
cardedit.value.onSubmit = handleEditCard; |
||||
|
}; |
||||
|
// 编辑卡片数据的接收与处理 |
||||
|
const handleEditCard = (newCard: cardDatass) => { |
||||
|
cardData.value.splice(0,1,newCard); |
||||
|
}; |
||||
|
//删除 |
||||
|
const deleteCard = (index: number) => { |
||||
|
cardData.value.splice(index, 1); |
||||
|
emits('data', cardData.value); |
||||
|
}; |
||||
|
//监听子组件发来的 'data' 事件 |
||||
|
watch(() => props.visible, () => { |
||||
|
}, |
||||
|
{ immediate: true } |
||||
|
); |
||||
|
// 监听子组件返回的新卡片数据 |
||||
|
const handleNewCard = (newCard: cardDatass) => { |
||||
|
cardData.value.push(newCard); |
||||
|
}; |
||||
|
|
||||
|
onMounted(() => { |
||||
|
for(let i = 0;i<9;i++){ |
||||
|
cardData.value.push({ |
||||
|
id: i, |
||||
|
name: '卡片' + i, |
||||
|
imageUrl: '' |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
</script> |
||||
|
<template> |
||||
|
<cardadd v-model:visible="drawerRefadd" :keyval="props.visible" @data="handleNewCard"/> |
||||
|
<cardedit v-model:visible="drawerRefedit" :keyval="props.visible" @data="handleNewCard"/> |
||||
|
<el-row :gutter="10"> |
||||
|
<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6"> |
||||
|
<div class="grid-content ep-bg-purple" > |
||||
|
<el-card class="cardlarge"> |
||||
|
<template #header> |
||||
|
<div class="cardhead-large"> |
||||
|
<el-row class="block-col-2"> |
||||
|
<el-col style="text-align: right;"> |
||||
|
<el-dropdown> |
||||
|
<span class="el-dropdown-link"> |
||||
|
<el-icon><MoreFilled /></el-icon> |
||||
|
</span> |
||||
|
<template #dropdown> |
||||
|
<el-dropdown-menu> |
||||
|
<el-dropdown-item @click="opencardadd" >添加</el-dropdown-item> |
||||
|
<el-dropdown-item >编辑</el-dropdown-item> |
||||
|
<el-dropdown-item >删除</el-dropdown-item> |
||||
|
</el-dropdown-menu> |
||||
|
</template> |
||||
|
</el-dropdown> |
||||
|
</el-col> |
||||
|
<el-col style="text-align: left;"> |
||||
|
<span>标题一</span> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</div> |
||||
|
</template> |
||||
|
<div class="grid-content ep-bg-purple" > |
||||
|
<el-row :gutter="10" > |
||||
|
<el-col v-for="(card, index) in cardData" :key="card.id" :xs="8" :sm="12" :md="8" :lg="8" :xl="8"> |
||||
|
<el-card class="cardpattern"> |
||||
|
<img |
||||
|
v-if="card.imageUrl" |
||||
|
src="card.imageUrl" |
||||
|
title="示例图片" |
||||
|
class="picture" |
||||
|
/> |
||||
|
<div class="cardhead"> |
||||
|
<span>{{ card.name }}</span> |
||||
|
</div> |
||||
|
<div class="bottom"> |
||||
|
<el-button size="small" circle class="button" :icon="View"></el-button> |
||||
|
<el-button size="small" circle class="button" :icon="Edit" @click="() => opencardedit(index)"></el-button> |
||||
|
<el-button size="small" circle class="button" :icon="Delete" @click="() => deleteCard(index)"></el-button> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
|
||||
|
<!-- 分页 --> |
||||
|
<div class="example-pagination-block"> |
||||
|
<div class="example-demonstration"></div> |
||||
|
<el-pagination layout="prev, pager, next" :total="50" /> |
||||
|
</div> |
||||
|
|
||||
|
</template> |
||||
|
<style scoped> |
||||
|
/* 小卡片 */ |
||||
|
.cardpattern{ |
||||
|
padding-bottom: 0px; |
||||
|
margin-bottom: 10px; |
||||
|
min-width: 100px; |
||||
|
} |
||||
|
/* 小卡片标题 */ |
||||
|
.cardhead{ |
||||
|
padding: 10px; |
||||
|
font-size: 15px; |
||||
|
} |
||||
|
/* 大卡片 */ |
||||
|
.cardlarge{ |
||||
|
max-width: 480px; |
||||
|
} |
||||
|
/* 大卡片标题 */ |
||||
|
.cardhead-large{ |
||||
|
font-size: 20px; |
||||
|
} |
||||
|
|
||||
|
/* 按钮整体 */ |
||||
|
.bottom { |
||||
|
margin-top: 20px; |
||||
|
line-height: 10px; |
||||
|
display: flex; |
||||
|
justify-content: space-evenly; |
||||
|
align-items: center; |
||||
|
|
||||
|
} |
||||
|
/* 单个按钮 */ |
||||
|
.button { |
||||
|
padding: 0px; |
||||
|
min-height: auto; |
||||
|
margin-bottom: 1px; |
||||
|
} |
||||
|
/* 图片 */ |
||||
|
.picture { |
||||
|
height: 100%; |
||||
|
min-height: 50px; |
||||
|
max-height: 100px; |
||||
|
display: block; |
||||
|
width: 100%; |
||||
|
min-width: 50px; |
||||
|
} |
||||
|
|
||||
|
.el-col { |
||||
|
border-radius: 4px; |
||||
|
} |
||||
|
|
||||
|
.grid-content { |
||||
|
border-radius: 4px; |
||||
|
min-height: 36px; |
||||
|
} |
||||
|
|
||||
|
.app_box{ |
||||
|
margin: 15px 0 0 0px; |
||||
|
} |
||||
|
|
||||
|
.block-col-2 .demonstration { |
||||
|
display: block; |
||||
|
color: var(--el-text-color-secondary); |
||||
|
font-size: 14px; |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
|
||||
|
.block-col-2 .el-dropdown-link { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
} |
||||
|
/* 分页 */ |
||||
|
.example-pagination-block + .example-pagination-block { |
||||
|
margin-top: 10px; |
||||
|
} |
||||
|
.example-pagination-block .example-demonstration { |
||||
|
margin-bottom: 16px; |
||||
|
} |
||||
|
</style> |
||||
Loading…
Reference in new issue