明树Git Lab

Commit 4cfcb74f authored by yangyajing's avatar yangyajing

部门管理

parent e1030023
Pipeline #104515 passed with stage
in 14 seconds
......@@ -23,7 +23,7 @@
.manage-content{
flex: 1;
height: 0;
&>.common-table{
.common-table{
height: 100%;
display: flex;
flex-direction: column;
......@@ -70,7 +70,7 @@
height: 0;
display: flex;
flex-direction: column;
&>.common-table{
.common-table{
height: 100%;
display: flex;
flex-direction: column;
......
<template>
<div class="depart-manage" v-loading="loading">
<div class="manage-left">
<div class="origin-title">
<h4>部门</h4>
<div class="handle-btn">
<el-button type="primary" size="small" @click="handleAdd">新增</el-button>
</div>
<div class="tree-content">
<span class="filterRow">
<el-dropdown>
<span class="el-dropdown-link">
<i class="iconfont icon-gengduo"></i>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="handleAdd"
><i class="iconfont icon-tianjia"></i
>添加组织</el-dropdown-item
>
<el-dropdown-item @click="handleOriginEdit"
><i class="iconfont icon-bianji"></i
>编辑组织</el-dropdown-item
>
<el-dropdown-item @click="handleDeleteOrigin"
><i class="iconfont icon-shanchu"></i
>删除组织</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
</span>
<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>
<span class="el-dropdown-link">
<i class="iconfont icon-gengduo"></i>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="handleAddChild(data)"
><i class="iconfont icon-tianjia"></i
>添加子部门</el-dropdown-item
>
<el-dropdown-item @click="handleEdit(data)"
><i class="iconfont icon-bianji"></i
>编辑</el-dropdown-item
>
<el-dropdown-item @click="handleDelete(data)"
><i class="iconfont icon-shanchu"></i
>删除</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-tree>
</div>
</div>
<div class="table-container" v-loading="userLoading">
<div class="search-contain">
<div>
人员信息:
<el-input placeholder="请输入人员信息" v-model="userName" />
</div>
<div>
<el-button type="" @click="handleReset">重置</el-button>
<el-button type="primary" @click="handleUserData">查询</el-button>
</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>
<common-table
:autoHeight="true"
:maxRows="10"
:data="tableData"
:columns="tableColumns"
:total="total"
......@@ -74,16 +76,19 @@
v-model="dialogVisible"
:title="dialogTitle"
width="400px"
@close="handleDialogClose"
@close="cancelDepartForm"
>
<commonForm
v-model="originForm"
:config="formConfig"
:items="formItems"
:rules="formRules"
@submit="handleFormSubmit"
@reset="handleFormReset"
/>
<el-form :model="departFormData" ref="departForm" :rules="departRules" label-width="100">
<el-form-item label="项目名称" prop="name">
<el-input v-model="departFormData.name" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="cancelDepartForm">取消</el-button>
<el-button type="primary" @click="saveDepartForm">保存</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
......@@ -91,276 +96,95 @@
<script setup>
import { ref, reactive, onMounted, getCurrentInstance, computed } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import commonForm from "@/components/common/commonForm.vue";
import CommonTable from "@/components/common/commonTable.vue";
const { proxy } = getCurrentInstance();
const loading = ref(false);
const userLoading = ref(false);
const treeData = ref([]);
const originTreeData = ref([]);
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 dialogTitle = ref("新增用户");
const isEdit = ref(false);
// 用户表单数据
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 dialogTitle = ref("");
let departFormData = ref({});
const departForm = ref();
// 表单验证规则
const formRules = {};
const handleSizeChange = (size) => {
pageSize.value = size;
currentPage.value = 1;
loadTableData();
const departRules = {
name: [
{ required: true, message: "请输入部门名称", trigger: "blur" }
]
};
const handleCurrentPageChange = (page) => {
currentPage.value = page;
loadTableData();
};
// 新增用户
// 新增部门
const handleAdd = () => {
isEdit.value = false;
dialogTitle.value = "新增组织";
dialogTitle.value = "新增部门";
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 = () => {
if (selectedNode.value === null) {
ElMessage.warning("请选择要编辑的数据");
} else {
isEdit.value = true;
dialogVisible.value = true;
dialogTitle.value = "编辑组织";
const selectID = {
id: selectedNode.value.id,
};
proxy.$post({
url: "/api/user/depart/getDepart",
data: selectID,
callback: (data) => {
originForm.value = { ...data };
currentID.value = data.id;
},
error: (err) => {
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({
url: "/api/user/depart/deleteDepart",
data: deleteItem,
callback: (data) => {
handleTreeData();
ElMessage.success("删除成功");
},
error: (err) => {
ElMessage.error("删除失败", err);
},
// 添加子部门
const handleAddChild = (data) => {
dialogTitle.value = "新增子部门";
departFormData.value.parentId = data.id;
dialogVisible.value = true;
}
const handleEdit = (data) => {
departFormData.value = {...data};
dialogTitle.value = "编辑部门";
dialogVisible.value = true;
}
const handleDelete = (data) => {
ElMessageBox.confirm(`确定删除${data.name}?`, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
proxy.$post({
url: "/api/user/depart/deleteDepart",
data: { id: data.id },
callback: (data) => {
ElMessage.success("删除成功");
loadTreeData();
},
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,
parentId: formData.parentId ? formData.parentId : null,
};
proxy.$post({
url: "/api/user/depart/createDepart",
data: addOroginForm,
callback: (data) => {
dialogVisible.value = false;
handleTreeData();
ElMessage.success("组织添加成功");
},
error: (err) => {
ElMessage.error("组织添加失败:", err);
},
});
}
};
const handleFormReset = () => {
dialogVisible.value = false;
selectedNode.value = "";
const saveDepartForm = () => {
let url = departFormData.value.id ? "updateDepart" : "createDepart"
proxy.$post({
url: "/api/user/depart/" + url,
data: departFormData.value,
callback: (data) => {
ElMessage.success(dialogTitle.value + "成功");
cancelDepartForm();
loadTreeData();
},
error: (err) => {
ElMessage.error("组织添加失败:", err);
},
});
};
const handleDialogClose = () => {
const cancelDepartForm = () => {
departForm.value.resetFields();
departFormData.value = {};
dialogVisible.value = false;
selectedNode.value = null;
};
const handleReset = () => {
userName.value = "";
currentPage.value = 1;
// 处理树节点点击事件
const handleNodeClick = (data, node, element) => {
selectedNode.value = data;
handleUserData();
};
// 树形数据
const handleTreeData = () => {
const loadTreeData = () => {
loading.value = true;
proxy.$post({
url: "/api/user/depart/treeDepart",
......@@ -369,8 +193,7 @@ const handleTreeData = () => {
pageSize: pageSize.value,
},
callback: (data) => {
treeData.value = convertToTreeData(data, "id");
originTreeData.value = convertToTreeData(data, "value");
treeData.value = data;
selectedNode.value = data[0].id;
loading.value = false;
},
......@@ -380,6 +203,8 @@ const handleTreeData = () => {
},
});
};
// 人员信息
const handleUserData = () => {
userLoading.value = true;
......@@ -388,8 +213,8 @@ const handleUserData = () => {
data: {
page: currentPage.value,
pageSize: pageSize.value,
departId: currentID.value,
name: userName.value,
departId: selectedNode.value.id,
name: searchForm.value.name,
},
callback: (data) => {
tableData.value = data.rows.map((item) => {
......@@ -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(() => {
handleTreeData();
loadTreeData();
});
</script>
......@@ -427,36 +314,18 @@ onMounted(() => {
padding: 20px;
margin-right: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
width: 240px;
overflow: auto;
}
.origin-title {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
span {
color: #2561ef;
cursor: pointer;
}
}
.search-contain {
width: 270px;
display: flex;
justify-content: space-between;
.el-input {
width: 255px;
}
flex-direction: column;
}
.filterRow {
display: inline-block;
cursor: pointer;
.handle-btn{
display: flex;
justify-content: end;
.icon-gedian {
color: rgba(37, 97, 239, 1);
font-size: 20px;
}
justify-content: flex-end;
}
.tree-content {
flex: 1;
height: 0;
overflow: auto;
margin-top: 20px;
position: relative;
.el-tree {
......@@ -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;
width: 0;
background: rgba(255, 255, 255, 0.9);
border-radius: 8px;
padding: 20px;
padding: 20px 12px;
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 {
......@@ -508,17 +414,9 @@ onMounted(() => {
}
:deep(.el-tree-node.is-current > .el-tree-node__content) {
background-color: rgba(37, 97, 239, 1);
color: #fff;
background-color: #ecf5ff;
color: #409eff;
height: 40px;
border-radius: 3px;
.el-tree-node__label {
color: white !important;
}
.el-icon {
color: white !important;
}
}
</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