From a63543a5c793c8954fa2f9da0ee4fb215c62d8c2 Mon Sep 17 00:00:00 2001 From: 疯狂的狮子Li <15040126243@163.com> Date: 星期一, 20 五月 2024 10:26:46 +0800 Subject: [PATCH] !118 ♥️发布 5.2.0-BETA 公测版本 Merge pull request !118 from 疯狂的狮子Li/dev --- src/components/UserSelect/index.vue | 314 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 314 insertions(+), 0 deletions(-) diff --git a/src/components/UserSelect/index.vue b/src/components/UserSelect/index.vue new file mode 100644 index 0000000..f6e552e --- /dev/null +++ b/src/components/UserSelect/index.vue @@ -0,0 +1,314 @@ +<template> + <div> + <el-dialog v-model="userDialog.visible.value" :title="userDialog.title.value" width="80%" append-to-body> + <el-row :gutter="20"> + <!-- 閮ㄩ棬鏍� --> + <el-col :lg="4" :xs="24" style=""> + <el-card shadow="hover"> + <el-input v-model="deptName" placeholder="璇疯緭鍏ラ儴闂ㄥ悕绉�" prefix-icon="Search" clearable /> + <el-tree + ref="deptTreeRef" + class="mt-2" + node-key="id" + :data="deptOptions" + :props="{ label: 'label', children: 'children' }" + :expand-on-click-node="false" + :filter-node-method="filterNode" + highlight-current + default-expand-all + @node-click="handleNodeClick" + /> + </el-card> + </el-col> + <el-col :lg="20" :xs="24"> + <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> + <div v-show="showSearch" class="mb-[10px]"> + <el-card shadow="hover"> + <el-form ref="queryFormRef" :model="queryParams" :inline="true"> + <el-form-item label="鐢ㄦ埛鍚嶇О" prop="userName"> + <el-input v-model="queryParams.userName" placeholder="璇疯緭鍏ョ敤鎴峰悕绉�" clearable @keyup.enter="handleQuery" /> + </el-form-item> + <el-form-item label="鎵嬫満鍙风爜" prop="phonenumber"> + <el-input + v-model="queryParams.phonenumber" + placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�" + clearable + @keyup.enter="handleQuery" + /> + </el-form-item> + <el-form-item> + <el-button type="primary" icon="Search" @click="handleQuery">鎼滅储</el-button> + <el-button icon="Refresh" @click="resetQuery">閲嶇疆</el-button> + </el-form-item> + </el-form> + </el-card> + </div> + </transition> + + <el-card shadow="hover"> + <template v-if="prop.multiple" #header> + <el-tag v-for="user in selectUserList" :key="user.userId" closable style="margin: 2px" @close="handleCloseTag(user)"> + {{ user.userName }} + </el-tag> + </template> + + <vxe-table + ref="tableRef" + height="400px" + border + show-overflow + :data="userList" + :loading="loading" + :row-config="{ keyField: 'userId', isHover: true }" + :checkbox-config="{ reserve: true, trigger: 'row', highlight: true, showHeader: prop.multiple }" + @checkbox-all="handleCheckboxAll" + @checkbox-change="handleCheckboxChange" + > + <vxe-column type="checkbox" width="50" align="center" /> + <vxe-column key="userId" title="鐢ㄦ埛缂栧彿" align="center" field="userId" /> + <vxe-column key="userName" title="鐢ㄦ埛鍚嶇О" align="center" field="userName" /> + <vxe-column key="nickName" title="鐢ㄦ埛鏄电О" align="center" field="nickName" /> + <vxe-column key="deptName" title="閮ㄩ棬" align="center" field="deptName" /> + <vxe-column key="phonenumber" title="鎵嬫満鍙风爜" align="center" field="phonenumber" width="120" /> + <vxe-column key="status" title="鐘舵��" align="center"> + <template #default="scope"> + <dict-tag :options="sys_normal_disable" :value="scope.row.status"></dict-tag> + </template> + </vxe-column> + + <vxe-column title="鍒涘缓鏃堕棿" align="center" width="160"> + <template #default="scope"> + <span>{{ scope.row.createTime }}</span> + </template> + </vxe-column> + </vxe-table> + + <pagination + v-show="total > 0" + v-model:page="queryParams.pageNum" + v-model:limit="queryParams.pageSize" + :total="total" + @pagination="pageList" + /> + </el-card> + </el-col> + </el-row> + + <template #footer> + <el-button @click="close">鍙栨秷</el-button> + <el-button type="primary" @click="confirm">纭畾</el-button> + </template> + </el-dialog> + </div> +</template> + +<script setup lang="ts"> +import api from '@/api/system/user'; +import { UserQuery, UserVO } from '@/api/system/user/types'; +import { DeptVO } from '@/api/system/dept/types'; +import { VxeTableInstance } from 'vxe-table'; +import useDialog from '@/hooks/useDialog'; + +interface PropType { + modelValue?: UserVO[] | UserVO | undefined; + multiple?: boolean; + data?: string | number | (string | number)[]; +} +const prop = withDefaults(defineProps<PropType>(), { + multiple: true, + modelValue: undefined, + data: undefined +}); +const emit = defineEmits(['update:modelValue', 'confirmCallBack']); + +const { proxy } = getCurrentInstance() as ComponentInternalInstance; +const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable')); + +const userList = ref<UserVO[]>(); +const loading = ref(true); +const showSearch = ref(true); +const total = ref(0); +const dateRange = ref<[DateModelType, DateModelType]>(['', '']); +const deptName = ref(''); +const deptOptions = ref<DeptVO[]>([]); +const selectUserList = ref<UserVO[]>([]); + +const deptTreeRef = ref<ElTreeInstance>(); +const queryFormRef = ref<ElFormInstance>(); +const tableRef = ref<VxeTableInstance<UserVO>>(); + +const userDialog = useDialog({ + title: '鐢ㄦ埛閫夋嫨' +}); + +const queryParams = ref<UserQuery>({ + pageNum: 1, + pageSize: 10, + userName: '', + phonenumber: '', + status: '', + deptId: '', + roleId: '' +}); + +const defaultSelectUserIds = computed(() => computedIds(prop.data)); + +/** 鏍规嵁鍚嶇О绛涢�夐儴闂ㄦ爲 */ +watchEffect( + () => { + deptTreeRef.value?.filter(deptName.value); + }, + { + flush: 'post' // watchEffect浼氬湪DOM鎸傝浇鎴栬�呮洿鏂颁箣鍓嶅氨浼氳Е鍙戯紝姝ゅ睘鎬ф帶鍒跺湪DOM鍏冪礌鏇存柊鍚庤繍琛� + } +); + +const confirm = () => { + emit('update:modelValue', selectUserList.value); + emit('confirmCallBack', selectUserList.value); + userDialog.closeDialog(); +}; + +const computedIds = (data) => { + if (data instanceof Array) { + return [...data]; + } else if (typeof data === 'string') { + return data.split(','); + } else if (typeof data === 'number') { + return [data]; + } else { + console.warn('<UserSelect> The data type of data should be array or string or number, but I received other'); + return []; + } +}; + +/** 閫氳繃鏉′欢杩囨护鑺傜偣 */ +const filterNode = (value: string, data: any) => { + if (!value) return true; + return data.label.indexOf(value) !== -1; +}; + +/** 鏌ヨ閮ㄩ棬涓嬫媺鏍戠粨鏋� */ +const getTreeSelect = async () => { + const res = await api.deptTreeSelect(); + deptOptions.value = res.data; +}; + +/** 鏌ヨ鐢ㄦ埛鍒楄〃 */ +const getList = async () => { + loading.value = true; + const res = await api.listUser(proxy?.addDateRange(queryParams.value, dateRange.value)); + loading.value = false; + userList.value = res.rows; + total.value = res.total; +}; + +const pageList = async () => { + await getList(); + const users = userList.value.filter((item) => { + return selectUserList.value.some((user) => user.userId === item.userId); + }); + await tableRef.value.setCheckboxRow(users, true); +}; + +/** 鑺傜偣鍗曞嚮浜嬩欢 */ +const handleNodeClick = (data: DeptVO) => { + queryParams.value.deptId = data.id; + handleQuery(); +}; + +/** 鎼滅储鎸夐挳鎿嶄綔 */ +const handleQuery = () => { + queryParams.value.pageNum = 1; + getList(); +}; +/** 閲嶇疆鎸夐挳鎿嶄綔 */ +const resetQuery = () => { + dateRange.value = ['', '']; + queryFormRef.value?.resetFields(); + queryParams.value.pageNum = 1; + queryParams.value.deptId = undefined; + deptTreeRef.value?.setCurrentKey(undefined); + handleQuery(); +}; + +const handleCheckboxChange = (checked) => { + if (!prop.multiple && checked.checked) { + tableRef.value.setCheckboxRow(selectUserList.value, false); + selectUserList.value = []; + } + const row = checked.row; + if (checked.checked) { + selectUserList.value.push(row); + } else { + selectUserList.value = selectUserList.value.filter((item) => { + return item.userId !== row.userId; + }); + } +}; +const handleCheckboxAll = (checked) => { + const rows = userList.value; + if (checked.checked) { + rows.forEach((row) => { + if (!selectUserList.value.some((item) => item.userId === row.userId)) { + selectUserList.value.push(row); + } + }); + } else { + selectUserList.value = selectUserList.value.filter((item) => { + return !rows.some((row) => row.userId === item.userId); + }); + } +}; + +const handleCloseTag = (user: UserVO) => { + const userId = user.userId; + // 浣跨敤split鍒犻櫎鐢ㄦ埛 + const index = selectUserList.value.findIndex((item) => item.userId === userId); + const rows = selectUserList.value[index]; + tableRef.value?.setCheckboxRow(rows, false); + selectUserList.value.splice(index, 1); +}; + +const initSelectUser = async () => { + if (defaultSelectUserIds.value.length > 0) { + const { data } = await api.optionSelect(defaultSelectUserIds.value); + selectUserList.value = data; + const users = userList.value.filter((item) => { + return defaultSelectUserIds.value.includes(String(item.userId)); + }); + await nextTick(() => { + tableRef.value.setCheckboxRow(users, true); + }); + } +}; +const close = () => { + userDialog.closeDialog(); +}; + +watch( + () => userDialog.visible.value, + (newValue: boolean) => { + if (newValue) { + initSelectUser(); + } else { + tableRef.value.clearCheckboxReserve(); + tableRef.value.clearCheckboxRow(); + resetQuery(); + selectUserList.value = []; + } + } +); + +onMounted(() => { + getTreeSelect(); // 鍒濆鍖栭儴闂ㄦ暟鎹� + getList(); // 鍒濆鍖栧垪琛ㄦ暟鎹� +}); + +defineExpose({ + open: userDialog.openDialog, + close: userDialog.closeDialog +}); +</script> + +<style lang="scss" scoped></style> -- Gitblit v1.9.3