一、前言

博主大三上软件工程课要交一个项目,就想着在平时聊天的 QQ 群里面搞一个接入 AI 的 QQ 机器人。

这个想法确实很早就有了,也已经部署过一个聊天的猫娘机器人,不过用的是一个叫 Kirara AI 的现成开源项目,挺好用的,就想着自己写一个当作业交上去。

上个学期学数据库应用的时候也是要交一个前端+后端的项目,当时教的是 Swing + JDBC 这种纯 Java 的方式写前后端。但说实话,Swing 东西又老又丑,我记得期末的时候就没几个用 Swing 做项目(老师也没限制用什么,只有你有东西出来🤔)的,大多用的都是 Vue + SpringBoot。我不会 SpringBoot,就直接用的 node.js,毕竟做的就一个简单的学生成绩管理系统。

前端框架我们学校是教了一个 Vue 的,但后端没有教过,这导致这种项目课大多都是边学边做。感觉现在这些框架用的话已经用语法糖包得很简单了,就是用完了完全没印象,大多数时候就是对着官网的例子抄抄,再改点自己要用的东西😶‍🌫️。这次做项目的时候发现好多东西都忘了怎么用的了,翻之前的项目结果连启动后端服务器的命令都忘了🐱。想着把这次做的过程记录下来,下次忘了还有地方翻。

我尽量把项目做得严谨一点,不严谨的地方也不要压力我😭。

二、创建项目

JetBrains 家的 WebStorm 挺好用的,个人还是免费🦆。

CUKd0Ik7-1.png

npm install 安装依赖,git init 创建 git 仓库(可选,我感觉用一下 git 方便出问题后回退排查🤔)。

CUKd0Ik7-2.png

npm run dev ,打开本地连接,查看是否正常启动。

CUKd0Ik7-3.png

CUKd0Ik7-4.png

删除模板文件,和 App.vue、mian.js 中的模板。

CUKd0Ik7-5.png

CUKd0Ik7-6.png

三、前端

1、引入 Element Plus

一个基于 Vue 3,面向设计师和开发者的组件库。挺好用的,按 Element Plus 官网的教程引入就行了🐱(引入后记得再次使用 npm install 命令安装)。

CUKd0Ik7-7.png

CUKd0Ik7-8.png

Element Plus 的所有组件可在 Overview 组件总览 | Element Plus 查看。

2、添加一级路由

创建路由配置文件

准备做两个页面,一个登录页面和一个功能页面。一级路由加这两个就差不多了。

src 目录下创建一个 router 目录,在此目录下创建 index.js 文件编写路由信息。

这是当前最新的 Vue Router 的官方文档:Vue Router | Vue.js 的官方路由

使用 npm 在控制台安装 vue-router。

CUKd0Ik7-9.png

复制官方文档的例子到 index.js,使用 export default router 导出,等将一级路由的组件创建完后再修改配置文件🥳。

CUKd0Ik7-10.png

CUKd0Ik7-11.png

注册路由插件

创建了路由实例后还需要将其注册为插件。

已经参照官方文档,由于注册的插件会有很多,最好分开注册。

CUKd0Ik7-12.png

CUKd0Ik7-13.png

创建页面组件

src 目录下创建一个 view 目录,用来存放页面组件。

view 文件夹下创建 layout 目录来存放功能页面的组件,login 目录存放登录页面组件。两个目录下都创建 index.vue 默认组件。

CUKd0Ik7-14.png

编辑路由配置文件

vite.config.js 配置文件中添加 extensions: ['.js', '.vue'],指定在导入模块时可以省略的文件扩展名。

导入组件路径,@ 代表 src 目录,由于前面在 vite.config.js 配置了可以省略的文件扩展名,所以路径写到组件的存放目录后就能自动识别了😎(如果不想改 vite.config.js,在路径后把 index.vue 加上也是可以的)。

CUKd0Ik7-15.png

CUKd0Ik7-16.png

设置路由对应页面渲染位置

已经创建了两个页面和对应的路由,现在要找地方将页面展示出来。

就是展示用的组件,这个组件放在哪里,哪里就会替换渲染成对应路由的组件。

我一般会将页面组件直接放到 App.vue 这个全局组件里面。在 App.vue 中添加

