1.下载依赖
"@element-plus/icons": "^0.0.11", "@element-plus/icons-vue": "^2.3.1", "@fortawesome/fontawesome-svg-core": "^6.7.2", "@fortawesome/free-solid-svg-icons": "^6.7.2", "@fortawesome/vue-fontawesome": "^3.0.8", "axios": "^1.7.9", "element-plus": "^2.9.3", "vue": "^3.5.13", "vue-router": "^4.5.0"
2.注册组件
import { createApp } from 'vue';
import App from './App.vue';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import './assets/css/global.css';
import zhCn from 'element-plus/es/locale/lang/zh-cn';
// 导入所有需要的图标组件
import * as Icons from '@element-plus/icons-vue';
import {router} from "./router/router.js";
// 创建 Vue 应用实例
const app = createApp(App);
// 使用路由
app.use(router);
// 使用 Element Plus,并设置语言为中文
app.use(ElementPlus, {
locale: zhCn,
});
// 动态注册所有图标组件
Object.keys(Icons).forEach(key => {
app.component(key, Icons[key]);
});
// 挂载应用到 #app 元素上
app.mount('#app');
3.编写登陆界面
<template> <div class="login-container"> <!-- 背景轮播图 --> <el-carousel :interval="5000" indicator-position="none" class="background-carousel" height="100vh"> <el-carousel-item v-for="(image, index) in backgroundImages" :key="index"> <div class="carousel-image" :style="{ backgroundImage: `url(${image})` }"></div> </el-carousel-item> </el-carousel> <!-- 登录框 --> <div class="login-box"> <div class="title-container"> <h3 class="title">实验室信息管理系统</h3> </div> <el-form ref="formRef" :model="form" :rules="rules" class="login-form"> <el-form-item prop="number"> <el-input v-model="form.number" placeholder="请输入学工号" prefix-icon="User"></el-input> </el-form-item> <el-form-item prop="password"> <el-input v-model="form.password" placeholder="请输入密码" show-password prefix-icon="Lock"></el-input> </el-form-item> <div class="button-group"> <el-button type="primary" @click="handleLogin" class="login-btn">登 录</el-button> <el-button type="success" @click="goRegister" class="register-btn">注 册</el-button> </div> </el-form> </div> </div> </template> <script setup> import { ref, reactive } from 'vue'; import { ElMessage } from 'element-plus'; import { useRouter } from 'vue-router'; // 创建路由实例 const router = useRouter(); // 表单引用 const formRef = ref(null); // 表单数据 const form = reactive({ number: '', password: '' }); // 表单规则 const rules = reactive({ number: [ { required: true, message: '请输入学号/学工号', trigger: 'blur' } ], password: [ { required: true, message: '请输入密码', trigger: 'blur' } ] }); // 背景图片数组 const backgroundImages = [ new URL('https://pic.meitukk.com/uploads/meitukk/dm/20230621/230621120150827.jpg').href, new URL('https://pic.meitukk.com/uploads/meitukk/dm/20230622/230622045223599.jpg').href, new URL('https://img.shetu66.com/2022/10/28/1666928035720956.jpg').href, new URL('https://n.sinaimg.cn/sinacn10116/600/w1920h1080/20190326/2c30-hutwezf6832339.jpg').href, new URL('https://c-ssl.duitang.com/uploads/blog/202303/15/20230315122347_db706.jpg').href ]; // 登录方法 const handleLogin = () => { formRef.value.validate((valid) => { if (valid) { // 这里添加登录逻辑,例如调用API进行验证 console.log('submit!'); ElMessage.success('登录成功'); // 假设登录成功后跳转到主页 router.push('/'); } else { console.log('error submit!!'); return false; } }); }; // 注册方法 const goRegister = () => { // 这里添加注册逻辑,例如跳转到注册页面 router.push('/register'); }; </script></script> <style scoped> .login-container { width: 100vw; /* 使用视口宽度 */ height: 100vh; /* 使用视口高度 */ overflow: hidden; position: relative; display: flex; justify-content: center; align-items: center; } .background-carousel { position: absolute; top: 0; left: 0; width: 100%; height: 100%; /* 修改为全屏高度 */ z-index: -1; /* 确保轮播图在最底层 */ overflow: hidden; } .carousel-image { width: 100%; height: 100%; background-size: cover; background-position: center; /* 确保背景图片居中 */ background-repeat: no-repeat; } .login-box { width: 400px; padding: 40px; background-color: rgba(255, 255, 255, 0.8); border-radius: 10px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); text-align: center; position: relative; z-index: 1; /* 确保登录框在轮播图之上 */ } .title-container { margin-bottom: 30px; } .title { color: #2c3e50; font-size: 26px; font-weight: bold; } .login-form { padding: 0 30px; } .button-group { display: flex; justify-content: space-between; } .login-btn, .register-btn { width: 48%; margin-top: 15px; } </style>
-
实现效果

