明树Git Lab

Commit 4cfcb74f authored by yangyajing's avatar yangyajing

部门管理

parent e1030023
Pipeline #104515 passed with stage
in 14 seconds
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
.manage-content{ .manage-content{
flex: 1; flex: 1;
height: 0; height: 0;
&>.common-table{ .common-table{
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
height: 0; height: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
&>.common-table{ .common-table{
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
......
<template> <template>
<div class="depart-manage" v-loading="loading"> <div class="depart-manage" v-loading="loading">
<div class="manage-left"> <div class="manage-left">
<div class="origin-title"> <div class="handle-btn">
<h4>部门</h4> <el-button type="primary" size="small" @click="handleAdd">新增</el-button>
</div> </div>
<div class="tree-content"> <div class="tree-content">
<span class="filterRow"> <el-tree
:data="treeData"
node-key="id"
default-expand-all
draggable
:props="{label: 'name'}"
@node-click="handleNodeClick"
>
<template #default="{ node, data }">
<div class="custom-tree-node">
<span class="node-name">{{ node.label }}</span>
<el-dropdown> <el-dropdown>
<span class="el-dropdown-link"> <span class="el-dropdown-link">
<i class="iconfont icon-gengduo"></i> <i class="iconfont icon-gengduo"></i>
</span> </span>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item @click="handleAdd" <el-dropdown-item @click="handleAddChild(data)"
><i class="iconfont icon-tianjia"></i ><i class="iconfont icon-tianjia"></i
>添加组织</el-dropdown-item >添加子部门</el-dropdown-item
> >
<el-dropdown-item @click="handleOriginEdit" <el-dropdown-item @click="handleEdit(data)"
><i class="iconfont icon-bianji"></i ><i class="iconfont icon-bianji"></i
>编辑组织</el-dropdown-item >编辑</el-dropdown-item
> >
<el-dropdown-item @click="handleDeleteOrigin" <el-dropdown-item @click="handleDelete(data)"
><i class="iconfont icon-shanchu"></i ><i class="iconfont icon-shanchu"></i
>删除组织</el-dropdown-item >删除</el-dropdown-item
> >
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
</span>
<el-tree
:data="treeData"
node-key="id"
default-expand-all
draggable
@node-click="handleNodeClick"
>
</el-tree>
</div>
</div> </div>
<div class="table-container" v-loading="userLoading"> </template>
<div class="search-contain"> </el-tree>
<div>
人员信息:
<el-input placeholder="请输入人员信息" v-model="userName" />
</div> </div>
<div>
<el-button type="" @click="handleReset">重置</el-button>
<el-button type="primary" @click="handleUserData">查询</el-button>
</div> </div>
<div class="user-content" v-loading="userLoading">
<div class="search-container">
<el-form :inline="true" :model="searchForm">
<el-form-item label="关键字查询">
<el-input v-model="searchForm.name" :style="{width: '220px'}" clearable placeholder="请输入用户姓名" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">查询</el-button>
</el-form-item>
</el-form>
</div> </div>
<common-table <common-table
:autoHeight="true"
:maxRows="10"
:data="tableData" :data="tableData"
:columns="tableColumns" :columns="tableColumns"
:total="total" :total="total"
...@@ -74,16 +76,19 @@ ...@@ -74,16 +76,19 @@
v-model="dialogVisible" v-model="dialogVisible"
:title="dialogTitle" :title="dialogTitle"
width="400px" width="400px"
@close="handleDialogClose" @close="cancelDepartForm"
> >
<commonForm <el-form :model="departFormData" ref="departForm" :rules="departRules" label-width="100">
v-model="originForm" <el-form-item label="项目名称" prop="name">
:config="formConfig" <el-input v-model="departFormData.name" />
:items="formItems" </el-form-item>
:rules="formRules" </el-form>
@submit="handleFormSubmit" <template #footer>
@reset="handleFormReset" <div class="dialog-footer">
/> <el-button @click="cancelDepartForm">取消</el-button>
<el-button type="primary" @click="saveDepartForm">保存</el-button>
</div>
</template>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
...@@ -91,276 +96,95 @@ ...@@ -91,276 +96,95 @@
<script setup> <script setup>
import { ref, reactive, onMounted, getCurrentInstance, computed } from "vue"; import { ref, reactive, onMounted, getCurrentInstance, computed } from "vue";
import { ElMessage, ElMessageBox } from "element-plus"; import { ElMessage, ElMessageBox } from "element-plus";
import commonForm from "@/components/common/commonForm.vue";
import CommonTable from "@/components/common/commonTable.vue"; import CommonTable from "@/components/common/commonTable.vue";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const loading = ref(false); const loading = ref(false);
const userLoading = ref(false); const userLoading = ref(false);
const treeData = ref([]); const treeData = ref([]);
const originTreeData = ref([]);
const selectedNode = ref(null); const selectedNode = ref(null);
const userName = ref("");
// 数据转换函数
const convertToTreeData = (apiData, type) => {
if (type === "id") {
return apiData.map((item) => ({
id: item.id,
label: item.name,
parentId: item.parentId,
children: item.children ? convertToTreeData(item.children, "id") : [],
}));
} else {
return apiData.map((item) => ({
parentId: item.parentId,
value: item.id,
label: item.name,
children: item.children ? convertToTreeData(item.children, "value") : [],
}));
}
};
// 表格数据
const tableData = ref([]);
const total = ref(0);
const currentPage = ref(1);
const pageSize = ref(10);
// 表格列配置
const tableColumns = [
{
prop: "name",
label: "用户姓名",
minWidth: 100,
showOverflowTooltip: true,
},
{
prop: "departs",
label: "所属部门",
minWidth: 80,
showOverflowTooltip: true,
},
{
prop: "positions",
label: "岗位",
minWidth: 100,
showOverflowTooltip: true,
},
{
prop: "roles",
label: "角色",
minWidth: 100,
showOverflowTooltip: true,
},
{
prop: "mobile",
label: "手机号码",
minWidth: 100,
},
{
prop: "createdAt",
label: "创建时间",
minWidth: 160,
},
{
prop: "enable",
label: "状态",
width: 100,
slot: "enable",
align: "center",
},
];
// 对话框相关 // 对话框相关
const dialogVisible = ref(false); const dialogVisible = ref(false);
const dialogTitle = ref("新增用户"); const dialogTitle = ref("");
const isEdit = ref(false); let departFormData = ref({});
const departForm = ref();
// 用户表单数据
const originForm = ref({
name: "",
parentId: "",
});
// 用户表单配置
const formConfig = {
labelWidth: "100px",
showButtons: true,
submitText: "保存",
resetText: "取消",
};
// 用户表单项配置
const formItems = computed(() => [
{
type: "tree",
prop: "parentId",
label: "上级组织",
placeholder: "请选择上级组织",
data: originTreeData.value,
clearable: true,
filterable: true,
checkStrictly: true,
renderAfterExpand: false,
showCheckbox: false,
multiple: false,
span: 24,
// required: true,
// rules: [{ required: true, message: "请选择上级组织", trigger: "blur" }],
},
{
type: "input",
prop: "name",
label: "组织名称:",
placeholder: "请输入组织名称",
required: true,
rules: [{ required: true, message: "请输入组织名称", trigger: "blur" }],
span: 24,
},
]);
// 表单验证规则 // 表单验证规则
const formRules = {}; const departRules = {
name: [
const handleSizeChange = (size) => { { required: true, message: "请输入部门名称", trigger: "blur" }
pageSize.value = size; ]
currentPage.value = 1;
loadTableData();
}; };
// 新增部门
const handleCurrentPageChange = (page) => {
currentPage.value = page;
loadTableData();
};
// 新增用户
const handleAdd = () => { const handleAdd = () => {
isEdit.value = false; dialogTitle.value = "新增部门";
dialogTitle.value = "新增组织";
dialogVisible.value = true; dialogVisible.value = true;
console.log(selectedNode.value);
originForm.value = {
parentId: "",
name: "",
};
};
let currentID = ref("");
// 处理树节点点击事件
const handleNodeClick = (data, node, element) => {
selectedNode.value = data;
currentID.value = selectedNode.value.id;
handleUserData();
}; };
// 组织详情 // 添加子部门
const handleOriginEdit = () => { const handleAddChild = (data) => {
if (selectedNode.value === null) { dialogTitle.value = "新增子部门";
ElMessage.warning("请选择要编辑的数据"); departFormData.value.parentId = data.id;
} else {
isEdit.value = true;
dialogVisible.value = true; dialogVisible.value = true;
dialogTitle.value = "编辑组织"; }
const selectID = { const handleEdit = (data) => {
id: selectedNode.value.id, departFormData.value = {...data};
}; dialogTitle.value = "编辑部门";
proxy.$post({ dialogVisible.value = true;
url: "/api/user/depart/getDepart", }
data: selectID, const handleDelete = (data) => {
callback: (data) => { ElMessageBox.confirm(`确定删除${data.name}?`, "提示", {
originForm.value = { ...data }; confirmButtonText: "确定",
currentID.value = data.id; cancelButtonText: "取消",
}, type: "warning",
error: (err) => { }).then(() => {
ElMessage.error("编辑失败:", err);
},
});
}
};
// 组织删除
const handleDeleteOrigin = () => {
console.log(selectedNode.value);
if (selectedNode.value === null) {
ElMessage.warning("请选择要删除的组织");
} else {
const deleteItem = {
id: selectedNode.value.id,
name: selectedNode.value.label,
parentId: selectedNode.value.parentId
? selectedNode.value.parentId
: null,
};
proxy.$post({ proxy.$post({
url: "/api/user/depart/deleteDepart", url: "/api/user/depart/deleteDepart",
data: deleteItem, data: { id: data.id },
callback: (data) => { callback: (data) => {
handleTreeData();
ElMessage.success("删除成功"); ElMessage.success("删除成功");
loadTreeData();
}, },
error: (err) => { error: (err) => {
ElMessage.error("删除失败", err); ElMessage.error("删除失败:", err);
}, },
}); });
}
};
const handleFormSubmit = (formData) => {
if (isEdit.value) {
// 编辑组织
const updateOriForm = {
...formData,
parentId: formData.parentId ? formData.parentId : null,
id: currentID.value,
};
proxy.$post({
url: "/api/user/depart/updateDepart",
data: updateOriForm,
callback: (data) => {
dialogVisible.value = false;
handleTreeData();
ElMessage.success("组织更新成功");
},
error: (err) => {
ElMessage.error("组织更新失败", err);
},
}); });
} else { }
// 新增组织
const addOroginForm = {
...formData, const saveDepartForm = () => {
parentId: formData.parentId ? formData.parentId : null, let url = departFormData.value.id ? "updateDepart" : "createDepart"
};
proxy.$post({ proxy.$post({
url: "/api/user/depart/createDepart", url: "/api/user/depart/" + url,
data: addOroginForm, data: departFormData.value,
callback: (data) => { callback: (data) => {
dialogVisible.value = false; ElMessage.success(dialogTitle.value + "成功");
handleTreeData(); cancelDepartForm();
ElMessage.success("组织添加成功"); loadTreeData();
}, },
error: (err) => { error: (err) => {
ElMessage.error("组织添加失败:", err); ElMessage.error("组织添加失败:", err);
}, },
}); });
}
}; };
const cancelDepartForm = () => {
const handleFormReset = () => { departForm.value.resetFields();
departFormData.value = {};
dialogVisible.value = false; dialogVisible.value = false;
selectedNode.value = "";
}; };
const handleDialogClose = () => {
dialogVisible.value = false;
selectedNode.value = null;
};
const handleReset = () => { // 处理树节点点击事件
userName.value = ""; const handleNodeClick = (data, node, element) => {
currentPage.value = 1; selectedNode.value = data;
handleUserData(); handleUserData();
}; };
// 树形数据 // 树形数据
const handleTreeData = () => { const loadTreeData = () => {
loading.value = true; loading.value = true;
proxy.$post({ proxy.$post({
url: "/api/user/depart/treeDepart", url: "/api/user/depart/treeDepart",
...@@ -369,8 +193,7 @@ const handleTreeData = () => { ...@@ -369,8 +193,7 @@ const handleTreeData = () => {
pageSize: pageSize.value, pageSize: pageSize.value,
}, },
callback: (data) => { callback: (data) => {
treeData.value = convertToTreeData(data, "id"); treeData.value = data;
originTreeData.value = convertToTreeData(data, "value");
selectedNode.value = data[0].id; selectedNode.value = data[0].id;
loading.value = false; loading.value = false;
}, },
...@@ -380,6 +203,8 @@ const handleTreeData = () => { ...@@ -380,6 +203,8 @@ const handleTreeData = () => {
}, },
}); });
}; };
// 人员信息 // 人员信息
const handleUserData = () => { const handleUserData = () => {
userLoading.value = true; userLoading.value = true;
...@@ -388,8 +213,8 @@ const handleUserData = () => { ...@@ -388,8 +213,8 @@ const handleUserData = () => {
data: { data: {
page: currentPage.value, page: currentPage.value,
pageSize: pageSize.value, pageSize: pageSize.value,
departId: currentID.value, departId: selectedNode.value.id,
name: userName.value, name: searchForm.value.name,
}, },
callback: (data) => { callback: (data) => {
tableData.value = data.rows.map((item) => { tableData.value = data.rows.map((item) => {
...@@ -407,9 +232,71 @@ const handleUserData = () => { ...@@ -407,9 +232,71 @@ const handleUserData = () => {
}, },
}); });
}; };
// 表格数据
const tableData = ref([]);
const total = ref(0);
const currentPage = ref(1);
const pageSize = ref(10);
const searchForm = ref({});
// 表格列配置
const tableColumns = [
{
prop: "name",
label: "用户姓名",
minWidth: 100,
showOverflowTooltip: true,
},
{
prop: "departs",
label: "所属部门",
minWidth: 80,
showOverflowTooltip: true,
},
{
prop: "positions",
label: "岗位",
minWidth: 100,
showOverflowTooltip: true,
},
{
prop: "roles",
label: "角色",
minWidth: 100,
showOverflowTooltip: true,
},
{
prop: "mobile",
label: "手机号码",
minWidth: 100,
},
{
prop: "enable",
label: "状态",
width: 100,
slot: "enable",
align: "center",
},
];
const handleSearch = () => {
currentPage.value = 1;
handleUserData();
};
const handleSizeChange = (size) => {
pageSize.value = size;
currentPage.value = 1;
handleUserData();
};
const handleCurrentPageChange = (page) => {
currentPage.value = page;
handleUserData();
};
onMounted(() => { onMounted(() => {
handleTreeData(); loadTreeData();
}); });
</script> </script>
...@@ -427,36 +314,18 @@ onMounted(() => { ...@@ -427,36 +314,18 @@ onMounted(() => {
padding: 20px; padding: 20px;
margin-right: 20px; margin-right: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
width: 240px; width: 270px;
overflow: auto;
}
.origin-title {
display: flex; display: flex;
justify-content: space-between; flex-direction: column;
margin-bottom: 20px;
span {
color: #2561ef;
cursor: pointer;
}
} }
.search-contain { .handle-btn{
display: flex; display: flex;
justify-content: space-between; justify-content: flex-end;
.el-input {
width: 255px;
}
}
.filterRow {
display: inline-block;
cursor: pointer;
display: flex;
justify-content: end;
.icon-gedian {
color: rgba(37, 97, 239, 1);
font-size: 20px;
}
} }
.tree-content { .tree-content {
flex: 1;
height: 0;
overflow: auto;
margin-top: 20px; margin-top: 20px;
position: relative; position: relative;
.el-tree { .el-tree {
...@@ -485,15 +354,52 @@ onMounted(() => { ...@@ -485,15 +354,52 @@ onMounted(() => {
} }
} }
} }
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
.node-name{
flex: 1;
width: 0;
-webkit-background-clip: text;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
} }
.table-container { .user-content {
flex: 1; flex: 1;
width: 0; width: 0;
background: rgba(255, 255, 255, 0.9); background: rgba(255, 255, 255, 0.9);
border-radius: 8px; border-radius: 8px;
padding: 20px; padding: 20px 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
.search-container{
padding: 0 20px;
}
.common-table{
flex: 1;
height: 0;
display: flex;
flex-direction: column;
.table-container{
flex: 1;
height: 0;
display: flex;
flex-direction: column;
.el-table{
flex: 1;
height: 0;
}
}
}
} }
} }
.el-input__wrapper { .el-input__wrapper {
...@@ -508,17 +414,9 @@ onMounted(() => { ...@@ -508,17 +414,9 @@ onMounted(() => {
} }
:deep(.el-tree-node.is-current > .el-tree-node__content) { :deep(.el-tree-node.is-current > .el-tree-node__content) {
background-color: rgba(37, 97, 239, 1); background-color: #ecf5ff;
color: #fff; color: #409eff;
height: 40px; height: 40px;
border-radius: 3px; border-radius: 3px;
.el-tree-node__label {
color: white !important;
}
.el-icon {
color: white !important;
}
} }
</style> </style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment