粤嵌实训医疗项目day02(Vue + SpringBoot)
目录
一、创建vue项目并运行
二、vue-cli中的路由使用
三、element-ui框架、实现页面布局以及vue-路由
四、前端登录页面
五、user登录后端接口完善【后端】
六、user登录前端-请求工具-请求发起【前端】
七、请求的跨域-访问策略
八、完善项目的页面布局、导航菜单以及权限划分
九、实现疫苗分类的查询及分析流程
十、疫苗分类--页面完善、以及添加、修改及删除实现
一、创建vue项目并运行
--使用管理员身份运行VSCode,然后在终端打开dos命令行界面
--设置国内的镜像
#经过下面的配置,以后所有的 npm install 都会经过淘宝的镜像地址下载
npm config set registry https://registry.npm.taobao.org
--安装vue-cli的插件\全局安装
npm install vue-cli -gnpm install -g @vue/cli-init 或者 npm install -g '@vue/cli-init'
--安装webpack的插件\全局安装
npm install -g webpack
注意:shell命令策略设置【当命令执行失败时操作、没有问题就不用管、继续下一步即可】
像这种都是策略问题,用管理员打开vscode,然后设置策略
get-ExecutionPolicy执行set-ExecutionPolicy RemoteSigned 然后 get-ExecutionPolicy,显示RemoteSigned就是ok了set-ExecutionPolicy RemoteSigned
--通过vue-cli脚手架来创建一个项目
vue init webpack vaccinum-vue
--切换到当前项目路径下、然后在启动vue项目测试【npm run dev】
cd vaccinum-vuenpm run dev
二、vue-cli中的路由使用
路由主要是实现页面跳转【实际上是请求地址映射vue页面】
--在components中创建两个vue页面文件
<template><div class="hello"><h2>Demo1111 Links</h2></div>
</template>
<template><div class="hello"><h2>Demo222 Links</h2></div>
</template>
--在router路由配置文件中配置页面的访问地址
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
export default new Router({routes: [{path: '/',name: 'HelloWorld',component: HelloWorld},{path: '/demo1',name: 'demo1',component: ()=>import('@/components/demo1')},{path: '/demo2',name: 'demo2',component: ()=>import('@/components/demo2')}]
})
--在App.vue中提供两个链接,然后测试
<!-- 两个链接 --><router-link to="/demo1">demo1</router-link><router-link to="/demo2">demo2</router-link><!-- 两个链接 -->
三、element-ui框架、实现页面布局以及vue-路由
--布局效果图
--element-ui网站【参考学习】
https://element.eleme.cn/#/zh-CN/component/installation
--ctrl+c 结束程序,然后执行命令下载element-ui依赖
--添加elementui依赖
--在vue项目目录下使用下面命令,添加ElementUI 依赖
npm i element-ui -S
--在src中的main.js中配置、导入element-ui组件及样式文件
// 导入ElementUI
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);//在vue使用ElementUI
--创建页面
--页面布局:在components下创建Layout.vue
<template><div><!-- 头部 --><Header /><!-- 主题 --><div style="display: flex"><!-- 主题-左边 --><Aside /><!-- 主题-右边 flex: 1 自适应布局 --><router-view style="flex: 1" /></div></div>
</template><!-- js --><script>
// 导入组件
import Header from "@/components/Header";
import Aside from "@/components/Aside";export default {name: "Layout",// 使用哪些组件components: {Aside,Header,},
};
</script>
--页面布局:在components下创建Header.vue文件
<template><divstyle="height: 50px;line-height: 50px;border-bottom: 1px solid #ccc;display: flex;"><divstyle="width: 200px;padding-left: 30px;font-weight: bold;color: dodgerblue;">管理系统</div><div style="flex: 1"></div><div style="width: 150px"><el-dropdown @command="handleCommand"><span class="el-dropdown-link"><el-avatarsrc="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"></el-avatar>admin<i class="el-icon-arrow-down el-icon--right"></i></span><el-dropdown-menu slot="dropdown"><el-dropdown-item command="a">个人信息</el-dropdown-item><el-dropdown-item command="b">退出系统</el-dropdown-item></el-dropdown-menu></el-dropdown></div></div>
</template><script>
import router from "@/router";export default {name: "Header",data() {return {name: "未登录",};},created() {},methods: {handleCommand(command) {},},
};
</script>
--页面布局:在components下创建Aside.vue文件
<template><div><el-menustyle="width: 250px; min-height: calc(100vh - 50px)"default-active="2"class="el-menu-vertical-demo"@open="handleOpen"@close="handleClose":default-openeds="[path]"router><el-submenu index="1"><template slot="title"><i class="el-icon-location"></i><span>导航一</span></template><el-menu-item-group><template slot="title">分组一</template><el-menu-item index="/list">选项1</el-menu-item><el-menu-item index="1-2">选项2</el-menu-item></el-menu-item-group><el-menu-item-group title="分组2"><el-menu-item index="1-3">选项3</el-menu-item></el-menu-item-group><el-submenu index="1-4"><template slot="title">选项4</template><el-menu-item index="1-4-1">选项1</el-menu-item></el-submenu></el-submenu><el-menu-item index="2"><i class="el-icon-menu"></i><span slot="title">导航二</span></el-menu-item><el-menu-item index="3" disabled><i class="el-icon-document"></i><span slot="title">导航三</span></el-menu-item><el-menu-item index="4"><i class="el-icon-setting"></i><span slot="title">导航四</span></el-menu-item></el-menu></div>
</template><script>
export default {data() {return {//path变量path: this.$route.path,};},methods: {handleOpen(key, keyPath) {console.log(key, keyPath);},handleClose(key, keyPath) {console.log(key, keyPath);},},
};
</script>
--把App.vue的图标注释掉
--路由:在router下index.js修改请求映射
import Vue from 'vue'
import Router from 'vue-router'
//导入局部的页面Layout
import Layout from '@/components/Layout'
Vue.use(Router)
export default new Router({routes: [// 也就是-- / 映射到了 Layout的页面{path: '/',name: 'Layout',component: Layout}]
})
--重新启动前端项目-访问即可
四、前端登录页面
--1、在components下创建Login.vue
<template><div class="login"><!-- 登录表单 v-model --><div class="login-form"><!-- :gutter="20" --><el-row :gutter="20"><el-col :span="12"><div><imgsrc="../assets/logo.png"alt=""style="position: relative;left: -100px;width: 250px;height: 85px;"/></div><div style="position: relative; left: 50px"><img src="../assets/icon-big.png" alt="" /></div></el-col><el-col :span="2"></el-col><el-col :span="10"><!-- 登录的form组件【提交的信息】 --><el-formref="loginForm":model="loginForm"style="margin-left: 150px; margin-top: 150px"><el-form-item><el-tabsv-model="roleType"@tab-click="selectRole":stretch="true"><el-tab-pane label="用户登录" name="用户"></el-tab-pane><el-tab-pane label="医生登录" name="医生"></el-tab-pane><el-tab-pane label="管理员登录" name="管理员"></el-tab-pane></el-tabs></el-form-item><el-form-item prop="name" v-if="roleType === '管理员'"><el-inputprefix-icon="el-icon-user"v-model="loginForm.name"type="text"placeholder="账号"></el-input></el-form-item><el-form-item prop="phone" v-if="roleType !== '管理员'"><el-inputprefix-icon="el-icon-user"v-model="loginForm.phone"type="text"placeholder="账号"></el-input></el-form-item><el-form-item prop="password"><el-inputprefix-icon="el-icon-lock"v-model="loginForm.password"autocomplete="off"show-passwordplaceholder="密码"></el-input></el-form-item><el-form-item prop="code" v-if="captchaEnabled"><el-inputv-model="loginForm.code"placeholder="请输入验证码"style="width: 63%"></el-input><div class="login-code"><el-avatarshape="square"style="width: 100px":src="codeUrl"></el-avatar></div></el-form-item><el-form-item style="width: 100%"><el-buttonsize="medium"type="primary"style="width: 100%; background-color: rgb(77, 167, 252)"@click="doLogin()"><span style="font-size: 20px">登 录</span></el-button></el-form-item><el-form-item style="width: 100%"><el-buttonsize="medium"type="primary"style="width: 100%; background-color: rgb(77, 167, 252)"v-if="roleType == '用户'"@click="registerFormVisible = true"><span style="font-size: 20px">注 册</span></el-button></el-form-item></el-form><!-- 登录的form组件【提交的信息】 --></el-col></el-row></div><!-- 用户注册表单 --><el-dialogtitle="用户注册":visible.sync="registerFormVisible":close-on-click-modal="false"><el-formlabel-position="top":model="registerForm"status-iconref="registerForm"label-width="100px"class="demo-registerForm"><!-- 头像 --><el-form-item label="头像" prop="image"><el-uploadclass="avatar-uploader"action="http://localhost:80/vaccinum/common/upload":show-file-list="false":on-success="handleAvatarSuccess":before-upload="beforeAvatarUpload"><img v-if="imageUrl" :src="imageUrl" class="avatar" /><i v-else class="el-icon-plus avatar-uploader-icon"></i></el-upload><!-- 隐藏输入字段,用来存储图片的文件名 --><input type="hidden" name="avatar" v-model="registerForm.image" /></el-form-item><!-- 用户名\性别 --><el-row :gutter="20"><el-col :span="12"><el-form-item label="用户名" prop="name"><el-inputtype="text"v-model="registerForm.name"autocomplete="off"></el-input></el-form-item></el-col><el-col :span="12"><el-form-item label="性别" prop="sex"><el-inputtype="text"v-model="registerForm.sex"autocomplete="off"></el-input></el-form-item></el-col></el-row><!-- 年龄\身份证号 --><el-row :gutter="20"><el-col :span="12"><el-form-item label="年龄" prop="age"><el-inputtype="text"v-model="registerForm.age"autocomplete="off"></el-input></el-form-item></el-col><el-col :span="12"><el-form-item label="身份证号" prop="codeid"><el-inputtype="text"v-model="registerForm.codeid"autocomplete="off"></el-input></el-form-item></el-col></el-row><!-- 密码\密码 --><el-row :gutter="20"><el-col :span="12"><el-form-item label="密 码" prop="password"><el-inputtype="password"v-model="registerForm.password"autocomplete="off"></el-input></el-form-item></el-col><el-col :span="12"><el-form-item label="确认密码" prop="password_check"><el-inputtype="password"v-model="registerForm.password_check"autocomplete="off"></el-input></el-form-item></el-col></el-row><!-- 手机号\地址 --><el-row :gutter="20"><el-col :span="12"><el-form-item label="手机号" prop="phone"><el-inputtype="text"v-model="registerForm.phone"autocomplete="off"></el-input></el-form-item></el-col><el-col :span="12"><el-form-item label="地址" prop="address"><el-inputtype="text"v-model="registerForm.address"autocomplete="off"></el-input></el-form-item></el-col></el-row><el-form-item><el-button type="primary" @click="registerSumbit">提交</el-button><el-button@click="registerFormVisible = false;this.registerForm = {name: '',password: '',password_check: '',phone: '',};">取消</el-button></el-form-item></el-form></el-dialog><!-- 用户注册表单 --><!-- 底部 --><div class="el-login-footer"><span>Copyright © 2018-2022 gec All Rights Reserved.</span></div><!-- 底部 --></div>
</template><script>
import router from "@/router";
export default {name: "Login",data() {return {password_type: "password", //密码显示类型imageUrl: "", //头像上传路径codeUrl: "",loginForm: {//登录的表单数据name: "12345678909",phone: "12345678909",password: "123",code: "",},registerForm: {//注册的表单数据name: "",sex: "",age: "",password: "",password_check: "",image: "",codeid: "",phone: "",address: "",},loading: false,captchaEnabled: true,register: true,registerFormVisible: false,roleType: "用户",};},created() {},methods: {//修改密码显示类型cho() {this.password_type = this.password_type == "text" ? "password" : "text";}, //选择哪个用户类型就显示那个类型selectRole() {console.log(this.roleType); // this.roleType = command;},//登录的处理函数doLogin() {if (this.loginForm.phone=="12345678909"&&this.loginForm.password=="123") {this.$message.success("登录成功!"); //跳转到Layout页面【首页】router.push("/Layout");} else {//登录失败提示信息this.$message.error("登录失败!");}}, //注册函数registerSumbit() {//发起了异步请求request.post("register", this.registerForm) //回调函数.then((res) => {if (res.flag == true) {this.$message.success("注册成功!");this.registerFormVisible = false;this.registerForm = {name: "",sex: "",age: "",password: "",password_check: "",image: "",codeid: "",phone: "",address: "",};this.imageUrl = "";} else {//注册失败提示信息this.$message.error(res.message);}});}, //在上传成功后处理函数中,获取服务端返回的图片文件名或URLhandleAvatarSuccess(res, file) {this.registerForm.image = res.fileName;this.imageUrl = URL.createObjectURL(file.raw);}, // 在上传之前,清空旧图片信息beforeAvatarUpload(file) {this.registerForm.image = "";this.imageUrl = "";const isJPG = file.type === "image/jpeg";const isLt2M = file.size / 1024 / 1024 < 2;if (!isJPG) {this.$message.error("上传头像图片只能是 JPG 格式!");}if (!isLt2M) {this.$message.error("上传头像图片大小不能超过 2MB!");}return isJPG && isLt2M;},},
};
</script><style>
.el-dialog {border-radius: 45px;
}
.login {position: absolute;width: 100%;height: 100%;overflow: hidden;background-image: url("../assets/1.png");background-size: 100% 100%;background-repeat: no-repeat;
}
.title {margin: 0px auto 30px auto;text-align: center;color: #707070;
}
.login-form {margin: 150px auto;background-image: url("../assets/beijing.png");border-radius: 45px;background-position: -35px, -35px;width: 1240px;height: 657px;/* padding: 25px 25px 5px 25px; */
}
.el-input {height: 38px;
}
input {height: 38px;
}
.input-icon {height: 39px;width: 14px;margin-left: 2px;
}
.login-tip {font-size: 13px;text-align: center;color: #bfbfbf;
}
.login-code {width: 33%;height: 38px;float: right;
}
.el-login-footer {height: 40px;line-height: 40px;position: fixed;bottom: 0;width: 100%;text-align: center;/* color: #fff; */font-family: Arial;font-size: 12px;letter-spacing: 1px;
}
.login-code-img {height: 38px;
}
.avatar-uploader .el-upload {/* border: 1px dashed #d9d9d9; */border: 1px solid black;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;
}
.avatar-uploader .el-upload:hover {border-color: #409eff;
}
.avatar-uploader-icon {font-size: 28px;color: #8c939d;width: 178px;height: 178px;line-height: 178px;text-align: center;
}
.avatar {width: 178px;height: 178px;display: block;
}
</style>
--2、在路由index.js中配置根目录访问登录页面、然后修改首页的
import Vue from 'vue'
import Router from 'vue-router'
//导入局部的页面Layout
import Layout from '@/components/Layout'
import Login from '@/components/Login'
Vue.use(Router)
export default new Router({routes: [// 也就是-- / 映射到了 Login的页面{path: '/',name: 'Login', component: Login},{path: '/Layout',name: 'Layout', component: Layout}]
})
--3、替换src中的assets文件中的图片
五、user登录后端接口完善【后端】
--1、在UserController中提供登录的处理方法、接收数据,响应json格式的数据
//json 的解析工具
ObjectMapper jsonTool = new ObjectMapper();// http://localhost:8085/user/loginUser?phone=sdfsdf&password=xxxx
// 定义user的登录查询的请求接口【根据手机号码和密码进行登录】
@RequestMapping("/loginUser")
public String loginUser(String phone,String password) throws JsonProcessingException {// map集合-结果集HashMap result =new HashMap();//調用业务层的查询方法,根据手机号码和密码进行查询QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("phone",phone).eq("password",password);//条件查询,获取一个对象User user = userService.getOne(wrapper);//业务逻辑的判断if(user!=null){//登录成功result.put("flag",true);result.put("user",user);result.put("role","user");}else{//登录失败result.put("flag",false);result.put("message","用戶名或密碼錯誤!!!");}//返回json格式的数据return jsonTool.writeValueAsString(result);
}
--2、启动项目然后测试
http://localhost:8085/user/loginUser?phone=123451645602&password=123sdfsdfsdfsd
六、user登录前端-请求工具-请求发起【前端】
--结束前端程序ctrl+c
--执行命令、安装axios和cookie依赖
npm install axios --save
npm install --save js-cookie
--在src下创建utils文件夹、并创建request.js文件
import axios from 'axios'
import router from "@/router";
import qs from "qs"
import Cookies from "js-cookie";
axios.defaults.withCredentials=true //让ajax请求携带cookie
//1、目的是封装请求对象 2、目的对请求和响应数据进行格式
// 创建对象
const request = axios.create({baseURL: 'http://localhost:8085', // 注意!! 这里是全局统一加上了 baseURL 前缀,timeout: 5000
})// request 拦截器
request.interceptors.request.use(config => {//对请求的数据进行处理if (config.method != 'get') {config.data = qs.stringify(config.data);}// post请求方式的content格式config.headers['content-Type'] = 'application/x-www-form-urlencoded';//允许通过访问return config;},error => {console.log('err' + error) // for debugreturn Promise.reject(error)}
)// response 拦截器
// 可以在接口响应后统一处理结果
request.interceptors.response.use(response => {let res = response.data;// 如果是返回的文件if (response.config.responseType === 'blob') {return res}// 兼容服务端返回的字符串数据if (typeof res === 'string') {res = res ? JSON.parse(res) : res}return res;},error => {console.log('err' + error) // for debugreturn Promise.reject(error)}
)export default request
--修改Login.vue中的登录请求处理函数、发起异步请求
//注意导入请求工具类和cookie
import Cookies from "js-cookie";
import request from "@/utils/request.js";
doLogin() {//通过请求对象发起一个异步请求操作【axios】request.post("/user/loginUser", this.loginForm) //第一个参数是请求地址、第二个参数提交的数据 //回调函数\获取服务器响应的结果.then((res) => {//如果成功flagif (res.flag == true) {this.$message.success("登录成功!"); //把user信息、角色信息存放在cookie中Cookies.set("user", JSON.stringify(res.user), { expires: 0.3 });Cookies.set("role", res.role, { expires: 0.3 }); //通过路由跳转、登录成功后跳转到首页router.push("/Layout");} else {//登录失败提示信息this.$message.error(res.message);}});},
--点击登录按钮进行测试、请求是成功发起的,但是发现跨域拦截:
七、请求的跨域-访问策略
--后端项目中创建config包,然后创建配置类提供跨域访问策略:
import org.springframework.stereotype.Component;import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;//定义拦截器允许跨域访问
@Component
public class UrlCorsConfiguration implements Filter {public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException {HttpServletResponse response = (HttpServletResponse) res;// 允许跨域访问的地址【前端项目部署的地址】response.setHeader("Access-Control-Allow-Origin", "http://localhost:8080");//允许跨域的请求方法GET, POST, HEAD 等response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");//重新预检验跨域的缓存时间 (s)response.setHeader("Access-Control-Max-Age", "3600");//允许跨域的请求头response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type");//是否携带cookieresponse.setHeader("Access-Control-Allow-Credentials", "true");// 设置响应的类型及字符集编码response.setContentType("text/json;charset=utf-8");//设置响应的中文编码chain.doFilter(req, res);}public void init(FilterConfig filterConfig) {}public void destroy() {}}
--重启后端项目,然后发起请求查看
八、完善项目的页面布局、导航菜单以及权限划分
--替换Aside.vue后端项目
<template><div><el-menustyle="width: 250px; min-height: calc(100vh - 50px);padding-top: 10px;"default-active="2"class="el-menu-vertical-demo"@open="handleOpen"@close="handleClose":default-openeds="[path]"router><el-submenu index="1" v-if="role == 'manager'"><template slot="title"><i class="el-icon-s-management"></i><!-- font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;" --><span style="font-size: 17px; font-weight: bold;font-family:'苹方'">管理员模块</span></template><el-menu-item-group><el-menu-item index="/Layout/adminList"><i class="el-icon-link"></i>管理员列表</el-menu-item></el-menu-item-group></el-submenu><el-submenu index="2"><template slot="title"><i class="el-icon-first-aid-kit"></i><span style="font-size: 17px; font-weight: bold;font-family:'苹方'">医生模块</span></template><el-menu-item-group><!-- <i class="icon_line"></i> --><el-menu-item index="/Layout/doctorList"><i class="el-icon-link"></i> 医生列表</el-menu-item><el-menu-itemindex="/Layout/registration"v-if="role == 'manager' || role == 'doctor' || role == 'user'"><i class="el-icon-link"></i>挂号记录</el-menu-item><el-menu-item index="/Layout/vaccineRecord" v-if="role != 'doctor'"><i class="el-icon-link"></i>接种记录</el-menu-item></el-menu-item-group></el-submenu><el-submenu index="3" v-if="role == 'manager' || role == 'user'"><template slot="title"><i class="el-icon-user"></i><span style="font-size: 17px; font-weight: bold;font-family:'苹方'">用户模块</span></template><el-menu-item-group><el-menu-item index="/Layout/userList" v-if="role == 'manager'"><i class="el-icon-link"></i>用户列表</el-menu-item><el-menu-item index="/Layout/userRegis" v-if="role == 'user'"><i class="el-icon-link"></i>预约挂号</el-menu-item></el-menu-item-group></el-submenu><el-submenu index="4"><template slot="title"><i class="el-icon-office-building"></i><span style="font-size: 17px; font-weight: bold;font-family:'苹方'">医院模块</span></template><el-menu-item-group><el-menu-item index="/Layout/hosList"><i class="el-icon-link"></i>医院列表</el-menu-item><el-menu-item index="/Layout/deptList"><i class="el-icon-link"></i>科室列表</el-menu-item></el-menu-item-group></el-submenu><el-submenu index="5"><template slot="title"><i class="el-icon-office-building"></i><span style="font-size: 17px; font-weight: bold;font-family:'苹方'">疫苗模块</span></template><el-menu-item-group><el-menu-item index="/Layout/vaccineType"><i class="el-icon-link"></i>疫苗种类</el-menu-item><el-menu-item index="/Layout/vaccine"><i class="el-icon-link"></i>疫苗信息</el-menu-item><el-menu-item index="/Layout/appVaccineList"><i class="el-icon-link"></i>可预约疫苗</el-menu-item></el-menu-item-group></el-submenu></el-menu></div>
</template>
<style>
.icon1 {display: inline-block;width: 50px;height: 50px;background-image: url("../assets/BUTTON_NOOPEN.png");background-position: center center;background-repeat: no-repeat;
}
.icon_line {display: block;width: 20px;height: 20px;background-image: url("../assets/line1.png");position: relative;left: 75px;background-repeat: no-repeat;
}
</style><script>
import Cookies from "js-cookie";
import request from "@/utils/request";
export default {data() {return {//path变量path: this.$route.path,role: "",userId: "",timer: null,};},//生命周期【当页面对象创建成功,触发的函数】created() {//获取manager信息var userJson = JSON.parse(Cookies.get("user"));this.role = Cookies.get("role");console.log("this.role="+this.role);this.userId = userJson.id;// 启动定时器,每5秒钟检查一次this.timer = setInterval(this.checkDatabaseChanges, 5000);},methods: {//获取数据库最新数据,持续更新cookiecheckDatabaseChanges() {//判断是哪种用户let url =this.role == "manager"? "/manager/selectById": this.role == "doctor"? "/doctor/selectById": "/user/selectById";// 通过请求获取最新的数据request.get(url, {params: {id: this.userId,},})//回调函数.then((res) => {if (res.flag == true) {//更新Cookie值Cookies.set("user", JSON.stringify(res.user), { expires: 0.3 });}});},handleOpen(key, keyPath) {console.log(key, keyPath);console.log("打开");},handleClose(key, keyPath) {console.log(key, keyPath);console.log("关闭");},},beforeDestroy() {// 销毁定时器clearInterval(this.timer);},
};
</script>
--替换Header.vue
<template><divstyle="height: 65px;line-height: 65px;border-bottom: 1px solid #ccc;background-color: #254175;display: flex;"><divstyle="width: 200px;padding-left: 30px;font-weight: bold;color: dodgerblue;"><imgsrc="../assets/logo-06.png"style="width: 200px; height: 50px; padding-top: 5px"alt=""/></div><div style="flex: 1"></div><div style="width: 250px"><el-dropdown @command="handleCommand"><span class="el-dropdown-link"><el-row :gutter="5"><el-col :span="12" style="padding-top: 9px;"><el-avatar :src="image" shape="square" :size="50"></el-avatar></el-col><el-col :span="9" style="color:#fff;font-weight: bold;">{{ name }}</el-col><el-col :span="3" style="color:#fff;font-weight: bold;"><i class="el-icon-arrow-down el-icon--right"></i></el-col></el-row></span><el-dropdown-menu slot="dropdown"><el-dropdown-item command="a" v-if="role !== 'manager'">个人信息</el-dropdown-item><el-dropdown-item command="b">退出系统</el-dropdown-item></el-dropdown-menu></el-dropdown></div></div>
</template><script>
import router from "@/router";
import Cookies from "js-cookie";
export default {name: "Header",data() {return {name: "未登录",image: "",role: "",};},created() {//获取登录用户信息var userJson = JSON.parse(Cookies.get("user"));this.name = userJson.name;this.image = userJson.image;this.role = Cookies.get("role");},methods: {handleCommand(command) {if (command == "b") {Cookies.remove("user");//跳转到登录router.push("/login");} else {//跳转到个人信息router.push("/Layout/personalInfo");}},},
};
</script>
--修改后端UserController中-的登录请求要返回user的对象数据、用户的角色
// 在结果集中保存user对象以及角色信息
result.put("user", user);
result.put("role", "user");
--登录页面的登录函数中存储user和role角色信息
--重新登录测试即可
九、实现疫苗分类的查询及分析流程
--后端:VaccineType实体类中添加主键变量
/*** 主键*/
@TableId(type = IdType.AUTO)
private Integer id;
--后端:VaccineTypeController中定义查询请求接口
@RestController
@RequestMapping("/vaccinetype")
public class VaccineTypeController {//jsonObjectMapper json = new ObjectMapper();//service@AutowiredIVaccineTypeService typeService;// 测试 http://localhost:8085/vaccinetype/query//查询分类、响应json数据【键值对的数据】@RequestMapping("/query")public String query() throws JsonProcessingException {//结果的存放集合HashMap result = new HashMap();// 1\调用业务层方法执行查询操作List<VaccineType> list = typeService.list();// 2\在结果集中存放list集合result.put("list", list);// 返回json数据return json.writeValueAsString(result);}}
--前端:在src下创建type文件夹,然后创建TypeList.vue
--前端:从element-ui中获取组件代码、提供请求操作和修改table中的字段名
<template><el-table :data="tableData" stripe style="width: 100%"><el-table-column prop="id" label="编号"> </el-table-column><el-table-column prop="name" label="名称"> </el-table-column><el-table-column prop="remark" label="描述"> </el-table-column></el-table>
</template><script>
import request from "@/utils/request.js";
export default {data() {return {tableData: [],};},// 页面中的vue对象创建成功后触发created() {//发起查询请求request.get("/vaccinetype/query") //第一个参数是请求地址、第二个参数提交的数据 //回调函数\获取服务器响应的结果.then((res) => {this.tableData = res.list;});},
};
</script>
--前端:修改路由、在Layout路径下配置子url的映射【router中的index.js文件】
import Vue from 'vue'
import Router from 'vue-router'
//导入局部的页面Layout
import Layout from '@/components/Layout'
import Login from '@/components/Login'
Vue.use(Router)
export default new Router({routes: [// 也就是-- / 映射到了 Login的页面{path: '/',name: 'Login',component: Login},// 页面布局的映射{path: '/Layout',name: 'Layout',component: Layout,children: [{path: 'vaccineType',// --> /Layout/vaccineTypename: 'vaccineType',component: ()=>import('@/type/TypeList')},],}]
})
十、疫苗分类--页面完善、以及添加、修改及删除实现
--后端:在VaccineTypeController中提供删除、添加和修改的请求接口
@RestController
@RequestMapping("/vaccinetype")
public class VaccineTypeController {//依賴VaccineType业务层对象@Autowired //自动注入IVaccineTypeService typeService;//json 的解析工具ObjectMapper jsonTool = new ObjectMapper();// http://localhost:8085/vaccinetype/query// 定义查询的请求接口@RequestMapping("/query")public String query(String phone,String password) throws JsonProcessingException {// map集合-结果集HashMap result =new HashMap();//調用业务层的查询方法List<VaccineType> list = typeService.list();result.put("list",list);//返回json格式的数据return jsonTool.writeValueAsString(result);}// http://localhost:8085/vaccinetype/update// 定义修改的请求接口@RequestMapping("/update")public String update(VaccineType type) throws JsonProcessingException {// map集合-结果集HashMap result =new HashMap();//調用业务层的查询方法boolean update = typeService.updateById(type);result.put("flag",update);//返回json格式的数据return jsonTool.writeValueAsString(result);}// http://localhost:8085/vaccinetype/insert// 定义添加的请求接口@RequestMapping("/insert")public String insert(VaccineType type) throws JsonProcessingException {// map集合-结果集HashMap result =new HashMap();//調用业务层的查询方法boolean insert = typeService.save(type);result.put("flag",insert);//返回json格式的数据return jsonTool.writeValueAsString(result);}// http://localhost:8085/vaccinetype/insert// 定义刪除的请求接口@RequestMapping("/delete")public String delete(Integer id) throws JsonProcessingException {// map集合-结果集HashMap result =new HashMap();//調用业务层的查询方法boolean delete = typeService.removeById(id);result.put("flag",delete);//返回json格式的数据return jsonTool.writeValueAsString(result);}}
--替换TypeList.vue页面即可、效果如下:
<template><div style="width: 100%"><div class="top_div"><!-- 模糊查询表单 --><el-form:inline="true"class="demo-form-inline"style="padding-top: 22px"><!--批量删除、新增按钮--><el-form-item v-if="role == 'manager' || role == 'nurse'"><el-popconfirmtitle="删除后无法恢复,确定吗?"icon-color="red"@confirm="batch_delete()"><el-button slot="reference" plain type="danger">批量删除</el-button></el-popconfirm></el-form-item><el-form-item><el-inputv-model="name"placeholder="请输入疫苗种类名关键字"></el-input></el-form-item><el-form-item><el-buttontype="primary"style="background-color: #254175"@click="selectPage">查询</el-button><el-buttontype="primary"style="background-color: #254175"@click="addOperate">新增</el-button></el-form-item></el-form></div><div class="botoom_div"><!-- 疫苗种类信息展示表格 --><el-table:data="tableData"style="width: 100%"@selection-change="handleSelectionChange"><!-- 复选框 --><el-table-columntype="selection"width="55"v-if="role == 'manager' || role == 'nurse'"></el-table-column><el-table-column prop="id" label="种类编号"> </el-table-column><el-table-column prop="name" label="种类名称" sortable></el-table-column><el-table-column prop="remark" label="介绍"><template #default="scope"><el-popoverplacement="top-start"width="100"trigger="click":content="scope.row.remark"><el-button slot="reference" class="ellipsis-button">{{scope.row.remark}}</el-button></el-popover></template></el-table-column><!-- v-if="role == 'manager' || role == 'nurse'" --><el-table-column prop="status" label="状态"><template #default="scope"><el-tag type="success" v-if="scope.row.status == 1">正常</el-tag><el-tag type="danger" v-if="scope.row.status == 0">禁用</el-tag></template></el-table-column><!-- v-if="role == 'manager' || role == 'nurse'" --><el-table-column label="管理"><template #default="scope"><el-buttonsize="small"v-if="scope.row.status == 1"type="danger"@click="updateStatus(scope.row)">禁用</el-button><el-buttonsize="small"v-if="scope.row.status == 0"type="success"@click="updateStatus(scope.row)">启用</el-button></template></el-table-column><!-- v-if="role == 'manager' || role == 'nurse'" --><el-table-column label="操作"><template #default="scope"><el-button size="small" @click="handleEdit(scope.$index, scope.row)">修改</el-button><el-popconfirmtitle="删除后无法恢复,确定吗?"icon-color="red"@confirm="handleDelete(scope.$index, scope.row)"><el-button slot="reference" size="small" type="danger">删除</el-button></el-popconfirm></template></el-table-column></el-table><!-- 添加-修改表单 --><el-dialog:title="!vaccineType.id ? '疫苗种类-添加' : '疫苗种类-修改'":visible.sync="formVisible":close-on-click-modal="false"><el-form:model="vaccineType"status-icon:rules="rules"ref="addType"label-width="50px"class="demo-vaccineType"><el-form-item label="编号" prop="id" v-if="vaccineType.id"><el-input v-model="vaccineType.id" disabled></el-input></el-form-item><el-form-item label="种类名" prop="name"><el-inputtype="text"v-model="vaccineType.name"autocomplete="off"></el-input></el-form-item><el-form-item label="介绍" prop="remark"><el-inputtype="textarea"v-model="vaccineType.remark"autocomplete="off"></el-input></el-form-item><el-form-item><el-button type="primary" @click="submitForm('addType')">提交</el-button><el-button @click="formVisible = false">取消</el-button></el-form-item></el-form></el-dialog></div></div>
</template><script>
//导入request工具
import request from "@/utils/request";
import Cookies from "js-cookie";
export default {data() {return {role: "",name: "", //模糊查询数据 //表格数据tableData: [],ids: [], //根据id批量删除存放的容器vaccineType: {id: "",name: "",remark: "",},rules: {name: [{ required: true, message: "请输入疫苗种类名称", trigger: "blur" },],remark: [{ required: true, message: "请输入疫苗种类介绍", trigger: "blur" },],},formVisible: false,};}, //当vue创建后,发起请求查询数据created() {if (Cookies.get("user")) {//获取登录用户角色var userJson = JSON.parse(Cookies.get("user"));this.role = userJson.role;}this.selectPage();},methods: {//分页-模糊查询函数selectPage() {//发送请求request.get("/vaccinetype/query", {params: {name: this.name,},}).then((res) => {//处理响应if (res.flag == false) {//查询失败this.$message.error(res.message);} else {this.$message.success("查询成功"); //将查询到的数据赋值到当前tableData中this.tableData = res.list;}});}, //当复选框状态改变时,自动调用该函数,将复选框选中的行的数据id存入ids数组中handleSelectionChange(selection) {//遍历selection数组,存储id值this.ids = selection.map((item) => item.id);}, //批量删除函数batch_delete(index, row) {if (this.ids != "") {request.get("/vaccinetype/batchDelete", {params: {ids: this.ids.toString(),},}).then((res) => {//处理响应if (res.flag == false) {//删除失败this.$message.error(res.message);} else {this.$message.success("删除成功");this.selectPage();}});} else {this.$message.error("请先选择需要删除的数据!");}}, //删除函数handleDelete(index, row) {request.get("/vaccinetype/delete", {params: {//参数id: row.id,},}).then((res) => {//处理响应if (res.flag == false) {//删除失败this.$message.error(res.message);} else {this.$message.success("删除成功");this.selectPage();}});}, //每页展示多少条handleSizeChange(val) {this.pageSize = val;this.selectPage();}, //当前页为多少页handleCurrentChange(val) {this.currentPage = val;this.selectPage();}, //打开添加表单addOperate() {this.formVisible = true; //对该表单项进行移除校验结果this.$refs.addType.resetFields();this.vaccineType = {id: "",name: "",remark: "",};}, //修改-添加表单提交函数submitForm(formName) {//validate校验代码this.$refs[formName].validate((valid) => {// ok--通过校验if (valid) {if (this.vaccineType.id) {//id存在则是进行修改操作request.post("/vaccinetype/update", this.vaccineType).then((res) => {if (res.flag == false) {//修改失败this.$message.error(res.message);// 查询方法this.selectPage();} else {//修改成功this.formVisible = false;this.$message.success("修改成功");this.vaccineType = {id: "",name: "",remark: "",};this.selectPage();}});} else {//id不存在则是进行添加操作//发送请求request.post("/vaccinetype/insert", this.vaccineType).then((res) => {//处理响应if (res.flag == false) {//添加失败this.$message.error(res.message);} else {this.$message.success("添加成功"); //关闭模态框this.formVisible = false; //清空数据this.vaccineType = {id: "",name: "",remark: "",}; //重新查询数据this.selectPage();}});}}});}, // 打开修改表单函数handleEdit(index, row) {//打开嵌套表单的修改对话框this.formVisible = true; //将数据进行回显this.vaccineType.id = row.id;this.vaccineType.name = row.name;this.vaccineType.remark = row.remark; //对该表单项进行移除校验结果 // this.$refs.addType.clearValidate();},},
};
</script><style>
.top_div {border-radius: 15px;box-shadow: rgba(0, 0, 0, 0.32) 0px 2px 5px;margin-bottom: 50px;background-color: #fff;
}
.botoom_div {border-radius: 15px;padding-top: 25px;padding-bottom: 25px;box-shadow: rgba(0, 0, 0, 0.32) 0px 2px 5px;margin-bottom: 50px;background-color: #fff;
}
.ellipsis-button {white-space: nowrap;overflow: hidden;text-overflow: ellipsis;height: 50px;max-width: 200px;/* 假设按钮最大宽度为100px,根据需要进行调整 */
}
</style>
--重启后端服务进行测试、建议可以先新增一些数据,然后再测试修改和删除的操作
相关文章:

粤嵌实训医疗项目day02(Vue + SpringBoot)
目录 一、创建vue项目并运行 二、vue-cli中的路由使用 三、element-ui框架、实现页面布局以及vue-路由 四、前端登录页面 五、user登录后端接口完善【后端】 六、user登录前端-请求工具-请求发起【前端】 七、请求的跨域-访问策略 八、完善项目的页面布局、导航菜单以及…...

又是一年1024程序员日
程序员节是每年的10月24日,这是一个特殊的节日,旨在庆祝和表彰程序员们对科技和社会的贡献。作为技术领域的从业者,程序员们在现代社会中扮演着重要的角色,他们致力于编写、测试和维护软件代码,为我们的生活带来了无数…...

acme.sh签发和部署ZeroSSL泛域名证书
大家好,我叫徐锦桐,个人博客地址为www.xujintong.com。平时记录一下学习计算机过程中获取的知识,还有日常折腾的经验,欢迎大家访问。 介绍 acme.sh 是个开源的shell证书生成脚本,他可以自动生成Let’s Encrypt 的证书…...

Calibre拾遗:FDI (Foreign Database Interface)系统简介
Calibre是强大的GDS处理工具,包括查看,验证,分析等操作,操作由浅入深,除过手动编辑GDS的不是很灵活外,其他各种命令和操作策略,都是远(遥)远(遥)走…...

记一次渗透测试事件
一、漏洞发现 拿到登录的接口,丢到sqlmap里面跑一把,发现延时注入 进一步查询,发现是sa权限,直接os-shell whomai查询发现是管理员权限 os-shell执行命令太慢了,直接进行nc 反弹 执行base64 加密后的powershell命令&…...

AIGC笔记--基于DDPM实现图片生成
目录 1--扩散模型 2--训练过程 3--损失函数 4--生成过程 5--参考 1--扩散模型 完整代码:ljf69/DDPM 扩散模型包含两个过程,前向扩散过程和反向生成过程。 前向扩散过程对一张图像逐渐添加高斯噪声,直至图像变为随机噪声。 反向生成过程…...

三十七、【进阶】SQL的explain
1、explain 2、基础使用 在使用explain关键字时,只需要在所执行语句前加上explain即可 mysql> explain select * from stu where id3; ---------------------------------------------------------------------------------------------------------- | id | s…...
【Python】取火柴小游戏(巴什博弈)
火柴游戏:Python编程示例 当我们想要玩一个简单而有趣的游戏,同时又想锻炼自己的编程技能时,一个经典的选择就是火柴游戏。这个游戏的规则很简单:有一堆火柴,每次可以拿走1到6根,两名玩家轮流取火柴&#…...

030-第三代软件开发-密码输入框
第三代软件开发-密码输入框 文章目录 第三代软件开发-密码输入框项目介绍密码输入框总结一下 关键字: Qt、 Qml、 echoMode、 TextInput、 Image 项目介绍 欢迎来到我们的 QML & C 项目!这个项目结合了 QML(Qt Meta-Object Language…...

mysql读取文件
环境地址:phpMyAdmin LOAD DATA INFILE 任意文件读取漏洞 | VULNSPY 参考文章: mysql任意文件读取漏洞学习_BerL1n的博客-CSDN博客 从一道ctf题学习mysql任意文件读取漏洞 - 安全客,安全资讯平台 MYSQL 任意文件读取 小组CTF出题感想 - …...
CentOS(5)——rpm包和源码包区别
目录 一、简介 二、区别 ①包名称 ②概念 ③优缺点 ④安装位置的区别 ⑤安装位置不同带来的影响 ⑥卸载方式的不同 一、简介 最近在公司内网离线升级Git时,遇见两个概念,分别是使用rpm包安装git,另一个这是编译源码包安装git&#x…...
Golang 实现对配置文件加密
引言 在实际的应用中,配置文件通常包含了一些敏感的信息,如数据库密码、API密钥等。为了保护这些敏感信息不被恶意获取,我们可以对配置文件进行加密。本文将介绍如何使用Go语言实现对配置文件的加密。 场景 在这个场景中,我们将…...
MYSQL数字函数详解和实战(数字函数大全,内含示例)
MySQL提供了许多数字函数,用于对数字进行各种计算和处理。以下是一些常用的MySQL数字函数。 内容有点多,建议收藏以备后续用到查阅参考。 目录 一、SIGN 取数字的符号 二、ABS 取绝对值 三、COS 取余弦值 四、ACOS 取反余弦值 五、SIN 取正弦值 六…...

Linux系列讲解 —— VIM配置与美化
目录 1. Vim基本配置1.1 配置文件1.2 基本配置 2. 插件管理器Vundle2.1 下载Vundle2.2 在vimrc中添加Vundle的配置 3. Vundle的使用3.1 安装插件3.2 卸载插件 1. Vim基本配置 1.1 配置文件 vim的配置文件有两处,请根据实际情况选择修改哪个。 (1) 全局配置文件&am…...
FreeSWITCH 使用指北(2)-多段音频顺序播放的设置
文章目录 1. 多段音频顺序播放的设置 1. 多段音频顺序播放的设置 在 FreeSWITCH 中涉及到放音的 APP 有不少,比较典型的是播放录音文件的 playback 和 play_and_detect_speech 。这两个 APP 播放录音的功能都依赖于 switch_ivr_play_say.c#switch_ivr_play_file() …...
使用python爬虫语言调用有道翻译实现英中互译(2023实现)
使用python爬虫语言调用有道翻译实现英中互译(2023实现) 作者: 安静到无声 作者简介:人工智能和硬件设计博士生、CSDN与阿里云开发者博客专家,多项比赛获奖者,发表SCI论文多篇。 Thanks♪(・ω・)ノ 如果觉得文章不错或能帮助到你学习,可以点赞👍收藏📁评论📒+关…...

2024王道考研计算机组成原理——指令系统
零、本章概要 指令寻址:解决的是PC"1"的问题 数据寻址:使用寄存器/内存/结合 基址寻址:用于多道程序的并发执行 直接寻址:call 0x12345678 变址寻址:esi edi用于循环,因为使用直接寻址需要一堆…...
vscode中如何将cmd设置为默认终端
vscode中如何将cmd设置为默认终端?下面本篇文章给大家介绍一下vscode中设置默认终端为cmdPowerShelWSL等的方法,希望对需要的朋友有所协助! 一、快捷键(CtrlShiftP打开命令面板,输入select选择“SelectDefaultProfil …...
Unity UGUI 循环滑动列表实现思路及简单代码实现
前言: 自己之前其实比着书上实现过一个循环滑动列表,并且商业化到了项目里,上线后也在用。可后来怎么也想不起来细节,看着之前的代码也看不很懂。这次复习一下,希望真能理解它的本质,也记录一下࿰…...

贪心算法(1)--经典贪心算法
目录 一、活动安排问题 二、最优装载问题 三、分数背包问题 四、多机调度问题 一、活动安排问题 1、策略 活动安排问题:设有n个活动的集合E{1,2,...,n},每个活动i都有一个使用该资源的起始时间和一个结束时间,且。如果选择了活动i则它在…...

K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...

前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...