Commit c351dac8 authored by 水落(YangLei)'s avatar 水落(YangLei)

feat: 完成菜单组件管理

parent ac470ab1
...@@ -35,3 +35,11 @@ export function getRoleApi(id) { ...@@ -35,3 +35,11 @@ export function getRoleApi(id) {
export function updateRoleApi(data) { export function updateRoleApi(data) {
return putReq('/api/v1/roles', data); return putReq('/api/v1/roles', data);
} }
export function getMenuComponentApi(id) {
return getReq(`/api/v1/menus/${id}/components`);
}
export function addMenuComponentApi(id, data) {
return postReq(`/api/v1/menus/${id}/components`, data);
}
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
:onOk="btn.onOk" :onOk="btn.onOk"
:label="btn.label" :label="btn.label"
/> />
<a v-else @click="() => btn.click(row)">{{ btn.label }}</a> <a v-else @click="() => btn.click(row)" v-bind="btn.option">{{ btn.label }}</a>
<a-divider type="vertical" v-if="moreBtns.length || index !== basicBtns.length - 1" /> <a-divider type="vertical" v-if="moreBtns.length || index !== basicBtns.length - 1" />
</span> </span>
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
:onOk="btn.onOk" :onOk="btn.onOk"
:label="btn.label" :label="btn.label"
/> />
<a v-else @click="() => btn.click(row)">{{ btn.label }}</a> <a v-else @click="() => btn.click(row)" v-bind="btn.option">{{ btn.label }}</a>
</span> </span>
</a-space> </a-space>
</template> </template>
...@@ -62,6 +62,7 @@ export default { ...@@ -62,6 +62,7 @@ export default {
}, },
created() { created() {
this.init(); this.init();
console.log(this.buttonsArr);
}, },
computed: { computed: {
basicBtns() { basicBtns() {
...@@ -77,10 +78,10 @@ export default { ...@@ -77,10 +78,10 @@ export default {
return url; return url;
}, },
init() { init() {
this.buttons.map((i) => { this.buttons.map(i => {
i.__hidden__ = i.isHidden && i.isHidden(this.row); i.__hidden__ = i.isHidden && i.isHidden(this.row);
}); });
this.buttonsArr = this.buttons.filter((i) => !i.__hidden__); this.buttonsArr = this.buttons.filter(i => !i.__hidden__);
}, },
}, },
}; };
......
...@@ -15,10 +15,14 @@ ...@@ -15,10 +15,14 @@
</div> </div>
</my-card> </my-card>
<my-card class="tw-mt-3"> <my-card>
<a-space class="tw-mb-2.5"> <a-space :class="{ 'tw-mb-2.5': !!$scopedSlots.search }">
<slot name="action" /> <a-button type="primary" v-if="addBtn" @click="addBtnClick">
{{ typeof addBtn === 'object' ? addBtn.text : '新增' }}
</a-button>
<slot name="operation" />
</a-space> </a-space>
<a-table <a-table
:data-source="data" :data-source="data"
:loading="loading" :loading="loading"
...@@ -27,8 +31,26 @@ ...@@ -27,8 +31,26 @@
@change="pageChange" @change="pageChange"
> >
<slot /> <slot />
<a-table-column title="操作" v-if="buttons">
<template #default="row">
<my-ac-btn :row="row" :buttons="buttons" />
</template>
</a-table-column>
</a-table> </a-table>
</my-card> </my-card>
<a-drawer
placement="right"
:visible="visible"
:drawerStyle="drawerStyle"
:bodyStyle="bodyStyle"
destroyOnClose
:width="600"
@close="hidden"
:maskClosable="false"
>
<slot name="drawer" :hidden="hidden" />
</a-drawer>
</div> </div>
</template> </template>
...@@ -43,6 +65,10 @@ const initQuery = { ...@@ -43,6 +65,10 @@ const initQuery = {
export default { export default {
props: { props: {
url: String, url: String,
addBtn: [Object, Boolean],
buttons: Array,
noPage: Boolean,
formatData: Function,
}, },
data() { data() {
...@@ -54,6 +80,17 @@ export default { ...@@ -54,6 +80,17 @@ export default {
queryForm: {}, queryForm: {},
loading: false, loading: false,
total: 0, total: 0,
visible: false,
title: '新增',
drawerStyle: {
display: 'flex',
flexDirection: 'column',
overflowY: 'hidden',
},
bodyStyle: {
flex: 1,
overflow: 'hidden',
},
}; };
}, },
...@@ -63,12 +100,14 @@ export default { ...@@ -63,12 +100,14 @@ export default {
computed: { computed: {
pagination() { pagination() {
return { return this.noPage
current: this.initQuery.pageNum, ? false
pageSize: this.initQuery.pageSize, : {
total: this.total, current: this.initQuery.pageNum,
showQuickJumper: true, pageSize: this.initQuery.pageSize,
}; total: this.total,
showQuickJumper: true,
};
}, },
}, },
...@@ -76,7 +115,7 @@ export default { ...@@ -76,7 +115,7 @@ export default {
async getData() { async getData() {
this.loading = true; this.loading = true;
try { try {
await this.getDataWithPage(); this.noPage ? await this.getDataNoPage() : await this.getDataWithPage();
} catch (error) { } catch (error) {
// todo // todo
} }
...@@ -90,10 +129,34 @@ export default { ...@@ -90,10 +129,34 @@ export default {
else this.data = res.records; else this.data = res.records;
}, },
async getDataNoPage() {
const res = await request(this.url, METHOD.GET, this.queryForm);
if (this.formatData) this.data = this.formatData(res);
else this.data = res;
},
pageChange(page) { pageChange(page) {
this.initQuery.pageNum = page.current; this.initQuery.pageNum = page.current;
this.getData(); this.getData();
}, },
hidden() {
this.visible = false;
},
show({ title } = {}) {
this.visible = true;
if (title) this.title = title;
},
reset() {
this.queryForm = {};
this.initQuery = { ...initQuery };
this.getData();
},
addBtnClick() {
const { click } = typeof this.addBtn === 'object' ? this.addBtn : {};
click && click();
this.visible = true;
},
}, },
}; };
</script> </script>
<template>
<div>
<Drawer />
<Table>
<template #search="query">
<slot name="search" :query="query" />
</template>
<slot name="table" />
</Table>
</div>
</template>
<script>
import Table from './table.vue';
import Drawer from './drawer.vue';
export default {
components: { Table, Drawer },
};
</script>
<template>
<div class="tw-flex tw-flex-col tw-h-full">
<div class="tw-overflow-y-hidden tw-flex-1">
<div class="tw-overflow-y-auto tw-h-full">
<slot />
</div>
</div>
<template>
<a-divider />
<a-space class="tw-justify-end">
<a-button @click="cancel">取消</a-button>
<slot name="footer">
<a-button type="primary" @click="ok" :loading="loading">确认</a-button>
</slot>
</a-space>
</template>
</div>
</template>
<script>
import { EMPTY_FUN } from '@/utils';
export default {
props: {
onOk: {
type: Function,
default: EMPTY_FUN,
},
onCancel: Function,
hidden: {
type: Function,
default: EMPTY_FUN,
},
},
data: () => ({
loading: false,
}),
methods: {
cancel() {
if (this.onCancel) this.onCancel();
this.hidden();
},
async ok() {
this.loading = true;
await this.onOk();
this.loading = false;
this.hidden();
},
},
};
</script>
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
ref="table" ref="table"
> >
<template #drawer> <template #drawer>
<AddCom v-if="addCom" /> <AddCom v-if="addCom" :row="currentClickRow" ref="addCom" />
<Form ref="addForm" v-else /> <Form ref="addForm" v-else />
</template> </template>
...@@ -33,24 +33,31 @@ import AddCom from './add_com.vue'; ...@@ -33,24 +33,31 @@ import AddCom from './add_com.vue';
export default { export default {
data: vm => ({ data: vm => ({
addCom: false, addCom: false,
currentClickRow: null,
addBtn: { addBtn: {
text: '新建', text: '新建',
onOk() { onOk() {
return vm.$refs['addForm']?.submit(); console.log(vm.addCom);
return vm.addCom ? vm.$refs['addCom']?.submit() : vm.$refs['addForm']?.submit();
}, },
onCancel() { onCancel() {
vm.addCom = false; vm.addCom = false;
vm.currentClickRow = null;
}, },
}, },
sortOrder: 'ascend', sortOrder: 'ascend',
buttons: [ buttons: [
{ {
label: '新增组件', label: '新增组件',
click() { option: {
type: 'danger',
},
click(row) {
vm.show(); vm.show();
vm.addCom = true; vm.addCom = true;
vm.currentClickRow = row;
}, },
isHidden: row => row.menuType === 'MENU', isHidden: row => row.menuType !== 'MENU',
}, },
{ label: '编辑', click: vm.edit }, { label: '编辑', click: vm.edit },
{ type: 'confirm', url: row => `/api/v1/menus/${row.menuId}`, after: vm.refreshTable }, { type: 'confirm', url: row => `/api/v1/menus/${row.menuId}`, after: vm.refreshTable },
...@@ -74,7 +81,7 @@ export default { ...@@ -74,7 +81,7 @@ export default {
}); });
}, },
show() { show() {
this.$refs['table'].show(); this.$refs['table'].show({ title: '菜单组件' });
}, },
}, },
}; };
......
<template> <template>
<h1>addCom</h1> <div>
<a-button type="primary" class="tw-mb-2" @click="add">新增</a-button>
<a-table :dataSource="components" :rowKey="getRowKey">
<a-table-column title="组件编码">
<template #default="row">
<span v-if="row.componentId">{{ row.componentCode }}</span>
<a-input v-else v-model="row.componentCode" />
</template>
</a-table-column>
<a-table-column title="组件名称">
<template #default="row">
<span v-if="row.componentId">{{ row.componentName }}</span>
<a-input v-else v-model="row.componentName" />
</template>
</a-table-column>
<a-table-column title="操作">
<template #default="row">
<a @click="() => del(row)">删除</a>
</template>
</a-table-column>
</a-table>
</div>
</template> </template>
<script>
import { getMenuComponentApi, addMenuComponentApi } from '@/api';
export default {
props: ['row'],
data: () => ({
components: [],
}),
mounted() {
this.getData();
},
methods: {
async getData() {
const { menuId } = this.row;
this.components = await getMenuComponentApi(menuId);
},
add() {
this.components.push({
componentCode: '',
componentName: '',
__key__: this.components.length,
});
},
del(row) {
this.components = this.components.filter(r => r !== row);
},
getRowKey(row) {
return row.__key__ ? row.__key__ : row.componentId;
},
submit() {
const { menuId } = this.row;
return addMenuComponentApi(
menuId,
this.components.map(i => {
delete i.__key__;
return i;
}),
);
},
},
};
</script>
<template>
<Wraper :onCancel="hidden" :hidden="hidden">
<h1>这是内容</h1>
</Wraper>
</template>
<script>
import Wraper from '@/components/table/wraper.vue';
export default {
components: { Wraper },
props: ['hidden'],
};
</script>
<template> <template>
<h1>TODO</h1> <Table url="/api/v1/logger/login" rowKey="logId" addBtn :actions="actions" ref="table">
<template #search="{query}">
<my-form-item label="开始时间">
<a-date-picker
class="tw-w-full"
show-time
v-model="query.startTime"
valueFormat="YYYY-MM-DD HH:mm:ss"
/>
</my-form-item>
</template>
<template #drawer="{hidden}">
<Form :hidden="hidden" />
</template>
<a-table-column title="用户Id" data-index="userId" />
<a-table-column title="登录用户" data-index="userName" />
<a-table-column title="登录IP" data-index="loginIp" />
<a-table-column title="事件类型" data-index="loginTypeName" />
<a-table-column title="事件状态" data-index="isSuccessName" />
<a-table-column title="登录时间" data-index="loginTime" />
<a-table-column title="说明" data-index="logResultContent" />
</Table>
</template> </template>
<script>
import Table from '@/components/table/table.vue';
import Form from './form.vue';
export default {
components: { Table, Form },
data: () => ({
addBtn: {
text: '新增',
},
actions: [],
}),
};
</script>
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