用户管理里面添加过鱼设施权限管理功能

This commit is contained in:
王兴凯 2026-04-21 10:14:16 +08:00
parent 5528f413a2
commit 60ad0f357a
3 changed files with 494 additions and 19 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

View File

@ -5,7 +5,7 @@ export default {
</script> </script>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, nextTick } from "vue"; import { ref, onMounted, nextTick, watch } from "vue";
import { import {
getTreelist, getTreelist,
gettableData, gettableData,
@ -20,6 +20,7 @@ import {
import { ElMessageBox, ElMessage } from "element-plus"; import { ElMessageBox, ElMessage } from "element-plus";
import { useAppStore } from '@/store/modules/app'; import { useAppStore } from '@/store/modules/app';
import Page from '@/components/Pagination/page.vue' import Page from '@/components/Pagination/page.vue'
import { Search } from '@element-plus/icons-vue'
// import { constant } from "lodash"; // import { constant } from "lodash";
// //
interface Tree { interface Tree {
@ -40,6 +41,7 @@ const total = ref()
const treedata: any = ref([]); const treedata: any = ref([]);
const dialog = ref(false) const dialog = ref(false)
const treeRef = ref(); const treeRef = ref();
const fishTreeRef = ref();
const infoForm = ref(); const infoForm = ref();
// //
const treeloading = ref(true) const treeloading = ref(true)
@ -56,7 +58,7 @@ function getTree() {
}); });
getdata() getdata()
}) })
.catch((error:any)=>{ .catch((error: any) => {
treeloading.value = false treeloading.value = false
}) })
@ -266,6 +268,370 @@ function setpassword(row: any) {
}) })
userid.value = row.id userid.value = row.id
} }
//
const fishway = ref(false)
const userId = ref('')
// ID
const fishhui = ref<any[]>([])
const fishTreeDialog = ref(false)
function openFishway(row: any) {
fishway.value = true
userId.value = row.id
//
getFishTree()
// watch
}
// fishway,
watch(fishway, (newVal) => {
if (newVal) {
// dialog,tree
setTimeout(() => {
console.log('开始回显, fishTreeRef:', fishTreeRef.value);
console.log('回显ID:', fishhui.value);
if (fishTreeRef.value && fishhui.value.length > 0) {
//
fishTreeRef.value.setCheckedKeys([], false);
// ,
setTimeout(() => {
fishTreeRef.value.setCheckedKeys(fishhui.value, false);
//
const checkedKeys = fishTreeRef.value.getCheckedKeys();
const halfCheckedKeys = fishTreeRef.value.getHalfCheckedKeys();
console.log('回显完成 - 全选节点:', checkedKeys);
console.log('回显完成 - 半选节点:', halfCheckedKeys);
}, 100);
}
}, 500);
} else {
//
console.log('关闭对话框,清理数据');
fishhui.value = [];
// tree
setTimeout(() => {
if (fishTreeRef.value) {
fishTreeRef.value.setCheckedKeys([], false);
}
}, 300);
}
});
function fishHandleClose() {
fishway.value = false
}
//type
const activeName = ref('1')
//
const isBaseDisabled = ref(false) //
const isCompanyDisabled = ref(false) //
const handleClick = (tab: any, event: any) => {
// tab.props.name
console.log(tab.props.name, event)
activeName.value = tab.props.name
treeInput.value = ''
getFishTree()
}
//
const treeInput = ref('')
const fishProps = {
children: 'children',
label: 'label',
}
const fishData: Tree[] = [
{
id: 1,
label: 'Level one 1',
children: [
{
id: 4,
label: 'Level two 1-1',
children: [
{
id: 9,
label: 'Level three 1-1-1',
},
{
id: 10,
label: 'Level three 1-1-2',
},
],
},
],
},
{
id: 2,
label: 'Level one 2',
children: [
{
id: 5,
label: 'Level two 2-1',
},
{
id: 6,
label: 'Level two 2-2',
},
],
},
{
id: 3,
label: 'Level one 3',
children: [
{
id: 7,
label: 'Level two 3-1',
},
{
id: 8,
label: 'Level two 3-2',
},
],
},
]
//
function getFishTree() {
fishTreeDialog.value = true
const params = {
type: activeName.value,
name: treeInput.value
}
fishTreeDialog.value = false
// fishhui.value = [1, 5];
if (fishhui.value.length > 0 && activeName.value == '1') {
isCompanyDisabled.value = true
} else if (fishhui.value.length > 0 && activeName.value == '2') {
isBaseDisabled.value = true
} else {
isCompanyDisabled.value = false
isBaseDisabled.value = false
}
// console.log('ID:', fishhui.value);
console.log(params)
// getFishTreeData().then((res) => {
// fishData.value = res.data.data
// })
}
// - ID
function getAllChildrenIds(node: any): number[] {
const ids: number[] = [];
if (node.children && node.children.length > 0) {
node.children.forEach((child: any) => {
ids.push(child.id);
if (child.children && child.children.length > 0) {
ids.push(...getAllChildrenIds(child));
}
});
}
return ids;
}
// -
function areAllChildrenChecked(parentNode: any, checkedKeysArray: any[]): boolean {
const allChildrenIds = getAllChildrenIds(parentNode);
if (allChildrenIds.length === 0) {
return false;
}
// IDkeys
return allChildrenIds.every(id => checkedKeysArray.includes(id));
}
// -
function isNodeContainedByOtherParent(nodeId: number, parentIds: number[], allCheckedNodes: any[]): boolean {
// ""
for (const parentId of parentIds) {
const parentNode = allCheckedNodes.find((n: any) => n.id === parentId);
if (parentNode) {
const childrenIds = getAllChildrenIds(parentNode);
// ,true
if (childrenIds.includes(nodeId)) {
return true;
}
}
}
return false;
}
// -
function handleFishCheckChange(checkedNode: any, checkedInfo: any) {
console.log('当前操作的节点:', checkedNode);
console.log('选中的info:', checkedInfo);
const treeInstance = treeRef.value;
if (!treeInstance) return;
// checkedInfo keys
const checkedKeysArray = checkedInfo.checkedKeys || [];
const allCheckedNodes = checkedInfo.checkedNodes || [];
console.log('选中的keys数组:', checkedKeysArray);
console.log('选中的节点数组:', allCheckedNodes);
// ID
const resultIds: number[] = [];
// :""
const fullySelectedParentIds: number[] = [];
const filteredNodeIds = new Set<number>();
allCheckedNodes.forEach((node: any) => {
// ()
if (node.children && node.children.length > 0) {
//
if (areAllChildrenChecked(node, checkedKeysArray)) {
//
fullySelectedParentIds.push(node.id);
// ""
const childrenIds = getAllChildrenIds(node);
childrenIds.forEach(childId => {
filteredNodeIds.add(childId);
});
}
}
});
console.log('全选父节点IDs:', fullySelectedParentIds);
console.log('应过滤的子节点IDs:', Array.from(filteredNodeIds));
// :
// 1. ""()
fullySelectedParentIds.forEach(parentId => {
//
if (!isNodeContainedByOtherParent(parentId, fullySelectedParentIds, allCheckedNodes)) {
resultIds.push(parentId);
}
});
// 2. ()
allCheckedNodes.forEach((node: any) => {
// ,resultIds
if (!filteredNodeIds.has(node.id) && !resultIds.includes(node.id)) {
// :,
if (!isNodeContainedByOtherParent(node.id, fullySelectedParentIds, allCheckedNodes)) {
resultIds.push(node.id);
}
}
});
console.log('最终获取的IDs:', resultIds);
if (resultIds.length > 0 && activeName.value == '1') {
isCompanyDisabled.value = true
} else if (resultIds.length > 0 && activeName.value == '2') {
isBaseDisabled.value = true
} else {
isCompanyDisabled.value = false
isBaseDisabled.value = false
}
// 使resultIds,
// saveFishPermissions(resultIds);
getFishTableData(resultIds)
tableids.value = resultIds
}
//
const fishTableData = ref([
{
name: '过鱼设施权限1',
type: '站点',
id: 'fish_along_point1',
radio: '1'
},
{
name: '过鱼设施权限2',
type: '站点',
id: 'fish_along_point2',
radio: '2'
}, {
name: '过鱼设施权限3',
type: '站点',
id: 'fish_along_point3',
radio: '1'
},
])
const fishDialog = ref(false)
const fishTableSelection = ref([])
//
function getFishTableData(ids: any[]) {
fishDialog.value = true
fishDialog.value = false;
//
// getFishPermissions().then((res: any) => {
// fishTableData.value = res.data
// })
}
//
const tableids:any = ref([])
function handleRadioChange(data: any){
console.log('当前操作的行数据:', data);
ElMessageBox.confirm(`确定要更改此权限为${data.radio == 1 ? '读' : '写'}吗?`, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
ElMessage({
type: "success",
message: "更改成功",
});
})
.catch(() => {
getFishTableData(tableids.value)
});
}
//
function fishDataHandleSelectionChange(val: any) {
console.log('选中的行数据:', val);
fishTableSelection.value = val
}
//
function delFishTable() {
ElMessageBox.confirm("确定移除选中权限吗?", "删除提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
// ID
const selectedIds = fishTableSelection.value.map((item: any) => item.id);
// fishTableDataID
fishTableData.value = fishTableData.value.filter((item: any) => {
return !selectedIds.includes(item.id);
});
ElMessage({
type: "success",
message: "删除成功",
});
//
fishTableSelection.value = [];
})
.catch(() => {
//
});
}
//
function fishSure() {
// fishTableDataID
const ids = fishTableData.value.map((item: any) => item.id);
// userId.value //id
console.log('fishTableData中的所有ID:', ids);
// 使ids
// saveFishPermissions(ids);
}
// //
function delclick(row: any) { function delclick(row: any) {
ElMessageBox.confirm("确定删除此用户吗?", "删除提示", { ElMessageBox.confirm("确定删除此用户吗?", "删除提示", {
@ -370,8 +736,9 @@ const vMove = {
<div class="faulttemplate-box"> <div class="faulttemplate-box">
<aside id="silderLeft"> <aside id="silderLeft">
<el-tree ref="treeRef" :class="useAppStore().size === 'default' ? 'silderLeft-large' : 'silderLeft-default'" <el-tree ref="treeRef" :class="useAppStore().size === 'default' ? 'silderLeft-large' : 'silderLeft-default'"
node-key="id" :data="treedata" :current-node-key="currentNodeKey" :highlight-current="true" :props="defaultProps" v-loading="treeloading" node-key="id" :data="treedata" :current-node-key="currentNodeKey" :highlight-current="true"
@node-click="handleNodeClick" style="height: calc(100vh - 150px); overflow: auto"> :props="defaultProps" v-loading="treeloading" @node-click="handleNodeClick"
style="height: calc(100vh - 150px); overflow: auto">
</el-tree> </el-tree>
<div class="moveBtn" v-move> <div class="moveBtn" v-move>
<div class="moveBtn-line"></div> <div class="moveBtn-line"></div>
@ -380,7 +747,8 @@ const vMove = {
<section class="silderRight"> <section class="silderRight">
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
<div style="margin-bottom:10px;display: flex;display: -webkit-flex; justify-content: space-between;-webkit-justify-content: space-between; width: 100%;"> <div
style="margin-bottom:10px;display: flex;display: -webkit-flex; justify-content: space-between;-webkit-justify-content: space-between; width: 100%;">
<div> <div>
<el-input v-model="queryParams.querystr" placeholder="请输入用户姓名" clearable style="width: 200px" <el-input v-model="queryParams.querystr" placeholder="请输入用户姓名" clearable style="width: 200px"
@keyup.enter="getdata" /> @keyup.enter="getdata" />
@ -406,7 +774,7 @@ const vMove = {
<el-table-column type="index" label="序号" width="70" align="center" /> <el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column prop="nickname" label="用户姓名" width="100"></el-table-column> <el-table-column prop="nickname" label="用户姓名" width="100"></el-table-column>
<!-- <el-table-column prop="avatar" label="头像"></el-table-column> --> <!-- <el-table-column prop="avatar" label="头像"></el-table-column> -->
<el-table-column prop="email" label="邮箱" ></el-table-column> <el-table-column prop="email" label="邮箱"></el-table-column>
<el-table-column prop="phone" label="手机号" min-width="90"></el-table-column> <el-table-column prop="phone" label="手机号" min-width="90"></el-table-column>
<el-table-column prop="username" label="登录账号" width="120"></el-table-column> <el-table-column prop="username" label="登录账号" width="120"></el-table-column>
<!-- <el-table-column prop="custom1" label="登录账号"></el-table-column> --> <!-- <el-table-column prop="custom1" label="登录账号"></el-table-column> -->
@ -417,7 +785,7 @@ const vMove = {
</el-table-column> </el-table-column>
<el-table-column prop="status" label="账号状态" align="center" width="120"> <el-table-column prop="status" label="账号状态" align="center" width="120">
<template #default="scope"> <template #default="scope">
<el-switch v-model="scope.row.status" active-value="1" inactive-value="0" @change="switchChange(scope.row)" <el-switch v-model="scope.row.status" :active-value="1" inactive-value="0" @change="switchChange(scope.row)"
style="margin-right: 4px;"></el-switch> style="margin-right: 4px;"></el-switch>
<span v-if="scope.row.status == 1" style="color:#0099FF">启用</span> <span v-if="scope.row.status == 1" style="color:#0099FF">启用</span>
<span v-else style="color:#D7D7D7">停用</span> <span v-else style="color:#D7D7D7">停用</span>
@ -431,9 +799,13 @@ const vMove = {
</el-table-column> </el-table-column>
<el-table-column fixed="right" label="操作" width="110"> <el-table-column fixed="right" label="操作" width="110">
<template #default="scope"> <template #default="scope">
<span style="display: flex;display: -webkit-flex;justify-content: space-around;-webkit-justify-content: space-around; "> <span
style="display: flex;display: -webkit-flex;justify-content: space-around;-webkit-justify-content: space-around; ">
<img src="@/assets/MenuIcon/lbcz_xg.png" alt="" title="修改" @click="editdepartment(scope.row)" <img src="@/assets/MenuIcon/lbcz_xg.png" alt="" title="修改" @click="editdepartment(scope.row)"
style="cursor: pointer;"> style="cursor: pointer;">
<!-- frontend/src/assets/components/fish.png -->
<img src="@/assets/components/fish.png" alt="" title="过鱼设施权限维护" @click="openFishway(scope.row)"
style="cursor: pointer;">
<img src="@/assets/MenuIcon/lbcz_czmm.png" alt="" title="重置密码" @click="setpassword(scope.row)" <img src="@/assets/MenuIcon/lbcz_czmm.png" alt="" title="重置密码" @click="setpassword(scope.row)"
style="cursor: pointer;"> style="cursor: pointer;">
<img src="@/assets/MenuIcon/lbcz_sc.png" alt="" title="删除" @click="delclick(scope.row)" <img src="@/assets/MenuIcon/lbcz_sc.png" alt="" title="删除" @click="delclick(scope.row)"
@ -442,7 +814,9 @@ const vMove = {
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<Page :total="total" v-model:size="queryParams.size" v-model:current="queryParams.current" @pagination="getdata()" ></Page> <Page :total="total" v-model:size="queryParams.size" v-model:current="queryParams.current"
@pagination="getdata()">
</Page>
</section> </section>
<!-- 用户 弹框--> <!-- 用户 弹框-->
<el-dialog v-model="dialogVisible" :close-on-click-modal="false" :before-close="handleClose" :title="title" <el-dialog v-model="dialogVisible" :close-on-click-modal="false" :before-close="handleClose" :title="title"
@ -451,30 +825,117 @@ const vMove = {
<el-form-item label="用户姓名" prop="nickname"> <el-form-item label="用户姓名" prop="nickname">
<el-input v-model="info.nickname" style="width: 100%" placeholder="请输入用户姓名"></el-input> <el-input v-model="info.nickname" style="width: 100%" placeholder="请输入用户姓名"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="联系邮箱" > <el-form-item label="联系邮箱">
<el-input v-model="info.email" style="width: 100%" placeholder="请输入联系邮箱"></el-input> <el-input v-model="info.email" style="width: 100%" placeholder="请输入联系邮箱"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="联系电话" > <el-form-item label="联系电话">
<el-input v-model="info.phone" style="width: 100%" placeholder="请输入联系电话"></el-input> <el-input v-model="info.phone" style="width: 100%" placeholder="请输入联系电话"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="登录账号" prop="username"> <el-form-item label="登录账号" prop="username">
<el-input v-model="info.username" style="width: 100%" placeholder="请输入登录账号"></el-input> <el-input v-model="info.username" style="width: 100%" placeholder="请输入登录账号"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="所属角色" > <el-form-item label="所属角色">
<el-select v-model="info.roleinfo" placeholder=" " style="width: 100%" multiple> <el-select v-model="info.roleinfo" placeholder=" " style="width: 100%" multiple>
<el-option v-for="item in rolesdata" :key="item.id" :label="item.rolename" :value="item.id" /> <el-option v-for="item in rolesdata" :key="item.id" :label="item.rolename" :value="item.id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-form> </el-form>
<span class="dialog-footer" style="display: flex;display: -webkit-flex; justify-content: flex-end;-webkit-justify-content: flex-end;"> <span class="dialog-footer"
style="display: flex;display: -webkit-flex; justify-content: flex-end;-webkit-justify-content: flex-end;">
<el-button @click="handleClose"> </el-button> <el-button @click="handleClose"> </el-button>
<el-button type="primary" @click="confirmClick(infoForm)">保存</el-button> <el-button type="primary" @click="confirmClick(infoForm)">保存</el-button>
</span> </span>
</el-dialog> </el-dialog>
<!-- 过鱼设施权限维护 -->
<el-dialog v-model="fishway" :close-on-click-modal="false" :before-close="fishHandleClose" title="过鱼设施权限维护"
append-to-body width="1600px" draggable>
<el-scrollbar height="628px">
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
<el-tab-pane label="基地" name="1" :disabled="isBaseDisabled"></el-tab-pane>
<el-tab-pane label="公司" name="2" :disabled="isCompanyDisabled"></el-tab-pane>
</el-tabs>
<div class="fishBody">
<div class="fishTree">
<div style="width: 100%;padding: 0px 10px; box-sizing: border-box;">
<el-input v-model="treeInput" style="width: 100%" placeholder="请输入电站名称" clearable
class="input-with-select">
<template #append>
<el-button :icon="Search" @click="getFishTree()" />
</template>
</el-input>
</div>
<el-scrollbar height="500px">
<el-tree ref="fishTreeRef" style="max-width: 300px" :data="fishData" show-checkbox default-expand-all
:v-loading="fishTreeDialog" node-key="id" highlight-current :props="fishProps"
@check="handleFishCheckChange" />
</el-scrollbar>
</div>
<div class="fishTable">
<div class="topTable">
<el-button type="danger" :disabled="fishTableSelection.length == 0" @click="delFishTable">移除权限</el-button>
</div>
<el-table :data="fishTableData" style="width: 100%;" row-key="id" border default-expand-all
:v-loading="fishDialog" @selection-change="fishDataHandleSelectionChange" max-height="500"
:header-cell-style="{ background: 'rgb(250 250 250)', color: ' #383838', height: '50px' }">
<el-table-column type="selection" width="50" align="center" />
<el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column prop="name" label="名称"></el-table-column>
<el-table-column prop="type" label="类型" width="200" align="center">
<template #default="scope">
<span>{{ scope.row.type }}</span>
</template>
</el-table-column>
<el-table-column prop="id" label="权限" align="center" width="200">
<template #default="scope">
<el-radio-group v-model="scope.row.radio" @change="handleRadioChange(scope.row)">
<el-radio value="1" size="large"></el-radio>
<el-radio value="2" size="large"></el-radio>
</el-radio-group>
</template>
</el-table-column>
</el-table>
</div>
</div>
</el-scrollbar>
<span class="dialog-footer"
style="display: flex;display: -webkit-flex; justify-content: flex-end;-webkit-justify-content: flex-end;margin-top: 20px;">
<el-button @click="fishHandleClose"> </el-button>
<el-button type="primary" @click="fishSure">保存</el-button>
</span>
</el-dialog>
</div> </div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
.fishBody {
height: 500px;
width: 100%;
display: flex;
// align-items: center;
justify-content: space-between;
.fishTree {
width: 300px;
height: 542px;
margin-right: 10px;
border-right: #409eff 1px solid;
}
.fishTable {
width: 100%;
height: 100%;
.topTable {
width: 100%;
display: flex;
align-items: center;
justify-content: end;
margin-bottom: 10px;
}
}
}
.silderLeft-default { .silderLeft-default {
:deep(.el-tree-node__label) { :deep(.el-tree-node__label) {
font-size: 16px !important; font-size: 16px !important;
@ -542,6 +1003,21 @@ const vMove = {
display: block; display: block;
} }
.fishTree {
:deep(.el-tree-node.is-current>.el-tree-node__content) {
width: 100%;
height: 40px;
background-color: #ecf5ff !important;
// color: #fff !important;
}
:deep(.el-tree-node__content) {
width: 100% !important;
height: 40px !important;
margin: auto !important;
}
}
:deep(.el-tree-node.is-current>.el-tree-node__content) { :deep(.el-tree-node.is-current>.el-tree-node__content) {
width: 100%; width: 100%;
height: 40px; height: 40px;
@ -554,9 +1030,8 @@ const vMove = {
height: 40px !important; height: 40px !important;
margin: auto !important; margin: auto !important;
} }
.el-message-box{
.el-message-box {
width: 300px !important; width: 300px !important;
} }
</style> </style>