4.编写注册页面
<template> <div class="register-container"> <!-- 背景轮播图 --> <transition name="fade" mode="out-in"> <el-carousel v-if="carouselLoaded" :interval="5000" indicator-position="none" class="background-carousel" height="100vh"> <el-carousel-item v-for="(image, index) in backgroundImages" :key="index"> <div class="carousel-image" :style="{ backgroundImage: `url(${image})` }"></div> </el-carousel-item> </el-carousel> </transition> <!-- 注册框 --> <div class="register-box"> <div class="title-container"> <h3 class="title">欢迎注册</h3> </div> <el-form ref="formRef" :model="form" :rules="rules" class="register-form" @submit.prevent> <el-form-item prop="number"> <el-input v-model="form.number" placeholder="请输入学工号"></el-input> </el-form-item> <el-form-item prop="nickname"> <el-input v-model="form.nickname" placeholder="请输入姓名"></el-input> </el-form-item> <el-form-item prop="password"> <el-input v-model="form.password" placeholder="请输入密码" show-password></el-input> </el-form-item> <el-form-item prop="confirm"> <el-input v-model="form.confirm" placeholder="请再次输入密码" show-password></el-input> </el-form-item> <div class="button-group"> <el-button type="primary" @click="handleRegister" class="register-btn">注 册</el-button> <el-button type="success" @click="goLogin" class="login-btn">登 录</el-button> </div> </el-form> </div> </div> </template><script setup> import {onMounted, reactive, ref} from 'vue'; import {useRouter} from 'vue-router'; import {ElMessage} from 'element-plus'; import axios from 'axios'; // 创建路由实例 const router = useRouter(); // 表单引用 const formRef = ref(null); // 表单数据 const form = reactive({ number: '', nickname: '', password: '', confirm: '' }); // 表单规则 const rules = reactive({ number: [ { required: true, message: '请输入学工号', trigger: 'blur' } ], nickname: [ { required: true, message: '请输入姓名', trigger: 'blur' } ], password: [ { required: true, message: '请输入密码', trigger: 'blur' } ], confirm: [ { required: true, message: '请确认密码', trigger: 'blur' } ] }); // 背景图片加载状态 const carouselLoaded = ref(false); const backgroundImages = ref([]); onMounted(async () => { try { // 使用相对路径引入图片 // 直接将图片路径赋值给 backgroundImages backgroundImages.value = [ new URL('https://pic.meitukk.com/uploads/meitukk/dm/20230621/230621120150827.jpg').href, new URL('https://pic.meitukk.com/uploads/meitukk/dm/20230622/230622045223599.jpg').href, new URL('https://img.shetu66.com/2022/10/28/1666928035720956.jpg').href, new URL('https://n.sinaimg.cn/sinacn10116/600/w1920h1080/20190326/2c30-hutwezf6832339.jpg').href, new URL('https://c-ssl.duitang.com/uploads/blog/202303/15/20230315122347_db706.jpg').href ]; carouselLoaded.value = true; } catch (error) { console.error('Failed to load images:', error); } }); // 注册方法 const handleRegister = () => { if (form.password !== form.confirm) { ElMessage({ type: 'error', message: '密码不一致' }); return; } formRef.value.validate((valid) => { if (valid) { axios.post('http://localhost:9090/user/register', form) .then(res => { if (res.data.code === '0') { ElMessage({ type: 'success', message: '注册成功' }); router.push('/login'); } else { ElMessage({ type: 'error', message: res.data.msg }); } }) .catch(error => { console.error('There was an error!', error); ElMessage({ type: 'error', message: '服务器错误,请稍后再试' }); }); } }); }; // 登录方法 const goLogin = () => { router.push('/login'); }; </script><style scoped> .register-container { width: 100vw; /* 使用视口宽度 */ height: 100vh; /* 使用视口高度 */ overflow: hidden; position: relative; display: flex; justify-content: center; align-items: center; } .background-carousel { position: absolute; top: 0; left: 0; width: 100%; height: 100%; /* 修改为全屏高度 */ z-index: -1; /* 确保轮播图在最底层 */ overflow: hidden; } .carousel-image { width: 100%; height: 100%; background-size: cover; background-position: center; /* 确保背景图片居中 */ background-repeat: no-repeat; transition: opacity 0.5s ease; } .register-box { width: 400px; padding: 40px; background-color: rgba(255, 255, 255, 0.8); border-radius: 10px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); text-align: center; position: relative; z-index: 1; /* 确保注册框在轮播图之上 */ } .title-container { margin-bottom: 30px; } .title { color: #2c3e50; font-size: 30px; font-weight: bold; } .register-form { padding: 0 30px; } .button-group { display: flex; justify-content: space-between; margin-top: 20px; } .register-btn, .login-btn { width: 48%; } /* 隐藏前缀图标 */ .el-input__prefix { display: none; } </style>
-
实现效果

