用户管理左侧树编辑、添加、删除弹框添加

This commit is contained in:
2026-08-18 13:52:48 +08:00
parent 6c1fdf8551
commit bbbdb85f6e
+154 -34
View File
@@ -3,11 +3,12 @@ import { ref, computed, h, onMounted, defineComponent } from 'vue';
import { useAppStore } from '@/store/modules/app';
import { Icon } from '@iconify/vue'
import { useThemeStore } from '@/store/modules/theme';
import { NButton, NPopconfirm, NTag, NDropdown } from 'naive-ui';
import { NButton, NPopconfirm, NTag, NDropdown, useDialog } from 'naive-ui';
const appStore = useAppStore();
const themeStore = useThemeStore();
const gap = computed(() => (appStore.isMobile ? 0 : 16));
const dialog = useDialog()
const loading = ref<boolean>(false);
const btnLoading = ref<boolean>(false);
@@ -102,7 +103,7 @@ const columns = ref([
return h(NTag, {
size: 'small',
type: `${row.status===1?'success':'error'}`
}, { default: () => `${row.status===1?'启':'关闭'}` })
}, { default: () => `${row.status===1?'启':'禁用'}` })
}
},
{
@@ -181,36 +182,64 @@ const roleOptions = ref([
{ label: '管理员', value: 'admin' },
{ label: '普通用户', value: 'user' },
])
const formNodeRef = ref<any>(null);
const treeModal = ref<boolean>(false);
const currentNode = ref<{ id: string, label: string, key: string, children: any[], shortLabel: string, parent: string, isLeaf: number, sort: number }>({
id: '',
label: '',
key: '',
children: [],
shortLabel: '',
parent: '',
isLeaf: 1,
sort: 0,
})
const formNode = ref<{ id: string, label: string, key: string, children: any[], shortLabel: string, parent: string, isLeaf: number, sort: number }>({
id: '',
label: '',
key: '',
children: [],
shortLabel: '',
parent: '',
isLeaf: 1,
sort: 0,
})
const currentNodeType = ref<string>('edit')
// 树节点规则
const treeRules = ref({
label: [{ required: true, message: '请输入层级名称', trigger: ['blur'] }],
})
// 左侧组织树
const orgTree = ref([
{
id: "factory", label: "演示工厂", key: "YS",
id: "factory", label: "演示工厂", key: "YS", shortLabel: 'YS', parent: '', isLeaf: 0, sort: 0,
children: [
{
id: "scb", label: "生产部", key: "SCB",
id: "scb", label: "生产部", key: "SCB", shortLabel: 'SCB', parent: '演示工厂', isLeaf: 0, sort: 0,
children: [
{ id: "cj1", label: "测试车间一", key: "CJ1" },
{ id: "cj2", label: "测试车间二", key: "CJ2" },
{ id: "cj3", label: "测试车间三", key: "CJ3" },
{ id: "cj1", label: "测试车间一", key: "CJ1", shortLabel: 'CJ1', parent: '生产部', isLeaf: 1, sort: 0 },
{ id: "cj2", label: "测试车间二", key: "CJ2", shortLabel: 'CJ2', parent: '生产部', isLeaf: 1, sort: 0 },
{ id: "cj3", label: "测试车间三", key: "CJ3", shortLabel: 'CJ3', parent: '生产部', isLeaf: 1, sort: 0 },
],
},
{
id: "ahb", label: "安环部", key: "AHB",
id: "ahb", label: "安环部", key: "AHB", shortLabel: 'AHB', parent: '演示工厂', isLeaf: 0, sort: 0,
children: [
{ id: "aqk", label: "安全科", key: "AQK" },
{ id: "hbk", label: "环保科", key: "HBK" },
{ id: "aqk", label: "安全科", key: "AQK", shortLabel: 'AQK', parent: '安环部', isLeaf: 1, sort: 0 },
{ id: "hbk", label: "环保科", key: "HBK", shortLabel: 'HBK', parent: '安环部', isLeaf: 1, sort: 0 },
],
},
{
id: "sbb", label: "设备部", key: "SBB",
id: "sbb", label: "设备部", key: "SBB", shortLabel: 'SBB', parent: '演示工厂', isLeaf: 0, sort: 0,
children: [
{ id: "sbk", label: "设备科", key: "SBK" },
{ id: "sbk", label: "设备科", key: "SBK", shortLabel: 'SBK', parent: '设备部', isLeaf: 1, sort: 0 },
],
},
{
id: "zlb", label: "质量部", key: "ZLB",
id: "zlb", label: "质量部", key: "ZLB", shortLabel: 'ZLB', parent: '演示工厂', isLeaf: 0, sort: 0,
children: [
{ id: "zjk", label: "质检科", key: "ZJK" },
{ id: "zjk", label: "质检科", key: "ZJK", shortLabel: 'ZJK', parent: '质量部', isLeaf: 1, sort: 0 },
],
},
],
@@ -222,11 +251,10 @@ const defaultSelectedKeys = ref<string[]>(['YS'])
const menuVisible = ref(false)
const menuX = ref(0)
const menuY = ref(0)
const currentNode = ref(null)
// 菜单选项
const menuOptions = [
{ label: '编辑', key: 'edit' },
{ label: '添加子级', key: 'addChild' },
{ label: '添加子级', key: 'add' },
{ label: '删除', key: 'delete' },
]
const handleSelectKeys = (keys: string[]) => {
@@ -238,6 +266,7 @@ const treeProps = ({ option }: { option: any }) => {
onContextmenu(e: MouseEvent) {
e.preventDefault()
currentNode.value = option
console.log(currentNode.value)
menuX.value = e.clientX
menuY.value = e.clientY
menuVisible.value = true
@@ -246,16 +275,44 @@ const treeProps = ({ option }: { option: any }) => {
}
// 点击菜单项
const handleMenuSelect = (key: string) => {
const node = currentNode.value
currentNodeType.value = key
switch (key) {
case 'edit':
console.log('编辑节点', node)
formNode.value = currentNode.value
treeModal.value = true
break
case 'add':
formNode.value = {
id: '',
label: '',
key: '',
children: [],
shortLabel: '',
parent: currentNode.value.label,
isLeaf: 0,
sort: 0,
}
treeModal.value = true
break
case 'delete':
console.log('删除节点', node)
break
case 'addChild':
console.log('添加子节点到', node)
const d = dialog.info({
title: '删除',
content: `确定删除层级「${currentNode.value.label}」吗? 该操作不可恢复`,
positiveText: '确定',
negativeText: '取消',
onPositiveClick: () => {
d.loading = true
return new Promise((resolve) => {
setTimeout(() => {
d.loading = false
resolve(true)
}, 1000)
})
},
onNegativeClick: () => {
d.loading = false
}
})
break
}
closeMenu()
@@ -263,7 +320,6 @@ const handleMenuSelect = (key: string) => {
// 关闭菜单
const closeMenu = () => {
menuVisible.value = false
currentNode.value = null
}
const renderSwitcherIcon = () => {
return h(Icon, { icon: 'formkit:right',class:'size-14px' }, {})
@@ -313,14 +369,6 @@ const getList = async () => {
{id:10,name:'姓名10',dept:[],mobile:'13800000009',email:'user1@example.com',account:'user10',role:'普通用户',dataPermission:[],gender:1,status:1},
{id:11,name:'姓名11',dept:['YS'],mobile:'13800000010',email:'user1@example.com',account:'user11',role:'普通用户',dataPermission:[],gender:1,status:1},
{id:12,name:'姓名12',dept:[],mobile:'13800000011',email:'user1@example.com',account:'user12',role:'普通用户',dataPermission:[],gender:1,status:1},
{id:12,name:'姓名12',dept:[],mobile:'13800000011',email:'user1@example.com',account:'user12',role:'普通用户',dataPermission:[],gender:1,status:1},
{id:12,name:'姓名12',dept:[],mobile:'13800000011',email:'user1@example.com',account:'user12',role:'普通用户',dataPermission:[],gender:1,status:1},
{id:12,name:'姓名12',dept:[],mobile:'13800000011',email:'user1@example.com',account:'user12',role:'普通用户',dataPermission:[],gender:1,status:1},
{id:12,name:'姓名12',dept:[],mobile:'13800000011',email:'user1@example.com',account:'user12',role:'普通用户',dataPermission:[],gender:1,status:1},
{id:12,name:'姓名12',dept:[],mobile:'13800000011',email:'user1@example.com',account:'user12',role:'普通用户',dataPermission:[],gender:1,status:1},
{id:12,name:'姓名12',dept:[],mobile:'13800000011',email:'user1@example.com',account:'user12',role:'普通用户',dataPermission:[],gender:1,status:1},
{id:12,name:'姓名12',dept:[],mobile:'13800000011',email:'user1@example.com',account:'user12',role:'普通用户',dataPermission:[],gender:1,status:1},
{id:12,name:'姓名12',dept:[],mobile:'13800000011',email:'user1@example.com',account:'user12',role:'普通用户',dataPermission:[],gender:1,status:1},
]
}, 1000)
}
@@ -420,6 +468,20 @@ const saveUser = async (e: MouseEvent) => {
}
})
}
// 保存节点
const saveNode = async (e: MouseEvent) => {
e.preventDefault()
formNodeRef.value?.validate((errors: any) => {
if (!errors) {
btnLoading.value = true;
setTimeout(() => {
window.$message?.success(`${currentNodeType.value === 'edit' ? '编辑' : '添加'}成功`)
btnLoading.value = false;
treeModal.value = false;
}, 1000)
}
})
}
onMounted(() => {
getList()
@@ -500,8 +562,8 @@ onMounted(() => {
/>
</div>
</div>
<!-- 新增或编辑弹框 -->
<NDrawer v-model:show="userModal" :width="400" placement="right">
<!-- 新增或编辑抽屉 -->
<NDrawer v-model:show="userModal" :width="400" placement="right">
<NDrawerContent :title="currentType === 'add' ? '新增成员' : '编辑成员'" closable>
<NForm ref="formRef" :model="currentUser" :rules="rules" label-placement="left" label-width="auto">
<NFormItem label="姓名" path="name">
@@ -561,7 +623,7 @@ onMounted(() => {
</NFormItem>
<NFormItem label="状态">
<NRadioGroup v-model:value="currentUser.status" name="status">
<n-radio :value="1">正常</n-radio>
<n-radio :value="1">启用</n-radio>
<n-radio :value="2">禁用</n-radio>
</NRadioGroup>
</NFormItem>
@@ -574,6 +636,64 @@ onMounted(() => {
</template>
</NDrawerContent>
</NDrawer>
<!-- 左侧树添加/编辑弹框 -->
<NModal
v-model:show="treeModal"
preset="card"
:title="currentNodeType === 'edit' ? '编辑层级' : '添加子级'"
:auto-focus="false"
:style="{ width: '450px', height: 'auto' }"
:segmented="{ content: true, footer: true }"
>
<template #default>
<NForm ref="formNodeRef" :model="formNode" :rules="treeRules" label-placement="left" label-width="auto">
<NFormItem label="层级名称" path="label">
<NInput
v-model:value="formNode.label"
maxlength="10"
show-count
placeholder="请输入层级名称"
/>
</NFormItem>
<NFormItem label="层级简称">
<NInput
v-model:value="formNode.shortLabel"
maxlength="10"
show-count
placeholder="请输入层级简称"
/>
</NFormItem>
<NFormItem label="所属层级">
<NInput
v-model:value="formNode.parent"
:disabled="true"
placeholder=""
/>
</NFormItem>
<NFormItem label="末端层级">
<NRadioGroup v-model:value="formNode.isLeaf" name="isLeaf">
<n-radio :value="1"></n-radio>
<n-radio :value="0"></n-radio>
</NRadioGroup>
</NFormItem>
<NFormItem label="排序">
<NInputNumber
class="w-full"
v-model:value="formNode.sort"
:min="0"
:show-button="false"
placeholder="请输入排序"
/>
</NFormItem>
</NForm>
</template>
<template #footer>
<div class="flex justify-end gap-[10px]">
<NButton @click="treeModal = false">取消</NButton>
<NButton type="primary" :loading="btnLoading" @click="saveNode">确定</NButton>
</div>
</template>
</NModal>
</NCard>
</NSpace>
</template>