初始版本提交

This commit is contained in:
yaoyn
2024-02-05 09:15:37 +08:00
parent b52d4414be
commit 445292105f
1848 changed files with 236859 additions and 75 deletions

View File

@ -0,0 +1,355 @@
<template>
<BasicModal
wrapClassName="autherizeDialog"
v-bind="$attrs"
@register="registerRoleAuthModal"
:title="t('APP功能授权')"
destroy-on-close
@ok="handleSubmit"
width="90%"
>
<a-row :gutter="[16, 16]" class="h-full">
<a-col :span="6">
<div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">{{
t('系统功能')
}}</div>
<div class="treebox">
<BasicTree
:treeData="treeData"
checkable
ref="treeRef"
@check="handleTreeSelect"
:fieldNames="{ title: 'name', key: 'id' }"
/>
</div>
</a-col>
<a-col :span="6">
<div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">{{
t('按钮权限')
}}</div>
<div class="treebox">
<BasicTree
:treeData="buttonSelectData"
checkable
ref="ButtonRef"
@check="handleButtonSelect"
:fieldNames="{ title: 'name', key: 'id' }"
/>
</div>
</a-col>
<a-col :span="6">
<div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">{{
t('字段权限')
}}</div>
<div class="treebox">
<BasicTree
:treeData="columnSelectData"
checkable
ref="ColumnRef"
@check="handleColumnSelect"
:fieldNames="{ title: 'name', key: 'id' }"
/>
</div>
</a-col>
<a-col :span="6">
<div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">{{
t('表单权限')
}}</div>
<div class="treebox">
<BasicTree
:treeData="fieldSelectData"
checkable
ref="FieldRef"
@check="handleFieldSelect"
:fieldNames="{ title: 'name', key: 'id' }"
/>
</div>
</a-col>
</a-row>
</BasicModal>
</template>
<script lang="ts">
import { defineComponent, ref, unref, nextTick } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { TreeItem, BasicTree, TreeActionType } from '/@/components/Tree';
import { RoleSetAppAuth, getAppMenuAuth, getAppMenu } from '/@/api/system/role';
import { useMessage } from '/@/hooks/web/useMessage';
import {
getAppMenuButtonList,
getAppMenuColumnList,
getAppMenuFieldList,
} from '/@/api/system/menuButton';
import { cloneDeep } from 'lodash-es';
import { useI18n } from '/@/hooks/web/useI18n';
export default defineComponent({
name: 'SelectUserModal',
components: { BasicModal, BasicTree },
emits: ['success', 'register'],
setup(_, { emit }) {
const { notification } = useMessage();
const { t } = useI18n();
const treeRef = ref<Nullable<TreeActionType>>(null);
const ButtonRef = ref<Nullable<TreeActionType>>(null);
const ColumnRef = ref<Nullable<TreeActionType>>(null);
const FieldRef = ref<Nullable<TreeActionType>>(null);
const treeData = ref<TreeItem[]>([]);
const buttonData = ref<TreeItem[]>([]);
const columnData = ref<TreeItem[]>([]);
const fieldData = ref<TreeItem[]>([]);
const buttonSelectData = ref<TreeItem[]>([]);
const columnSelectData = ref<TreeItem[]>([]);
const fieldSelectData = ref<TreeItem[]>([]);
const btnKeys = ref<string[]>([]);
const colKeys = ref<string[]>([]);
const menuKeys = ref<string[]>([]);
const fieldKeys = ref<string[]>([]);
const btnFilterKeys = ref<string[]>([]);
const colFilterKeys = ref<string[]>([]);
const fieldFilterKeys = ref<string[]>([]);
const rowId = ref('');
function getTree(tree) {
if (!tree) {
return null;
}
return tree;
}
const [registerRoleAuthModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
setModalProps({ confirmLoading: false });
rowId.value = data.id;
treeData.value = await getAppMenu();
buttonData.value = await getAppMenuButtonList();
columnData.value = await getAppMenuColumnList();
fieldData.value = await getAppMenuFieldList();
const authList = await getAppMenuAuth(rowId.value);
menuKeys.value = authList.menuIds || [];
btnKeys.value = authList.buttonIds || [];
colKeys.value = authList.columnIds || [];
fieldKeys.value = authList.formIds || [];
let menuCheckedKey = [];
let btnCheckedKey = [];
let colCheckedKey = [];
let fieldCheckedKey = [];
menuKeys.value.forEach((o) => {
getParentKeys(menuCheckedKey, treeData.value, o);
});
menuKeys.value = menuCheckedKey;
getTree(unref(treeRef)).setCheckedKeys(authList.menuIds);
initTree(menuCheckedKey);
btnKeys.value.forEach((o) => {
getParentKeys(btnCheckedKey, buttonSelectData.value, o);
});
btnKeys.value = btnCheckedKey;
colKeys.value.forEach((o) => {
getParentKeys(colCheckedKey, columnSelectData.value, o);
});
colKeys.value = colCheckedKey;
fieldKeys.value.forEach((o) => {
getParentKeys(fieldCheckedKey, fieldSelectData.value, o);
});
fieldKeys.value = fieldCheckedKey;
nextTick(() => {
getTree(unref(ButtonRef))?.setCheckedKeys(authList.buttonIds);
getTree(unref(ColumnRef))?.setCheckedKeys(authList.columnIds);
getTree(unref(FieldRef))?.setCheckedKeys(authList.formIds);
getTree(unref(ButtonRef)).expandAll(true);
getTree(unref(ColumnRef)).expandAll(true);
getTree(unref(FieldRef)).expandAll(true);
});
getTree(unref(treeRef)).expandAll(true);
});
async function handleSubmit() {
try {
setModalProps({ confirmLoading: true });
await RoleSetAppAuth({
id: rowId.value,
menuIds: menuKeys.value,
buttonIds: btnKeys.value,
columnIds: colKeys.value,
formIds: fieldKeys.value,
});
notification.success({
message: t('提示'),
description: t('功能授权更新成功'),
}); //提示消息
closeModal();
emit('success');
} catch (error) {
setModalProps({ confirmLoading: false });
}
}
function handleButtonSelect(keys, e) {
btnKeys.value = [...e.halfCheckedKeys, ...keys];
}
function handleColumnSelect(keys, e) {
colKeys.value = [...e.halfCheckedKeys, ...keys];
}
function handleFieldSelect(keys, e) {
fieldKeys.value = [...e.halfCheckedKeys, ...keys];
}
function handleTreeSelect(keys, e) {
//keys 所有全选中的key
//e.halfCheckedKeys 所有半选中的
//如果没有半选 就证明全部全选 直接使用keys
//如果有半选需要 使用keys + e.halfCheckedKeys
const menuSelect: string[] = [...e.halfCheckedKeys, ...keys];
initTree(menuSelect);
menuKeys.value = menuSelect;
}
function initTree(menuSelect) {
buttonSelectData.value = [];
columnSelectData.value = [];
fieldSelectData.value = [];
btnFilterKeys.value = [];
colFilterKeys.value = [];
fieldFilterKeys.value = [];
findMenuTree(buttonSelectData.value, treeData.value, menuSelect, 'button');
findMenuTree(columnSelectData.value, treeData.value, menuSelect, 'column');
findMenuTree(fieldSelectData.value, treeData.value, menuSelect, 'field');
getTree(unref(ButtonRef))?.setExpandedKeys(menuSelect);
getTree(unref(ColumnRef))?.setExpandedKeys(menuSelect);
getTree(unref(FieldRef))?.setExpandedKeys(menuSelect);
}
function getParentKeys(checkedKey, arr, keys) {
for (let i = 0; i < arr.length; i++) {
let o = arr[i];
if (o.id == keys) {
checkedKey.push(o.id);
if (o.categoryId > 0 && !checkedKey.includes(o.categoryId)) {
checkedKey.push(o.categoryId);
}
}
if (o.children?.length > 0) {
getParentKeys(checkedKey, o.children, keys);
}
}
}
function findMenuTree(menuSelectTree, treeData, keys, type) {
for (let i = 0; i < treeData.length; i++) {
let o = cloneDeep(treeData[i]);
if (keys.includes(o.id)) {
o.children = [];
menuSelectTree.push(o);
if (treeData[i].children?.length > 0) {
findMenuTree(o.children, treeData[i].children, keys, type);
} else {
let list =
type == 'button'
? buttonData.value
: type == 'column'
? columnData.value
: fieldData.value;
o.children = getAuthData(list, o.id, type);
}
}
}
}
function getAuthData(list, id, type) {
let arr: TreeItem[] = [];
arr = list.filter((o) => {
return o.menuId == id;
});
arr.forEach((o) => {
o.categoryId = o.menuId;
if (type == 'button') {
btnFilterKeys.value.push(o.id);
} else if (type == 'column') {
colFilterKeys.value.push(o.id);
} else {
if (o.children && o.children.length > 0) {
o.children?.forEach((k) => {
fieldFilterKeys.value.push(k.id);
});
}
fieldFilterKeys.value.push(o.id);
}
});
return arr;
}
return {
registerRoleAuthModal,
handleSubmit,
handleTreeSelect,
handleButtonSelect,
handleColumnSelect,
handleFieldSelect,
menuKeys,
treeData,
treeRef,
ButtonRef,
FieldRef,
ColumnRef,
buttonSelectData,
columnSelectData,
fieldSelectData,
t,
};
},
});
</script>
<style lang="less">
.autherizeDialog {
.ant-modal {
top: 20px;
height: calc(100% - 40px) !important;
.ant-modal-content {
height: 100%;
.ant-modal-body {
height: calc(100% - 120px) !important;
.scrollbar__view {
height: 100%;
& > div {
height: 100%;
max-height: none !important;
.ant-col {
height: 100%;
.treebox {
height: calc(100% - 42px);
overflow: auto;
padding-right: 15px;
margin-bottom: 10px;
border-right: solid 1px #ccc;
.vben-tree {
height: auto;
}
}
}
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,162 @@
<template>
<PageLayout
:hasOperationSlot="false"
:searchConfig="searchConfig"
@search="search"
@scroll-height="scrollHeight"
>
<template #search> </template>
<template #right>
<div v-if="data.dataSource.length > 0">
<a-row
:gutter="16"
class="list-box"
:style="{ overflowY: 'auto', maxHeight: tableOptions.scrollHeight + 70 + 'px' }"
:key="data.renderKey"
>
<a-col :span="6" class="item" v-for="(item, index) in data.dataSource" :key="index">
<div class="image"><img :src="item.backgroundUrl" /></div>
<div class="main">
<a-checkbox v-model:checked="item.checked" @change="handleCheck(item)">{{
item.name
}}</a-checkbox>
</div>
</a-col>
</a-row>
<div class="page-box">
<a-pagination
v-model:current="data.pagination.current"
:pageSize="data.pagination.pageSize"
:total="data.pagination.total"
show-less-items
@change="getList"
/>
</div>
</div>
<div v-else>
<EmptyBox />
</div>
</template>
</PageLayout>
</template>
<script lang="ts" setup>
import { onMounted, reactive, watch } from 'vue';
import { DesktopAuthPage } from '/@/api/desktop/model';
import { PageLayout, EmptyBox } from '/@/components/ModalPanel';
import userTableScrollHeight from '/@/hooks/setting/userTableScrollHeight';
import { getRolePageList } from '/@/api/desktop';
import { useI18n } from '/@/hooks/web/useI18n';
const props = defineProps({
checkedIds: { type: Array as PropType<String[]> },
});
const { t } = useI18n();
const emit = defineEmits(['checked']);
watch(
() => props.checkedIds,
() => {
checkItems();
},
{ deep: true },
);
const searchConfig = [
{
field: 'keyword',
label: t('关键字'),
type: 'input',
},
];
const { tableOptions, scrollHeight } = userTableScrollHeight();
let data: {
dataSource: Array<DesktopAuthPage>;
renderKey: number;
keyword: string;
pagination: {
current: number;
total: number;
pageSize: number;
};
} = reactive({
dataSource: [],
renderKey: 0,
pagination: { current: 1, total: 0, pageSize: 8 },
keyword: '',
});
onMounted(() => {
data.pagination.current = 1;
data.dataSource = [];
getList();
});
async function getList() {
let params = {
limit: data.pagination.current,
size: data.pagination.pageSize,
keyword: data.keyword,
};
let res = await getRolePageList(params);
data.dataSource = res.list;
data.pagination.total = res.total;
data.renderKey++;
checkItems();
}
function checkItems() {
data.dataSource.forEach((o) => {
o.checked = false;
if (props.checkedIds?.includes(o.id)) {
o.checked = true;
}
});
}
function search(params?: any) {
data.keyword = params.keyword;
data.pagination.current = 1;
data.dataSource = [];
getList();
}
function handleCheck(item) {
emit('checked', item);
}
</script>
<style lang="less" scoped>
.list-box {
display: flex;
flex-wrap: wrap;
margin: 10px -8px;
.ant-row {
margin: 0 !important;
}
.item {
position: relative;
margin-bottom: 16px;
overflow: hidden;
border-radius: 4px;
}
.image {
width: 100%;
height: 140px;
img {
width: 100%;
height: 100%;
}
}
.main {
font-size: 12px;
text-align: center;
line-height: 40px;
}
}
.page-box {
position: absolute;
bottom: 20px;
right: 20px;
}
</style>

View File

@ -0,0 +1,174 @@
<template>
<BasicModal
v-bind="$attrs"
destroy-on-close
@register="registerModal"
:title="t('首页授权')"
width="1100px"
@ok="handleSubmit"
>
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" :tab="t('首页列表')">
<div class="-mx-8px -mt-10px" v-if="activeKey == '1'"
><HomeList @checked="handleChange" :checkedIds="checkedIds"
/></div>
</a-tab-pane>
<a-tab-pane key="2" :tab="t('已选择')">
<div class="-mx-8px -mt-16px">
<PageLayout
:hasOperationSlot="false"
:hasSearchSlot="false"
@scroll-height="scrollHeight"
>
<template #right>
<div v-if="dataSource.length > 0">
<a-row
:gutter="16"
class="list-box"
:style="{ overflowY: 'auto', maxHeight: tableOptions.scrollHeight + 70 + 'px' }"
>
<a-col :span="6" class="item" v-for="(item, index) in dataSource" :key="index">
<div class="image"><img :src="item.backgroundUrl" /></div>
<div class="main">
<a-checkbox v-model:checked="item.checked" @change="handleChecked(item)">{{
item.name
}}</a-checkbox>
</div>
</a-col>
</a-row>
</div>
<div v-else>
<EmptyBox />
</div>
</template>
</PageLayout>
</div>
</a-tab-pane>
</a-tabs>
</BasicModal>
</template>
<script lang="tsx" setup>
import { ref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import HomeList from './HomeList.vue';
import { useMessage } from '/@/hooks/web/useMessage';
import { PageLayout, EmptyBox } from '/@/components/ModalPanel';
import { addRoleHomeAuth, getRoleHomeAuth } from '/@/api/system/role';
import { useI18n } from '/@/hooks/web/useI18n';
import userTableScrollHeight from '/@/hooks/setting/userTableScrollHeight';
import { DesktopAuthPage } from '/@/api/desktop/model';
const { t } = useI18n();
const activeKey = ref('1');
const emit = defineEmits(['success', 'register']);
const { tableOptions, scrollHeight } = userTableScrollHeight();
const dataSource = ref<DesktopAuthPage[]>([]);
const { notification } = useMessage();
const checkedIds = ref<string[]>([]);
const rowId = ref();
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
setModalProps({ confirmLoading: false });
activeKey.value = '1';
rowId.value = data.id;
let res = await getRoleHomeAuth(data.id);
dataSource.value = [];
checkedIds.value = [];
if (res) {
res.forEach((o) => {
o.checked = true;
dataSource.value.push(o);
checkedIds.value.push(o.id);
});
}
});
async function handleSubmit() {
try {
setModalProps({ confirmLoading: true });
let ids: string[] = [];
dataSource.value.forEach((o) => {
ids.push(o.id);
});
await addRoleHomeAuth(rowId.value, ids);
notification.success({
message: t('首页授权成功'),
description: t('成功'),
}); //提示消息
closeModal();
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
function handleChange(v) {
if (v.checked) {
let obj = dataSource.value.find((o) => {
return o.id == v.id;
});
if (!obj) {
dataSource.value.push(v);
}
} else {
let idx = dataSource.value.findIndex((o) => {
return o.id == v.id;
});
if (idx >= 0) {
dataSource.value.splice(idx, 1);
}
}
}
function handleChecked(v) {
if (!v.checked) {
let idx = dataSource.value.findIndex((o) => {
return o.id == v.id;
});
if (idx >= 0) {
dataSource.value.splice(idx, 1);
}
checkedIds.value = [];
dataSource.value.forEach((o) => {
checkedIds.value.push(o.id);
});
}
}
</script>
<style lang="less" scoped>
.list-box {
display: flex;
flex-wrap: wrap;
margin: 10px -8px;
.ant-row {
margin: 0 !important;
}
.item {
position: relative;
margin-bottom: 16px;
overflow: hidden;
border-radius: 4px;
}
.image {
width: 100%;
height: 140px;
img {
width: 100%;
height: 100%;
}
}
.main {
font-size: 12px;
text-align: center;
line-height: 40px;
}
}
</style>

View File

@ -0,0 +1,419 @@
<template>
<BasicModal
wrapClassName="autherizeDialog"
v-bind="$attrs"
@register="registerRoleAuthModal"
:title="t('功能授权')"
destroy-on-close
@ok="handleSubmit"
width="90%"
>
<a-row :gutter="[16, 16]" class="h-full">
<a-col :span="6">
<div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">{{
t('系统功能')
}}</div>
<div class="treebox">
<BasicTree
:treeData="treeData"
checkable
ref="treeRef"
@check="handleTreeSelect"
:fieldNames="{ title: 'title', key: 'id' }"
>
<template #title="{ title, systemName, parentId }">
<div v-if="parentId == 0">{{ title }} {{ systemName }}</div>
<div v-else>{{ title }}</div>
</template>
</BasicTree>
</div>
</a-col>
<a-col :span="6">
<div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">{{
t('按钮权限')
}}</div>
<div class="treebox">
<BasicTree
:treeData="buttonSelectData"
checkable
ref="ButtonRef"
@check="handleButtonSelect"
:fieldNames="{ title: 'title', key: 'id' }"
/>
</div>
</a-col>
<a-col :span="6">
<div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">{{
t('字段权限')
}}</div>
<div class="treebox">
<BasicTree
:treeData="columnSelectData"
checkable
ref="ColumnRef"
@check="handleColumnSelect"
:fieldNames="{ title: 'title', key: 'id' }"
/>
</div>
</a-col>
<a-col :span="6">
<div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">{{
t('表单权限')
}}</div>
<div class="treebox">
<BasicTree
:treeData="fieldSelectData"
checkable
ref="FieldRef"
@check="handleFieldSelect"
:fieldNames="{ title: 'title', key: 'id' }"
/>
</div>
</a-col>
</a-row>
</BasicModal>
</template>
<script lang="ts">
import { defineComponent, ref, unref, nextTick } from 'vue';
import { getMenuSimpleTree } from '/@/api/system/menu';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { TreeItem, BasicTree, TreeActionType } from '/@/components/Tree';
import { getRoleAuth, RoleSetAuth } from '/@/api/system/role';
import { useMessage } from '/@/hooks/web/useMessage';
import { getMenuButtonList, getMenuColumnList, getMenuFieldList } from '/@/api/system/menuButton';
import { cloneDeep } from 'lodash-es';
import { useI18n } from '/@/hooks/web/useI18n';
export default defineComponent({
name: 'SelectUserModal',
components: { BasicModal, BasicTree },
emits: ['success', 'register'],
setup(_, { emit }) {
const { notification } = useMessage();
const { t } = useI18n();
const treeRef = ref<Nullable<TreeActionType>>(null);
const ButtonRef = ref<Nullable<TreeActionType>>(null);
const ColumnRef = ref<Nullable<TreeActionType>>(null);
const FieldRef = ref<Nullable<TreeActionType>>(null);
const treeData = ref<TreeItem[]>([]);
const buttonData = ref<TreeItem[]>([]);
const columnData = ref<TreeItem[]>([]);
const fieldData = ref<TreeItem[]>([]);
const buttonSelectData = ref<TreeItem[]>([]);
const columnSelectData = ref<TreeItem[]>([]);
const fieldSelectData = ref<TreeItem[]>([]);
const btnKeys = ref<string[]>([]);
const colKeys = ref<string[]>([]);
const menuKeys = ref<string[]>([]);
const fieldKeys = ref<string[]>([]);
const btnFilterKeys = ref<string[]>([]);
const colFilterKeys = ref<string[]>([]);
const fieldFilterKeys = ref<string[]>([]);
const rowId = ref('');
function getTree(tree) {
if (!tree) {
return null;
}
return tree;
}
const [registerRoleAuthModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
setModalProps({ confirmLoading: false });
rowId.value = data.id;
treeData.value = await getMenuSimpleTree();
buttonData.value = await getMenuButtonList();
columnData.value = await getMenuColumnList();
fieldData.value = await getMenuFieldList();
const authList = await getRoleAuth(rowId.value);
menuKeys.value = authList.menuIds || [];
btnKeys.value = authList.buttonIds || [];
colKeys.value = authList.columnIds || [];
fieldKeys.value = authList.formIds || [];
let menuCheckedKey = [];
let btnCheckedKey = [];
let colCheckedKey = [];
let fieldCheckedKey = [];
menuKeys.value.forEach((o) => {
getParentKeys(menuCheckedKey, treeData.value, o);
});
menuKeys.value = menuCheckedKey;
getTree(unref(treeRef)).setCheckedKeys(authList.menuIds);
initTree(menuCheckedKey);
btnKeys.value.forEach((o) => {
getParentKeys(btnCheckedKey, buttonSelectData.value, o);
});
btnKeys.value = btnCheckedKey;
colKeys.value.forEach((o) => {
getParentKeys(colCheckedKey, columnSelectData.value, o);
});
colKeys.value = colCheckedKey;
fieldKeys.value.forEach((o) => {
getParentKeys(fieldCheckedKey, fieldSelectData.value, o);
});
fieldKeys.value = fieldCheckedKey;
nextTick(() => {
getTree(unref(ButtonRef))?.setCheckedKeys(authList.buttonIds);
getTree(unref(ColumnRef))?.setCheckedKeys(authList.columnIds);
getTree(unref(FieldRef))?.setCheckedKeys(authList.formIds);
getTree(unref(ButtonRef)).expandAll(true);
getTree(unref(ColumnRef)).expandAll(true);
getTree(unref(FieldRef)).expandAll(true);
});
getTree(unref(treeRef)).expandAll(true);
});
async function handleSubmit() {
try {
setModalProps({ confirmLoading: true });
//由于树组件的原因,提交之前先过滤一遍,没有选中的不提交
// btnKeys.value = getTree(unref(ButtonRef)).getCheckedKeys();
// colKeys.value = getTree(unref(ColumnRef)).getCheckedKeys();
// fieldKeys.value = getTree(unref(FieldRef)).getCheckedKeys();
// btnKeys.value = btnKeys.value.filter((o) => {
// return btnFilterKeys.value.includes(o);
// });
// colKeys.value = colKeys.value.filter((o) => {
// return colFilterKeys.value.includes(o);
// });
// fieldKeys.value = fieldKeys.value.filter((o) => {
// return fieldFilterKeys.value.includes(o);
// });
await RoleSetAuth({
id: rowId.value,
menuIds: menuKeys.value,
buttonIds: btnKeys.value,
columnIds: colKeys.value,
formIds: fieldKeys.value,
});
notification.success({
message: t('提示'),
description: t('功能授权更新成功'),
}); //提示消息
closeModal();
emit('success');
} catch (error) {
setModalProps({ confirmLoading: false });
}
}
function handleButtonSelect(keys, e) {
btnKeys.value = [...e.halfCheckedKeys, ...keys];
}
function handleColumnSelect(keys, e) {
colKeys.value = [...e.halfCheckedKeys, ...keys];
}
function handleFieldSelect(keys, e) {
fieldKeys.value = [...e.halfCheckedKeys, ...keys];
}
function handleTreeSelect(keys, e) {
//keys 所有全选中的key
//e.halfCheckedKeys 所有半选中的
//如果没有半选 就证明全部全选 直接使用keys
//如果有半选需要 使用keys + e.halfCheckedKeys
const menuSelect: string[] = [...e.halfCheckedKeys, ...keys];
initTree(menuSelect);
menuKeys.value = menuSelect;
}
function initTree(menuSelect) {
buttonSelectData.value = [];
columnSelectData.value = [];
fieldSelectData.value = [];
btnFilterKeys.value = [];
colFilterKeys.value = [];
fieldFilterKeys.value = [];
findMenuTree(buttonSelectData.value, treeData.value, menuSelect, 'button');
findMenuTree(columnSelectData.value, treeData.value, menuSelect, 'column');
findMenuTree(fieldSelectData.value, treeData.value, menuSelect, 'field');
getTree(unref(ButtonRef))?.setExpandedKeys(menuSelect);
getTree(unref(ColumnRef))?.setExpandedKeys(menuSelect);
getTree(unref(FieldRef))?.setExpandedKeys(menuSelect);
}
function getParentKeys(checkedKey, arr, keys) {
for (let i = 0; i < arr.length; i++) {
let o = arr[i];
if (o.id == keys) {
checkedKey.push(o.id);
if (o.parentId > 0 && !checkedKey.includes(o.parentId)) {
checkedKey.push(o.parentId);
}
}
if (o.children?.length > 0) {
getParentKeys(checkedKey, o.children, keys);
}
}
}
function findMenuTree(menuSelectTree, treeData, keys, type) {
for (let i = 0; i < treeData.length; i++) {
let o = cloneDeep(treeData[i]);
if (keys.includes(o.id)) {
o.children = [];
menuSelectTree.push(o);
if (treeData[i].children?.length > 0) {
findMenuTree(o.children, treeData[i].children, keys, type);
} else {
let list =
type == 'button'
? buttonData.value
: type == 'column'
? columnData.value
: fieldData.value;
o.children = getAuthData(list, o.id, type);
}
}
}
}
function getAuthData(list, id, type) {
let arr: TreeItem[] = [];
arr = list.filter((o) => {
return o.menuId == id;
});
arr.forEach((o) => {
o.parentId = o.menuId;
if (type == 'button') {
btnFilterKeys.value.push(o.id);
} else if (type == 'column') {
colFilterKeys.value.push(o.id);
} else {
if (o.children && o.children.length > 0) {
o.children?.forEach((k) => {
fieldFilterKeys.value.push(k.id);
});
}
fieldFilterKeys.value.push(o.id);
}
});
return arr;
}
// function findMenuTree(menuTree, menuSelectTree, keys) {
// let selected: any = {};
// menuTree.forEach((key) => {
// //找到node对象
// if (keys.includes(key.id)) {
// console.log(key, 'kkkkkkkkkk');
// selected = cloneDeep(key);
// if (key.children?.length > 0) {
// selected.children = [];
// findMenuTree(key.children, selected.children, keys);
// }
// }
// });
// // let obj = menuSelectTree.find((o) => {
// // return o.id == selected.id;
// // });
// // if (!obj) {
// // menuSelectTree.push(selected);
// // } else {
// // obj.children = obj.children.concat(selected.children);
// // }
// checkChild(menuSelectTree, selected);
// }
// function checkChild(menuTree, selected) {
// menuTree.forEach((o) => {
// if (o.id == selected.parentId) {
// o.children = o.children.concat(selected.children);
// checkChild(o.children, selected);
// } else {
// menuTree.push(selected);
// }
// });
// }
//将按钮塞入到菜单树
// function menuInsertButton(menuTree, buttonList) {
// menuTree.forEach((menu) => {
// const thisMenuButton = buttonList.filter((btn) => btn.menuId === menu.id);
// if (menu.children && menu.children.length > 0) {
// menuInsertButton(menu.children, buttonList);
// }
// // console.log('thisMenuButton', thisMenuButton);
// menu.children = menu.children?.concat(thisMenuButton);
// });
// }
return {
registerRoleAuthModal,
handleSubmit,
handleTreeSelect,
handleButtonSelect,
handleColumnSelect,
handleFieldSelect,
menuKeys,
treeData,
treeRef,
ButtonRef,
FieldRef,
ColumnRef,
buttonSelectData,
columnSelectData,
fieldSelectData,
t,
};
},
});
</script>
<style lang="less">
.autherizeDialog {
.ant-modal {
top: 20px;
height: calc(100% - 40px) !important;
.ant-modal-content {
height: 100%;
.ant-modal-body {
height: calc(100% - 120px) !important;
.scrollbar__view {
height: 100%;
& > div {
height: 100%;
max-height: none !important;
.ant-col {
height: 100%;
.treebox {
height: calc(100% - 42px);
overflow: auto;
padding-right: 15px;
margin-bottom: 10px;
border-right: solid 1px #ccc;
.vben-tree {
height: auto;
}
}
}
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,117 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit">
<BasicForm @register="registerForm" :style="{ 'margin-right': '10px' }" />
</BasicModal>
</template>
<script lang="tsx" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { FormSchema } from '/@/components/Table';
import { useMessage } from '/@/hooks/web/useMessage';
import { addRole, updateRole } from '/@/api/system/role';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n();
const formSchema: FormSchema[] = [
{
field: 'name',
label: t('角色名称'),
required: true,
component: 'Input',
colProps: { span: 24 },
},
{
field: 'code',
label: t('角色编码'),
required: true,
component: 'Input',
colProps: { span: 24 },
},
{
field: 'enabledMark',
label: t('状态'),
component: 'RadioButtonGroup',
defaultValue: 1,
componentProps: {
options: [
{ label: t('启用'), value: 1 },
{ label: t('停用'), value: 0 },
],
},
colProps: { span: 24 },
},
{
label: t('备注'),
field: 'remark',
component: 'InputTextArea',
colProps: { span: 24 },
},
{
label: ' ',
field: 'authList',
slot: 'menu',
component: 'Input',
colProps: { span: 24 },
},
];
const emit = defineEmits(['success', 'register']);
const { notification } = useMessage();
const isUpdate = ref(true);
const rowId = ref('');
const [registerForm, { setFieldsValue, resetFields, validate }] = useForm({
labelWidth: 100,
schemas: formSchema,
showActionButtonGroup: false,
actionColOptions: {
span: 23,
},
});
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
resetFields();
setModalProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
rowId.value = data.record.id;
setFieldsValue({
...data.record,
});
}
});
const getTitle = computed(() => (!unref(isUpdate) ? t('新增角色') : t('编辑角色')));
async function handleSubmit() {
try {
const values = await validate();
setModalProps({ confirmLoading: true });
// TODO custom api
if (!unref(isUpdate)) {
//false 新增
await addRole(values);
notification.success({
message: t('新增角色'),
description: t('成功'),
}); //提示消息
} else {
values.id = rowId.value;
await updateRole(values);
notification.success({
message: t('编辑角色'),
description: t('成功'),
}); //提示消息
}
closeModal();
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>

View File

@ -0,0 +1,104 @@
<template>
<BasicModal v-bind="$attrs" @register="registerSelectUserModal" @ok="handleSubmit" width="1000px">
<BasicTable @register="registerTable" />
</BasicModal>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
// import { getUserPageList } from '/@/api/system/user';
import { useTable, FormSchema, BasicColumn, BasicTable } from '/@/components/Table';
import { getRoleInterfaceList } from '/@/api/system/role';
import { getAllInterface } from '/@/api/system/interface';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n();
export const searchFormSchema: FormSchema[] = [
{
field: 'keyword',
label: t('关键字'),
component: 'Input',
componentProps: {
placeholder: t('输入接口名称或接口地址搜索'),
},
colProps: { span: 8 },
},
];
export const columns: BasicColumn[] = [
{
title: t('名称'),
dataIndex: 'name',
width: 120,
},
{
title: t('接口地址'),
dataIndex: 'path',
width: 120,
},
{
title: t('请求类型'),
dataIndex: 'method',
width: 120,
},
];
export default defineComponent({
name: 'SelectInterfaceModal',
components: { BasicModal, BasicTable },
props: {
value: {
type: String,
default: '',
},
},
emits: ['success', 'register'],
setup(_, { emit }) {
const roleId = ref<string>();
const selectIds = ref<string[]>([]);
const [registerTable, { setSelectedRowKeys, getSelectRowKeys }] = useTable({
api: getAllInterface,
rowKey: 'id',
columns,
formConfig: {
rowProps: {
gutter: 16,
},
schemas: searchFormSchema,
},
rowSelection: {
type: 'checkbox',
checkStrictly: false,
},
pagination: false,
useSearchForm: true,
showTableSetting: true,
bordered: true,
showIndexColumn: false,
});
const [registerSelectUserModal, { setModalProps, closeModal }] = useModalInner(
async (data) => {
roleId.value = data.id;
setModalProps({ confirmLoading: false, title: data.title });
selectIds.value = await getRoleInterfaceList({ roleId: data.id });
setSelectedRowKeys(selectIds.value || []);
},
);
async function handleSubmit() {
try {
setModalProps({ confirmLoading: true });
const selectRows = getSelectRowKeys();
closeModal();
emit('success', selectRows);
} catch (error) {
setModalProps({ confirmLoading: false });
}
}
return { registerSelectUserModal, registerTable, handleSubmit, t };
},
});
</script>

View File

@ -0,0 +1,404 @@
<template>
<PageWrapper dense fixedHeight contentFullHeight>
<BasicTable @register="registerTable">
<template #toolbar>
<a-button type="primary" v-auth="'role:add'" @click="handleCreate">
{{ t('新增角色') }}
</a-button>
<a-button type="primary" v-auth="'role:addMember'" @click="handleAddUser">
{{ t('添加成员') }}
</a-button>
<a-button type="primary" v-auth="'role:view'" @click="handleViewUser">
{{ t('查看成员') }}
</a-button>
<a-button type="primary" v-auth="'role:functionalAuth'" @click="handleAuth">
{{ t('功能授权') }}
</a-button>
<a-button type="primary" v-auth="'role:functionalAuth'" @click="handleAppAuth">
{{ t('移动端功能授权') }}
</a-button>
<a-button type="primary" v-auth="'role:interfaceAuth'" @click="handleInterfaceAuth">
{{ t('接口授权') }}
</a-button>
<a-button type="primary" v-auth="'role:homeAuth'" @click="handleHomeAuth">
{{ t('首页授权') }}
</a-button>
</template>
<template #action="{ record }">
<TableAction
:actions="[
{
icon: 'clarity:note-edit-line',
auth: 'role:edit',
onClick: handleEdit.bind(null, record),
},
{
icon: 'ant-design:delete-outlined',
auth: 'role:delete',
color: 'error',
popConfirm: {
title: t('是否确认删除'),
confirm: handleDelete.bind(null, record),
},
},
]"
/>
</template>
</BasicTable>
<RoleModal @register="registerRoleModal" @success="handleSuccess" />
<SelectInterfaceModal
@register="registerInterfaceModal"
@success="handleInterfaceSuccess"
:minHeight="500"
/>
<RoleAuthModal
@register="registerRoleAuthModal"
@success="handleRoleAuthSuccess"
:minHeight="500"
/>
<AppAuthModal @register="registerAppAuthModal" :minHeight="500" />
<SelectDepartment
v-if="visible"
:visible="visible"
:multiple="true"
:selectedIds="selectedUserId"
@close="
() => {
visible = false;
}
"
@change="handleSelectUserSuccess"
/>
<AuthModal @register="registerModal" />
<HomeModal @register="registerHomeModal" @success="handleRoleAuthSuccess" :minHeight="500" />
</PageWrapper>
</template>
<script lang="ts">
import { defineComponent, h, ref } from 'vue';
import { BasicTable, useTable, TableAction, FormSchema, BasicColumn } from '/@/components/Table';
import {
getRolePageList,
updateRoleStatus,
deleteRole,
addRoleUser,
getRoleUser,
addRoleInterface,
} from '/@/api/system/role';
import AuthModal from '../dataAuthority/components/AuthModal.vue';
import HomeModal from './components/HomeModal.vue';
import RoleModal from './components/RoleModal.vue';
import SelectInterfaceModal from './components/SelectInterfaceModal.vue';
import RoleAuthModal from './components/RoleAuthModal.vue';
import AppAuthModal from './components/AppAuthModal.vue';
import { SelectDepartment } from '/@/components/SelectOrganizational/index';
import { useMessage } from '/@/hooks/web/useMessage';
import { Switch } from 'ant-design-vue';
import { PageWrapper } from '/@/components/Page';
import { useModal } from '/@/components/Modal';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n();
export const columns: BasicColumn[] = [
{
title: t('角色名称'),
dataIndex: 'name',
sorter: true,
align: 'left',
},
{
title: t('角色编码'),
dataIndex: 'code',
sorter: true,
align: 'left',
},
{
title: t('状态'),
dataIndex: 'enabledMark',
sorter: true,
align: 'left',
customRender: ({ record }) => {
if (!Reflect.has(record, 'pendingStatus')) {
record.pendingStatus = false;
}
return h(Switch, {
checked: record.enabledMark === 1,
checkedChildren: t('已启用'),
unCheckedChildren: t('已禁用'),
loading: record.pendingStatus,
onChange(checked: boolean) {
record.pendingStatus = true;
const newStatus = checked ? 1 : 0;
const { createMessage } = useMessage();
updateRoleStatus(record.id, newStatus)
.then(() => {
record.enabledMark = newStatus;
createMessage.success(t('已成功修改角色状态'));
})
.catch(() => {
createMessage.error(t('修改角色状态失败'));
})
.finally(() => {
record.pendingStatus = false;
});
},
});
},
},
{
title: t('备注'),
dataIndex: 'remark',
sorter: true,
align: 'left',
},
];
export const searchFormSchema: FormSchema[] = [
{
field: 'name',
label: t('角色名称'),
component: 'Input',
colProps: { lg: 8, md: 12, sm: 12 },
},
{
field: 'code',
label: t('角色编码'),
component: 'Input',
colProps: { lg: 8, md: 12, sm: 12 },
},
{
field: 'enabledMark',
label: t('状态'),
component: 'Select',
componentProps: {
options: [
{ label: t('启用'), value: 1 },
{ label: t('停用'), value: 0 },
],
},
colProps: { lg: 8, md: 12, sm: 12 },
},
];
export default defineComponent({
name: 'RoleManagement',
components: {
BasicTable,
RoleModal,
TableAction,
RoleAuthModal,
AuthModal,
SelectDepartment,
SelectInterfaceModal,
PageWrapper,
HomeModal,
AppAuthModal,
},
setup() {
const { notification } = useMessage();
const visible = ref<boolean>(false);
const selectedUserId = ref<string[]>([]);
const [registerRoleAuthModal, { openModal: openRoleUserModal }] = useModal();
const [registerAppAuthModal, { openModal: openAppAuthModal }] = useModal();
const [registerInterfaceModal, { openModal: openInterfaceModal }] = useModal();
const [registerModal, { openModal, setModalProps }] = useModal();
const [registerRoleModal, { openModal: openRoleModal }] = useModal();
const [registerHomeModal, { openModal: openHomeModal }] = useModal();
const [registerTable, { reload, getSelectRows }] = useTable({
title: t('角色列表'),
api: getRolePageList,
columns,
formConfig: {
rowProps: {
gutter: 16,
},
schemas: searchFormSchema,
actionColOptions: { span: 16 },
showResetButton: false,
},
// clickToRowSelect:true,
rowSelection: {
type: 'radio',
},
useSearchForm: true,
showTableSetting: true,
striped: false,
showIndexColumn: false,
actionColumn: {
width: 80,
title: t('操作'),
dataIndex: 'action',
slots: { customRender: 'action' },
fixed: undefined,
},
tableSetting: {
size: false,
setting: false,
},
});
function handleCreate() {
openRoleModal(true, {
isUpdate: false,
});
}
function handleInterfaceAuth() {
let res = warning(true);
if (!res) {
return;
}
openInterfaceModal(true, {
isUpdate: false,
title: t('接口授权') + ' - ' + res.name,
id: res.id,
});
}
function handleAuth() {
let res = warning(true);
if (!res) {
return;
}
openRoleUserModal(true, {
id: res.id,
});
}
function handleAppAuth() {
let res = warning(true);
if (!res) {
return;
}
openAppAuthModal(true, {
id: res.id,
});
}
function handleAddUser() {
let rows = warning();
if (!rows) {
return;
}
getRoleUser(rows.id).then((res) => {
selectedUserId.value = res.map((item) => {
return item.id;
});
console.log(selectedUserId.value);
visible.value = true;
});
}
function warning(isAdminCantUse = false) {
const selectRows = getSelectRows();
if (selectRows.length === 0) {
notification.warning({
message: t('警告'),
description: t('必须选中一行!'),
}); //提示消息
return false;
} else if (isAdminCantUse && selectRows[0].id === '1') {
notification.warning({
message: t('警告'),
description: t('超级管理员不允许授权'),
});
return false;
} else {
return selectRows[0];
}
}
function handleSelectUserSuccess(rows, type) {
const selectRows = getSelectRows();
let paramas;
if (type === 0) {
paramas = { type, id: selectRows[0].id, userIds: rows };
} else {
paramas = { type, id: selectRows[0].id, departmentIds: rows };
}
addRoleUser(paramas).then((_) => {
notification.info({
message: t('添加人员'),
description: t('成功'),
}); //提示消息
});
}
function handleInterfaceSuccess(rows) {
const selectRows = getSelectRows();
addRoleInterface(selectRows[0].id, rows).then((_) => {
notification.info({
message: t('接口授权成功'),
description: t('成功'),
}); //提示消息
});
}
function handleViewUser() {
let rows = warning();
if (!rows) {
return;
}
getRoleUser(rows.id).then((res) => {
openModal(true, res);
setModalProps({ title: t('查看成员') });
});
}
function handleRoleAuthSuccess() {}
function handleEdit(record: Recordable) {
openRoleModal(true, {
record,
isUpdate: true,
});
}
function handleDelete(record: Recordable) {
deleteRole([record.id]).then((_) => {
reload();
notification.success({
message: t('删除角色'),
description: t('成功'),
}); //提示消息
});
}
function handleSuccess() {
reload();
}
function handleHomeAuth() {
let res = warning();
if (!res) {
return;
}
openHomeModal(true, {
id: res.id,
});
}
return {
registerTable,
registerRoleModal,
handleCreate,
handleEdit,
handleDelete,
handleSuccess,
handleAuth,
handleAddUser,
handleViewUser,
handleSelectUserSuccess,
handleInterfaceSuccess,
registerRoleAuthModal,
handleRoleAuthSuccess,
registerModal,
visible,
selectedUserId,
registerInterfaceModal,
handleInterfaceAuth,
registerHomeModal,
handleHomeAuth,
t,
registerAppAuthModal,
handleAppAuth,
};
},
});
</script>