This commit is contained in:
2026-04-13 09:10:53 +08:00
5 changed files with 320 additions and 24 deletions

View File

@@ -1,5 +1,5 @@
import { post, get } from '@/api/request';
import { userListFormat } from '@/utils/common';
import { userListFormat, relatedUserFormat } from '@/utils/common';
const env = import.meta.env;
const PREFIX = env.VITE_API_PREFIX_SYSTEM;
@@ -68,3 +68,14 @@ export const getUserPermissionsApi = (params: any) => {
export const listUserWithKeyWordApi = (params: any) => {
return get(`${PREFIX}user/listUserWithKeyWord`, params);
};
// 关联权限
export const saveUserRelationApi = (params: any) => {
return post(`${PREFIX}user/saveUserRelation`, params);
};
// 根据用户获取权限
export const queryRelatedUserIdsApi = async (params: any) => {
const res = await post(`${PREFIX}user/queryRelatedUserIds`, params);
return relatedUserFormat(res);
};

View File

@@ -172,16 +172,33 @@ export const resListFormat = (res: any) => {
};
// CID用户列表返回数据格式化
export const userListFormat = (res: any) => {
res?.data?.data?.forEach((item: any) => {
item.userId = item.userInfo.userId;
item.nickname = item.userInfo.nickname;
item.roleListStr = item.roleList.map((item: any) => item.roleName).join(',');
item.postListStr = item.postList.map((item: any) => item.postName).join(',');
item.deptListStr = item.deptList.map((item: any) => item.deptName).join(',');
});
const list =
res?.data?.data?.map((item: any) => {
return {
userId: item.userInfo.userId,
nickname: item.userInfo.nickname,
roleListStr: item.roleList.map((item: any) => item.roleName).join(','),
postListStr: item.postList.map((item: any) => item.postName).join(','),
deptListStr: item.deptList.map((item: any) => item.deptName).join(','),
};
}) || [];
res.data.data = list;
return res;
};
export const relatedUserFormat = (res: any) => {
const list =
res?.data?.map((item: any) => {
return {
userId: item.userInfo.userId,
nickname: item.userInfo.nickname,
roleListStr: item.roleList.map((item: any) => item.roleName).join(','),
postListStr: item.postList.map((item: any) => item.postName).join(','),
deptListStr: item.deptList.map((item: any) => item.deptName).join(','),
};
}) || [];
res.data = list;
return res;
};
const pageStorageData: any = JSON.parse(localStorage.getItem('PAGE_STORAGE_DATA') || '{}');
// 设置页面本地存储
export const setPageStorage = (key: string, val: any) => {

View File

@@ -1,6 +1,15 @@
<template>
<div class="workload-permission">
<DragSplit leftContentWidth="50%" :showToggleBtn="false">
<div class="relate">
<el-button
type="primary"
:icon="Connection"
:disabled="leftCheckedData.length === 0 || rightCheckedData.length === 0"
@click="relateConfirm"
> </el-button
>
</div>
<DragSplit leftContentWidth="50%" :showToggleBtn="false" class="content">
<template #left>
<div class="left">
<div class="table-head">
@@ -13,6 +22,12 @@
leftCheckedData.length
}}</span>
<span class="text"></span>
<span class="divider">|</span>
<el-tooltip content="清空负责人" placement="top">
<el-icon class="delete-btn" @click="clearAll('left')">
<Delete />
</el-icon>
</el-tooltip>
</div>
<div class="filter">
<el-form label-width="auto" @submit.prevent class="demo-form-inline">
@@ -55,23 +70,88 @@
</div>
</div>
</template>
<template #right> 34 </template>
<template #right>
<div class="left right">
<div class="table-head">
<div class="title">
<el-icon class="icon"><Avatar /></el-icon>
<span class="tip">负责列表</span>
<span class="divider">|</span>
<span class="text">已选</span>
<span class="user-num" @click="showRightCheckedData">{{
rightCheckedData.length
}}</span>
<span class="text"></span>
<span class="divider">|</span>
<el-tooltip content="清空负责列表" placement="top">
<el-icon class="delete-btn" @click="clearAll('right')">
<Delete />
</el-icon>
</el-tooltip>
</div>
<div class="filter">
<el-form label-width="auto" @submit.prevent class="demo-form-inline">
<el-form-item label="部门:">
<el-select
v-model="rightParams.deptId"
placeholder="请选择要过滤的部门"
filterable
clearable
class="department-select"
>
<el-option
v-for="item in groupData"
:key="item.id"
:label="item.groupName"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-form>
</div>
</div>
<div class="table">
<BaseTable
ref="rightTableRef"
showCheckbox
tableName="WORKLOAD_CONFIG_TABLE"
fullHeight
:params="rightParams"
:showSetting="false"
:api="listUserDetailPageApi"
:rowConfig="{
keyField: 'userId',
}"
@checkbox-change="rightChangeFun"
@checkbox-all="rightAllChangeFun"
@tableDataLoad="rightTableDataLoad"
>
</BaseTable>
</div>
</div>
</template>
</DragSplit>
<checkedDataDialog
v-model="checkTableDataVisible"
:checked-data="leftCheckedData"
:checked-data="dialogDataType === 'left' ? leftCheckedData : rightCheckedData"
@data-change="handleDataChange"
/>
</div>
</template>
<script setup lang="ts">
import { ref, nextTick, onMounted } from 'vue';
import { ref, nextTick, onMounted, watch } from 'vue';
import DragSplit from '@/components/common/dragSplit/index.vue';
import BaseTable from '@/components/common/table/baseTable.vue';
import { userListUserApi } from '@/api/system/user';
import checkedDataDialog from './checkedDataDialog.vue';
import { userQueryGroupApi, listUserDetailPageApi } from '@/api/system/user';
import {
userQueryGroupApi,
listUserDetailPageApi,
saveUserRelationApi,
queryRelatedUserIdsApi,
} from '@/api/system/user';
import { Connection, Delete } from '@element-plus/icons-vue';
import { ElMessage, ElMessageBox } from 'element-plus';
// 用户组/部门
const groupData = ref<any>([]);
@@ -82,6 +162,7 @@ const getUserGroup = async () => {
onMounted(() => {
getUserGroup();
});
const dialogDataType = ref('');
// #region 左侧表格
const leftTableRef = ref();
@@ -124,32 +205,170 @@ const leftTableDataLoad = () => {
const checkTableDataVisible = ref(false);
const checkTableData = ref<any>([]);
const showLeftCheckedData = () => {
dialogDataType.value = 'left';
checkTableDataVisible.value = true;
checkTableData.value = leftCheckedData.value;
};
// 更新右侧所选数据
const updateRightCheckData = (data: any) => {
const addData = data;
// 把addData添加到rightCheckedData中,且根据userId去重
rightCheckedData.value = rightCheckedData.value
.concat(addData)
.filter(
(item: any, index: number, arr: any) =>
arr.findIndex((i: any) => i.userId === item.userId) === index
);
// console.log(rightCheckedData.value, 'rightCheckedData.value');
rightTableDataLoad();
};
const getRelatedUserIds = async () => {
const params = {
userIds: leftCheckedData.value.map((item: any) => item.userId),
relationType: 1,
};
const { data } = await queryRelatedUserIdsApi(params);
console.log(data, 'data');
updateRightCheckData(data);
};
watch(
() => leftCheckedData.value,
(newVal) => {
if (newVal.length > 0) {
// 获取所选择的用户权限
getRelatedUserIds();
}
},
{ deep: true }
);
// #endregion
// 弹窗数据更新
const handleDataChange = (newData: any[]) => {
leftCheckedData.value = newData;
// 同步更新左侧表格的选中状态
if (dialogDataType.value === 'left') {
leftCheckedData.value = newData;
// 同步更新左侧表格的选中状态
nextTick(() => {
leftTableRef.value?.tableRef?.clearCheckboxRow();
leftTableDataLoad();
});
} else if (dialogDataType.value === 'right') {
rightCheckedData.value = newData;
// 同步更新右侧表格的选中状态
nextTick(() => {
rightTableRef.value?.tableRef?.clearCheckboxRow();
rightTableDataLoad();
});
}
};
// #region 右侧表格
const rightTableRef = ref();
const rightParams = ref({
deptId: '',
});
const rightCheckedData = ref<any>([]);
const showRightCheckedData = () => {
dialogDataType.value = 'right';
checkTableDataVisible.value = true;
checkTableData.value = rightCheckedData.value;
};
const rightChangeFun = (data: any) => {
if (data.checked) {
rightCheckedData.value.push(data.row);
} else {
rightCheckedData.value = rightCheckedData.value.filter(
(item: any) => item.userId !== data.row.userId
);
}
};
const rightAllChangeFun = (data: any) => {
if (data.checked) {
rightCheckedData.value = [...rightCheckedData.value, ...rightTableRef.value.tableData];
console.log(rightCheckedData.value, 'rightCheckedData.value');
// 根据id去重
rightCheckedData.value = rightCheckedData.value.filter(
(item: any, index: number, arr: any) =>
arr.findIndex((i: any) => i.userId === item.userId) === index
);
} else {
rightCheckedData.value = rightCheckedData.value.filter((item: any) => {
return !rightTableRef.value.tableData.some((i: any) => i.userId === item.userId);
});
}
};
const rightTableDataLoad = () => {
nextTick(() => {
const selectedKeys = rightCheckedData.value.map((item: any) => item.userId);
rightTableRef.value.tableRef.setCheckboxRowKey(selectedKeys, true); // 设置为选中
});
};
// #endregion
const clearAll = (type: string) => {
if (type === 'left') {
leftCheckedData.value = [];
leftTableRef.value?.tableRef?.clearCheckboxRow();
leftTableDataLoad();
} else if (type === 'right') {
rightCheckedData.value = [];
rightTableRef.value?.tableRef?.clearCheckboxRow();
}
};
// #region 关联确认
const relateConfirm = () => {
const tips = `${leftCheckedData.value.length} 位负责人绑定当前所选的权限( ${rightCheckedData.value.length} 位用户)<br>确定操作吗?`;
ElMessageBox.confirm(tips, '提示', {
type: 'warning',
dangerouslyUseHTMLString: true,
})
.then(() => {
relateFun();
})
.catch(() => {
ElMessage.info('取消操作');
});
};
const relateFun = async () => {
console.log(leftCheckedData.value, rightCheckedData.value);
const params = {
userIds: leftCheckedData.value.map((item: any) => item.userId),
relatedUserIds: rightCheckedData.value.map((item: any) => item.userId),
relationType: 1,
};
saveUserRelationApi(params).then((res) => {
if (res.code === 200) {
ElMessage.success('关联成功');
}
});
};
// # endregion
// #endregion
</script>
<style scoped lang="scss">
.workload-permission {
height: 100%;
width: 100%;
position: relative;
.relate {
position: absolute;
right: 20px;
top: -8px;
}
.left {
height: 100%;
height: calc(100% - 40px);
margin-top: 36px;
display: flex;
flex-direction: column;
overflow: hidden;
}
.right {
.table-head {
padding-left: 20px;
}
}
.table-head {
width: 100%;
height: 32px;
@@ -166,6 +385,13 @@ const handleDataChange = (newData: any[]) => {
color: var(--el-color-primary);
margin-right: 8px;
}
.delete-btn {
font-size: 18px;
color: var(--el-color-danger);
margin-left: 8px;
cursor: pointer;
font-weight: bold;
}
.tip {
font-size: 14px;
color: var(--el-text-color-primary);
@@ -211,3 +437,11 @@ const handleDataChange = (newData: any[]) => {
}
}
</style>
<style lang="scss">
.relate {
.el-icon {
font-size: 18px;
}
}
</style>

View File

@@ -1,6 +1,6 @@
<template>
<div class="gl-page-content">
<DragSplit :leftContentWidth="400">
<DragSplit :leftContentWidth="240">
<template #left>
<div class="left-box">
<ul class="menu-list">
@@ -24,6 +24,7 @@
<roleDiscipline v-if="currentActive === 'roleDiscipline'" />
<physicalUnits v-if="currentActive === 'physicalUnits'"></physicalUnits>
<workforceAllocation v-if="currentActive === 'workforceAllocation'"></workforceAllocation>
<!-- <workloadPermission v-if="currentActive === 'workloadPermission'" /> -->
</div>
</template>
</DragSplit>
@@ -37,6 +38,7 @@ import Review from './components/review.vue';
import roleDiscipline from './components/roleDiscipline.vue';
import physicalUnits from './components/physicalUnits.vue';
import workforceAllocation from './components/workforceAllocation.vue';
// import workloadPermission from './components/workloadPermission.vue';
import { ref } from 'vue';
import { getPageStorage, setPageStorage } from '@/utils/common';
@@ -61,6 +63,10 @@ const configList = [
label: '工种配置',
value: 'workforceAllocation',
},
// {
// label: '负载权限配置',
// value: 'workloadPermission',
// },
{
label: '其他配置',
value: 'other',

View File

@@ -951,10 +951,9 @@ const getSubmitParamFun = async (appPath: any) => {
const taskPostCmdParam = {
'pptx.py': '',
};
const { fileIds, fileNames, taskCmdParam }: any = await getNodeFileIdAndNames();
const { fileIds, fileNames, taskCmdParam, nodeExeCommand }: any = await getNodeFileIdAndNames();
const fileType = await getfileTypeList();
const uploadId = flowNodeData.value.userParams.outputDirId.toString();
const uploadId = flowNodeData.value.outputDirId.toString();
const owner = getUserData()?.nickname;
const tenantId = getUserTenantId().toString();
const userId = getUserId().toString();
@@ -988,11 +987,37 @@ const getSubmitParamFun = async (appPath: any) => {
subRunId,
asyncTaskId,
outputFormat,
nodeExeCommand,
};
};
const getNodeFileIdAndNames = async () => {
const dirId = flowNodeData.value.userParams.inputDirId;
let nodeExeCommand = flowNodeParamData.value.nodeExeCommand;
const params = nodeExeCommand.split(' ').filter((item: any) => {
return item.startsWith('$');
});
for (let i = 0; i < params.length; i++) {
for (const key in flowNodeData.value.userParams) {
if (params[i].includes(key)) {
// 1.字符串
if (flowNodeData.value.userParams[key] instanceof String) {
nodeExeCommand = nodeExeCommand.replace(params[i], flowNodeData.value.userParams[key]);
} else if (flowNodeData.value.userParams[key] instanceof Array) {
// 2.数组
const names = flowNodeData.value.userParams[key]
.map((item: any) => {
const name = item.split('/').at(-1);
return name;
})
?.join(',');
nodeExeCommand = nodeExeCommand.replace(params[i], `./${names}`);
}
}
}
}
const fileIds: any = [];
const fileNames: any = [];
const taskCmdParam: any = {};
@@ -1053,12 +1078,14 @@ const getNodeFileIdAndNames = async () => {
fileIds,
fileNames,
taskCmdParam,
nodeExeCommand,
};
} else {
return {
fileIds,
fileNames,
taskCmdParam,
nodeExeCommand,
};
}
} catch {
@@ -1066,6 +1093,7 @@ const getNodeFileIdAndNames = async () => {
fileIds,
fileNames,
taskCmdParam,
nodeExeCommand,
};
}
};