CUKd0Ik7-17.png

3、 页面布局

页面的大体布局,Element Plus 里面有例子,这里我用的侧边栏加主体部分的布局😎。

大概就是这个效果。

CUKd0Ik7-18.png

参照 Element Plus 的 Container 容器布局在 /src/views/layout/index.vue 中大体的模板写好。运行项目,查看效果。

CUKd0Ik7-19.png

CUKd0Ik7-20.png

5、编写侧边栏

CUKd0Ik7-21.png

分顶部信息和菜单两个部分写,每个部分给出的代码用于替换上图的对应的文字部分。

顶部信息

侧边栏顶部展示信息,我一般喜欢放个图标然后后面接项目名字。最近玩三角洲比较上瘾,准备搞一个鼠鼠机器人,这个项目就叫 Mouse AI 吧🐭。

先把项目 Loge 放到 src/assets/images 目录下。

<el-aside> 侧边栏高度设为 100hv(占满整个浏览器窗口高度),添加边框。

<el-header> 容器修改为 flex,里面的元素居中排列。

<el-header> 中放 Loge 和 Title,调整好大小间距。

<script setup>
</script>

<template>
    <div class="common-layout">
        <el-container>
            <!-- 侧边栏 -->
            <el-aside class="sidebar" width="200px">
                <el-container>

                    <!-- Logo + Title -->
                    <el-header class="logo-title">
                        <el-image class="logo" src="src/assets/images/little-mouse.png"/>
                        <span class="title">Mouse AI</span>
                    </el-header>

                    <!-- Menu -->
                    <el-main>
                        Menu
                    </el-main>

                </el-container>
            </el-aside>
            <el-container>

                <!-- 主页面 -->
                <el-main>
                    Main
                </el-main>

            </el-container>
        </el-container>
    </div>
</template>

<style scoped>

.sidebar {
    height: 100vh;
    border-right: 1px solid var(--el-border-color);
}

.logo-title {
    display: flex;
    align-items: center;
    justify-content: start;
    height: 64px;
    border-bottom: 1px solid var(--el-border-color);
}

.logo {
    width: 36px;
    height: 36px;
    margin-right: 8px;
}

.title {
    font-size: 18px;
    font-weight: bold;
    color: #333;
}

</style>

22

菜单

准备做下面四个页面的菜单:

  • 首页
  • 请求记录
  • 机器人管理
  • 大模型管理
  • 设置

每个菜单选项也是 Icon + Title 的形式。对于 Icon 图标,可以选择用 Element Plus 提供的图标库,但缺点是种类有限(比如我想要一个 QQ 的图标它就没有😓)。这里推荐一个网站:iconfont-阿里巴巴矢量图标库,真的非常非常好用😍。

直接搜索你想要的图标,有非常多的格式可以选择,我这里就直接复制 SVG 代码插入了。

使用 <el-menu> 创建一个垂直菜单,设置菜单样式。

如果是从 iconfont 复制的 SVG 代码会自带 icon 类和 fill 属性(图标颜色),如果想让图标颜色和文字颜色同时改变的话,需要删除 <svg> 标签中的 fill 属性,再在 icon 类选择器中添加 fill: currentColor; 属性。

<script setup>
</script>

