Files
td_official/src/views/system/user/comm/roleInfo.vue

478 lines
13 KiB
Vue
Raw Normal View History

2025-09-04 09:03:42 +08:00
<template>
<div class="roleInfo">
<div class="title_detail">
<span>当前选定角色信息预览</span>
<div style="margin-top: 10px">
<el-table :data="roleList" border height="150">
<el-table-column label="所属部门" align="center" prop="deptName" />
<el-table-column label="关联项目" align="center" prop="projectName" />
<el-table-column label="web端担任角色" align="center" prop="webRoles" />
<el-table-column label="APP端担任角色" align="center" prop="appRoles" />
</el-table>
</div>
</div>
<div class="title_detail" style="margin-top: 20px">
<span>选择或修改当前角色信息</span>
<div style="margin-top: 10px" class="box_detail">
<!-- 项目列表选择区 -->
<div class="project_list">
<span>关联项目模块</span>
<div class="project-items">
<div
v-for="item in projectOptions"
:key="item.id"
class="project-item"
:class="{ 'project-item-selected': isProjectSelected(item.id) }"
@click="toggleProjectSelection(item)"
>
<div class="project-item-content">
<el-checkbox v-model="item.checked" :value="item.id" class="project-checkbox" @change="handleProjectCheck(item, $event)" />
<span class="project-name">{{ item.projectName }}</span>
</div>
</div>
</div>
</div>
<!-- 角色分配区 -->
<div class="post_list">
<span>关联项目角色分配</span>
<div v-if="selectedProjects.length === 0" class="no-selection">请从左侧选择项目进行角色分配</div>
<div v-for="(project, index) in selectedProjects" :key="project.id" class="project-role-container">
<div class="project-header">
<span class="project-title">{{ project.projectName }}</span>
<el-button type="text" class="remove-project" @click="removeProject(project.id)"> 移除 </el-button>
</div>
<div class="role-assignment">
<div class="role-group">
<label class="role-label">web端角色</label>
<el-checkbox-group v-model="project.webRoles" @change="updateRoleList">
<el-checkbox v-for="role in allRoles" :key="role.roleId" :value="role.roleId">
{{ role.roleName }}
</el-checkbox>
</el-checkbox-group>
</div>
<div class="role-group">
<label class="role-label">APP端角色</label>
<el-checkbox-group v-model="project.appRoles" @change="updateRoleList">
<el-checkbox v-for="role in AppRoles" :key="role.roleId" :value="role.roleId">
{{ role.roleName }}
</el-checkbox>
</el-checkbox-group>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="box_submit">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel()"> </el-button>
</div>
</div>
</template>
<script setup name="RoleProjectManagement" lang="ts">
import { ref, reactive, toRefs, getCurrentInstance, ComponentInternalInstance, defineExpose, watch } from 'vue';
import { ElFormInstance } from 'element-plus';
import api from '@/api/system/user';
import { listProject } from '@/api/project/project';
import { getRoleList } from '@/api/system/post';
// 类型定义
interface Project {
id: number | string;
projectName: string;
checked: boolean;
webRoles: string[];
appRoles: string[];
}
interface Role {
roleId: number | string;
roleName: string;
roleSort?: number;
}
interface RoleInfo {
userNick: string;
deptName: string;
postName: string;
projectName: string;
webRoles: string;
appRoles: string;
}
// 组件实例
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
// 响应式数据
const projectOptions = ref<Project[]>([]);
const selectedProjects = ref<Project[]>([]);
const allRoles = ref<Role[]>([]); // web端角色
const AppRoles = ref<Role[]>([]); // APP端角色
const roleList = ref<RoleInfo[]>([]);
// 表单初始数据
const initFormData = {
userId: undefined,
deptId: undefined,
userName: '',
nickName: undefined,
password: '',
phonenumber: undefined,
email: undefined,
sex: undefined,
projectRoles: [] as Array<{ projectId: number | string; webRoles: string[]; appRoles: string[] }>,
status: '0',
remark: '',
postIds: [],
filePath: undefined,
deptName: '' // 新增部门名称字段
};
const data = reactive({
form: { ...initFormData }
});
const deptName = ref('');
const { form } = toRefs(data);
// 核心方法:更新预览列表
const updateRoleList = () => {
if (selectedProjects.value.length === 0) {
roleList.value = [];
return;
}
roleList.value = selectedProjects.value.map((project) => {
// 处理web端角色名称
var webRoleNames = project.webRoles
.map((roleId) => {
const role = allRoles.value.find((r) => r.roleId === roleId);
return role ? role.roleName : '';
})
.filter(Boolean);
// 处理APP端角色名称
var appRoleNames = project.appRoles
.map((roleId) => {
const role = AppRoles.value.find((r) => r.roleId === roleId);
return role ? role.roleName : '';
})
.filter(Boolean);
webRoleNames = [...new Set(webRoleNames)];
appRoleNames = [...new Set(appRoleNames)];
return {
deptName: deptName.value,
projectName: project.projectName,
webRoles: webRoleNames.length > 0 ? webRoleNames.join('') : '无',
appRoles: appRoleNames.length > 0 ? appRoleNames.join('') : '无'
};
});
};
// 监听已选项目变化,自动更新预览列表
watch(
selectedProjects,
() => {
updateRoleList();
},
{ deep: true }
);
// 检查项目是否被选中
const isProjectSelected = (projectId: number | string) => {
return selectedProjects.value.some((p) => p.id === projectId);
};
// 切换项目选择状态
const toggleProjectSelection = (project: Project) => {
// handleProjectCheck(project, !project.checked);
};
// 处理项目勾选状态变化
const handleProjectCheck = (project: Project, checked: boolean) => {
// project.checked = checked;
const index = selectedProjects.value.findIndex((p) => p.id === project.id);
if (checked && index === -1) {
// 添加选中的项目
selectedProjects.value.push({
...project,
webRoles: [],
appRoles: []
});
} else if (!checked && index !== -1) {
// 移除取消选中的项目
selectedProjects.value.splice(index, 1);
}
};
// 移除项目
const removeProject = (projectId: number | string) => {
// 更新选中项目列表
selectedProjects.value = selectedProjects.value.filter((p) => p.id !== projectId);
// 更新项目选项的勾选状态
const project = projectOptions.value.find((p) => p.id === projectId);
if (project) {
project.checked = false;
}
};
// 提交表单
const submitForm = async () => {
// 整理项目角色数据
form.value.projectRoles = selectedProjects.value.map((project) => ({
projectId: project.id,
roleIds: [...new Set(project.webRoles), ...new Set(project.appRoles)]
}));
// 提交数据
try {
if (form.value.userId) {
await api.updateUser(form.value);
} else {
await api.addUser(form.value);
}
proxy?.$modal.msgSuccess('操作成功');
proxy?.$emit('submit', form.value);
cancel();
} catch (error) {
proxy?.$modal.msgError('操作失败,请重试');
console.error('提交失败:', error);
}
};
// 取消操作
const cancel = () => {
resetForm();
proxy?.$emit('close');
};
// 重置表单
const resetForm = () => {
data.form = { ...initFormData };
projectOptions.value.forEach((p) => (p.checked = false));
selectedProjects.value = [];
roleList.value = [];
};
// 初始化数据
const initData = async () => {
try {
// 获取项目列表
const projectRes = await listProject();
projectOptions.value = projectRes.rows.map((item: any) => ({
id: item.id,
projectName: item.projectName,
checked: false
}));
} catch (error) {
proxy?.$modal.msgError('数据加载失败');
console.error('初始化数据失败:', error);
}
};
// 打开弹窗时调用
const open = async (row?: any, deptId?: any) => {
resetForm();
await initData();
deptName.value = row.deptName;
console.log(row);
if (row) {
try {
if (!row.createTime) {
form.value = { ...row };
// 获取角色列表
if (form.value.deptId) {
deptId = form.value.deptId;
}
const roleRes = await getRoleList(deptId);
allRoles.value = roleRes.data.filter((item: Role) => item.roleSort === 1);
AppRoles.value = roleRes.data.filter((item: Role) => item.roleSort !== 1);
} else {
const { data } = await api.getUser(row.userId);
Object.assign(form.value, data.user);
// 获取角色列表
if (form.value.deptId) {
deptId = form.value.deptId;
}
const roleRes = await getRoleList(deptId);
// 区分web端和app端角色
allRoles.value = roleRes.data.filter((item: Role) => item.roleSort === 1);
AppRoles.value = roleRes.data.filter((item: Role) => item.roleSort !== 1);
// 加载项目角色数据
if (data.projectRoles && data.projectRoles.length) {
data.projectRoles.forEach((pr: any) => {
const project = projectOptions.value.find((p) => p.id === pr.projectId);
if (project) {
project.checked = true;
selectedProjects.value.push({
...project,
webRoles: pr.roleIds || [],
appRoles: pr.roleIds || []
});
}
});
}
}
} catch (error) {
proxy?.$modal.msgError('加载用户数据失败');
console.error('加载用户数据失败:', error);
}
}
};
// 暴露方法
defineExpose({ open });
</script>
<style lang="scss">
.roleInfo {
position: relative;
height: 100%;
padding-bottom: 60px;
box-sizing: border-box;
.title_detail {
> span {
font-size: 16px;
font-weight: 600;
color: #333;
display: inline-block;
padding-bottom: 5px;
border-bottom: 2px solid #409eff;
}
.box_detail {
display: flex;
gap: 15px;
margin-top: 15px;
> div {
height: 350px;
padding: 15px;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
overflow-y: auto;
box-sizing: border-box;
}
.project_list {
width: 320px;
background-color: #fff;
.project-items {
margin-top: 10px;
}
.project-item {
padding: 10px 12px;
margin-bottom: 8px;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s ease;
border: 1px solid #eee;
&:hover {
background-color: #f5f7fa;
border-color: #e4e7ed;
}
.project-item-content {
display: flex;
align-items: center;
}
.project-checkbox {
margin-right: 8px;
}
.project-name {
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.project-item-selected {
background-color: #ecf5ff;
border-color: #c6e2ff;
}
}
.post_list {
flex: 1;
background-color: #fff;
.no-selection {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: #909399;
font-size: 14px;
}
.project-role-container {
padding: 15px;
margin-bottom: 15px;
background-color: #f9f9f9;
border-radius: 4px;
border: 1px solid #f0f0f0;
.project-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
.project-title {
font-weight: 500;
color: #333;
font-size: 14px;
}
.remove-project {
color: #f56c6c;
padding: 0 5px;
&:hover {
color: #e4393c;
}
}
}
.role-assignment {
.role-group {
margin-bottom: 15px;
.role-label {
display: inline-block;
width: 110px;
color: #606266;
font-size: 14px;
}
.el-checkbox-group {
display: inline-block;
margin-left: 10px;
.el-checkbox {
margin-right: 15px;
margin-bottom: 8px;
}
}
}
}
}
}
}
}
.box_submit {
position: absolute;
right: 20px;
bottom: 0px;
display: flex;
gap: 10px;
}
}
</style>