fix: 修改bug

This commit is contained in:
leiqiaochu 2023-09-26 18:15:21 +08:00
parent 1540cd71f8
commit e482e158f6
14 changed files with 357 additions and 242 deletions

View File

@ -3445,6 +3445,30 @@ export default [
permission: 'role', permission: 'role',
actions: ['query'], actions: ['query'],
}, },
{
permission: 'role-group',
actions: ['query']
}
],
},
{
id: 'groupUpdate',
name: '角色组编辑',
permissions: [
{
permission: 'role-group',
actions: ['query','save']
}
],
},
{
id: 'groupDelete',
name: '角色组删除',
permissions: [
{
permission: 'role-group',
actions: ['query','delete']
}
], ],
}, },
], ],

View File

@ -1,85 +1,68 @@
<template> <template>
<div class="left-contain"> <div class="left-contain">
<j-input placeholder="字典名称" v-model:value="searchValue" @pressEnter="search" @change="searchChange"> <j-input placeholder="字典名称" v-model:value="searchValue" @pressEnter="search" @change="searchChange">
<template #suffix> <template #suffix>
<AIcon type="SearchOutlined" @click="search" /> <AIcon type="SearchOutlined" @click="search" />
</template>
</j-input>
<div class="controls">
<PermissionButton
type="primary"
hasPermission="system/Dictionary:add"
@click="showSave"
style="width: 60%"
>
新增字典
</PermissionButton>
<PermissionButton
type="text"
hasPermission="system/Dictionary:down"
@click="downVisible=true"
>
下载
</PermissionButton>
<j-upload
:before-upload="beforeUpload"
accept=".json"
:show-upload-list="false"
>
<PermissionButton
type="text"
hasPermission="system/Dictionary:import"
>
导入
</PermissionButton>
</j-upload>
</div>
<div>
<j-tree :tree-data="listData" v-if="listData.length" :fieldNames="{title:'name',key:'id'}" blockNode :selectedKeys="selectedKeys">
<template #title="item">
<div class="treeItem" @click="()=>selectDic(item.data)">
<div class="itemText"><Ellipsis style="width: calc(100%-100px)">{{ item.name }}</Ellipsis></div>
<div @click="(e) => e.stopPropagation()">
<j-popconfirm v-if="hasPermission('system/Dictionary:action')" :title="item.data.status === 1 ? '确定禁用?' : '确定启用?'" @confirm="()=>updateDic(item.data)">
<j-switch :checked="item.status" :disabled="!hasPermission('system/Dictionary:action')" :checkedValue="1" :unCheckedValue="0"></j-switch>
</j-popconfirm>
<j-tooltip v-else placement="top" title="暂无权限,请联系管理员">
<j-switch :checked="item.status" :disabled="!hasPermission('system/Dictionary:action')" :checkedValue="1" :unCheckedValue="0"></j-switch>
</j-tooltip>
<PermissionButton
type="text"
hasPermission="system/Dictionary:delete"
:popConfirm="{
title: `确定要删除?`,
onConfirm: () => deleteDic(item.id),
}"
>
删除
</PermissionButton>
<PermissionButton
type="text"
hasPermission="system/Dictionary:update"
@click="showEdit(item.data)"
>
编辑
</PermissionButton>
</div>
</div>
</template> </template>
</j-tree> </j-input>
<j-empty v-else style="margin-top: 100px;"/> <div class="controls">
<PermissionButton type="primary" hasPermission="system/Dictionary:add" @click="showSave" style="width: 160px">
新增字典
</PermissionButton>
<PermissionButton type="text" hasPermission="system/Dictionary:down" @click="downVisible = true">
下载
</PermissionButton>
<j-upload :before-upload="beforeUpload" accept=".json" :show-upload-list="false"
:disabled="!hasPermission('system/Dictionary:import')">
<PermissionButton type="text" hasPermission="system/Dictionary:import">
导入
</PermissionButton>
</j-upload>
</div>
<div class="tree">
<j-tree :tree-data="listData" v-if="listData.length" :fieldNames="{ title: 'name', key: 'id' }" blockNode
:selectedKeys="selectedKeys">
<template #title="item">
<div class="treeItem" @click="() => selectDic(item.data)">
<div class="itemText">
<Ellipsis style="width: calc(100%-100px)">{{ item.name }}</Ellipsis>
</div>
<div @click="(e) => e.stopPropagation()">
<j-popconfirm v-if="hasPermission('system/Dictionary:action')"
:title="item.data.status === 1 ? '确定禁用?' : '确定启用?'" @confirm="() => updateDic(item.data)">
<j-switch :checked="item.status" :disabled="!hasPermission('system/Dictionary:action')"
:checkedValue="1" :unCheckedValue="0"></j-switch>
</j-popconfirm>
<j-tooltip v-else placement="top" title="暂无权限,请联系管理员">
<j-switch :checked="item.status" :disabled="!hasPermission('system/Dictionary:action')"
:checkedValue="1" :unCheckedValue="0"></j-switch>
</j-tooltip>
<PermissionButton type="text" hasPermission="system/Dictionary:delete" :popConfirm="{
title: `确定要删除?`,
onConfirm: () => deleteDic(item.id),
}">
删除
</PermissionButton>
<PermissionButton type="text" hasPermission="system/Dictionary:update"
@click="showEdit(item.data)">
编辑
</PermissionButton>
</div>
</div>
</template>
</j-tree>
<j-empty v-else style="margin-top: 100px;" />
</div>
</div> </div>
</div> <Save v-if="saveShow" :type="addType" @close-save="saveShow = false" @success="saveSuccess" :data="editData" />
<Save v-if="saveShow" :type="addType" @close-save="saveShow = false" @success="saveSuccess" :data="editData"/> <Export v-if="downVisible" @closeDown="closeDown" />
<Export v-if="downVisible" @closeDown="closeDown"/> <Import />
<Import/>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { getDicList ,deleteDictionary,addDictionary} from '@/api/system/dictionary'; import { getDicList, deleteDictionary, addDictionary } from '@/api/system/dictionary';
import Save from './save/index.vue' import Save from './save/index.vue'
import { onlyMessage} from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import Export from './Export/index.vue' import Export from './Export/index.vue'
import { usePermissionStore } from '@/store/permission'; import { usePermissionStore } from '@/store/permission';
const emit = defineEmits(['selectData']) const emit = defineEmits(['selectData'])
@ -88,34 +71,34 @@ const saveShow = ref(false)
const addType = ref('add') const addType = ref('add')
const listData = ref<any[]>([]) const listData = ref<any[]>([])
const editData = ref() const editData = ref()
const selectedKeys:any = ref([]) const selectedKeys: any = ref([])
const showSave = () =>{ const showSave = () => {
saveShow.value = true saveShow.value = true
addType.value = 'add' addType.value = 'add'
} }
const downVisible = ref(false) const downVisible = ref(false)
const searchValue = ref() const searchValue = ref()
const queryData = (first?:Boolean,searchName?:any) =>{ const queryData = (first?: Boolean, searchName?: any) => {
const params = searchName ? {sorts: [{ name: 'createTime', order: 'desc' }],terms:[{terms:[{value:'%'+ searchName +'%',termType:'like',column:'name'}]}]} : {sorts: [{ name: 'createTime', order: 'desc' }]} const params = searchName ? { sorts: [{ name: 'createTime', order: 'desc' }], terms: [{ terms: [{ value: '%' + searchName + '%', termType: 'like', column: 'name' }] }] } : { sorts: [{ name: 'createTime', order: 'desc' }] }
getDicList(params).then((res:any)=>{ getDicList(params).then((res: any) => {
if(res.status === 200){ if (res.status === 200) {
listData.value = res.result listData.value = res.result
if(first && res.result.length){ if (first && res.result.length) {
selectDic(res.result[0]) selectDic(res.result[0])
} }
} }
}) })
} }
const search = () =>{ const search = () => {
queryData(true,searchValue.value) queryData(true, searchValue.value)
} }
const searchChange = () =>{ const searchChange = () => {
console.log(searchValue.value ==='') console.log(searchValue.value === '')
if(searchValue.value === ''){ if (searchValue.value === '') {
queryData(true) queryData(true)
} }
} }
const showEdit = (data:any) =>{ const showEdit = (data: any) => {
saveShow.value = true saveShow.value = true
addType.value = 'edit' addType.value = 'edit'
editData.value = data editData.value = data
@ -123,10 +106,10 @@ const showEdit = (data:any) =>{
/** /**
* 重新请求数据 * 重新请求数据
*/ */
const reload = () =>{ const reload = () => {
queryData() queryData()
} }
const saveSuccess = () =>{ const saveSuccess = () => {
saveShow.value = false saveShow.value = false
reload() reload()
} }
@ -135,49 +118,49 @@ const saveSuccess = () =>{
* @param id 字典id * @param id 字典id
* 删除字典 * 删除字典
*/ */
const deleteDic = (id:string) =>{ const deleteDic = (id: string) => {
deleteDictionary(id).then((res:any)=>{ deleteDictionary(id).then((res: any) => {
if(res.status === 200){ if (res.status === 200) {
onlyMessage('操作成功!') onlyMessage('操作成功!')
queryData(true) queryData(true)
}else{ } else {
onlyMessage('操作失败!','error') onlyMessage('操作失败!', 'error')
} }
}) })
} }
/** /**
* 更新字典 * 更新字典
*/ */
const updateDic = (data:any)=>{ const updateDic = (data: any) => {
data.status = data.status === 1 ? 0 : 1 data.status = data.status === 1 ? 0 : 1
addDictionary(data).then((res:any)=>{ addDictionary(data).then((res: any) => {
if(res.status===200){ if (res.status === 200) {
onlyMessage('操作成功!') onlyMessage('操作成功!')
reload() reload()
}else{ } else {
onlyMessage('操作失败!','error') onlyMessage('操作失败!', 'error')
} }
}) })
} }
/** /**
* 切换选中字典 * 切换选中字典
*/ */
const selectDic = (selectKeys:any)=>{ const selectDic = (selectKeys: any) => {
selectedKeys.value = [selectKeys.id] selectedKeys.value = [selectKeys.id]
emit('selectData',selectKeys) emit('selectData', selectKeys)
} }
/** /**
* 导入字典 * 导入字典
*/ */
const beforeUpload = (file:any) => { const beforeUpload = (file: any) => {
if(file.type === 'application/json') { if (file.type === 'application/json') {
const reader = new FileReader(); const reader = new FileReader();
reader.readAsText(file); reader.readAsText(file);
reader.onload = async(json) => { reader.onload = async (json) => {
if(json.target?.result){ if (json.target?.result) {
const data = JSON.parse(json.target?.result); const data = JSON.parse(json.target?.result);
const res =await addDictionary(data) const res = await addDictionary(data)
if(res.status === 200){ if (res.status === 200) {
reload() reload()
onlyMessage('操作成功!') onlyMessage('操作成功!')
} }
@ -190,26 +173,39 @@ const selectDic = (selectKeys:any)=>{
} }
}; };
const closeDown = () =>{ const closeDown = () => {
downVisible.value = false downVisible.value = false
} }
onMounted(()=>{ onMounted(() => {
queryData(true) queryData(true)
}) })
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
:deep(.ant-tree-switcher){ .left-contain {
width: 300px;
height: 100%;
}
:deep(.ant-tree-switcher) {
display: none; display: none;
} }
.controls{
.tree {
height: calc(100% - 110px);
overflow-y: auto;
}
.controls {
margin: 10px 0; margin: 10px 0;
} }
.treeItem{
.treeItem {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
.itemText{
.itemText {
line-height: 32px; line-height: 32px;
max-width:40% max-width: 40%;
} }
} }
</style> </style>

View File

@ -66,7 +66,7 @@ const validateInput = async (_rule: Rule, value: string) => {
* 校验value唯一 * 校验value唯一
*/ */
const validateValue = async (_rule: Rule, value: string) => { const validateValue = async (_rule: Rule, value: string) => {
if (value) { if (value && props.type === 'add') {
const res:any = await verifyValue({ const res:any = await verifyValue({
terms: [ terms: [
{ {

View File

@ -1,5 +1,5 @@
<template> <template>
<div> <div class="des">
<div class="des_head"> <div class="des_head">
<div>字典ID<span>{{ data.id }}</span></div> <div>字典ID<span>{{ data.id }}</span></div>
<div>说明<span>{{ data.describe }}</span></div> <div>说明<span>{{ data.describe }}</span></div>
@ -12,7 +12,7 @@
}}</span></div> }}</span></div>
</div> </div>
<div class="contain"> <div class="contain">
<pro-search :columns="columns" @search="handleSearch" /> <pro-search :columns="columns" @search="handleSearch" target="system_dictionary"/>
<JProTable :columns="columns" model="TABLE" :request="queryItem" :params="params" ref="tableRef"> <JProTable :columns="columns" model="TABLE" :request="queryItem" :params="params" ref="tableRef">
<template #headerTitle> <template #headerTitle>
<PermissionButton type="primary" @click="add" hasPermission="system/Dictionary:add"> <PermissionButton type="primary" @click="add" hasPermission="system/Dictionary:add">
@ -167,7 +167,7 @@ const queryItem = async (_params: any) => {
if (props.data?.id) { if (props.data?.id) {
const params = { const params = {
..._params, ..._params,
sorts: [{ name: 'createTime', order: 'desc' }], sorts: [{ name: 'ordinal', order: 'asc' }],
terms: [ terms: [
..._params.terms, ..._params.terms,
{ {
@ -209,6 +209,7 @@ watch(() => props?.data?.id, () => {
}) })
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.des_head { .des_head {
padding: 10px 20px; padding: 10px 20px;
background-color: rgb(242, 242, 242); background-color: rgb(242, 242, 242);

View File

@ -63,7 +63,7 @@ const form = reactive({
if (props.type === 'add') { if (props.type === 'add') {
const res:any = await verifyId(value); const res:any = await verifyId(value);
if (res.status === 200 && res.result) { if (res.status === 200 && res.result) {
return Promise.reject('ID重复'); return Promise.reject('该字典ID已存在');
} else { } else {
return Promise.resolve(); return Promise.resolve();
} }

View File

@ -1,40 +1,45 @@
<template> <template>
<page-container> <page-container>
<FullPage> <FullPage>
<div class="dictionary_contain"> <div class="dictionary_contain">
<div class="dictionary_left"> <div class="dictionary_left">
<Left @selectData="selectData"/> <Left @selectData="selectData" />
</div> </div>
<div class="dictionary_right"> <div class="dictionary_right">
<Right :data="data"/> <Right :data="data" />
</div> </div>
</div> </div>
</FullPage> </FullPage>
</page-container> </page-container>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import Left from './components/Left.vue' import Left from './components/Left.vue'
import Right from './components/Right/index.vue' import Right from './components/Right/index.vue'
const data = ref() const data = ref()
const selectData = (i:any)=>{ const selectData = (i: any) => {
data.value= i data.value = i
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.dictionary_contain{ .dictionary_contain {
display: flex;
background-color: #fff; background-color: #fff;
padding: 24px; padding: 24px;
padding-bottom: 0;
position: relative;
height: 100%; height: 100%;
} }
.dictionary_left{
.dictionary_left {
position: absolute;
border-right: 1px solid #f0f0f0; border-right: 1px solid #f0f0f0;
padding-right: 24px; padding-right: 24px;
flex:1; width: 310px;
height:100% height: 100%;
} }
.dictionary_right{
flex:4 .dictionary_right {
margin-left: 317px;
width: calc(100% - 317px);
} }
</style> </style>

View File

@ -315,6 +315,7 @@ const form = reactive({
getMenuInfo_api(routeParams.id).then((resp: any) => { getMenuInfo_api(routeParams.id).then((resp: any) => {
form.data = { form.data = {
...(resp.result as formType), ...(resp.result as formType),
permissions: resp.result?.permissions ? resp.result.permissions : [],
accessSupport: accessSupport:
resp.result?.accessSupport?.value || 'unsupported', resp.result?.accessSupport?.value || 'unsupported',
}; };

View File

@ -65,6 +65,7 @@ import {
import { import {
filterMenu, filterMenu,
initData, initData,
inItSelected,
drop, drop,
select, select,
getMaxDepth, getMaxDepth,
@ -128,7 +129,38 @@ const getProvidersFn = async () => {
} }
} }
getProvidersFn(); getProvidersFn();
function filterTree(nodes: Array<any>, selectedKeys: Array<any>,parentId?:string) { /**
* 作用过滤掉非选中菜单重新组成新的数组
*/
// function filterTree(nodes: Array<any>, selectedKeys: Array<any>,parentId?:string) {
// const filtered = [];
// for (let i = 0; i < nodes.length; i++) {
// const node = nodes[i];
// if (!node.code) {
// continue;
// }
// node.parentId = parentId ? undefined : parentId
// if (selectedKeys.indexOf(node.code) !== -1) {
// filtered.push(node);
// if (node.children) {
// node.children = filterTree(node.children, selectedKeys,node.id);
// }
// } else if (node.children) {
// node.children = filterTree(node.children, selectedKeys,node.id);
// if (node.children.length > 0) {
// filtered.push(node);
// }
// }
// }
// return filtered;
// }
/**
*
* @param nodes 菜单数据
* @param selectedKeys 选中的菜单
* 选中和非选中改变show的值
*/
const dealTree = (nodes: Array<any>, selectedKeys: Array<any>,parentId?:string) =>{
const filtered = []; const filtered = [];
for (let i = 0; i < nodes.length; i++) { for (let i = 0; i < nodes.length; i++) {
const node = nodes[i]; const node = nodes[i];
@ -136,26 +168,33 @@ function filterTree(nodes: Array<any>, selectedKeys: Array<any>,parentId?:string
continue; continue;
} }
node.parentId = parentId ? undefined : parentId node.parentId = parentId ? undefined : parentId
node?.options ? node.options.show = false : node.options = { show : false }
if (selectedKeys.indexOf(node.code) !== -1) { if (selectedKeys.indexOf(node.code) !== -1) {
filtered.push(node); node.options.show = true
if (node.children) { if (node.children) {
node.children = filterTree(node.children, selectedKeys,node.id); node.children = dealTree(node.children, selectedKeys,node.id);
} }
} else if (node.children) { } else if (node.children) {
node.children = filterTree(node.children, selectedKeys,node.id); node.children = dealTree(node.children, selectedKeys,node.id);
if (node.children.length > 0) { const children =node.children.filter((item:any)=>{
filtered.push(node); item.options.show === true
})
if (children.length > 0) {
node.options.show = true
} }
}else{
node.options.show = false
} }
filtered.push(node)
} }
return filtered; return filtered;
} }
const handleOk = async () => { const handleOk = async () => {
const _dataArr = filterTree(cloneDeep(treeData.value), selectedKeys.value); // const _dataArr = filterTree(cloneDeep(treeData.value), selectedKeys.value);
const _dataArr = dealTree(cloneDeep(treeData.value),selectedKeys.value)
const _dataSorts = handleSorts(_dataArr) const _dataSorts = handleSorts(_dataArr)
loading.value = true; loading.value = true;
console.log(_dataSorts)
const res = await updateMenus(_dataSorts).catch(() => {}); const res = await updateMenus(_dataSorts).catch(() => {});
if (res?.status === 200) { if (res?.status === 200) {
onlyMessage('操作成功', 'success'); onlyMessage('操作成功', 'success');
@ -204,13 +243,13 @@ const onDragend = (info: AntTreeNodeDropEvent) => {
onMounted(() => { onMounted(() => {
getSystemPermission_api().then((resp: any) => { getSystemPermission_api().then((resp: any) => {
const filterBaseMenu = BaseMenu.filter(item => ![ // const filterBaseMenu = BaseMenu.filter(item => ![
USER_CENTER_MENU_CODE,messageSubscribe // USER_CENTER_MENU_CODE,messageSubscribe
].includes(item.code)) // ].includes(item.code))
baseMenu.value = filterMenu( // baseMenu.value = filterMenu(
resp.result.map((item: any) => JSON.parse(item).id), // resp.result.map((item: any) => JSON.parse(item).id),
filterBaseMenu, // filterBaseMenu,
); // );
getMenuTree_api(params).then((resp: any) => { getMenuTree_api(params).then((resp: any) => {
if (resp.status == 200) { if (resp.status == 200) {
systemMenu.value = resp.result?.filter( systemMenu.value = resp.result?.filter(
@ -220,15 +259,14 @@ onMounted(() => {
].includes(item.code), ].includes(item.code),
); );
// //
initData(baseMenu.value); // keyname // initData(baseMenu.value); // keyname
const systemMenuData = initData(systemMenu.value); const systemMenuData = inItSelected(systemMenu.value);
selectedKeys.value = systemMenuData.checkedKeys; selectedKeys.value = systemMenuData.checkedKeys;
// const AllMenu = filterMenus(mergeArr(
const AllMenu = filterMenus(mergeArr( // cloneDeep(baseMenu.value),
cloneDeep(baseMenu.value), // cloneDeep(systemMenu.value),
cloneDeep(systemMenu.value), // ))
)) // console.log(AllMenu);
console.log(AllMenu);
// //
treeData.value = handleSortsArr(systemMenu.value); treeData.value = handleSortsArr(systemMenu.value);
} }

View File

@ -115,9 +115,7 @@ export const initData = (Menu: any) => {
arr.forEach((item: any) => { arr.forEach((item: any) => {
item.title = item.code; item.title = item.code;
item.key = item.code; // treeData需要唯一key item.key = item.code; // treeData需要唯一key
checkedKeys.push(item.code); checkedKeys.push(item.code);
if (item?.children) { if (item?.children) {
getMap(item?.children); getMap(item?.children);
} }
@ -127,6 +125,23 @@ export const initData = (Menu: any) => {
return { checkedKeys }; return { checkedKeys };
}; };
/**通过options判断选中菜单 */
export const inItSelected = (Menu:any) =>{
const checkedKeys: any = [];
const getMap = (arr: any) => {
arr.forEach((item: any) => {
item.title = item.code;
item.key = item.code; // treeData需要唯一key
item?.options?.show ? checkedKeys.push(item.code) : '';
if (item?.children) {
getMap(item?.children);
}
});
};
getMap(Menu);
return { checkedKeys };
}
/** /**
* code * code
* @param data * @param data

View File

@ -41,11 +41,12 @@
<template #action="slotProps"> <template #action="slotProps">
<j-space :size="16"> <j-space :size="16">
<j-tooltip> <j-tooltip>
<template #title>编辑</template> <template #title>{{ slotProps?.options?.LowCode ? '低码创建的菜单不支持编辑' : '编辑' }}</template>
<j-button <j-button
style="padding: 0" style="padding: 0"
type="link" type="link"
@click="table.toDetails(slotProps)" @click="table.toDetails(slotProps)"
:disabled="slotProps?.options?.LowCode"
> >
<AIcon type="EditOutlined" /> <AIcon type="EditOutlined" />
</j-button> </j-button>
@ -53,8 +54,8 @@
<PermissionButton <PermissionButton
type="link" type="link"
:hasPermission="`${permission}:add`" :hasPermission="`${permission}:add`"
:tooltip="{ title: slotProps?.options?.LowCode ? '低码创建的菜单不支持编辑' : slotProps.level >= 3 ? '仅支持3级菜单' : '新增子菜单' }" :tooltip="{ title: slotProps.level >= 3 ? '仅支持3级菜单' : '新增子菜单' }"
:disabled="slotProps.level >= 3 || slotProps?.options?.LowCode" :disabled="slotProps.level >= 3"
@click="table.addChildren(slotProps)" @click="table.addChildren(slotProps)"
> >
<AIcon type="PlusCircleOutlined" /> <AIcon type="PlusCircleOutlined" />

View File

@ -10,22 +10,9 @@
class="edit-dialog-container" class="edit-dialog-container"
> >
<j-form ref="formRef" :model="form.data" layout="vertical"> <j-form ref="formRef" :model="form.data" layout="vertical">
<j-form-item
label="名称"
name="name"
:rules="[
{ required: true, message: '请输入名称' },
{ max: 64, message: '最多可输入64个字符' },
]"
>
<j-input
v-model:value="form.data.name"
placeholder="请输入名称"
/>
</j-form-item>
<j-form-item <j-form-item
name="relation" name="relation"
label="标识" label="关系标识"
:rules="[ :rules="[
{ required: true, message: '请输入标识' }, { required: true, message: '请输入标识' },
{ max: 64, message: '最多可输入64个字符' }, { max: 64, message: '最多可输入64个字符' },
@ -83,6 +70,32 @@
</j-form-item> </j-form-item>
</j-col> </j-col>
</j-row> </j-row>
<j-form-item
label="正向关系名称"
name="name"
:rules="[
{ required: true, message: '请输入名称' },
{ max: 64, message: '最多可输入64个字符' },
]"
>
<j-input
v-model:value="form.data.name"
placeholder="请输入名称"
/>
</j-form-item>
<j-form-item
label="反向关系名称"
name="reverseName"
:rules="[
{ required: true, message: '请输入名称' },
{ max: 64, message: '最多可输入64个字符' },
]"
>
<j-input
v-model:value="form.data.reverseName"
placeholder="请输入名称"
/>
</j-form-item>
<j-form-item name="description" label="说明"> <j-form-item name="description" label="说明">
<j-textarea <j-textarea
v-model:value="form.data.description" v-model:value="form.data.description"
@ -203,6 +216,7 @@ form.getObjectList();
type formType = { type formType = {
name: string; name: string;
reverseName: string;
relation: string; relation: string;
objectType: string | undefined; objectType: string | undefined;
targetType: string | undefined; targetType: string | undefined;

View File

@ -80,7 +80,7 @@ const permission = 'system/Relationship';
const columns = [ const columns = [
{ {
title: '名称', title: '正向关系名称',
dataIndex: 'name', dataIndex: 'name',
key: 'name', key: 'name',
ellipsis: true, ellipsis: true,
@ -89,6 +89,16 @@ const columns = [
type: 'string', type: 'string',
}, },
}, },
{
title: '正向关系名称',
dataIndex: 'reverseName',
key: 'reverseName',
ellipsis: true,
fixed: 'left',
search: {
type: 'string',
},
},
{ {
title: '关联方', title: '关联方',
dataIndex: 'objectTypeName', dataIndex: 'objectTypeName',

View File

@ -15,38 +15,45 @@
</j-button> </j-button>
</div> </div>
<div class="listBox"> <div class="listBox">
<j-tree :tree-data="listData" v-if="listData.length" :fieldNames="{title:'name',key:'id'}" blockNode :selectedKeys="selectedKeys"> <j-tree
:tree-data="listData"
v-if="listData.length"
:fieldNames="{title:'name',key:'id',children:'children'}"
blockNode
:selectedKeys="selectedKeys"
:default-expanded-keys="['global_role']"
:showLine="{ showLeafIcon: false }"
>
<template #title="item"> <template #title="item">
<div class="treeItem" @click="()=>selectGroup(item.data.id)" v-if="!item.data?.edit"> <div class="treeItem" @click="()=>selectGroup(item.data.id)" v-if="!item.data?.edit">
<div class="itemText"> <template v-if="!item?.children">
<Ellipsis style="width: calc(100%-100px)">{{ item.name }}</Ellipsis> <div class="itemText">
<Ellipsis style="width: calc(100%-100px)">{{ item.name }}</Ellipsis>
</div>
<div @click="(e) => e.stopPropagation()" v-if="item.id !== 'default_group'">
<PermissionButton
type="text"
hasPermission="system/Role:groupDelete"
:popConfirm="{
title: `确定要删除?`,
onConfirm: () => deleteGroup(item.id),
}"
:disabled="item.id === 'default_group'"
>
删除
</PermissionButton>
<PermissionButton
type="text"
hasPermission="system/Role:groupUpdate"
@click="editGroup(item.data)"
:disabled="item.id === 'default_group'"
>
编辑
</PermissionButton>
</div>
</template>
<template v-else><Ellipsis style="width: calc(100%-100px)">{{ item.name }}</Ellipsis></template>
</div> </div>
<div @click="(e) => e.stopPropagation()">
<PermissionButton
type="text"
hasPermission="system/Role:delete"
:popConfirm="{
title: `确定要删除?`,
onConfirm: () => deleteGroup(item.id),
}"
:disabled="item.id === 'default_group'"
>
删除
</PermissionButton>
<PermissionButton
type="text"
hasPermission="system/Role:update"
@click="editGroup(item.data)"
:disabled="item.id === 'default_group'"
>
编辑
</PermissionButton>
</div>
</div>
<div v-else>
<j-input v-model:value="addName" @blur="()=>saveGroup(item.data)" ref="inputRef" :maxlength="64"></j-input>
</div>
</template> </template>
</j-tree> </j-tree>
<j-empty v-else style="margin-top: 100px;"/> <j-empty v-else style="margin-top: 100px;"/>
@ -66,8 +73,12 @@ const { userInfos } = storeToRefs(userInfoStore)
const admin = computed(() => { const admin = computed(() => {
return userInfos.value?.username === 'admin'; return userInfos.value?.username === 'admin';
}) })
const listData:any = ref([]) const listData:any = ref([{
const selectedKeys = ref<string[]>([]) name:'全局角色',
id:'global_role',
children:[]
}])
const selectedKeys = ref<string[]>(['global_role'])
const searchValue = ref() const searchValue = ref()
const inputRef = ref() const inputRef = ref()
const addName = ref() const addName = ref()
@ -76,10 +87,10 @@ const queryGroup = async(select?:Boolean,searchName?:string) =>{
const params = searchName ? {sorts: [{ name: 'createTime', order: 'desc' }],terms:[{terms:[{value:'%'+ searchName +'%',termType:'like',column:'name'}]}]} : {sorts: [{ name: 'createTime', order: 'desc' }]} const params = searchName ? {sorts: [{ name: 'createTime', order: 'desc' }],terms:[{terms:[{value:'%'+ searchName +'%',termType:'like',column:'name'}]}]} : {sorts: [{ name: 'createTime', order: 'desc' }]}
const req:any = await queryRoleGroup(params) const req:any = await queryRoleGroup(params)
if(req.status === 200){ if(req.status === 200){
listData.value = req.result listData.value[0].children = req.result
if(req.result.length && select){ // if(req.result.length && select){
selectGroup(req.result[0].id) // selectGroup(req.result[0].id)
} // }
} }
} }
const addGroup = () =>{ const addGroup = () =>{
@ -121,7 +132,8 @@ const searchChange = () =>{
} }
const selectGroup = (id:string) =>{ const selectGroup = (id:string) =>{
selectedKeys.value = [id] selectedKeys.value = [id]
emit('selectData',selectedKeys.value) id === 'global_role' ? emit('selectData','') : emit('selectData',selectedKeys.value)
} }
const deleteGroup = async(id:string)=>{ const deleteGroup = async(id:string)=>{
const res:any = await deleteRoleGroup(id) const res:any = await deleteRoleGroup(id)
@ -144,10 +156,7 @@ onMounted(()=>{
queryGroup(true) queryGroup(true)
}) })
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
:deep(.ant-tree-switcher){
display: none;
}
.controls{ .controls{
margin: 10px 0; margin: 10px 0;
} }

View File

@ -4,7 +4,12 @@
<pro-search :columns="columns" target="system-role" @search="handelSearch" /> <pro-search :columns="columns" target="system-role" @search="handelSearch" />
<FullPage> <FullPage>
<j-pro-table ref="tableRef" :columns="columns" :request="getRoleList_api" model="TABLE" <j-pro-table ref="tableRef" :columns="columns" :request="getRoleList_api" model="TABLE"
:params="queryParams" :defaultParams="defaultParams"> :params="queryParams" :defaultParams="{
sorts: [
{ name: 'createTime', order: 'desc' },
{ name: 'id', order: 'desc' },
]
}">
<template #headerTitle> <template #headerTitle>
<PermissionButton type="primary" :hasPermission="`${permission}:add`" @click="addRole"> <PermissionButton type="primary" :hasPermission="`${permission}:add`" @click="addRole">
<AIcon type="PlusOutlined" />新增 <AIcon type="PlusOutlined" />新增
@ -16,8 +21,8 @@
<template v-for="i in getActions(slotProps, 'table')" :key="i.key"> <template v-for="i in getActions(slotProps, 'table')" :key="i.key">
<PermissionButton :disabled="i.disabled" :popConfirm="i.popConfirm" :tooltip="{ <PermissionButton :disabled="i.disabled" :popConfirm="i.popConfirm" :tooltip="{
...i.tooltip, ...i.tooltip,
}" @click="i.onClick" type="link" style="padding: 0 5px" }" @click="i.onClick" type="link" style="padding: 0 5px" :danger="i.key === 'delete'"
:danger="i.key === 'delete'" :hasPermission="'system/Role:' + i.key :hasPermission="'system/Role:' + i.key
"> ">
<template #icon> <template #icon>
<AIcon :type="i.icon" /> <AIcon :type="i.icon" />
@ -53,22 +58,7 @@ const { jumpPage } = useMenuStore();
const modalType = ref('add') const modalType = ref('add')
const current = ref() const current = ref()
const isSave = !!useRoute().query.save; const isSave = !!useRoute().query.save;
const queryParams = ref({}); const queryParams = ref<any>({terms:[]});
const defaultParams = ref({
sorts: [
{ name: 'createTime', order: 'desc' },
{ name: 'id', order: 'desc' },
],
terms: [
{
terms: [{
value: props.groupId,
termType: 'eq',
column: 'groupId'
}]
}
]
})
// //
const tableRef = ref<Record<string, any>>(); const tableRef = ref<Record<string, any>>();
const dialogVisible = ref(isSave); const dialogVisible = ref(isSave);
@ -168,16 +158,27 @@ const getActions = (
return actions; return actions;
}; };
const addRole = () =>{ const addRole = () => {
dialogVisible.value = true dialogVisible.value = true
modalType.value = 'add' modalType.value = 'add'
} }
const handelSearch = (search: any) => { const handelSearch = (search: any) => {
queryParams.value = search queryParams.value.terms =props.groupId ? [{
value: props.groupId,
termType: 'eq',
column: 'groupId'
}, ...search.terms] : [...search.terms]
} }
watch(() => props.groupId, () => { watch(() => props.groupId, (value) => {
defaultParams.value.terms[0].terms[0].value = props.groupId queryParams.value = value ? {
tableRef.value?.reload() terms: [{
value: props.groupId,
termType: 'eq',
column: 'groupId'
}]
} : {
terms: []
}
}) })
</script> </script>