Vue.js 筆記(六)vite-element-admin 動態選單

今天要跟大家介紹如何使用 vite-element-admin 製作動態 menu
vite-element-admin 是一個後台前端解決方案,使用了最新的 vue3vite2…等技術。

Quick Start

Table Schema

在開始之前,需要先跟大家介紹一下關於動態選單,我的後端 table schema 是怎麼設計的。

  • adm_user 後台使用者

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    create table adm_user
    (
    id bigint auto_increment primary key,
    role_code varchar(10) not null comment 'role code',
    username varchar(255) charset utf8mb3 not null comment '用户名',
    password varchar(255) charset utf8mb3 not null comment '密码',
    user_status int default 0 null comment '0:正常, 1:禁止',
    last_login_time datetime null,
    create_user varchar(50) charset utf8mb3 null,
    create_time datetime default CURRENT_TIMESTAMP null,
    modify_user varchar(50) charset utf8mb3 null,
    modify_time datetime default CURRENT_TIMESTAMP null,
    constraint username unique (username)
    );
    INSERT INTO djsj.adm_user (id, role_code, username, password, user_status, last_login_time, create_user, create_time, modify_user, modify_time) VALUES (1, 'admin', 'admin', '$2b$10$c4lupIdjmr/znwcTqkjVX./7wveGopVLO/MfgcB0QtOoNEGyEkIeC', 0, '2023-08-25 15:05:09', 'sys', '2021-03-19 10:06:51', null, null);
  • adm_role 後台角色

    1
    2
    3
    4
    5
    6
    7
    8
    9
    create table adm_role
    (
    id bigint auto_increment primary key,
    role_code varchar(10) not null,
    name varchar(255) charset utf8mb3 not null comment '角色名稱',
    createTime datetime default CURRENT_TIMESTAMP null comment '創建時間',
    constraint name unique (role_code)
    );
    INSERT INTO djsj.adm_role (id, role_code, name, createTime) VALUES (1, 'admin', '管理員', '2021-03-01 00:00:00');
  • adm_menu 選單

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    create table adm_menu
    (
    id bigint auto_increment primary key,
    pid bigint not null comment '上層選單',
    phyle varchar(50) null comment 'Parent Hierarchy',
    name varchar(255) not null comment '权限名称',
    path varchar(255) not null comment '权限对应的接口',
    redirect varchar(255) null comment 'redirect',
    component varchar(255) not null comment 'component',
    meta json null comment 'meta data',
    sort int default 0 not null comment '排序'
    );
    INSERT INTO djsj.adm_menu (id, pid, phyle, name, path, redirect, component, meta, sort) VALUES (1, 0, '0', 'Dashboard', '/', '/dashboard', 'layout', '{"icon": "home", "title": "首頁"}', 1);
    INSERT INTO djsj.adm_menu (id, pid, phyle, name, path, redirect, component, meta, sort) VALUES (2, 1, '0|1', 'Dashboard', 'dashboard', null, 'dashboard/index', '{"title": "首頁", "noCache": true}', 1);
    INSERT INTO djsj.adm_menu (id, pid, phyle, name, path, redirect, component, meta, sort) VALUES (3, 0, '0', 'User', '/user', '/user/log', 'layout', '{"title": "個人資訊", "hidden": true}', 1);
    INSERT INTO djsj.adm_menu (id, pid, phyle, name, path, redirect, component, meta, sort) VALUES (4, 3, '0|3', 'UserLog', 'log', null, 'user/log', '{"title": "操作記錄", "hidden": true}', 0);
    INSERT INTO djsj.adm_menu (id, pid, phyle, name, path, redirect, component, meta, sort) VALUES (5, 3, '0|3', 'UserPassword', 'password', null, 'user/password', '{"title": "修改密碼", "hidden": true}', 0);
    INSERT INTO djsj.adm_menu (id, pid, phyle, name, path, redirect, component, meta, sort) VALUES (6, 0, '0', 'Admin', '/admin', '/admin/user', 'layout', '{"icon": "users", "title": "使用者管理"}', 2);
    INSERT INTO djsj.adm_menu (id, pid, phyle, name, path, redirect, component, meta, sort) VALUES (7, 6, '0|6', 'AdminUser', 'user', null, 'admin/user', '{"title": "使用者帳號", "noCache": true}', 0);
    INSERT INTO djsj.adm_menu (id, pid, phyle, name, path, redirect, component, meta, sort) VALUES (8, 6, '0|6', 'AdminLog', 'log', null, 'admin/log', '{"title": "系統日誌", "noCache": true}', 1);
    INSERT INTO djsj.adm_menu (id, pid, phyle, name, path, redirect, component, meta, sort) VALUES (9, 0, '0', 'Player', '/player', '/player/index', 'layout', '{"icon": "account", "title": "玩家管理"}', 3);
    INSERT INTO djsj.adm_menu (id, pid, phyle, name, path, redirect, component, meta, sort) VALUES (10, 9, '0|9', 'PlayerIndex', 'index', null, 'player/index', '{"title": "玩家帳號", "noCache": true}', 0);
    INSERT INTO djsj.adm_menu (id, pid, phyle, name, path, redirect, component, meta, sort) VALUES (11, 9, '0|9', 'PlayerWallet', 'wallet', null, 'player/wallet', '{"title": "玩家帳務", "noCache": true}', 1);
    INSERT INTO djsj.adm_menu (id, pid, phyle, name, path, redirect, component, meta, sort) VALUES (12, 0, '0', 'Game', '/game', '/game/record', 'layout', '{"icon": "bug", "title": "遊戲管理"}', 4);
    INSERT INTO djsj.adm_menu (id, pid, phyle, name, path, redirect, component, meta, sort) VALUES (13, 12, '0|12', 'GameRecord', 'record', null, 'game/record', '{"title": "遊戲紀錄", "noCache": true}', 0);
    INSERT INTO djsj.adm_menu (id, pid, phyle, name, path, redirect, component, meta, sort) VALUES (14, 12, '0|12', 'GameLog', 'log', null, 'game/log', '{"title": "遊戲歷程", "noCache": true}', 1);
  • adm_role_menu_map 角色選單對應表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    create table adm_role_menu_map
    (
    id bigint auto_increment primary key,
    role_code varchar(10) not null comment 'role code',
    menu_id bigint not null comment 'adm_menu.id'
    );
    INSERT INTO djsj.adm_role_menu_map (id, role_code, menu_id) VALUES (1, 'admin', 1);
    INSERT INTO djsj.adm_role_menu_map (id, role_code, menu_id) VALUES (2, 'admin', 2);
    INSERT INTO djsj.adm_role_menu_map (id, role_code, menu_id) VALUES (3, 'admin', 3);
    INSERT INTO djsj.adm_role_menu_map (id, role_code, menu_id) VALUES (4, 'admin', 4);
    INSERT INTO djsj.adm_role_menu_map (id, role_code, menu_id) VALUES (5, 'admin', 5);
    INSERT INTO djsj.adm_role_menu_map (id, role_code, menu_id) VALUES (6, 'admin', 6);
    INSERT INTO djsj.adm_role_menu_map (id, role_code, menu_id) VALUES (7, 'admin', 7);
    INSERT INTO djsj.adm_role_menu_map (id, role_code, menu_id) VALUES (8, 'admin', 8);
    INSERT INTO djsj.adm_role_menu_map (id, role_code, menu_id) VALUES (9, 'admin', 9);
    INSERT INTO djsj.adm_role_menu_map (id, role_code, menu_id) VALUES (10, 'admin', 10);
    INSERT INTO djsj.adm_role_menu_map (id, role_code, menu_id) VALUES (11, 'admin', 11);
    INSERT INTO djsj.adm_role_menu_map (id, role_code, menu_id) VALUES (12, 'admin', 12);
    INSERT INTO djsj.adm_role_menu_map (id, role_code, menu_id) VALUES (13, 'admin', 13);
    INSERT INTO djsj.adm_role_menu_map (id, role_code, menu_id) VALUES (14, 'admin', 14);

