要实现“搜索角色+下拉选择+添加到列表(带‘新增’标签)”的功能,可基于Vue+Element UI封装组件,以下是贴合截图效果的完整实现:
一、Vue组件代码(RoleAddWithNewTag.vue)
<template> <div class="role-container"> <!-- 已选角色列表(含“新增”标签) --> <div class="selected-role-item" v-for="(item, index) in selectedRoles" :key="index"> <!-- 角色名 + 新增标签 --> <span class="role-name"> {{ item.roleName }} <el-tag size="mini" type="info" v-if="item.isNew">新增</el-tag> </span> <!-- 人员选择框 --> <el-select v-model="item.userId" placeholder="待填" style="width: 120px; margin-left: 10px;" @change="updateUserName(item, $event)" > <el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" /> </el-select> </div> <!-- 添角色按钮 + 搜索下拉框 --> <div class="add-role-area" style="margin-top: 10px;"> <el-button type="primary" icon="el-icon-plus" @click="showRolePopover = true" size="mini" > 添加角色 </el-button> <!-- 搜索+下拉角色列表(Popover) --> <el-popover v-model="showRolePopover" trigger="manual" placement="bottom-start" width="200" style="margin-left: 10px;" > <el-input v-model="searchKey" placeholder="搜索角色名称" prefix-icon="el-icon-search" @input="filterRoles" size="mini" /> <div class="role-option-list" style="max-height: 200px; overflow-y: auto; margin-top: 5px;"> <div class="role-option-item" v-for="role in filteredRoles" :key="role.roleCode" @click="selectRole(role)" > {{ role.roleName }} </div> <div class="no-data" v-if="filteredRoles.length === 0">无匹配角色</div> </div> </el-popover> </div> </div> </template> <script> import { getRoleDict, listUser } from "@/api/project/role"; // 后端接口 export default { name: "RoleAddWithNewTag", data() { return { allRoles: [], // 所有角色字典(后端获取:{roleCode: 'RD', roleName: '研发'}) filteredRoles: [], // 搜索过滤后的角色列表 searchKey: "", // 角色搜索关键词 showRolePopover: false, // 角色下拉框显隐 selectedRoles: [], // 已选角色列表(含isNew标记) userList: [] // 系统用户列表(人员选择) }; }, created() { this.loadBaseData(); }, methods: { // 加载角色字典+系统用户 async loadBaseData() { // 1. 加载所有角色(后端字典接口) const roleRes = await getRoleDict(); this.allRoles = roleRes.data; this.filteredRoles = [...this.allRoles]; // 2. 加载系统用户(人员选择项) const userRes = await listUser({ pageSize: 200 }); this.userList = userRes.data.rows; }, // 搜索过滤角色 filterRoles() { if (!this.searchKey) { this.filteredRoles = [...this.allRoles]; return; } this.filteredRoles = this.allRoles.filter(role => role.roleName.includes(this.searchKey.trim()) ); }, // 选择下拉中的角色 selectRole(role) { // 1. 去重校验:已选角色不能重复 const isDuplicate = this.selectedRoles.some( item => item.roleCode === role.roleCode ); if (isDuplicate) { this.$message.warning("该角色已添加"); this.showRolePopover = false; return; } // 2. 添加到已选列表,并标记“新增” this.selectedRoles.push({ ...role, userId: null, // 人员ID(待填) userName: "", // 人员名称(待填) isNew: true // 标记为新增角色 }); // 3. 重置搜索+关闭下拉框 this.searchKey = ""; this.showRolePopover = false; }, // 选择人员后更新名称 updateUserName(item, userId) { const selectedUser = this.userList.find(u => u.userId === userId); item.userName = selectedUser ? selectedUser.nickName : ""; } } }; </script> <style scoped> .selected-role-item { display: flex; align-items: center; margin-bottom: 8px; } .role-name { display: inline-flex; align-items: center; width: 100px; } .role-option-item { padding: 6px 10px; cursor: pointer; font-size: 14px; } .role-option-item:hover { background-color: #f5f7fa; } .no-data { padding: 6px 10px; color: #999; font-size: 14px; } </style>二、核心功能说明
下拉搜索&选择:
- 点击「添加角色」弹出
el-popover,内含搜索框+角色列表; - 输入关键词实时过滤角色,点击角色项完成选择。
- 点击「添加角色」弹出
去重校验:
- 选择角色前,检查
selectedRoles中是否已有相同roleCode的角色,避免重复添加。
- 选择角色前,检查
“新增”标签显示:
- 给新添加的角色项增加
isNew: true标记,通过el-tag渲染“新增”标签。
- 给新添加的角色项增加
人员选择:
- 每个已选角色右侧显示「待填」选择框,关联系统用户列表,选择后自动填充人员名称。
三、后端接口适配(角色字典示例)
若后端getRoleDict接口返回的角色数据格式为:
[{"roleCode":"RD","roleName":"研发"},{"roleCode":"UI&UX","roleName":"UI&UX设计"},{"roleCode":"PM","roleName":"项目经理"},{"roleCode":"FE","roleName":"前端开发"},{"roleCode":"Server","roleName":"服务端开发"}]则组件可直接兼容,无需额外修改。
四、组件使用方式
在“新建需求”等页面中直接引入该组件即可:
<template> <div> <label>角色与人员</label> <role-add-with-new-tag /> </div> </template> <script> import RoleAddWithNewTag from "@/components/RoleAddWithNewTag"; export default { components: { RoleAddWithNewTag } }; </script>要不要我帮你补充该组件的“角色编辑/删除”扩展功能代码?