mirror of
https://github.com/continew-org/continew-admin-ui.git
synced 2025-09-09 20:57:17 +08:00
refactor: 重构用户选择器组件
This commit is contained in:
@@ -1,269 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="container">
|
|
||||||
<a-row :gutter="16">
|
|
||||||
<a-col :span="24" :md="18" class="section">
|
|
||||||
<GiTable
|
|
||||||
v-model:selectedKeys="selectedKeys"
|
|
||||||
row-key="id"
|
|
||||||
:data="dataList"
|
|
||||||
:columns="tableColumns"
|
|
||||||
:loading="loading"
|
|
||||||
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
|
|
||||||
style="max-height: 600px"
|
|
||||||
:pagination="pagination"
|
|
||||||
:disabled-tools="['size', 'fullscreen', 'setting', 'refresh']"
|
|
||||||
:row-selection="{ type: props.multiple ? 'checkbox' : 'radio', showCheckedAll: true }"
|
|
||||||
@select="onRowSelect"
|
|
||||||
@select-all="onTableSelectAll"
|
|
||||||
@refresh="search"
|
|
||||||
>
|
|
||||||
<template #top>
|
|
||||||
<div>
|
|
||||||
<a-space class="mt-5">
|
|
||||||
<a-input v-model="queryForm.description" placeholder="用户名/昵称/描述" allow-clear @change="search" />
|
|
||||||
<a-tree-select
|
|
||||||
v-model="queryForm.deptId"
|
|
||||||
:data="deptList"
|
|
||||||
placeholder="请选择所属部门"
|
|
||||||
allow-clear
|
|
||||||
allow-search
|
|
||||||
:filter-tree-node="filterDeptOptions"
|
|
||||||
@change="search"
|
|
||||||
/>
|
|
||||||
<a-button @click="reset">
|
|
||||||
<template #icon>
|
|
||||||
<icon-refresh />
|
|
||||||
</template>
|
|
||||||
<template #default>重置</template>
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</div>
|
|
||||||
<a-alert class="mt-5">
|
|
||||||
<template v-if="selectedKeys.length > 0">
|
|
||||||
已选中{{ selectedKeys.length }}条记录(可跨页)
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
未选中任何用户
|
|
||||||
</template>
|
|
||||||
<template v-if="selectedKeys.length > 0" #action>
|
|
||||||
<a-link @click="onClearSelected">清空</a-link>
|
|
||||||
</template>
|
|
||||||
</a-alert>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #status="{ record }">
|
|
||||||
<GiCellStatus :status="record.status" />
|
|
||||||
</template>
|
|
||||||
<template #gender="{ record }">
|
|
||||||
<GiCellGender :gender="record.gender" />
|
|
||||||
</template>
|
|
||||||
</GiTable>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<a-col :span="24" :md="6" class="section">
|
|
||||||
<a-card title="已选用户">
|
|
||||||
<a-table :columns="rightColumn" :data="selectedData" :pagination="paginationOptions">
|
|
||||||
<template #nickname="{ record }">
|
|
||||||
{{ record.nickname }}({{ record.username }})
|
|
||||||
</template>
|
|
||||||
<template #action="{ record }">
|
|
||||||
<a-button @click="handleDeleteSelectUser(record)">
|
|
||||||
<icon-delete />
|
|
||||||
</a-button>
|
|
||||||
</template>
|
|
||||||
</a-table>
|
|
||||||
</a-card>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import type { TreeNodeData } from '@arco-design/web-vue'
|
|
||||||
import { useDept } from '@/hooks/app'
|
|
||||||
import { type Options, useTable } from '@/hooks'
|
|
||||||
import { type UserQuery, type UserResp, listAllUser, listUser } from '@/apis'
|
|
||||||
import type { UserSelectPropType } from '@/components/UserSelect/type'
|
|
||||||
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
|
||||||
import { isMobile } from '@/utils'
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<UserSelectPropType & { selectedUsers: string | string[] }>(), {
|
|
||||||
multiple: false,
|
|
||||||
selectedUsers: () => [],
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:selectedUsers'])
|
|
||||||
|
|
||||||
// 表格列定义
|
|
||||||
const tableColumns: TableInstanceColumns[] = [
|
|
||||||
{
|
|
||||||
title: '昵称',
|
|
||||||
dataIndex: 'nickname',
|
|
||||||
slotName: 'nickname',
|
|
||||||
minWidth: 140,
|
|
||||||
ellipsis: true,
|
|
||||||
tooltip: true,
|
|
||||||
fixed: !isMobile() ? 'left' : undefined,
|
|
||||||
},
|
|
||||||
{ title: '用户名', dataIndex: 'username', slotName: 'username', minWidth: 140, ellipsis: true, tooltip: true },
|
|
||||||
{ title: '状态', slotName: 'status', align: 'center' },
|
|
||||||
{ title: '性别', dataIndex: 'gender', slotName: 'gender', align: 'center' },
|
|
||||||
{ title: '所属部门', dataIndex: 'deptName', ellipsis: true, tooltip: true, minWidth: 180 },
|
|
||||||
{ title: '角色', dataIndex: 'roleNames', minWidth: 160, slotName: 'roleNames' },
|
|
||||||
{ title: '手机号', dataIndex: 'phone', minWidth: 170, ellipsis: true, tooltip: true },
|
|
||||||
{ title: '邮箱', dataIndex: 'email', minWidth: 170, ellipsis: true, tooltip: true },
|
|
||||||
{ title: '系统内置', slotName: 'isSystem', width: 100, align: 'center', show: false },
|
|
||||||
{ title: '描述', dataIndex: 'description', minWidth: 130, ellipsis: true, tooltip: true },
|
|
||||||
{ title: '创建人', dataIndex: 'createUserString', width: 140, ellipsis: true, tooltip: true, show: false },
|
|
||||||
{ title: '创建时间', dataIndex: 'createTime', width: 180 },
|
|
||||||
{ title: '修改人', dataIndex: 'updateUserString', width: 140, ellipsis: true, tooltip: true, show: false },
|
|
||||||
{ title: '修改时间', dataIndex: 'updateTime', width: 180, show: false },
|
|
||||||
]
|
|
||||||
|
|
||||||
// 右侧已选用户列定义
|
|
||||||
const rightColumn = [
|
|
||||||
{ title: '用户', dataIndex: 'nickname', slotName: 'nickname', minWidth: 140, ellipsis: true, tooltip: true },
|
|
||||||
{ title: '操作', dataIndex: 'action', slotName: 'action' },
|
|
||||||
]
|
|
||||||
|
|
||||||
// 查询表单
|
|
||||||
const queryForm = reactive<UserQuery>({
|
|
||||||
sort: ['t1.createTime,desc'],
|
|
||||||
})
|
|
||||||
// 定义分页器参数
|
|
||||||
const paginationOptions: Options = {
|
|
||||||
defaultPageSize: 10,
|
|
||||||
defaultSizeOptions: [10, 20, 30, 40, 50],
|
|
||||||
}
|
|
||||||
|
|
||||||
// 用户列表
|
|
||||||
const { tableData: dataList, loading, pagination, search } = useTable(
|
|
||||||
(page) => listUser({ ...queryForm, ...page }),
|
|
||||||
{ immediate: false, formatResult: (data) => data.map((i) => ({ ...i, disabled: false })) },
|
|
||||||
)
|
|
||||||
|
|
||||||
// 重置
|
|
||||||
const reset = () => {
|
|
||||||
queryForm.description = undefined
|
|
||||||
queryForm.deptId = undefined
|
|
||||||
search()
|
|
||||||
}
|
|
||||||
|
|
||||||
const treeRef = ref()
|
|
||||||
// 部门列表
|
|
||||||
const { deptList, getDeptList } = useDept({
|
|
||||||
onSuccess: () => {
|
|
||||||
nextTick(() => treeRef.value?.expandAll(true))
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// 过滤部门
|
|
||||||
const filterDeptOptions = (searchKey: string, nodeData: TreeNodeData) => {
|
|
||||||
if (nodeData.title) {
|
|
||||||
return nodeData.title.toLowerCase().includes(searchKey.toLowerCase())
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const allUsers = ref<UserResp[]>() // 用于存储所有用户信息
|
|
||||||
const selectedKeys = ref<string[]>([]) // 使用 Array 来存储选中的 id
|
|
||||||
const selectedData = ref<Set<UserResp>>(new Set()) // 使用 Set 来存储选中的用户对象
|
|
||||||
|
|
||||||
const emitSelectedUsers = () => {
|
|
||||||
emit('update:selectedUsers', selectedKeys.value)
|
|
||||||
}
|
|
||||||
// 行选择事件
|
|
||||||
const onRowSelect = (rowKeys: string[], rowKey: string, record: UserResp) => {
|
|
||||||
if (props.multiple) {
|
|
||||||
// 多选
|
|
||||||
if (rowKeys.includes(rowKey)) {
|
|
||||||
// 包含 选中
|
|
||||||
selectedData.value.add(record)
|
|
||||||
selectedKeys.value?.push(rowKey)
|
|
||||||
} else {
|
|
||||||
// 不包含 去除
|
|
||||||
selectedData.value.delete(record)
|
|
||||||
selectedKeys.value?.splice(selectedKeys.value?.indexOf(rowKey), 1)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 单选
|
|
||||||
selectedData.value.clear()
|
|
||||||
selectedKeys.value = []
|
|
||||||
if (rowKeys.includes(rowKey)) {
|
|
||||||
// 包含 选中
|
|
||||||
selectedData.value.add(record)
|
|
||||||
selectedKeys.value?.push(rowKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
emitSelectedUsers()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 全选事件
|
|
||||||
const onTableSelectAll = (checked: boolean) => {
|
|
||||||
if (checked) {
|
|
||||||
// 选中
|
|
||||||
dataList.value.forEach((item) => {
|
|
||||||
selectedData.value.add(item)
|
|
||||||
selectedKeys.value?.push(item.id)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// 取消选中
|
|
||||||
dataList.value.forEach((item) => {
|
|
||||||
selectedData.value.delete(item)
|
|
||||||
selectedKeys.value?.splice(selectedKeys.value?.indexOf(item.id), 1)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
emitSelectedUsers()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从选中列表中移除用户
|
|
||||||
const handleDeleteSelectUser = (user: UserResp) => {
|
|
||||||
selectedData.value.delete(user)
|
|
||||||
selectedKeys.value?.splice(selectedKeys.value?.indexOf(user.id), 1)
|
|
||||||
emitSelectedUsers()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清空所有选中数据
|
|
||||||
const onClearSelected = () => {
|
|
||||||
selectedData.value.clear()
|
|
||||||
selectedKeys.value = []
|
|
||||||
emitSelectedUsers()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始化函数
|
|
||||||
const init = async (selectUsers: string[]) => {
|
|
||||||
getDeptList()
|
|
||||||
search()
|
|
||||||
// 获取所有用户数据
|
|
||||||
const { data } = await listAllUser({})
|
|
||||||
allUsers.value = data
|
|
||||||
|
|
||||||
// 过滤已选择的用户
|
|
||||||
if (selectUsers && selectUsers.length > 0) {
|
|
||||||
if (props.multiple) {
|
|
||||||
selectedData.value = new Set(allUsers.value.filter((item) => selectUsers.includes(item.id)))
|
|
||||||
selectedKeys.value = Array.from(selectedData.value).map((user) => user.id)
|
|
||||||
} else {
|
|
||||||
selectedData.value = new Set(allUsers.value.filter((item) => selectUsers[0] === item.id))
|
|
||||||
selectedKeys.value = Array.from(selectedData.value).map((user) => user.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
defineExpose({ init, onClearSelected })
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.container {
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mt-5 {
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
</style>
|
|
@@ -1,98 +1,257 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="container">
|
||||||
<div style="display: flex;">
|
<a-row :gutter="16">
|
||||||
<a-select
|
<a-col :span="24" :md="18">
|
||||||
v-model="selectedUsers"
|
<GiTable
|
||||||
:options="userList"
|
v-model:selectedKeys="selectedKeys"
|
||||||
:max-tag-count="4"
|
row-key="id"
|
||||||
:multiple="props.multiple"
|
:data="dataList"
|
||||||
:allow-clear="true"
|
:columns="listColumns"
|
||||||
@change="handleSelectChange"
|
:loading="loading"
|
||||||
/>
|
:scroll="{ x: '100%', y: '100%', minWidth: 900 }"
|
||||||
<a-tooltip content="选择用户">
|
style="max-height: 600px"
|
||||||
<a-button @click="onOpen">
|
:pagination="pagination"
|
||||||
<template #icon>
|
:disabled-tools="['size', 'fullscreen', 'setting', 'refresh']"
|
||||||
<icon-plus />
|
:row-selection="{ type: props.multiple ? 'checkbox' : 'radio', showCheckedAll: true }"
|
||||||
|
@select="onSelect"
|
||||||
|
@select-all="onSelectAll"
|
||||||
|
@refresh="search"
|
||||||
|
>
|
||||||
|
<template #top>
|
||||||
|
<a-space wrap :size="[8, 8]">
|
||||||
|
<a-input v-model="queryForm.description" placeholder="用户名/昵称/描述" allow-clear @change="search" />
|
||||||
|
<a-tree-select
|
||||||
|
v-model="queryForm.deptId"
|
||||||
|
:data="deptList"
|
||||||
|
placeholder="请选择所属部门"
|
||||||
|
allow-clear
|
||||||
|
allow-search
|
||||||
|
:filter-tree-node="filterDeptOptions"
|
||||||
|
@change="search"
|
||||||
|
/>
|
||||||
|
<a-button @click="reset">
|
||||||
|
<template #icon>
|
||||||
|
<icon-refresh />
|
||||||
|
</template>
|
||||||
|
<template #default>重置</template>
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
<a-alert>
|
||||||
|
<template v-if="selectedKeys.length > 0">
|
||||||
|
已选中 {{ selectedKeys.length }} 条记录(可跨页)
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
未选中任何记录
|
||||||
|
</template>
|
||||||
|
<template v-if="selectedKeys.length > 0" #action>
|
||||||
|
<a-link @click="onClearSelected">清空</a-link>
|
||||||
|
</template>
|
||||||
|
</a-alert>
|
||||||
</template>
|
</template>
|
||||||
</a-button>
|
|
||||||
</a-tooltip>
|
<template #gender="{ record }">
|
||||||
</div>
|
<GiCellGender :gender="record.gender" />
|
||||||
<a-modal
|
</template>
|
||||||
v-model:visible="visible"
|
<template #status="{ record }">
|
||||||
title="用户选择"
|
<GiCellStatus :status="record.status" />
|
||||||
:width="width >= 1350 ? 1350 : '100%'"
|
</template>
|
||||||
:esc-to-close="true"
|
</GiTable>
|
||||||
@ok="handleModalOk"
|
</a-col>
|
||||||
>
|
<a-col :span="24" :md="6" class="section">
|
||||||
<UserSelectContent
|
<a-card>
|
||||||
ref="userSelectContentRef"
|
<template #title>已选择: {{ selectedKeys.length }}</template>
|
||||||
:value="selectedUsers"
|
<a-table :columns="selectedColumns" :data="selectedData" :pagination="paginationOptions">
|
||||||
:multiple="props.multiple"
|
<template #nickname="{ record }">
|
||||||
:selected-users="selectedUsers"
|
{{ record.nickname }}({{ record.username }})
|
||||||
@update:selected-users="updateSelectedUsers"
|
</template>
|
||||||
/>
|
<template #action="{ record }">
|
||||||
</a-modal>
|
<a-button status="danger" size="mini" @click="handleDeleteSelectedUser(record)">
|
||||||
|
<icon-delete />
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useWindowSize } from '@vueuse/core'
|
import type { TreeNodeData } from '@arco-design/web-vue'
|
||||||
import UserSelectContent from './component/UserSelectContent.vue'
|
import { type UserQuery, type UserResp, listAllUser, listUser } from '@/apis'
|
||||||
import { listUserDict } from '@/apis'
|
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
||||||
import type { UserSelectPropType } from '@/components/UserSelect/type'
|
import { type Options, useTable } from '@/hooks'
|
||||||
import type { LabelValueState } from '@/types/global'
|
import { useDept } from '@/hooks/app'
|
||||||
|
import { isMobile } from '@/utils'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<UserSelectPropType>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
multiple: false, // 是否支持多选
|
multiple: true,
|
||||||
value: [], // 单选时默认值为空数组
|
value: () => [],
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['update:value'])
|
|
||||||
const { width } = useWindowSize() // 获取窗口的宽度,用于设置弹窗宽度
|
|
||||||
const visible = ref<boolean>(false) // 控制弹窗显示的状态
|
|
||||||
const userList = ref<LabelValueState[]>([]) // 保存用户选项列表
|
|
||||||
const userSelectContentRef = ref() // 引用 UserSelectContent 组件实例
|
|
||||||
const selectedUsers = ref<string[]>([]) // 保存已选择的用户
|
|
||||||
|
|
||||||
// 打开用户选择弹窗
|
const emit = defineEmits<{
|
||||||
const onOpen = () => {
|
(e: 'select-user', keys: Array<any>): void
|
||||||
visible.value = true
|
}>()
|
||||||
userSelectContentRef.value.init(selectedUsers.value) // 调用子组件的初始化方法
|
|
||||||
|
interface Props {
|
||||||
|
multiple?: boolean
|
||||||
|
value: string | string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发出数据更新事件
|
// 查询表单
|
||||||
const emitDataChange = () => {
|
const queryForm = reactive<UserQuery>({
|
||||||
emit('update:value', selectedUsers.value.filter(Boolean)) // 发出更新事件
|
sort: ['t1.createTime,desc', 't1.id,desc'],
|
||||||
|
})
|
||||||
|
|
||||||
|
// 用户列表
|
||||||
|
const { tableData: dataList, loading, pagination, search } = useTable(
|
||||||
|
(page) => listUser({ ...queryForm, ...page }),
|
||||||
|
{ immediate: true, formatResult: (data) => data.map((i) => ({ ...i, disabled: false })) },
|
||||||
|
)
|
||||||
|
|
||||||
|
// 表格列定义
|
||||||
|
const listColumns: TableInstanceColumns[] = [
|
||||||
|
{
|
||||||
|
title: '序号',
|
||||||
|
width: 66,
|
||||||
|
align: 'center',
|
||||||
|
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
|
||||||
|
fixed: !isMobile() ? 'left' : undefined,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '昵称',
|
||||||
|
dataIndex: 'nickname',
|
||||||
|
slotName: 'nickname',
|
||||||
|
minWidth: 140,
|
||||||
|
ellipsis: true,
|
||||||
|
tooltip: true,
|
||||||
|
fixed: !isMobile() ? 'left' : undefined,
|
||||||
|
},
|
||||||
|
{ title: '用户名', dataIndex: 'username', slotName: 'username', minWidth: 140, ellipsis: true, tooltip: true },
|
||||||
|
{ title: '状态', slotName: 'status', align: 'center' },
|
||||||
|
{ title: '性别', dataIndex: 'gender', slotName: 'gender', align: 'center' },
|
||||||
|
{ title: '所属部门', dataIndex: 'deptName', minWidth: 180, ellipsis: true, tooltip: true },
|
||||||
|
{ title: '描述', dataIndex: 'description', minWidth: 130, ellipsis: true, tooltip: true },
|
||||||
|
]
|
||||||
|
|
||||||
|
// 右侧已选用户列定义
|
||||||
|
const selectedColumns = [
|
||||||
|
{ title: '用户', dataIndex: 'nickname', slotName: 'nickname', minWidth: 140, ellipsis: true, tooltip: true },
|
||||||
|
{ title: '操作', dataIndex: 'action', slotName: 'action', align: 'center', width: 90 },
|
||||||
|
]
|
||||||
|
const paginationOptions: Options = {
|
||||||
|
defaultPageSize: 10,
|
||||||
|
defaultSizeOptions: [10, 20, 30, 40, 50],
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理用户选择变更事件
|
// 重置
|
||||||
const handleSelectChange = (value: any) => {
|
const reset = () => {
|
||||||
|
queryForm.description = undefined
|
||||||
|
queryForm.deptId = undefined
|
||||||
|
search()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选中用户 ID
|
||||||
|
const selectedKeys = ref<string[]>([])
|
||||||
|
// 选中用户信息
|
||||||
|
const selectedData = ref<UserResp[]>([])
|
||||||
|
|
||||||
|
const emitSelectUser = () => {
|
||||||
|
emit('select-user', selectedKeys.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单选
|
||||||
|
const onSelect = (rowKeys: string[], rowKey: string, record: UserResp) => {
|
||||||
if (props.multiple) {
|
if (props.multiple) {
|
||||||
// 多选模式下,selectedUsers 应该是一个数组
|
// 多选
|
||||||
selectedUsers.value = value
|
if (rowKeys.includes(rowKey)) {
|
||||||
|
// 包含 选中
|
||||||
|
selectedData.value.push(record)
|
||||||
|
selectedKeys.value?.push(rowKey)
|
||||||
|
} else {
|
||||||
|
// 不包含 去除
|
||||||
|
selectedData.value = selectedData.value.filter((item) => item.id !== rowKey)
|
||||||
|
selectedKeys.value?.splice(selectedKeys.value?.indexOf(rowKey), 1)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 单选模式下,selectedUsers 只应保存一个值
|
// 单选
|
||||||
selectedUsers.value = value ? [value] : []
|
selectedData.value = []
|
||||||
|
selectedKeys.value = []
|
||||||
|
if (rowKeys.includes(rowKey)) {
|
||||||
|
// 包含 选中
|
||||||
|
selectedData.value.push(record)
|
||||||
|
selectedKeys.value?.push(rowKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
emitDataChange() // 每次选择变化时发出更新事件
|
emitSelectUser()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新已选择的用户列表
|
// 全选
|
||||||
const updateSelectedUsers = (users: string[]) => {
|
const onSelectAll = (checked: boolean) => {
|
||||||
selectedUsers.value = users
|
if (checked) {
|
||||||
emitDataChange() // 每次选择变化时发出更新事件
|
// 选中
|
||||||
|
dataList.value.forEach((item) => {
|
||||||
|
selectedData.value.push(item)
|
||||||
|
selectedKeys.value?.push(item.id)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 取消选中
|
||||||
|
dataList.value.forEach((item) => {
|
||||||
|
selectedData.value = selectedData.value.filter((i) => i.id !== item.id)
|
||||||
|
selectedKeys.value?.splice(selectedKeys.value?.indexOf(item.id), 1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
emitSelectUser()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 弹窗确认按钮点击事件
|
// 从选中列表中移除用户
|
||||||
const handleModalOk = () => {
|
const handleDeleteSelectedUser = (user: UserResp) => {
|
||||||
emitDataChange() // 确认时发出数据更新事件
|
selectedData.value = selectedData.value.filter((i) => i.id !== user.id)
|
||||||
visible.value = false // 关闭弹窗
|
selectedKeys.value?.splice(selectedKeys.value?.indexOf(user.id), 1)
|
||||||
|
emitSelectUser()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空所有选中数据
|
||||||
|
const onClearSelected = () => {
|
||||||
|
selectedData.value = []
|
||||||
|
selectedKeys.value = []
|
||||||
|
emitSelectUser()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 部门列表
|
||||||
|
const { deptList, getDeptList } = useDept()
|
||||||
|
// 过滤部门
|
||||||
|
const filterDeptOptions = (searchKey: string, nodeData: TreeNodeData) => {
|
||||||
|
if (nodeData.title) {
|
||||||
|
return nodeData.title.toLowerCase().includes(searchKey.toLowerCase())
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 组件挂载后初始化用户列表
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const { data } = await listUserDict() // 获取所有用户
|
await getDeptList()
|
||||||
userList.value = data
|
// 过滤已选择的用户
|
||||||
// 初始化选择的用户
|
if (props.value && props.value.length > 0) {
|
||||||
selectedUsers.value = Array.isArray(props.value) ? props.value : props.value?.split(',')
|
const { data } = await listAllUser({ userIds: props.value })
|
||||||
|
if (props.multiple) {
|
||||||
|
selectedData.value = data.filter((item) => props.value.includes(item.id))
|
||||||
|
selectedKeys.value = Array.from(selectedData.value).map((user) => user.id)
|
||||||
|
} else {
|
||||||
|
selectedData.value = data.filter((item) => props.value[0] === item.id)
|
||||||
|
selectedKeys.value = Array.from(selectedData.value).map((user) => user.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defineExpose({ onClearSelected })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
:deep(.arco-row-align-start) {
|
||||||
|
align-items: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@@ -1,14 +0,0 @@
|
|||||||
export interface UserSelectPropType {
|
|
||||||
multiple: boolean
|
|
||||||
value: string[] | string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserItem {
|
|
||||||
id: string
|
|
||||||
nickname: string
|
|
||||||
deptName: string
|
|
||||||
roleNames: string
|
|
||||||
phone: string
|
|
||||||
email: string
|
|
||||||
status: number
|
|
||||||
}
|
|
@@ -20,25 +20,55 @@
|
|||||||
<div class="detail_content" style="display: flex; flex-direction: column;">
|
<div class="detail_content" style="display: flex; flex-direction: column;">
|
||||||
<GiForm ref="formRef" v-model="form" :options="options" :columns="columns">
|
<GiForm ref="formRef" v-model="form" :options="options" :columns="columns">
|
||||||
<template #noticeUsers>
|
<template #noticeUsers>
|
||||||
<UserSelect v-model:value="form.noticeUsers" :multiple="true" class="w-full" />
|
<a-select
|
||||||
|
v-model="form.noticeUsers"
|
||||||
|
:options="userList"
|
||||||
|
multiple
|
||||||
|
:max-tag-count="4"
|
||||||
|
:allow-clear="true"
|
||||||
|
/>
|
||||||
|
<a-tooltip content="选择用户">
|
||||||
|
<a-button @click="onOpenSelectUser">
|
||||||
|
<template #icon>
|
||||||
|
<icon-plus />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</GiForm>
|
</GiForm>
|
||||||
<div style="flex: 1;">
|
<div style="flex: 1;">
|
||||||
<AiEditor v-model="form.content" />
|
<AiEditor v-model="form.content" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="visible"
|
||||||
|
title="用户选择"
|
||||||
|
:mask-closable="false"
|
||||||
|
:esc-to-close="false"
|
||||||
|
:width="width >= 1350 ? 1350 : '100%'"
|
||||||
|
draggable
|
||||||
|
@close="reset"
|
||||||
|
>
|
||||||
|
<UserSelect v-if="visible" ref="UserSelectRef" v-model:value="form.noticeUsers" @select-user="onSelectUser" />
|
||||||
|
</a-modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { Message } from '@arco-design/web-vue'
|
import { Message } from '@arco-design/web-vue'
|
||||||
|
import { useWindowSize } from '@vueuse/core'
|
||||||
|
import { ref } from 'vue'
|
||||||
import AiEditor from '../components/edit/index.vue'
|
import AiEditor from '../components/edit/index.vue'
|
||||||
import { useTabsStore } from '@/stores'
|
import { useTabsStore } from '@/stores'
|
||||||
import { type Columns, GiForm, type Options } from '@/components/GiForm'
|
import { type Columns, GiForm, type Options } from '@/components/GiForm'
|
||||||
import { addNotice, getNotice, updateNotice } from '@/apis/system'
|
import { addNotice, getNotice, updateNotice } from '@/apis/system'
|
||||||
import { useForm } from '@/hooks'
|
import { useForm } from '@/hooks'
|
||||||
import { useDict } from '@/hooks/app'
|
import { useDict } from '@/hooks/app'
|
||||||
|
import { listUserDict } from '@/apis'
|
||||||
|
import type { LabelValueState } from '@/types/global'
|
||||||
|
|
||||||
|
const { width } = useWindowSize()
|
||||||
const { notice_type } = useDict('notice_type')
|
const { notice_type } = useDict('notice_type')
|
||||||
const containerRef = ref<HTMLElement | null>()
|
const containerRef = ref<HTMLElement | null>()
|
||||||
const tabsStore = useTabsStore()
|
const tabsStore = useTabsStore()
|
||||||
@@ -84,7 +114,6 @@ const columns: Columns = reactive([
|
|||||||
props: {
|
props: {
|
||||||
showTime: true,
|
showTime: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '终止时间',
|
label: '终止时间',
|
||||||
@@ -104,23 +133,27 @@ const columns: Columns = reactive([
|
|||||||
{
|
{
|
||||||
label: '指定用户',
|
label: '指定用户',
|
||||||
field: 'noticeUsers',
|
field: 'noticeUsers',
|
||||||
type: 'input',
|
type: 'select',
|
||||||
hide: () => {
|
hide: () => {
|
||||||
return form.noticeScope === 1
|
return form.noticeScope === 1
|
||||||
},
|
},
|
||||||
rules: [{ required: true, message: '请选择指定用户' }],
|
rules: [{ required: true, message: '请选择指定用户' }],
|
||||||
},
|
},
|
||||||
|
|
||||||
])
|
])
|
||||||
|
|
||||||
// 修改
|
// 修改
|
||||||
const onUpdate = async (id: string) => {
|
const onUpdate = async (id: string) => {
|
||||||
resetForm()
|
resetForm()
|
||||||
const res = await getNotice(id)
|
const res = await getNotice(id)
|
||||||
Object.assign(form, res.data)
|
Object.assign(form, res.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 返回
|
||||||
const onBack = () => {
|
const onBack = () => {
|
||||||
tabsStore.closeCurrent(route.path)
|
tabsStore.closeCurrent(route.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 发布
|
||||||
const onReleased = async () => {
|
const onReleased = async () => {
|
||||||
const isInvalid = await formRef.value?.formRef?.validate()
|
const isInvalid = await formRef.value?.formRef?.validate()
|
||||||
if (isInvalid) return false
|
if (isInvalid) return false
|
||||||
@@ -141,11 +174,34 @@ const onReleased = async () => {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
|
||||||
|
// 打开用户选择窗口
|
||||||
|
const visible = ref(false)
|
||||||
|
const onOpenSelectUser = () => {
|
||||||
|
visible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const UserSelectRef = ref()
|
||||||
|
// 重置
|
||||||
|
const reset = () => {
|
||||||
|
UserSelectRef.value?.onClearSelected()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户选择回调
|
||||||
|
const onSelectUser = (value: string[]) => {
|
||||||
|
form.noticeUsers = value
|
||||||
|
formRef.value?.formRef?.validateField('noticeUsers')
|
||||||
|
}
|
||||||
|
|
||||||
|
const userList = ref<LabelValueState[]>([])
|
||||||
|
onMounted(async () => {
|
||||||
// 当id存在与type为edit时,执行修改操作
|
// 当id存在与type为edit时,执行修改操作
|
||||||
if (id && type === 'edit') {
|
if (id && type === 'edit') {
|
||||||
onUpdate(id as string)
|
onUpdate(id as string)
|
||||||
}
|
}
|
||||||
|
// 获取所有用户
|
||||||
|
const { data } = await listUserDict()
|
||||||
|
userList.value = data
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user