Commit 8846a011 authored by 水落(YangLei)'s avatar 水落(YangLei)

feat: 菜单管理页面大体完成

parent ea21c88e
import { request, METHOD } from '@/utils'; import { request, METHOD } from '@/utils';
export * from './menu';
export function getUserDetailInfoApi() { export function getUserDetailInfoApi() {
return request('/api/v1/detail', METHOD.GET); return request('/api/v1/detail', METHOD.GET);
......
import { delReq, getReq, postReq } from '@/utils';
export function delMenuApi(id) {
return delReq(`/api/v1/menus/${id}`);
}
export function getMenuDataApi() {
return getReq('/api/v1/menus');
}
export function addMenuApi(data) {
return postReq('/api/v1/menus', data);
}
<template>
<a-popconfirm title="确认是否删除" ok-text="确认" cancel-text="取消" @confirm="onOk" @cancel="onCancel">
<a>删除</a>
</a-popconfirm>
</template>
<script>
import { EMPTY_FUN } from '@/utils';
export default {
props: {
onOk: Function,
onCancel: {
type: Function,
default: EMPTY_FUN,
},
},
};
</script>
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
</template> </template>
</a-space> </a-space>
<a-table :data-source="data" :loading="loading" v-bind="$attrs"> <a-table :data-source="data" :loading="loading" v-bind="$attrs" :pagination="!noPage">
<slot /> <slot />
</a-table> </a-table>
</div> </div>
...@@ -35,9 +35,23 @@ ...@@ -35,9 +35,23 @@
:visible="addVisible" :visible="addVisible"
@close="addDrawerClose" @close="addDrawerClose"
v-if="addBtn" v-if="addBtn"
:maskClosable="addBtn.maskClosable" :maskClosable="!!addBtn.maskClosable"
:closable="false"
:drawerStyle="drawerStyle"
:bodyStyle="bodyStyle"
:width="addBtn.width"
destroyOnClose
> >
<div class="tw-overflow-y-hidden">
<div class="tw-overflow-y-auto tw-h-full">
<slot name="add" /> <slot name="add" />
</div>
</div>
<a-divider />
<a-space>
<a-button @click="addVisible = false">取消</a-button>
<a-button type="primary" @click="submit" :loading="submitLoading">确认</a-button>
</a-space>
</a-drawer> </a-drawer>
</div> </div>
</template> </template>
...@@ -45,71 +59,6 @@ ...@@ -45,71 +59,6 @@
<script> <script>
import { request, METHOD } from '@/utils/requestUtil'; import { request, METHOD } from '@/utils/requestUtil';
const data = [
{
key: 1,
name: 'John Brown sr.',
age: 60,
address: 'New York No. 1 Lake Park',
children: [
{
key: 11,
name: 'John Brown',
age: 42,
address: 'New York No. 2 Lake Park',
},
{
key: 12,
name: 'John Brown jr.',
age: 30,
address: 'New York No. 3 Lake Park',
children: [
{
key: 121,
name: 'Jimmy Brown',
age: 16,
address: 'New York No. 3 Lake Park',
},
],
},
{
key: 13,
name: 'Jim Green sr.',
age: 72,
address: 'London No. 1 Lake Park',
children: [
{
key: 131,
name: 'Jim Green',
age: 42,
address: 'London No. 2 Lake Park',
children: [
{
key: 1311,
name: 'Jim Green jr.',
age: 25,
address: 'London No. 3 Lake Park',
},
{
key: 1312,
name: 'Jimmy Green sr.',
age: 18,
address: 'London No. 4 Lake Park',
},
],
},
],
},
],
},
{
key: 2,
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
},
];
export default { export default {
props: { props: {
url: String, url: String,
...@@ -121,6 +70,7 @@ export default { ...@@ -121,6 +70,7 @@ export default {
type: Object, type: Object,
}, },
formatData: Function, formatData: Function,
noPage: Boolean,
}, },
data() { data() {
return { return {
...@@ -128,8 +78,25 @@ export default { ...@@ -128,8 +78,25 @@ export default {
queryForm: {}, queryForm: {},
loading: false, loading: false,
addVisible: false, addVisible: false,
submitLoading: false,
drawerStyle: {
display: 'flex',
flexDirection: 'column',
overflowY: 'hidden',
},
bodyStyle: {
flex: 1,
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
},
}; };
}, },
watch: {
addVisible(val) {
if (!val && this.addBtn.onCancel) this.addBtn.onCancel();
},
},
mounted() { mounted() {
console.log(this.addBtn); console.log(this.addBtn);
this.getData(); this.getData();
...@@ -153,6 +120,22 @@ export default { ...@@ -153,6 +120,22 @@ export default {
addDrawerClose() { addDrawerClose() {
this.addVisible = false; this.addVisible = false;
}, },
async submit() {
this.submitLoading = true;
try {
await this.addBtn?.onOk();
} catch (error) {
// todo
}
this.submitLoading = false;
this.addVisible = false;
},
showAdd() {
this.addVisible = true;
},
refresh() {
this.getData();
},
}, },
}; };
</script> </script>
......
...@@ -34,7 +34,7 @@ const store = new Vuex.Store({ ...@@ -34,7 +34,7 @@ const store = new Vuex.Store({
Vue.use(Router); Vue.use(Router);
const isAsynRount = store.state.settingModule.asyncRoutes; const isAsynRount = store.state.settingModule.asyncRoutes;
const options = initRouter(isAsynRount); const options = initRouter(isAsynRount);
const router = new Router(options); const router = new Router({ mode: 'history', ...options });
//装载vue-i18n控件 如果语言优先级 请直接修改这里localeLang和fallbackLang //装载vue-i18n控件 如果语言优先级 请直接修改这里localeLang和fallbackLang
Vue.use(VueI18n); Vue.use(VueI18n);
......
<template> <template>
<my-table url="/api/v1/menus" :addBtn="addBtn" :formatData="formatData" rowKey="menuId"> <my-table
url="/api/v1/menus"
:addBtn="addBtn"
:formatData="formatData"
rowKey="menuId"
noPage
ref="table"
>
<template #search="{query}"> <template #search="{query}">
<a-form-model-item label="菜单、目录名称"> <a-form-model-item label="菜单、目录名称">
<a-input v-model="query.name" /> <a-input v-model="query.name" />
</a-form-model-item> </a-form-model-item>
</template> </template>
<template #add> <template #add>
<a-input v-model="add.name" /> <Form ref="addForm" />
</template> </template>
<a-table-column title="名称" data-index="menuName" /> <a-table-column title="名称" data-index="menuName" />
<a-table-column title="类型" data-index="menuTypeName" /> <a-table-column title="类型" data-index="menuTypeName" />
<a-table-column title="显示排序" data-index="viewIndex" :sorter="sorter" sortOrder="ascend" /> <a-table-column title="显示排序" data-index="viewIndex" :sorter="sorter" sortOrder="ascend" />
<a-table-column title="显示图标" data-index="menuIcon" /> <a-table-column title="显示图标" data-index="menuIcon" />
<a-table-column title="模块URL" data-index="menuUrl" /> <a-table-column title="模块URL" data-index="menuUrl" />
<a-table-column title="操作"> <a-table-column title="操作">
<template #default> <template #default="row">
<span> <a @click="() => edit(row)">编辑</a>
<a>编辑</a>
<a-divider type="vertical" /> <a-divider type="vertical" />
<a>删除</a> <PopconfirmDelete :onOk="() => delMenu(row.menuId)" />
</span>
</template> </template>
</a-table-column> </a-table-column>
</my-table> </my-table>
...@@ -27,19 +34,45 @@ ...@@ -27,19 +34,45 @@
<script> <script>
import { convertListToTree } from '@/utils'; import { convertListToTree } from '@/utils';
import PopconfirmDelete from '@/components/popconfirm_delete/index.vue';
import { delMenuApi } from '@/api';
import Form from './form.vue';
export default { export default {
data: () => ({ data: vm => ({
add: {}, addBtn: {
addBtn: { text: '新建', title: '菜单配置' }, text: '新建',
title: '菜单配置',
width: 400,
async onOk() {
await vm.$refs['addForm']?.submit();
vm.refreshTable();
},
},
sortOrder: 'ascend', sortOrder: 'ascend',
}), }),
components: { PopconfirmDelete, Form },
methods: { methods: {
formatData: convertListToTree, formatData: convertListToTree,
refreshTable() {
this.$refs['table'].refresh();
},
async delMenu(id) {
await delMenuApi(id);
this.refreshTable();
},
sorter(pre, next) { sorter(pre, next) {
return pre.viewIndex - next.viewIndex; return pre.viewIndex - next.viewIndex;
}, },
edit(data) {
console.log(data);
this.$refs['table']?.showAdd();
this.$nextTick(() => {
this.$refs['addForm'].setEdit(data);
});
},
}, },
}; };
</script> </script>
<template>
<a-form-model layout="vertical" :model="form" :rules="rules">
<a-form-model-item label="父级" v-if="isAdd">
<a-tree
v-model="checkedKeys"
:selectable="false"
checkable
checkStrictly
:replaceFields="replaceFields"
:tree-data="treeData"
@check="onCheck"
style="max-height:400px"
class="tw-overflow-y-auto"
/>
</a-form-model-item>
<a-form-model-item label="类型">
<a-radio-group v-model="form.menuType" :disabled="isEdit">
<a-radio value="CATALOG">目录</a-radio>
<a-radio value="MENU">菜单</a-radio>
</a-radio-group>
</a-form-model-item>
<a-form-model-item label="中文名称">
<a-input v-model="form.menuName" />
</a-form-model-item>
<a-form-model-item label="英文名称">
<a-input />
</a-form-model-item>
<a-form-model-item label="模块URL" prop="menuUrl">
<a-input v-model="form.menuUrl" />
</a-form-model-item>
<a-form-model-item label="显示排序" prop="viewIndex">
<a-input-number v-model="form.viewIndex" />
</a-form-model-item>
<a-form-model-item label="显示图标" prop="menuIcon">
<a-input v-model="form.menuIcon" />
</a-form-model-item>
<a-form-model-item label="说明" prop="menuRemark">
<a-textarea v-model="form.menuRemark" />
</a-form-model-item>
</a-form-model>
</template>
<script>
import { getMenuDataApi, addMenuApi } from '@/api';
import { convertListToTree } from '@/utils';
export default {
data: () => ({
type: 0,
form: {
menuType: 'CATALOG',
parentMenuId: 0,
menuName: '',
},
rules: {
menuUrl: [{ required: true }],
},
replaceFields: {
title: 'menuName',
key: 'menuId',
},
checkedKeys: {
checked: [],
halfChecked: [],
},
treeData: [],
}),
mounted() {
this.getMenuData();
},
computed: {
isAdd() {
return this.type === 0;
},
isEdit() {
return this.type === 1;
},
},
methods: {
async getMenuData() {
this.treeData = convertListToTree(await getMenuDataApi(), true);
console.log(this.treeData);
},
submit() {
return addMenuApi({ ...this.form, parentMenuId: this.checkedKeys.checked[0] ?? 0 });
},
onCheck(checkedKeys) {
this.checkedKeys.checked = checkedKeys.checked.slice(-1);
},
setEdit(data) {
this.type = 1;
this.form = data;
},
},
};
</script>
...@@ -11,7 +11,6 @@ import { getI18nKey } from '@/utils/routerUtil'; ...@@ -11,7 +11,6 @@ import { getI18nKey } from '@/utils/routerUtil';
function generateI18n(lang, routes, valueKey) { function generateI18n(lang, routes, valueKey) {
routes.forEach(route => { routes.forEach(route => {
let keys = getI18nKey(route.fullPath).split('.'); let keys = getI18nKey(route.fullPath).split('.');
console.log(keys);
let value = let value =
valueKey === 'path' valueKey === 'path'
? route[valueKey] ? route[valueKey]
......
...@@ -13,9 +13,13 @@ export function setUserId(val) { ...@@ -13,9 +13,13 @@ export function setUserId(val) {
/** /**
* 转变菜单列表为tree结构 * 转变菜单列表为tree结构
* @param {Array} menuList 菜单列表 * @param {Array} menuList 菜单列表
* @param {Boolean} filterMenu 是否过滤掉菜单,只保留目录
*/ */
export function convertListToTree(menuList) { export function convertListToTree(menuList, filterMenu = false) {
const tempMenu = [...menuList]; let tempMenu = [...menuList];
if (filterMenu) {
tempMenu = tempMenu.filter(m => m.menuType !== 'MENU');
}
for (const menu of menuList) { for (const menu of menuList) {
if (menu.parentMenuId === 0) continue; if (menu.parentMenuId === 0) continue;
const parent = menuList.find(m => m.menuId === menu.parentMenuId); const parent = menuList.find(m => m.menuId === menu.parentMenuId);
...@@ -23,3 +27,5 @@ export function convertListToTree(menuList) { ...@@ -23,3 +27,5 @@ export function convertListToTree(menuList) {
} }
return tempMenu.filter(m => m.parentMenuId === 0); return tempMenu.filter(m => m.parentMenuId === 0);
} }
export function EMPTY_FUN() {}
...@@ -133,4 +133,27 @@ function checkAuthorization() { ...@@ -133,4 +133,27 @@ function checkAuthorization() {
return !!getToken(); return !!getToken();
} }
export { METHOD, request, parseUrlParams, loadResponseInterceptor, setToken, checkAuthorization, clearToken }; function delReq(url, config) {
return request(url, METHOD.DELETE, config);
}
function getReq(url, params, config) {
return request(url, METHOD.GET, params, config);
}
function postReq(url, data, config) {
return request(url, METHOD.POST, data, config);
}
export {
METHOD,
request,
parseUrlParams,
loadResponseInterceptor,
setToken,
checkAuthorization,
clearToken,
delReq,
getReq,
postReq,
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment