page: 📄 路由查询

This commit is contained in:
Bunny 2024-09-28 03:07:47 +08:00
parent f3bdd89a44
commit 1eb1eced1b
6 changed files with 225 additions and 241 deletions

View File

@ -1,37 +1,30 @@
import { http } from '@/api/service'; import { http } from '@/api/service';
import type { BaseResult } from '@/types/BaseResult';
type Result = {
success: boolean;
data?: Array<any>;
};
type ResultTable = { type ResultTable = {
success: boolean; /** 列表数据 */
data?: { list: Array<any>;
/** 列表数据 */ /** 总条目数 */
list: Array<any>; total?: number;
/** 总条目数 */ /** 每页显示条目个数 */
total?: number; pageSize?: number;
/** 每页显示条目个数 */ /** 当前页数 */
pageSize?: number; pageNo?: number;
/** 当前页数 */
currentPage?: number;
};
}; };
/** 获取系统管理-用户管理列表 */ /** 获取系统管理-用户管理列表 */
export const getUserList = (data?: object) => { export const getUserList = (data?: object) => {
return http.request<ResultTable>('post', '/user', { data }); return http.request<BaseResult<ResultTable>>('post', '/user', { data });
}; };
/** 系统管理-用户管理-获取所有角色列表 */ /** 系统管理-用户管理-获取所有角色列表 */
export const getAllRoleList = () => { export const getAllRoleList = () => {
return http.request<Result>('get', '/list-all-role'); return http.request<any>('get', '/list-all-role');
}; };
/** 系统管理-用户管理-根据userId获取对应角色id列表userId用户id */ /** 系统管理-用户管理-根据userId获取对应角色id列表userId用户id */
export const getRoleIds = (data?: object) => { export const getRoleIds = (data?: object) => {
return http.request<Result>('post', '/list-role-ids', { data }); return http.request<any>('post', '/list-role-ids', { data });
}; };
/** 获取系统管理-角色管理列表 */ /** 获取系统管理-角色管理列表 */
@ -40,13 +33,14 @@ export const getRoleList = (data?: object) => {
}; };
/** 获取系统管理-菜单管理列表 */ /** 获取系统管理-菜单管理列表 */
export const getMenuList = (data?: object) => { export const getMenuList = (data?: any) => {
return http.request<Result>('post', '/menu', { data }); // /${data.page}/${data.limit}
return http.request<BaseResult<ResultTable>>('get', `router/getMenus`, { data });
}; };
/** 获取系统管理-部门管理列表 */ /** 获取系统管理-部门管理列表 */
export const getDeptList = (data?: object) => { export const getDeptList = (data?: object) => {
return http.request<Result>('post', '/dept', { data }); return http.request<any>('post', '/dept', { data });
}; };
/** 获取系统监控-在线用户列表 */ /** 获取系统监控-在线用户列表 */
@ -71,15 +65,15 @@ export const getSystemLogsList = (data?: object) => {
/** 获取系统监控-系统日志-根据 id 查日志详情 */ /** 获取系统监控-系统日志-根据 id 查日志详情 */
export const getSystemLogsDetail = (data?: object) => { export const getSystemLogsDetail = (data?: object) => {
return http.request<Result>('post', '/system-logs-detail', { data }); return http.request<any>('post', '/system-logs-detail', { data });
}; };
/** 获取角色管理-权限-菜单权限 */ /** 获取角色管理-权限-菜单权限 */
export const getRoleMenu = (data?: object) => { export const getRoleMenu = (data?: object) => {
return http.request<Result>('post', '/role-menu', { data }); return http.request<any>('post', '/role-menu', { data });
}; };
/** 获取角色管理-权限-菜单权限-根据角色 id 查对应菜单 */ /** 获取角色管理-权限-菜单权限-根据角色 id 查对应菜单 */
export const getRoleMenuIds = (data?: object) => { export const getRoleMenuIds = (data?: object) => {
return http.request<Result>('post', '/role-menu-ids', { data }); return http.request<any>('post', '/role-menu-ids', { data });
}; };

View File

@ -53,6 +53,6 @@ export const refreshTokenApi = (data?: object) => {
* * 退 * * 退
* @param data * @param data
*/ */
export const fetchLogOut = (data?: object) => { export const fetchLogout = (data?: object) => {
return http.request<BaseResult<any>>('post', 'user/logOut', { data }); return http.request<BaseResult<any>>('post', 'user/logout', { data });
}; };

View File

@ -1,6 +1,6 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { resetRouter, router, routerArrays, storageLocal, store, type userType } from '../utils'; import { resetRouter, router, routerArrays, storageLocal, store, type userType } from '../utils';
import { fetchLogin, fetchLogOut, fetchPostEmailCode, refreshTokenApi } from '@/api/v1/user'; import { fetchLogin, fetchLogout, fetchPostEmailCode, refreshTokenApi } from '@/api/v1/user';
import { useMultiTagsStoreHook } from '../multiTags'; import { useMultiTagsStoreHook } from '../multiTags';
import { type DataInfo, removeToken, setToken, userKey } from '@/utils/auth'; import { type DataInfo, removeToken, setToken, userKey } from '@/utils/auth';
import { message } from '@/utils/message'; import { message } from '@/utils/message';
@ -58,7 +58,7 @@ export const useUserStore = defineStore({
*/ */
async logOut() { async logOut() {
// 登出 // 登出
const result = await fetchLogOut(); const result = await fetchLogout();
if (result.code == 200) { if (result.code == 200) {
this.username = ''; this.username = '';
this.roles = []; this.roles = [];

View File

@ -1,6 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { onMounted, ref } from 'vue';
import { useMenu } from './utils/hook';
import { $t } from '@/plugins/i18n'; import { $t } from '@/plugins/i18n';
import { PureTableBar } from '@/components/TableBar'; import { PureTableBar } from '@/components/TableBar';
import { useRenderIcon } from '@/components/ReIcon/src/hooks'; import { useRenderIcon } from '@/components/ReIcon/src/hooks';
@ -9,6 +8,9 @@ import Delete from '@iconify-icons/ep/delete';
import EditPen from '@iconify-icons/ep/edit-pen'; import EditPen from '@iconify-icons/ep/edit-pen';
import Refresh from '@iconify-icons/ep/refresh'; import Refresh from '@iconify-icons/ep/refresh';
import AddFill from '@iconify-icons/ri/add-circle-line'; import AddFill from '@iconify-icons/ri/add-circle-line';
import { columns, dataList, handleDelete, handleSelectionChange, loading, onSearch, openDialog, resetForm } from '@/views/menu/utils/hook';
import form from '@/views/role/form.vue';
import PureTable from '@pureadmin/table';
defineOptions({ defineOptions({
name: 'SystemMenu', name: 'SystemMenu',
@ -16,12 +18,18 @@ defineOptions({
const formRef = ref(); const formRef = ref();
const tableRef = ref(); const tableRef = ref();
const { form, loading, columns, dataList, onSearch, resetForm, openDialog, handleDelete, handleSelectionChange } = useMenu();
function onFullscreen() { /**
* 全屏
*/
const onFullscreen = () => {
// //
tableRef.value.setAdaptive(); tableRef.value.setAdaptive();
} };
onMounted(() => {
onSearch();
});
</script> </script>
<template> <template>

View File

@ -4,214 +4,196 @@ import { message } from '@/utils/message';
import { getMenuList } from '@/api/v1/system'; import { getMenuList } from '@/api/v1/system';
import { $t } from '@/plugins/i18n'; import { $t } from '@/plugins/i18n';
import { addDialog } from '@/components/BaseDialog'; import { addDialog } from '@/components/BaseDialog';
import { h, onMounted, reactive, ref } from 'vue'; import { h, reactive, ref } from 'vue';
import type { FormItemProps } from '../utils/types'; import type { FormItemProps } from '../utils/types';
import { useRenderIcon } from '@/components/ReIcon/src/hooks'; import { useRenderIcon } from '@/components/ReIcon/src/hooks';
import { cloneDeep, deviceDetection, isAllEmpty } from '@pureadmin/utils'; import { cloneDeep, deviceDetection, isAllEmpty } from '@pureadmin/utils';
export function useMenu() { export const form = reactive({
const form = reactive({ title: '',
title: '', });
});
const formRef = ref(); export const formRef = ref();
const dataList = ref([]); export const dataList = ref([]);
const loading = ref(true); export const loading = ref(true);
const getMenuType = (type, text = false) => { export const getMenuType = (type, text = false) => {
switch (type) { switch (type) {
case 0: case 0:
return text ? '菜单' : 'primary'; return text ? '菜单' : 'primary';
case 1: case 1:
return text ? 'iframe' : 'warning'; return text ? 'iframe' : 'warning';
case 2: case 2:
return text ? '外链' : 'danger'; return text ? '外链' : 'danger';
case 3: case 3:
return text ? '按钮' : 'info'; return text ? '按钮' : 'info';
}
};
const columns: TableColumnList = [
{
label: '菜单名称',
prop: 'title',
align: 'left',
cellRenderer: ({ row }) => (
<>
<span class='inline-block mr-1'>
{h(useRenderIcon(row.icon), {
style: { paddingTop: '1px' },
})}
</span>
<span>{$t(row.title)}</span>
</>
),
},
{
label: '菜单类型',
prop: 'menuType',
width: 100,
cellRenderer: ({ row, props }) => (
<el-tag size={props.size} type={getMenuType(row.menuType)} effect='plain'>
{getMenuType(row.menuType, true)}
</el-tag>
),
},
{
label: '路由路径',
prop: 'path',
},
{
label: '组件路径',
prop: 'component',
formatter: ({ path, component }) => (isAllEmpty(component) ? path : component),
},
{
label: '权限标识',
prop: 'auths',
},
{
label: '排序',
prop: 'rank',
width: 100,
},
{
label: '隐藏',
prop: 'showLink',
formatter: ({ showLink }) => (showLink ? '否' : '是'),
width: 100,
},
{
label: '操作',
fixed: 'right',
width: 210,
slot: 'operation',
},
];
function handleSelectionChange(val) {
console.log('handleSelectionChange', val);
} }
};
function resetForm(formEl) { export const columns: TableColumnList = [
if (!formEl) return; {
formEl.resetFields(); label: '菜单名称',
onSearch(); prop: 'title',
} align: 'left',
cellRenderer: ({ row }) => (
<>
<span class='inline-block mr-1'>
{h(useRenderIcon(row.icon), {
style: { paddingTop: '1px' },
})}
</span>
<span>{$t(row.title)}</span>
</>
),
},
{
label: '菜单类型',
prop: 'menuType',
width: 100,
cellRenderer: ({ row, props }) => (
<el-tag size={props.size} type={getMenuType(row.menuType)} effect='plain'>
{getMenuType(row.menuType, true)}
</el-tag>
),
},
{
label: '路由路径',
prop: 'path',
},
{
label: '组件路径',
prop: 'component',
formatter: ({ path, component }) => (isAllEmpty(component) ? path : component),
},
{
label: '权限标识',
prop: 'auths',
},
{
label: '排序',
prop: 'rank',
width: 100,
},
{
label: '隐藏',
prop: 'showLink',
formatter: ({ showLink }) => (showLink ? '否' : '是'),
width: 100,
},
{
label: '操作',
fixed: 'right',
width: 210,
slot: 'operation',
},
];
async function onSearch() { export function handleSelectionChange(val) {
loading.value = true; console.log('handleSelectionChange', val);
const { data } = await getMenuList(); // 这里是返回一维数组结构前端自行处理成树结构返回格式要求唯一id加父节点parentIdparentId取父节点id }
let newData = data;
if (!isAllEmpty(form.title)) { export function resetForm(formEl) {
// 前端搜索菜单名称 if (!formEl) return;
newData = newData.filter(item => $t(item.title).includes(form.title)); formEl.resetFields();
} onSearch();
dataList.value = handleTree(newData); // 处理成树结构 }
setTimeout(() => {
loading.value = false; export async function onSearch() {
}, 500); loading.value = true;
}
// 获取菜单数据
function formatHigherMenuOptions(treeList) { const result = await getMenuList();
if (!treeList || !treeList.length) return; if (result.code !== 200) message(result.message, { type: 'error' });
const newTreeList = [];
for (let i = 0; i < treeList.length; i++) { // 前端搜索菜单名称
treeList[i].title = $t(treeList[i].title); if (!isAllEmpty(form.title)) {
formatHigherMenuOptions(treeList[i].children); result.data = result.data.filter(item => $t(item.title).includes(form.title));
newTreeList.push(treeList[i]); }
}
return newTreeList; // 处理成树结构
} dataList.value = handleTree(result.data);
function openDialog(title = '新增', row?: FormItemProps) { loading.value = false;
addDialog({ }
title: `${title}菜单`,
props: { export function formatHigherMenuOptions(treeList) {
formInline: { if (!treeList || !treeList.length) return;
menuType: row?.menuType ?? 0, const newTreeList = [];
higherMenuOptions: formatHigherMenuOptions(cloneDeep(dataList.value)), for (let i = 0; i < treeList.length; i++) {
parentId: row?.parentId ?? 0, treeList[i].title = $t(treeList[i].title);
title: row?.title ?? '', formatHigherMenuOptions(treeList[i].children);
name: row?.name ?? '', newTreeList.push(treeList[i]);
path: row?.path ?? '', }
component: row?.component ?? '', return newTreeList;
rank: row?.rank ?? 99, }
redirect: row?.redirect ?? '',
icon: row?.icon ?? '', export function openDialog(title = '新增', row?: FormItemProps) {
extraIcon: row?.extraIcon ?? '', addDialog({
enterTransition: row?.enterTransition ?? '', title: `${title}菜单`,
leaveTransition: row?.leaveTransition ?? '', props: {
activePath: row?.activePath ?? '', formInline: {
auths: row?.auths ?? '', menuType: row?.menuType ?? 0,
frameSrc: row?.frameSrc ?? '', higherMenuOptions: formatHigherMenuOptions(cloneDeep(dataList.value)),
frameLoading: row?.frameLoading ?? true, parentId: row?.parentId ?? 0,
keepAlive: row?.keepAlive ?? false, title: row?.title ?? '',
hiddenTag: row?.hiddenTag ?? false, name: row?.name ?? '',
fixedTag: row?.fixedTag ?? false, path: row?.path ?? '',
showLink: row?.showLink ?? true, component: row?.component ?? '',
showParent: row?.showParent ?? false, rank: row?.rank ?? 99,
}, redirect: row?.redirect ?? '',
}, icon: row?.icon ?? '',
width: '45%', extraIcon: row?.extraIcon ?? '',
draggable: true, enterTransition: row?.enterTransition ?? '',
fullscreen: deviceDetection(), leaveTransition: row?.leaveTransition ?? '',
fullscreenIcon: true, activePath: row?.activePath ?? '',
closeOnClickModal: false, auths: row?.auths ?? '',
contentRenderer: () => h(editForm, { ref: formRef, formInline: null }), frameSrc: row?.frameSrc ?? '',
beforeSure: (done, { options }) => { frameLoading: row?.frameLoading ?? true,
const FormRef = formRef.value.getRef(); keepAlive: row?.keepAlive ?? false,
const curData = options.props.formInline as FormItemProps; hiddenTag: row?.hiddenTag ?? false,
fixedTag: row?.fixedTag ?? false,
function chores() { showLink: row?.showLink ?? true,
message(`${title}了菜单名称为${$t(curData.title)}的这条数据`, { showParent: row?.showParent ?? false,
type: 'success', },
}); },
done(); // 关闭弹框 width: '45%',
onSearch(); // 刷新表格数据 draggable: true,
} fullscreen: deviceDetection(),
fullscreenIcon: true,
FormRef.validate(valid => { closeOnClickModal: false,
if (valid) { contentRenderer: () => h(editForm, { ref: formRef, formInline: null }),
console.log('curData', curData); beforeSure: (done, { options }) => {
// 表单规则校验通过 const FormRef = formRef.value.getRef();
if (title === '新增') { const curData = options.props.formInline as FormItemProps;
// 实际开发先调用新增接口,再进行下面操作
chores(); function chores() {
} else { message(`${title}了菜单名称为${$t(curData.title)}的这条数据`, {
// 实际开发先调用修改接口,再进行下面操作 type: 'success',
chores(); });
} done(); // 关闭弹框
} onSearch(); // 刷新表格数据
}); }
},
}); FormRef.validate(valid => {
} if (valid) {
console.log('curData', curData);
function handleDelete(row) { // 表单规则校验通过
message(`您删除了菜单名称为${$t(row.title)}的这条数据`, { if (title === '新增') {
type: 'success', // 实际开发先调用新增接口,再进行下面操作
}); chores();
onSearch(); } else {
} // 实际开发先调用修改接口,再进行下面操作
chores();
onMounted(() => { }
onSearch(); }
}); });
},
return { });
form, }
loading,
columns, export function handleDelete(row) {
dataList, message(`您删除了菜单名称为${$t(row.title)}的这条数据`, {
/** 搜索 */ type: 'success',
onSearch, });
/** 重置 */ onSearch();
resetForm,
/** 新增、修改菜单 */
openDialog,
/** 删除菜单 */
handleDelete,
handleSelectionChange,
};
} }

View File

@ -1,10 +1,10 @@
import { reactive } from "vue"; import { reactive } from 'vue';
import type { FormRules } from "element-plus"; import type { FormRules } from 'element-plus';
/** 自定义表单规则校验 */ /** 自定义表单规则校验 */
export const formRules = reactive(<FormRules>{ export const formRules = reactive(<FormRules>{
title: [{ required: true, message: "菜单名称为必填项", trigger: "blur" }], title: [{ required: true, message: '菜单名称为必填项', trigger: 'blur' }],
name: [{ required: true, message: "路由名称为必填项", trigger: "blur" }], name: [{ required: true, message: '路由名称为必填项', trigger: 'blur' }],
path: [{ required: true, message: "路由路径为必填项", trigger: "blur" }], path: [{ required: true, message: '路由路径为必填项', trigger: 'blur' }],
auths: [{ required: true, message: "权限标识为必填项", trigger: "blur" }] auths: [{ required: true, message: '权限标识为必填项', trigger: 'blur' }],
}); });