Compare commits
2 Commits
d8783898f4
...
e0ca17a4b7
Author | SHA1 | Date |
---|---|---|
expressgy | e0ca17a4b7 | 3 months ago |
expressgy | ead6a92bd9 | 3 months ago |
@ -0,0 +1,73 @@ |
||||
// | ------------------------------------------------------------
|
||||
// | @版本: version 0.1
|
||||
// | @创建人: 【Nie-x7129】
|
||||
// | @E-mail: x71291@outlook.com
|
||||
// | @所在项目: hoto-auth-vue3
|
||||
// | @文件描述: index.js -
|
||||
// | @创建时间: 2024-07-11 14:26
|
||||
// | @更新时间: 2024-07-11 14:26
|
||||
// | @修改记录:
|
||||
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
|
||||
// | =
|
||||
// | ------------------------------------------------------------
|
||||
|
||||
import HTTP from '@/api/http.js'; |
||||
import { PageData } from '@utils/DefaultData.js'; |
||||
|
||||
export const CoreMenu = { |
||||
/** |
||||
* Name: createMenu |
||||
* Desc: 新增菜单 |
||||
* Time: 2024-07-11 14:33:50 - |
||||
* */ |
||||
createMenu: async (data) => { |
||||
return HTTP({ |
||||
method: 'post', |
||||
url: '/coremenu', |
||||
data, |
||||
}); |
||||
}, |
||||
|
||||
/** |
||||
* Name: getMenu |
||||
* Desc: 获取菜单的分页或列表 |
||||
* Time: 2024-07-11 14:33:54 - |
||||
* */ |
||||
getMenu: async ( |
||||
params = { |
||||
...PageData, |
||||
serviceInfo: undefined, |
||||
}, |
||||
) => { |
||||
return HTTP({ |
||||
method: 'get', |
||||
url: '/coremenu', |
||||
params, |
||||
}); |
||||
}, |
||||
|
||||
/** |
||||
* Name: removeMenu |
||||
* Desc: 删除菜单 |
||||
* Time: 2024-07-11 14:33:59 - |
||||
* */ |
||||
removeMenu: async (menuId) => { |
||||
return HTTP({ |
||||
method: 'delete', |
||||
url: `/coremenu/${menuId}`, |
||||
}); |
||||
}, |
||||
|
||||
/** |
||||
* Name: updateMenu |
||||
* Desc: 编辑菜单 |
||||
* Time: 2024-07-11 14:34:03 - |
||||
* */ |
||||
updateMenu: async (menuId, data) => { |
||||
return HTTP({ |
||||
method: 'patch', |
||||
url: `/coremenu/${menuId}`, |
||||
data, |
||||
}); |
||||
}, |
||||
}; |
@ -0,0 +1,28 @@ |
||||
<script setup name="TablePagination"> |
||||
defineOptions({ |
||||
name: 'TablePagination', |
||||
}); |
||||
const props = defineProps({ |
||||
data: { |
||||
type: Object, |
||||
required: true, |
||||
}, |
||||
}); |
||||
</script> |
||||
|
||||
<template> |
||||
<APagination |
||||
v-model:current="props.data.pageInfo.pageNumber" |
||||
:total="props.data.total" |
||||
:pageSize="props.data.pageInfo.pageSize" |
||||
:pageSizeOptions="[10, 20, 50, 100, 200]" |
||||
:showSizeChanger="true" |
||||
:showQuickJumper="true" |
||||
:showTotal="(total) => `共 ${total} 条`" |
||||
@change="props.data.handlePageChange" |
||||
/> |
||||
</template> |
||||
|
||||
<style scoped> |
||||
|
||||
</style> |
@ -0,0 +1,212 @@ |
||||
// | ------------------------------------------------------------
|
||||
// | @版本: version 0.1
|
||||
// | @创建人: 【Nie-x7129】
|
||||
// | @E-mail: x71291@outlook.com
|
||||
// | @所在项目: hoto-auth-vue3
|
||||
// | @文件描述: dataModal.js -
|
||||
// | @创建时间: 2024-07-09 14:47
|
||||
// | @更新时间: 2024-07-09 14:47
|
||||
// | @修改记录:
|
||||
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
|
||||
// | =
|
||||
// | ------------------------------------------------------------
|
||||
|
||||
import { IconPool } from '@/components/AntDesignVue/Icon/index.js'; |
||||
import { h } from 'vue'; |
||||
|
||||
export class MenuFormType { |
||||
constructor() { |
||||
return new Object({ |
||||
// 上级菜单
|
||||
pid: undefined, |
||||
// 接口路径
|
||||
apiPath: '', |
||||
// 页面路由
|
||||
webPath: '', |
||||
// 页面组件路径
|
||||
webComponentPath: '', |
||||
// 菜单名称
|
||||
menuName: '', |
||||
// 菜单描述
|
||||
menuDesc: '', |
||||
// 菜单类型
|
||||
menuType: undefined, |
||||
// 菜单图标
|
||||
menuIcon: undefined, |
||||
// 是否链接到外部
|
||||
isFrame: 0, |
||||
// 是否可见
|
||||
isVisible: 1, |
||||
// 是否激活
|
||||
isActivate: 1, |
||||
// 排序
|
||||
orderNum: 0, |
||||
// 所属服务
|
||||
serviceOf: undefined, |
||||
}); |
||||
} |
||||
} |
||||
|
||||
// 查询数据
|
||||
export class MenuSearchType { |
||||
constructor() { |
||||
return new Object({ |
||||
// 每页数量
|
||||
pageSize: 10, |
||||
// 页码
|
||||
pageNumber: 1, |
||||
// 是否是列表
|
||||
isList: false, |
||||
// 排序方式
|
||||
isAsc: false, |
||||
// 菜单信息
|
||||
menuInfo: undefined, |
||||
// 菜单类型
|
||||
menuType: undefined, |
||||
// 是否链接到外部
|
||||
isFrame: undefined, |
||||
// 是否可见
|
||||
isVisible: undefined, |
||||
// 是否激活
|
||||
isActivate: undefined, |
||||
// 是否是原始数据
|
||||
root: undefined, |
||||
// 所属服务
|
||||
serviceKey: undefined, |
||||
// 状态
|
||||
status: undefined, |
||||
// 根据pid查
|
||||
hierarchy: [], |
||||
}); |
||||
} |
||||
} |
||||
|
||||
// 表单规则
|
||||
export class MenuFormRulesType { |
||||
constructor() { |
||||
return new Object({}); |
||||
} |
||||
} |
||||
|
||||
// Env表格列数据
|
||||
export class MenuTableColumnType { |
||||
constructor() { |
||||
return new Object({ |
||||
index: { |
||||
title: '序号', |
||||
key: 'index', |
||||
width: 70, // 你可以根据需要设置列宽
|
||||
customRender: ({ text, record, index, column }) => `${index + 1}`, // 使用索引 + 1 来显示序号
|
||||
}, |
||||
menuName: { |
||||
title: '菜单名称', |
||||
dataIndex: 'menuName', |
||||
key: 'menuName', |
||||
}, |
||||
menuIcon: { |
||||
title: '图标', |
||||
dataIndex: 'menuIcon', |
||||
customRender: ({ text, record, index, column }) => (text && IconPool[text] ? h(IconPool[text], { style: { fontSize: '20px' } }) : h('div', text)), |
||||
key: 'menuIcon', |
||||
}, |
||||
menuType: { |
||||
title: '类型', |
||||
dataIndex: 'menuType', |
||||
key: 'menuType', |
||||
customRender: ({ text, record, index, column }) => record.menuTypeName, |
||||
}, |
||||
apiPath: { |
||||
title: '接口路径', |
||||
dataIndex: 'apiPath', |
||||
key: 'apiPath', |
||||
}, |
||||
// 页面路由
|
||||
webPath: { |
||||
title: '页面路由', |
||||
dataIndex: 'webPath', |
||||
key: 'webPath', |
||||
}, |
||||
// 页面组件路径
|
||||
webComponentPath: { |
||||
title: '组件路径', |
||||
dataIndex: 'webComponentPath', |
||||
key: 'webComponentPath', |
||||
}, |
||||
isFrame: { |
||||
title: '外链', |
||||
dataIndex: 'isFrame', |
||||
key: 'isFrame', |
||||
customRender: ({ text, record, index, column }) => (text == '1' ? '是' : '否'), |
||||
}, |
||||
isVisible: { |
||||
title: '可见', |
||||
dataIndex: 'isVisible', |
||||
key: 'isVisible', |
||||
customRender: ({ text, record, index, column }) => (text == '1' ? '是' : '否'), |
||||
}, |
||||
isActivate: { |
||||
title: '激活', |
||||
dataIndex: 'isActivate', |
||||
key: 'isActivate', |
||||
customRender: ({ text, record, index, column }) => (text == '1' ? '是' : '否'), |
||||
}, |
||||
serviceKey: { |
||||
title: '所属服务', |
||||
dataIndex: 'serviceKey', |
||||
key: 'serviceKey', |
||||
customRender: ({ text, record, index, column }) => record.serviceName, |
||||
}, |
||||
haveChildren: { |
||||
title: '子项', |
||||
dataIndex: 'haveChildren', |
||||
key: 'haveChildren', |
||||
width: '50px', |
||||
}, |
||||
createtime: { |
||||
title: '创建时间', |
||||
dataIndex: 'createtime', |
||||
key: 'createtime', |
||||
width: '140px', |
||||
sorter: true, |
||||
}, |
||||
createName: { |
||||
title: '创建人', |
||||
dataIndex: 'createName', |
||||
key: 'createName', |
||||
}, |
||||
updatetime: { |
||||
title: '更新时间', |
||||
dataIndex: 'updatetime', |
||||
key: 'updatetime', |
||||
maxWidth: '140px', |
||||
minWidth: '140px', |
||||
}, |
||||
updateName: { |
||||
title: '更新人', |
||||
dataIndex: 'updateName', |
||||
key: 'updateName', |
||||
}, |
||||
action: { |
||||
title: '操作', |
||||
dataIndex: 'action', |
||||
key: 'action', |
||||
width: 100, |
||||
align: 'center', |
||||
}, |
||||
}); |
||||
} |
||||
} |
||||
|
||||
|
||||
// Env可选表格列
|
||||
export class MenuTableColumnChooseType { |
||||
constructor() { |
||||
const excludeColumn = ['updateName', 'updatetime', 'createName']; |
||||
const tableColumn = new MenuTableColumnType(); |
||||
return Object.keys(tableColumn).map((i) => ({ |
||||
title: tableColumn[i].title, |
||||
key: tableColumn[i].key, |
||||
status: excludeColumn.includes(i) ? false : true, |
||||
})); |
||||
} |
||||
} |
@ -0,0 +1,244 @@ |
||||
<script setup name="MenuPage"> |
||||
import { onMounted, reactive, watch } from 'vue'; |
||||
import { MenuFormType, MenuSearchType, MenuTableColumnChooseType } from './DataModal.js'; |
||||
import MenuForm from './MenuForm.vue'; |
||||
import MenuTable from './MenuTable.vue'; |
||||
import { useMessage } from 'naive-ui'; |
||||
import { useBaseDataStore } from '@/stores/baseData.js'; |
||||
import TablePagination from '@/components/AntDesignVue/CustomAntDesignVue/TablePagination/index.vue'; |
||||
import { CoreMenu } from '@/api/index.js'; |
||||
import MenuTree from '@/views/Auth/Menu/MenuTree.vue'; |
||||
const baseDataStore = useBaseDataStore(); |
||||
const Message = useMessage(); |
||||
defineOptions({ |
||||
name: 'MenuPage', |
||||
}); |
||||
// 待查询次数 |
||||
let searchCount = 0; |
||||
|
||||
|
||||
// ! 表单数据 |
||||
const formData = reactive({ |
||||
// 弹窗名称 |
||||
modelName: '创建菜单', |
||||
// 弹窗状态 |
||||
status: false, |
||||
// 编辑状态 |
||||
isUpdate: false, |
||||
// 菜单ID |
||||
menuId: undefined, |
||||
formData: new MenuFormType(), |
||||
// 确认 |
||||
handleAck: handleCreateAck, |
||||
// 取消 |
||||
handleCancel: () => clearFormData() |
||||
}); |
||||
// 表格数据 |
||||
const tableData = reactive({ |
||||
dataSource: [], |
||||
pageInfo: new MenuSearchType(), |
||||
searchBase:{ |
||||
menuType: [] |
||||
}, |
||||
total: 0, |
||||
methods: { |
||||
handleTableChange, |
||||
handleRemoveAck, |
||||
handleUpdate, |
||||
}, |
||||
handlePageChange, |
||||
columnList: new MenuTableColumnChooseType(), |
||||
}); |
||||
// @1确认添加 |
||||
async function handleCreateAck(data) { |
||||
await CoreMenu.createMenu(data); |
||||
Message.success('添加菜单成功!'); |
||||
clearSearchData(); |
||||
clearFormData(); |
||||
getPage(); |
||||
baseDataStore.getMenuList(); |
||||
} |
||||
// @2确认删除 |
||||
async function handleRemoveAck(data) { |
||||
await CoreMenu.removeMenu(data.menuId); |
||||
Message.success('删除菜单成功!'); |
||||
if (tableData.dataSource.length == 1 && tableData.pageInfo.pageNumber > 1) { |
||||
tableData.pageInfo.pageNumber--; |
||||
} |
||||
getPage(); |
||||
baseDataStore.getMenuList(); |
||||
} |
||||
// @3更新数据 todo |
||||
async function handleUpdate(data) { |
||||
formData.modelName = '更新变量'; |
||||
formData.status = true; |
||||
formData.isUpdate = true; |
||||
formData.menuId = data.menuId; |
||||
formData.handleAck = handleUpdateAck; |
||||
Object.keys(formData.formData).forEach(key => { |
||||
formData.formData[key] = data[key]; |
||||
}); |
||||
} |
||||
// @4确认更新数据 todo |
||||
async function handleUpdateAck(data) { |
||||
if(!data.pid){ |
||||
data.pid = 0; |
||||
} |
||||
await CoreMenu.updateMenu(formData.menuId, data); |
||||
Message.success('更新变量成功!'); |
||||
clearFormData(); |
||||
getPage(); |
||||
baseDataStore.getMenuList(); |
||||
} |
||||
// @5监听筛选 todo |
||||
watch(tableData.pageInfo, () => { |
||||
getPage(); |
||||
}); |
||||
// @6获取表格数据 |
||||
async function getPage() { |
||||
if (searchCount === 0) { |
||||
searchCount++; |
||||
setTimeout(() => { |
||||
searchCount = 0; |
||||
}, 500); |
||||
} else { |
||||
searchCount++; |
||||
return; |
||||
} |
||||
const pageInfo = {...tableData.pageInfo}; |
||||
pageInfo.hierarchy = pageInfo.hierarchy.length > 0 ? pageInfo.hierarchy[0] : undefined; |
||||
const resd = await CoreMenu.getMenu(pageInfo); |
||||
tableData.dataSource = resd.rowData; |
||||
tableData.total = Number(resd.total); |
||||
} |
||||
// @7页码变动 |
||||
function handlePageChange(page, pageSize) { |
||||
tableData.pageInfo.pageSize = pageSize; |
||||
tableData.pageInfo.pageNumber = page; |
||||
} |
||||
// @7表格筛选变动 |
||||
function handleTableChange(page, filter, sorter) { |
||||
if (sorter.order == 'ascend') { |
||||
tableData.pageInfo.isAsc = true; |
||||
} else if (sorter.order == 'descend') { |
||||
tableData.pageInfo.isAsc = false; |
||||
} else { |
||||
tableData.pageInfo.isAsc = undefined; |
||||
} |
||||
} |
||||
// @8清除筛选条件 |
||||
function clearSearchData() { |
||||
const newPageInfo = new MenuSearchType(); |
||||
Object.keys(tableData.pageInfo).forEach((key) => { |
||||
tableData.pageInfo[key] = newPageInfo[key]; |
||||
}); |
||||
} |
||||
// @9清除编辑数据 |
||||
function clearFormData() { |
||||
formData.modelName = '创建变量'; |
||||
formData.isUpdate = false; |
||||
formData.status = false; |
||||
formData.menuId = undefined; |
||||
formData.handleAck = handleCreateAck; |
||||
const newFormData = new MenuFormType(); |
||||
Object.keys(formData.formData).forEach((key) => { |
||||
formData.formData[key] = newFormData[key]; |
||||
}); |
||||
} |
||||
|
||||
onMounted(() => { |
||||
window.pino.deb('@1 MenuPage Mounted!'); |
||||
getPage(); |
||||
// ! 检测获取菜单类型列表 |
||||
if (baseDataStore.state.menuTypeList?.length == 0) { |
||||
baseDataStore.getMenuTypeList(); |
||||
} |
||||
|
||||
// ! 检测获取服务列表 |
||||
if (baseDataStore.state.serviceList?.length == 0) { |
||||
baseDataStore.getServiceList(); |
||||
} |
||||
}); |
||||
</script> |
||||
|
||||
<template> |
||||
<WorkContainer> |
||||
<template #header> |
||||
<ASpace> |
||||
<CreateAntdButton name="菜单" @click="formData.status = true" /> |
||||
<TableColumChoose v-model:columnList="tableData.columnList" /> |
||||
<AInputSearch v-model:value="tableData.pageInfo.menuInfo" placeholder="菜单名称/路径" style="width: 200px" @search="getPage" /> |
||||
<ASelect |
||||
style="width: 150px" |
||||
placeholder="请选择所属服务" |
||||
allowClear |
||||
v-model:value="tableData.pageInfo.serviceKey" |
||||
:options="baseDataStore.state.serviceList" |
||||
:field-names="{ label: 'serviceName', value: 'serviceKey', options: 'children' }" |
||||
/> |
||||
<ASelect |
||||
style="width: 150px" |
||||
placeholder="请选择菜单类型" |
||||
allowClear |
||||
v-model:value="tableData.pageInfo.menuType" |
||||
:options="baseDataStore.state.menuTypeTree" |
||||
/> |
||||
<ASelect style="width: 150px" placeholder="请选择可见状态" allowClear v-model:value="tableData.pageInfo.isVisible"> |
||||
<ASelectOption :value="true">可见</ASelectOption> |
||||
<ASelectOption :value="false">不可见</ASelectOption> |
||||
</ASelect> |
||||
<ASelect style="width: 150px" placeholder="请选择激活状态" allowClear v-model:value="tableData.pageInfo.isActivate"> |
||||
<ASelectOption :value="true">激活</ASelectOption> |
||||
<ASelectOption :value="false">未激活</ASelectOption> |
||||
</ASelect> |
||||
<ASelect style="width: 170px" placeholder="请选择是否是外部链接" allowClear v-model:value="tableData.pageInfo.isFrame"> |
||||
<ASelectOption :value="true">外部链接</ASelectOption> |
||||
<ASelectOption :value="false">非外部链接</ASelectOption> |
||||
</ASelect> |
||||
</ASpace> |
||||
</template> |
||||
<template #main> |
||||
<div class="menuBody"> |
||||
<div class="tree"> |
||||
<MenuTree v-model:selectedKeys="tableData.pageInfo.hierarchy"/> |
||||
</div> |
||||
<div class="table"> |
||||
<MenuTable :tableData="tableData"/> |
||||
</div> |
||||
</div> |
||||
|
||||
</template> |
||||
<template #footer> |
||||
<TablePagination :data="tableData"/> |
||||
</template> |
||||
<template #modal> |
||||
<AModal v-model:open="formData.status" :title="formData.modelName" :centered="true" :maskClosable="false" :destroyOnClose="true" :onCancel="clearFormData"> |
||||
<MenuForm :data="formData"/> |
||||
<template #footer></template> |
||||
</AModal> |
||||
</template> |
||||
</WorkContainer> |
||||
</template> |
||||
|
||||
<style scoped> |
||||
.menuBody { |
||||
position: relative; |
||||
height: 100%; |
||||
width: 100%; |
||||
display: flex; |
||||
& > div.tree { |
||||
position: relative; |
||||
flex-shrink: 0; |
||||
max-height: 100%; |
||||
width: 300px; |
||||
border-right: 1px solid #cdcdcd; |
||||
padding-right: 5px; |
||||
} |
||||
& > div.table { |
||||
position: relative; |
||||
flex: 1; |
||||
max-height: 100%; |
||||
padding-left: 5px; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,34 @@ |
||||
<script setup name="MenuTree"> |
||||
defineOptions({ |
||||
name: 'MenuTree', |
||||
}); |
||||
import { useBaseDataStore } from '@/stores/baseData.js'; |
||||
import { onMounted, reactive } from 'vue'; |
||||
const baseDataStore = useBaseDataStore(); |
||||
|
||||
|
||||
// ! 树字段重置 |
||||
const fieldNames = reactive({ |
||||
children:'children', title:'label', key:'id' |
||||
}); |
||||
|
||||
// 当页面加载时 |
||||
onMounted(() => { |
||||
window.pino.info('@4 MenuTree Mounted'); |
||||
// ! 检测获取字典列表 |
||||
if (baseDataStore.state.menuList?.length == 0) { |
||||
baseDataStore.getMenuList(); |
||||
} |
||||
}); |
||||
</script> |
||||
|
||||
<template> |
||||
<ATree |
||||
:treeData="baseDataStore.state.menuTree" |
||||
:show-line="true" |
||||
show-icon |
||||
:fieldNames="fieldNames" |
||||
/> |
||||
</template> |
||||
|
||||
<style scoped></style> |
@ -1,16 +0,0 @@ |
||||
// | ------------------------------------------------------------
|
||||
// | @版本: version 0.1
|
||||
// | @创建人: 【Nie-x7129】
|
||||
// | @E-mail: x71291@outlook.com
|
||||
// | @所在项目: hoto-auth-vue3
|
||||
// | @文件描述: dataModal.js -
|
||||
// | @创建时间: 2024-07-09 14:47
|
||||
// | @更新时间: 2024-07-09 14:47
|
||||
// | @修改记录:
|
||||
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
|
||||
// | =
|
||||
// | ------------------------------------------------------------
|
||||
|
||||
export const formType = new Object({ |
||||
|
||||
}) |
@ -1,64 +0,0 @@ |
||||
<script setup name="MenuPage"> |
||||
import { onMounted, reactive } from 'vue'; |
||||
|
||||
defineOptions({ |
||||
name: 'MenuPage', |
||||
}); |
||||
|
||||
onMounted(() => { |
||||
window.pino.info('MenuPage Mounted!'); |
||||
}); |
||||
// ! 表单数据 |
||||
const formData = reactive({ |
||||
// 弹窗名称 |
||||
modelName: '创建菜单', |
||||
// 弹窗状态 |
||||
status: false, |
||||
// 编辑状态 |
||||
isUpdate: false, |
||||
// 字典ID |
||||
dictId: undefined, |
||||
}); |
||||
// ! 清理输入项表单 |
||||
function clearFormData() {} |
||||
</script> |
||||
|
||||
<template> |
||||
<WorkContainer> |
||||
<template #header> |
||||
<ASpace> |
||||
<CreateAntdButton name="菜单" @click="formData.status = true" /> |
||||
</ASpace> |
||||
</template> |
||||
<template #main></template> |
||||
<template #footer></template> |
||||
<template #modal> |
||||
<AModal v-model:open="formData.status" :title="formData.modelName" :centered="true" :maskClosable="false" :destroyOnClose="true" :onCancel="clearFormData"> |
||||
<template #footer></template> |
||||
</AModal> |
||||
</template> |
||||
</WorkContainer> |
||||
</template> |
||||
|
||||
<style scoped> |
||||
.menuBody { |
||||
position: relative; |
||||
height: 100%; |
||||
width: 100%; |
||||
display: flex; |
||||
& > div.tree { |
||||
position: relative; |
||||
flex-shrink: 0; |
||||
max-height: 100%; |
||||
width: 300px; |
||||
border-right: 1px solid #cdcdcd; |
||||
padding-right: 5px; |
||||
} |
||||
& > div.table { |
||||
position: relative; |
||||
flex: 1; |
||||
max-height: 100%; |
||||
padding-left: 5px; |
||||
} |
||||
} |
||||
</style> |
Loading…
Reference in new issue