From 63ba90cc10779b34648e91019b2fb408a9fc4c2e Mon Sep 17 00:00:00 2001 From: LiuHao <liuhaoai545@gmail.com> Date: 星期五, 26 一月 2024 09:59:23 +0800 Subject: [PATCH] add 增加全局用户选择组件 --- src/components/UserSelect/index.vue | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 261 insertions(+), 0 deletions(-) diff --git a/src/components/UserSelect/index.vue b/src/components/UserSelect/index.vue new file mode 100644 index 0000000..6a68f92 --- /dev/null +++ b/src/components/UserSelect/index.vue @@ -0,0 +1,261 @@ +<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" label-width="68px"> + <el-form-item label="鐢ㄦ埛鍚嶇О" prop="userName"> + <el-input v-model="queryParams.userName" placeholder="璇疯緭鍏ョ敤鎴峰悕绉�" clearable style="width: 200px" @keyup.enter="handleQuery" /> + </el-form-item> + <el-form-item label="鎵嬫満鍙风爜" prop="phonenumber"> + <el-input + v-model="queryParams.phonenumber" + placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�" + clearable + style="width: 200px" + @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 #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' }" + :checkbox-config="{ reserve: true, checkRowKeys: userIds }" + highlight-current-row + @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="getList" + /> + </el-card> + </el-col> + </el-row> + + <template #footer> + <el-button @click="userDialog.closeDialog">鍙栨秷</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[]; +} +const prop = withDefaults(defineProps<PropType>(), { + modelValue: () => [] +}); +const emit = defineEmits(['update:modelValue']); + +const { proxy } = getCurrentInstance() as ComponentInternalInstance; +const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable')); + +const userIds = computed(() => prop.modelValue.map((item) => item.userId as string)); + +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 filterNode = (value: string, data: any) => { + if (!value) return true; + return data.label.indexOf(value) !== -1; +}; +/** 鏍规嵁鍚嶇О绛涢�夐儴闂ㄦ爲 */ +watchEffect( + () => { + deptTreeRef.value?.filter(deptName.value); + }, + { + flush: 'post' // watchEffect浼氬湪DOM鎸傝浇鎴栬�呮洿鏂颁箣鍓嶅氨浼氳Е鍙戯紝姝ゅ睘鎬ф帶鍒跺湪DOM鍏冪礌鏇存柊鍚庤繍琛� + } +); + +const confirm = () => { + emit('update:modelValue', [...selectUserList.value]); + userDialog.closeDialog(); +}; + +/** 鏌ヨ閮ㄩ棬涓嬫媺鏍戠粨鏋� */ +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 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) => { + 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; + const index = selectUserList.value.findIndex((item) => item.userId === userId); + const rows = selectUserList.value[index]; + tableRef.value?.setCheckboxRow(rows, false); + selectUserList.value.splice(index, 1); +}; +watch( + () => prop.modelValue, + (newVal, oldValue) => { + Object.assign(selectUserList.value, newVal); + }, + { deep: true } +); + +onMounted(() => { + getTreeSelect(); + getList(); +}); + +defineExpose({ + open: userDialog.openDialog, + close: userDialog.closeDialog +}); +</script> + +<style lang="scss" scoped></style> -- Gitblit v1.9.3