项目初始化
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
<!--
|
||||
* Copyright (c) 2013-Now https://jeesite.com All rights reserved.
|
||||
* No deletion without permission, or be held responsible to law.
|
||||
* @author ThinkGem
|
||||
-->
|
||||
<template>
|
||||
<div class="flex flex-row flex-wrap">
|
||||
<template v-for="item in dataScopes" :key="item.moduleCode">
|
||||
<div class="mb-5 mr-5" v-if="moduleCodes.includes(item.moduleCode) && ctrlPermis.includes(item.ctrlPermi)">
|
||||
<BasicTree
|
||||
class="bg-gray"
|
||||
style="min-width: 300px"
|
||||
:title="t(item['ctrlName_' + localeStore.getLocale] || item.ctrlName)"
|
||||
:toolbar="true"
|
||||
:checkable="true"
|
||||
:checkStrictly="!(item.chkboxType?.Y + item.chkboxType?.N).includes('p')"
|
||||
:api="api"
|
||||
:params="{ url: item.ctrlDataUrl, ctrlPermi: ctrlPermi, parentAttr: 'disableCheckbox' }"
|
||||
:canSelectParent="!isLoadUser.includes(item.ctrlType)"
|
||||
:immediate="immediate"
|
||||
:defaultExpandLevel="Number(item.expandLevel)"
|
||||
:ref="setTreeRefs(item.ctrlType)"
|
||||
@tree-data-change="handleTreeDataChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup name="ViewsSysRoleAuthDataScope">
|
||||
import { ref, nextTick, type PropType } from 'vue';
|
||||
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
|
||||
import { useLocaleStore } from '@jeesite/core/store/modules/locale';
|
||||
import { BasicTree, TreeActionType } from '@jeesite/core/components/Tree';
|
||||
import { propTypes } from '@jeesite/core/utils/propTypes';
|
||||
|
||||
const props = defineProps({
|
||||
namespace: propTypes.string,
|
||||
checkStrictly: propTypes.bool,
|
||||
api: { type: Function as PropType<(arg?: Recordable) => Promise<Recordable>> },
|
||||
ctrlPermis: propTypes.array.def(['0', '1']),
|
||||
});
|
||||
|
||||
const { t } = useI18n(props.namespace);
|
||||
const localeStore = useLocaleStore();
|
||||
|
||||
const dataScopes = ref<Array<Recordable>>([]);
|
||||
const dataScopeList = ref<Array<Recordable>>([]);
|
||||
const moduleCodes = ref<Array<string>>([]);
|
||||
const ctrlPermi = ref<string>('');
|
||||
const menuCode = ref<string>('');
|
||||
const immediate = ref(false);
|
||||
const isLoadUser = ref<Array<string>>([]);
|
||||
|
||||
const treeRefs: Recordable<TreeActionType> = {};
|
||||
const setTreeRefs = (key: string) => (el: any) => {
|
||||
if (el) treeRefs[key] = el;
|
||||
};
|
||||
|
||||
let loadTreeDataNum: number;
|
||||
async function loadDataScopeList(data: Recordable) {
|
||||
dataScopes.value = data.dataScopes || [];
|
||||
dataScopeList.value = data.dataScopeList || [];
|
||||
moduleCodes.value = data.moduleCodes || [];
|
||||
ctrlPermi.value = data.ctrlPermi || '1';
|
||||
menuCode.value = data.menuCode || '0';
|
||||
loadTreeDataNum = 0;
|
||||
await nextTick(() => {
|
||||
if (immediate.value) {
|
||||
for (const key of Object.keys(treeRefs)) {
|
||||
treeRefs[key].setCheckedKeys([]);
|
||||
treeRefs[key].reload();
|
||||
}
|
||||
} else {
|
||||
immediate.value = true;
|
||||
}
|
||||
});
|
||||
isLoadUser.value = dataScopes.value
|
||||
.filter((item) => String(item.ctrlDataUrl).includes('isLoadUser=true'))
|
||||
.map((item) => item.ctrlType);
|
||||
}
|
||||
|
||||
function handleTreeDataChange() {
|
||||
const keys = Object.keys(treeRefs);
|
||||
loadTreeDataNum = loadTreeDataNum + 1;
|
||||
if (loadTreeDataNum == keys.length) {
|
||||
let checkedKeys = {};
|
||||
dataScopeList.value.forEach((item) => {
|
||||
if (!checkedKeys[item.ctrlType]) {
|
||||
checkedKeys[item.ctrlType] = [];
|
||||
}
|
||||
checkedKeys[item.ctrlType].push((isLoadUser.value.includes(item.ctrlType) ? 'u_' : '') + item.ctrlData);
|
||||
});
|
||||
for (const key of keys) {
|
||||
treeRefs[key].setCheckedKeys(checkedKeys[key] || []);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getDataScopeList() {
|
||||
const keys = Object.keys(treeRefs);
|
||||
let dataScopeData: Array<any> = [];
|
||||
for (const key of keys) {
|
||||
const ks = treeRefs[key].getCheckedKeys();
|
||||
for (const k of ks as Array<any>) {
|
||||
dataScopeData.push({
|
||||
ctrlType: String(key),
|
||||
ctrlData: String(k).replace(/^u_/g, ''),
|
||||
menuCode: menuCode.value,
|
||||
});
|
||||
}
|
||||
}
|
||||
return dataScopeData;
|
||||
}
|
||||
|
||||
function getDataScopeListJson() {
|
||||
return JSON.stringify(getDataScopeList());
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
loadDataScopeList,
|
||||
getDataScopeList,
|
||||
getDataScopeListJson,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,314 @@
|
||||
<!--
|
||||
* Copyright (c) 2013-Now https://jeesite.com All rights reserved.
|
||||
* No deletion without permission, or be held responsible to law.
|
||||
* @author ThinkGem
|
||||
-->
|
||||
<template>
|
||||
<ARow class="h-full pl-4">
|
||||
<ACol :span="9" :style="getTreeStyle">
|
||||
<BasicTree
|
||||
ref="treeRef"
|
||||
:search="true"
|
||||
:toolbar="true"
|
||||
:showIcon="true"
|
||||
:api="menuTreeDataByRoleCode"
|
||||
:params="apiParams"
|
||||
:immediate="false"
|
||||
:defaultExpandLevel="1"
|
||||
@select="handleSelect"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<Dropdown class="cursor-pointer" :trigger="['hover']" :dropMenuList="dropMenuList">
|
||||
{{ sysName }} <DownOutlined />
|
||||
</Dropdown>
|
||||
</template>
|
||||
<template #icon="{ dataRef, isLeaf, expanded }">
|
||||
<Icon v-if="dataRef.hasDataScope" icon="i-ant-design:unordered-list-outlined" color="#f00" />
|
||||
<Icon v-else-if="isLeaf" icon="ant-design:file-outlined" />
|
||||
<Icon v-else-if="expanded" icon="i-ant-design:folder-open-outlined" />
|
||||
<Icon v-else icon="ant-design:folder-outlined" />
|
||||
</template>
|
||||
</BasicTree>
|
||||
</ACol>
|
||||
<ACol :span="15" :style="getMainStyle">
|
||||
<Tabs class="jeesite-role-auth-data-scope-tabs" v-model:activeKey="ruleType" @change="handleTabChange">
|
||||
<Tabs.TabPane key="1" :forceRender="true">
|
||||
<template #tab>
|
||||
<Icon v-if="ruleType == '1'" icon="i-ant-design:check-circle-outlined" />
|
||||
<Icon v-else icon="i-ant-design:minus-circle-outlined" />
|
||||
<span class="pr-1"> {{ t('通用数据权限') }} </span>
|
||||
</template>
|
||||
<RoleDataScope ref="roleDataScopeRef" :menuDataScope="true" />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane key="2" :forceRender="true">
|
||||
<template #tab>
|
||||
<Icon v-if="ruleType == '2'" icon="i-ant-design:check-circle-outlined" />
|
||||
<Icon v-else icon="i-ant-design:minus-circle-outlined" />
|
||||
<span class="pr-1"> {{ t('自定义条件规则') }} </span>
|
||||
</template>
|
||||
<RuleDataScope ref="ruleDataScopeRef" />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane key="3" :forceRender="true">
|
||||
<template #tab>
|
||||
<Icon v-if="ruleType == '3'" icon="i-ant-design:check-circle-outlined" />
|
||||
<Icon v-else icon="i-ant-design:minus-circle-outlined" />
|
||||
<span class="pr-1"> {{ t('自定义SQL片段') }} </span>
|
||||
</template>
|
||||
<SqlDataScope ref="sqlDataScopeRef" />
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
<div class="ml-4 mt-2">
|
||||
<Alert
|
||||
v-if="!ruleType || ruleType === '0' || menuCode == '0'"
|
||||
message="提示:请先选择菜单,然后再选择权限类型。"
|
||||
type="info"
|
||||
/>
|
||||
</div>
|
||||
</ACol>
|
||||
</ARow>
|
||||
</template>
|
||||
<script lang="ts" setup name="ViewsSysMenuIndex">
|
||||
import { ref, computed, CSSProperties } from 'vue';
|
||||
import { Alert, Col, Row, Tabs } from 'ant-design-vue';
|
||||
import { DownOutlined } from '@ant-design/icons-vue';
|
||||
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
|
||||
import { useDict } from '@jeesite/core/components/Dict';
|
||||
import { Icon } from '@jeesite/core/components/Icon';
|
||||
import { Dropdown, DropMenu } from '@jeesite/core/components/Dropdown';
|
||||
import { BasicTree, TreeActionType } from '@jeesite/core/components/Tree';
|
||||
import { menuTreeDataByRoleCode } from '@jeesite/core/api/sys/role';
|
||||
import { useWindowSizeFn } from '@jeesite/core/hooks/event/useWindowSizeFn';
|
||||
import { onMountedOrActivated } from '@jeesite/core/hooks/core/onMountedOrActivated';
|
||||
import { encryptByBase64 } from '@jeesite/core/utils/cipher';
|
||||
import RoleDataScope from './RoleDataScope.vue';
|
||||
import RuleDataScope from './RuleDataScope.vue';
|
||||
import SqlDataScope from './SqlDataScope.vue';
|
||||
|
||||
const ARow = Row;
|
||||
const ACol = Col;
|
||||
|
||||
const { t } = useI18n('sys.role');
|
||||
const record = ref<Recordable>({});
|
||||
const menuDataScopes = ref<any>({});
|
||||
|
||||
const treeRef = ref<Nullable<TreeActionType>>(null);
|
||||
const apiParams = ref<Recordable>({ roleCode: '', sysCode: 'default' });
|
||||
|
||||
const dropMenuList = ref<Array<DropMenu>>([]);
|
||||
const sysCode = ref<string>('default');
|
||||
const sysName = ref<string>(t('菜单'));
|
||||
|
||||
const menuCode = ref<string>('0');
|
||||
const ruleType = ref<string>('0');
|
||||
const roleDataScopeRef = ref<InstanceType<typeof RoleDataScope>>();
|
||||
const ruleDataScopeRef = ref<InstanceType<typeof RuleDataScope>>();
|
||||
const sqlDataScopeRef = ref<InstanceType<typeof SqlDataScope>>();
|
||||
|
||||
const contentHeight = ref(400);
|
||||
const getTreeStyle = computed((): CSSProperties => {
|
||||
const treeHeight = contentHeight.value - 220;
|
||||
return {
|
||||
height: `${treeHeight}px`,
|
||||
minHeight: `${treeHeight}px`,
|
||||
};
|
||||
});
|
||||
const getMainStyle = computed((): CSSProperties => {
|
||||
const mainHeight = contentHeight.value - 220 + 30;
|
||||
return {
|
||||
height: `${mainHeight}px`,
|
||||
minHeight: `${mainHeight}px`,
|
||||
overflowX: 'auto',
|
||||
};
|
||||
});
|
||||
function calcTreeHeight() {
|
||||
contentHeight.value = document.documentElement.clientHeight;
|
||||
}
|
||||
useWindowSizeFn(calcTreeHeight, 280);
|
||||
onMountedOrActivated(calcTreeHeight);
|
||||
|
||||
async function loadDataScopeFormData(res: Recordable) {
|
||||
// 初始化变量值
|
||||
const { roleCode, roleName } = (res.role || {}) as Recordable;
|
||||
record.value = { roleCode, roleName, dataScope: '0' };
|
||||
sysCode.value = 'default';
|
||||
menuCode.value = '0';
|
||||
ruleType.value = '0';
|
||||
// 加载菜单树
|
||||
apiParams.value = { roleCode: record.value.roleCode, sysCode: sysCode.value };
|
||||
dropMenuList.value = (await useDict().initGetDictList('sys_menu_sys_code')).map((item) => {
|
||||
if (item.value == sysCode.value) {
|
||||
sysName.value = item.name;
|
||||
}
|
||||
return {
|
||||
text: item.name,
|
||||
event: item.value,
|
||||
icon: 'i-radix-icons:dot',
|
||||
onClick: () => {
|
||||
sysCode.value = item.value;
|
||||
sysName.value = item.name;
|
||||
apiParams.value.sysCode = item.value;
|
||||
treeRef.value?.reload();
|
||||
},
|
||||
};
|
||||
});
|
||||
treeRef.value?.reload();
|
||||
treeRef.value?.setSelectedKeys([]);
|
||||
// 读取存储的数据
|
||||
menuDataScopes.value = {};
|
||||
for (const menuDataScope of res.menuDataScopeList) {
|
||||
menuDataScopes.value[menuDataScope.menuCode] = {
|
||||
menuCode: menuDataScope.menuCode,
|
||||
roleCode: menuDataScope.roleCode,
|
||||
ruleName: menuDataScope.ruleName,
|
||||
ruleType: menuDataScope.ruleType,
|
||||
...menuDataScope.ruleConfigMap,
|
||||
roleDataScopeList: [],
|
||||
};
|
||||
}
|
||||
for (const roleDataScope of res.roleDataScopeList) {
|
||||
if (roleDataScope.menuCode && roleDataScope.menuCode !== '0') {
|
||||
const mds = menuDataScopes.value[roleDataScope.menuCode] || {};
|
||||
if (mds.roleDataScopeList) {
|
||||
mds.roleDataScopeList.push(roleDataScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 加载数据权限表单
|
||||
roleDataScopeRef.value?.loadDataScopeFormData(record.value, res);
|
||||
ruleDataScopeRef.value?.loadDataScopeFormData(record.value, res);
|
||||
sqlDataScopeRef.value?.loadDataScopeFormData(record.value, res);
|
||||
}
|
||||
|
||||
async function handleSelect(_keys?: string[], obj?: any) {
|
||||
// 存储上一个菜单数据权限
|
||||
if (ruleType.value === '1') {
|
||||
const formData = await roleDataScopeRef.value?.getDataScopeFormData();
|
||||
if (formData.menuCode) {
|
||||
formData.ruleType = ruleType.value;
|
||||
menuDataScopes.value[formData.menuCode] = formData;
|
||||
treeRef.value?.updateNodeByKey(formData.menuCode, {
|
||||
hasDataScope: formData.dataScope && formData.dataScope !== '0',
|
||||
});
|
||||
}
|
||||
} else if (ruleType.value === '2') {
|
||||
const formData = await ruleDataScopeRef.value?.getDataScopeFormData();
|
||||
if (formData.menuCode) {
|
||||
formData.ruleType = ruleType.value;
|
||||
menuDataScopes.value[formData.menuCode] = formData;
|
||||
treeRef.value?.updateNodeByKey(formData.menuCode, {
|
||||
hasDataScope: formData.ruleList && formData.ruleList.length > 0,
|
||||
});
|
||||
}
|
||||
} else if (ruleType.value === '3') {
|
||||
const formData = await sqlDataScopeRef.value?.getDataScopeFormData();
|
||||
if (formData.menuCode) {
|
||||
formData.ruleType = ruleType.value;
|
||||
menuDataScopes.value[formData.menuCode] = formData;
|
||||
treeRef.value?.updateNodeByKey(formData.menuCode, {
|
||||
hasDataScope: formData.sqlWhere && formData.sqlWhere !== '',
|
||||
});
|
||||
}
|
||||
}
|
||||
// 加载当前选择的菜单数据权限
|
||||
if (obj && obj.node && obj.node.dataRef) {
|
||||
const { id, rawName, permission } = obj.node.dataRef;
|
||||
menuCode.value = id;
|
||||
menuDataScopes.value[id] = {
|
||||
...(menuDataScopes.value[id] || record.value),
|
||||
menuCode: id,
|
||||
menuName: rawName,
|
||||
permission: permission,
|
||||
};
|
||||
const menuDataScope = menuDataScopes.value[id];
|
||||
ruleType.value = menuDataScope.ruleType || '1';
|
||||
roleDataScopeRef.value?.loadDataScopeFormData(menuDataScope);
|
||||
ruleDataScopeRef.value?.loadDataScopeFormData(menuDataScope);
|
||||
sqlDataScopeRef.value?.loadDataScopeFormData(menuDataScope);
|
||||
}
|
||||
}
|
||||
|
||||
function handleTabChange() {
|
||||
if (menuCode.value == '0') {
|
||||
ruleType.value = '0';
|
||||
}
|
||||
// 更新菜单图标状态
|
||||
if (ruleType.value === '1') {
|
||||
const formData = menuDataScopes.value[menuCode.value] as Recordable;
|
||||
if (formData && formData.menuCode) {
|
||||
treeRef.value?.updateNodeByKey(formData.menuCode, {
|
||||
hasDataScope: formData.dataScope && formData.dataScope !== '0',
|
||||
});
|
||||
}
|
||||
} else if (ruleType.value === '2') {
|
||||
const formData = menuDataScopes.value[menuCode.value] as Recordable;
|
||||
if (formData && formData.menuCode) {
|
||||
treeRef.value?.updateNodeByKey(formData.menuCode, {
|
||||
hasDataScope: formData.ruleList && formData.ruleList.length > 0,
|
||||
});
|
||||
}
|
||||
} else if (ruleType.value === '3') {
|
||||
const formData = menuDataScopes.value[menuCode.value] as Recordable;
|
||||
if (formData && formData.menuCode) {
|
||||
treeRef.value?.updateNodeByKey(formData.menuCode, {
|
||||
hasDataScope: formData.sqlWhere && formData.sqlWhere !== '',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getDataScopeFormData() {
|
||||
await handleSelect(); // 获取最后一个设置
|
||||
let menuDataScopeList: any = [];
|
||||
let roleDataScopeList: any = [];
|
||||
for (const key in menuDataScopes.value) {
|
||||
const menuDataScope = menuDataScopes.value[key];
|
||||
// 1 角色数据范围 2自定义条件规则 3自定义SQL
|
||||
if (menuDataScope.ruleType === '1') {
|
||||
if (menuDataScope.dataScope && menuDataScope.dataScope !== '0') {
|
||||
menuDataScopeList.push({
|
||||
menuCode: menuDataScope.menuCode,
|
||||
ruleName: record.value.roleName,
|
||||
ruleType: menuDataScope.ruleType,
|
||||
ruleConfigMap: {
|
||||
dataScope: menuDataScope.dataScope,
|
||||
},
|
||||
});
|
||||
if (menuDataScope.dataScope === '2') {
|
||||
roleDataScopeList = roleDataScopeList.concat(menuDataScope.roleDataScopeList);
|
||||
}
|
||||
}
|
||||
} else if (menuDataScope.ruleType === '2') {
|
||||
if (menuDataScope.ruleList && menuDataScope.ruleList.length > 0) {
|
||||
menuDataScopeList.push({
|
||||
menuCode: menuDataScope.menuCode,
|
||||
ruleName: record.value.roleName,
|
||||
ruleType: menuDataScope.ruleType,
|
||||
ruleConfigMap: {
|
||||
ruleList: menuDataScope.ruleList,
|
||||
},
|
||||
});
|
||||
}
|
||||
} else if (menuDataScope.ruleType === '3') {
|
||||
if (menuDataScope.sqlWhere && menuDataScope.sqlWhere !== '') {
|
||||
menuDataScopeList.push({
|
||||
menuCode: menuDataScope.menuCode,
|
||||
ruleName: record.value.roleName,
|
||||
ruleType: menuDataScope.ruleType,
|
||||
ruleConfigMap: {
|
||||
sqlWhere: encryptByBase64(menuDataScope.sqlWhere),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
menuDataScopeList,
|
||||
roleDataScopeList,
|
||||
} as any;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
loadDataScopeFormData,
|
||||
getDataScopeFormData,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,152 @@
|
||||
<!--
|
||||
* Copyright (c) 2013-Now https://jeesite.com All rights reserved.
|
||||
* No deletion without permission, or be held responsible to law.
|
||||
* @author ThinkGem
|
||||
-->
|
||||
<template>
|
||||
<div class="pt-2">
|
||||
<BasicForm @register="registerForm">
|
||||
<template #dataScopeTrees>
|
||||
<CustomDataScope ref="customDataScopeRef" :api="roleCtrlDataTreeData" />
|
||||
</template>
|
||||
</BasicForm>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup name="ViewsSysRoleAuthDataScope">
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
|
||||
// import { useMessage } from '@jeesite/core/hooks/web/useMessage';
|
||||
import { BasicForm, FormSchema, useForm } from '@jeesite/core/components/Form';
|
||||
import { roleCtrlDataTreeData } from '@jeesite/core/api/sys/role';
|
||||
import { propTypes } from '@jeesite/core/utils/propTypes';
|
||||
import CustomDataScope from './CustomDataScope.vue';
|
||||
|
||||
const props = defineProps({
|
||||
menuDataScope: propTypes.bool,
|
||||
});
|
||||
|
||||
const { t } = useI18n('sys.role');
|
||||
// const { showMessage } = useMessage();
|
||||
const record = ref<Recordable>({});
|
||||
const customDataScope = ref<Recordable>({});
|
||||
|
||||
const customDataScopeRef = ref<InstanceType<typeof CustomDataScope>>();
|
||||
|
||||
const inputFormSchemas: FormSchema[] = [
|
||||
{
|
||||
label: t('菜单名称'),
|
||||
field: 'menuName',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
ifShow: () => !!props.menuDataScope,
|
||||
},
|
||||
{
|
||||
label: t('权限标识'),
|
||||
field: 'permission',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
ifShow: () => !!props.menuDataScope,
|
||||
},
|
||||
{
|
||||
label: t('角色名称'),
|
||||
field: 'roleName',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
ifShow: () => !props.menuDataScope,
|
||||
},
|
||||
{
|
||||
label: t('角色编码'),
|
||||
field: 'roleCode',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
ifShow: () => !props.menuDataScope,
|
||||
},
|
||||
{
|
||||
label: t('数据范围'),
|
||||
field: 'dataScope',
|
||||
helpMessage: t('指定数据权限范围类型,多个角色同时指定,之间为或者关系'),
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
dictType: 'sys_role_data_scope',
|
||||
allowClear: true,
|
||||
},
|
||||
colProps: { md: 24, lg: 24 },
|
||||
},
|
||||
{
|
||||
label: t('业务范围'),
|
||||
field: 'bizScope',
|
||||
helpMessage: t(
|
||||
'在 addFilter 权限过滤的时候指定适应的业务范围,不指定代表所有生效,如:有的功能看本部门,有的功能看本公司;新的业务范围从字典 sys_role_biz_scope 类型添加。',
|
||||
),
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
dictType: 'sys_role_biz_scope',
|
||||
allowClear: true,
|
||||
mode: 'multiple',
|
||||
},
|
||||
colProps: { md: 24, lg: 24 },
|
||||
ifShow: () => !props.menuDataScope,
|
||||
},
|
||||
{
|
||||
label: t('授权数据权限'),
|
||||
field: 'authDataScopeInfo',
|
||||
component: 'FormGroup',
|
||||
colProps: { md: 24, lg: 24 },
|
||||
show: ({ values }) => values.dataScope === '2',
|
||||
},
|
||||
{
|
||||
field: 'roleDataScopeList',
|
||||
component: 'Input',
|
||||
colProps: { md: 24, lg: 24 },
|
||||
slot: 'dataScopeTrees',
|
||||
show: ({ values }) => values.dataScope === '2',
|
||||
},
|
||||
];
|
||||
|
||||
const [registerForm, { resetFields, setFieldsValue, getFieldsValue, validate }] = useForm({
|
||||
labelWidth: 120,
|
||||
schemas: inputFormSchemas,
|
||||
baseColProps: { md: 24, lg: 12 },
|
||||
});
|
||||
|
||||
async function loadDataScopeFormData(role: Recordable, res?: Recordable) {
|
||||
await resetFields();
|
||||
record.value = role;
|
||||
await setFieldsValue(record.value);
|
||||
if (res) {
|
||||
customDataScope.value = {
|
||||
dataScopes: res.dataScopes || [],
|
||||
moduleCodes: res.moduleCodes || [],
|
||||
dataScopeList: props.menuDataScope
|
||||
? []
|
||||
: (res.roleDataScopeList || []).filter((item: Recordable) => item.menuCode === '0'),
|
||||
ctrlPermi: res.ctrlPermi || '2',
|
||||
};
|
||||
} else {
|
||||
customDataScope.value.menuCode = role.menuCode || '0';
|
||||
customDataScope.value.dataScopeList = role.roleDataScopeList || [];
|
||||
}
|
||||
await customDataScopeRef.value?.loadDataScopeList(customDataScope.value);
|
||||
}
|
||||
|
||||
async function getDataScopeFormData() {
|
||||
return {
|
||||
...(await validate()),
|
||||
menuCode: record.value.menuCode,
|
||||
roleDataScopeList: customDataScopeRef.value?.getDataScopeList(),
|
||||
};
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
loadDataScopeFormData,
|
||||
getDataScopeFormData,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,263 @@
|
||||
<!--
|
||||
* Copyright (c) 2013-Now https://jeesite.com All rights reserved.
|
||||
* No deletion without permission, or be held responsible to law.
|
||||
* @author ThinkGem
|
||||
-->
|
||||
<template>
|
||||
<div class="pt-2">
|
||||
<BasicForm @register="registerForm">
|
||||
<template #dataScopeTable>
|
||||
<BasicTable @register="registerTable" @row-click="handleRowClick" />
|
||||
<a-button class="mt-2" @click="handleRowAdd" v-auth="'sys:role:edit'">
|
||||
<Icon icon="i-ant-design:plus-circle-outlined" /> {{ t('新增') }}
|
||||
</a-button>
|
||||
</template>
|
||||
</BasicForm>
|
||||
<div class="ml-5 mt-2">
|
||||
<Alert
|
||||
message="匹配值支持如下动态表达式:
|
||||
(1)当前用户对象中的属性值:#{currentUser.属性名}
|
||||
(2)会话对象中的属性值:#{session.属性名}
|
||||
(3)当前查询实体中的属性值:#{属性名}
|
||||
(4)当前实体查询不到,则从用户缓存里查询,
|
||||
仍然查询不到,则从系统参数配置里获取,
|
||||
再查询不到,则原样返回。"
|
||||
type="info"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup name="ViewsSysRoleAuthDataScope">
|
||||
import { ref } from 'vue';
|
||||
import { pick } from 'lodash-es';
|
||||
import { Alert } from 'ant-design-vue';
|
||||
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
|
||||
// import { useMessage } from '@jeesite/core/hooks/web/useMessage';
|
||||
import { Icon } from '@jeesite/core/components/Icon';
|
||||
import { BasicForm, FormSchema, useForm } from '@jeesite/core/components/Form';
|
||||
import { BasicTable, useTable } from '@jeesite/core/components/Table';
|
||||
|
||||
const { t } = useI18n('sys.role');
|
||||
// const { showMessage } = useMessage();
|
||||
const record = ref<Recordable>({});
|
||||
|
||||
const inputFormSchemas: FormSchema[] = [
|
||||
{
|
||||
label: t('菜单名称'),
|
||||
field: 'menuName',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('权限标识'),
|
||||
field: 'permission',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('规则列表'),
|
||||
field: 'authDataScopeRule',
|
||||
component: 'FormGroup',
|
||||
colProps: { md: 24, lg: 24 },
|
||||
},
|
||||
{
|
||||
field: 'ruleList',
|
||||
component: 'Input',
|
||||
colProps: { md: 24, lg: 24 },
|
||||
slot: 'dataScopeTable',
|
||||
},
|
||||
];
|
||||
|
||||
const [registerForm, { resetFields, setFieldsValue, getFieldsValue, validate }] = useForm({
|
||||
labelWidth: 120,
|
||||
schemas: inputFormSchemas,
|
||||
baseColProps: { md: 24, lg: 12 },
|
||||
});
|
||||
|
||||
const [registerTable, tableAction] = useTable({
|
||||
columns: [
|
||||
{
|
||||
title: t('关系'),
|
||||
dataIndex: 'andOr',
|
||||
width: 60,
|
||||
align: 'left',
|
||||
editRow: true,
|
||||
className: 'jeesite-table-tree-name',
|
||||
editComponent: 'Select',
|
||||
editComponentProps: {
|
||||
options: [
|
||||
{ label: t('并且'), value: 'AND' },
|
||||
{ label: t('或者'), value: 'OR' },
|
||||
],
|
||||
},
|
||||
format: (text, _record, _index, column) => {
|
||||
return column?.editComponentProps.options.find((item) => item.value === text).label;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('字段名'),
|
||||
dataIndex: 'columnName',
|
||||
width: 60,
|
||||
align: 'left',
|
||||
editRow: true,
|
||||
editComponent: 'Input',
|
||||
editComponentProps: {},
|
||||
},
|
||||
{
|
||||
title: t('条件'),
|
||||
dataIndex: 'queryType',
|
||||
width: 50,
|
||||
align: 'left',
|
||||
editRow: true,
|
||||
editComponent: 'Select',
|
||||
editComponentProps: {
|
||||
options: [
|
||||
{ label: t('等于'), value: 'EQ' },
|
||||
{ label: t('不等于'), value: 'NE' },
|
||||
{ label: t('大于'), value: 'GT' },
|
||||
{ label: t('大于等于'), value: 'GTE' },
|
||||
{ label: t('小于'), value: 'LT' },
|
||||
{ label: t('小于等于'), value: 'LTE' },
|
||||
{ label: t('等多值'), value: 'IN' },
|
||||
{ label: t('不等多值'), value: 'NOT_IN' },
|
||||
{ label: t('包含'), value: 'LIKE' },
|
||||
{ label: t('不包含'), value: 'NOT_LIKE' },
|
||||
{ label: t('开始以'), value: 'RIGHT_LIKE' },
|
||||
{ label: t('不开始以'), value: 'RIGHT_NOT_LIKE' },
|
||||
{ label: t('结束以'), value: 'LEFT_LIKE' },
|
||||
{ label: t('不结束以'), value: 'LEFT_NOT_LIKE' },
|
||||
{ label: t('是空'), value: 'IS_NULL' },
|
||||
{ label: t('不是空'), value: 'IS_NOT_NULL' },
|
||||
],
|
||||
},
|
||||
format: (text, _record, _index, column) => {
|
||||
return column?.editComponentProps.options.find((item) => item.value === text).label;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('值类型'),
|
||||
dataIndex: 'columnType',
|
||||
width: 50,
|
||||
align: 'left',
|
||||
editRow: true,
|
||||
editComponent: 'Select',
|
||||
editComponentProps: {
|
||||
options: [
|
||||
{ label: t('字符串'), value: 'String' },
|
||||
{ label: t('整型'), value: 'Long' },
|
||||
{ label: t('长整型'), value: 'Integer' },
|
||||
{ label: t('浮点型'), value: 'Float' },
|
||||
{ label: t('双精度'), value: 'Double' },
|
||||
{ label: t('大数值'), value: 'BigDecimal' },
|
||||
{ label: t('布尔型'), value: 'Boolean' },
|
||||
{ label: t('日期'), value: 'Date' },
|
||||
],
|
||||
},
|
||||
format: (text, _record, _index, column) => {
|
||||
return column?.editComponentProps.options.find((item) => item.value === text).label;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('匹配值'),
|
||||
dataIndex: 'value',
|
||||
width: 80,
|
||||
align: 'left',
|
||||
editRow: true,
|
||||
editComponent: 'Input',
|
||||
editComponentProps: {},
|
||||
},
|
||||
],
|
||||
actionColumn: {
|
||||
width: 50,
|
||||
actions: (record: Recordable) => [
|
||||
{
|
||||
icon: 'i-fluent:add-circle-24-regular',
|
||||
title: t('新增下级规则'),
|
||||
onClick: handleRowAdd.bind(this, record),
|
||||
auth: 'sys:role:edit',
|
||||
},
|
||||
{
|
||||
icon: 'i-ant-design:delete-outlined',
|
||||
color: 'error',
|
||||
popConfirm: {
|
||||
title: t('是否确认删除'),
|
||||
confirm: handleRowDelete.bind(this, record),
|
||||
},
|
||||
auth: 'sys:role:edit',
|
||||
},
|
||||
],
|
||||
},
|
||||
rowKey: 'id',
|
||||
pagination: false,
|
||||
bordered: true,
|
||||
size: 'small',
|
||||
inset: true,
|
||||
isTreeTable: true,
|
||||
childrenColumnName: 'children',
|
||||
});
|
||||
|
||||
function handleRowClick(data: Recordable) {
|
||||
data.onEdit?.(true, false);
|
||||
}
|
||||
|
||||
function handleRowAdd(parent?: Recordable) {
|
||||
const record = {
|
||||
id: new Date().getTime(),
|
||||
editable: true,
|
||||
andOr: 'AND',
|
||||
queryType: 'EQ',
|
||||
columnType: 'String',
|
||||
children: [],
|
||||
};
|
||||
if (parent && parent.children) {
|
||||
parent.children.push(record);
|
||||
tableAction.expandRows([parent.id]);
|
||||
} else {
|
||||
tableAction.insertTableDataRecord(record);
|
||||
}
|
||||
}
|
||||
|
||||
function handleRowDelete(data: Recordable) {
|
||||
tableAction.deleteTableDataRecord(data);
|
||||
}
|
||||
|
||||
async function getTableData(children?: Recordable[]): Promise<Recordable> {
|
||||
let tableList: Recordable[] = [];
|
||||
for (const record of children || tableAction.getDataSource()) {
|
||||
await record.onEdit?.(false, true);
|
||||
const newRecord = pick(record, 'id', 'andOr', 'columnName', 'queryType', 'columnType', 'value') as Recordable;
|
||||
if (record.children && record.children.length > 0) {
|
||||
newRecord.children = await getTableData(record.children);
|
||||
} else {
|
||||
newRecord.children = [];
|
||||
}
|
||||
tableList.push(newRecord);
|
||||
}
|
||||
return tableList;
|
||||
}
|
||||
|
||||
async function loadDataScopeFormData(data: Recordable, res?: Recordable) {
|
||||
await resetFields();
|
||||
record.value = data;
|
||||
await setFieldsValue(record.value);
|
||||
tableAction.setTableData(data.ruleList || []);
|
||||
tableAction.expandAll();
|
||||
}
|
||||
|
||||
async function getDataScopeFormData() {
|
||||
return {
|
||||
...(await validate()),
|
||||
menuCode: record.value.menuCode,
|
||||
ruleList: await getTableData(),
|
||||
};
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
loadDataScopeFormData,
|
||||
getDataScopeFormData,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,86 @@
|
||||
<!--
|
||||
* Copyright (c) 2013-Now https://jeesite.com All rights reserved.
|
||||
* No deletion without permission, or be held responsible to law.
|
||||
* @author ThinkGem
|
||||
-->
|
||||
<template>
|
||||
<div class="pt-2">
|
||||
<BasicForm @register="registerForm" />
|
||||
<div class="ml-5 mt-2">
|
||||
<Alert message="提示:在后端配置文件开启 user.dataScopeRuleSql 参数后,方可使用该功能。" type="info" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup name="ViewsSysRoleAuthDataScope">
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
|
||||
import { Alert } from 'ant-design-vue';
|
||||
// import { useMessage } from '@jeesite/core/hooks/web/useMessage';
|
||||
import { BasicForm, FormSchema, useForm } from '@jeesite/core/components/Form';
|
||||
import { trim } from 'lodash-es';
|
||||
|
||||
const { t } = useI18n('sys.role');
|
||||
// const { showMessage } = useMessage();
|
||||
const record = ref<Recordable>({});
|
||||
|
||||
const inputFormSchemas: FormSchema[] = [
|
||||
{
|
||||
label: t('菜单名称'),
|
||||
field: 'menuName',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('权限标识'),
|
||||
field: 'permission',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('SQL片段'),
|
||||
field: 'authDataScopeSql',
|
||||
component: 'FormGroup',
|
||||
colProps: { md: 24, lg: 24 },
|
||||
},
|
||||
{
|
||||
field: 'sqlWhere',
|
||||
component: 'InputTextArea',
|
||||
componentProps: {
|
||||
rows: 8,
|
||||
},
|
||||
colProps: { md: 24, lg: 24 },
|
||||
},
|
||||
];
|
||||
|
||||
const [registerForm, { resetFields, setFieldsValue, getFieldsValue, validate }] = useForm({
|
||||
labelWidth: 120,
|
||||
schemas: inputFormSchemas,
|
||||
baseColProps: { md: 24, lg: 12 },
|
||||
});
|
||||
|
||||
async function loadDataScopeFormData(data: Recordable, res?: Recordable) {
|
||||
await resetFields();
|
||||
record.value = data;
|
||||
await setFieldsValue(record.value);
|
||||
}
|
||||
|
||||
async function getDataScopeFormData() {
|
||||
const data = {
|
||||
...(await validate()),
|
||||
menuCode: record.value.menuCode,
|
||||
};
|
||||
if (data.sqlWhere) {
|
||||
data.sqlWhere = trim(data.sqlWhere);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
loadDataScopeFormData,
|
||||
getDataScopeFormData,
|
||||
});
|
||||
</script>
|
||||
339
web-vue/packages/core/views/sys/role/form.vue
Normal file
339
web-vue/packages/core/views/sys/role/form.vue
Normal file
@@ -0,0 +1,339 @@
|
||||
<!--
|
||||
* Copyright (c) 2013-Now https://jeesite.com All rights reserved.
|
||||
* No deletion without permission, or be held responsible to law.
|
||||
* @author ThinkGem
|
||||
-->
|
||||
<template>
|
||||
<BasicDrawer
|
||||
v-bind="$attrs"
|
||||
:showFooter="true"
|
||||
:okAuth="'sys:role:edit'"
|
||||
@register="registerDrawer"
|
||||
@ok="handleSubmit"
|
||||
width="80%"
|
||||
>
|
||||
<template #title>
|
||||
<Icon :icon="getTitle.icon" class="m-1 pr-1" />
|
||||
<span> {{ getTitle.value }} </span>
|
||||
</template>
|
||||
<BasicForm @register="registerForm">
|
||||
<template #menuTrees>
|
||||
<div class="flex flex-row flex-wrap">
|
||||
<template v-for="item in sysCodeRef" :key="item.id">
|
||||
<div class="mb-5 mr-5" v-show="sysCodesRef.length == 0 || sysCodesRef.includes(item.value)">
|
||||
<BasicTree
|
||||
class="bg-gray"
|
||||
style="width: 500px"
|
||||
:title="item.name"
|
||||
:toolbar="true"
|
||||
:checkable="true"
|
||||
:checkStrictly="false"
|
||||
:immediate="false"
|
||||
:defaultExpandLevel="2"
|
||||
:ref="setTreeRefs(item.value)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</BasicForm>
|
||||
<FormExtend v-show="op === 'add' || op === 'edit'" ref="formExtendRef" />
|
||||
</BasicDrawer>
|
||||
</template>
|
||||
<script lang="ts" setup name="ViewsSysRoleForm">
|
||||
import { ref, unref, computed } from 'vue';
|
||||
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
|
||||
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
|
||||
import { router } from '@jeesite/core/router';
|
||||
import { Icon } from '@jeesite/core/components/Icon';
|
||||
import { useDict } from '@jeesite/core/components/Dict';
|
||||
import { BasicTree, TreeActionType } from '@jeesite/core/components/Tree';
|
||||
import { BasicForm, FormExtend, FormSchema, useForm } from '@jeesite/core/components/Form';
|
||||
import { BasicDrawer, useDrawerInner } from '@jeesite/core/components/Drawer';
|
||||
import { Role, roleSave, checkRoleName, roleForm, roleMenuTreeData } from '@jeesite/core/api/sys/role';
|
||||
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
|
||||
const { t } = useI18n('sys.role');
|
||||
const { showMessage } = useMessage();
|
||||
const { meta } = unref(router.currentRoute);
|
||||
const record = ref<Role>({} as Role);
|
||||
const getTitle = computed(() => ({
|
||||
icon: meta.icon || 'ant-design:book-outlined',
|
||||
value: record.value.isNewRecord ? t('新增角色') : op.value === 'auth' ? t('授权菜单') : t('编辑角色'),
|
||||
}));
|
||||
const op = ref<string>('');
|
||||
const sysCodeRef = ref<Array<Recordable>>([]);
|
||||
const sysCodesRef = ref<Array<string>>([]);
|
||||
const formExtendRef = ref<InstanceType<typeof FormExtend>>();
|
||||
|
||||
const inputFormSchemas: FormSchema[] = [
|
||||
{
|
||||
label: t('基本信息'),
|
||||
field: 'basicInfo',
|
||||
component: 'FormGroup',
|
||||
colProps: { md: 24, lg: 24 },
|
||||
},
|
||||
{
|
||||
label: t('角色名称'),
|
||||
field: 'roleName',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
maxlength: 100,
|
||||
},
|
||||
rules: [
|
||||
{ required: true },
|
||||
{ pattern: /^[\u0391-\uFFE5\w]+$/, message: t('不能输入特殊字符') },
|
||||
{
|
||||
validator(_rule, value) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!value || value === '') return resolve();
|
||||
checkRoleName(record.value.roleName || '', value)
|
||||
.then((res) => (res ? resolve() : reject(t('角色名称已存在'))))
|
||||
.catch((err) => reject(err.message || t('验证失败')));
|
||||
});
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: t('角色编码'),
|
||||
field: 'roleCode',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
maxlength: 500,
|
||||
},
|
||||
required: true,
|
||||
ifShow: () => !record.value.isNewRecord,
|
||||
},
|
||||
{
|
||||
label: t('角色代码'),
|
||||
field: 'viewCode',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
maxlength: 500,
|
||||
},
|
||||
required: true,
|
||||
ifShow: () => record.value.isNewRecord,
|
||||
},
|
||||
{
|
||||
label: t('排序号'),
|
||||
field: 'roleSort',
|
||||
helpMessage: '升序',
|
||||
component: 'InputNumber',
|
||||
defaultValue: '30',
|
||||
componentProps: {
|
||||
maxlength: 10,
|
||||
},
|
||||
required: true,
|
||||
ifShow: () => op.value === 'add' || op.value === 'edit',
|
||||
},
|
||||
{
|
||||
label: t('用户类型'),
|
||||
field: 'userType',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
dictType: 'sys_user_type',
|
||||
allowClear: true,
|
||||
},
|
||||
ifShow: () => op.value === 'add' || op.value === 'edit',
|
||||
},
|
||||
{
|
||||
label: t('角色分类'),
|
||||
field: 'roleType',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
dictType: 'sys_role_type',
|
||||
allowClear: true,
|
||||
},
|
||||
ifShow: () => op.value === 'add' || op.value === 'edit',
|
||||
},
|
||||
{
|
||||
label: t('系统角色'),
|
||||
field: 'isSys',
|
||||
component: 'RadioGroup',
|
||||
defaultValue: '1',
|
||||
componentProps: {
|
||||
dictType: 'sys_yes_no',
|
||||
allowClear: true,
|
||||
},
|
||||
ifShow: () => op.value === 'add' || op.value === 'edit',
|
||||
},
|
||||
|
||||
{
|
||||
label: t('其它信息'),
|
||||
field: 'otherInfo',
|
||||
component: 'FormGroup',
|
||||
colProps: { md: 24, lg: 24 },
|
||||
ifShow: () => op.value === 'add' || op.value === 'edit',
|
||||
},
|
||||
{
|
||||
label: t('桌面地址'),
|
||||
field: 'desktopUrl',
|
||||
helpMessage: '仪表盘地址,如果当前多个角色,则根据角色的排序优先级选择。',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
maxlength: 250,
|
||||
},
|
||||
ifShow: () => op.value === 'add' || op.value === 'edit',
|
||||
},
|
||||
{
|
||||
label: t('是否可见'),
|
||||
field: 'isShow',
|
||||
helpMessage: '切换身份列表中是否显示该角色',
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
dictType: 'sys_show_hide',
|
||||
allowClear: true,
|
||||
},
|
||||
ifShow: () => op.value === 'add' || op.value === 'edit',
|
||||
},
|
||||
{
|
||||
label: t('包含系统'),
|
||||
field: 'sysCodes',
|
||||
helpMessage: '展示子系统列表的时候会根据此条件进行过滤,否则展示全部子系统',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
dictType: 'sys_menu_sys_code',
|
||||
allowClear: true,
|
||||
mode: 'multiple',
|
||||
onChange: (val) => {
|
||||
sysCodesRef.value = val ? val.split(',') : [];
|
||||
},
|
||||
},
|
||||
colProps: { md: 24, lg: 24 },
|
||||
ifShow: () => op.value === 'add' || op.value === 'auth',
|
||||
},
|
||||
{
|
||||
label: t('备注信息'),
|
||||
field: 'remarks',
|
||||
component: 'InputTextArea',
|
||||
componentProps: {
|
||||
maxlength: 500,
|
||||
},
|
||||
colProps: { md: 24, lg: 24 },
|
||||
ifShow: () => op.value === 'add' || op.value === 'edit',
|
||||
},
|
||||
{
|
||||
label: t('授权功能菜单'),
|
||||
field: 'authMenuInfo',
|
||||
component: 'FormGroup',
|
||||
colProps: { md: 24, lg: 24 },
|
||||
ifShow: () => op.value === 'add' || op.value === 'auth',
|
||||
},
|
||||
{
|
||||
field: 'roleMenuListJson',
|
||||
component: 'Input',
|
||||
colProps: { md: 24, lg: 24 },
|
||||
slot: 'menuTrees',
|
||||
ifShow: () => op.value === 'add' || op.value === 'auth',
|
||||
},
|
||||
];
|
||||
|
||||
const treeRefs: Recordable<TreeActionType> = {};
|
||||
const setTreeRefs = (key: string) => (el: any) => {
|
||||
if (el) treeRefs[key] = el;
|
||||
};
|
||||
|
||||
const [registerForm, { resetFields, setFieldsValue, updateSchema, validate }] = useForm({
|
||||
labelWidth: 120,
|
||||
schemas: inputFormSchemas,
|
||||
baseColProps: { md: 24, lg: 12 },
|
||||
});
|
||||
|
||||
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
|
||||
setDrawerProps({ loading: true });
|
||||
await resetFields();
|
||||
await formExtendRef.value?.resetFields();
|
||||
op.value = data.op || 'add';
|
||||
const res = await roleForm(data);
|
||||
record.value = (res.role || {}) as Role;
|
||||
await setFieldsValue(record.value);
|
||||
await updateSchema([
|
||||
{
|
||||
field: 'roleCode',
|
||||
componentProps: {
|
||||
disabled: !record.value.isNewRecord,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'roleName',
|
||||
componentProps: {
|
||||
disabled: op.value === 'auth',
|
||||
},
|
||||
},
|
||||
]);
|
||||
if (op.value === 'add' || op.value === 'auth') {
|
||||
await loadSysCode();
|
||||
await loadTreeDatas();
|
||||
}
|
||||
await formExtendRef.value?.setFieldsValue(record.value.extend);
|
||||
setDrawerProps({ loading: false });
|
||||
});
|
||||
|
||||
async function loadSysCode() {
|
||||
sysCodeRef.value = await useDict().initGetDictList('sys_menu_sys_code');
|
||||
sysCodesRef.value = record.value.sysCodes ? record.value.sysCodes?.split(',') : [];
|
||||
}
|
||||
|
||||
async function loadTreeDatas() {
|
||||
const res = await roleMenuTreeData({ roleCode: record.value.roleCode });
|
||||
const checkedKeys = {};
|
||||
(res.roleMenuList || []).forEach((item) => {
|
||||
if (!checkedKeys[item.sysCode]) {
|
||||
checkedKeys[item.sysCode] = [];
|
||||
}
|
||||
checkedKeys[item.sysCode].push(item.id);
|
||||
});
|
||||
for (const key in res.menuMap) {
|
||||
treeRefs[key].setTreeData(res.menuMap[key]);
|
||||
treeRefs[key].setCheckedKeys(checkedKeys[key]);
|
||||
}
|
||||
}
|
||||
|
||||
function getRoleMenuListJson() {
|
||||
const keys = Object.keys(treeRefs);
|
||||
let menuData: Array<any> = [];
|
||||
for (const key of keys) {
|
||||
if (sysCodesRef.value.length == 0 || sysCodesRef.value.includes(key)) {
|
||||
const ks = treeRefs[key].getCheckedKeys();
|
||||
for (const k of ks as Array<any>) {
|
||||
menuData.push(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
return JSON.stringify(menuData);
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const data = await validate();
|
||||
setDrawerProps({ confirmLoading: true });
|
||||
const params: any = {
|
||||
isNewRecord: record.value.isNewRecord,
|
||||
roleCode: record.value.roleCode,
|
||||
op: op.value,
|
||||
};
|
||||
if (!data.viewCode) {
|
||||
data.viewCode = record.value.viewCode;
|
||||
}
|
||||
if (op.value === 'add' || op.value === 'auth') {
|
||||
data.roleMenuListJson = getRoleMenuListJson();
|
||||
}
|
||||
data.extend = await formExtendRef.value?.validate();
|
||||
// console.log('submit', params, data, record);
|
||||
const res = await roleSave(params, data);
|
||||
showMessage(res.message);
|
||||
setTimeout(closeDrawer);
|
||||
emit('success', data);
|
||||
} catch (error: any) {
|
||||
if (error && error.errorFields) {
|
||||
showMessage(error.message || t('common.validateError'));
|
||||
}
|
||||
console.log('error', error);
|
||||
} finally {
|
||||
setDrawerProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
141
web-vue/packages/core/views/sys/role/formAuthDataScope.vue
Normal file
141
web-vue/packages/core/views/sys/role/formAuthDataScope.vue
Normal file
@@ -0,0 +1,141 @@
|
||||
<!--
|
||||
* Copyright (c) 2013-Now https://jeesite.com All rights reserved.
|
||||
* No deletion without permission, or be held responsible to law.
|
||||
* @author ThinkGem
|
||||
-->
|
||||
<template>
|
||||
<BasicDrawer
|
||||
wrapClassName="jeesite-role-auth-data-scope"
|
||||
v-bind="$attrs"
|
||||
:showFooter="true"
|
||||
:okAuth="'sys:role:edit'"
|
||||
@register="registerDrawer"
|
||||
@ok="handleSubmit"
|
||||
width="90%"
|
||||
>
|
||||
<template #title>
|
||||
<Icon :icon="getTitle.icon" class="m-1 pr-1" />
|
||||
<span> {{ getTitle.value }} </span>
|
||||
</template>
|
||||
<Tabs class="jeesite-role-auth-data-scope-tabs" v-model:activeKey="activeKey">
|
||||
<Tabs.TabPane key="1" :forceRender="true">
|
||||
<template #tab>
|
||||
<Icon icon="i-ant-design:deployment-unit-outlined" />
|
||||
<span class="pr-1"> {{ t('角色数据权限') }} </span>
|
||||
</template>
|
||||
<RoleDataScope ref="roleDataScopeRef" />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane key="2" :forceRender="true">
|
||||
<template #tab>
|
||||
<Icon icon="i-ant-design:unordered-list-outlined" />
|
||||
<span class="pr-1"> {{ t('菜单数据权限') }} </span>
|
||||
</template>
|
||||
<MenuDataScope ref="menuDataScopeRef" />
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
</BasicDrawer>
|
||||
</template>
|
||||
<script lang="ts" setup name="ViewsSysRoleAuthDataScope">
|
||||
import { computed, ref, unref } from 'vue';
|
||||
import { Tabs } from 'ant-design-vue';
|
||||
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
|
||||
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
|
||||
import { router } from '@jeesite/core/router';
|
||||
import { Icon } from '@jeesite/core/components/Icon';
|
||||
import { BasicDrawer, useDrawerInner } from '@jeesite/core/components/Drawer';
|
||||
import { roleFormAuthDataScope, roleSaveAuthDataScope } from '@jeesite/core/api/sys/role';
|
||||
import { useDict } from '@jeesite/core/components/Dict';
|
||||
import RoleDataScope from './components/RoleDataScope.vue';
|
||||
import MenuDataScope from './components/MenuDataScope.vue';
|
||||
import { omit } from 'lodash-es';
|
||||
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
|
||||
const { t } = useI18n('sys.role');
|
||||
const { showMessage } = useMessage();
|
||||
const { meta } = unref(router.currentRoute);
|
||||
const record = ref<Recordable>({});
|
||||
const getTitle = computed(() => {
|
||||
const r = record.value;
|
||||
const { getDictLabel } = useDict();
|
||||
return {
|
||||
icon: meta.icon || 'ant-design:book-outlined',
|
||||
value:
|
||||
t('角色分配数据权限') +
|
||||
' (' +
|
||||
r.roleName +
|
||||
'-' +
|
||||
r.viewCode +
|
||||
'-' +
|
||||
getDictLabel('sys_user_type', r.userType, t('未设置')) +
|
||||
')',
|
||||
};
|
||||
});
|
||||
|
||||
const activeKey = ref<string>('1');
|
||||
const roleDataScopeRef = ref<InstanceType<typeof RoleDataScope>>();
|
||||
const menuDataScopeRef = ref<InstanceType<typeof MenuDataScope>>();
|
||||
|
||||
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
|
||||
setDrawerProps({ loading: true });
|
||||
activeKey.value = '1';
|
||||
data.menuCode = 'true'; // 查询菜单数据权限
|
||||
const res = await roleFormAuthDataScope(data);
|
||||
record.value = (res.role || {}) as Recordable;
|
||||
roleDataScopeRef.value?.loadDataScopeFormData(record.value, res);
|
||||
menuDataScopeRef.value?.loadDataScopeFormData(res);
|
||||
setDrawerProps({ loading: false });
|
||||
});
|
||||
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
setDrawerProps({ confirmLoading: true });
|
||||
const roleDataScope = await roleDataScopeRef.value?.getDataScopeFormData();
|
||||
const menuDataScope = await menuDataScopeRef.value?.getDataScopeFormData();
|
||||
const params: any = {
|
||||
...omit(roleDataScope, ['roleDataScopeList']),
|
||||
roleDataScopeListJson: JSON.stringify(roleDataScope.roleDataScopeList.concat(menuDataScope.roleDataScopeList)),
|
||||
menuDataScopeListJson: JSON.stringify(menuDataScope.menuDataScopeList),
|
||||
isNewRecord: record.value.isNewRecord,
|
||||
roleCode: record.value.roleCode,
|
||||
menuCode: 'true', // 存储菜单数据权限
|
||||
};
|
||||
// console.log('submit', params, data, record);
|
||||
const res = await roleSaveAuthDataScope(params);
|
||||
showMessage(res.message);
|
||||
setTimeout(closeDrawer);
|
||||
emit('success', params);
|
||||
} catch (error: any) {
|
||||
if (error && error.errorFields) {
|
||||
showMessage(error.message || t('common.validateError'));
|
||||
}
|
||||
console.log('error', error);
|
||||
} finally {
|
||||
setDrawerProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
.jeesite-role-auth-data-scope {
|
||||
.scroll-container {
|
||||
> .scrollbar__wrap {
|
||||
> .scrollbar__view {
|
||||
margin: 6px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-tabs.ant-tabs {
|
||||
margin-top: 0 !important;
|
||||
padding-right: 5px;
|
||||
|
||||
.ant-tabs-nav {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.ant-tabs-tab {
|
||||
padding: 7px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
270
web-vue/packages/core/views/sys/role/formAuthUser.vue
Normal file
270
web-vue/packages/core/views/sys/role/formAuthUser.vue
Normal file
@@ -0,0 +1,270 @@
|
||||
<!--
|
||||
* Copyright (c) 2013-Now https://jeesite.com All rights reserved.
|
||||
* No deletion without permission, or be held responsible to law.
|
||||
* @author ThinkGem
|
||||
-->
|
||||
<template>
|
||||
<BasicDrawer
|
||||
v-bind="$attrs"
|
||||
:showFooter="true"
|
||||
:showOkBtn="false"
|
||||
@register="registerDrawer"
|
||||
@close="handleClose"
|
||||
width="80%"
|
||||
>
|
||||
<template #title>
|
||||
<Icon :icon="getTitle.icon" class="m-1 pr-1" />
|
||||
<span> {{ getTitle.value }} </span>
|
||||
</template>
|
||||
<template #centerFooter>
|
||||
<a-button type="primary" @click="handleForm" v-auth="'sys:role:edit'">
|
||||
<Icon icon="i-fluent:add-12-filled" /> {{ t('添加用户') }}
|
||||
</a-button>
|
||||
<ListSelect
|
||||
ref="listSelectRef"
|
||||
selectType="empUserSelect"
|
||||
:checkbox="true"
|
||||
@select="handleUserSelect"
|
||||
v-show="false"
|
||||
/>
|
||||
<Popconfirm :title="t('是否确认取消选中用户的角色')" @confirm="handleDelete">
|
||||
<a-button type="error" v-auth="'sys:role:edit'">
|
||||
<Icon icon="i-ant-design:close-outlined" /> {{ t('批量取消') }}
|
||||
</a-button>
|
||||
</Popconfirm>
|
||||
</template>
|
||||
<BasicTable @register="registerTable" />
|
||||
</BasicDrawer>
|
||||
</template>
|
||||
<script lang="ts" setup name="ViewsSysRoleAuthDataScope">
|
||||
import { ref, unref, computed } from 'vue';
|
||||
import { Popconfirm } from 'ant-design-vue';
|
||||
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
|
||||
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
|
||||
import { router } from '@jeesite/core/router';
|
||||
import { Icon } from '@jeesite/core/components/Icon';
|
||||
import { BasicDrawer, useDrawerInner } from '@jeesite/core/components/Drawer';
|
||||
import { BasicTable, BasicColumn, useTable, TableRowSelection } from '@jeesite/core/components/Table';
|
||||
import { FormProps } from '@jeesite/core/components/Form';
|
||||
import { ListSelect } from '@jeesite/core/components/ListSelect';
|
||||
import { formAuthUser, saveAuthUser, deleteAuthUser } from '@jeesite/core/api/sys/role';
|
||||
import { userListData } from '@jeesite/core/api/sys/user';
|
||||
import { useDict } from '@jeesite/core/components/Dict';
|
||||
|
||||
//const emit = defineEmits(['success', 'register']);
|
||||
|
||||
const { t } = useI18n('sys.role');
|
||||
const { showMessage } = useMessage();
|
||||
const { meta } = unref(router.currentRoute);
|
||||
const record = ref<Recordable>({});
|
||||
const getTitle = computed(() => {
|
||||
const r = record.value;
|
||||
const { getDictLabel } = useDict();
|
||||
return {
|
||||
icon: meta.icon || 'ant-design:book-outlined',
|
||||
value:
|
||||
t('角色分配用户') +
|
||||
' (' +
|
||||
r.roleName +
|
||||
'-' +
|
||||
r.viewCode +
|
||||
'-' +
|
||||
getDictLabel('sys_user_type', r.userType, t('未设置')) +
|
||||
')',
|
||||
};
|
||||
});
|
||||
const listSelectRef = ref<any>(null);
|
||||
|
||||
const searchForm: FormProps = {
|
||||
baseColProps: { md: 8, lg: 6 },
|
||||
labelWidth: 60,
|
||||
schemas: [
|
||||
{
|
||||
label: t('账号'),
|
||||
field: 'loginCode',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: t('昵称'),
|
||||
field: 'userName',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: t('状态'),
|
||||
field: 'status',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
dictType: 'sys_user_status',
|
||||
allowClear: true,
|
||||
onChange: handleSuccess,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('姓名'),
|
||||
field: 'refName',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: t('手机'),
|
||||
field: 'mobile',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: t('邮箱'),
|
||||
field: 'email',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: t('电话'),
|
||||
field: 'phone',
|
||||
component: 'Input',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const tableColumns: BasicColumn[] = [
|
||||
{
|
||||
title: t('登录账号'),
|
||||
dataIndex: 'loginCode',
|
||||
key: 'a.login_code',
|
||||
sorter: true,
|
||||
width: 100,
|
||||
slot: 'firstColumn',
|
||||
},
|
||||
{
|
||||
title: t('用户昵称'),
|
||||
dataIndex: 'userName',
|
||||
key: 'a.user_name',
|
||||
sorter: true,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: t('电子邮箱'),
|
||||
dataIndex: 'email',
|
||||
key: 'a.email',
|
||||
sorter: true,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: t('手机号码'),
|
||||
dataIndex: 'mobile',
|
||||
key: 'a.mobile',
|
||||
sorter: true,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: t('办公电话'),
|
||||
dataIndex: 'phone',
|
||||
key: 'a.phone',
|
||||
sorter: true,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: t('更新时间'),
|
||||
dataIndex: 'updateDate',
|
||||
key: 'a.update_date',
|
||||
sorter: true,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: t('状态'),
|
||||
dataIndex: 'status',
|
||||
key: 'a.status',
|
||||
sorter: true,
|
||||
width: 80,
|
||||
dictType: 'sys_status',
|
||||
},
|
||||
];
|
||||
|
||||
const actionColumn: BasicColumn = {
|
||||
width: 60,
|
||||
actions: (record: Recordable) => [
|
||||
{
|
||||
icon: 'i-ant-design:delete-outlined',
|
||||
color: 'error',
|
||||
title: t('取消授权'),
|
||||
popConfirm: {
|
||||
title: t('是否取消该用户角色'),
|
||||
confirm: handleDelete.bind(this, { userCode: record.userCode }),
|
||||
},
|
||||
auth: 'sys:secAdmin:edit',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const rowSelection: TableRowSelection = {
|
||||
type: 'checkbox',
|
||||
};
|
||||
|
||||
const [registerTable, { reload, getSelectRowKeys, setSelectedRowKeys }] = useTable({
|
||||
api: userListData,
|
||||
beforeFetch: (params) => {
|
||||
params.roleCode = record.value.roleCode;
|
||||
params.userType = record.value.userType;
|
||||
return params;
|
||||
},
|
||||
immediate: false,
|
||||
columns: tableColumns,
|
||||
actionColumn: actionColumn,
|
||||
rowSelection: rowSelection,
|
||||
formConfig: searchForm,
|
||||
showTableSetting: false,
|
||||
useSearchForm: true,
|
||||
canResize: true,
|
||||
resizeHeightOffset: 60,
|
||||
});
|
||||
|
||||
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
|
||||
setDrawerProps({ loading: true });
|
||||
const res = await formAuthUser(data);
|
||||
record.value = (res.role || {}) as Recordable;
|
||||
handleSuccess();
|
||||
setDrawerProps({ loading: false });
|
||||
});
|
||||
|
||||
function handleForm() {
|
||||
listSelectRef.value.openSelectModal();
|
||||
}
|
||||
|
||||
async function handleUserSelect(values: Recordable[]) {
|
||||
if (values.length == 0) {
|
||||
showMessage(t('请选中要授权角色的用户'));
|
||||
return;
|
||||
}
|
||||
const params = {
|
||||
roleCode: record.value.roleCode,
|
||||
userRoleString: values.map((e) => e.userCode).join(','),
|
||||
};
|
||||
const res = await saveAuthUser(params);
|
||||
showMessage(res.message);
|
||||
handleSuccess();
|
||||
listSelectRef.value.setSelectList([]);
|
||||
}
|
||||
|
||||
async function handleDelete(event: any) {
|
||||
let userRoleString: string;
|
||||
if (event && event.userCode) {
|
||||
userRoleString = event.userCode;
|
||||
} else {
|
||||
const selectedRowKeys = getSelectRowKeys();
|
||||
if (selectedRowKeys.length == 0) {
|
||||
showMessage(t('请选中要取消角色的用户'));
|
||||
return;
|
||||
}
|
||||
userRoleString = selectedRowKeys.join(',');
|
||||
}
|
||||
const params = { roleCode: record.value.roleCode, userRoleString };
|
||||
const res = await deleteAuthUser(params);
|
||||
showMessage(res.message);
|
||||
handleSuccess();
|
||||
setSelectedRowKeys([]);
|
||||
}
|
||||
|
||||
function handleSuccess() {
|
||||
reload();
|
||||
}
|
||||
|
||||
async function handleClose() {
|
||||
closeDrawer();
|
||||
}
|
||||
</script>
|
||||
318
web-vue/packages/core/views/sys/role/list.vue
Normal file
318
web-vue/packages/core/views/sys/role/list.vue
Normal file
@@ -0,0 +1,318 @@
|
||||
<!--
|
||||
* Copyright (c) 2013-Now https://jeesite.com All rights reserved.
|
||||
* No deletion without permission, or be held responsible to law.
|
||||
* @author ThinkGem
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<BasicTable @register="registerTable">
|
||||
<template #tableTitle>
|
||||
<Icon :icon="getTitle.icon" class="m-1 pr-1" />
|
||||
<span> {{ getTitle.value }} </span>
|
||||
</template>
|
||||
<template #toolbar>
|
||||
<a-button type="primary" @click="handleForm({ op: 'add' })" v-auth="'sys:role:edit'">
|
||||
<Icon icon="i-fluent:add-12-filled" /> {{ t('新增') }}
|
||||
</a-button>
|
||||
</template>
|
||||
<template #firstColumn="{ record }">
|
||||
<a @click="handleForm({ roleCode: record.roleCode, op: 'edit' })">
|
||||
{{ record.roleName }}
|
||||
</a>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<InputForm @register="registerDrawer" @success="handleSuccess" />
|
||||
<FormAuthDataScope @register="registerAuthDataSourceDrawer" @success="handleSuccess" />
|
||||
<FormAuthUser @register="registerAuthUserDrawer" @success="handleSuccess" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup name="ViewsSysRoleList">
|
||||
import { unref } from 'vue';
|
||||
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
|
||||
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
|
||||
import { router } from '@jeesite/core/router';
|
||||
import { Icon } from '@jeesite/core/components/Icon';
|
||||
import { BasicTable, BasicColumn, useTable } from '@jeesite/core/components/Table';
|
||||
import { roleDelete, roleListData } from '@jeesite/core/api/sys/role';
|
||||
import { roleDisable, roleEnable } from '@jeesite/core/api/sys/role';
|
||||
import { useDrawer } from '@jeesite/core/components/Drawer';
|
||||
import { FormProps } from '@jeesite/core/components/Form';
|
||||
import InputForm from './form.vue';
|
||||
import FormAuthDataScope from './formAuthDataScope.vue';
|
||||
import FormAuthUser from './formAuthUser.vue';
|
||||
|
||||
const { t } = useI18n('sys.role');
|
||||
const { showMessage } = useMessage();
|
||||
const { meta } = unref(router.currentRoute);
|
||||
const getTitle = {
|
||||
icon: meta.icon || 'ant-design:book-outlined',
|
||||
value: meta.title || t('角色管理'),
|
||||
};
|
||||
|
||||
const searchForm: FormProps = {
|
||||
baseColProps: { md: 8, lg: 6 },
|
||||
labelWidth: 90,
|
||||
schemas: [
|
||||
{
|
||||
label: t('角色名称'),
|
||||
field: 'roleName',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: t('角色编码'),
|
||||
field: 'roleCode_like',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: t('状态'),
|
||||
field: 'status',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
dictType: 'sys_search_status',
|
||||
allowClear: true,
|
||||
onChange: handleSuccess,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('用户类型'),
|
||||
field: 'userType',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
dictType: 'sys_user_type',
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('系统角色'),
|
||||
field: 'isSys',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
dictType: 'sys_yes_no',
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('角色分类'),
|
||||
field: 'roleType',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
dictType: 'sys_role_type',
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const tableColumns: BasicColumn[] = [
|
||||
{
|
||||
title: t('角色名称'),
|
||||
dataIndex: 'roleName',
|
||||
key: 'a.role_name',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'center',
|
||||
slot: 'firstColumn',
|
||||
},
|
||||
{
|
||||
title: t('角色编码'),
|
||||
dataIndex: 'roleCode',
|
||||
key: 'a.role_code',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: t('排序号'),
|
||||
dataIndex: 'roleSort',
|
||||
key: 'a.role_sort',
|
||||
sorter: true,
|
||||
width: 90,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: t('用户类型'),
|
||||
dataIndex: 'userType',
|
||||
key: 'a.user_type',
|
||||
sorter: true,
|
||||
width: 90,
|
||||
align: 'center',
|
||||
dictType: 'sys_user_type',
|
||||
},
|
||||
{
|
||||
title: t('系统角色'),
|
||||
dataIndex: 'isSys',
|
||||
key: 'a.is_sys',
|
||||
sorter: true,
|
||||
width: 90,
|
||||
align: 'center',
|
||||
dictType: 'sys_yes_no',
|
||||
},
|
||||
{
|
||||
title: t('角色分类'),
|
||||
dataIndex: 'roleType',
|
||||
key: 'a.role_type',
|
||||
sorter: true,
|
||||
width: 90,
|
||||
align: 'center',
|
||||
dictType: 'sys_role_type',
|
||||
},
|
||||
{
|
||||
title: t('数据范围'),
|
||||
dataIndex: 'dataScope',
|
||||
key: 'a.data_scope',
|
||||
sorter: true,
|
||||
width: 100,
|
||||
align: 'center',
|
||||
dictType: 'sys_role_data_scope',
|
||||
},
|
||||
{
|
||||
title: t('业务范围'),
|
||||
dataIndex: 'bizScope',
|
||||
key: 'a.biz_scope',
|
||||
sorter: true,
|
||||
width: 100,
|
||||
align: 'center',
|
||||
dictType: 'sys_role_biz_scope',
|
||||
},
|
||||
{
|
||||
title: t('状态'),
|
||||
dataIndex: 'status',
|
||||
key: 'a.status',
|
||||
sorter: true,
|
||||
width: 90,
|
||||
align: 'left',
|
||||
dictType: 'sys_status',
|
||||
},
|
||||
{
|
||||
title: t('更新时间'),
|
||||
dataIndex: 'updateDate',
|
||||
key: 'a.update_date',
|
||||
sorter: true,
|
||||
width: 100,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: t('备注信息'),
|
||||
dataIndex: 'remarks',
|
||||
key: 'a.remarks',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
];
|
||||
|
||||
const actionColumn: BasicColumn = {
|
||||
width: 160,
|
||||
actions: (record: Recordable) => [
|
||||
{
|
||||
icon: 'i-clarity:note-edit-line',
|
||||
title: t('编辑角色'),
|
||||
onClick: handleForm.bind(this, { roleCode: record.roleCode, op: 'edit' }),
|
||||
auth: 'sys:role:edit',
|
||||
},
|
||||
{
|
||||
icon: 'i-ant-design:stop-outlined',
|
||||
color: 'error',
|
||||
title: t('停用角色'),
|
||||
popConfirm: {
|
||||
title: t('是否确认停用角色'),
|
||||
confirm: handleDisable.bind(this, { roleCode: record.roleCode }),
|
||||
},
|
||||
auth: 'sys:role:edit',
|
||||
ifShow: () => record.status === '0',
|
||||
},
|
||||
{
|
||||
icon: 'i-ant-design:check-circle-outlined',
|
||||
color: 'success',
|
||||
title: t('启用角色'),
|
||||
popConfirm: {
|
||||
title: t('是否确认启用角色'),
|
||||
confirm: handleEnable.bind(this, { roleCode: record.roleCode }),
|
||||
},
|
||||
auth: 'sys:role:edit',
|
||||
ifShow: () => record.status === '2',
|
||||
},
|
||||
{
|
||||
icon: 'i-ant-design:delete-outlined',
|
||||
color: 'error',
|
||||
title: t('删除角色'),
|
||||
popConfirm: {
|
||||
title: t('是否确认删除角色'),
|
||||
confirm: handleDelete.bind(this, { roleCode: record.roleCode }),
|
||||
},
|
||||
auth: 'sys:role:edit',
|
||||
},
|
||||
],
|
||||
dropDownActions: (record: Recordable) => [
|
||||
{
|
||||
icon: 'i-ant-design:check-square-outlined',
|
||||
label: t('授权菜单'),
|
||||
onClick: handleForm.bind(this, { roleCode: record.roleCode, op: 'auth' }),
|
||||
auth: 'sys:role:edit',
|
||||
},
|
||||
{
|
||||
icon: 'i-ant-design:check-circle-outlined',
|
||||
label: t('数据权限'),
|
||||
onClick: handleFormAuthDataScope.bind(this, { roleCode: record.roleCode }),
|
||||
auth: 'sys:role:edit',
|
||||
},
|
||||
{
|
||||
icon: 'i-ant-design:user-outlined',
|
||||
label: t('分配用户'),
|
||||
onClick: handleFormAuthUser.bind(this, { roleCode: record.roleCode }),
|
||||
auth: 'sys:role:edit',
|
||||
ifShow: () => record.userType === 'employee',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const [registerDrawer, { openDrawer }] = useDrawer();
|
||||
const [registerAuthDataSourceDrawer, { openDrawer: openAuthDataScopeDrawer }] = useDrawer();
|
||||
const [registerAuthUserDrawer, { openDrawer: openAuthUserDrawer }] = useDrawer();
|
||||
const [registerTable, { reload }] = useTable({
|
||||
api: roleListData,
|
||||
beforeFetch: (params) => {
|
||||
return params;
|
||||
},
|
||||
columns: tableColumns,
|
||||
actionColumn: actionColumn,
|
||||
formConfig: searchForm,
|
||||
showTableSetting: true,
|
||||
useSearchForm: true,
|
||||
canResize: true,
|
||||
});
|
||||
|
||||
function handleForm(record: Recordable) {
|
||||
openDrawer(true, record);
|
||||
}
|
||||
|
||||
async function handleDisable(record: Recordable) {
|
||||
const res = await roleDisable(record);
|
||||
showMessage(res.message);
|
||||
handleSuccess();
|
||||
}
|
||||
|
||||
async function handleEnable(record: Recordable) {
|
||||
const res = await roleEnable(record);
|
||||
showMessage(res.message);
|
||||
handleSuccess();
|
||||
}
|
||||
|
||||
async function handleDelete(record: Recordable) {
|
||||
const res = await roleDelete(record);
|
||||
showMessage(res.message);
|
||||
handleSuccess();
|
||||
}
|
||||
|
||||
function handleFormAuthDataScope(record: Recordable) {
|
||||
openAuthDataScopeDrawer(true, record);
|
||||
}
|
||||
|
||||
function handleFormAuthUser(record: Recordable) {
|
||||
openAuthUserDrawer(true, record);
|
||||
}
|
||||
|
||||
function handleSuccess() {
|
||||
reload();
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user