Commit fee53bb2 by lijiabin

【需求 25171】feat: 新增部门/人员选择组件,替代企微选人 API

- DepartmentUserModal:自封装选部门/选人弹窗,懒加载组织架构树 + 成员,
  支持部门/人员/两者、单选/多选、userId|account|jobNumId 三种取值字段、
  搜索下拉(超过 100 条截断展示 + 查看全部)。
- DeptUserPicker:表单场景的轻量封装,v-model 直接绑 DepartmentUserSelection[],
  触发区交给调用方自定义,用于逐步替换页面里的 selectDepOrUser(企微选人)调用。
- src/api/department 改名为 src/api/deptUser,接口不只是部门,也包含查成员/搜人。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
parent 8b8ed832
import service from '@/utils/request/index'
import type {
DepartmentDto,
DepartmentListParams,
DepartmentUserDto,
DepartmentUserListParams,
} from './types'
/** 获取扁平部门列表,由组件根据 pid 构建部门树。 */
export const getAllDept = (data: DepartmentListParams = {}) => {
return service.request<DepartmentDto[]>({
url: '/api/dept/getAllDept',
method: 'POST',
data,
})
}
/** 获取指定部门成员;传 keyword 时用于全局搜索人员。 */
export const getDeptUsers = (data: DepartmentUserListParams) => {
return service.request<DepartmentUserDto[]>({
url: '/api/dept/getDeptUsers',
method: 'POST',
data,
})
}
/** 部门树节点 */
export interface DepartmentDto {
deptId: string | number
pid: string | number
pids?: string
simpleName: string
fullName: string
hasUserFlag: number
children?: DepartmentDto[]
}
/** 部门成员 */
export interface DepartmentUserDto {
userId: string | number
name: string
account?: string
jobNumId?: string
avatar?: string
deptId: string | number
}
/** 获取部门树的查询参数 */
export interface DepartmentListParams {
deptIdList?: Array<string | number>
simpleName?: string
}
/** 获取部门成员或搜索人员的查询参数 */
export interface DepartmentUserListParams {
deptId?: string | number
keyword?: string
}
...@@ -17,6 +17,7 @@ export * from './dailyLottery' ...@@ -17,6 +17,7 @@ export * from './dailyLottery'
export * from './launchCampaign' export * from './launchCampaign'
export * from './selfMessage' export * from './selfMessage'
export * from './luckyWheel' export * from './luckyWheel'
export * from './deptUser'
// 导出类型 // 导出类型
export * from './task/types' export * from './task/types'
export * from './shop/types' export * from './shop/types'
...@@ -36,3 +37,4 @@ export * from './dailyLottery/types' ...@@ -36,3 +37,4 @@ export * from './dailyLottery/types'
export * from './launchCampaign/types' export * from './launchCampaign/types'
export * from './selfMessage/types' export * from './selfMessage/types'
export * from './luckyWheel/types' export * from './luckyWheel/types'
export * from './deptUser/types'
export type SelectionMode = 'department' | 'user' | 'both'
export type UserValueField = 'userId' | 'account' | 'jobNumId'
/** 选人弹窗对外返回的统一选择项。 */
export interface DepartmentUserSelection {
valueType: 1 | 2
valueId: string
valueName: string
valueField?: UserValueField
avatar?: string
deptId?: string
userId?: string
account?: string
jobNumId?: string
}
/** 命令式打开弹窗时的配置,selected 用于表单或表格编辑回显。 */
export interface DepartmentUserModalOpenOptions {
selectionMode?: SelectionMode
userValueField?: UserValueField
selected?: DepartmentUserSelection[]
/** 是否允许多选,默认 true;单选时选中新项会自动替换掉之前的选择(不区分部门/人员)。 */
multiple?: boolean
}
export interface DepartmentUserModalExpose {
open: (options?: DepartmentUserModalOpenOptions) => void
close: () => void
}
<template>
<!-- 触发区完全交给调用方自己写(长度、placeholder 等都自己控制),这里只负责点击打开弹窗。 -->
<div class="inline-block" :class="{ 'cursor-not-allowed': disabled }" @click="open">
<slot :echo-text="echoText" />
</div>
<DepartmentUserModal ref="modalRef" @confirm="handleConfirm" />
</template>
<script setup lang="ts">
/**
* 表单场景下的选部门/选人控件,套了一层 DepartmentUserModal,替代 selectDepOrUser(企微选人)。
* 触发区完全由调用方自己写(没有默认按钮/输入框),组件只负责打开弹窗和传出拼好的 echoText。
*
* 用法:
* <DeptUserPicker v-model="form.pushList" selection-mode="both" v-slot="{ echoText }">
* <el-input readonly class="w-96" placeholder="请选择部门/人员" :model-value="echoText" />
* </DeptUserPicker>
*
* v-model 绑的是 DepartmentUserSelection[](valueId/valueName/valueType 成对出现,不用额外查名字回显);
* 单选传 :multiple="false";只选人/只选部门用 selection-mode="user" / "department"。
*/
import DepartmentUserModal from '@/components/common/DepartmentUserModal/index.vue'
import type { DepartmentUserSelection } from '@/components/common/DepartmentUserModal/types'
import type { DeptUserPickerProps } from './types'
const {
selectionMode = 'both',
multiple = true,
userValueField = 'userId',
disabled = false,
} = defineProps<DeptUserPickerProps>()
const modelValue = defineModel<DepartmentUserSelection[]>({ default: () => [] })
const modalRef = useTemplateRef<InstanceType<typeof DepartmentUserModal>>('modalRef')
// 顿号拼接已选名字,调用方直接拿去当输入框回显文案用,不用自己再拼一遍。
const echoText = computed(() => modelValue.value.map((item) => item.valueName).join('、'))
const open = () => {
if (disabled) return
modalRef.value?.open({
selectionMode,
multiple,
userValueField,
selected: modelValue.value,
})
}
const handleConfirm = (items: DepartmentUserSelection[]) => {
modelValue.value = items
}
defineExpose({ open })
</script>
import type { SelectionMode, UserValueField } from '@/components/common/DepartmentUserModal/types'
export type DeptUserPickerProps = {
/** 部门/人员/两者,默认 both */
selectionMode?: SelectionMode
/** 是否多选,默认 true;单选时选中新项会自动替换掉之前的选择 */
multiple?: boolean
/** 人员值字段,默认 userId */
userValueField?: UserValueField
disabled?: boolean
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment