feat: 暗黑模式临时提交
Former-commit-id: 8653f21636d0c32f48caae65a52aca98cbef8710
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"globals": {
|
"globals": {
|
||||||
"EffectScope": true,
|
"EffectScope": true,
|
||||||
|
"ElForm": true,
|
||||||
"ElMessage": true,
|
"ElMessage": true,
|
||||||
"ElMessageBox": true,
|
"ElMessageBox": true,
|
||||||
"asyncComputed": true,
|
"asyncComputed": true,
|
||||||
|
|||||||
@@ -32,13 +32,13 @@ function toggleClick() {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style lang="scss" scoped>
|
||||||
.hamburger {
|
.hamburger {
|
||||||
|
display: inline-block;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
&.is-active {
|
||||||
|
transform: rotate(180deg);
|
||||||
.hamburger.is-active {
|
}
|
||||||
transform: rotate(180deg);
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ onMounted(() => {
|
|||||||
placeholder="点击选择图标"
|
placeholder="点击选择图标"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<svg-icon :iconName="inputValue"></svg-icon>
|
<svg-icon :icon-class="inputValue"></svg-icon>
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ const symbolId = computed(() => `#${props.prefix}-${props.iconClass}`);
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
|
display: inline-block;
|
||||||
outline: none;
|
outline: none;
|
||||||
width: 1em;
|
width: 1em;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
|
|||||||
@@ -4,25 +4,24 @@ import { Sunny, Moon } from '@element-plus/icons-vue';
|
|||||||
import { useSettingsStore } from '@/store/modules/settings';
|
import { useSettingsStore } from '@/store/modules/settings';
|
||||||
|
|
||||||
import { useDark, useToggle } from '@vueuse/core';
|
import { useDark, useToggle } from '@vueuse/core';
|
||||||
import { ElDivider, ElSwitch, ElTooltip } from 'element-plus';
|
/**
|
||||||
import { onMounted } from 'vue';
|
* 暗黑模式
|
||||||
|
*/
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
const isDark = useDark();
|
const isDark = useDark();
|
||||||
|
const toggleDark = useToggle(isDark);
|
||||||
|
|
||||||
function toggleTheme() {
|
/**
|
||||||
const isDark = useDark();
|
* 切换布局
|
||||||
useToggle(isDark);
|
*/
|
||||||
|
function changeLayout(layout: string) {
|
||||||
|
settingsStore.changeSetting({ key: 'layout', value: layout });
|
||||||
|
window.document.body.setAttribute('layout', settingsStore.layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.document.body.setAttribute('layout', settingsStore.layout);
|
window.document.body.setAttribute('layout', settingsStore.layout);
|
||||||
});
|
});
|
||||||
|
|
||||||
function changeLayout(layout: string) {
|
|
||||||
settingsStore.changeSetting({ key: 'layout', value: layout });
|
|
||||||
window.document.body.setAttribute('layout', settingsStore.layout);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -46,11 +45,12 @@ function changeLayout(layout: string) {
|
|||||||
|
|
||||||
<el-divider>主题</el-divider>
|
<el-divider>主题</el-divider>
|
||||||
|
|
||||||
<div class="flex justify-center" @click.stop>
|
<button @click="toggleDark()">当前状态是: {{ isDark }}</button>
|
||||||
|
|
||||||
|
<div class="flex justify-center" @click="toggleDark()">
|
||||||
<el-switch
|
<el-switch
|
||||||
v-model="isDark"
|
v-model="isDark"
|
||||||
inline-prompt
|
inline-prompt
|
||||||
@change="toggleTheme"
|
|
||||||
:active-icon="Sunny"
|
:active-icon="Sunny"
|
||||||
:inactive-icon="Moon"
|
:inactive-icon="Moon"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,12 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {
|
import { ComponentInternalInstance } from 'vue';
|
||||||
getCurrentInstance,
|
|
||||||
nextTick,
|
|
||||||
ref,
|
|
||||||
watch,
|
|
||||||
onMounted,
|
|
||||||
ComponentInternalInstance
|
|
||||||
} from 'vue';
|
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
|
||||||
import path from 'path-browserify';
|
import path from 'path-browserify';
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import i18n from '@/lang/index';
|
|||||||
|
|
||||||
import '@/styles/index.scss';
|
import '@/styles/index.scss';
|
||||||
import 'element-plus/theme-chalk/index.css';
|
import 'element-plus/theme-chalk/index.css';
|
||||||
//import 'element-plus/theme-chalk/dark/css-vars.css';
|
import 'element-plus/theme-chalk/dark/css-vars.css';
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
// 自定义指令
|
// 自定义指令
|
||||||
|
|||||||
11
src/styles/dark.scss
Normal file
11
src/styles/dark.scss
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// only scss variables
|
||||||
|
|
||||||
|
$--colors: (
|
||||||
|
"primary": (
|
||||||
|
"base": #589ef8,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
@forward "element-plus/theme-chalk/src/dark/var.scss" with (
|
||||||
|
$colors: $--colors
|
||||||
|
);
|
||||||
@@ -10,12 +10,6 @@
|
|||||||
font-weight: 400 !important;
|
font-weight: 400 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.el-upload__input {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 选中行背景色值
|
// 选中行背景色值
|
||||||
.el-table__body tr.current-row td {
|
.el-table__body tr.current-row td {
|
||||||
background-color: #e1f3d8b5 !important;
|
background-color: #e1f3d8b5 !important;
|
||||||
|
|||||||
@@ -2,10 +2,8 @@
|
|||||||
@import 'src/styles/element-plus';
|
@import 'src/styles/element-plus';
|
||||||
@import './sidebar.scss';
|
@import './sidebar.scss';
|
||||||
@import './tailwind.scss';
|
@import './tailwind.scss';
|
||||||
|
@import './reset.scss';
|
||||||
|
|
||||||
html,body,#app{
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
// main-container global css
|
// main-container global css
|
||||||
.app-container {
|
.app-container {
|
||||||
@@ -20,6 +18,3 @@ html,body,#app{
|
|||||||
box-shadow: 1px 1px 1px #eee;
|
box-shadow: 1px 1px 1px #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
svg{
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|||||||
4
src/styles/reset.scss
Normal file
4
src/styles/reset.scss
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
svg{
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
2
src/types/auto-imports.d.ts
vendored
2
src/types/auto-imports.d.ts
vendored
@@ -2,6 +2,7 @@
|
|||||||
export {}
|
export {}
|
||||||
declare global {
|
declare global {
|
||||||
const EffectScope: typeof import('vue')['EffectScope']
|
const EffectScope: typeof import('vue')['EffectScope']
|
||||||
|
const ElForm: typeof import('element-plus/es')['ElForm']
|
||||||
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
||||||
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
|
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
|
||||||
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
|
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
|
||||||
@@ -266,6 +267,7 @@ import { UnwrapRef } from 'vue'
|
|||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
interface ComponentCustomProperties {
|
interface ComponentCustomProperties {
|
||||||
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
||||||
|
readonly ElForm: UnwrapRef<typeof import('element-plus/es')['ElForm']>
|
||||||
readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']>
|
readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']>
|
||||||
readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']>
|
readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']>
|
||||||
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
|
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
|
||||||
|
|||||||
2
src/types/components.d.ts
vendored
2
src/types/components.d.ts
vendored
@@ -55,6 +55,8 @@ declare module '@vue/runtime-core' {
|
|||||||
IEpClose: typeof import('~icons/ep/close')['default']
|
IEpClose: typeof import('~icons/ep/close')['default']
|
||||||
IEpDownload: typeof import('~icons/ep/download')['default']
|
IEpDownload: typeof import('~icons/ep/download')['default']
|
||||||
IEpPlus: typeof import('~icons/ep/plus')['default']
|
IEpPlus: typeof import('~icons/ep/plus')['default']
|
||||||
|
IEpRefresh: typeof import('~icons/ep/refresh')['default']
|
||||||
|
IEpSearch: typeof import('~icons/ep/search')['default']
|
||||||
IEpTop: typeof import('~icons/ep/top')['default']
|
IEpTop: typeof import('~icons/ep/top')['default']
|
||||||
LangSelect: typeof import('./../components/LangSelect/index.vue')['default']
|
LangSelect: typeof import('./../components/LangSelect/index.vue')['default']
|
||||||
MultiUpload: typeof import('./../components/Upload/MultiUpload.vue')['default']
|
MultiUpload: typeof import('./../components/Upload/MultiUpload.vue')['default']
|
||||||
|
|||||||
@@ -1,3 +1,215 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'cmenu'
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { MenuQuery, MenuForm, Menu } from '@/api/menu/types';
|
||||||
|
// API 依赖
|
||||||
|
import {
|
||||||
|
listMenus,
|
||||||
|
getMenuDetail,
|
||||||
|
listMenuOptions,
|
||||||
|
addMenu,
|
||||||
|
deleteMenus,
|
||||||
|
updateMenu
|
||||||
|
} from '@/api/menu';
|
||||||
|
|
||||||
|
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||||
|
import IconSelect from '@/components/IconSelect/index.vue';
|
||||||
|
|
||||||
|
const emit = defineEmits(['menuClick']);
|
||||||
|
const queryFormRef = ref(ElForm);
|
||||||
|
const dataFormRef = ref(ElForm);
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
loading: true,
|
||||||
|
// 选中ID数组
|
||||||
|
ids: [],
|
||||||
|
queryParams: {} as MenuQuery,
|
||||||
|
menuList: [] as Menu[],
|
||||||
|
dialog: { visible: false } as DialogType,
|
||||||
|
formData: {
|
||||||
|
parentId: '0',
|
||||||
|
name: '',
|
||||||
|
visible: 1,
|
||||||
|
sort: 1,
|
||||||
|
component: undefined,
|
||||||
|
type: 'MENU'
|
||||||
|
} as MenuForm,
|
||||||
|
rules: {
|
||||||
|
parentId: [{ required: true, message: '请选择顶级菜单', trigger: 'blur' }],
|
||||||
|
name: [{ required: true, message: '请输入菜单名称', trigger: 'blur' }],
|
||||||
|
type: [{ required: true, message: '请选择菜单类型', trigger: 'blur' }],
|
||||||
|
path: [{ required: true, message: '请输入路由路径', trigger: 'blur' }],
|
||||||
|
component: [
|
||||||
|
{ required: true, message: '请输入组件完整路径', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
menuOptions: [] as OptionType[],
|
||||||
|
currentRow: undefined,
|
||||||
|
cacheData: {
|
||||||
|
menuType: '',
|
||||||
|
menuPath: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
loading,
|
||||||
|
queryParams,
|
||||||
|
menuList,
|
||||||
|
dialog,
|
||||||
|
formData,
|
||||||
|
rules,
|
||||||
|
menuOptions,
|
||||||
|
cacheData
|
||||||
|
} = toRefs(state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询
|
||||||
|
*/
|
||||||
|
function handleQuery() {
|
||||||
|
// 重置父组件
|
||||||
|
emit('menuClick', null);
|
||||||
|
loading.value = true;
|
||||||
|
listMenus(state.queryParams).then(({ data }) => {
|
||||||
|
menuList.value = data;
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下拉菜单
|
||||||
|
*/
|
||||||
|
async function loadMenuData() {
|
||||||
|
listMenuOptions().then(({ data }) => {
|
||||||
|
menuOptions.value = [{ value: '0', label: '顶级菜单', children: data }];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询重置
|
||||||
|
*/
|
||||||
|
function resetQuery() {
|
||||||
|
queryFormRef.value.resetFields();
|
||||||
|
handleQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRowClick(row: any) {
|
||||||
|
state.currentRow = JSON.parse(JSON.stringify(row));
|
||||||
|
emit('menuClick', row);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增菜单
|
||||||
|
*/
|
||||||
|
async function handleAdd(row: any) {
|
||||||
|
dialog.value = {
|
||||||
|
title: '添加菜单',
|
||||||
|
visible: true
|
||||||
|
};
|
||||||
|
await loadMenuData();
|
||||||
|
if (row.id) {
|
||||||
|
// 行点击新增
|
||||||
|
formData.value.parentId = row.id;
|
||||||
|
} else {
|
||||||
|
// 工具栏新增
|
||||||
|
if (state.currentRow) {
|
||||||
|
// 选择行
|
||||||
|
formData.value.parentId = (state.currentRow as any).id;
|
||||||
|
} else {
|
||||||
|
// 未选择行
|
||||||
|
formData.value.parentId = '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑菜单
|
||||||
|
*/
|
||||||
|
async function handleUpdate(row: MenuForm) {
|
||||||
|
await loadMenuData();
|
||||||
|
dialog.value = {
|
||||||
|
title: '编辑菜单',
|
||||||
|
visible: true
|
||||||
|
};
|
||||||
|
const id = row.id as string;
|
||||||
|
getMenuDetail(id).then(({ data }) => {
|
||||||
|
state.formData = data;
|
||||||
|
cacheData.value.menuType = data.type;
|
||||||
|
cacheData.value.menuPath = data.path;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单类型 change
|
||||||
|
*/
|
||||||
|
function handleMenuTypeChange(menuType: any) {
|
||||||
|
if (menuType !== cacheData.value.menuType) {
|
||||||
|
formData.value.path = '';
|
||||||
|
} else {
|
||||||
|
formData.value.path = cacheData.value.menuPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单提交
|
||||||
|
*/
|
||||||
|
function submitForm() {
|
||||||
|
dataFormRef.value.validate((isValid: boolean) => {
|
||||||
|
if (isValid) {
|
||||||
|
if (state.formData.id) {
|
||||||
|
updateMenu(state.formData.id, state.formData).then(() => {
|
||||||
|
ElMessage.success('修改成功');
|
||||||
|
cancel();
|
||||||
|
handleQuery();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
addMenu(state.formData).then(() => {
|
||||||
|
ElMessage.success('新增成功');
|
||||||
|
cancel();
|
||||||
|
handleQuery();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除菜单
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function handleDelete(row: any) {
|
||||||
|
const ids = [row.id || state.ids].join(',');
|
||||||
|
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
deleteMenus(ids).then(() => {
|
||||||
|
ElMessage.success('删除成功');
|
||||||
|
handleQuery();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => ElMessage.info('已取消删除'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消关闭弹窗
|
||||||
|
*/
|
||||||
|
function cancel() {
|
||||||
|
formData.value.id = undefined;
|
||||||
|
dataFormRef.value.resetFields();
|
||||||
|
dialog.value.visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
handleQuery();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<div class="search">
|
<div class="search">
|
||||||
@@ -11,10 +223,13 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" :icon="Search" @click="handleQuery"
|
<el-button type="primary" @click="handleQuery"
|
||||||
>搜索</el-button
|
><template #icon><i-ep-search /></template>搜索</el-button
|
||||||
|
>
|
||||||
|
<el-button @click="resetQuery">
|
||||||
|
<template #icon><i-ep-refresh /></template>
|
||||||
|
重置</el-button
|
||||||
>
|
>
|
||||||
<el-button :icon="Refresh" @click="resetQuery">重置</el-button>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
@@ -22,8 +237,9 @@
|
|||||||
<!-- 数据表格 -->
|
<!-- 数据表格 -->
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-button type="success" :icon="Plus" @click="handleAdd"
|
<el-button type="success" @click="handleAdd">
|
||||||
>新增</el-button
|
<template #icon><i-ep-plus /></template>
|
||||||
|
新增</el-button
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -122,7 +338,6 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- dialog -->
|
|
||||||
<el-dialog
|
<el-dialog
|
||||||
:title="dialog.title"
|
:title="dialog.title"
|
||||||
v-model="dialog.visible"
|
v-model="dialog.visible"
|
||||||
@@ -251,214 +466,3 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { Search, Plus, Refresh } from '@element-plus/icons-vue';
|
|
||||||
import { ElForm, ElMessage, ElMessageBox } from 'element-plus';
|
|
||||||
|
|
||||||
import { MenuQuery, MenuForm, Menu } from '@/api/menu/types';
|
|
||||||
// API 依赖
|
|
||||||
import {
|
|
||||||
listMenus,
|
|
||||||
getMenuDetail,
|
|
||||||
listMenuOptions,
|
|
||||||
addMenu,
|
|
||||||
deleteMenus,
|
|
||||||
updateMenu
|
|
||||||
} from '@/api/menu';
|
|
||||||
|
|
||||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
|
||||||
import IconSelect from '@/components/IconSelect/index.vue';
|
|
||||||
|
|
||||||
const emit = defineEmits(['menuClick']);
|
|
||||||
const queryFormRef = ref(ElForm);
|
|
||||||
const dataFormRef = ref(ElForm);
|
|
||||||
|
|
||||||
const state = reactive({
|
|
||||||
loading: true,
|
|
||||||
// 选中ID数组
|
|
||||||
ids: [],
|
|
||||||
queryParams: {} as MenuQuery,
|
|
||||||
menuList: [] as Menu[],
|
|
||||||
dialog: { visible: false } as DialogType,
|
|
||||||
formData: {
|
|
||||||
parentId: '0',
|
|
||||||
name: '',
|
|
||||||
visible: 1,
|
|
||||||
sort: 1,
|
|
||||||
component: undefined,
|
|
||||||
type: 'MENU'
|
|
||||||
} as MenuForm,
|
|
||||||
rules: {
|
|
||||||
parentId: [{ required: true, message: '请选择顶级菜单', trigger: 'blur' }],
|
|
||||||
name: [{ required: true, message: '请输入菜单名称', trigger: 'blur' }],
|
|
||||||
type: [{ required: true, message: '请选择菜单类型', trigger: 'blur' }],
|
|
||||||
path: [{ required: true, message: '请输入路由路径', trigger: 'blur' }],
|
|
||||||
component: [
|
|
||||||
{ required: true, message: '请输入组件完整路径', trigger: 'blur' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
menuOptions: [] as OptionType[],
|
|
||||||
currentRow: undefined,
|
|
||||||
cacheData: {
|
|
||||||
menuType: '',
|
|
||||||
menuPath: ''
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
|
||||||
loading,
|
|
||||||
queryParams,
|
|
||||||
menuList,
|
|
||||||
dialog,
|
|
||||||
formData,
|
|
||||||
rules,
|
|
||||||
menuOptions,
|
|
||||||
cacheData
|
|
||||||
} = toRefs(state);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询
|
|
||||||
*/
|
|
||||||
function handleQuery() {
|
|
||||||
// 重置父组件
|
|
||||||
emit('menuClick', null);
|
|
||||||
loading.value = true;
|
|
||||||
listMenus(state.queryParams).then(({ data }) => {
|
|
||||||
menuList.value = data;
|
|
||||||
loading.value = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下拉菜单
|
|
||||||
*/
|
|
||||||
async function loadMenuData() {
|
|
||||||
await listMenuOptions().then(({ data }) => {
|
|
||||||
menuOptions.value = [{ value: '0', label: '顶级菜单', children: data }];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询重置
|
|
||||||
*/
|
|
||||||
function resetQuery() {
|
|
||||||
queryFormRef.value.resetFields();
|
|
||||||
handleQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleRowClick(row: any) {
|
|
||||||
state.currentRow = JSON.parse(JSON.stringify(row));
|
|
||||||
emit('menuClick', row);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增菜单
|
|
||||||
*/
|
|
||||||
async function handleAdd(row: any) {
|
|
||||||
formData.value.id = undefined;
|
|
||||||
await loadMenuData();
|
|
||||||
dialog.value = {
|
|
||||||
title: '添加菜单',
|
|
||||||
visible: true
|
|
||||||
};
|
|
||||||
|
|
||||||
if (row.id) {
|
|
||||||
// 行点击新增
|
|
||||||
formData.value.parentId = row.id;
|
|
||||||
} else {
|
|
||||||
// 工具栏新增
|
|
||||||
if (state.currentRow) {
|
|
||||||
// 选择行
|
|
||||||
formData.value.parentId = (state.currentRow as any).id;
|
|
||||||
} else {
|
|
||||||
// 未选择行
|
|
||||||
formData.value.parentId = '0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 编辑菜单
|
|
||||||
*/
|
|
||||||
async function handleUpdate(row: MenuForm) {
|
|
||||||
await loadMenuData();
|
|
||||||
dialog.value = {
|
|
||||||
title: '编辑菜单',
|
|
||||||
visible: true
|
|
||||||
};
|
|
||||||
const id = row.id as string;
|
|
||||||
getMenuDetail(id).then(({ data }) => {
|
|
||||||
state.formData = data;
|
|
||||||
cacheData.value.menuType = data.type;
|
|
||||||
cacheData.value.menuPath = data.path;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 菜单类型 change
|
|
||||||
*/
|
|
||||||
function handleMenuTypeChange(menuType: any) {
|
|
||||||
if (menuType !== cacheData.value.menuType) {
|
|
||||||
formData.value.path = '';
|
|
||||||
} else {
|
|
||||||
formData.value.path = cacheData.value.menuPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 菜单提交
|
|
||||||
*/
|
|
||||||
function submitForm() {
|
|
||||||
dataFormRef.value.validate((isValid: boolean) => {
|
|
||||||
if (isValid) {
|
|
||||||
if (state.formData.id) {
|
|
||||||
updateMenu(state.formData.id, state.formData).then(() => {
|
|
||||||
ElMessage.success('修改成功');
|
|
||||||
cancel();
|
|
||||||
handleQuery();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
addMenu(state.formData).then(() => {
|
|
||||||
ElMessage.success('新增成功');
|
|
||||||
cancel();
|
|
||||||
handleQuery();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除菜单
|
|
||||||
*
|
|
||||||
* @param row
|
|
||||||
*/
|
|
||||||
function handleDelete(row: any) {
|
|
||||||
const ids = [row.id || state.ids].join(',');
|
|
||||||
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning'
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
deleteMenus(ids).then(() => {
|
|
||||||
ElMessage.success('删除成功');
|
|
||||||
handleQuery();
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(() => ElMessage.info('已取消删除'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 取消关闭弹窗
|
|
||||||
*/
|
|
||||||
function cancel() {
|
|
||||||
dataFormRef.value.resetFields();
|
|
||||||
state.dialog.visible = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
handleQuery();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|||||||
@@ -40,14 +40,17 @@ const state = reactive({
|
|||||||
title: '',
|
title: '',
|
||||||
visible: false
|
visible: false
|
||||||
} as DialogType,
|
} as DialogType,
|
||||||
formData: {} as RoleForm,
|
formData: {
|
||||||
|
sort: 1,
|
||||||
|
status: 1
|
||||||
|
} as RoleForm,
|
||||||
rules: {
|
rules: {
|
||||||
name: [{ required: true, message: '请输入角色名称', trigger: 'blur' }],
|
name: [{ required: true, message: '请输入角色名称', trigger: 'blur' }],
|
||||||
code: [{ required: true, message: '请输入角色编码', trigger: 'blur' }],
|
code: [{ required: true, message: '请输入角色编码', trigger: 'blur' }],
|
||||||
dataScope: [{ required: true, message: '请选择数据权限', trigger: 'blur' }],
|
dataScope: [{ required: true, message: '请选择数据权限', trigger: 'blur' }],
|
||||||
status: [{ required: true, message: '请选择状态', trigger: 'blur' }]
|
status: [{ required: true, message: '请选择状态', trigger: 'blur' }]
|
||||||
},
|
},
|
||||||
allocationDialogVisible: false,
|
resourceDialogVisible: false,
|
||||||
resourceOptions: [] as OptionType[],
|
resourceOptions: [] as OptionType[],
|
||||||
// 勾选的菜单ID
|
// 勾选的菜单ID
|
||||||
checkedMenuIds: new Set([]),
|
checkedMenuIds: new Set([]),
|
||||||
@@ -67,7 +70,7 @@ const {
|
|||||||
dialog,
|
dialog,
|
||||||
formData,
|
formData,
|
||||||
rules,
|
rules,
|
||||||
allocationDialogVisible,
|
resourceDialogVisible,
|
||||||
checkedRole,
|
checkedRole,
|
||||||
resourceOptions
|
resourceOptions
|
||||||
} = toRefs(state);
|
} = toRefs(state);
|
||||||
@@ -171,8 +174,8 @@ function handleDelete(row: any) {
|
|||||||
/**
|
/**
|
||||||
* 资源分配弹窗
|
* 资源分配弹窗
|
||||||
*/
|
*/
|
||||||
function showAllocationDialog(row: Role) {
|
function openResourceDialog(row: Role) {
|
||||||
allocationDialogVisible.value = true;
|
resourceDialogVisible.value = true;
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
||||||
const roleId: any = row.id;
|
const roleId: any = row.id;
|
||||||
@@ -206,7 +209,7 @@ function handleAllocationSubmit() {
|
|||||||
|
|
||||||
updateRoleMenus(checkedRole.value.id, checkedMenuIds).then(res => {
|
updateRoleMenus(checkedRole.value.id, checkedMenuIds).then(res => {
|
||||||
ElMessage.success('分配权限成功');
|
ElMessage.success('分配权限成功');
|
||||||
allocationDialogVisible.value = false;
|
resourceDialogVisible.value = false;
|
||||||
handleQuery();
|
handleQuery();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -214,8 +217,8 @@ function handleAllocationSubmit() {
|
|||||||
/**
|
/**
|
||||||
* 关闭资源弹窗
|
* 关闭资源弹窗
|
||||||
*/
|
*/
|
||||||
function closeAllocationDialog() {
|
function closeResourceDailog() {
|
||||||
allocationDialogVisible.value = false;
|
resourceDialogVisible.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -288,7 +291,7 @@ onMounted(() => {
|
|||||||
<el-button
|
<el-button
|
||||||
type="success"
|
type="success"
|
||||||
link
|
link
|
||||||
@click.stop="showAllocationDialog(scope.row)"
|
@click.stop="openResourceDialog(scope.row)"
|
||||||
>
|
>
|
||||||
资源分配
|
资源分配
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -306,12 +309,12 @@ onMounted(() => {
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<!-- pagination -->
|
<!-- 分页 -->
|
||||||
<pagination
|
<pagination
|
||||||
v-if="total > 0"
|
v-if="total > 0"
|
||||||
:total="total"
|
:total="total"
|
||||||
v-model:page="queryParams.pageNum"
|
:page="queryParams.pageNum"
|
||||||
v-model:limit="queryParams.pageSize"
|
:limit="queryParams.pageSize"
|
||||||
@pagination="handleQuery"
|
@pagination="handleQuery"
|
||||||
/>
|
/>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -374,7 +377,7 @@ onMounted(() => {
|
|||||||
<!-- assign permission dialog -->
|
<!-- assign permission dialog -->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
:title="'【' + checkedRole.name + '】资源分配'"
|
:title="'【' + checkedRole.name + '】资源分配'"
|
||||||
v-model="allocationDialogVisible"
|
v-model="resourceDialogVisible"
|
||||||
width="800px"
|
width="800px"
|
||||||
>
|
>
|
||||||
<el-scrollbar max-height="600px" v-loading="loading">
|
<el-scrollbar max-height="600px" v-loading="loading">
|
||||||
@@ -396,7 +399,7 @@ onMounted(() => {
|
|||||||
<el-button type="primary" @click="handleAllocationSubmit"
|
<el-button type="primary" @click="handleAllocationSubmit"
|
||||||
>确 定</el-button
|
>确 定</el-button
|
||||||
>
|
>
|
||||||
<el-button @click="closeAllocationDialog">取 消</el-button>
|
<el-button @click="closeResourceDailog">取 消</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|||||||
Reference in New Issue
Block a user