feat: 综合实例、权限管理重构
This commit is contained in:
parent
07adefb89b
commit
a4bd2068a5
|
@ -51,6 +51,7 @@ declare module 'vue' {
|
||||||
ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
|
ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
|
||||||
ElTimeSelect: typeof import('element-plus/es')['ElTimeSelect']
|
ElTimeSelect: typeof import('element-plus/es')['ElTimeSelect']
|
||||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||||
|
ElTree: typeof import('element-plus/es')['ElTree']
|
||||||
Loading: typeof import('element-plus/es')['ElLoadingDirective']
|
Loading: typeof import('element-plus/es')['ElLoadingDirective']
|
||||||
ParentView: typeof import('./src/components/ParentView/index.vue')['default']
|
ParentView: typeof import('./src/components/ParentView/index.vue')['default']
|
||||||
Preview: typeof import('./src/components/Preview/index.vue')['default']
|
Preview: typeof import('./src/components/Preview/index.vue')['default']
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
"highlight.js": "^11.3.1",
|
"highlight.js": "^11.3.1",
|
||||||
"intro.js": "^4.2.2",
|
"intro.js": "^4.2.2",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
"mitt": "^3.0.0",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
|
|
|
@ -157,7 +157,7 @@ export function useWork(option?: InitOption) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除多选
|
// 删除多选
|
||||||
function dels(item: IObj, single: boolean, callback: Fn) {
|
function dels(item: IObj, single?: boolean, callback?: Fn) {
|
||||||
delData(
|
delData(
|
||||||
async () => {
|
async () => {
|
||||||
let ids: Nullable<IObj[]> = null
|
let ids: Nullable<IObj[]> = null
|
||||||
|
@ -190,7 +190,7 @@ export function useWork(option?: InitOption) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打开弹窗
|
// 打开弹窗
|
||||||
function open(row: IObj, component: string, options: DilogOption) {
|
function open(row: Nullable<IObj>, component: string, options?: DilogOption) {
|
||||||
comName.value = component
|
comName.value = component
|
||||||
dialogTitle.value =
|
dialogTitle.value =
|
||||||
(options && options.title) || (!row ? '新增' : component === 'Detail' ? '详情' : '编辑')
|
(options && options.title) || (!row ? '新增' : component === 'Detail' ? '详情' : '编辑')
|
||||||
|
|
|
@ -49,19 +49,14 @@ export const checkedNodes = [
|
||||||
title: '弹窗',
|
title: '弹窗',
|
||||||
name: 'DialogDemo'
|
name: 'DialogDemo'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/components-demo/more',
|
|
||||||
title: '显示更多',
|
|
||||||
name: 'MoreDemo'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/components-demo/detail',
|
path: '/components-demo/detail',
|
||||||
title: '详情组件',
|
title: '详情',
|
||||||
name: 'DetailDemo'
|
name: 'DetailDemo'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/components-demo/qrcode',
|
path: '/components-demo/qrcode',
|
||||||
title: '二维码组件',
|
title: '二维码',
|
||||||
name: 'QrcodeDemo'
|
name: 'QrcodeDemo'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -78,31 +73,6 @@ export const checkedNodes = [
|
||||||
path: '/components-demo/watermark',
|
path: '/components-demo/watermark',
|
||||||
name: 'WatermarkDemo',
|
name: 'WatermarkDemo',
|
||||||
title: '水印'
|
title: '水印'
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/components-demo/timer',
|
|
||||||
name: 'TimerDemo',
|
|
||||||
title: '计时器'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/components-demo/marquee',
|
|
||||||
name: 'MarqueeDemo',
|
|
||||||
title: '无缝滚动'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/components-demo/water-fall',
|
|
||||||
name: 'WaterFallDemo',
|
|
||||||
title: '瀑布流'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/components-demo/tree-select',
|
|
||||||
name: 'TreeSelectDemo',
|
|
||||||
title: '瀑布流'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/components-demo/ellipsis',
|
|
||||||
name: 'Ellipsis',
|
|
||||||
title: '省略号'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -151,19 +121,14 @@ export const checkedNodes = [
|
||||||
title: '弹窗',
|
title: '弹窗',
|
||||||
name: 'DialogDemo'
|
name: 'DialogDemo'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/components-demo/more',
|
|
||||||
title: '显示更多',
|
|
||||||
name: 'MoreDemo'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/components-demo/detail',
|
path: '/components-demo/detail',
|
||||||
title: '详情组件',
|
title: '详情',
|
||||||
name: 'DetailDemo'
|
name: 'DetailDemo'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/components-demo/qrcode',
|
path: '/components-demo/qrcode',
|
||||||
title: '二维码组件',
|
title: '二维码',
|
||||||
name: 'QrcodeDemo'
|
name: 'QrcodeDemo'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -181,31 +146,6 @@ export const checkedNodes = [
|
||||||
name: 'WatermarkDemo',
|
name: 'WatermarkDemo',
|
||||||
title: '水印'
|
title: '水印'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/components-demo/timer',
|
|
||||||
name: 'TimerDemo',
|
|
||||||
title: '计时器'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/components-demo/marquee',
|
|
||||||
name: 'MarqueeDemo',
|
|
||||||
title: '无缝滚动'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/components-demo/water-fall',
|
|
||||||
name: 'WaterFallDemo',
|
|
||||||
title: '瀑布流'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/components-demo/tree-select',
|
|
||||||
name: 'TreeSelectDemo',
|
|
||||||
title: '瀑布流'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/components-demo/ellipsis',
|
|
||||||
name: 'Ellipsis',
|
|
||||||
title: '瀑布流'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/table-demo',
|
path: '/table-demo',
|
||||||
title: '表格',
|
title: '表格',
|
||||||
|
@ -430,33 +370,6 @@ export const checkedNodes = [
|
||||||
title: 'Clipboard',
|
title: 'Clipboard',
|
||||||
name: 'ClipboardDemo'
|
name: 'ClipboardDemo'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/hooks-demo',
|
|
||||||
title: 'Hooks',
|
|
||||||
name: 'HooksDemo',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: '/hooks-demo/watermark',
|
|
||||||
title: 'UseWaterMark',
|
|
||||||
name: 'UseWatermarkDemo'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/hooks-demo/useScrollTo',
|
|
||||||
title: 'UseScrollTo',
|
|
||||||
name: 'UseScrollToDemo'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/hooks-demo/watermark',
|
|
||||||
title: 'UseWaterMark',
|
|
||||||
name: 'UseWatermarkDemo'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/hooks-demo/useScrollTo',
|
|
||||||
title: 'UseScrollTo',
|
|
||||||
name: 'UseScrollToDemo'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/icon/index',
|
path: '/icon/index',
|
||||||
title: '图标',
|
title: '图标',
|
||||||
|
@ -563,6 +476,21 @@ export const checkedNodes = [
|
||||||
path: '/example-demo/example-page',
|
path: '/example-demo/example-page',
|
||||||
title: '列表综合实例-页面',
|
title: '列表综合实例-页面',
|
||||||
name: 'ExamplePage'
|
name: 'ExamplePage'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/example-demo/example-add',
|
||||||
|
title: '列表综合实例-新增',
|
||||||
|
name: 'ExampleAdd'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/example-demo/example-edit',
|
||||||
|
title: '列表综合实例-编辑',
|
||||||
|
name: 'ExampleEdit'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/example-demo/example-detail',
|
||||||
|
title: '列表综合实例-详情',
|
||||||
|
name: 'ExampleDetail'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -576,6 +504,21 @@ export const checkedNodes = [
|
||||||
title: '列表综合实例-页面',
|
title: '列表综合实例-页面',
|
||||||
name: 'ExamplePage'
|
name: 'ExamplePage'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/example-demo/example-add',
|
||||||
|
title: '列表综合实例-新增',
|
||||||
|
name: 'ExampleAdd'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/example-demo/example-edit',
|
||||||
|
title: '列表综合实例-编辑',
|
||||||
|
name: 'ExampleEdit'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/example-demo/example-detail',
|
||||||
|
title: '列表综合实例-详情',
|
||||||
|
name: 'ExampleDetail'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/role-demo',
|
path: '/role-demo',
|
||||||
title: '权限管理',
|
title: '权限管理',
|
||||||
|
@ -621,11 +564,6 @@ export const checkedkeys = [
|
||||||
'/components-demo/qrcode',
|
'/components-demo/qrcode',
|
||||||
'/components-demo/avatars',
|
'/components-demo/avatars',
|
||||||
'/components-demo/watermark',
|
'/components-demo/watermark',
|
||||||
'/components-demo/timer',
|
|
||||||
'/components-demo/marquee',
|
|
||||||
'/components-demo/water-fall',
|
|
||||||
'/components-demo/tree-select',
|
|
||||||
'/components-demo/ellipsis',
|
|
||||||
'/table-demo',
|
'/table-demo',
|
||||||
'/table-demo/basic-table',
|
'/table-demo/basic-table',
|
||||||
'/table-demo/page-table',
|
'/table-demo/page-table',
|
||||||
|
@ -649,9 +587,6 @@ export const checkedkeys = [
|
||||||
'/table-demo/custom-index',
|
'/table-demo/custom-index',
|
||||||
'/directives-demo',
|
'/directives-demo',
|
||||||
'/directives-demo/clipboard',
|
'/directives-demo/clipboard',
|
||||||
'/hooks-demo',
|
|
||||||
'/hooks-demo/watermark',
|
|
||||||
'/hooks-demo/useScrollTo',
|
|
||||||
'/icon/index',
|
'/icon/index',
|
||||||
'/level',
|
'/level',
|
||||||
'/level/menu1',
|
'/level/menu1',
|
||||||
|
@ -662,6 +597,9 @@ export const checkedkeys = [
|
||||||
'/example-demo',
|
'/example-demo',
|
||||||
'/example-demo/example-dialog',
|
'/example-demo/example-dialog',
|
||||||
'/example-demo/example-page',
|
'/example-demo/example-page',
|
||||||
|
'/example-demo/example-add',
|
||||||
|
'/example-demo/example-edit',
|
||||||
|
'/example-demo/example-detail',
|
||||||
'/role-demo',
|
'/role-demo',
|
||||||
'/role-demo/user',
|
'/role-demo/user',
|
||||||
'/role-demo/role'
|
'/role-demo/role'
|
||||||
|
|
|
@ -71,7 +71,7 @@ export const checkedRoleNodes = [
|
||||||
component: 'views/components-demo/detail/index',
|
component: 'views/components-demo/detail/index',
|
||||||
name: 'DetailDemo',
|
name: 'DetailDemo',
|
||||||
meta: {
|
meta: {
|
||||||
title: '详情组件'
|
title: '详情'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -79,7 +79,7 @@ export const checkedRoleNodes = [
|
||||||
component: 'views/components-demo/qrcode/index',
|
component: 'views/components-demo/qrcode/index',
|
||||||
name: 'QrcodeDemo',
|
name: 'QrcodeDemo',
|
||||||
meta: {
|
meta: {
|
||||||
title: '二维码组件'
|
title: '二维码'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -105,46 +105,6 @@ export const checkedRoleNodes = [
|
||||||
meta: {
|
meta: {
|
||||||
title: '水印'
|
title: '水印'
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'timer',
|
|
||||||
component: 'views/components-demo/timer/index',
|
|
||||||
name: 'TimerDemo',
|
|
||||||
meta: {
|
|
||||||
title: '计时器'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'marquee',
|
|
||||||
component: 'views/components-demo/marquee/index',
|
|
||||||
name: 'MarqueeDemo',
|
|
||||||
meta: {
|
|
||||||
title: '无缝滚动'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'water-fall',
|
|
||||||
component: 'views/components-demo/water-fall/index',
|
|
||||||
name: 'WaterFallDemo',
|
|
||||||
meta: {
|
|
||||||
title: '瀑布流'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'tree-select',
|
|
||||||
component: 'views/components-demo/tree-select/index',
|
|
||||||
name: 'TreeSelectDemo',
|
|
||||||
meta: {
|
|
||||||
title: '下拉树'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'ellipsis',
|
|
||||||
component: 'views/components-demo/ellipsis/index',
|
|
||||||
name: 'Ellipsis',
|
|
||||||
meta: {
|
|
||||||
title: '省略号'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -496,104 +496,104 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/example-demo',
|
||||||
|
component: Layout,
|
||||||
|
name: 'ExampleDemo',
|
||||||
|
redirect: '/example-demo/example-dialog',
|
||||||
|
meta: {
|
||||||
|
alwaysShow: true,
|
||||||
|
icon: 'example',
|
||||||
|
title: '综合实例'
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'example-dialog',
|
||||||
|
component: () => import('_v/example-demo/example-dialog/index.vue'),
|
||||||
|
name: 'ExampleDialog',
|
||||||
|
meta: {
|
||||||
|
title: '列表综合实例-弹窗'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'example-page',
|
||||||
|
component: () => import('_v/example-demo/example-page/index.vue'),
|
||||||
|
name: 'ExamplePage',
|
||||||
|
meta: {
|
||||||
|
title: '列表综合实例-页面'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'example-add',
|
||||||
|
component: () => import('_v/example-demo/example-page/example-add.vue'),
|
||||||
|
name: 'ExampleAdd',
|
||||||
|
meta: {
|
||||||
|
title: '列表综合实例-新增',
|
||||||
|
noTagsView: true,
|
||||||
|
noCache: true,
|
||||||
|
hidden: true,
|
||||||
|
showMainRoute: true,
|
||||||
|
activeMenu: '/example-demo/example-page'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'example-edit',
|
||||||
|
component: () => import('_v/example-demo/example-page/example-edit.vue'),
|
||||||
|
name: 'ExampleEdit',
|
||||||
|
meta: {
|
||||||
|
title: '列表综合实例-编辑',
|
||||||
|
noTagsView: true,
|
||||||
|
noCache: true,
|
||||||
|
hidden: true,
|
||||||
|
showMainRoute: true,
|
||||||
|
activeMenu: '/example-demo/example-page'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'example-detail',
|
||||||
|
component: () => import('_v/example-demo/example-page/example-detail.vue'),
|
||||||
|
name: 'ExampleDetail',
|
||||||
|
meta: {
|
||||||
|
title: '列表综合实例-详情',
|
||||||
|
noTagsView: true,
|
||||||
|
noCache: true,
|
||||||
|
hidden: true,
|
||||||
|
showMainRoute: true,
|
||||||
|
activeMenu: '/example-demo/example-page'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/role-demo',
|
||||||
|
component: Layout,
|
||||||
|
redirect: '/role-demo/user',
|
||||||
|
name: 'RoleDemo',
|
||||||
|
meta: {
|
||||||
|
title: '权限管理',
|
||||||
|
icon: 'user',
|
||||||
|
alwaysShow: true
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'user',
|
||||||
|
component: () => import('_v/role-demo/user/index.vue'),
|
||||||
|
name: 'User',
|
||||||
|
meta: {
|
||||||
|
title: '用户管理'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'role',
|
||||||
|
component: () => import('_v/role-demo/role/index.vue'),
|
||||||
|
name: 'Role',
|
||||||
|
meta: {
|
||||||
|
title: '角色管理'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
// {
|
|
||||||
// path: '/example-demo',
|
|
||||||
// component: Layout,
|
|
||||||
// name: 'ExampleDemo',
|
|
||||||
// redirect: '/example-demo/example-dialog',
|
|
||||||
// meta: {
|
|
||||||
// alwaysShow: true,
|
|
||||||
// icon: 'example',
|
|
||||||
// title: '综合实例'
|
|
||||||
// },
|
|
||||||
// children: [
|
|
||||||
// {
|
|
||||||
// path: 'example-dialog',
|
|
||||||
// component: () => import('_v/example-demo/example-dialog/index.vue'),
|
|
||||||
// name: 'ExampleDialog',
|
|
||||||
// meta: {
|
|
||||||
// title: '列表综合实例-弹窗'
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: 'example-page',
|
|
||||||
// component: () => import('_v/example-demo/example-page/index.vue'),
|
|
||||||
// name: 'ExamplePage',
|
|
||||||
// meta: {
|
|
||||||
// title: '列表综合实例-页面'
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: 'example-add',
|
|
||||||
// component: () => import('_v/example-demo/example-page/example-add.vue'),
|
|
||||||
// name: 'ExampleAdd',
|
|
||||||
// meta: {
|
|
||||||
// title: '列表综合实例-新增',
|
|
||||||
// noTagsView: true,
|
|
||||||
// noCache: true,
|
|
||||||
// hidden: true,
|
|
||||||
// showMainRoute: true,
|
|
||||||
// activeMenu: '/example-demo/example-page'
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: 'example-edit',
|
|
||||||
// component: () => import('_v/example-demo/example-page/example-edit.vue'),
|
|
||||||
// name: 'ExampleEdit',
|
|
||||||
// meta: {
|
|
||||||
// title: '列表综合实例-编辑',
|
|
||||||
// noTagsView: true,
|
|
||||||
// noCache: true,
|
|
||||||
// hidden: true,
|
|
||||||
// showMainRoute: true,
|
|
||||||
// activeMenu: '/example-demo/example-page'
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: 'example-detail',
|
|
||||||
// component: () => import('_v/example-demo/example-page/example-detail.vue'),
|
|
||||||
// name: 'ExampleDetail',
|
|
||||||
// meta: {
|
|
||||||
// title: '列表综合实例-详情',
|
|
||||||
// noTagsView: true,
|
|
||||||
// noCache: true,
|
|
||||||
// hidden: true,
|
|
||||||
// showMainRoute: true,
|
|
||||||
// activeMenu: '/example-demo/example-page'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/role-demo',
|
|
||||||
// component: Layout,
|
|
||||||
// redirect: '/role-demo/user',
|
|
||||||
// name: 'RoleDemo',
|
|
||||||
// meta: {
|
|
||||||
// title: '权限管理',
|
|
||||||
// icon: 'user',
|
|
||||||
// alwaysShow: true
|
|
||||||
// },
|
|
||||||
// children: [
|
|
||||||
// {
|
|
||||||
// path: 'user',
|
|
||||||
// component: () => import('_v/role-demo/user/index.vue'),
|
|
||||||
// name: 'User',
|
|
||||||
// meta: {
|
|
||||||
// title: '用户管理'
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: 'role',
|
|
||||||
// component: () => import('_v/role-demo/role/index.vue'),
|
|
||||||
// name: 'Role',
|
|
||||||
// meta: {
|
|
||||||
// title: '角色管理'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
|
|
|
@ -17,5 +17,6 @@ export interface RouteMeta {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export interface AppRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
|
export interface AppRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
|
||||||
meta: RouteMeta
|
meta: RouteMeta
|
||||||
|
title?: string
|
||||||
children?: AppRouteRecordRaw[]
|
children?: AppRouteRecordRaw[]
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,8 @@ import { store } from '../index'
|
||||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||||
const appStore = useAppStoreWithOut()
|
const appStore = useAppStoreWithOut()
|
||||||
|
|
||||||
const modules = import.meta.glob('./src/views/*/*.vue')
|
const modules = import.meta.glob('../../views/**/*.vue')
|
||||||
|
console.log(modules)
|
||||||
|
|
||||||
/* Layout */
|
/* Layout */
|
||||||
const Layout = () => import('@/layout/index.vue')
|
const Layout = () => import('@/layout/index.vue')
|
||||||
|
@ -100,6 +101,7 @@ function generateRoutesFn(routes: AppRouteRecordRaw[], basePath = '/'): AppRoute
|
||||||
for (const route of routes) {
|
for (const route of routes) {
|
||||||
// skip some route
|
// skip some route
|
||||||
if (route.meta && route.meta.hidden && !route.meta.showMainRoute) {
|
if (route.meta && route.meta.hidden && !route.meta.showMainRoute) {
|
||||||
|
console.log(route)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +164,7 @@ function getFilterRoutes(routes: AppRouteRecordRaw[]): AppRouteRecordRaw[] {
|
||||||
? Layout
|
? Layout
|
||||||
: (route.component as any).includes('##')
|
: (route.component as any).includes('##')
|
||||||
? getParentLayout((route.component as any).split('##')[1])
|
? getParentLayout((route.component as any).split('##')[1])
|
||||||
: modules[`@/${route.component}.vue`]
|
: modules[`../../${route.component}.vue`]
|
||||||
) as any
|
) as any
|
||||||
}
|
}
|
||||||
// recursive child routes
|
// recursive child routes
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import fetch from '@/axios-config'
|
||||||
|
|
||||||
|
export const getExampleListApi = ({ params }: any) => {
|
||||||
|
return fetch({ url: '/example/list', method: 'get', params })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const delsExampApi = ({ data }: any) => {
|
||||||
|
return fetch({ url: '/example/delete', method: 'post', data })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setExampApi = ({ data }: any) => {
|
||||||
|
return fetch({ url: '/example/save', method: 'post', data })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getExampDetApi = ({ params }: any) => {
|
||||||
|
return fetch({ url: '/example/detail', method: 'get', params })
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<com-detail :data="form" :schema="fromSchema" :collapsed="false" title="文章详情">
|
||||||
|
<template #contentContent="scope">
|
||||||
|
<div v-html="scope.row.content"></div>
|
||||||
|
</template>
|
||||||
|
</com-detail>
|
||||||
|
<div class="dialong__button--wrap">
|
||||||
|
<el-button @click="close">取消</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="Detail">
|
||||||
|
import { PropType, reactive } from 'vue'
|
||||||
|
import { getExampDetApi } from '../api'
|
||||||
|
import { SchemaConfig } from '_c/ComDetail/types'
|
||||||
|
|
||||||
|
const fromSchema: SchemaConfig[] = [
|
||||||
|
{
|
||||||
|
field: 'title',
|
||||||
|
label: '标题',
|
||||||
|
span: 24
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'author',
|
||||||
|
label: '作者'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'display_time',
|
||||||
|
label: '创建时间'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'importance',
|
||||||
|
label: '重要性'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'pageviews',
|
||||||
|
label: '阅读数'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'content',
|
||||||
|
label: '内容',
|
||||||
|
span: 24
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
info: {
|
||||||
|
type: Object as PropType<Nullable<IObj>>,
|
||||||
|
default: () => null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['close'])
|
||||||
|
|
||||||
|
const form = reactive<IObj>({
|
||||||
|
id: '', // id
|
||||||
|
author: '', // 作者
|
||||||
|
title: '', // 标题
|
||||||
|
content: '', // 内容
|
||||||
|
importance: '', // 重要性
|
||||||
|
display_time: '', // 创建时间
|
||||||
|
pageviews: 0 // 阅读数
|
||||||
|
})
|
||||||
|
|
||||||
|
async function getDet() {
|
||||||
|
if (props.info) {
|
||||||
|
const id = props.info.id
|
||||||
|
try {
|
||||||
|
const res: any = await getExampDetApi({
|
||||||
|
params: {
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (res) {
|
||||||
|
for (const key in form) {
|
||||||
|
if (key === 'importance') {
|
||||||
|
form[key] = (res.data[key] as number).toString()
|
||||||
|
} else {
|
||||||
|
form[key] = res.data[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
|
||||||
|
getDet()
|
||||||
|
</script>
|
|
@ -0,0 +1,158 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item prop="title" label="标题">
|
||||||
|
<el-input v-model="form.title" placeholder="请输入标题" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item prop="author" label="作者">
|
||||||
|
<el-input v-model="form.author" placeholder="请输入作者" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item prop="display_time" label="创建时间">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="form.display_time"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="请选择创建时间"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item prop="importance" label="重要性">
|
||||||
|
<el-select v-model="form.importance" placeholder="请选择重要性" style="width: 100%">
|
||||||
|
<el-option label="重要" value="3" />
|
||||||
|
<el-option label="良好" value="2" />
|
||||||
|
<el-option label="一般" value="1" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item prop="pageviews" label="阅读数">
|
||||||
|
<el-input-number
|
||||||
|
v-model="form.pageviews"
|
||||||
|
:min="0"
|
||||||
|
:max="99999999"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item prop="content" label="内容">
|
||||||
|
<editor ref="editorRef" :value="form.content" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<div class="dialong__button--wrap">
|
||||||
|
<el-button @click="close">取消</el-button>
|
||||||
|
<el-button :loading="subLoading" type="primary" @click="setListData">保存</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="IfnoWrite">
|
||||||
|
import { PropType, reactive, ref } from 'vue'
|
||||||
|
import { setExampApi, getExampDetApi } from '../api'
|
||||||
|
import Editor from '_c/Editor/index.vue'
|
||||||
|
import { Message } from '_c/Message'
|
||||||
|
|
||||||
|
const requiredRule: {
|
||||||
|
required: boolean
|
||||||
|
message: string
|
||||||
|
} = {
|
||||||
|
required: true,
|
||||||
|
message: '该项为必填项'
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
info: {
|
||||||
|
type: Object as PropType<Nullable<IObj>>,
|
||||||
|
default: () => null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['success', 'close'])
|
||||||
|
|
||||||
|
const editorRef = ref<Nullable<HTMLElement>>(null)
|
||||||
|
const formRef = ref<Nullable<HTMLElement>>(null)
|
||||||
|
|
||||||
|
const subLoading = ref<boolean>(false)
|
||||||
|
const form = reactive<IObj>({
|
||||||
|
id: '', // id
|
||||||
|
author: '', // 作者
|
||||||
|
title: '', // 标题
|
||||||
|
content: '', // 内容
|
||||||
|
importance: '', // 重要性
|
||||||
|
display_time: '', // 创建时间
|
||||||
|
pageviews: 0 // 阅读数
|
||||||
|
})
|
||||||
|
const rules = reactive<IObj>({
|
||||||
|
title: [requiredRule],
|
||||||
|
author: [requiredRule],
|
||||||
|
content: [requiredRule],
|
||||||
|
importance: [requiredRule],
|
||||||
|
display_time: [requiredRule],
|
||||||
|
pageviews: [requiredRule]
|
||||||
|
})
|
||||||
|
|
||||||
|
async function getDet() {
|
||||||
|
if (props.info) {
|
||||||
|
const id = props.info.id
|
||||||
|
try {
|
||||||
|
const res: any = await getExampDetApi({
|
||||||
|
params: {
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (res) {
|
||||||
|
for (const key in form) {
|
||||||
|
if (key === 'importance') {
|
||||||
|
form[key] = (res.data[key] as number).toString()
|
||||||
|
} else {
|
||||||
|
form[key] = res.data[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增或者编辑
|
||||||
|
function setListData() {
|
||||||
|
try {
|
||||||
|
subLoading.value = true
|
||||||
|
form.content = (editorRef.value as any).getHtml()
|
||||||
|
;(formRef.value as any).validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
const res = await setExampApi({
|
||||||
|
data: form
|
||||||
|
})
|
||||||
|
if (res) {
|
||||||
|
Message.success(form.id ? '编辑成功' : '新增成功')
|
||||||
|
emit('success', form.id ? 'edit' : 'add')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('error submit!!')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
} finally {
|
||||||
|
subLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
|
||||||
|
getDet()
|
||||||
|
</script>
|
|
@ -0,0 +1,18 @@
|
||||||
|
export interface InfoWriteParams {
|
||||||
|
title: string
|
||||||
|
id?: string
|
||||||
|
author: string
|
||||||
|
content: string
|
||||||
|
importance: string
|
||||||
|
display_time: string
|
||||||
|
pageviews: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InfoWriteRules {
|
||||||
|
title?: any[]
|
||||||
|
author?: any[]
|
||||||
|
content?: any[]
|
||||||
|
importance?: any[]
|
||||||
|
display_time?: any[]
|
||||||
|
pageviews?: any[]
|
||||||
|
}
|
|
@ -0,0 +1,135 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="search__example--wrap">
|
||||||
|
<com-search :data="searchData" @search-submit="searchSubmit" @reset-submit="resetSubmit" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="button__example--wrap">
|
||||||
|
<el-button type="primary" icon="el-icon-circle-plus-outline" @click="open(null, 'InfoWrite')">
|
||||||
|
新增
|
||||||
|
</el-button>
|
||||||
|
<el-button type="danger" icon="el-icon-delete" @click="dels">删除</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<com-table
|
||||||
|
v-loading="loading"
|
||||||
|
selection
|
||||||
|
:columns="columns"
|
||||||
|
:data="tableData"
|
||||||
|
:pagination="{
|
||||||
|
currentPage: defaultParams.pageIndex,
|
||||||
|
total: total,
|
||||||
|
onSizeChange: handleSizeChange,
|
||||||
|
onCurrentChange: handleCurrentChange
|
||||||
|
}"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
>
|
||||||
|
<template #importance="scope">
|
||||||
|
<el-tag
|
||||||
|
:type="
|
||||||
|
scope.row.importance === 3
|
||||||
|
? 'success'
|
||||||
|
: scope.row.importance === 2
|
||||||
|
? 'warning'
|
||||||
|
: 'danger'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ scope.row.importance === 3 ? '重要' : scope.row.importance === 2 ? '良好' : '一般' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
<template #action="scope">
|
||||||
|
<el-button type="primary" size="mini" @click="open(scope.row, 'InfoWrite')">编辑</el-button>
|
||||||
|
<el-button type="success" size="mini" @click="open(scope.row, 'Detail')">查看</el-button>
|
||||||
|
<el-button type="danger" size="mini" @click="dels(scope.row)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</com-table>
|
||||||
|
|
||||||
|
<com-dialog v-model="dialogVisible" :title="dialogTitle">
|
||||||
|
<info-write
|
||||||
|
v-if="comName === 'InfoWrite' && dialogVisible"
|
||||||
|
:info="rowData"
|
||||||
|
@close="toggleVisible"
|
||||||
|
@success="refreshTable"
|
||||||
|
/>
|
||||||
|
<detail v-if="comName === 'Detail' && dialogVisible" :info="rowData" @close="toggleVisible" />
|
||||||
|
</com-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="ExampleDialog">
|
||||||
|
import { getExampleListApi, delsExampApi } from './api'
|
||||||
|
import { useWork } from '@/hooks/work/useWork'
|
||||||
|
import InfoWrite from './components/InfoWrite.vue'
|
||||||
|
import Detail from './components/Detail.vue'
|
||||||
|
const {
|
||||||
|
defaultParams,
|
||||||
|
tableData,
|
||||||
|
loading,
|
||||||
|
total,
|
||||||
|
dialogVisible,
|
||||||
|
dialogTitle,
|
||||||
|
comName,
|
||||||
|
rowData,
|
||||||
|
handleSizeChange,
|
||||||
|
handleCurrentChange,
|
||||||
|
handleSelectionChange,
|
||||||
|
toggleVisible,
|
||||||
|
getList,
|
||||||
|
searchSubmit,
|
||||||
|
resetSubmit,
|
||||||
|
open,
|
||||||
|
refreshTable,
|
||||||
|
dels
|
||||||
|
} = useWork({
|
||||||
|
listFun: getExampleListApi,
|
||||||
|
delFun: delsExampApi
|
||||||
|
})
|
||||||
|
|
||||||
|
const searchData = [
|
||||||
|
{
|
||||||
|
label: '标题',
|
||||||
|
value: '',
|
||||||
|
itemType: 'input',
|
||||||
|
field: 'title',
|
||||||
|
placeholder: '请输入标题',
|
||||||
|
clearable: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
field: 'title',
|
||||||
|
label: '标题',
|
||||||
|
showOverflowTooltip: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'author',
|
||||||
|
label: '作者'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'display_time',
|
||||||
|
label: '创建时间'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'importance',
|
||||||
|
label: '重要性',
|
||||||
|
slots: {
|
||||||
|
default: 'importance'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'pageviews',
|
||||||
|
label: '阅读数'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'action',
|
||||||
|
label: '操作',
|
||||||
|
width: '220px',
|
||||||
|
slots: {
|
||||||
|
default: 'action'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
getList()
|
||||||
|
</script>
|
|
@ -0,0 +1,17 @@
|
||||||
|
import fetch from '@/axios-config'
|
||||||
|
|
||||||
|
export const getExampleListApi = ({ params }: any) => {
|
||||||
|
return fetch({ url: '/example/list2', method: 'get', params })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const delsExampApi = ({ data }: any) => {
|
||||||
|
return fetch({ url: '/example/delete', method: 'post', data })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setExampApi = ({ data }: any) => {
|
||||||
|
return fetch({ url: '/example/save', method: 'post', data })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getExampDetApi = ({ params }: any) => {
|
||||||
|
return fetch({ url: '/example/detail', method: 'get', params })
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<com-detail :data="form" :schema="fromSchema" :collapsed="false" title="文章详情">
|
||||||
|
<template #contentContent="scope">
|
||||||
|
<div v-html="scope.row.content"></div>
|
||||||
|
</template>
|
||||||
|
</com-detail>
|
||||||
|
<div class="dialong__button--wrap">
|
||||||
|
<el-button @click="close">取消</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="Detail">
|
||||||
|
import { PropType, reactive } from 'vue'
|
||||||
|
import { getExampDetApi } from '../api'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
const { push } = useRouter()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
id: {
|
||||||
|
type: String as PropType<string>,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const fromSchema = [
|
||||||
|
{
|
||||||
|
field: 'title',
|
||||||
|
label: '标题',
|
||||||
|
span: 24
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'author',
|
||||||
|
label: '作者'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'display_time',
|
||||||
|
label: '创建时间'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'importance',
|
||||||
|
label: '重要性'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'pageviews',
|
||||||
|
label: '阅读数'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'content',
|
||||||
|
label: '内容',
|
||||||
|
span: 24,
|
||||||
|
slots: {
|
||||||
|
default: 'content'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const form = reactive<IObj>({
|
||||||
|
id: '', // id
|
||||||
|
author: '', // 作者
|
||||||
|
title: '', // 标题
|
||||||
|
content: '', // 内容
|
||||||
|
importance: '', // 重要性
|
||||||
|
display_time: '', // 创建时间
|
||||||
|
pageviews: 0 // 阅读数
|
||||||
|
})
|
||||||
|
|
||||||
|
async function getDet() {
|
||||||
|
if (props.id) {
|
||||||
|
const id = props.id
|
||||||
|
try {
|
||||||
|
const res: any = await getExampDetApi({
|
||||||
|
params: {
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (res) {
|
||||||
|
for (const key in form) {
|
||||||
|
if (key === 'importance') {
|
||||||
|
form[key] = (res.data[key] as number).toString()
|
||||||
|
} else {
|
||||||
|
form[key] = res.data[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
push('/example-demo/example-page')
|
||||||
|
}
|
||||||
|
|
||||||
|
getDet()
|
||||||
|
</script>
|
|
@ -0,0 +1,160 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item prop="title" label="标题">
|
||||||
|
<el-input v-model="form.title" placeholder="请输入标题" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item prop="author" label="作者">
|
||||||
|
<el-input v-model="form.author" placeholder="请输入作者" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item prop="display_time" label="创建时间">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="form.display_time"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="请选择创建时间"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item prop="importance" label="重要性">
|
||||||
|
<el-select v-model="form.importance" placeholder="请选择重要性" style="width: 100%">
|
||||||
|
<el-option label="重要" value="3" />
|
||||||
|
<el-option label="良好" value="2" />
|
||||||
|
<el-option label="一般" value="1" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item prop="pageviews" label="阅读数">
|
||||||
|
<el-input-number
|
||||||
|
v-model="form.pageviews"
|
||||||
|
:min="0"
|
||||||
|
:max="99999999"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item prop="content" label="内容">
|
||||||
|
<editor ref="editorRef" :value="form.content" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<div class="dialong__button--wrap">
|
||||||
|
<el-button @click="close">取消</el-button>
|
||||||
|
<el-button :loading="subLoading" type="primary" @click="setListData">保存</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="InfoWrite">
|
||||||
|
import { PropType, ref, reactive } from 'vue'
|
||||||
|
import { setExampApi, getExampDetApi } from '../api'
|
||||||
|
import Editor from '_c/Editor/index.vue'
|
||||||
|
import { Message } from '_c/Message'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
const { push } = useRouter()
|
||||||
|
|
||||||
|
const requiredRule: {
|
||||||
|
required: boolean
|
||||||
|
message: string
|
||||||
|
} = {
|
||||||
|
required: true,
|
||||||
|
message: '该项为必填项'
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
id: {
|
||||||
|
type: String as PropType<string>,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['success'])
|
||||||
|
|
||||||
|
const editorRef = ref<Nullable<HTMLElement>>(null)
|
||||||
|
const formRef = ref<Nullable<HTMLElement>>(null)
|
||||||
|
|
||||||
|
const subLoading = ref<boolean>(false)
|
||||||
|
const form = reactive<IObj>({
|
||||||
|
id: '', // id
|
||||||
|
author: '', // 作者
|
||||||
|
title: '', // 标题
|
||||||
|
content: '', // 内容
|
||||||
|
importance: '', // 重要性
|
||||||
|
display_time: '', // 创建时间
|
||||||
|
pageviews: 0 // 阅读数
|
||||||
|
})
|
||||||
|
const rules = reactive<IObj>({
|
||||||
|
title: [requiredRule],
|
||||||
|
author: [requiredRule],
|
||||||
|
content: [requiredRule],
|
||||||
|
importance: [requiredRule],
|
||||||
|
display_time: [requiredRule],
|
||||||
|
pageviews: [requiredRule]
|
||||||
|
})
|
||||||
|
|
||||||
|
async function getDet() {
|
||||||
|
if (props.id) {
|
||||||
|
const id = props.id
|
||||||
|
try {
|
||||||
|
const res: any = await getExampDetApi({
|
||||||
|
params: {
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (res) {
|
||||||
|
for (const key in form) {
|
||||||
|
if (key === 'importance') {
|
||||||
|
form[key] = (res.data[key] as number).toString()
|
||||||
|
} else {
|
||||||
|
form[key] = res.data[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增或者编辑
|
||||||
|
function setListData() {
|
||||||
|
try {
|
||||||
|
subLoading.value = true
|
||||||
|
form.content = (editorRef.value as any).getHtml()
|
||||||
|
;(formRef.value as any).validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
const res = await setExampApi({
|
||||||
|
data: form
|
||||||
|
})
|
||||||
|
if (res) {
|
||||||
|
Message.success(form.id ? '编辑成功' : '新增成功')
|
||||||
|
emit('success', form.id ? 'edit' : 'add')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('error submit!!')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
} finally {
|
||||||
|
subLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
push('/example-demo/example-page')
|
||||||
|
}
|
||||||
|
|
||||||
|
getDet()
|
||||||
|
</script>
|
|
@ -0,0 +1,18 @@
|
||||||
|
export interface InfoWriteParams {
|
||||||
|
title: string
|
||||||
|
id?: string
|
||||||
|
author: string
|
||||||
|
content: string
|
||||||
|
importance: string
|
||||||
|
display_time: string
|
||||||
|
pageviews: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InfoWriteRules {
|
||||||
|
title?: any[]
|
||||||
|
author?: any[]
|
||||||
|
content?: any[]
|
||||||
|
importance?: any[]
|
||||||
|
display_time?: any[]
|
||||||
|
pageviews?: any[]
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
<template>
|
||||||
|
<info-write @success="success" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="ExampleAdd">
|
||||||
|
import InfoWrite from './components/InfoWrite.vue'
|
||||||
|
import bus from '@/vue-bus'
|
||||||
|
function success(type: string) {
|
||||||
|
bus.$emit('success', type)
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<template>
|
||||||
|
<detail :id="id" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="ExampleDetail">
|
||||||
|
import Detail from './components/Detail.vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
const { query } = useRoute()
|
||||||
|
const id = query.id as string
|
||||||
|
</script>
|
|
@ -0,0 +1,17 @@
|
||||||
|
<template>
|
||||||
|
<info-write :id="id" @success="success" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import InfoWrite from './components/InfoWrite.vue'
|
||||||
|
import bus from '@/vue-bus'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
const { query } = useRoute()
|
||||||
|
const id = query.id as string
|
||||||
|
|
||||||
|
// 成功之后的回调
|
||||||
|
function success(type: string) {
|
||||||
|
// 由于使用的是页面跳转,所以只能通过vueBus去进行通信
|
||||||
|
bus.$emit('success', type)
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,139 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="search__example--wrap">
|
||||||
|
<com-search :data="searchData" @search-submit="searchSubmit" @reset-submit="resetSubmit" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="button__example--wrap">
|
||||||
|
<el-button type="primary" icon="el-icon-circle-plus-outline" @click="open(null)">
|
||||||
|
新增
|
||||||
|
</el-button>
|
||||||
|
<el-button type="danger" icon="el-icon-delete" @click="dels">删除</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<com-table
|
||||||
|
v-loading="loading"
|
||||||
|
selection
|
||||||
|
:columns="columns"
|
||||||
|
:data="tableData"
|
||||||
|
:pagination="{
|
||||||
|
currentPage: defaultParams.pageIndex,
|
||||||
|
total: total,
|
||||||
|
onSizeChange: handleSizeChange,
|
||||||
|
onCurrentChange: handleCurrentChange
|
||||||
|
}"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
>
|
||||||
|
<template #importance="scope">
|
||||||
|
<el-tag
|
||||||
|
:type="
|
||||||
|
scope.row.importance === 3
|
||||||
|
? 'success'
|
||||||
|
: scope.row.importance === 2
|
||||||
|
? 'warning'
|
||||||
|
: 'danger'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ scope.row.importance === 3 ? '重要' : scope.row.importance === 2 ? '良好' : '一般' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
<template #action="scope">
|
||||||
|
<el-button type="primary" size="mini" @click="open(scope.row)">编辑</el-button>
|
||||||
|
<el-button type="success" size="mini" @click="open(scope.row, 'Detail')">查看</el-button>
|
||||||
|
<el-button type="danger" size="mini" @click="dels(scope.row)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</com-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="ExampleDialog">
|
||||||
|
import { onBeforeUnmount } from 'vue'
|
||||||
|
import { getExampleListApi, delsExampApi } from './api'
|
||||||
|
import { useWork } from '@/hooks/work/useWork'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
const { push } = useRouter()
|
||||||
|
import bus from '@/vue-bus'
|
||||||
|
const {
|
||||||
|
defaultParams,
|
||||||
|
tableData,
|
||||||
|
loading,
|
||||||
|
total,
|
||||||
|
handleSizeChange,
|
||||||
|
handleCurrentChange,
|
||||||
|
handleSelectionChange,
|
||||||
|
getList,
|
||||||
|
searchSubmit,
|
||||||
|
resetSubmit,
|
||||||
|
refreshTable,
|
||||||
|
dels
|
||||||
|
} = useWork({
|
||||||
|
listFun: getExampleListApi,
|
||||||
|
delFun: delsExampApi
|
||||||
|
})
|
||||||
|
|
||||||
|
const searchData = [
|
||||||
|
{
|
||||||
|
label: '标题',
|
||||||
|
value: '',
|
||||||
|
itemType: 'input',
|
||||||
|
field: 'title',
|
||||||
|
placeholder: '请输入标题',
|
||||||
|
clearable: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
field: 'title',
|
||||||
|
label: '标题',
|
||||||
|
showOverflowTooltip: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'author',
|
||||||
|
label: '作者'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'display_time',
|
||||||
|
label: '创建时间'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'importance',
|
||||||
|
label: '重要性',
|
||||||
|
slots: {
|
||||||
|
default: 'importance'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'pageviews',
|
||||||
|
label: '阅读数'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'action',
|
||||||
|
label: '操作',
|
||||||
|
width: '220px',
|
||||||
|
slots: {
|
||||||
|
default: 'action'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
function open(row: Nullable<IObj>, component?: string) {
|
||||||
|
push(
|
||||||
|
!row
|
||||||
|
? `/example-demo/example-add`
|
||||||
|
: component
|
||||||
|
? `/example-demo/example-detail?id=${row.id}`
|
||||||
|
: `/example-demo/example-edit?id=${row.id}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
getList()
|
||||||
|
|
||||||
|
bus.$on('success', (type: string) => {
|
||||||
|
refreshTable(type)
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
bus.$off('success')
|
||||||
|
})
|
||||||
|
</script>
|
|
@ -0,0 +1,13 @@
|
||||||
|
import fetch from '@/axios-config'
|
||||||
|
|
||||||
|
export const getRoleListApi = ({ params }: any) => {
|
||||||
|
return fetch({ url: '/role/list', method: 'get', params })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setRoleApi = ({ data }: any) => {
|
||||||
|
return fetch({ url: '/role/save', method: 'post', data })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getRoleDetApi = ({ params }: any) => {
|
||||||
|
return fetch({ url: '/role/detail', method: 'get', params })
|
||||||
|
}
|
|
@ -0,0 +1,201 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item prop="roleName" label="角色名">
|
||||||
|
<el-input v-model="form.roleName" disabled placeholder="请输入角色名" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="角色权限">
|
||||||
|
<el-tree
|
||||||
|
ref="tree"
|
||||||
|
:check-strictly="false"
|
||||||
|
:data="routesData as any"
|
||||||
|
:props="defaultProps as any"
|
||||||
|
show-checkbox
|
||||||
|
accordion
|
||||||
|
node-key="path"
|
||||||
|
highlight-current
|
||||||
|
class="permission-tree"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<div class="dialong__button--wrap">
|
||||||
|
<el-button @click="close">取消</el-button>
|
||||||
|
<el-button :loading="subLoading" type="primary" @click="setListData">保存</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="InfoWrite">
|
||||||
|
import { PropType, computed, nextTick, reactive, ref } from 'vue'
|
||||||
|
import path from 'path-browserify'
|
||||||
|
import { setRoleApi, getRoleDetApi } from '../api'
|
||||||
|
import { asyncRouterMap } from '@/router'
|
||||||
|
import { isExternal } from '@/utils/validate'
|
||||||
|
import { Message } from '_c/Message'
|
||||||
|
import { AppRouteRecordRaw } from '@/router/types'
|
||||||
|
|
||||||
|
const requiredRule: {
|
||||||
|
required: boolean
|
||||||
|
message: string
|
||||||
|
} = {
|
||||||
|
required: true,
|
||||||
|
message: '该项为必填项'
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
info: {
|
||||||
|
type: Object as PropType<Nullable<IObj>>,
|
||||||
|
default: () => null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['success', 'close'])
|
||||||
|
|
||||||
|
const tree = ref<Nullable<HTMLElement>>(null)
|
||||||
|
const formRef = ref<Nullable<HTMLElement>>(null)
|
||||||
|
const subLoading = ref<boolean>(false)
|
||||||
|
const form = reactive<IObj>({
|
||||||
|
id: '', // id
|
||||||
|
roleName: '', // 角色名
|
||||||
|
checkedNodes: [], // 被选中的节点
|
||||||
|
checkedkeys: [] // 被选中的keys
|
||||||
|
})
|
||||||
|
const rules = reactive<IObj>({
|
||||||
|
roleName: [requiredRule]
|
||||||
|
})
|
||||||
|
const routes = ref<IObj>([])
|
||||||
|
const defaultProps = reactive<IObj>({
|
||||||
|
children: 'children',
|
||||||
|
label: 'title'
|
||||||
|
})
|
||||||
|
|
||||||
|
const routesData = computed(() => routes.value)
|
||||||
|
|
||||||
|
async function getDet() {
|
||||||
|
if (props.info) {
|
||||||
|
const id = props.info.id
|
||||||
|
try {
|
||||||
|
const res: any = await getRoleDetApi({
|
||||||
|
params: {
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (res) {
|
||||||
|
for (const key in form) {
|
||||||
|
form[key] = res.data[key]
|
||||||
|
}
|
||||||
|
nextTick(() => {
|
||||||
|
;(tree.value as any).setCheckedKeys(form.checkedkeys)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增或者编辑
|
||||||
|
function setListData() {
|
||||||
|
try {
|
||||||
|
subLoading.value = true
|
||||||
|
;(formRef.value as any).validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
// 获取所有被选中节点,由于是前端渲染,所以只要保存一维数组就行
|
||||||
|
form.checkedNodes = (tree.value as any).getCheckedNodes(false, true)
|
||||||
|
console.log(JSON.stringify(form.checkedNodes))
|
||||||
|
// 获取所有被选中的keys,便于渲染是否选中
|
||||||
|
form.checkedkeys = (tree.value as any).getCheckedKeys()
|
||||||
|
console.log(JSON.stringify(form.checkedkeys))
|
||||||
|
const res = await setRoleApi({
|
||||||
|
data: form
|
||||||
|
})
|
||||||
|
if (res) {
|
||||||
|
Message.success(
|
||||||
|
form.id ? '编辑成功,请重新退出登录后查看效果' : '新增成功,请重新退出登录后查看效果'
|
||||||
|
)
|
||||||
|
emit('success', form.id ? 'edit' : 'add')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('error submit!!')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
} finally {
|
||||||
|
subLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateRoutes(routes: AppRouteRecordRaw[], basePath = '/') {
|
||||||
|
const res: AppRouteRecordRaw[] = []
|
||||||
|
|
||||||
|
for (let route of routes) {
|
||||||
|
// skip some route
|
||||||
|
if (route.meta && route.meta.hidden) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const onlyOneShowingChild = onlyOneShowingChildFn(
|
||||||
|
route.children,
|
||||||
|
route,
|
||||||
|
path.resolve(basePath, route.path)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (route.children && onlyOneShowingChild && !(route.meta && route.meta.alwaysShow)) {
|
||||||
|
route = onlyOneShowingChild
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
path: isExternal(route.path) ? route.path : path.resolve(basePath, route.path),
|
||||||
|
title: route.meta && route.meta.title,
|
||||||
|
name: route.name
|
||||||
|
}
|
||||||
|
// recursive child routes
|
||||||
|
if (route.children) {
|
||||||
|
;(data as any).children = generateRoutes(route.children, data.path)
|
||||||
|
}
|
||||||
|
res.push(data as any)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
function onlyOneShowingChildFn(
|
||||||
|
children: AppRouteRecordRaw[] = [],
|
||||||
|
parent: AppRouteRecordRaw,
|
||||||
|
basePath: string
|
||||||
|
) {
|
||||||
|
let onlyOneChild: Nullable<AppRouteRecordRaw | any> = null
|
||||||
|
const showingChildren = children.filter((item) => !(item.meta && item.meta.hidden))
|
||||||
|
// When there is only one child route, the child route is displayed by default
|
||||||
|
if (showingChildren.length === 1) {
|
||||||
|
onlyOneChild = showingChildren[0]
|
||||||
|
onlyOneChild.path = isExternal(onlyOneChild.path)
|
||||||
|
? onlyOneChild.path
|
||||||
|
: path.resolve(basePath, onlyOneChild.path)
|
||||||
|
return onlyOneChild
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show parent if there are no child route to display
|
||||||
|
if (showingChildren.length === 0) {
|
||||||
|
onlyOneChild = { ...parent, path: '', noShowingChildren: true }
|
||||||
|
return onlyOneChild
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldRoutes = [...asyncRouterMap]
|
||||||
|
routes.value = generateRoutes(oldRoutes)
|
||||||
|
getDet()
|
||||||
|
</script>
|
|
@ -0,0 +1,225 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="130px">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item prop="roleName" label="角色名">
|
||||||
|
<el-input v-model="form.roleName" disabled placeholder="请输入角色名" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="角色权限">
|
||||||
|
<el-tree
|
||||||
|
ref="tree"
|
||||||
|
:check-strictly="false"
|
||||||
|
:expand-on-click-node="false"
|
||||||
|
:data="routesData as any"
|
||||||
|
:props="defaultProps as any"
|
||||||
|
accordion
|
||||||
|
node-key="path"
|
||||||
|
highlight-current
|
||||||
|
class="permission-tree"
|
||||||
|
@node-click="handleNodeClick"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-if="seletTreeData" :span="12">
|
||||||
|
<el-form-item label="title">
|
||||||
|
<el-input v-model="seletTreeData.title" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="component">
|
||||||
|
<el-input v-model="seletTreeData.component" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="redirect">
|
||||||
|
<el-input v-model="seletTreeData.redirect" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="activeMenu">
|
||||||
|
<el-input v-model="seletTreeData.meta.activeMenu" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="name">
|
||||||
|
<el-input v-model="seletTreeData.name" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="icon">
|
||||||
|
<el-input v-model="seletTreeData.meta.icon" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="hidden">
|
||||||
|
<el-switch v-model="seletTreeData.meta.hidden" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="alwaysShow">
|
||||||
|
<el-switch v-model="seletTreeData.meta.alwaysShow" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="noCache">
|
||||||
|
<el-switch v-model="seletTreeData.meta.noCache" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="breadcrumb">
|
||||||
|
<el-switch v-model="seletTreeData.meta.breadcrumb" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="affix">
|
||||||
|
<el-switch v-model="seletTreeData.meta.affix" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="noTagsView">
|
||||||
|
<el-switch v-model="seletTreeData.meta.noTagsView" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="showMainRoute">
|
||||||
|
<el-switch v-model="seletTreeData.meta.showMainRoute" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<div class="dialong__button--wrap">
|
||||||
|
<el-button @click="close">取消</el-button>
|
||||||
|
<el-button :loading="subLoading" type="primary" @click="setListData">保存</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="InfoWrite2">
|
||||||
|
import { PropType, computed, nextTick, reactive, ref } from 'vue'
|
||||||
|
import { setRoleApi, getRoleDetApi } from '../api'
|
||||||
|
import { Message } from '_c/Message'
|
||||||
|
import { AppRouteRecordRaw } from '@/router/types'
|
||||||
|
|
||||||
|
const requiredRule: {
|
||||||
|
required: boolean
|
||||||
|
message: string
|
||||||
|
} = {
|
||||||
|
required: true,
|
||||||
|
message: '该项为必填项'
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
info: {
|
||||||
|
type: Object as PropType<Nullable<IObj>>,
|
||||||
|
default: () => null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['success', 'close'])
|
||||||
|
|
||||||
|
const tree = ref<Nullable<HTMLElement>>(null)
|
||||||
|
const formRef = ref<Nullable<HTMLElement>>(null)
|
||||||
|
const subLoading = ref<boolean>(false)
|
||||||
|
const form = reactive<IObj>({
|
||||||
|
id: '', // id
|
||||||
|
roleName: '', // 角色名
|
||||||
|
checkedNodes: [], // 被选中的节点
|
||||||
|
checkedkeys: [] // 被选中的keys
|
||||||
|
})
|
||||||
|
const rules = reactive<IObj>({
|
||||||
|
roleName: [requiredRule]
|
||||||
|
})
|
||||||
|
const routes = ref<IObj>([])
|
||||||
|
const defaultProps = reactive<IObj>({
|
||||||
|
children: 'children',
|
||||||
|
label: 'title'
|
||||||
|
})
|
||||||
|
const seletTreeData = ref<Nullable<IObj>>(null)
|
||||||
|
const routesData = computed(() => routes.value)
|
||||||
|
|
||||||
|
async function getDet() {
|
||||||
|
if (props.info) {
|
||||||
|
const id = props.info.id
|
||||||
|
try {
|
||||||
|
const res: any = await getRoleDetApi({
|
||||||
|
params: {
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (res) {
|
||||||
|
console.log(res)
|
||||||
|
for (const key in form) {
|
||||||
|
form[key] = res.data[key]
|
||||||
|
}
|
||||||
|
routes.value = generateRoutes(form.checkedNodes)
|
||||||
|
nextTick(() => {
|
||||||
|
;(tree.value as any).setCheckedKeys(form.checkedkeys)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 树形点击
|
||||||
|
function handleNodeClick(data: IObj) {
|
||||||
|
seletTreeData.value = data
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增或者编辑
|
||||||
|
function setListData() {
|
||||||
|
try {
|
||||||
|
subLoading.value = true
|
||||||
|
;(formRef.value as any).validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
console.log(routesData.value)
|
||||||
|
// 获取所有被选中节点
|
||||||
|
// const checkedNodes = this.$refs.tree.getCheckedNodes(false, true).filter(v => {
|
||||||
|
// if (v.path.includes('/')) return v
|
||||||
|
// })
|
||||||
|
// // 获取所有被选中的keys,便于渲染是否选中
|
||||||
|
// this.form.checkedkeys = this.$refs.tree.getCheckedKeys()
|
||||||
|
// console.log(JSON.stringify(this.form.checkedkeys))
|
||||||
|
|
||||||
|
// this.form.checkedNodes = this.getFilterNodes(checkedNodes)
|
||||||
|
// console.log(JSON.stringify(this.form.checkedNodes))
|
||||||
|
const res = await setRoleApi({
|
||||||
|
data: Object.assign(form, { checkedNodes: routesData.value })
|
||||||
|
})
|
||||||
|
if (res) {
|
||||||
|
Message.success(
|
||||||
|
form.id ? '编辑成功,请重新退出登录后查看效果' : '新增成功,请重新退出登录后查看效果'
|
||||||
|
)
|
||||||
|
emit('success', form.id ? 'edit' : 'add')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('error submit!!')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
} finally {
|
||||||
|
subLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 树形渲染过滤
|
||||||
|
function generateRoutes(routes: AppRouteRecordRaw[]) {
|
||||||
|
const res: AppRouteRecordRaw[] = []
|
||||||
|
|
||||||
|
for (const route of routes) {
|
||||||
|
const data: AppRouteRecordRaw = {
|
||||||
|
path: route.path,
|
||||||
|
name: route.name,
|
||||||
|
redirect: route.redirect || '',
|
||||||
|
title: (route as any).title || (route.meta && route.meta.title),
|
||||||
|
component: (route as any).component || '',
|
||||||
|
meta: {
|
||||||
|
title: (route as any).title || (route.meta && route.meta.title),
|
||||||
|
alwaysShow: route.meta && route.meta.alwaysShow,
|
||||||
|
hidden: route.meta && route.meta.hidden,
|
||||||
|
icon: route.meta && route.meta.icon,
|
||||||
|
noCache: route.meta && route.meta.noCache,
|
||||||
|
breadcrumb: route.meta && route.meta.breadcrumb,
|
||||||
|
affix: route.meta && route.meta.affix,
|
||||||
|
noTagsView: route.meta && route.meta.noTagsView,
|
||||||
|
activeMenu: route.meta && route.meta.activeMenu,
|
||||||
|
showMainRoute: route.meta && route.meta.showMainRoute
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// recursive child routes
|
||||||
|
if (route.children) {
|
||||||
|
data.children = generateRoutes(route.children)
|
||||||
|
}
|
||||||
|
res.push(data)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
getDet()
|
||||||
|
</script>
|
|
@ -0,0 +1,124 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-alert
|
||||||
|
effect="dark"
|
||||||
|
:closable="false"
|
||||||
|
title="由于是模拟数据,所以只提供了两种不同权限的角色,开发者可根据实际情况自行改造结合。"
|
||||||
|
type="info"
|
||||||
|
style="margin-bottom: 20px"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="search__example--wrap">
|
||||||
|
<com-search :data="searchData" @search-submit="searchSubmit" @reset-submit="resetSubmit" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<com-table
|
||||||
|
v-loading="loading"
|
||||||
|
:columns="columns"
|
||||||
|
:data="tableData"
|
||||||
|
:pagination="{
|
||||||
|
currentPage: defaultParams.pageIndex,
|
||||||
|
total: total,
|
||||||
|
onSizeChange: handleSizeChange,
|
||||||
|
onCurrentChange: handleCurrentChange
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #remark="scope">
|
||||||
|
<span>模拟</span>
|
||||||
|
<el-tag
|
||||||
|
:type="scope.row.roleName === 'admin' ? 'success' : 'warning'"
|
||||||
|
style="margin: 0 15px"
|
||||||
|
>
|
||||||
|
{{ scope.row.roleName === 'admin' ? '前端' : '后端' }}
|
||||||
|
</el-tag>
|
||||||
|
<span>角色</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #action="scope">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="mini"
|
||||||
|
@click="open(scope.row, scope.row.roleName === 'admin' ? 'InfoWrite' : 'InfoWrite2')"
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</com-table>
|
||||||
|
|
||||||
|
<com-dialog v-model="dialogVisible" :title="dialogTitle">
|
||||||
|
<info-write
|
||||||
|
v-if="comName === 'InfoWrite' && dialogVisible"
|
||||||
|
:info="rowData"
|
||||||
|
@close="toggleVisible"
|
||||||
|
@success="refreshTable"
|
||||||
|
/>
|
||||||
|
<info-write2
|
||||||
|
v-if="comName === 'InfoWrite2' && dialogVisible"
|
||||||
|
:info="rowData"
|
||||||
|
@close="toggleVisible"
|
||||||
|
@success="refreshTable"
|
||||||
|
/>
|
||||||
|
</com-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="Role">
|
||||||
|
import { getRoleListApi } from './api'
|
||||||
|
import { useWork } from '@/hooks/work/useWork'
|
||||||
|
import InfoWrite from './components/InfoWrite.vue'
|
||||||
|
import InfoWrite2 from './components/InfoWrite2.vue'
|
||||||
|
const {
|
||||||
|
defaultParams,
|
||||||
|
tableData,
|
||||||
|
loading,
|
||||||
|
total,
|
||||||
|
dialogVisible,
|
||||||
|
dialogTitle,
|
||||||
|
comName,
|
||||||
|
rowData,
|
||||||
|
handleSizeChange,
|
||||||
|
handleCurrentChange,
|
||||||
|
toggleVisible,
|
||||||
|
getList,
|
||||||
|
searchSubmit,
|
||||||
|
resetSubmit,
|
||||||
|
open,
|
||||||
|
refreshTable
|
||||||
|
} = useWork({
|
||||||
|
listFun: getRoleListApi
|
||||||
|
})
|
||||||
|
|
||||||
|
const searchData = [
|
||||||
|
{
|
||||||
|
label: '角色名',
|
||||||
|
value: '',
|
||||||
|
itemType: 'input',
|
||||||
|
field: 'roleName',
|
||||||
|
placeholder: '请输入角色名',
|
||||||
|
clearable: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
field: 'roleName',
|
||||||
|
label: '角色名'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '备注',
|
||||||
|
slots: {
|
||||||
|
default: 'remark'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'action',
|
||||||
|
label: '操作',
|
||||||
|
width: '80px',
|
||||||
|
slots: {
|
||||||
|
default: 'action'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
getList()
|
||||||
|
</script>
|
|
@ -0,0 +1,5 @@
|
||||||
|
import fetch from '@/axios-config'
|
||||||
|
|
||||||
|
export const getUserListApi = ({ params }: any) => {
|
||||||
|
return fetch({ url: '/user/list', method: 'get', params })
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-alert
|
||||||
|
effect="dark"
|
||||||
|
:closable="false"
|
||||||
|
title="由于是模拟数据,所以只提供了两种不同权限的帐号,开发者可根据实际情况自行改造结合。"
|
||||||
|
type="info"
|
||||||
|
style="margin-bottom: 20px"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="search__example--wrap">
|
||||||
|
<com-search :data="searchData" @search-submit="searchSubmit" @reset-submit="resetSubmit" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<com-table
|
||||||
|
v-loading="loading"
|
||||||
|
:columns="columns"
|
||||||
|
:data="tableData"
|
||||||
|
:pagination="{
|
||||||
|
currentPage: defaultParams.pageIndex,
|
||||||
|
total: total,
|
||||||
|
onSizeChange: handleSizeChange,
|
||||||
|
onCurrentChange: handleCurrentChange
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #remark="scope">
|
||||||
|
<span>模拟</span>
|
||||||
|
<el-tag
|
||||||
|
:type="scope.row.userName === 'admin' ? 'success' : 'warning'"
|
||||||
|
style="margin: 0 15px"
|
||||||
|
>
|
||||||
|
{{ scope.row.userName === 'admin' ? '前端' : '后端' }}
|
||||||
|
</el-tag>
|
||||||
|
<span>控制路由权限</span>
|
||||||
|
</template>
|
||||||
|
</com-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="User">
|
||||||
|
import { getUserListApi } from './api'
|
||||||
|
import { useWork } from '@/hooks/work/useWork'
|
||||||
|
const {
|
||||||
|
defaultParams,
|
||||||
|
tableData,
|
||||||
|
loading,
|
||||||
|
total,
|
||||||
|
handleSizeChange,
|
||||||
|
handleCurrentChange,
|
||||||
|
getList,
|
||||||
|
searchSubmit,
|
||||||
|
resetSubmit
|
||||||
|
} = useWork({
|
||||||
|
listFun: getUserListApi
|
||||||
|
})
|
||||||
|
|
||||||
|
const searchData = [
|
||||||
|
{
|
||||||
|
label: '帐号',
|
||||||
|
value: '',
|
||||||
|
itemType: 'input',
|
||||||
|
field: 'userName',
|
||||||
|
placeholder: '请输入帐号',
|
||||||
|
clearable: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
field: 'userName',
|
||||||
|
label: '帐号'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'password',
|
||||||
|
label: '密码'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'role',
|
||||||
|
label: '角色'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '备注',
|
||||||
|
slots: {
|
||||||
|
default: 'remark'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
getList()
|
||||||
|
</script>
|
|
@ -0,0 +1,13 @@
|
||||||
|
// 通过mitt实现vue-bus通信
|
||||||
|
|
||||||
|
import mitt from 'mitt'
|
||||||
|
|
||||||
|
const bus: any = {}
|
||||||
|
|
||||||
|
const emitter = mitt()
|
||||||
|
|
||||||
|
bus.$on = emitter.on
|
||||||
|
bus.$off = emitter.off
|
||||||
|
bus.$emit = emitter.emit
|
||||||
|
|
||||||
|
export default bus
|
|
@ -5115,6 +5115,11 @@ minimist@1.2.5, minimist@^1.2.0, minimist@^1.2.5:
|
||||||
resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||||
|
|
||||||
|
mitt@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.nlark.com/mitt/download/mitt-3.0.0.tgz?cache=0&sync_timestamp=1624481394885&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fmitt%2Fdownload%2Fmitt-3.0.0.tgz#69ef9bd5c80ff6f57473e8d89326d01c414be0bd"
|
||||||
|
integrity sha1-ae+b1cgP9vV0c+jYkybQHEFL4L0=
|
||||||
|
|
||||||
mixin-deep@^1.2.0:
|
mixin-deep@^1.2.0:
|
||||||
version "1.3.2"
|
version "1.3.2"
|
||||||
resolved "https://registry.nlark.com/mixin-deep/download/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
|
resolved "https://registry.nlark.com/mixin-deep/download/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
|
||||||
|
|
Loading…
Reference in New Issue