Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Hooke
/
vue-flow-editor
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
hookehuyr
2023-11-01 11:32:22 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
a68733b546bac679a9d08935ef96660f2b9e2e6e
a68733b5
1 parent
7982f4f9
拆分用户选择弹框为组件
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
679 additions
and
616 deletions
doc/App.vue
doc/selectUserView.vue
doc/App.vue
View file @
a68733b
...
...
@@ -193,168 +193,11 @@
</vue-flow-editor>
</div>
<el-dialog v-model="state.dialogUserFormVisible" title="成员列表">
<div style="border: 1px dashed #DCDFE6; padding: 10px;">
<el-tag
v-if="state.userTags.length"
v-for="tag in state.userTags"
:key="tag.name"
class=""
style="margin-left: 0.25rem; margin-right: 0.25rem;"
closable
@close="handleTagClose(tag)"
>
{{ tag.name }}
</el-tag>
<div v-else style="text-align: center; color: #DCDFE6;">请选择成员</div>
</div>
<div style="border: 1px solid #DCDFE6; padding: 10px; margin-top: 10px;">
<div style="height: 40px">
<div style="padding: 0; position: relative; margin: 0 0 15px;">
<div v-if="!state.is_active_search">
<div class="flow-tabs__nav-wrap">
<div class="flow-tabs__nav-scroll">
<div class="flow-tabs__nav is-top">
<div
ref_key="barRef"
class="flow-tabs__active-bar"
:style="{
width: state.tabTextWidth,
transform: 'translateX' + '(' + state.tabOffset + ')'
}"
></div>
<div
v-for="(item, index) in state.userTabs"
:key="index"
:class="[
'flow-tabs__item',
'is-top',
item.id === state.activeTabId ? 'is-active' : ''
]"
:id="item.id"
@click="handleTabClick(item, $event, index)"
>
{{ item.label }}
</div>
</div>
</div>
</div>
<div class="flow-tab-search" @click="activeSearchBtn">
<el-icon :size="15"><Search /></el-icon> 搜索框
</div>
</div>
<div v-else>
<el-input
v-model="state.search_input"
class="search-btn-wrapper"
placeholder="请输入关键字"
>
<template #prefix>
<el-icon class="el-input__icon"><search /></el-icon>
</template>
<template #append>
<div class="search-group">
<div class="confirm-btn" @click="onSearch">搜索</div>
<div class="cancel-btn" @click="onClearSearch">取消</div>
</div>
</template>
</el-input>
</div>
</div>
</div>
<!-- 未激活搜索框 -->
<div v-if="!state.is_active_search">
<div v-for="(item, index) in state.userTabs" :key="index">
<div v-if="item.id === state.activeTabId && item.type === 'tree'">
<el-row>
<el-col :span="8">
<el-tree
:data="item.data"
:props="state.defaultProps"
node-key="id"
:default-expanded-keys="state.currentNodeKey"
empty-text="暂无数据"
@node-click="handleNodeClick"
<select-user-view
:visible="state.dialogUserFormVisible"
@close="onCloseUserView"
@confirm="onConfirmUserView"
/>
</el-col>
<el-col :span="16">
<div
style="border-left: 2px solid #e4e7ed; width: 2px; height: 100%; padding-left: 10px;"
>
<el-checkbox-group
class="flow-checkbox-group"
v-model="state.checkedUserList"
>
<el-checkbox
v-for="(user, idx) in state.userList"
:key="idx"
:label="user.id"
:disabled="user.disabled"
@change="handleCheckedUserListChange(user, $event)"
>{{ user.label }}</el-checkbox
>
</el-checkbox-group>
</div>
</el-col>
</el-row>
</div>
<div v-if="item.id === state.activeTabId && item.type === 'list'">
<el-tabs
tab-position="left"
style=""
class="demo-tabs"
v-model="state.activeTabContent"
@tab-click="handleTabContentClick"
>
<el-tab-pane
v-for="(role, idx) in item.data"
:key="idx"
:name="role.label"
:label="role.label"
>
<el-checkbox-group
class="flow-checkbox-group"
v-model="state.checkedUserList"
>
<el-checkbox
v-for="(user, idx) in state.userList"
:key="idx"
:label="user.id"
:disabled="user.disabled"
@change="handleCheckedUserListChange(user, $event)"
>{{ user.label }}</el-checkbox
>
</el-checkbox-group>
</el-tab-pane>
</el-tabs>
</div>
</div>
</div>
<!-- 激活搜索框 -->
<div v-else>
<el-checkbox-group
class="flow-checkbox-group"
style="padding-left: 10px;"
v-model="state.checkedSearchUserList"
>
<el-checkbox
v-for="(user, idx) in state.searchUserList"
:key="idx"
:label="user.id"
:disabled="user.disabled"
@change="handleCheckedUserListChange(user, $event)"
>{{ user.label }}</el-checkbox
>
</el-checkbox-group>
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="closeUserForm">取消</el-button>
<el-button type="primary" @click="confirmUserForm">确定</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts">
...
...
@@ -365,6 +208,7 @@ import { ElNotification } from "element-plus";
import axios from "./axios";
import $ from "jquery";
import { Calendar, Search } from "@element-plus/icons-vue";
import SelectUserView from "./selectUserView.vue";
const G6 = (window as any).G6.default as any;
...
...
@@ -373,6 +217,11 @@ function delay(time) {
}
export default {
components: {
Calendar,
Search,
SelectUserView
},
setup(props, context) {
const state = reactive({
data: AppData,
...
...
@@ -466,55 +315,9 @@ export default {
}
}
],
userTags: [],
currentNodeKey: [], // 当前展开的节点
activeTabId: "tab-1", // TODO: 需要获取默认第一个ID
activeTabContent: "",
userTabs: [],
tabSelectData: [],
userTabType: "tree",
tabOffset: "0px",
tabTextWidth: "76px", // 文字宽度需要打开弹框时重新计算
is_active_search: false,
search_input: "",
userList: [],
checkedUserList: [],
searchUserList: [], // 搜索框 选中 用户ID
checkedSearchUserList: [],
defaultProps: {
children: "children",
label: "label"
}
});
onMounted(() => {
// // 显示提示框的标志位
// var showConfirmation = true;
// // 监听 beforeunload 事件
// window.addEventListener('beforeunload', function (event) {
// if (showConfirmation) {
// // 取消事件的默认行为(弹出确认对话框)
// event.preventDefault();
// // Chrome 和 Firefox 需要返回一个值以显示确认对话框
// event.returnValue = '';
// // 显示自定义的提示信息
// var confirmationMessage = '确定要离开此页面吗?';
// (event || window.event).returnValue = confirmationMessage; // 兼容旧版浏览器
// return confirmationMessage;
// }
// });
// // 监听 unload 事件
// window.addEventListener('unload', function () {
// // 设置标志位为 false,避免在刷新页面时再次显示提示框
// showConfirmation = false;
// });
// axios.get('/srv/?a=query_form_all_field')
// .then(res => {
// console.warn(res.data);
// });
// $('.el-tabs__nav')
// 根据数据获取选中的tag标签
// setTagsList(state.userTabs);
});
function handleActiveChange(name) {
...
...
@@ -538,411 +341,18 @@ export default {
console.warn(val);
};
/****** 用户选择控件弹框 ******/
const openUserForm = () => { // 打开设置用户弹框
state.dialogUserFormVisible = true;
// TODO:查询到的用户列表数据
state.userTags = [
{ id: "user-1-1", name: "用户1-1" },
]
state.userTabs = [
{
id: "tab-1",
label: "组织架构",
type: "tree",
data: [
{
id: "dept-1",
label: "上级部门 1",
children: [
{
id: "dept-1-1",
label: "部门名称 1-1",
children: [],
list: [
{
id: "user-1-1",
label: "用户1-1",
checked: false,
disabled: false
},
{
id: "user-1-2",
label: "用户1-2",
checked: false,
disabled: false
},
{
id: "user-1-3",
label: "用户1-3",
checked: false,
disabled: true
}
]
}
]
},
{
id: "dept-2",
label: "上级部门 2",
children: [
{
id: "dept-2-1",
label: "部门名称 2-1",
children: [],
list: [
{
id: "user-2-1",
label: "用户2-1",
checked: false,
disabled: false
},
{
id: "user-2-2",
label: "用户2-2",
checked: false,
disabled: false
},
{
id: "user-2-3",
label: "用户2-3",
checked: false,
disabled: true
}
]
}
]
}
]
},
{
id: "tab-2",
label: "角色",
type: "list",
data: [
{
id: "role-1-1",
label: "流程发起人",
children: [],
list: [
{
id: "user-1-1",
label: "用户1-1",
checked: true,
disabled: false
},
{
id: "user-2-2",
label: "用户2-2",
checked: false,
disabled: false
},
{
id: "role-1-4",
label: "选项 C",
checked: false,
disabled: true
}
]
},
{
id: "role-1-2",
label: "成员字段",
children: [],
list: []
},
{
id: "role-1-3",
label: "部门字段",
children: [],
list: []
},
{
id: "role-1-4",
label: "主管",
children: [],
list: []
}
]
}
];
// 对比选中的用户的 ID,选中的 ID 同步状态到 userTabs 的数据结构上
state.userTags.forEach(ele => {
modifyFieldValue(state.userTabs, "id", ele.id, true);
});
};
const handleTabClick = (tab, event, idx) => { // 点击Tab切换回调
state.tabSelectData = tab.data; // tab选中数据提供给list类型使用
state.userList = []; // 清空用户列表
state.checkedUserList = []; // 清空选中用户列表
state.activeTabContent = ""; // 清空侧边栏显示
state.currentNodeKey = []; // 清空树形的默认展开
// console.log(tab, event);
// 设置当前激活的tab
state.userTabType = tab.type;
state.activeTabId = tab.id;
// 子容器相对于父容器的相对x轴位移, 第一项为0
if (idx) {
state.tabOffset = $("#" + tab.id).position().left + 20 + "px";
} else {
state.tabOffset = "0px";
}
// 文字宽度
state.tabTextWidth = $("#" + tab.id).width() + "px";
// 检查列表第一项是否有值
// if (tab?.data[0]?.list) {
// let list = tab.data[0].list;
// state.userList = list;
// state.checkedUserList = list
// .filter(ele => {
// return ele.checked;
// })
// .map(ele => {
// return ele.id;
// });
// }
};
const handleTabContentClick = (tab, event) => { // 侧边栏Tab点击回调
// console.log(state.activeTabContent);
// console.log(tab);
// console.log(event);
state.tabSelectData.forEach(ele => {
if (ele.label === tab.props.label) {
state.userList = ele.list;
state.checkedUserList = ele.list
.filter(ele => {
return ele.checked;
})
.map(ele => {
return ele.id;
});
}
});
};
const handleNodeClick = data => { // 树形结构点击回调
// console.log(data);
if (data.list) {
state.userList = data.list;
state.checkedUserList = data.list
.filter(ele => {
return ele.checked;
})
.map(ele => {
return ele.id;
});
// console.warn(state.checkedUserList);
state.currentNodeKey = [data.id];
}
};
/**
* 递归查找匹配字段,并修改字段为新值
*
* @param {object} obj - 修改对象
* @param {string} fieldName - 修改字段
* @param {any} targetValue - 匹配值
* @param {any} newValue - 修改新值
*/
function modifyFieldValue(obj, fieldName, targetValue, newValue) {
// 检查当前层级的字段值是否匹配目标值
if (obj[fieldName] === targetValue) {
obj["checked"] = newValue;
}
// 遍历当前层级的子项(如果有)
for (var key in obj) {
if (typeof obj[key] === "object" && obj[key] !== null) {
modifyFieldValue(obj[key], fieldName, targetValue, newValue);
}
}
}
const handleCheckedUserListChange = (user, checked) => { // 勾选用户回调
// 修改选中值状态
modifyFieldValue(state.userTabs, "id", user.id, checked);
};
/**
* 递归获取树形结构下的所有list字段数据
*
* @param {Array} arr - The array to traverse.
* @return {Array} - The list items found.
*/
function getAllListItems(arr) {
var result = [];
function recursiveGetListItems(subArr) {
for (var i = 0; i < subArr.length; i++) {
var item = subArr[i];
if (item.list && Array.isArray(item.list)) {
result = result.concat(item.list);
}
if (item.children && Array.isArray(item.children)) {
recursiveGetListItems(item.children);
}
}
}
recursiveGetListItems(arr);
return result;
}
/**
* 根据 userTabs 的选中状态,更新 tag 选中列表显示
* 获取生成 list 集合的 checked 状态,生成 tags 的勾选显示
*
* @param {Array} val - userTabs
*/
const setTagsList = (val) => {
let userList = []; // 存储所有的list数据
val.forEach(ele => {
let data = getAllListItems(ele.data);
userList.push(data);
});
// 合并成一维数组列表
userList = [...userList.flat()];
// 如果ID相同,需要数据去重
let uniqueArray = userList.filter(
(value, index, self) =>
index === self.findIndex(obj => obj.id === value.id)
);
// 勾选变化后同步到选中列表
state.userTags = uniqueArray
.filter(ele => {
return ele.checked;
})
.map(ele => {
return {
id: ele.id,
name: ele.label
};
});
};
watch( // TAG: watch state.userTabs 监听数据结构选中值变化
() => state.userTabs,
val => {
if (val) {
// 更新 tags 选中列表显示
setTagsList(val);
}
},
{ deep: true }
);
const handleTagClose = (tag) => { // 移除 tags 成员标签回调
state.userTags.splice(state.userTags.indexOf(tag), 1); // 删除标签列表中的项
// 移除数据结构中的选中值
modifyFieldValue(state.userTabs, "id", tag.id, false);
//
let tagsId = state.userTags.map(ele => {
return ele.id;
});
// 处理tags列表和下面选中列表同步问题
let checkDataList = [];
if (state.is_active_search) { // 激活搜索状态
checkDataList = state.checkedSearchUserList;
} else { // 激活非搜索状态
checkDataList = state.checkedUserList;
}
// 获取 tags 中已删除的, 勾选列表中还勾选的值
let result = checkDataList.filter(
value => !tagsId.includes(value)
);
// 如果存在不同步的值,需要在列表中删除勾选列表中的项
if (result.length) {
result.forEach(ele => {
checkDataList.splice(
checkDataList.indexOf(ele),
1
);
});
}
};
const closeUserForm = () => { // 关闭用户列表表单回调
state.dialogUserFormVisible = false;
};
const confirmUserForm = () => { // 确认用户列表表单回调
state.dialogUserFormVisible = false;
console.log(state.userTags);
};
const activeSearchBtn = () => { // 激活搜索按钮操作
state.is_active_search = !state.is_active_search;
state.searchUserList = []; // 清空搜索列表
};
const checkSearchStatus = () => { // 在搜索框中同步显示tag框选中的用户
state.userTags.forEach(ele => {
state.searchUserList.forEach(item => {
if (ele.id === item.id) {
item.checked = true;
}
});
});
// 显示选中tags的用户
state.checkedSearchUserList = state.searchUserList
.filter(ele => ele.checked)
.map(ele => ele.id);
};
const checkUserStatus = () => { // 在搜索框中同步显示tag框选中的用户
state.userTags.forEach(ele => {
state.userList.forEach(item => {
if (ele.id === item.id) {
item.checked = true;
}
});
});
// 显示选中tags的用户
state.checkedUserList = state.userList
.filter(ele => ele.checked)
.map(ele => ele.id);
};
const onClearSearch = () => { // 清空搜索回调
state.is_active_search = !state.is_active_search;
// 同步显示tag框选中的用户
checkUserStatus();
};
const onSearch = () => { // 搜索回调
// TODO: 获取后台数据
state.searchUserList = [
{
id: "user-1-1",
label: "用户1-1",
checked: false,
disabled: false
},
{
id: "user-1-2",
label: "用户1-2",
checked: false,
disabled: false
},
{
id: "user-1-3",
label: "用户1-3",
checked: false,
disabled: true
}
];
// 如果 tags 里存在的值,需要在搜索列表中勾选
checkSearchStatus();
};
watch( // TAG: watch state.dialogUserFormVisible 监听弹框显示,修改tab文字宽度
() => state.dialogUserFormVisible,
val => {
if (val) {
nextTick(() => {
state.tabTextWidth = $("#" + state.activeTabId).width() + "px";
});
const onCloseUserView = (status) => {
state.dialogUserFormVisible = status;
}
const onConfirmUserView = (data) => {
console.log(data);
}
);
/******************* END *******************/
/********** 流程图功能函数 **********/
...
...
@@ -1119,20 +529,14 @@ export default {
handleAfterDelete,
handleBeforeAdd,
handleAfterAdd,
handleActiveChange,
onAuthAllChange,
onAuthAllEditChange,
handleTabClick,
handleTabContentClick,
handleNodeClick,
handleTagClose,
closeUserForm,
confirmUserForm,
handleCheckedUserListChange,
onSearch,
onClearSearch,
activeSearchBtn,
openUserForm,
onCloseUserView,
onConfirmUserView,
logData,
...
...
doc/selectUserView.vue
0 → 100644
View file @
a68733b
<!--
* @Date: 2023-11-01 10:18:53
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2023-11-01 11:28:37
* @FilePath: /vue-flow-editor/doc/selectUserView.vue
* @Description: 文件描述
-->
<template>
<el-dialog v-model="dialogUserFormVisible" title="成员列表">
<div style="border: 1px dashed #DCDFE6; padding: 10px;">
<el-tag
v-if="userTags.length"
v-for="tag in userTags"
:key="tag.name"
class=""
style="margin-left: 0.25rem; margin-right: 0.25rem;"
closable
@close="handleTagClose(tag)"
>
{{ tag.name }}
</el-tag>
<div v-else style="text-align: center; color: #DCDFE6;">请选择成员</div>
</div>
<div style="border: 1px solid #DCDFE6; padding: 10px; margin-top: 10px;">
<div style="height: 40px">
<div style="padding: 0; position: relative; margin: 0 0 15px;">
<div v-if="!is_active_search">
<div class="flow-tabs__nav-wrap">
<div class="flow-tabs__nav-scroll">
<div class="flow-tabs__nav is-top">
<div
ref_key="barRef"
class="flow-tabs__active-bar"
:style="{
width: tabTextWidth,
transform: 'translateX' + '(' + tabOffset + ')'
}"
></div>
<div
v-for="(item, index) in userTabs"
:key="index"
:class="[
'flow-tabs__item',
'is-top',
item.id === activeTabId ? 'is-active' : ''
]"
:id="item.id"
@click="handleTabClick(item, $event, index)"
>
{{ item.label }}
</div>
</div>
</div>
</div>
<div class="flow-tab-search" @click="activeSearchBtn">
<el-icon :size="15"><Search /></el-icon> 搜索框
</div>
</div>
<div v-else>
<el-input
v-model="search_input"
class="search-btn-wrapper"
placeholder="请输入关键字"
>
<template #prefix>
<el-icon class="el-input__icon"><search /></el-icon>
</template>
<template #append>
<div class="search-group">
<div class="confirm-btn" @click="onSearch">搜索</div>
<div class="cancel-btn" @click="onClearSearch">取消</div>
</div>
</template>
</el-input>
</div>
</div>
</div>
<!-- 未激活搜索框 -->
<div v-if="!is_active_search">
<div v-for="(item, index) in userTabs" :key="index">
<div v-if="item.id === activeTabId && item.type === 'tree'">
<el-row>
<el-col :span="8">
<el-tree
:data="item.data"
:props="defaultProps"
node-key="id"
:default-expanded-keys="currentNodeKey"
empty-text="暂无数据"
@node-click="handleNodeClick"
/>
</el-col>
<el-col :span="16">
<div
style="border-left: 2px solid #e4e7ed; width: 2px; height: 100%; padding-left: 10px;"
>
<el-checkbox-group
class="flow-checkbox-group"
v-model="checkedUserList"
>
<el-checkbox
v-for="(user, idx) in userList"
:key="idx"
:label="user.id"
:disabled="user.disabled"
@change="handleCheckedUserListChange(user, $event)"
>{{ user.label }}</el-checkbox
>
</el-checkbox-group>
</div>
</el-col>
</el-row>
</div>
<div v-if="item.id === activeTabId && item.type === 'list'">
<el-tabs
tab-position="left"
style=""
class="demo-tabs"
v-model="activeTabContent"
@tab-click="handleTabContentClick"
>
<el-tab-pane
v-for="(role, idx) in item.data"
:key="idx"
:name="role.label"
:label="role.label"
>
<el-checkbox-group
class="flow-checkbox-group"
v-model="checkedUserList"
>
<el-checkbox
v-for="(user, idx) in userList"
:key="idx"
:label="user.id"
:disabled="user.disabled"
@change="handleCheckedUserListChange(user, $event)"
>{{ user.label }}</el-checkbox
>
</el-checkbox-group>
</el-tab-pane>
</el-tabs>
</div>
</div>
</div>
<!-- 激活搜索框 -->
<div v-else>
<el-checkbox-group
class="flow-checkbox-group"
style="padding-left: 10px;"
v-model="checkedSearchUserList"
>
<el-checkbox
v-for="(user, idx) in searchUserList"
:key="idx"
:label="user.id"
:disabled="user.disabled"
@change="handleCheckedUserListChange(user, $event)"
>{{ user.label }}</el-checkbox
>
</el-checkbox-group>
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="closeUserForm">取消</el-button>
<el-button type="primary" @click="confirmUserForm">确定</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup>
import { ref, onMounted, watch, nextTick } from "vue";
import { useRoute, useRouter } from "vue-router";
import axios from "./axios";
import $ from "jquery";
const props = defineProps({
visible: Boolean
});
const emit = defineEmits(["close", "confirm"]);
const dialogUserFormVisible = ref(false);
const userTags = ref([]);
const currentNodeKey = ref([]); // 当前展开的节点
const activeTabId = ref("tab-1"); // TODO: 需要获取默认第一个ID
const activeTabContent = ref("");
const userTabs = ref([]);
const tabSelectData = ref([]);
const userTabType = ref("tree");
const tabOffset = ref("0px");
const tabTextWidth = ref("76px"); // 文字宽度需要打开弹框时重新计算
const is_active_search = ref(false);
const search_input = ref("");
const userList = ref([]);
const checkedUserList = ref([]);
const searchUserList = ref([]); // 搜索框 选中 用户ID
const checkedSearchUserList = ref([]);
const defaultProps = ref({
children: "children",
label: "label"
});
onMounted(() => {
// console.log(props.visible);
// // 显示提示框的标志位
// var showConfirmation = true;
// // 监听 beforeunload 事件
// window.addEventListener('beforeunload', function (event) {
// if (showConfirmation) {
// // 取消事件的默认行为(弹出确认对话框)
// event.preventDefault();
// // Chrome 和 Firefox 需要返回一个值以显示确认对话框
// event.returnValue = '';
// // 显示自定义的提示信息
// var confirmationMessage = '确定要离开此页面吗?';
// (event || window.event).returnValue = confirmationMessage; // 兼容旧版浏览器
// return confirmationMessage;
// }
// });
// // 监听 unload 事件
// window.addEventListener('unload', function () {
// // 设置标志位为 false,避免在刷新页面时再次显示提示框
// showConfirmation = false;
// });
// axios.get('/srv/?a=query_form_all_field')
// .then(res => {
// console.warn(res.data);
// });
// $('.el-tabs__nav')
// 根据数据获取选中的tag标签
// setTagsList(userTabs);
// TODO:查询到的用户列表数据
userTags.value = [{ id: "user-1-1", name: "用户1-1" }];
userTabs.value = [
{
id: "tab-1",
label: "组织架构",
type: "tree",
data: [
{
id: "dept-1",
label: "上级部门 1",
children: [
{
id: "dept-1-1",
label: "部门名称 1-1",
children: [],
list: [
{
id: "user-1-1",
label: "用户1-1",
checked: false,
disabled: false
},
{
id: "user-1-2",
label: "用户1-2",
checked: false,
disabled: false
},
{
id: "user-1-3",
label: "用户1-3",
checked: false,
disabled: true
}
]
}
]
},
{
id: "dept-2",
label: "上级部门 2",
children: [
{
id: "dept-2-1",
label: "部门名称 2-1",
children: [],
list: [
{
id: "user-2-1",
label: "用户2-1",
checked: false,
disabled: false
},
{
id: "user-2-2",
label: "用户2-2",
checked: false,
disabled: false
},
{
id: "user-2-3",
label: "用户2-3",
checked: false,
disabled: true
}
]
}
]
}
]
},
{
id: "tab-2",
label: "角色",
type: "list",
data: [
{
id: "role-1-1",
label: "流程发起人",
children: [],
list: [
{
id: "user-1-1",
label: "用户1-1",
checked: true,
disabled: false
},
{
id: "user-2-2",
label: "用户2-2",
checked: false,
disabled: false
},
{
id: "role-1-4",
label: "选项 C",
checked: false,
disabled: true
}
]
},
{
id: "role-1-2",
label: "成员字段",
children: [],
list: []
},
{
id: "role-1-3",
label: "部门字段",
children: [],
list: []
},
{
id: "role-1-4",
label: "主管",
children: [],
list: []
}
]
}
];
// 对比选中的用户的 ID,选中的 ID 同步状态到 userTabs 的数据结构上
userTags.value.forEach(ele => {
modifyFieldValue(userTabs.value, "id", ele.id, true);
});
});
watch(() => {
//
if (props.visible) {
dialogUserFormVisible.value = true;
} else {
dialogUserFormVisible.value = false;
}
});
const handleTabClick = (tab, event, idx) => {
// 点击Tab切换回调
tabSelectData.value = tab.data; // tab选中数据提供给list类型使用
userList.value = []; // 清空用户列表
checkedUserList.value = []; // 清空选中用户列表
activeTabContent.value = ""; // 清空侧边栏显示
currentNodeKey.value = []; // 清空树形的默认展开
// console.log(tab, event);
// 设置当前激活的tab
userTabType.value = tab.type;
activeTabId.value = tab.id;
// 子容器相对于父容器的相对x轴位移, 第一项为0
if (idx) {
tabOffset.value = $("#" + tab.id).position().left + 20 + "px";
} else {
tabOffset.value = "0px";
}
// 文字宽度
tabTextWidth.value = $("#" + tab.id).width() + "px";
// 检查列表第一项是否有值
// if (tab?.data[0]?.list) {
// let list = tab.data[0].list;
// userList.value = list;
// checkedUserList.value = list
// .filter(ele => {
// return ele.checked;
// })
// .map(ele => {
// return ele.id;
// });
// }
};
const handleTabContentClick = (tab, event) => {
// 侧边栏Tab点击回调
// console.log(activeTabContent.value);
// console.log(tab);
// console.log(event);
tabSelectData.value.forEach(ele => {
if (ele.label === tab.props.label) {
userList.value = ele.list;
checkedUserList.value = ele.list
.filter(ele => {
return ele.checked;
})
.map(ele => {
return ele.id;
});
}
});
};
const handleNodeClick = data => {
// 树形结构点击回调
// console.log(data);
if (data.list) {
userList.value = data.list;
checkedUserList.value = data.list
.filter(ele => {
return ele.checked;
})
.map(ele => {
return ele.id;
});
// console.warn(checkedUserList.value);
currentNodeKey.value = [data.id];
}
};
/**
* 递归查找匹配字段,并修改字段为新值
*
* @param {object} obj - 修改对象
* @param {string} fieldName - 修改字段
* @param {any} targetValue - 匹配值
* @param {any} newValue - 修改新值
*/
function modifyFieldValue(obj, fieldName, targetValue, newValue) {
// 检查当前层级的字段值是否匹配目标值
if (obj[fieldName] === targetValue) {
obj["checked"] = newValue;
}
// 遍历当前层级的子项(如果有)
for (var key in obj) {
if (typeof obj[key] === "object" && obj[key] !== null) {
modifyFieldValue(obj[key], fieldName, targetValue, newValue);
}
}
}
const handleCheckedUserListChange = (user, checked) => {
// 勾选用户回调
// 修改选中值状态
modifyFieldValue(userTabs.value, "id", user.id, checked);
};
/**
* 递归获取树形结构下的所有list字段数据
*
* @param {Array} arr - The array to traverse.
* @return {Array} - The list items found.
*/
function getAllListItems(arr) {
var result = [];
function recursiveGetListItems(subArr) {
for (var i = 0; i < subArr.length; i++) {
var item = subArr[i];
if (item.list && Array.isArray(item.list)) {
result = result.concat(item.list);
}
if (item.children && Array.isArray(item.children)) {
recursiveGetListItems(item.children);
}
}
}
recursiveGetListItems(arr);
return result;
}
/**
* 根据 userTabs 的选中状态,更新 tag 选中列表显示
* 获取生成 list 集合的 checked 状态,生成 tags 的勾选显示
*
* @param {Array} val - userTabs
*/
const setTagsList = val => {
let userList = []; // 存储所有的list数据
val.forEach(ele => {
let data = getAllListItems(ele.data);
userList.push(data);
});
// 合并成一维数组列表
userList = [...userList.flat()];
// 如果ID相同,需要数据去重
let uniqueArray = userList.filter(
(value, index, self) => index === self.findIndex(obj => obj.id === value.id)
);
// 勾选变化后同步到选中列表
userTags.value = uniqueArray
.filter(ele => {
return ele.checked;
})
.map(ele => {
return {
id: ele.id,
name: ele.label
};
});
};
watch(
// TAG: watch userTabs.value 监听数据结构选中值变化
() => userTabs.value,
val => {
if (val) {
// 更新 tags 选中列表显示
setTagsList(val);
}
},
{ deep: true }
);
const handleTagClose = tag => {
// 移除 tags 成员标签回调
userTags.value.splice(userTags.value.indexOf(tag), 1); // 删除标签列表中的项
// 移除数据结构中的选中值
modifyFieldValue(userTabs.value, "id", tag.id, false);
//
let tagsId = userTags.value.map(ele => {
return ele.id;
});
// 处理tags列表和下面选中列表同步问题
let checkDataList = [];
if (is_active_search.value) {
// 激活搜索状态
checkDataList = checkedSearchUserList.value;
} else {
// 激活非搜索状态
checkDataList = checkedUserList.value;
}
// 获取 tags 中已删除的, 勾选列表中还勾选的值
let result = checkDataList.filter(value => !tagsId.includes(value));
// 如果存在不同步的值,需要在列表中删除勾选列表中的项
if (result.length) {
result.forEach(ele => {
checkDataList.splice(checkDataList.indexOf(ele), 1);
});
}
};
const closeUserForm = () => {
// 关闭用户列表表单回调
dialogUserFormVisible.value = false;
emit("close", dialogUserFormVisible.value);
};
const confirmUserForm = () => {
// 确认用户列表表单回调
dialogUserFormVisible.value = false;
// console.log(userTags.value);
emit("close", dialogUserFormVisible.value);
emit("confirm", userTags.value);
};
const activeSearchBtn = () => {
// 激活搜索按钮操作
is_active_search.value = !is_active_search.value;
searchUserList.value = []; // 清空搜索列表
};
const checkSearchStatus = () => {
// 在搜索框中同步显示tag框选中的用户
userTags.value.forEach(ele => {
searchUserList.value.forEach(item => {
if (ele.id === item.id) {
item.checked = true;
}
});
});
// 显示选中tags的用户
checkedSearchUserList.value = searchUserList.value
.filter(ele => ele.checked)
.map(ele => ele.id);
};
const checkUserStatus = () => {
// 在搜索框中同步显示tag框选中的用户
userTags.value.forEach(ele => {
userList.value.forEach(item => {
if (ele.id === item.id) {
item.checked = true;
}
});
});
// 显示选中tags的用户
checkedUserList.value = userList.value
.filter(ele => ele.checked)
.map(ele => ele.id);
};
const onClearSearch = () => {
// 清空搜索回调
is_active_search.value = !is_active_search.value;
// 同步显示tag框选中的用户
checkUserStatus();
};
const onSearch = () => {
// 搜索回调
// TODO: 获取后台数据
searchUserList.value = [
{
id: "user-1-1",
label: "用户1-1",
checked: false,
disabled: false
},
{
id: "user-1-2",
label: "用户1-2",
checked: false,
disabled: false
},
{
id: "user-1-3",
label: "用户1-3",
checked: false,
disabled: true
}
];
// 如果 tags 里存在的值,需要在搜索列表中勾选
checkSearchStatus();
};
watch(
// TAG: watch dialogUserFormVisible.value 监听弹框显示,修改tab文字宽度
() => dialogUserFormVisible.value,
val => {
if (val) {
nextTick(() => {
tabTextWidth.value = $("#" + activeTabId.value).width() + "px";
});
}
}
);
</script>
<style lang="less" scoped></style>
Please
register
or
login
to post a comment