5.编写主页面
-
主界面父组件
<script setup> import Header from "../components/Header.vue"; import Aside from "../components/Aside.vue"; </script> <template> <div> <!-- 头部 --> <Header /> <!-- 主体 --> <div style="display: flex"> <!-- 侧边栏 --> <Aside /> <!-- 内容区域 --> <router-view style="flex: 1"/> </div> </div> </template> <style scoped> </style>
-
子组件侧边栏
<template>
<div class="aside-container">
<el-menu default-active="1-1" class="el-menu-vertical-demo" :collapse="isCollapsed" @open="handleOpen" @close="handleClose">
<!-- 个人中心 -->
<el-sub-menu index="1-1">
<template #title>
<el-icon><User /></el-icon>
<span>个人中心</span>
</template>
<el-menu-item index="1-1-1">
<el-icon><HomeFilled /></el-icon>
<span>信息维护</span>
</el-menu-item>
</el-sub-menu>
<!-- 系统管理 -->
<el-sub-menu index="1-2">
<template #title>
<el-icon><Setting /></el-icon>
<span>系统管理</span>
</template>
<el-menu-item index="1-2-1">
<el-icon><VideoCamera /></el-icon>
<span>设备管理</span>
</el-menu-item>
<el-menu-item index="1-2-2">
<el-icon><Mic /></el-icon>
<span>学生管理</span>
</el-menu-item>
<el-menu-item index="1-2-3">
<el-icon><IceTea /></el-icon>
<span>实验室管理</span>
</el-menu-item>
</el-sub-menu>
<!-- 记录查询 -->
<el-sub-menu index="1-3">
<template #title>
<el-icon><MessageBox /></el-icon>
<span>记录查询</span>
</template>
<el-menu-item index="1-3-1">
<el-icon><Document /></el-icon>
<span>设备申请记录</span>
</el-menu-item>
<el-menu-item index="1-3-2">
<el-icon><DeleteFilled /></el-icon>
<span>设备报废记录</span>
</el-menu-item>
<el-menu-item index="1-3-3">
<el-icon><TrendCharts /></el-icon>
<span>设备借出记录</span>
</el-menu-item>
<el-menu-item index="1-3-4">
<el-icon><Calendar /></el-icon>
<span>实验室预约记录</span>
</el-menu-item>
</el-sub-menu>
<!-- 设备相关申请 -->
<el-sub-menu index="1-4">
<template #title>
<el-icon><SetUp /></el-icon>
<span>设备相关申请</span>
</template>
<el-menu-item index="1-4-1">
<el-icon><Delete /></el-icon>
<span>设备报废申请</span>
</el-menu-item>
<el-menu-item index="1-4-2">
<el-icon><Tickets /></el-icon>
<span>设备使用申请</span>
</el-menu-item>
<el-menu-item index="1-4-3">
<el-icon><CircleCheckFilled /></el-icon>
<span>设备归还申请</span>
</el-menu-item>
</el-sub-menu>
<!-- 实验室相关申请 -->
<el-sub-menu index="1-5">
<template #title>
<el-icon><Plus /></el-icon>
<span>实验室相关申请</span>
</template>
<el-menu-item index="1-5-1" >
<el-icon><Ticket /></el-icon>
<span>预约实验室</span>
</el-menu-item>
<el-menu-item index="1-5-2">
<el-icon><CircleCloseFilled /></el-icon>
<span>归还实验室</span>
</el-menu-item>
</el-sub-menu>
<!-- 审批进度 -->
<el-sub-menu index="1-6">
<template #title>
<el-icon><Check /></el-icon>
<span>审批进度</span>
</template>
<el-menu-item index="1-6-1">
<el-icon><InfoFilled /></el-icon>
<span>设备申请审批</span>
</el-menu-item>
<el-menu-item index="1-6-2">
<el-icon><DeleteFilled /></el-icon>
<span>设备报废审批</span>
</el-menu-item>
<el-menu-item index="1-6-3">
<el-icon><Ticket /></el-icon>
<span>实验室预约审批</span>
</el-menu-item>
</el-sub-menu>
<!-- 数据可视化 -->
<el-sub-menu index="1-8">
<template #title>
<el-icon><PieChart /></el-icon> 设备数据可视化
</template>
<el-menu-item index="1-8-1">
<el-icon><DataAnalysis /></el-icon> 设备数据可视化
</el-menu-item>
</el-sub-menu>
</el-menu>
</div>
</template>
<script setup>
import { ref } from 'vue';
import {
Setting,
User,
HomeFilled,
VideoCamera,
Mic,
IceTea,
MessageBox,
Document,
DeleteFilled,
TrendCharts,
Calendar,
SetUp,
Delete,
Tickets,
CircleCheckFilled,
Plus,
Ticket,
CircleCloseFilled,
Check,
InfoFilled
} from '@element-plus/icons-vue';
// 控制菜单折叠状态
const isCollapsed = ref(false);
// 处理子菜单打开事件
const handleOpen = (key, keyPath) => {
console.log('opened sub menu:', key, keyPath);
};
// 处理子菜单关闭事件
const handleClose = (key, keyPath) => {
console.log('closed sub menu:', key, keyPath);
};
</script>
<style scoped>
.aside-container {
width: 200px;
transition: width 0.3s ease;
}
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
.el-menu {
border-right: none;
}
.el-menu-item [class^=el-icon-]+span {
margin-left: 8px;
}
.menu-item-group-title {
padding: 8px 20px;
color: #a8abb2;
font-size: 12px;
line-height: 24px;
background-color: #f5f7fa;
}
.el-menu-item.is-active {
background-color: #ecf5ff;
color: #409eff;
}
.el-sub-menu__title:hover,
.el-menu-item:hover {
background-color: #eef1f6 !important;
}
@media (max-width: 768px) {
.aside-container {
width: 64px;
}
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 64px;
}
.el-sub-menu__title span,
.el-menu-item span {
display: none;
}
.el-sub-menu__icon-arrow {
display: none;
}
}
</style>
-
子组件头部导航栏
<template>
<header class="app-header">
<div class="header-content">
<div class="logo">实验室信息管理系统</div>
<div class="user-action">
<el-dropdown trigger="click" @command="handleCommand">
<span class="el-dropdown-link user-profile" @click.stop>
<el-avatar :size="30" :src="defaultAvatar" style="vertical-align: middle;"></el-avatar>
<span class="username">{{ username }}</span>
<el-icon class="el-icon--right"><arrow-down /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="changePassword">修改密码</el-dropdown-item>
<el-dropdown-item command="logout">退出系统</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<!-- 修改密码对话框 -->
<el-dialog
title="修改密码"
v-model="dialogVisible"
width="400px"
center
@close="resetForm"
>
<el-form ref="passwordForm" :model="form" :rules="rules" label-width="100px">
<el-form-item label="旧密码" prop="oldPassword">
<el-input v-model="form.oldPassword" type="password"></el-input>
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input v-model="form.newPassword" type="password"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword">
<el-input v-model="form.confirmPassword" type="password"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitForm('passwordForm')">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</div>
</header>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { ArrowDown } from '@element-plus/icons-vue';
// 假定用户名称和默认头像链接
const username = ref('张三');
const defaultAvatar = ref('https://pic.meitukk.com/uploads/meitukk/dm/20230621/230621120150827.jpg');
// 对话框可见性控制
const dialogVisible = ref(false);
// 表单数据和验证规则
const form = reactive({
oldPassword: '',
newPassword: '',
confirmPassword: ''
});
const rules = {
oldPassword: [{ required: true, message: '请输入旧密码', trigger: 'blur' }],
newPassword: [{ required: true, message: '请输入新密码', trigger: 'blur' }],
confirmPassword: [
{ required: true, message: '请再次输入新密码', trigger: 'blur' },
({ value }, callback) => {
if (value !== form.newPassword) {
callback(new Error('两次输入的密码不一致'));
} else {
callback();
}
}
]
};
// 提交表单的方法
const submitForm = (formName) => {
// 这里可以添加提交逻辑,例如发送请求到服务器等
console.log('Submit:', form);
dialogVisible.value = false;
};
// 重置表单的方法
const resetForm = () => {
form.oldPassword = '';
form.newPassword = '';
form.confirmPassword = '';
};
// 下拉菜单命令处理
const handleCommand = (command) => {
if (command === 'changePassword') {
dialogVisible.value = true;
} else if (command === 'logout') {
// 处理登出逻辑
console.log('Logout');
}
};
</script>
<style scoped>
.app-header {
height: 60px;
line-height: 60px;
background-color: #304156;
color: #F8F8FF;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.header-content {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.logo {
font-weight: bold;
font-size: 18px;
}
.user-action {
display: flex;
align-items: center;
}
.user-profile {
cursor: pointer;
display: flex;
align-items: center;
color: #F8F8FF;
}
.username {
margin-left: 8px;
}
.el-dropdown-link {
display: flex;
align-items: center;
}
@media (max-width: 768px) {
.logo {
font-size: 16px;
}
.user-action {
flex-direction: column;
align-items: flex-end;
}
.user-profile {
flex-direction: column;
align-items: flex-start;
}
.el-avatar {
margin-bottom: 5px;
}
}
/* 新增样式 */
.el-dropdown-menu__item {
text-align: left;
}
.dialog-footer {
text-align: right;
}
.el-dialog__header {
background-color: #f5f7fa;
padding: 16px 20px;
border-bottom: 1px solid #ebeef5;
}
.el-dialog__body {
padding: 20px;
}
.el-form-item {
margin-bottom: 18px;
}
.el-input__inner {
border-radius: 4px;
}
</style>
-
实现效果

6.编写路由
import { createRouter, createWebHistory } from 'vue-router'
import LayOut from "../layout/LayOut.vue";
import Login from "../views/Login.vue";
import Register from "../views/Register.vue";
export const router = createRouter({
history: createWebHistory(),
routes:[
{
path: '/',
name: 'Layout',
component: LayOut,
},
{
path:'/login',
name:'Login',
component:Login
},
{
path:'/register',
name:'Register',
component:Register
}
]
})
7.全局样式
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}



![人工智能之深度学习-[1]-了解深度学习](https://i-blog.csdnimg.cn/direct/4c0baf8fa1724cc6a7a25ae80a8fd13e.png)















