新增角色管理查询列表,角色新增编辑表单设计

This commit is contained in:
dzl 2025-05-09 16:37:41 +08:00
parent c658905698
commit e1170d9f62
6 changed files with 611 additions and 114 deletions

View File

@ -54,31 +54,44 @@ const pages = [
icon: () => h(GatewayOutlined),
path: '/Urban',
name: '城市管理',
children: [{
path: '/OperateRegion',
name: '运营区域',
isMenu: true
},
{
path: '/OperateRegionAdd',
name: '运营区新增',
isMenu: false
}
children: [
{
path: '/OperateRegion',
name: '运营区域',
isMenu: true
},
{
path: '/SiteManage',
name: '站点列表',
isMenu: true
},
{
path: '/OperateRegionAdd',
name: '运营区新增',
isMenu: false
}
]
},
{
icon: () => h(GatewayOutlined),
path: '/SysManage',
name: '系统管理',
children: [{
path: '/OrgManage',
name: '品牌商管理',
isMenu: true
},{
path: '/PermManage',
name: '权限管理',
isMenu: true
}
children: [
{
path: '/OrgManage',
name: '品牌商管理',
isMenu: true
},
{
path: '/PermManage',
name: '菜单管理',
isMenu: true
},
{
path: '/RoleManage',
name: '角色管理',
isMenu: true
}
]
}
]

View File

@ -53,12 +53,20 @@
<div class="topAvatar">
<template v-if="userdfrname != '' && username != 'admin'">
<a-dropdown>
<a class="ant-dropdown-link" @click.prevent>
当前区域{{ userdfrname }} <DownOutlined />
<a
class="ant-dropdown-link"
@click.prevent
>
当前区域{{ userdfrname }}
<DownOutlined />
</a>
<template #overlay>
<a-menu @click="onOperationClick">
<a-menu-item v-for="(item) in useroperation" :key="item.regionId" :data="item">{{ item.regionName }}</a-menu-item>
<a-menu-item
v-for="(item) in useroperation"
:key="item.regionId"
:data="item"
>{{ item.regionName }}</a-menu-item>
</a-menu>
</template>
</a-dropdown>
@ -139,21 +147,19 @@ onMounted(() => {
router.push('/login');
return;
}
console.log('isLogin', isLogin.value)
//
const userinfo = getCache('ebike-userinfo');
console.log('userinfo', userinfo)
username.value = userinfo.username ? userinfo.username : 'X'
//
const cuseroperation = getCache('ebike-useroperation');
if(cuseroperation){
if (cuseroperation) {
useroperation.value = cuseroperation;
}
//
const cuserdefultoperation = getCache('ebike-userdefultoperation');
if(cuserdefultoperation){
if (cuserdefultoperation) {
userdfrname.value = cuserdefultoperation.regionName ? cuserdefultoperation.regionName : '';
}
@ -209,11 +215,11 @@ const cancel = (e) => {
}
const onOperationClick = (e) => {
if(e.item && e.item.data){
if (e.item && e.item.data) {
const regionName = e.item.data.regionName;
userdfrname.value = regionName;
//
setCache('ebike-userdefultoperation', e.item.data);
setCache('ebike-userdefultoperation', e.item.data);
}
}

View File

@ -0,0 +1,206 @@
<template>
<a-form
:label-col="{ xl: 7, lg: 5, md: 7, sm: 4 }"
:wrapper-col="{ xl: 17, lg: 19, md: 17, sm: 20 }"
>
<a-row :gutter="8">
<a-col
:xl="6"
:lg="12"
:md="12"
:sm="24"
:xs="24"
>
<a-form-item label="区域名称">
<a-input
v-model:value.trim="queryform.roleName"
placeholder="请输入区域名称"
allow-clear
></a-input>
</a-form-item>
</a-col>
<a-col
:xl="6"
:lg="12"
:md="12"
:sm="24"
:xs="24"
>
<a-form-item
class="ele-text-right"
:wrapper-col="{ span: 24 }"
>
<a-space>
<a-button
type="primary"
style="background-color: #5cc750"
@click="search"
>查询</a-button>
<!-- <a-button>重置</a-button> -->
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
<!-- 数据操作 -->
<a-space style="margin-bottom: 10px">
<a-button
style="background-color: #5cc750"
type="primary"
class="ele-btn-icon"
@click="handleAdd('新增角色')"
>
<template #icon>
<plus-outlined />
</template>
<span>新增</span>
</a-button>
</a-space>
<a-table
bordered
:pagination="pagination"
:columns="columns"
:dataSource="dataSource"
:scroll="{ x: 'max-content' }"
>
<template #bodyCell="{ column }">
<template v-if="column.key === 'action'">
<a-space>
<a>排序</a>
<a-divider type="vertical" />
<a @click="handleAdd('编辑角色')">编辑</a>
<a-divider type="vertical" />
<a>删除</a>
</a-space>
</template>
</template>
</a-table>
<!-- 角色信息 -->
<a-modal
v-model:open="open"
:title="openTitle"
@ok="handleOkModal"
@cancel="handleCancelModal"
width="800px"
:maskClosable="false"
>
<RoleManage ref="formModel"></RoleManage>
</a-modal>
</template>
<script setup>
import { ref, onMounted, reactive,nextTick } from 'vue';
import { message } from 'ant-design-vue'
import { callUser } from '@/apis/call.js'
import config from '@/utils/config.js'
import RoleManage from '@/views/form/rolemanage/RoleManage.vue';
const open = ref(false);
const openTitle = ref('');
const formModel = ref(null);
const columns = [
{
title: '品牌商名称',
dataIndex: 'orgName',
width: 200,
key: 'orgName',
align: 'center'
},
{
title: '角色名称',
dataIndex: 'roleName',
width: 200,
key: 'roleName',
align: 'center'
},
{
title: '角色描述',
dataIndex: 'roleDescription',
width: 200,
key: 'roleDescription',
align: 'center'
},
{
title: '员工数量',
dataIndex: 'staffCount',
width: 200,
key: 'staffCount',
align: 'center'
},
{
title: 'PC权限数量',
dataIndex: 'webCount',
width: 200,
key: 'webCount',
align: 'center'
},
{
title: '小程序权限数量',
dataIndex: 'appletCount',
width: 200,
key: 'appletCount',
align: 'center'
},
{
title: '操作',
key: 'action',
width: 200,
align: 'center',
fixed: 'right',
}
];
const queryform = ref({
roleName: '',
pageNum: config.pageParam.pageNum,
pageSize: config.pageParam.pageSize
})
//
const dataSource = ref([])
let pagination = reactive({
total: dataSource.value.length,
current: config.pageParam.pageNum,
pageSize: config.pageParam.pageSize,
showSizeChanger: true,
pageSizeOptions: config.pageParam.pageSizeOptions,
showQuickJumper: true
})
onMounted(() => {
getData();
})
const search = () => {
getData()
}
const getData = async () => {
callUser("/roles/pageQueryRoles", queryform.value).then((res) => {
if (res.code != 200) {
message.error(res.message)
dataSource.value = []
return
}
dataSource.value = res.data.records
});
}
const handleAdd = async (title) => {
openTitle.value = title;
open.value = true;
nextTick(() => {
if (formModel.value) {
formModel.value.openForm({});
} else {
console.log('formModel is not ready yet');
}
});
}
const handleCancelModal = () => {
formModel.value.resetAll(bres => {
if(bres) open.value = false;
});
}
</script>

View File

@ -113,7 +113,7 @@
<SettingOutlined style="margin-right: 5px" />{{ column.title }}
</template>
</template>
<template #bodyCell="{ column, record }">
<template #bodyCell="{ column }">
<template v-if="column.key === 'action'">
<a-space>
<a>详情</a>
@ -190,75 +190,96 @@ const columns = ref([
dataIndex: 'typeName'
},
{
key: 'regionName',
key: 'operationRegionName',
title: '运营区域',
width: 150,
align: 'center',
dataIndex: 'regionName'
dataIndex: 'operationRegionName'
},
{
key: 'simpleName',
title: '区域简称',
key: 'siteName',
title: '站点名称',
width: 150,
align: 'center',
dataIndex: 'simpleName'
dataIndex: 'siteName'
},
{
key: 'inOperation',
title: '运营状态',
title: '站点级别',
width: 150,
align: 'center',
dataIndex: 'inOperation'
},
{
key: 'regionRank',
title: '区域级别',
width: 150,
title: '站点地址',
width: 300,
align: 'center',
dataIndex: 'regionRank'
},
{
key: 'regionCode',
title: '区域编码',
title: '负责人',
width: 150,
align: 'center',
dataIndex: 'regionCode'
},
{
key: 'siteCount',
title: '站点数量',
title: '实时车辆',
width: 150,
align: 'center',
dataIndex: 'siteCount'
},
{
key: 'freeDuration',
title: '免费时长',
title: '可调入/调出',
width: 150,
align: 'center',
dataIndex: 'freeDuration'
},
{
key: 'billingStandard',
title: '计费标准',
title: '累计借车量',
width: 200,
align: 'center',
dataIndex: 'billingStandard'
},
{
key: 'dispatchFee',
title: '运调度费(元)',
title: '累计还车量',
width: 250,
align: 'center',
dataIndex: 'dispatchFee'
},
{
key: 'cappedAmount',
title: '封顶金额(元)',
title: '累计调入量',
width: 150,
align: 'center',
dataIndex: 'cappedAmount'
},
{
key: 'createdAt',
title: '累计调出量',
width: 150,
align: 'center',
dataIndex: 'createdAt'
},
{
key: 'createdAt',
title: '规范停车',
width: 350,
align: 'center',
dataIndex: 'createdAt'
},
{
key: 'createdAt',
title: '站点标签',
width: 200,
align: 'center',
dataIndex: 'createdAt'
},
{
key: 'createdAt',
title: '创建时间',
@ -266,6 +287,13 @@ const columns = ref([
align: 'center',
dataIndex: 'createdAt'
},
{
key: 'createdAt',
title: '更新时间',
width: 150,
align: 'center',
dataIndex: 'createdAt'
},
{
title: '操作',
key: 'action',

View File

@ -16,7 +16,31 @@
required
:rules="[{ required: true, message: '请输入权限名称' }]"
>
<a-input v-model:value="form.description" placeholder="请输入权限名称" />
<a-input
v-model:value="form.description"
placeholder="请输入权限名称"
/>
</a-form-item>
</a-col>
</a-row>
<a-row>
<a-col :span="24">
<a-form-item
label="菜单类型"
:label-col="{ span: 3 }"
:wrapper-col="{ span: 21 }"
name="permType"
>
<a-select
v-model:value="form.permType"
placeholder="请选择菜单类型"
>
<a-select-option
v-for="(item) in permTypeList"
:key="item.id"
:value="item.id"
>{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
@ -28,14 +52,9 @@
:wrapper-col="{ span: 21 }"
name="parentId"
>
<a-input
style="display: none;"
v-model:value="form.parentId"
/>
<a-cascader
v-model:value="parentValues"
v-model:value="form.parentId"
:options="parentOptions"
:load-data="loadParentData"
change-on-select
placeholder="请选择父级权限"
@change="changeParent"
@ -53,26 +72,37 @@
required
:rules="[{ required: true, message: '请输入权限编码' }]"
>
<a-input v-model:value="form.code" placeholder="请输入权限编码" :addon-before="form.pcode" />
<a-input
v-model:value="form.code"
placeholder="请输入权限编码"
:addon-before="form.pcode"
/>
</a-form-item>
</a-col>
</a-row>
<a-row>
<a-col :xs="24">
<a-form-item
label="类型"
:label-col="{ span: 3 }"
:wrapper-col="{ span: 21 }"
name="type"
required
:rules="[{ required: true, message: '请选择类型' }]"
<a-col :xs="24">
<a-form-item
label="类型"
:label-col="{ span: 3 }"
:wrapper-col="{ span: 21 }"
name="type"
required
:rules="[{ required: true, message: '请选择类型' }]"
>
<a-select
v-model:value="form.type"
placeholder="请选择类型"
>
<a-select v-model:value="form.type" placeholder="请选择类型">
<a-select-option v-for="(item) in typeList" :key="item.id" :value="item.id">{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-select-option
v-for="(item) in typeList"
:key="item.id"
:value="item.id"
>{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
</a-form>
</template>
@ -80,7 +110,7 @@
import { ref } from 'vue'
import { callUser } from '@/apis/call.js'
import { message } from 'ant-design-vue'
import { dataFormat } from '@/utils/tools'
import _ from 'lodash'
const formRef = ref();
const formData = () => ({
@ -91,7 +121,8 @@ const formData = () => ({
parentId: "",
type: "",
pcode: "",
code: ""
code: "",
permType: null
});
const form = ref(formData());
const data = ref([]);
@ -100,16 +131,26 @@ const parentOptions = ref([])
const typeList = ref([{
id: 0,
name: '最高权限'
},{
}, {
id: 1,
name: '页面权限'
},{
}, {
id: 2,
name: '按钮权限'
},{
}, {
id: 3,
name: '接口权限'
}])
const permTypeList = ref([{
id: 0,
name: '全系统'
}, {
id: 1,
name: 'PC端'
}, {
id: 2,
name: '小程序端'
}])
const openForm = (params = {}) => {
form.value = {
@ -120,24 +161,24 @@ const openForm = (params = {}) => {
const loadPermData = (permId) => {
if (permId) {
callUser("/permissions/getInfo/"+ permId, {}, "get").then(res => {
callUser("/permissions/getInfo/" + permId, {}, "get").then(res => {
if (res.code == 200) {
if (res.data) {
form.value = {
...res.data
};
const permCode = res.data.permCode;
if(res.data.parentId === null || res.data.parentId === undefined){
if (res.data.parentId === null || res.data.parentId === undefined) {
form.value.code = permCode;
form.value.pcode = "";
}
else
{
else {
form.value.code = permCode.substring(permCode.lastIndexOf('.') + 1);
form.value.pcode = permCode.substring(0, permCode.lastIndexOf('.'));
}
if(parentOptions.value.length > 0){
if (parentOptions.value.length > 0) {
parentValues.value = getParentValues(parentOptions.value, res.data.permId);
form.value.parentId = parentValues.value
console.log(parentValues.value)
}
}
@ -151,11 +192,11 @@ const loadPermData = (permId) => {
function getParentValues(tree, targetId, path = []) {
for (const node of tree) {
if (node.permId === targetId) {
return path;
return path;
}
if (node.children) {
const result = getParentValues(node.children, targetId, [...path, node.permId]);
if (result) return result;
if (result) return result;
}
}
return null; //
@ -163,7 +204,7 @@ function getParentValues(tree, targetId, path = []) {
const loadParentData = (params) => {
parentOptions.value = [];
callUser("/permissions/list", {},"get").then((res) => {
callUser("/permissions/list", {}, "get").then((res) => {
if (res.code != 200) {
message.error(res.message)
parentOptions.value = []
@ -191,12 +232,12 @@ const buildTreeWithChildren = (data) => {
data.forEach(item => {
const child = map.get(item.permId);
if (item.parentId === null || item.parentId === undefined) {
roots.push(child);
roots.push(child);
} else {
const parent = map.get(item.parentId);
if (parent) {
parent.children = parent.children || [];
parent.children.push(child);
parent.children.push(child);
} else {
roots.push(child);
}
@ -206,41 +247,41 @@ const buildTreeWithChildren = (data) => {
}
const changeParent = (data) => {
console.log(data)
const item = findItemByValue(parentOptions.value, data[data.length - 1]);
form.value.permCode = item.permCode
}
const formSave = (callBack) => {
formRef.value.validate().then(() => {
let params = {
orgId: "",
orgName: "",
orgCode: "",
createdTime: dataFormat(new Date(),'yyyy-MM-dd HH:mm:ss'),
const findItemByValue = (options, value) => {
for (const option of options) {
if (option.permId == value) {
return option;
}
if (form.value.orgId) {
params = {
...form.value
if (option.children) {
const found = findItemByValue(option.children, value);
if (found) {
return found;
}
callUser("/organizations/update", params).then(res => {
if (res.code != 200) {
message.error(res.message);
if (callBack) {
callBack(false, res);
}
return;
}
if (callBack) {
callBack(true, res);
}
resetAll();
}).catch(error => {
if (callBack) {
callBack(false, error);
}
});
}
else {
callUser("/organizations/save", params).then(res => {
if (res.code!= 200) {
}
return null;
}
const formSave = (callBack) => {
formRef.value.validate().then((res) => {
const data = _.cloneDeep(res);
let params = {
...data,
parentId: !Array.isArray(data['parentId']) ? data['parentId'] : data['parentId'][data['parentId'].length - 1],
level: data['parentId'].length == 0 ? 1 : data['parentId'].length + 1,
permCode: form.value.permCode + "." + data['code'].toLowerCase()
}
delete params['code']
if (form.value.permId) {
params['permId'] = form.value.permId;
params['permCode'] = form.value.pcode + "." + form.value.code;
callUser("/permissions/update", params).then(res => {
if (res.code != 200) {
message.error(res.message);
if (callBack) {
callBack(false, res);
@ -250,14 +291,33 @@ const formSave = (callBack) => {
if (callBack) {
callBack(true, res);
}
resetAll();
resetAll();
}).catch(error => {
if (callBack) {
callBack(false, error);
}
});
});
}
});
else {
callUser("/permissions/save", params).then(res => {
if (res.code != 200) {
message.error(res.message);
if (callBack) {
callBack(false, res);
}
return;
}
if (callBack) {
callBack(true, res);
}
resetAll();
}).catch(error => {
if (callBack) {
callBack(false, error);
}
});
}
});
};
const resetAll = (callBack) => {

View File

@ -0,0 +1,184 @@
<template>
<a-form
:model="form"
ref="formRef"
label-align="left"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 18 }"
>
<a-row>
<a-col :span="24">
<a-form-item
label="角色名称"
:label-col="{ span: 4 }"
:wrapper-col="{ span: 12 }"
name="roleName"
required
:rules="[{ required: true, message: '请输角色名称' }]"
>
<a-input
v-model:value="form.roleName"
placeholder="请输角色名称"
/>
</a-form-item>
</a-col>
</a-row>
<a-row>
<a-col :span="24">
<a-form-item
label="角色描述"
:label-col="{ span: 4 }"
:wrapper-col="{ span: 12 }"
name="roleDescription"
>
<a-input
v-model:value="form.roleDescription"
placeholder="请输入角色描述"
/>
</a-form-item>
</a-col>
</a-row>
<a-row>
<a-col :span="24">
<a-form-item
label="菜单权限配置"
:label-col="{ span: 4 }"
:wrapper-col="{ span: 21 }"
name="roleDescription"
>
<a-tabs
v-model:activeKey="activeKey"
@click="clickTab"
>
<a-tab-pane
key="1"
tab="运营后台"
>
<div style="border: solid 1px #ddd;margin-top: -15px;">
<a-tree
v-if="treeDataByWeb.length"
defaultExpandAll
v-model:checkedKeys="checkedKeys"
@check="checkNode"
v-model:tree-data="treeDataByWeb"
checkable
>
<template #title="{ description }">
{{ description }}
</template>
</a-tree>
</div>
</a-tab-pane>
<a-tab-pane
key="2"
tab="运维小程序"
force-render
>
<div style="border: solid 1px #ddd;margin-top: -15px;">
<a-tree
v-if="treeDataByApplet.length"
v-model:checkedKeys="checkedKeys"
@check="checkNode"
:tree-data="treeDataByApplet"
defaultExpandAll
checkable
>
<template #title="{ description }">
{{ description }}
</template>
</a-tree>
</div>
</a-tab-pane>
</a-tabs>
</a-form-item>
</a-col>
</a-row>
</a-form>
</template>
<script setup>
import { ref } from 'vue'
import { callUser } from '@/apis/call.js'
import { message } from 'ant-design-vue'
import _ from 'lodash'
const formRef = ref();
const form = ref({});
const activeKey = ref("1")
const checkedKeys = ref([])
const treeDataByWeb = ref([])
const treeDataByApplet = ref([])
const treeDataList = ref([])
const openForm = (params = {}) => {
loadData(params);
};
const loadData = () => {
callUser("/permissions/list", {}, "get").then((res) => {
if (res.code != 200) {
message.error(res.message)
treeData.value = []
return
}
const dataList = res.data.map((item) => {
return { ...item, key: item.permId }
})
treeDataList.value = dataList;
const newDataList = buildTreeWithChildren(dataList, 1)
treeDataByWeb.value = [{ description: "全部", key: "all", children: [...newDataList] }]
});
}
const clickTab = (e) => {
debugger
}
const checkNode = (checkNodes) => {
debugger
}
const buildTreeWithChildren = (data, where) => {
const map = new Map();
const roots = [];
data.forEach(item => {
map.set(item.permId, { ...item });
});
data.forEach(item => {
if (item['permType'] == where) {
const child = map.get(item.permId);
child.code = child.permCode;
if (item.parentId === null || item.parentId === undefined) {
roots.push(child);
} else {
const parent = map.get(item.parentId);
if (parent) {
parent.children = parent.children || [];
child.code = child.permCode.replace(parent.permCode + ".", '');
parent.children.push(child);
} else {
roots.push(child);
}
}
}
});
return roots;
}
const formSave = (callBack) => {
formRef.value.validate().then((res) => {
});
};
const resetAll = (callBack) => {
formRef.value.resetFields();
if (callBack) {
callBack(true, form.value);
}
}
defineExpose({ openForm, formSave, resetAll });
</script>