初始化
This commit is contained in:
203
src/views/system/menu/modules/icon-options.ts
Normal file
203
src/views/system/menu/modules/icon-options.ts
Normal file
@@ -0,0 +1,203 @@
|
||||
export interface IconOptionGroup {
|
||||
label: string;
|
||||
value: string;
|
||||
icons: string[];
|
||||
}
|
||||
|
||||
export const menuIconGroups: IconOptionGroup[] = [
|
||||
{
|
||||
label: '导航布局',
|
||||
value: 'navigation',
|
||||
icons: [
|
||||
'mdi:home-outline',
|
||||
'mdi:view-dashboard-outline',
|
||||
'mdi:menu-open',
|
||||
'mdi:map',
|
||||
'mdi:compass-outline',
|
||||
'mdi:application-outline',
|
||||
'mdi:monitor-dashboard',
|
||||
'material-symbols:dashboard-outline',
|
||||
'material-symbols:space-dashboard-outline',
|
||||
'material-symbols:route',
|
||||
'material-symbols:account-tree-outline',
|
||||
'icon-park-outline:all-application',
|
||||
'tabler:layout-dashboard',
|
||||
'tabler:sitemap',
|
||||
'tabler:apps',
|
||||
'tabler:browser',
|
||||
'carbon:network-overlay',
|
||||
'hugeicons:flow-square'
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '系统管理',
|
||||
value: 'system',
|
||||
icons: [
|
||||
'ep:setting',
|
||||
'ep:tools',
|
||||
'ep:operation',
|
||||
'ep:management',
|
||||
'ep:monitor',
|
||||
'ep:platform',
|
||||
'ep:connection',
|
||||
'ep:office-building',
|
||||
'mdi:cog-outline',
|
||||
'mdi:tune-variant',
|
||||
'mdi:server-outline',
|
||||
'mdi:cloud-outline',
|
||||
'mdi:shield-crown-outline',
|
||||
'carbon:cloud-service-management',
|
||||
'carbon:network-overlay',
|
||||
'ic:round-manage-accounts',
|
||||
'ic:round-supervisor-account',
|
||||
'carbon:user-role',
|
||||
'material-symbols:admin-panel-settings-outline',
|
||||
'material-symbols:settings-outline-rounded'
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '用户权限',
|
||||
value: 'user',
|
||||
icons: [
|
||||
'ep:user',
|
||||
'ep:user-filled',
|
||||
'ep:avatar',
|
||||
'mdi:account-outline',
|
||||
'mdi:account-group-outline',
|
||||
'mdi:account-key-outline',
|
||||
'mdi:badge-account-outline',
|
||||
'mdi:card-account-details-outline',
|
||||
'mdi:key-outline',
|
||||
'mdi:shield-account-outline',
|
||||
'mdi:lock-outline',
|
||||
'ri:admin-line',
|
||||
'ri:user-settings-line',
|
||||
'carbon:user-avatar',
|
||||
'carbon:user-role',
|
||||
'carbon:user-admin',
|
||||
'carbon:user-multiple',
|
||||
'ic:round-supervisor-account'
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '文档表单',
|
||||
value: 'document',
|
||||
icons: [
|
||||
'mdi:file-document-outline',
|
||||
'mdi:file-document-edit-outline',
|
||||
'mdi:file-document-multiple-outline',
|
||||
'mdi:clipboard-outline',
|
||||
'mdi:book-open-page-variant-outline',
|
||||
'mdi:form-select',
|
||||
'mdi:notebook-outline',
|
||||
'ri:file-excel-2-line',
|
||||
'ri:markdown-line',
|
||||
'uiw:file-pdf',
|
||||
'gridicons:posts',
|
||||
'icon-park-outline:editor',
|
||||
'material-symbols:article-outline',
|
||||
'material-symbols:description-outline',
|
||||
'ph:archive-box-light',
|
||||
'ph:note-pencil',
|
||||
'tabler:files',
|
||||
'tabler:report'
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '数据分析',
|
||||
value: 'data',
|
||||
icons: [
|
||||
'ant-design:bar-chart-outlined',
|
||||
'mdi:chart-areaspline',
|
||||
'mdi:chart-bar',
|
||||
'mdi:chart-box-outline',
|
||||
'mdi:database-outline',
|
||||
'mdi:table-large',
|
||||
'mdi:table-search',
|
||||
'icon-park-outline:table',
|
||||
'material-symbols:analytics-outline',
|
||||
'material-symbols:table-chart-outline',
|
||||
'material-symbols:dataset-outline',
|
||||
'simple-icons:apacheecharts',
|
||||
'simple-icons:swiper',
|
||||
'ri:pie-chart-2-line',
|
||||
'ri:line-chart-line',
|
||||
'tabler:chart-bar',
|
||||
'tabler:chart-donut',
|
||||
'tabler:database'
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '业务工具',
|
||||
value: 'business',
|
||||
icons: [
|
||||
'clarity:plugin-line',
|
||||
'ic:round-barcode',
|
||||
'mdi:printer',
|
||||
'mdi:typewriter',
|
||||
'mdi:video',
|
||||
'mdi:map-marker-path',
|
||||
'mdi:tools',
|
||||
'mdi:wrench-outline',
|
||||
'mdi:qrcode-scan',
|
||||
'mdi:hammer-wrench',
|
||||
'material-symbols:construction-outline',
|
||||
'material-symbols:extension-outline',
|
||||
'material-symbols:inventory-2-outline',
|
||||
'carbon:tool-kit',
|
||||
'carbon:settings-adjust',
|
||||
'ph:toolbox',
|
||||
'ph:package',
|
||||
'hugeicons:flow-square'
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '状态反馈',
|
||||
value: 'status',
|
||||
icons: [
|
||||
'ant-design:exception-outlined',
|
||||
'ic:baseline-block',
|
||||
'ic:baseline-web-asset-off',
|
||||
'ic:baseline-wifi-off',
|
||||
'material-symbols:filter-list-off',
|
||||
'mdi:alert-outline',
|
||||
'mdi:check-circle-outline',
|
||||
'mdi:close-circle-outline',
|
||||
'mdi:information-outline',
|
||||
'mdi:timer-sand',
|
||||
'mdi:progress-question',
|
||||
'tabler:alert-circle',
|
||||
'tabler:circle-check',
|
||||
'tabler:circle-x',
|
||||
'tabler:info-circle'
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '通用备选',
|
||||
value: 'common',
|
||||
icons: [
|
||||
'mdi:apps-box',
|
||||
'mdi:emoticon',
|
||||
'mdi:ab-testing',
|
||||
'mdi:alert',
|
||||
'mdi:airballoon',
|
||||
'mdi:airplane-edit',
|
||||
'mdi:alpha-f-box-outline',
|
||||
'mdi:arm-flex-outline',
|
||||
'ph:alarm',
|
||||
'ph:android-logo',
|
||||
'ph:align-bottom',
|
||||
'uil:basketball',
|
||||
'uil:brightness-plus',
|
||||
'uil:capture',
|
||||
'ic:baseline-10mp',
|
||||
'ic:baseline-access-time',
|
||||
'ic:baseline-brightness-4',
|
||||
'ic:baseline-brightness-5',
|
||||
'ic:baseline-credit-card',
|
||||
'entypo-social:google-hangouts'
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
export const menuIconOptions = Array.from(new Set(menuIconGroups.flatMap(group => group.icons)));
|
||||
62
src/views/system/menu/modules/menu-icon-cell.tsx
Normal file
62
src/views/system/menu/modules/menu-icon-cell.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import { defineComponent, ref, watch } from 'vue';
|
||||
import { loadIcon } from '@iconify/vue';
|
||||
import SvgIcon from '@/components/custom/svg-icon.vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MenuIconCell',
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const failed = ref(false);
|
||||
|
||||
watch(
|
||||
() => props.icon,
|
||||
(value, _, onCleanup) => {
|
||||
const icon = value.trim();
|
||||
|
||||
failed.value = !icon;
|
||||
|
||||
if (!icon) {
|
||||
return;
|
||||
}
|
||||
|
||||
let active = true;
|
||||
|
||||
onCleanup(() => {
|
||||
active = false;
|
||||
});
|
||||
|
||||
loadIcon(icon)
|
||||
.then(() => {
|
||||
if (active) {
|
||||
failed.value = false;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
if (active) {
|
||||
failed.value = true;
|
||||
}
|
||||
});
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
return () => {
|
||||
const icon = props.icon.trim();
|
||||
|
||||
if (!icon || failed.value) {
|
||||
return <div class="flex-center text-[#909399]">--</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="flex-center">
|
||||
<SvgIcon icon={icon} class="text-18px text-[#303133]" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
});
|
||||
58
src/views/system/menu/modules/menu-operate-cell.tsx
Normal file
58
src/views/system/menu/modules/menu-operate-cell.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { computed, defineComponent } from 'vue';
|
||||
import type { PropType } from 'vue';
|
||||
import BusinessTableActionCell, { type BusinessTableAction } from '@/components/custom/business-table-action-cell';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MenuOperateCell',
|
||||
props: {
|
||||
row: {
|
||||
type: Object as PropType<Api.SystemManage.Menu>,
|
||||
required: true
|
||||
},
|
||||
onEdit: {
|
||||
type: Function as PropType<(row: Api.SystemManage.Menu) => void>,
|
||||
required: true
|
||||
},
|
||||
onAddChild: {
|
||||
type: Function as PropType<(row: Api.SystemManage.Menu) => void>,
|
||||
required: true
|
||||
},
|
||||
onDelete: {
|
||||
type: Function as PropType<(row: Api.SystemManage.Menu) => Promise<void>>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const actions = computed<BusinessTableAction[]>(() => {
|
||||
const list: BusinessTableAction[] = [
|
||||
{
|
||||
key: 'edit',
|
||||
label: $t('common.edit'),
|
||||
buttonType: 'primary',
|
||||
onClick: () => props.onEdit(props.row)
|
||||
}
|
||||
];
|
||||
|
||||
if (props.row.type !== 3) {
|
||||
list.push({
|
||||
key: 'addChild',
|
||||
label: $t('page.system.menu.addChildMenu'),
|
||||
buttonType: 'primary',
|
||||
onClick: () => props.onAddChild(props.row)
|
||||
});
|
||||
}
|
||||
|
||||
list.push({
|
||||
key: 'delete',
|
||||
label: $t('common.delete'),
|
||||
buttonType: 'danger',
|
||||
onClick: () => props.onDelete(props.row)
|
||||
});
|
||||
|
||||
return list;
|
||||
});
|
||||
|
||||
return () => <BusinessTableActionCell actions={actions.value} />;
|
||||
}
|
||||
});
|
||||
1211
src/views/system/menu/modules/menu-operate-dialog.vue
Normal file
1211
src/views/system/menu/modules/menu-operate-dialog.vue
Normal file
File diff suppressed because it is too large
Load Diff
35
src/views/system/menu/modules/menu-search.vue
Normal file
35
src/views/system/menu/modules/menu-search.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<script setup lang="ts">
|
||||
import TableSearchPanel from '@/components/custom/table-search-panel.vue';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
defineOptions({ name: 'MenuSearch' });
|
||||
|
||||
interface Emits {
|
||||
(e: 'reset'): void;
|
||||
(e: 'search'): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const model = defineModel<Api.SystemManage.MenuSearchParams>('model', { required: true });
|
||||
|
||||
function reset() {
|
||||
emit('reset');
|
||||
}
|
||||
|
||||
function search() {
|
||||
emit('search');
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TableSearchPanel :model="model" :action-col-lg="6" :action-col-md="8" @reset="reset" @search="search">
|
||||
<ElCol :lg="6" :md="8" :sm="12">
|
||||
<ElFormItem :label="$t('page.system.menu.menuName')" prop="name">
|
||||
<ElInput v-model="model.name" clearable :placeholder="$t('page.system.menu.form.menuName')" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</TableSearchPanel>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
79
src/views/system/menu/modules/shared.ts
Normal file
79
src/views/system/menu/modules/shared.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
const LAYOUT_PREFIX = 'layout.';
|
||||
const VIEW_PREFIX = 'view.';
|
||||
const FIRST_LEVEL_ROUTE_COMPONENT_SPLIT = '$';
|
||||
|
||||
export function getLayoutAndPage(component?: string | null) {
|
||||
let layout = '';
|
||||
let page = '';
|
||||
|
||||
const [layoutOrPage = '', pageItem = ''] = component?.split(FIRST_LEVEL_ROUTE_COMPONENT_SPLIT) || [];
|
||||
|
||||
layout = getLayout(layoutOrPage);
|
||||
page = getPage(pageItem || layoutOrPage);
|
||||
|
||||
return { layout, page };
|
||||
}
|
||||
|
||||
function getLayout(layout: string) {
|
||||
return layout.startsWith(LAYOUT_PREFIX) ? layout.replace(LAYOUT_PREFIX, '') : '';
|
||||
}
|
||||
|
||||
function getPage(page: string) {
|
||||
return page.startsWith(VIEW_PREFIX) ? page.replace(VIEW_PREFIX, '') : '';
|
||||
}
|
||||
|
||||
export function transformLayoutAndPageToComponent(layout: string, page: string) {
|
||||
const hasLayout = Boolean(layout);
|
||||
const hasPage = Boolean(page);
|
||||
|
||||
if (hasLayout && hasPage) {
|
||||
return `${LAYOUT_PREFIX}${layout}${FIRST_LEVEL_ROUTE_COMPONENT_SPLIT}${VIEW_PREFIX}${page}`;
|
||||
}
|
||||
|
||||
if (hasLayout) {
|
||||
return `${LAYOUT_PREFIX}${layout}`;
|
||||
}
|
||||
|
||||
if (hasPage) {
|
||||
return `${VIEW_PREFIX}${page}`;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get route name by route path
|
||||
*
|
||||
* @param routeName
|
||||
*/
|
||||
export function getRoutePathByRouteName(routeName: string) {
|
||||
return `/${routeName.replace(/_/g, '/')}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get path param from route path
|
||||
*
|
||||
* @param routePath route path
|
||||
*/
|
||||
export function getPathParamFromRoutePath(routePath: string) {
|
||||
const [path, param = ''] = routePath.split('/:');
|
||||
|
||||
return {
|
||||
path,
|
||||
param
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get route path with param
|
||||
*
|
||||
* @param routePath route path
|
||||
* @param param path param
|
||||
*/
|
||||
export function getRoutePathWithParam(routePath: string, param: string) {
|
||||
if (param.trim()) {
|
||||
return `${routePath}/:${param}`;
|
||||
}
|
||||
|
||||
return routePath;
|
||||
}
|
||||
Reference in New Issue
Block a user