後台API

  • indexHandle.js

    1
    2
    3
    4
    5
    6
    7
    router.get('/getMenuInfo', [filter.authorize], asyncHandler(async function (req, res) {
    let roleCode = req.roleCode;
    let admMenuList = await admMenuService.getAdmMenuByRoleCode(roleCode);
    utils.resEnd(res, new SuccessResBaseObj({
    admMenuList
    }));
    }));
  • sql

    1
    2
    3
    4
    select am.*
    from adm_menu am
    join adm_role_menu_map armm on am.id = armm.menu_id
    where armm.role_code = ?
  • response

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    {
    "code": 0,
    "message": "成功",
    "data": {
    "admMenuList": [
    {
    "id": 1,
    "pid": 0,
    "phyle": "0",
    "name": "Dashboard",
    "path": "/",
    "redirect": "/dashboard",
    "component": "layout",
    "meta": "{\"icon\": \"home\", \"title\": \"首頁\"}",
    "sort": 1
    },
    {
    "id": 2,
    "pid": 1,
    "phyle": "0|1",
    "name": "Dashboard",
    "path": "dashboard",
    "redirect": null,
    "component": "dashboard/index",
    "meta": "{\"title\": \"首頁\", \"noCache\": true}",
    "sort": 1
    },
    {
    "id": 3,
    "pid": 0,
    "phyle": "0",
    "name": "User",
    "path": "/user",
    "redirect": "/user/log",
    "component": "layout",
    "meta": "{\"title\": \"個人資訊\", \"hidden\": true}",
    "sort": 1
    },
    {
    "id": 4,
    "pid": 3,
    "phyle": "0|3",
    "name": "UserLog",
    "path": "log",
    "redirect": null,
    "component": "user/log",
    "meta": "{\"title\": \"操作記錄\", \"hidden\": true}",
    "sort": 0
    },
    {
    "id": 5,
    "pid": 3,
    "phyle": "0|3",
    "name": "UserPassword",
    "path": "password",
    "redirect": null,
    "component": "user/password",
    "meta": "{\"title\": \"修改密碼\", \"hidden\": true}",
    "sort": 0
    },
    {
    "id": 6,
    "pid": 0,
    "phyle": "0",
    "name": "Admin",
    "path": "/admin",
    "redirect": "/admin/user",
    "component": "layout",
    "meta": "{\"icon\": \"users\", \"title\": \"使用者管理\"}",
    "sort": 2
    },
    {
    "id": 7,
    "pid": 6,
    "phyle": "0|6",
    "name": "AdminUser",
    "path": "user",
    "redirect": null,
    "component": "admin/user",
    "meta": "{\"title\": \"使用者帳號\", \"noCache\": true}",
    "sort": 0
    },
    {
    "id": 8,
    "pid": 6,
    "phyle": "0|6",
    "name": "AdminLog",
    "path": "log",
    "redirect": null,
    "component": "admin/log",
    "meta": "{\"title\": \"系統日誌\", \"noCache\": true}",
    "sort": 1
    },
    {
    "id": 9,
    "pid": 0,
    "phyle": "0",
    "name": "Player",
    "path": "/player",
    "redirect": "/player/index",
    "component": "layout",
    "meta": "{\"icon\": \"account\", \"title\": \"玩家管理\"}",
    "sort": 3
    },
    {
    "id": 10,
    "pid": 9,
    "phyle": "0|9",
    "name": "PlayerIndex",
    "path": "index",
    "redirect": null,
    "component": "player/index",
    "meta": "{\"title\": \"玩家帳號\", \"noCache\": true}",
    "sort": 0
    },
    {
    "id": 11,
    "pid": 9,
    "phyle": "0|9",
    "name": "PlayerWallet",
    "path": "wallet",
    "redirect": null,
    "component": "player/wallet",
    "meta": "{\"title\": \"玩家帳務\", \"noCache\": true}",
    "sort": 1
    },
    {
    "id": 12,
    "pid": 0,
    "phyle": "0",
    "name": "Game",
    "path": "/game",
    "redirect": "/game/record",
    "component": "layout",
    "meta": "{\"icon\": \"bug\", \"title\": \"遊戲管理\"}",
    "sort": 4
    },
    {
    "id": 13,
    "pid": 12,
    "phyle": "0|12",
    "name": "GameRecord",
    "path": "record",
    "redirect": null,
    "component": "game/record",
    "meta": "{\"title\": \"遊戲紀錄\", \"noCache\": true}",
    "sort": 0
    },
    {
    "id": 14,
    "pid": 12,
    "phyle": "0|12",
    "name": "GameLog",
    "path": "log",
    "redirect": null,
    "component": "game/log",
    "meta": "{\"title\": \"遊戲歷程\", \"noCache\": true}",
    "sort": 1
    }
    ]
    }
    }

vite-element-admin 修改

主要重點在於修改,router/index.js ,獲取方式改為由 api 資料,並且使用遞迴將 json 組合出來。

成果

這次的介紹就到這邊,如果有其他問題請再跟我說。

Reference

vite-element-admin
vue-element-admin

謝謝您的支持與鼓勵

Ads