577 lines
15 KiB
Vue
577 lines
15 KiB
Vue
<template>
|
||
<div class="org-dialog">
|
||
<n-modal
|
||
class="org-dialog"
|
||
v-model:show="props.orgVisible"
|
||
:z-index="1999"
|
||
:mask-closable="true"
|
||
style="min-width: 1000px; max-width: 1200px"
|
||
:to="app"
|
||
>
|
||
<n-card
|
||
:bordered="false"
|
||
:title="props.title"
|
||
size="huge"
|
||
role="dialog"
|
||
aria-modal="true"
|
||
>
|
||
<template #header-extra>
|
||
<div class="close-box">
|
||
<n-button @click="closeFn" text style="font-size: 24px">
|
||
<n-icon>
|
||
<close-icon />
|
||
</n-icon>
|
||
</n-button>
|
||
</div>
|
||
</template>
|
||
<div class="item-box">
|
||
<fl-tree
|
||
:data="state.treeData"
|
||
:expandedKeys="state.expandedKeys"
|
||
:refreshCount="state.treeRefreshCount"
|
||
:clickKey="state.clickKey"
|
||
:config="{
|
||
actions: ['edit', 'add', 'subtraction', 'move'],
|
||
moveShow: '[%=level%]>0',
|
||
subtractionShow: '[%=level%]>0',
|
||
}"
|
||
@triggerTreeAction="handleTreeAction"
|
||
@triggerTreeClick="handleTreeClick"
|
||
></fl-tree>
|
||
</div>
|
||
<template #footer>
|
||
<div
|
||
style="text-align: center; padding-left: 20px; padding-right: 10px"
|
||
>
|
||
<n-button class="button-box" @click="closeFn"> 返回 </n-button>
|
||
</div>
|
||
</template>
|
||
</n-card>
|
||
</n-modal>
|
||
<n-modal
|
||
v-model:show="state.dialogAddTree"
|
||
style="width: 600px"
|
||
:mask-closable="false"
|
||
preset="card"
|
||
>
|
||
<template #header>
|
||
<div
|
||
class="col-12 row justify-center relative"
|
||
style="border-bottom: 1px solid #dfd7f2"
|
||
>
|
||
<div style="font-size: 20px; font-weight: bold; color: #1f2225ff">
|
||
添加组织
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<div class="row justify-center fl-pa-md">
|
||
<div class="fl-my-lg font-20">
|
||
<n-input
|
||
v-model:value="state.dialogAddTreeData"
|
||
placeholder="请输入组织名称"
|
||
/>
|
||
</div>
|
||
<div class="col-12 row justify-center">
|
||
<n-button
|
||
tertiary
|
||
style="width: 161px; background: #764cf6; color: #fff"
|
||
class="fl-mr-md"
|
||
@click="handleDialogAddTreeSave"
|
||
>保存</n-button
|
||
>
|
||
<n-button
|
||
tertiary
|
||
style="width: 161px; background: #eeeaf7; color: #774ff6"
|
||
@click="state.dialogAddTree = false"
|
||
>返回</n-button
|
||
>
|
||
</div>
|
||
</div>
|
||
</n-modal>
|
||
<n-modal
|
||
v-model:show="state.dialogSubtractionTree"
|
||
style="width: 600px"
|
||
:mask-closable="false"
|
||
preset="card"
|
||
>
|
||
<template #header>
|
||
<div
|
||
class="col-12 row justify-center relative"
|
||
style="border-bottom: 1px solid #dfd7f2"
|
||
>
|
||
<div style="font-size: 20px; font-weight: bold; color: #1f2225ff">
|
||
删除组织
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<div class="row justify-center fl-pa-md">
|
||
<div class="font-20" style="margin: 115px 0">
|
||
是否确认删除该组织及其子组织(如有)?
|
||
</div>
|
||
<div class="col-12 row justify-center">
|
||
<n-button
|
||
tertiary
|
||
style="width: 161px; background: #764cf6; color: #fff"
|
||
class="fl-mr-md"
|
||
@click="handleDialogSubtractionTreeSave"
|
||
>确定</n-button
|
||
>
|
||
<n-button
|
||
tertiary
|
||
style="width: 161px; background: #eeeaf7; color: #774ff6"
|
||
@click="state.dialogSubtractionTree = false"
|
||
>返回</n-button
|
||
>
|
||
</div>
|
||
</div>
|
||
</n-modal>
|
||
<n-modal
|
||
v-model:show="state.dialogMoveTree"
|
||
style="width: 600px"
|
||
:mask-closable="false"
|
||
preset="card"
|
||
>
|
||
<template #header>
|
||
<div
|
||
class="col-12 row justify-center relative"
|
||
style="border-bottom: 1px solid #dfd7f2"
|
||
>
|
||
<div style="font-size: 20px; font-weight: bold; color: #1f2225ff">
|
||
移动
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<div class="row justify-center fl-pa-md">
|
||
<div class="fl-my-lg font-20">
|
||
<div class="font-16 fl-mb-md">请选择部门节点</div>
|
||
<fln-form-item
|
||
type="select"
|
||
:val="null"
|
||
:fatherData="state.dialogData"
|
||
:config="{
|
||
placeholder: '选择归属组织',
|
||
config: {
|
||
optionConfig: {
|
||
resDataField: 'list',
|
||
url: '/department/v2/base/all/list',
|
||
params: [
|
||
{
|
||
label: 'notDepartmentIds',
|
||
field: 'key',
|
||
type: 'Array',
|
||
},
|
||
],
|
||
labelField: 'name',
|
||
valueField: 'ID',
|
||
},
|
||
},
|
||
}"
|
||
:clearable="true"
|
||
@triggerValChange="handleValChange"
|
||
/>
|
||
|
||
<div class="font-14 fl-mt-sm" style="color: #ef0000">
|
||
确认后,所选部门及其所有子部门将统一归属于新选定的上级部门之下,且保持原有子部门层级关系不变。
|
||
</div>
|
||
</div>
|
||
<div class="col-12 row justify-center fl-mt-md">
|
||
<n-button
|
||
tertiary
|
||
style="width: 161px; background: #eeeaf7; color: #774ff6"
|
||
class="fl-mr-md"
|
||
@click="state.dialogMoveTree = false"
|
||
>取消</n-button
|
||
>
|
||
<n-button
|
||
tertiary
|
||
style="width: 161px; background: #764cf6; color: #fff"
|
||
@click="handleDialogMoveTreeSave"
|
||
>确定</n-button
|
||
>
|
||
</div>
|
||
</div>
|
||
</n-modal>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
// 组织管理
|
||
import flnTable from "@/components/flnlayout/table/flntable.vue";
|
||
import flTree from "./components/flnindex.vue";
|
||
import {
|
||
ref,
|
||
reactive,
|
||
onBeforeMount,
|
||
defineProps,
|
||
defineEmits,
|
||
onMounted,
|
||
getCurrentInstance,
|
||
computed,
|
||
} from "vue";
|
||
import { Close as CloseIcon } from "@vicons/ionicons5";
|
||
import { Local } from "@/utils/storage.js";
|
||
import {
|
||
processError,
|
||
processSuccess,
|
||
processWarning,
|
||
} from "@/utils/helper/message";
|
||
import { useRouter } from "vue-router";
|
||
import flnFormItem from "@/components/flnlayout/form/flnformItem.vue";
|
||
|
||
const router = useRouter();
|
||
const currentInstance = getCurrentInstance();
|
||
const { $request } = currentInstance.appContext.config.globalProperties;
|
||
const app = document.getElementById("app");
|
||
const state = reactive({
|
||
dialogData: {},
|
||
dialogMoveTree: false,
|
||
dialogMoveTreeData: null,
|
||
departmentOptions: [],
|
||
dialogAddTree: false,
|
||
dialogAddTreeData: "",
|
||
dialogSubtractionTree: false,
|
||
treeSelectData: {},
|
||
clickKey: "",
|
||
treeRefreshCount: 0,
|
||
expandedKeys: [],
|
||
treeData: [],
|
||
|
||
btnLoading: false,
|
||
selectedRows: [],
|
||
tableConfig: {
|
||
requestbysf: true,
|
||
rowKey: "ID",
|
||
refreshCount: 0,
|
||
listUrl: {
|
||
resDataField: "data",
|
||
pageField: "page",
|
||
pageSizeField: "pageSize",
|
||
url: "user/v2/list",
|
||
params: [
|
||
{
|
||
label: "departmentID",
|
||
field: "key",
|
||
},
|
||
],
|
||
},
|
||
},
|
||
});
|
||
const props = defineProps({
|
||
orgVisible: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
title: {
|
||
type: String,
|
||
require: true,
|
||
},
|
||
});
|
||
onBeforeMount(() => {
|
||
let treeSelectData = Local.get("orgmanage_treeSelectData");
|
||
if (treeSelectData) {
|
||
state.treeSelectData = treeSelectData;
|
||
state.clickKey = treeSelectData.key;
|
||
}
|
||
getTreeData();
|
||
});
|
||
onMounted(() => {});
|
||
|
||
const getTreeData = () => {
|
||
let url = "/department/v2/tree/my";
|
||
let params = {};
|
||
$request.HTTP.components.postDataByParams(url, params).then(
|
||
(res) => {
|
||
if (res.status === 0 && Array.isArray(res.data.nodes)) {
|
||
let data = res.data.nodes;
|
||
calcTreeData(data);
|
||
state.treeData = data;
|
||
if (JSON.stringify(state.treeSelectData) === "{}") {
|
||
state.treeSelectData = data[0];
|
||
state.clickKey = data[0].key;
|
||
}
|
||
|
||
if (
|
||
state.clickKey === data[0].key &&
|
||
!state.expandedKeys.includes(data[0].key)
|
||
) {
|
||
state.expandedKeys.push(data[0].key);
|
||
}
|
||
if (!state.expandedKeys.includes(state.clickKey)) {
|
||
state.expandedKeys.push(state.clickKey);
|
||
}
|
||
if (data.length === 1 && !state.expandedKeys.includes(data[0].key)) {
|
||
state.expandedKeys.push(data[0].key);
|
||
}
|
||
state.treeRefreshCount++;
|
||
state.tableConfig.refreshCount++;
|
||
} else {
|
||
processError(res.msg || "获取失败!");
|
||
}
|
||
},
|
||
() => {
|
||
processError("获取失败!");
|
||
},
|
||
() => {
|
||
processError("获取失败!");
|
||
}
|
||
);
|
||
};
|
||
|
||
const handleCreatePosi = () => {};
|
||
const handleValChange = ({ val, config, selectOpt }) => {
|
||
state.dialogMoveTreeData = selectOpt;
|
||
};
|
||
const handleTreeAction = ({ type, val }) => {
|
||
state.dialogData = val;
|
||
if (type === "add") {
|
||
state.clickKey = val.key;
|
||
state.treeSelectData = val;
|
||
state.tableConfig.refreshCount++;
|
||
state.dialogAddTreeData = "";
|
||
state.dialogAddTree = true;
|
||
}
|
||
if (type === "move") {
|
||
state.clickKey = val.key;
|
||
state.treeSelectData = val;
|
||
state.tableConfig.refreshCount++;
|
||
state.dialogMoveTreeData = {};
|
||
state.dialogMoveTree = true;
|
||
}
|
||
if (type === "subtraction") {
|
||
state.dialogSubtractionTree = true;
|
||
}
|
||
if (type === "save") {
|
||
let url = "/department/v2/update";
|
||
let params = {
|
||
name: val.title,
|
||
ID: val.key,
|
||
};
|
||
$request.HTTP.components.postDataByParams(url, params).then(
|
||
(res) => {
|
||
if (res.status === 0) {
|
||
getTreeData();
|
||
} else {
|
||
processError(res.msg || "操作失败!");
|
||
}
|
||
},
|
||
() => {
|
||
processError("操作失败!");
|
||
},
|
||
() => {
|
||
processError("操作失败!");
|
||
}
|
||
);
|
||
}
|
||
if (type === "cancel") {
|
||
getTreeData();
|
||
}
|
||
};
|
||
const handleTreeClick = ({ selectedKey, tree }) => {
|
||
state.clickKey = tree.key;
|
||
state.treeSelectData = tree;
|
||
Local.set("orgmanage_treeSelectData", tree);
|
||
state.tableConfig.refreshCount++;
|
||
};
|
||
// const handleTreeDefaultClick = () => {
|
||
// state.treeSelectData = state.treeData[0];
|
||
// state.clickKey = state.treeData[0].key;
|
||
// Local.remove("orgmanage_treeSelectData");
|
||
// state.tableConfig.refreshCount++;
|
||
// };
|
||
const handleCloseModal = () => {
|
||
// emits("triggerCloseModal");
|
||
};
|
||
const handleDialogMoveTreeSave = () => {
|
||
let url = "/department/v2/update";
|
||
let params = {
|
||
ID: state.dialogData.key,
|
||
name: state.dialogData.label,
|
||
pid: state.dialogMoveTreeData.value,
|
||
};
|
||
$request.HTTP.components.postDataByParams(url, params).then(
|
||
(res) => {
|
||
if (res.status === 0) {
|
||
if (Array.isArray(res.data.levelPathList)) {
|
||
state.expandedKeys = [];
|
||
res.data.levelPathList.forEach((treeid) => {
|
||
if (!state.expandedKeys.includes(treeid)) {
|
||
state.expandedKeys.push(treeid);
|
||
}
|
||
});
|
||
}
|
||
getTreeData();
|
||
state.dialogMoveTree = false;
|
||
if (
|
||
(state.dialogMoveTreeData.level || 0) +
|
||
1(state.dialogData.sonMaxDepth || 0) +
|
||
1 >
|
||
8
|
||
) {
|
||
processWarning("组织数已超过8级,建议不要再增加高度");
|
||
} else {
|
||
processSuccess("操作成功!");
|
||
}
|
||
} else {
|
||
processError(res.msg || "操作失败!");
|
||
}
|
||
},
|
||
() => {
|
||
processError("操作失败!");
|
||
state.dialogAddTree = false;
|
||
},
|
||
() => {
|
||
state.dialogAddTree = false;
|
||
processError("操作失败!");
|
||
}
|
||
);
|
||
};
|
||
// 树 新增
|
||
const handleDialogAddTreeSave = () => {
|
||
let url = "/department/v2/create";
|
||
let params = {
|
||
name: state.dialogAddTreeData,
|
||
pid: state.dialogData.key,
|
||
};
|
||
$request.HTTP.components.postDataByParams(url, params).then(
|
||
(res) => {
|
||
if (res.status === 0) {
|
||
if (Array.isArray(res.data.levelPathList)) {
|
||
state.expandedKeys = [];
|
||
res.data.levelPathList.forEach((treeid) => {
|
||
if (!state.expandedKeys.includes(treeid)) {
|
||
state.expandedKeys.push(treeid);
|
||
}
|
||
});
|
||
}
|
||
getTreeData();
|
||
state.dialogAddTree = false;
|
||
if (state.dialogData.level > 7) {
|
||
processWarning("组织数已超过8级,建议不要再增加高度");
|
||
}
|
||
} else {
|
||
processError(res.msg || "操作失败!");
|
||
}
|
||
},
|
||
() => {
|
||
processError("操作失败!");
|
||
state.dialogAddTree = false;
|
||
},
|
||
() => {
|
||
state.dialogAddTree = false;
|
||
processError("操作失败!");
|
||
}
|
||
);
|
||
};
|
||
// 树 减
|
||
const handleDialogSubtractionTreeSave = () => {
|
||
let url = "/department/v2/remove";
|
||
let params = {
|
||
ID: state.dialogData.key,
|
||
};
|
||
$request.HTTP.components.postDataByParams(url, params).then(
|
||
(res) => {
|
||
if (res.status === 0) {
|
||
getTreeData();
|
||
state.dialogSubtractionTree = false;
|
||
} else {
|
||
processError(res.msg || "操作失败!");
|
||
}
|
||
},
|
||
() => {
|
||
processError("操作失败!");
|
||
state.dialogSubtractionTree = false;
|
||
},
|
||
() => {
|
||
state.dialogSubtractionTree = false;
|
||
processError("操作失败!");
|
||
}
|
||
);
|
||
};
|
||
const calcTreeData = (data) => {
|
||
for (let item of data) {
|
||
item.key = item.ID;
|
||
item.label = item.name;
|
||
item.title = item.name;
|
||
if (item.sons) {
|
||
item.children = item.sons;
|
||
calcTreeData(item.children);
|
||
}
|
||
delete item.ID;
|
||
delete item.name;
|
||
delete item.sons;
|
||
}
|
||
};
|
||
const emit = defineEmits(["update:orgVisible", "orgHandleOk"]);
|
||
const closeFn = () => {
|
||
emit("orgHandleOk");
|
||
};
|
||
|
||
watch(
|
||
() => props.orgVisible,
|
||
(val) => {
|
||
let treeSelectData = Local.get("orgmanage_treeSelectData");
|
||
if (treeSelectData) {
|
||
state.treeSelectData = treeSelectData;
|
||
state.clickKey = treeSelectData.key;
|
||
}
|
||
getTreeData();
|
||
}
|
||
);
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.org-dialog {
|
||
text-align: center;
|
||
.naive-modal-body {
|
||
height: 750px !important;
|
||
}
|
||
}
|
||
.item-box {
|
||
height: 50vh;
|
||
overflow: auto;
|
||
text-align: center;
|
||
padding-left: 100px;
|
||
padding-right: 100px;
|
||
}
|
||
.button-box {
|
||
width: 150px;
|
||
background-color: rgba(199, 199, 201, 1);
|
||
color: #fff;
|
||
}
|
||
|
||
.search-item {
|
||
:deep(.ant-input-affix-wrapper) {
|
||
background: #fff;
|
||
color: #c3c3c3;
|
||
}
|
||
:deep(.ant-input) {
|
||
color: #000;
|
||
&::placeholder {
|
||
color: #c3c3c3;
|
||
}
|
||
}
|
||
:deep(.ant-picker-input > input) {
|
||
color: #000;
|
||
&::placeholder {
|
||
color: #c3c3c3;
|
||
}
|
||
}
|
||
:deep(.ant-picker) {
|
||
width: 100%;
|
||
border-radius: 20px;
|
||
background: #fff !important;
|
||
color: #c3c3c3;
|
||
border: none;
|
||
}
|
||
:deep(.ant-picker-input > input) {
|
||
color: #000;
|
||
&::placeholder {
|
||
color: #c3c3c3;
|
||
}
|
||
}
|
||
}
|
||
</style>
|