<template>
    <div class="common-layout">
        <el-container>

            <!-- 侧边栏 -->
            <el-aside class="sidebar" width="200px">
                <el-container>

                    <!-- Logo + Title -->
                    <el-header class="logo-title">
                        <el-image class="logo" src="src/assets/images/little-mouse.png"/>
                        <span class="title">Mouse AI</span>
                    </el-header>

                    <!-- Menu -->
                    <el-main class="menu-area">
                        <!-- default-active:默认激活菜单的 index -->
                        <el-menu
                            class="custom-menu"
                            default-active="1"
                        >
                            <!-- 首页 -->
                            <el-menu-item index="1">
                                <svg class="icon" height="200" p-id="24858" t="1759224577016"
                                     version="1.1" viewBox="0 0 1024 1024" width="200"
                                     xmlns="http://www.w3.org/2000/svg">
                                    <path
                                        d="M620 752h64a4 4 0 0 0 4-4V556a4 4 0 0 0-4-4h-64a4 4 0 0 0-4 4v192a4 4 0 0 0 4 4z m321.9-258.2L832 383.8V196a4 4 0 0 0-4-4H724a4 4 0 0 0-4 4v75.8L540.3 92.1a40.1 40.1 0 0 0-56.6 0l-22.6 22.7-379 379a3.9 3.9 0 0 0 0 5.6l45.2 45.3a4.2 4.2 0 0 0 5.7 0l59-59v369.9a40 40 0 0 0 40 40h560a40 40 0 0 0 40-40V485.7l59 59a4.2 4.2 0 0 0 5.7 0l45.2-45.3a3.9 3.9 0 0 0 0-5.6zM760 823.6H264V413.7l248-248 248 248z"
                                        p-id="24859"></path>
                                </svg>
                                首页
                            </el-menu-item>

                            <!-- 请求记录 -->
                            <el-menu-item index="2">
                                <svg class="icon" height="200" p-id="7611" t="1759231927950"
                                     version="1.1" viewBox="0 0 1024 1024" width="200"
                                     xmlns="http://www.w3.org/2000/svg">
                                    <path
                                        d="M511.7 958.9C264.9 958.9 64 758.1 64 511.3S264.9 63.7 511.7 63.7s447.6 200.8 447.6 447.6c0 99.7-32.1 194-92.7 272.8-10.1 13.1-28.8 15.5-41.9 5.4-13.1-10.1-15.5-28.8-5.4-41.9 52.5-68.3 80.3-150 80.3-236.4 0-213.9-174-388-388-388s-388 174-388 388c0 213.9 174 388 388 388 59.5 0 116.6-13.1 169.7-39 14.8-7.3 32.7-1.1 39.9 13.8 7.2 14.8 1.1 32.7-13.8 39.9-61.2 29.9-127.1 45-195.7 45z"
                                        p-id="7612"></path>
                                    <path
                                        d="M466.4 530h247.7c13.9 0 25.4 11.4 25.4 25.4v9c0 13.9-11.4 25.4-25.4 25.4H466.4c-13.9 0-25.4-11.4-25.4-25.4v-9c0.1-13.9 11.5-25.4 25.4-25.4z"
                                        p-id="7613"></path>
                                    <path
                                        d="M441.1 564.2v-249c0-14 11.5-25.5 25.5-25.5h8.7c14 0 25.5 11.5 25.5 25.5v249c0 14-11.5 25.5-25.5 25.5h-8.7c-14.1 0-25.5-11.4-25.5-25.5zM837.8 667.9l30.6 84.1c5.6 15.4-2.4 32.6-17.8 38.3-15.4 5.6-32.6-2.4-38.3-17.8l-30.6-84.1c-5.6-15.4 2.4-32.6 17.8-38.3 15.4-5.6 32.7 2.4 38.3 17.8z"
                                        p-id="7614"></path>
                                </svg>
                                请求记录
                            </el-menu-item>

                            <!-- 机器人管理 -->
                            <el-menu-item index="3">
                                <svg class="icon" height="200" p-id="18797" t="1759224362358"
                                     version="1.1" viewBox="0 0 1024 1024" width="200"
                                     xmlns="http://www.w3.org/2000/svg">
                                    <path
                                        d="M550.744931 834.806034 550.744931 834.806034c-11.183713 0-16.754592 0-22.327518 0-5.53404 0-11.144828 0-16.718777 0l-5.572926 0c-5.571902 0-16.717753 0-22.289656 5.53404-22.290679 22.326495-61.298088 33.475416-111.453395 33.475416-33.434483 0-61.298088-5.610788-89.163739-16.7198-22.289656-11.143805-33.435507-22.326495-33.435507-39.009456 0-16.717753 11.143805-27.862581 39.009456-39.045271 16.717753-5.535063 22.289656-11.106965 22.289656-22.326495 0-11.106965 0-22.25384-5.572926-27.863604-11.144828-11.034311-16.718777-27.788903-27.863604-38.896892-5.572926-11.144828-16.71673-16.755616-27.861558-16.755616l0 0c-11.144828 0-16.717753 5.608741-27.863604 11.220552-11.143805 11.106965-16.717753 16.644075-22.290679 16.644075l0 0c-5.572926 0-11.106965-16.644075-11.106965-44.505633 0-27.863604 5.535063-61.336974 11.070126-94.810343 11.145851-33.398668 27.862581-61.261249 55.725162-89.124853 5.574972-5.535063 11.146874-16.717753 11.146874-27.863604 0-5.53404 0-5.53404 0-11.106965 0-16.755616 5.571902-33.435507 16.71673-50.154283 5.573949-5.572926 5.573949-11.143805 5.573949-16.717753l0-5.573949c0.035816-66.908876 22.288632-122.635061 72.480778-172.789345 44.582381-50.191122 100.30652-72.444962 167.180604-72.444962 66.872037 0 122.600269 22.290679 172.751482 72.444962 44.618197 50.154283 72.480778 105.880469 72.480778 172.715667 0 0 0 0 0 5.572926 0 5.573949 0 11.144828 5.536087 16.717753 11.141758 16.718777 16.717753 33.398668 16.717753 50.154283 0 5.572926 0 5.572926 0 11.106965 0 11.144828 0 22.326495 11.143805 27.862581 27.863604 27.862581 44.581358 55.726186 55.726186 89.124853 11.144828 33.474392 16.717753 66.944691 11.144828 94.810343 0 27.862581-5.573949 38.97057-16.681938 44.50768-5.573949 0-11.183713-5.535063-22.328541-16.645099-5.533017-5.572926-16.718777-11.219529-27.861558-11.219529l-5.536087 0c-11.184737 0-22.325471 5.606695-27.861558 16.753569-5.573949 16.71673-16.754592 27.863604-27.863604 38.969547-5.572926 5.608741-11.18269 16.754592-5.572926 27.863604 0 11.220552 11.145851 16.753569 16.682961 22.326495 27.826765 11.219529 39.010479 22.364357 39.010479 39.08211 0 16.680914-11.183713 27.863604-33.43653 39.008432-22.289656 11.106965-55.724139 16.7198-89.164762 16.7198-50.15326 0-83.58979-11.184737-111.452371-33.474392 5.571902 0-5.572926-5.572926-11.106965-5.572926l0 0L550.744931 834.806034zM678.880263 940.724365c55.726186 0 100.30652-11.143805 133.74305-33.398668 33.435507-22.326495 55.724139-50.191122 55.724139-89.163739 0-22.291702-5.53404-39.046295-16.678868-55.726186 5.571902 0 16.678868 0 22.287609-5.608741 33.435507-11.106965 50.15633-38.97057 55.727209-83.591837 5.571902-38.9675 0-83.58979-16.681938-133.706211-11.18269-39.046295-33.435507-72.444962-61.297065-105.880469l0 0c0-27.862581-5.573949-50.154283-16.7198-78.015841 0-83.590813-27.861558-156.034752-89.124853-217.370703C684.450119 76.963882 612.004133 49.098231 528.418436 49.098231c-83.590813 0-156.034752 27.862581-217.334887 89.124853-55.764048 61.33595-89.163739 133.781936-89.163739 217.370703-11.143805 22.290679-16.717753 50.154283-16.717753 78.016865l0 5.571902c-33.434483 27.863604-50.154283 66.87306-61.298088 100.305497-16.718777 50.118468-22.290679 94.737688-16.718777 133.708258 5.573949 44.61922 27.863604 72.482825 55.726186 83.590813 5.572926 0 16.718777 5.608741 22.290679 5.608741-11.144828 16.681938-16.718777 33.43653-16.718777 55.726186 0 33.435507 16.718777 66.872037 55.727209 89.163739 33.435507 22.291702 78.015841 33.435507 128.169101 33.435507 55.725162 0 105.880469-11.142781 139.316999-39.007409l27.863604 0c39.045271 27.862581 83.590813 39.007409 139.316999 39.007409l0 0L678.880263 940.724365z"
                                        p-id="18798"></path>
                                </svg>
                                机器人管理
                            </el-menu-item>

                            <!-- 大模型管理 -->
                            <el-menu-item index="4">
                                <svg class="icon" height="200" p-id="19847" t="1759224400833"
                                     version="1.1" viewBox="0 0 1024 1024" width="200"
                                     xmlns="http://www.w3.org/2000/svg">
                                    <path
                                        d="M386.95424 122.34752a187.20768 187.20768 0 0 1 187.00288 0l197.40672 113.80736a187.20768 187.20768 0 0 1 93.70112 162.18624v41.81504a38.52288 38.52288 0 1 1-77.04064 0v-41.81504c0-9.02656-1.12128-17.8944-3.23584-26.43968l-267.7504 154.58816v316.7488a110.19776 110.19776 0 0 0 18.44224-8.4736l61.72672-35.64032a38.53312 38.53312 0 0 1 52.62848 14.10048 38.53824 38.53824 0 0 1-14.1056 52.62848l-61.72672 35.63008a187.19232 187.19232 0 0 1-187.10016 0.05632l-197.35552-113.77152a187.21792 187.21792 0 0 1-93.70624-162.18624V398.34112a187.2128 187.2128 0 0 1 93.70624-162.18624l197.40672-113.80736z m-211.456 252.2112a110.1824 110.1824 0 0 0-2.6112 23.7824v227.24096a110.1824 110.1824 0 0 0 55.1424 95.44192l197.3504 113.77152c4.73088 2.72896 9.6256 5.06368 14.61248 7.02976v-314.55744l-264.4992-152.704z m359.97696-185.45664a110.16192 110.16192 0 0 0-110.03904 0L228.02944 302.90432c-3.67616 2.11456-7.18848 4.43904-10.5472 6.92736l260.352 150.3232 263.27552-151.99232a109.568 109.568 0 0 0-8.23296-5.26336l-197.4016-113.79712zM914.76992 749.74208c0 7.93088-2.10432 13.99808-6.31808 18.21184s-10.28608 6.31808-18.21696 6.31808h-0.7424c-7.93088 0-13.99808-2.10432-18.21184-6.31808s-6.31808-10.28096-6.31808-18.21184V523.3664c0-7.92576 2.10432-13.99808 6.31808-18.21184s10.28096-6.31808 18.21184-6.31808h0.7424c7.93088 0 14.0032 2.10432 18.21696 6.31808s6.31808 10.28608 6.31808 18.21184v226.37568z"
                                        p-id="19848"></path>
                                    <path
                                        d="M827.39712 744.9088c2.72384 7.68 2.2272 14.49472-1.48992 20.44416s-9.66144 8.91904-17.8432 8.91904h-1.4848c-8.17664 0-14.7456-2.35008-19.70176-7.06048-4.70528-4.95616-8.67328-12.14464-11.89376-21.56032l-72.11008-198.49216h20.8128l-72.11008 198.49216c-3.47136 9.41568-7.55712 16.60416-12.26752 21.56032-4.45952 4.7104-10.9056 7.06048-19.328 7.06048h-1.48992c-7.92576 0-13.8752-2.9696-17.83808-8.91904-3.71712-5.94944-4.21376-12.76416-1.48992-20.44416l81.77664-224.512c5.4528-14.37696 16.10752-21.56032 31.96928-21.56032h0.7424c15.86176 0 26.51648 7.18336 31.96928 21.56032l81.77664 224.512z m-52.7872-89.58464v48.32256h-122.66496v-48.32256h122.66496z"
                                        p-id="19849"></path>
                                </svg>
                                大模型管理
                            </el-menu-item>

                            <!-- 设置 -->
                            <el-menu-item index="5">
                                <svg class="icon" height="200" p-id="20885" t="1759224433604"
                                     version="1.1" viewBox="0 0 1024 1024" width="200"
                                     xmlns="http://www.w3.org/2000/svg">
                                    <path
                                        d="M439.816 101.851c-8.631-16.952-28.007-25.48-46.337-20.396-70.066 19.435-133.165 55.501-184.82 103.628-12.909 12.028-16.413 31.094-8.623 46.926 5.374 10.92 8.414 23.234 8.414 36.376 0 45.555-36.833 82.347-82.1 82.347-0.381 0-0.762-0.003-1.142-0.008-17.691-0.253-33.448 11.147-38.74 28.031C73.159 421.209 66 466.344 66 513.078c0 30.844 3.118 61.001 9.07 90.156 4.1 20.082 22.714 33.816 43.111 31.808a83.069 83.069 0 0 1 8.169-0.399c45.267 0 82.1 36.791 82.1 82.346 0 20.276-7.254 38.74-19.334 53.086-13.177 15.649-12.423 38.718 1.748 53.472 52.742 54.916 119.403 96.417 194.376 118.784 20.888 6.231 42.918-5.408 49.543-26.174 10.616-33.275 41.714-57.212 78.217-57.212s67.601 23.937 78.217 57.212c6.625 20.766 28.655 32.405 49.543 26.174 74.973-22.367 141.634-63.868 194.376-118.784 14.17-14.755 14.924-37.823 1.748-53.471-12.08-14.346-19.334-32.811-19.334-53.087 0-45.554 36.834-82.346 82.1-82.346 2.773 0 5.496 0.135 8.169 0.399 20.397 2.008 39.011-11.726 43.111-31.808 5.951-29.155 9.07-59.312 9.07-90.156 0-46.734-7.16-91.869-20.468-134.323-5.292-16.884-21.049-28.285-38.741-28.031-0.379 0.005-0.76 0.008-1.141 0.008-45.266 0-82.1-36.792-82.1-82.347 0-13.142 3.04-25.456 8.414-36.376 7.79-15.832 4.286-34.898-8.623-46.926-51.655-48.127-114.754-84.193-184.82-103.628-18.33-5.084-37.706 3.444-46.337 20.396-13.648 26.806-41.357 44.97-73.184 44.97-31.827 0-59.536-18.164-73.184-44.97zM288.45 268.385c0-14.471-1.9-28.535-5.47-41.936 31.114-25.118 66.377-45.232 104.576-59.156 29.686 36.285 74.82 59.528 125.444 59.528 50.624 0 95.758-23.243 125.444-59.528 38.199 13.924 73.462 34.038 104.576 59.156a162.748 162.748 0 0 0-5.47 41.936c0 79.513 57.113 145.772 132.604 159.667 6.434 27.261 9.846 55.723 9.846 85.026 0 14.581-0.845 28.951-2.485 43.065-79.109 10.814-139.965 78.769-139.965 160.846 0 26.162 6.201 50.922 17.202 72.84-30.829 27.076-66.197 49.043-104.786 64.612-28.717-45.337-79.271-75.496-136.966-75.496-57.695 0-108.249 30.159-136.966 75.496-38.589-15.569-73.957-37.536-104.787-64.612 11.002-21.918 17.203-46.678 17.203-72.84 0-82.077-60.856-150.032-139.965-160.846A373.007 373.007 0 0 1 146 513.078c0-29.304 3.411-57.765 9.845-85.026 75.492-13.894 132.605-80.154 132.605-159.667zM513 336c-97.202 0-176 78.798-176 176s78.798 176 176 176 176-78.798 176-176-78.798-176-176-176zM409 512c0-57.438 46.562-104 104-104s104 46.562 104 104-46.562 104-104 104-104-46.562-104-104z"
                                        p-id="20886"></path>
                                </svg>
                                设置
                            </el-menu-item>

                        </el-menu>
                    </el-main>

                </el-container>
            </el-aside>

            <el-container>

                <!-- 主页面 -->
                <el-main>
                    Main
                </el-main>

            </el-container>
        </el-container>
    </div>
</template>

<style scoped>

.sidebar {
    height: 100vh;
    border-right: 1px solid var(--el-border-color);
}

.logo-title {
    display: flex;
    align-items: center;
    justify-content: start;
    height: 64px;
    border-bottom: 1px solid var(--el-border-color);
}

.logo {
    width: 36px;
    height: 36px;
    margin-right: 8px;
}

.title {
    font-size: 18px;
    font-weight: bold;
    color: #333;
}

.menu-area {
    padding: 0;
}

.custom-menu {
    border-right: none;
}

.custom-menu .el-menu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 15px;
    height: 56px;
    border-radius: 8px;
    margin-top: 8px;
    margin-bottom: 8px;
}

.icon {
    width: 30px;
    height: 30px;
    fill: currentColor;
}

</style>

23

6、编写主页面