二十二、登录
Login.vue如下
<template>
<div class="loginBody">
<div class="loginDiv">
<div class="login-content">
<h1 class="login-title">用户登录</h1>
<el-form :model="loginForm" label-width="100px"
:rules="rules" ref="loginForm">
<el-form-item label="账号" prop="no">
<el-input style="width: 200px" type="text" v-model="loginForm.no"
autocomplete="off" size="small"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input style="width: 200px" type="password" v-model="loginForm.password"
show-password autocomplete="off" size="small" @keyup.enter.native="confirm"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="confirm" :disabled="confirm_disabled">确 定</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Login",
data() {
return {
confirm_disabled: false,
loginForm: {
no: '',
password: ''
},
rules: {
no: [
{required: true, message: '请输入账号', trigger: 'blur'}
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'}
],
}
}
},
methods: {
confirm() {
this.confirm_disabled = true;
this.$refs.loginForm.validate((valid) => {
if (valid) { //valid成功为true,失败为false
//去后台验证用户名密码
this.$axios.post(this.$httpUrl + '/user/login', this.loginForm).then(res => res.data).then(res => {
console.log(res)
if (res.code == 200) {
//存储
sessionStorage.setItem("CurUser", JSON.stringify(res.data))
// console.log(res.data.menu)
// this.$store.commit("setMenu",res.data.menu)
//跳转到主页
this.$router.replace('/Index');
} else {
this.confirm_disabled = false;
alert('校验失败,用户名或密码错误!');
return false;
}
});
} else {
this.confirm_disabled = false;
console.log('校验失败');
return false;
}
});
}
}
}
</script>
<style scoped>
.loginBody {
position: absolute;
width: 100%;
height: 100%;
background-color: #B3C0D1;
}
.loginDiv {
position: absolute;
top: 50%;
left: 50%;
margin-top: -200px;
margin-left: -250px;
width: 450px;
height: 330px;
background: #fff;
border-radius: 5%;
}
.login-title {
margin: 20px 0;
text-align: center;
}
.login-content {
width: 400px;
height: 250px;
position: absolute;
top: 25px;
left: 25px;
}
</style>
在wms-web中 npm install vue-router@3.5.4
新建文件夹router在src下,里面新建 index.js,
import VueRouter from'vue-router';
const routes=[
{
path: '/',
name: 'login',
component: () => import('../components/Login')
},
{
path: '/Index',
name: 'index',
component: () => import('../components/Index')
}
]
const router=new VueRouter({
mode:'history',
routes,
})
export default router;
在main.js中创建路由
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import './assets/global.css'
import axios from "axios";
import VueRouter from "vue-router";
import router from "./router";
Vue.prototype.$axios =axios;
Vue.prototype.$httpUrl='http://localhost:8090'
Vue.config.productionTip = false
//Vue.use(ElementUI)
Vue.use(VueRouter)
Vue.use(ElementUI,{size:'small'})
new Vue({
router,
render: h => h(App),
}).$mount('#app')
UseerController中新增的login
// 登录
@PostMapping("/login")
public Result login(@RequestBody User user) {
List<User> list = userService.lambdaQuery()
.eq(User::getNo, user.getNo())
.eq(User::getPassword, user.getPassword())
.list();
return list.size()>0?Result.success(list.get(0)):Result.fail();
}
App.vue中记得 改为router,把下面的import和components删除
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
这些是用到的(包括没变化的)文件
二十三、退出登录
1.展示名字
2.退出登录事件
3.退出跳转、清空相关数据
4.退出确认
AppHeader.vue
<template>
<div style="display:flex;line-height:60px;">
<div style="cursor:pointer;">
<i :class="icon" style="font-size:20px;vertical-align: middle;" @click="collapse"></i>
</div>
<div style="flex:1;text-align:center;font-size:27px;">
<span>欢迎来到仓库管理系统</span>
</div>
<el-dropdown><!--trigger="click"-->
<span>{{ user.name }}</span>
<i class="el-icon-arrow-down" style="margin-left:5px;"></i>
<el-dropdown-menu slot="dropdown">
<!--直接给图标加line-height:60px就居中了;加上height和line-height,让他们相等就可以让文本垂直居中;加垂直vertical-align: middle;应该就好了-->
<el-dropdown-item @click.native="toUser">个人中心</el-dropdown-item>
<el-dropdown-item @click.native="logout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
<style scoped>
</style>
<script>
export default {
name: "AppHeader",
data() {
return {
user: JSON.parse(sessionStorage.getItem('CurUser'))
}
},
props: {
icon: String
},
methods: {
toUser() {
console.log('to_user')
},
logout() {
console.log('logout')
this.$confirm('您确定要退出登录吗?', '提示', {
confirmButtonText: '确定',//确认按钮的文字显示
type: 'warning',
center: true,//文字居中显示
})
.then(() => {
//官网有messageBox弹窗完整代码
this.$message({
type:'success',
message:'您已成功退出登录'
})
this.$router.push("/")
sessionStorage.clear()
})
.catch(() => {
this.$message({
type:'info',
message:'已取消退出登录'
})
})
},
collapse() {
this.$emit('doCollapse')
}
}
}
</script>
二十四、个人中心
新建Home.vue文件
<template>
<div style="text-align: center;background-color: #f1f1f3;height: 100%;padding: 0px;margin: 0px;">
<h1 style="font-size: 50px;">{{'欢迎你!'+user.name}}</h1>
<el-descriptions title="个人中心" :column="2" size="40" border>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-s-custom"></i>
账号
</template>
{{user.no}}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-mobile-phone"></i>
电话
</template>
{{user.phone}}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-location-outline"></i>
性别
</template>
<el-tag
:type="user.sex === '1' ? 'primary' : 'danger'"
disable-transitions><i :class="user.sex==1?'el-icon-male':'el-icon-female'"></i>{{user.sex==1?"男":"女"}}</el-tag>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-tickets"></i>
角色
</template>
<el-tag
type="success"
disable-transitions>{{user.roleId==0?"超级管理员":(user.roleId==1?"管理员":"用户")}}</el-tag>
</el-descriptions-item>
</el-descriptions>
<DateUtils></DateUtils>
</div>
</template>
<script>
import DateUtils from "./DateUtils";
export default {
name: "HomePage",
components: {DateUtils},
data() {
return {
user:{}
}
},
computed:{
},
methods:{
init(){
this.user = JSON.parse(sessionStorage.getItem('CurUser'))
}
},
created(){
this.init()
}
}
</script>
<style scoped>
.el-descriptions{
width:90%;
margin: 0 auto;
text-align: center;
}
</style>
DataUtils.vue文件
<template >
<div style="padding: 30px;font-size: 30px;">
<span class="time" id="time" >
今天是:<span class="date">{{ nowTime }}</span>
<span class="hour" style="margin-left: 5px;">{{time.hour}}</span>
<a class="split">:</a>
<span class="minitus">{{time.minitus}}</span>
<a class="split">:</a>
<span class="seconds">{{time.seconds}}</span>
</span>
</div>
</template>
<script>
export default {
name: "DateUtils",
props: ["s"],
data() {
return {
time: {
hour: "",
minitus: "",
seconds: ""
},
nowTime: "",
week: [
"星期天",
"星期一",
"星期二",
"星期三",
"星期四",
"星期五",
"星期六"
]
};
},
mounted() {
this.dateTime();
},
methods: {
dateTime() {
this.timeFormate();
setTimeout(() => {
this.dateTime();
}, 1000);
},
timeFormate() {
const newtime = new Date();
this.time.hour = this.getIncrease(newtime.getHours(), 2);
this.time.minitus = this.getIncrease(newtime.getMinutes(), 2);
this.time.seconds = this.getIncrease(newtime.getSeconds(), 2);
this.nowTime =
this.getIncrease(newtime.getFullYear(), 4) +
"年" +
this.getIncrease(newtime.getMonth() + 1, 2) +
"月" +
this.getIncrease(newtime.getDate(), 2) +
"日 " +
this.week[newtime.getDay()];
//this.hour=
// return `${this.time.hour}:${this.time.minitus}:${this.time.seconds}`;
},
getIncrease(num, digit) {
var increase = "";
for (var i = 0; i < digit; i++) {
increase += "0";
}
return (increase + num).slice(-digit);
}
}
}
</script>
<style scoped>
.txt-data .time {
font-size: 1rem;
margin-right: 0.5rem;
}
.split {
animation: shark 1s step-end infinite;
vertical-align: center;
margin-left: 2px;
margin-right: 2px;
}
@keyframes shark {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0;
}
}
</style>
我们在header中找到 toUser.vue,加一句跳转路由
toUser() { console.log('to_user') this.$router.push("/Home") },
在header后的methods后面再加created ,为了保证直接推到个人中心
created(){
this.$router.push("/Home")
}
接下来写home的路由index.js
import VueRouter from'vue-router';
const routes=[
{
path: '/',
name: 'LoginPage',
component: () => import('../components/LoginPage.vue')
},
{
path: '/Indexpage',
name: 'IndexPage',
component: () => import('../components/IndexPage.vue'),
children:[
{
path:'/HomePage',
name:'HomePage',
meta:{
title:'首页'
},
component:()=>import('../components/HomePage.vue')
}
]
}
]
const router=new VueRouter({
mode:'history',
routes,
})
const VueRouterPush=VueRouter.prototype.push
VueRouter.prototype.push=function push (to){
return VueRouterPush.call(this,to).catch(err=>err)
}
export default router;
在IndexPage中删除相关部分AppMain.vue,如import和component等,将template中的main替换成router-view就可以实现跳转了!
<el-main style="height: 100%"> <router-view></router-view> </el-main>
二十五、菜单跳转
AppAside中第一个el-menu加一个router即可方便的跳转,
<el-menu
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
style="height:100%;"
default-active="/Home"
:collapse="isCollapse"
:collapse-transition="false"
router
>
接下来配置aside的导向,index中为side加几个children,顺带把Aside.vue中两个index改一下,改为<el-menu-item index="/Admin">和<el-menu-item index="/User">
children:[
{
path:'/HomePage',
name:'HomePage',
meta:{
title:'首页'
},
component:()=>import('../components/HomePage.vue')
},
{
path:'/AdminPage',
name:'AdminPage',
meta:{
title:'管理员管理'
},
component:()=>import('../components/admin/AdminPage.vue')
},
{
path:'/UserPage',
name:'UserPage',
meta:{
title:'用户管理'
},
component:()=>import('../components/user/UserPage.vue')
}
]
这是AdminManage和UserManage
<template>
<span>admin</span>
</template>
<script>
export default{
name:"AdminManage"
}
</script>
<style scoped>
</style>
<template>
<span>user</span>
</template>
<script>
export default{
name:"UserManage"
}
</script>
<style scoped>
</style>
重启即可实现跳转!!! PS:这里有点难看,在Index.vue中的el-aside加了句 height:100vh;
3.模拟动态menu,生成动态路由 . 在Aside中添加menu的模拟
<template>
<el-menu
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
style="height:100%;"
default-active="/Home"
:collapse="isCollapse"
:collapse-transition="false"
router
>
<el-menu-item index="/Home">
<i class="el-icon-s-home"></i>
<span slot="title">首页</span>
</el-menu-item>
<el-menu-item :index="'/'+item.menuClick" v-for="(item,i) in menu" :key="i">
<i :class="item.menuIcon"></i>
<span slot="title">{{item.menuName}}</span>
</el-menu-item>
</el-menu>
</template>
<style scoped>
</style>
<script>
export default {
name: "Aside",
data() {
return {
// isCollapse:false
menu: [
{
menuClick: 'Admin',
menuName: '管理员管理',
menuIcon: 'el-icon-s-custom'
}, {
menuClick: 'User',
menuName: '用户管理',
menuIcon: 'el-icon-user-solid'
}
]
}
},
props: {
isCollapse: Boolean
}
}
</script>
二十六、动态路由
1.设计menu表和数据
复制如下文字,打开navicat生成表结构
CREATE TABLE `menu` ( `id` int(11) NOT NULL, `menuCode` varchar(8) DEFAULT NULL COMMENT '菜单编码', `menuName` varchar(16) DEFAULT NULL COMMENT '菜单名字', `menuLevel` varchar(2) DEFAULT NULL COMMENT '菜单级别', `menuParentCode` varchar(8) DEFAULT NULL COMMENT '菜单的父code', `menuClick` varchar(16) DEFAULT NULL COMMENT '点击触发的函数', `menuRight` varchar(8) DEFAULT NULL COMMENT '权限 0超级管理员,1表示管理员,2表示普通用户,可以用逗号组合使用', `menuComponent` varchar(200) DEFAULT NULL, `menuIcon` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; BEGIN; INSERT INTO `menu` VALUES (1, '001', '管理员管理', '1', NULL, 'Admin', '0', 'admin/AdminManage.vue', 'el-icon-s-custom'); INSERT INTO `menu` VALUES (2, '002', '用户管理', '1', NULL, 'User', '0,1', 'user/UserManage.vue', 'el-icon-user-solid'); COMMIT;

新建查询-->复制进入-->运行即可 看不见可以f5刷新一下.
2.生成menu对应的后端代码
再次打开CodeGenerator的,对menu进行代码生成(这个报错没什么,无非MySQL在5.7到8.0改了改加密方式)
在MenuMapper中开头添加@Mapper, 代码MenuController如下
package com.wms.controller;
import com.wms.common.Result;
import com.wms.service.MenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.wms.entity.Menu;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* <p>
* 前端控制器
* </p>
*
* @author wms
* @since 2024-11-24
*/
@RestController
@RequestMapping("/menu")
public class MenuController {
@Autowired
private MenuService menuService;
@GetMapping("/list")
public Result list(@RequestParam String roleId) {
List list = menuService.lambdaQuery().like(Menu::getMenuright, roleId).list();
return Result.success(list);
}
}
你可以通过直接访问后端8090端口来查看是否成功
3.返回数据
为了节省请求的次数,我们绑定在UserController的登录中一并给他在登录一次性获得数据 . (可能你需要 import com.wms.entity.Menu;
// 登录
@PostMapping("/login")
public Result login(@RequestBody User user) {
List<User> list = userService.lambdaQuery()
.eq(User::getNo, user.getNo())
.eq(User::getPassword, user.getPassword())
.list();
if(list.size()>0) {
User user1 = (User) list.get(0);
List menuList = menuService.lambdaQuery().like(Menu::getMenuright, user1.getRoleId()).list();
HashMap res = new HashMap();
res.put("user", user1);//这里有貌似可以修改的地方?不用动态路由权限改变要改源码,这样直接改数据库。依赖配置lombok可以省略getset步骤
res.put("menu", menuList);
return Result.success(res);
}
return Result.fail();
}
修改Login.vue看看能否打印
sessionStorage.setItem("CurUser", JSON.stringify(res.data.user)) console.log(res.data.menu)
看到了,是返回了0,1的 因为sql中他是管理员
4.vuex状态管理
在wms-web中加载vuex , 终端运行npm i vuex@3.0.0
在src下新建一个文件夹store,里面加文件index.js
import vue from 'vue'
import Vuex from 'vuex'
vue.use(Vuex)
export default new Vuex.Store({
state: {
menu: []
},
mutations: {
setMenu(state,menuList) {
state.menu=menuList
}
},
getters:{
getMenu(state){
return state.menu
}
}
})
main.js中注册 store相关内容
import store from "./store"; ........... new Vue({ router, store, render: h => h(App), }).$mount('#app')
如愿以偿在vue插件的vuex中找到,就是不知道为什么是ROOT下的不是setMenu (inspected,active)
5.生成menu数据
删除模拟的Aside,使用动态的computed的来显示
data() {
return {
// isCollapse:false
}
},
computed: {
"menu": {
get() {
return this.$store.state.menu
}
}
},
刷新失效,可以将state存进session,然后在index刷新时在读取就行
6.生成路由数据
页面路由的右边不是动态的,router/index.js里面的都是固定写死的。将router/index中的chirdren的Admin和User统统注释 这是store/index.js路由
import vue from 'vue'
import Vuex from 'vuex'
import router from '../router'
vue.use(Vuex)
function addNewRoute(menuList){
let routes= router.options.routes
console.log(routes)
/* {
path:'/Admin',
name:'admin',
meta:{
title:'管理员管理'
},
component:()=>import('../components/admin/AdminManage.vue')
},*/
}
export default new Vuex.Store({
state: {
menu: []
},
mutations: {
setMenu(state,menuList) {
state.menu=menuList
addNewRoute(menuList)
}
},
getters:{
getMenu(state){
return state.menu
}
}
})
可以在F12中看到对于的router
import vue from 'vue'
import Vuex from 'vuex'
import router from '../router'
vue.use(Vuex)
function addNewRoute(menuList){
console.log(menuList)
let routes= router.options.routes
console.log(routes)
routes.forEach(routeItem=>{
if(routeItem.path=="/Index"){
menuList.forEach(menu=>{
let childRoute={
path:'/'+menu.menuclick,
name:menu.menuname,
meta:{
title:menu.menuname
},
component:()=>import('../components/'+menu.menucomponent)
}
routeItem.children.push(childRoute)
})
}
})
router.addRoutes(routes)
}
export default new Vuex.Store({
state: {
menu: []
},
mutations: {
setMenu(state,menuList) {
state.menu=menuList
addNewRoute(menuList)
}
},
getters:{
getMenu(state){
return state.menu
}
}
})
对于3+2重路由的占用,使用这个来解决router/index.js最后另加
export function resetRouter(){ router.matcher=new VueRouter({ mode:'history', routes:[] }).matcher }
store/index中
function addNewRoute(menuList){
console.log(menuList)
let routes= router.options.routes
console.log(routes)
routes.forEach(routeItem=>{
if(routeItem.path=="/Index"){
menuList.forEach(menu=>{
let childRoute={
path:'/'+menu.menuclick,
name:menu.menuname,
meta:{
title:menu.menuname
},
component:()=>import('../components/'+menu.menucomponent)
}
routeItem.children.push(childRoute)
})
}
})
resetRouter()
router.addRoutes(routes)
}
二十七、管理员管理功能
AdminManage.vue
<template>
<div>
<div style="margin-left:5px">
<el-input v-model="name" placeholder="请输入名字:" suffix-icon="el-icon-search" style="width:200px;"
@keyup.enter.native="loadPost"></el-input>
<el-select v-model="sex" filterableplacehoLder="请选择性别" style="margin-left:5px">
<el-option
v-for="item in sexs"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<el-button type="primary" style="margin-left:5px" @click="loadPost">查询</el-button>
<el-button type="success" @click="resetParam">重置</el-button>
<el-button type="primary" style="margin-left:5px" @click="add">新增</el-button>
</div>
<el-table :data="tableData"
:header-cell-style="{background:'#f2f5fc',color:'#555'}"
border
>
<el-table-column prop="id" label="ID" width="60">
</el-table-column>
<el-table-column prop="no" label="账号" width="120">
</el-table-column>
<el-table-column prop="name" label="姓名" width="80">
</el-table-column>
<el-table-column prop="age" label="年龄" width="80">
</el-table-column>
<el-table-column prop="sex" label="性别" width="80">
<template slot-scope="scope">
<el-tag
:type="scope.row.sex === 1 ?'primary':'success'"
disable-transitions>{{ scope.row.sex === 1 ? '男' : '女' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="roleId" label="角色" width="120">
<template slot-scope="scope">
<el-tag
:type="scope.row.roleId === 0 ?'danger':(scope.row.roleId === 1 ?'primary':'success')"
disable-transitions>
{{ scope.row.roleId === 0 ? '超级管理员' : (scope.row.roleId === 1 ? '管理员' : '用户') }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="phone" label="电话" width="120">
</el-table-column>
<el-table-column prop="operate" label="操作">
<template slot-scope="scope">
<el-button size="small" type="success" @click="mod(scope.row)">编辑</el-button>
<el-popconfirm
title="确定删除吗?"
@confirm="del(scope.row.id)"
style="margin-left:8px;"
>
<el-button slot="reference" size="small" type="danger">删除</el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[5, 10, 20, 50]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
<el-dialog
title="提示"
:visible.sync="centerDialogVisible"
width="30%"
center>
<el-form ref="form" :rules="rules" :model="form" label-width="80px">
<el-form-item label="账号" prop="no">
<el-col :span="20">
<el-input v-model="form.no"></el-input>
</el-col>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-col :span="20">
<el-input v-model="form.password"></el-input>
</el-col>
</el-form-item>
<el-form-item label="名字" prop="name">
<el-col :span="20">
<el-input v-model="form.name"></el-input>
</el-col>
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-col :span="20">
<el-input v-model="form.age"></el-input>
</el-col>
</el-form-item>
<el-form-item label="性别">
<el-radio-group v-model="form.sex">
<el-radio label="1">男</el-radio>
<el-radio label="0">女</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="电话" prop="phone">
<el-col :span="20">
<el-input v-model="form.phone"></el-input>
</el-col>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="centerDialogVisible=false">取消</el-button>
<el-button type="primary" @click="save">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<style scoped>
</style>
<script>
export default {
name: "AdminManage",
data() {
let checkAge = (rule, value, callback) => {
if (value > 150) {
callback(new Error('年龄太大!lbd再来我让你飞起来!'));
} else {
callback();
}
};
let checkDuplicate = (rule, value, callback) => {
if (this.form.id) {
return callback();
}
this.$axios.get(this.$httpUrl + "/user/findByNo?no=" + this.form.no).then(res => res.data).then(res => {
if (res.code !== 200) {//es6解构也可以
callback();
} else {
callback(new Error('账号已经存在'));
}
});
};
return {
tableData: [],
pageSize: 10,
pageNum: 1,
total: 0,
name: '',
sex: '',
sexs: [
{
value: '1',
label: '男'
}, {
value: '0',
label: '女'
}
],
centerDialogVisible: false,
form: {
name: '',
no: '',
age: '',
password: '',
phone: '',
sex: '0',
roleId: '1'
},
rules: {
no: [
{required: true, message: '请输入账号', trigger: 'blur'},
{min: 3, max: 8, message: '长度在3-8个字符', trigger: 'blur'},
{validator: checkDuplicate, trigger: 'blur'}
],
name: [
{required: true, message: '请输入名字', trigger: 'blur'},
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'},
{min: 4, max: 10, message: '长度在4-10个字符之间', trigger: 'blur'}
],
age: [
{required: true, message: '请输入年龄', trigger: 'blur'},
{min: 1, max: 3, message: '长度在1到3个位', trigger: 'blur'},
{pattern: /^([1-9][0-9]*){1,3}$/, message: '年龄必须为正整数字', trigger: "blur"},
{validator: checkAge, trigger: 'blur'}
],
phone: [
{required: true, message: "手机号不能为空", trigger: "blur"},
{pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur"}
]
}
}
},
methods: {
add() {
this.centerDialogVisible = true
this.$nextTick(() => {
this.resetForm()
})
},
mod(row) {
//this.form=row就可以了
this.centerDialogVisible = true
this.$nextTick(() => {
this.form.id = row.id;
this.form.no = row.no;
this.form.name = row.name;
this.form.sex = row.sex + '';
this.form.age = row.age + '';//转化成字符串类型
this.form.phone = row.phone;
this.form.password = '';
this.form.roleId = row.roleId;
})//修改User的时候要确保账号不能修改,否则有可能会数据库存在账号相同的情况!!!!给账号的input里加个v-bind:disabled="isDisabled“,如果是修改就把isDisabled设置为true,添加就false
},
del(id) {
this.$axios.get(this.$httpUrl + '/user/del?id=' + id).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.loadPost();
} else {
this.$message({
message: '操作失败!请返回重新操作...',
type: 'error'
});
}
});
},
resetForm() {
this.centerDialogVisible = true
this.$refs.form.resetFields();
},
doSave() {
this.$axios.post(this.$httpUrl + '/user/save', this.form).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.centerDialogVisible = false
this.loadPost();
this.resetForm()
} else {
this.$message({
message: '操作失败!请返回重新操作...',
type: 'error'
});
}
});
},
doMod() {
this.$axios.post(this.$httpUrl + '/user/update', this.form).then(res => res.data).then(res => {
console.log(res);
if (res.code == 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.centerDialogVisible = false;
this.loadPost();
this.resetForm();
} else {
this.$message({
message: '操作失败!',
type: 'error'
});
}
});
},
save() {
this.$refs.form.validate((valid) => {
if (valid) {
if (this.form.id) {
this.doMod();
} else {
this.doSave();
}
} else {
console.log('error submit!!');
return false;
}
});
},
loadGet() {
this.$axios.get(this.$httpUrl + '/user/list').then(res => res.data).then(res => {
console.log(res)
})
},
loadPost() {
this.$axios.post(this.$httpUrl + '/user/listPageC1', {
pageSize: this.pageSize,
pageNum: this.pageNum,
param: {
name: this.name,
sex: this.sex,
roleId:'1'
}
}).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.tableData = res.data
this.total = res.total
} else {
alert('获取数据失败!请刷新页面')
}
})
},
resetParam() {
this.name = ''
this.sex = ''
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageNum = 1//这个错误是先翻到第二页在调页面条数,显示无数据
this.pageSize = val
this.loadPost()
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
this.pageNum = val
this.loadPost()
}
},
beforeMount() {
// this.loadGet();
this.loadPost()
}
}
</script>
在listPageC1中获取roleid并判段是否为black
String roleId = (String) param.get("roleId"); ....................... ....................... if(StringUtils.isNotBlank(roleId)) { lambdaQueryWrapper.eq(User::getRoleId, roleId); }
UserManage.vue和AdminManage极其相似,改成roleid 2和name UserManage即可
<template>
<div>
<div style="margin-left:5px">
<el-input v-model="name" placeholder="请输入名字:" suffix-icon="el-icon-search" style="width:200px;"
@keyup.enter.native="loadPost"></el-input>
<el-select v-model="sex" filterableplacehoLder="请选择性别" style="margin-left:5px">
<el-option
v-for="item in sexs"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<el-button type="primary" style="margin-left:5px" @click="loadPost">查询</el-button>
<el-button type="success" @click="resetParam">重置</el-button>
<el-button type="primary" style="margin-left:5px" @click="add">新增</el-button>
</div>
<el-table :data="tableData"
:header-cell-style="{background:'#f2f5fc',color:'#555'}"
border
>
<el-table-column prop="id" label="ID" width="60">
</el-table-column>
<el-table-column prop="no" label="账号" width="120">
</el-table-column>
<el-table-column prop="name" label="姓名" width="80">
</el-table-column>
<el-table-column prop="age" label="年龄" width="80">
</el-table-column>
<el-table-column prop="sex" label="性别" width="80">
<template slot-scope="scope">
<el-tag
:type="scope.row.sex === 1 ?'primary':'success'"
disable-transitions>{{ scope.row.sex === 1 ? '男' : '女' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="roleId" label="角色" width="120">
<template slot-scope="scope">
<el-tag
:type="scope.row.roleId === 0 ?'danger':(scope.row.roleId === 1 ?'primary':'success')"
disable-transitions>
{{ scope.row.roleId === 0 ? '超级管理员' : (scope.row.roleId === 1 ? '管理员' : '用户') }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="phone" label="电话" width="120">
</el-table-column>
<el-table-column prop="operate" label="操作">
<template slot-scope="scope">
<el-button size="small" type="success" @click="mod(scope.row)">编辑</el-button>
<el-popconfirm
title="确定删除吗?"
@confirm="del(scope.row.id)"
style="margin-left:8px;"
>
<el-button slot="reference" size="small" type="danger">删除</el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[5, 10, 20, 50]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
<el-dialog
title="提示"
:visible.sync="centerDialogVisible"
width="30%"
center>
<el-form ref="form" :rules="rules" :model="form" label-width="80px">
<el-form-item label="账号" prop="no">
<el-col :span="20">
<el-input v-model="form.no"></el-input>
</el-col>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-col :span="20">
<el-input v-model="form.password"></el-input>
</el-col>
</el-form-item>
<el-form-item label="名字" prop="name">
<el-col :span="20">
<el-input v-model="form.name"></el-input>
</el-col>
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-col :span="20">
<el-input v-model="form.age"></el-input>
</el-col>
</el-form-item>
<el-form-item label="性别">
<el-radio-group v-model="form.sex">
<el-radio label="1">男</el-radio>
<el-radio label="0">女</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="电话" prop="phone">
<el-col :span="20">
<el-input v-model="form.phone"></el-input>
</el-col>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="centerDialogVisible=false">取消</el-button>
<el-button type="primary" @click="save">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<style scoped>
</style>
<script>
export default {
name: "UserManage",
data() {
let checkAge = (rule, value, callback) => {
if (value > 150) {
callback(new Error('年龄太大!lbd再来我让你飞起来!'));
} else {
callback();
}
};
let checkDuplicate = (rule, value, callback) => {
if (this.form.id) {
return callback();
}
this.$axios.get(this.$httpUrl + "/user/findByNo?no=" + this.form.no).then(res => res.data).then(res => {
if (res.code !== 200) {//es6解构也可以
callback();
} else {
callback(new Error('账号已经存在'));
}
});
};
return {
tableData: [],
pageSize: 10,
pageNum: 1,
total: 0,
name: '',
sex: '',
sexs: [
{
value: '1',
label: '男'
}, {
value: '0',
label: '女'
}
],
centerDialogVisible: false,
form: {
name: '',
no: '',
age: '',
password: '',
phone: '',
sex: '0',
roleId: '2'
},
rules: {
no: [
{required: true, message: '请输入账号', trigger: 'blur'},
{min: 3, max: 8, message: '长度在3-8个字符', trigger: 'blur'},
{validator: checkDuplicate, trigger: 'blur'}
],
name: [
{required: true, message: '请输入名字', trigger: 'blur'},
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'},
{min: 4, max: 10, message: '长度在4-10个字符之间', trigger: 'blur'}
],
age: [
{required: true, message: '请输入年龄', trigger: 'blur'},
{min: 1, max: 3, message: '长度在1到3个位', trigger: 'blur'},
{pattern: /^([1-9][0-9]*){1,3}$/, message: '年龄必须为正整数字', trigger: "blur"},
{validator: checkAge, trigger: 'blur'}
],
phone: [
{required: true, message: "手机号不能为空", trigger: "blur"},
{pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur"}
]
}
}
},
methods: {
add() {
this.centerDialogVisible = true
this.$nextTick(() => {
this.resetForm()
})
},
mod(row) {
//this.form=row就可以了
this.centerDialogVisible = true
this.$nextTick(() => {
this.form.id = row.id;
this.form.no = row.no;
this.form.name = row.name;
this.form.sex = row.sex + '';
this.form.age = row.age + '';//转化成字符串类型
this.form.phone = row.phone;
this.form.password = '';
this.form.roleId = row.roleId;
})//修改User的时候要确保账号不能修改,否则有可能会数据库存在账号相同的情况!!!!给账号的input里加个v-bind:disabled="isDisabled“,如果是修改就把isDisabled设置为true,添加就false
},
del(id) {
this.$axios.get(this.$httpUrl + '/user/del?id=' + id).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.loadPost();
} else {
this.$message({
message: '操作失败!请返回重新操作...',
type: 'error'
});
}
});
},
resetForm() {
this.centerDialogVisible = true
this.$refs.form.resetFields();
},
doSave() {
this.$axios.post(this.$httpUrl + '/user/save', this.form).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.centerDialogVisible = false
this.loadPost();
this.resetForm()
} else {
this.$message({
message: '操作失败!请返回重新操作...',
type: 'error'
});
}
});
},
doMod() {
this.$axios.post(this.$httpUrl + '/user/update', this.form).then(res => res.data).then(res => {
console.log(res);
if (res.code == 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.centerDialogVisible = false;
this.loadPost();
this.resetForm();
} else {
this.$message({
message: '操作失败!',
type: 'error'
});
}
});
},
save() {
this.$refs.form.validate((valid) => {
if (valid) {
if (this.form.id) {
this.doMod();
} else {
this.doSave();
}
} else {
console.log('error submit!!');
return false;
}
});
},
loadGet() {
this.$axios.get(this.$httpUrl + '/user/list').then(res => res.data).then(res => {
console.log(res)
})
},
loadPost() {
this.$axios.post(this.$httpUrl + '/user/listPageC1', {
pageSize: this.pageSize,
pageNum: this.pageNum,
param: {
name: this.name,
sex: this.sex,
roleId:'2'
}
}).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.tableData = res.data
this.total = res.total
} else {
alert('获取数据失败!请刷新页面')
}
})
},
resetParam() {
this.name = ''
this.sex = ''
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageNum = 1//这个错误是先翻到第二页在调页面条数,显示无数据
this.pageSize = val
this.loadPost()
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
this.pageNum = val
this.loadPost()
}
},
beforeMount() {
// this.loadGet();
this.loadPost()
}
}
</script>
二十八、仓库管理功能
在navicat中新建查询
DROP TABLE IF EXISTS `storage`;
CREATE TABLE `storage`(
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(100) NOT NULL COMMENT '仓库名',
`remark` varchar(1000) DEFAULT NULL COMMENT '备注',
PRIMARY KEY(`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
运行CodeGenerator,输入storage即可
在StorageMapper前面加一个Mapper
StorageController.java如下
package com.wms.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wms.common.QueryPageParam;
import com.wms.common.Result;
import com.wms.entity.Storage;
import com.wms.entity.User;
import com.wms.service.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
/**
* <p>
* 前端控制器
* </p>
*
* @author wms
* @since 2024-12-05
*/
@RestController
@RequestMapping("/storage")
public class StorageController {
@Autowired
private StorageService storageService;
//新增
@PostMapping("/save")
public Result save(@RequestBody Storage storage) {
return storageService.save(storage)?Result.success():Result.fail();
}
//更新
@PostMapping("/update")
public Result update(@RequestBody Storage storage) {
return storageService.updateById(storage)?Result.success():Result.fail();
}
/* //修改
@PostMapping("/mod")
public boolean mod(@RequestBody Storage storage) {
return storageService.updateById(storage);
}*/
@GetMapping("/del")
public Result del(@RequestParam String id) {
return storageService.removeById(id)?Result.success():Result.fail();
}
@PostMapping("/listPage")
//public List<User>listPage(@RequestBody HashMap map){
public Result listPage(@RequestBody QueryPageParam query) {
HashMap param = query.getParam();
String name = (String) param.get("name");
Page<Storage> page = new Page();
page.setCurrent(query.getPageNum());
page.setSize(query.getPageSize());
LambdaQueryWrapper<Storage> lambdaQueryWrapper = new LambdaQueryWrapper();
if(StringUtils.isNotBlank(name)&&!"null".equals(name)) {
lambdaQueryWrapper.like(Storage::getName, name);
}
IPage result=storageService.pageCC(page,lambdaQueryWrapper);
return Result.success(result.getRecords(),result.getTotal());
}
}
StorageService.java
package com.wms.service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.wms.entity.Storage;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 服务类
* </p>
*
* @author wms
* @since 2024-12-05
*/
public interface StorageService extends IService<Storage> {
IPage pageCC(IPage<Storage> page, Wrapper wrapper);
}
StorageServiceImpl
package com.wms.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.wms.entity.Storage;
import com.wms.entity.User;
import com.wms.mapper.StorageMapper;
import com.wms.service.StorageService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author wms
* @since 2024-12-05
*/
@Service
public class StorageServiceImpl extends ServiceImpl<StorageMapper, Storage> implements StorageService {
@Resource
private StorageMapper storageMapper;
@Override
public IPage<Storage> pageCC(IPage<Storage> page, Wrapper wrapper) {
return storageMapper.pageCC(page,wrapper);
}
}
Storagemapper.java
package com.wms.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.wms.entity.Storage;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wms.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* <p>
* Mapper 接口
* </p>
*
* @author wms
* @since 2024-12-05
*/
@Mapper
public interface StorageMapper extends BaseMapper<Storage> {
IPage pageCC(IPage<Storage> page, @Param(Constants.WRAPPER) Wrapper<Storage> wrapper);
}
resourse的mapper下属的StorageMapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wms.mapper.StorageMapper">
<select id="pageCC" resultType="com.wms.entity.Storage">
select * from storage ${ew.customSqlSegment}
</select>
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.wms.entity.Storage">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="remark" property="remark" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, name, remark
</sql>
</mapper>
二十九、物品分类功能
丢失了
三十、物品管理01
navicat查询一段
DROP TABLE IF EXISTS `goods`;
CREATE TABLE `goods` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(100) NOT NULL COMMENT '货名',
`storage` int(11) NOT NULL COMMENT '仓库',
`goodsType` int(11) NOT NULL COMMENT '分类',
`count` int(11) DEFAULT NULL COMMENT'数量',
`remark` varchar(1000) DEFAULT NULL COMMENT'备注',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
codegenerator新建一段goods,接下来是那5套代码
GoodsController.java
package com.wms.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wms.common.QueryPageParam;
import com.wms.common.Result;
import com.wms.entity.Goods;
import com.wms.entity.Storage;
import com.wms.service.GoodsService;
import com.wms.service.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
/**
* <p>
* 前端控制器
* </p>
*
* @author wms
* @since 2024-12-07
*/
@RestController
@RequestMapping("/goods")
public class GoodsController {
@Autowired
private GoodsService goodsService;
//新增
@PostMapping("/save")
public Result save(@RequestBody Goods goods) {
return goodsService.save(goods)?Result.success():Result.fail();
}
//更新
@PostMapping("/update")
public Result update(@RequestBody Goods goods) {
return goodsService.updateById(goods)?Result.success():Result.fail();
}
@GetMapping("/del")
public Result del(@RequestParam String id) {
return goodsService.removeById(id)?Result.success():Result.fail();
}
@PostMapping("/listPage")
public Result listPage(@RequestBody QueryPageParam query) {
HashMap param = query.getParam();
String name = (String) param.get("name");
Page<Goods> page = new Page();
page.setCurrent(query.getPageNum());
page.setSize(query.getPageSize());
LambdaQueryWrapper<Goods> lambdaQueryWrapper = new LambdaQueryWrapper();
if(StringUtils.isNotBlank(name)&&!"null".equals(name)) {
lambdaQueryWrapper.like(Goods::getName, name);
}
IPage result=goodsService.pageCC(page,lambdaQueryWrapper);
return Result.success(result.getRecords(),result.getTotal());
}
}
GoodServiceImpl.java
package com.wms.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.wms.entity.Goods;
import com.wms.mapper.GoodsMapper;
import com.wms.service.GoodsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author wms
* @since 2024-12-07
*/
@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements GoodsService {
@Resource
private GoodsMapper goodsMapper;
@Override
public IPage pageCC(IPage<Goods> page, Wrapper wrapper){
return goodsMapper.pageCC(page,wrapper);
}
}
GoodService.java即可
package com.wms.service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.wms.entity.Goods;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 服务类
* </p>
*
* @author wms
* @since 2024-12-07
*/
public interface GoodsService extends IService<Goods> {
IPage pageCC (IPage<Goods> page, Wrapper wrapper);
}
goodmapper
package com.wms.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.wms.entity.Goods;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* <p>
* Mapper 接口
* </p>
*
* @author wms
* @since 2024-12-07
*/
@Mapper
public interface GoodsMapper extends BaseMapper<Goods> {
IPage pageCC(IPage<Goods> page , @Param(Constants.WRAPPER) Wrapper wrapper);
}
GoodMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wms.mapper.GoodsMapper">
<select id="pageCC" resultType="com.wms.entity.Goods">
select * from goods ${ew.customSqlSegment}
</select>
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.wms.entity.Goods">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="storage" property="storage" />
<result column="goodsType" property="goodstype" />
<result column="count" property="count" />
<result column="remark" property="remark" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, name, storage, goodsType, count, remark
</sql>
</mapper>
接下来写前端新建goods/GoodsManage.vue
<template>
<div>
<div style="margin-left:5px">
<el-input v-model="name" placeholder="请输入物品名:" suffix-icon="el-icon-search" style="width:200px;"
@keyup.enter.native="loadPost"></el-input>
<el-button type="primary" style="margin-left:5px" @click="loadPost">查询</el-button>
<el-button type="success" @click="resetParam">重置</el-button>
<el-button type="primary" style="margin-left:5px" @click="add">新增</el-button>
</div>
<el-table :data="tableData"
:header-cell-style="{background:'#f2f5fc',color:'#555'}"
border
>
<el-table-column prop="id" label="ID" width="60">
</el-table-column>
<el-table-column prop="name" label="物品名" width="80">
</el-table-column>
<el-table-column prop="storage" label="仓库">
</el-table-column>
<el-table-column prop="goodstype" label="分类">
</el-table-column>
<el-table-column prop="count" label="数量">
</el-table-column>
<el-table-column prop="remark" label="备注">
</el-table-column>
<el-table-column prop="operate" label="操作">
<template slot-scope="scope">
<el-button size="small" type="success" @click="mod(scope.row)">编辑</el-button>
<el-popconfirm
title="确定删除吗?"
@confirm="del(scope.row.id)"
style="margin-left:8px;"
>
<el-button slot="reference" size="small" type="danger">删除</el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[5, 10, 20, 50]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
<el-dialog
title="提示"
:visible.sync="centerDialogVisible"
width="30%"
center>
<el-form ref="form" :rules="rules" :model="form" label-width="80px">
<el-form-item label="仓库名" prop="name">
<el-col :span="20">
<el-input v-model="form.name"></el-input>
</el-col>
</el-form-item>
<el-form-item label="仓库" prop="storage">
<el-col :span="20">
<el-input v-model="form.storage"></el-input>
</el-col>
</el-form-item>
<el-form-item label="分类" prop="goodstype">
<el-col :span="20">
<el-input v-model="form.goodstype"></el-input>
</el-col>
</el-form-item>
<el-form-item label="数量" prop="count">
<el-col :span="20">
<el-input v-model="form.count"></el-input>
</el-col>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-col :span="20">
<el-input type="textarea" v-model="form.remark"></el-input>
</el-col>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="centerDialogVisible=false">取消</el-button>
<el-button type="primary" @click="save">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<style scoped>
</style>
<script>
export default {
name: "GoodsManage",
data() {
let checkCount = (rule, value, callback) => {
if (value > 9999) {
callback(new Error('数量输入过大'));
} else {
callback();
}
};
return {
tableData: [],
pageSize: 10,
pageNum: 1,
total: 0,
name: '',
centerDialogVisible: false,
form: {
id: '',
name: '',
remark: '',
count: '',
storage: '',
goodstype: '',
},
rules: {
name: [
{required: true, message: '请输入物品名', trigger: 'blur'},
],
count: [
{required: true, message: '请输入数量', trigger: 'blur'},
{pattern: /^([1-9][0-9]*){1,4}$/, message: '数量必须为正整数', trigger: "blur"},
{validator: checkCount, trigger: 'blur'}
]
}
}
},
methods: {
add() {
this.centerDialogVisible = true
this.$nextTick(() => {
this.resetForm()
this.form.id = ''
})
},
mod(row) {
//this.form=row就可以了
this.centerDialogVisible = true
this.$nextTick(() => {
this.form.id = row.id;
this.form.remark = row.remark;
this.form.name = row.name;
this.form.storage = row.storage;
this.form.goodstype = row.goodstype;
this.form.count = row.count;
})
},
del(id) {
this.$axios.get(this.$httpUrl + '/goods/del?id=' + id).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.loadPost();
} else {
this.$message({
message: '操作失败!请返回重新操作...',
type: 'error'
});
}
});
},
resetForm() {
this.centerDialogVisible = true
this.$refs.form.resetFields();
this.form.id = '';
},
doSave() {
this.$axios.post(this.$httpUrl + '/goods/save', this.form).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.centerDialogVisible = false
this.loadPost();
this.resetForm()
} else {
this.$message({
message: '操作失败!请返回重新操作...',
type: 'error'
});
}
});
},
doMod() {
this.$axios.post(this.$httpUrl + '/goods/update', this.form).then(res => res.data).then(res => {
console.log(res);
if (res.code == 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.centerDialogVisible = false;
this.loadPost();
this.resetForm();
} else {
this.$message({
message: '操作失败!',
type: 'error'
});
}
});
},
save() {
this.$refs.form.validate((valid) => {
if (valid) {
if (this.form.id) {
this.doMod();
} else {
this.doSave();
}
} else {
console.log('error submit!!');
return false;
}
});
},
loadPost() {
this.$axios.post(this.$httpUrl + '/goods/listPage', {
pageSize: this.pageSize,
pageNum: this.pageNum,
param: {
name: this.name,
}
}).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.tableData = res.data
this.total = res.total
} else {
alert('获取数据失败!请刷新页面')
}
})
},
resetParam() {
this.name = ''
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageNum = 1//这个错误是先翻到第二页在调页面条数,显示无数据
this.pageSize = val
this.loadPost()
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
this.pageNum = val
this.loadPost()
}
},
beforeMount() {
this.loadPost()
}
}
</script>


三十一、物品管理02
在storageController添加
@GetMapping("/list")
public Result list() {
List list = storageService.list();
return Result.success(list);
}
是在user login的时候顺便查的menu,这里就另写了loadStorage方法
这么写就不用数据库写外键多表连接了,数据少可以用formatter,数据多还是要sql内联查询
数据库创建的时候已经定义了仓库为int(11)类型
GoodsManage.vue
<template>
<div>
<div style="margin-left:5px">
<el-input v-model="name" placeholder="请输入物品名:" suffix-icon="el-icon-search" style="width:200px;"
@keyup.enter.native="loadPost"></el-input>
<el-button type="primary" style="margin-left:5px" @click="loadPost">查询</el-button>
<el-button type="success" @click="resetParam">重置</el-button>
<el-button type="primary" style="margin-left:5px" @click="add">新增</el-button>
</div>
<el-table :data="tableData"
:header-cell-style="{background:'#f2f5fc',color:'#555'}"
border
>
<el-table-column prop="id" label="ID" width="60">
</el-table-column>
<el-table-column prop="name" label="物品名" width="80">
</el-table-column>
<el-table-column prop="storage" label="仓库" :formatter="formatStorage">
</el-table-column>
<el-table-column prop="goodstype" label="分类" :formatter="formatGoodsType">
</el-table-column>
<el-table-column prop="count" label="数量">
</el-table-column>
<el-table-column prop="remark" label="备注">
</el-table-column>
<el-table-column prop="operate" label="操作">
<template slot-scope="scope">
<el-button size="small" type="success" @click="mod(scope.row)">编辑</el-button>
<el-popconfirm
title="确定删除吗?"
@confirm="del(scope.row.id)"
style="margin-left:8px;"
>
<el-button slot="reference" size="small" type="danger">删除</el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[5, 10, 20, 50]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
<el-dialog
title="提示"
:visible.sync="centerDialogVisible"
width="30%"
center>
<el-form ref="form" :rules="rules" :model="form" label-width="80px">
<el-form-item label="仓库名" prop="name">
<el-col :span="20">
<el-input v-model="form.name"></el-input>
</el-col>
</el-form-item>
<el-form-item label="仓库" prop="storage">
<el-col :span="20">
<el-input v-model="form.storage"></el-input>
</el-col>
</el-form-item>
<el-form-item label="分类" prop="goodstype">
<el-col :span="20">
<el-input v-model="form.goodstype"></el-input>
</el-col>
</el-form-item>
<el-form-item label="数量" prop="count">
<el-col :span="20">
<el-input v-model="form.count"></el-input>
</el-col>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-col :span="20">
<el-input type="textarea" v-model="form.remark"></el-input>
</el-col>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="centerDialogVisible=false">取消</el-button>
<el-button type="primary" @click="save">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<style scoped>
</style>
<script>
export default {
name: "GoodsManage",
data() {
let checkCount = (rule, value, callback) => {
if (value > 9999) {
callback(new Error('数量输入过大'));
} else {
callback();
}
};
return {
storageData: [],
tableData: [],
GoodsTypeData: [],
pageSize: 10,
pageNum: 1,
total: 0,
name: '',
centerDialogVisible: false,
form: {
id: '',
name: '',
remark: '',
count: '',
storage: '',
goodstype: '',
},
rules: {
name: [
{required: true, message: '请输入物品名', trigger: 'blur'},
],
count: [
{required: true, message: '请输入数量', trigger: 'blur'},
{pattern: /^([1-9][0-9]*){1,4}$/, message: '数量必须为正整数', trigger: "blur"},
{validator: checkCount, trigger: 'blur'}
]
}
}
},
methods: {
formatStorage(row) {
let temp = this.storageData.find(item => {
return item.id === row.storage
})
return temp && temp.name
},
formatGoodsType(row) {
let temp = this.GoodsTypeData.find(item => {
return item.id === row.goodstype
})
return temp && temp.name
},
add() {
this.centerDialogVisible = true
this.$nextTick(() => {
this.resetForm()
this.form.id = ''
})
},
mod(row) {
//this.form=row就可以了
this.centerDialogVisible = true
this.$nextTick(() => {
this.form.id = row.id;
this.form.remark = row.remark;
this.form.name = row.name;
this.form.storage = row.storage;
this.form.goodstype = row.goodstype;
this.form.count = row.count;
})
},
del(id) {
this.$axios.get(this.$httpUrl + '/goods/del?id=' + id).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.loadPost();
} else {
this.$message({
message: '操作失败!请返回重新操作...',
type: 'error'
});
}
});
},
resetForm() {
this.centerDialogVisible = true
this.$refs.form.resetFields();
this.form.id = '';
},
doSave() {
this.$axios.post(this.$httpUrl + '/goods/save', this.form).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.centerDialogVisible = false
this.loadPost();
this.resetForm()
} else {
this.$message({
message: '操作失败!请返回重新操作...',
type: 'error'
});
}
});
},
doMod() {
this.$axios.post(this.$httpUrl + '/goods/update', this.form).then(res => res.data).then(res => {
console.log(res);
if (res.code == 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.centerDialogVisible = false;
this.loadPost();
this.resetForm();
} else {
this.$message({
message: '操作失败!',
type: 'error'
});
}
});
},
save() {
this.$refs.form.validate((valid) => {
if (valid) {
if (this.form.id) {
this.doMod();
} else {
this.doSave();
}
} else {
console.log('error submit!!');
return false;
}
});
},
loadPost() {
this.$axios.post(this.$httpUrl + '/goods/listPage', {
pageSize: this.pageSize,
pageNum: this.pageNum,
param: {
name: this.name,
}
}).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.tableData = res.data
this.total = res.total
} else {
alert('获取数据失败!请刷新页面')
}
})
},
loadStorage() {
this.$axios.get(this.$httpUrl + '/storage/list').then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.storageData = res.data
} else {
alert('获取数据失败!请刷新页面')
}
})
},
loadGoodsType() {
this.$axios.get(this.$httpUrl + '/goodstype/list').then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.GoodsTypeData = res.data
} else {
alert('获取数据失败!请刷新页面')
}
})
},
resetParam() {
this.name = ''
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageNum = 1//这个错误是先翻到第二页在调页面条数,显示无数据
this.pageSize = val
this.loadPost()
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
this.pageNum = val
this.loadPost()
}
},
beforeMount() {
this.loadStorage()
this.loadGoodsType()
this.loadPost()
}
}
</script>
GoodstypeController下新加方法
@GetMapping("/list")
public Result list(){
List list =goodstypeService.list();
return Result.success(list);
}
接着修改GoodsManage.vue
<template>
<div>
<div style="margin-left:5px">
<el-input v-model="name" placeholder="请输入物品名:" suffix-icon="el-icon-search" style="width:200px;"
@keyup.enter.native="loadPost"></el-input>
<el-select v-model="storage" placehoLder="请选择仓库" style="margin-left: 5px;">
<el-option
v-for="item in storageData"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
<el-select v-model="goodstype" placeholder="请选择分类" style="margin-left: 5px;">
<el-option
v-for="item in goodstypeData"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
<el-button type="primary" style="margin-left:5px" @click="loadPost">查询</el-button>
<el-button type="success" @click="resetParam">重置</el-button>
<el-button type="primary" style="margin-left:5px" @click="add">新增</el-button>
</div>
<el-table :data="tableData"
:header-cell-style="{background:'#f2f5fc',color:'#555'}"
border
>
<el-table-column prop="id" label="ID" width="60">
</el-table-column>
<el-table-column prop="name" label="物品名" width="80">
</el-table-column>
<el-table-column prop="storage" label="仓库" :formatter="formatStorage">
</el-table-column>
<el-table-column prop="goodstype" label="分类" :formatter="formatGoodsType">
</el-table-column>
<el-table-column prop="count" label="数量">
</el-table-column>
<el-table-column prop="remark" label="备注">
</el-table-column>
<el-table-column prop="operate" label="操作">
<template slot-scope="scope">
<el-button size="small" type="success" @click="mod(scope.row)">编辑</el-button>
<el-popconfirm
title="确定删除吗?"
@confirm="del(scope.row.id)"
style="margin-left:8px;"
>
<el-button slot="reference" size="small" type="danger">删除</el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[5, 10, 20, 50]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
<el-dialog
title="提示"
:visible.sync="centerDialogVisible"
width="30%"
center>
<el-form ref="form" :rules="rules" :model="form" label-width="80px">
<el-form-item label="物品名" prop="name">
<el-col :span="20">
<el-input v-model="form.name"></el-input>
</el-col>
</el-form-item>
<el-form-item label="仓库" prop="storage">
<el-col :span="20">
<el-select v-model="form.storage" placehoLder="请选择仓库" style="margin-left: 5px;">
<el-option
v-for="item in storageData"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-col>
</el-form-item>
<el-form-item label="分类" prop="goodstype">
<el-col :span="20">
<el-select v-model="form.goodstype" placeholder="请选择分类" style="margin-left: 5px;">
<el-option
v-for="item in goodstypeData"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-col>
</el-form-item>
<el-form-item label="数量" prop="count">
<el-col :span="20">
<el-input v-model="form.count"></el-input>
</el-col>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-col :span="20">
<el-input type="textarea" v-model="form.remark"></el-input>
</el-col>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="centerDialogVisible=false">取消</el-button>
<el-button type="primary" @click="save">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<style scoped>
</style>
<script>
export default {
name: "GoodsManage",
data() {
let checkCount = (rule, value, callback) => {
if (value > 9999) {
callback(new Error('数量输入过大'));
} else {
callback();
}
};
return {
storageData: [],
tableData: [],
goodstypeData: [],
pageSize: 10,
pageNum: 1,
storage: '',
goodstype: '',
total: 0,
name: '',
centerDialogVisible: false,
form: {
id: '',
name: '',
remark: '',
count: '',
storage: '',
goodstype: '',
},
rules: {
name: [
{required: true, message: '请输入物品名', trigger: 'blur'},
],
storage:[
{required:true,message:'请选择仓库',trigger:'blur'}
],
goodstype:[
{required:true,message:'请选择分类’,trigger:‘blur'}
],
count: [
{required: true, message: '请输入数量', trigger: 'blur'},
{pattern: /^([1-9][0-9]*){1,4}$/, message: '数量必须为正整数', trigger: "blur"},
{validator: checkCount, trigger: 'blur'}
]
}
}
},
methods: {
formatStorage(row) {
let temp = this.storageData.find(item => {
return item.id === row.storage
})
return temp && temp.name
},
formatGoodsType(row) {
let temp = this.goodstypeData.find(item => {
return item.id === row.goodstype
})
return temp && temp.name
},
add() {
this.centerDialogVisible = true
this.$nextTick(() => {
this.resetForm()
this.form.id = ''
})
},
mod(row) {
//this.form=row就可以了
this.centerDialogVisible = true
this.$nextTick(() => {
this.form.id = row.id;
this.form.remark = row.remark;
this.form.name = row.name;
this.form.storage = row.storage;
this.form.goodstype = row.goodstype;
this.form.count = row.count;
})
},
del(id) {
this.$axios.get(this.$httpUrl + '/goods/del?id=' + id).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.loadPost();
} else {
this.$message({
message: '操作失败!请返回重新操作...',
type: 'error'
});
}
});
},
resetForm() {
this.centerDialogVisible = true
this.$refs.form.resetFields();
this.form.id = '';
},
doSave() {
this.$axios.post(this.$httpUrl + '/goods/save', this.form).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.centerDialogVisible = false
this.loadPost();
this.resetForm()
} else {
this.$message({
message: '操作失败!请返回重新操作...',
type: 'error'
});
}
});
},
doMod() {
this.$axios.post(this.$httpUrl + '/goods/update', this.form).then(res => res.data).then(res => {
console.log(res);
if (res.code == 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.centerDialogVisible = false;
this.loadPost();
this.resetForm();
} else {
this.$message({
message: '操作失败!',
type: 'error'
});
}
});
},
save() {
this.$refs.form.validate((valid) => {
if (valid) {
if (this.form.id) {
this.doMod();
} else {
this.doSave();
}
} else {
console.log('error submit!!');
return false;
}
});
},
loadPost() {
this.$axios.post(this.$httpUrl + '/goods/listPage', {
pageSize: this.pageSize,
pageNum: this.pageNum,
param: {
name: this.name,
goodstype: this.goodstype + '',//string和int强转一下
storage: this.storage + ''
}
}).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.tableData = res.data
this.total = res.total
} else {
alert('获取数据失败!请刷新页面')
}
})
},
loadStorage() {
this.$axios.get(this.$httpUrl + '/storage/list').then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.storageData = res.data
} else {
alert('获取数据失败!请刷新页面')
}
})
},
loadGoodsType() {
this.$axios.get(this.$httpUrl + '/goodstype/list').then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.goodstypeData = res.data
} else {
alert('获取数据失败!请刷新页面')
}
})
},
resetParam() {
this.name = ''
this.storage = ''
this.goodstype = ''
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageNum = 1//这个错误是先翻到第二页在调页面条数,显示无数据
this.pageSize = val
this.loadPost()
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
this.pageNum = val
this.loadPost()
}
},
beforeMount() {
this.loadStorage()
this.loadGoodsType()
this.loadPost()
}
}
</script>
后端接受一下GoodsControlller.java
package com.wms.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wms.common.QueryPageParam;
import com.wms.common.Result;
import com.wms.entity.Goods;
import com.wms.entity.Storage;
import com.wms.service.GoodsService;
import com.wms.service.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
/**
* <p>
* 前端控制器
* </p>
*
* @author wms
* @since 2024-12-07
*/
@RestController
@RequestMapping("/goods")
public class GoodsController {
@Autowired
private GoodsService goodsService;
//新增
@PostMapping("/save")
public Result save(@RequestBody Goods goods) {
return goodsService.save(goods)?Result.success():Result.fail();
}
//更新
@PostMapping("/update")
public Result update(@RequestBody Goods goods) {
return goodsService.updateById(goods)?Result.success():Result.fail();
}
@GetMapping("/del")
public Result del(@RequestParam String id) {
return goodsService.removeById(id)?Result.success():Result.fail();
}
@PostMapping("/listPage")
public Result listPage(@RequestBody QueryPageParam query) {
HashMap param = query.getParam();
String name = (String) param.get("name");
String storage = (String) param.get("storage");
String goodstype = (String) param.get("goodstype");
Page<Goods> page = new Page();
page.setCurrent(query.getPageNum());
page.setSize(query.getPageSize());
LambdaQueryWrapper<Goods> lambdaQueryWrapper = new LambdaQueryWrapper();
if(StringUtils.isNotBlank(name)&&!"null".equals(name)) {
lambdaQueryWrapper.like(Goods::getName, name);
}
if(StringUtils.isNotBlank(storage)&&!"null".equals(storage)) {
lambdaQueryWrapper.eq(Goods::getStorage, storage);
}
if(StringUtils.isNotBlank(goodstype)&&!"null".equals(goodstype)) {
lambdaQueryWrapper.eq(Goods::getGoodstype, goodstype);
}
IPage result=goodsService.pageCC(page,lambdaQueryWrapper);
return Result.success(result.getRecords(),result.getTotal());
}
}
三十二、记录管理
DROP TABLE IF EXISTS `record`;
CREATE TABLE `record` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`goods` int(11) NOT NULL COMMENT '货品id',
`userId` int(11) DEFAULT NULL COMMENT '取货人/补货人',
`admin_id` int(11) DEFAULT NULL COMMENT '操作人id',
`count` int(11) DEFAULT NULL COMMENT '数量',
`createtime` datetime DEFAULT NULL COMMENT '操作时间',
`remark` varchar(1000) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
提前设一个 record 记录
接下来依旧时那5个代码
package com.wms.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wms.common.QueryPageParam;
import com.wms.common.Result;
import com.wms.entity.Goods;
import com.wms.entity.Record;
import com.wms.service.RecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
/**
* <p>
* 前端控制器
* </p>
*
* @author wms
* @since 2024-12-07
*/
@RestController
@RequestMapping("/record")
public class RecordController {
@Autowired
private RecordService recordService;
@PostMapping("/listPage")
public Result listPage(@RequestBody QueryPageParam query) {
HashMap param = query.getParam();
String name = (String) param.get("name");
String storage = (String) param.get("storage");
String goodstype = (String) param.get("goodstype");
Page<Record> page = new Page();
page.setCurrent(query.getPageNum());
page.setSize(query.getPageSize());
LambdaQueryWrapper<Record> lambdaQueryWrapper = new LambdaQueryWrapper();
if(StringUtils.isNotBlank(name)&&!"null".equals(name)) {
//lambdaQueryWrapper.like(Record::getName, name);
}
if(StringUtils.isNotBlank(storage)&&!"null".equals(storage)) {
//lambdaQueryWrapper.eq(Record::getStorage, storage);
}
if(StringUtils.isNotBlank(goodstype)&&!"null".equals(goodstype)) {
//lambdaQueryWrapper.eq(Record::getGoodstype, goodstype);
}
IPage result=recordService.pageCC(page,lambdaQueryWrapper);
return Result.success(result.getRecords(),result.getTotal());
}
}
package com.wms.service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.wms.entity.Record;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 服务类
* </p>
*
* @author wms
* @since 2024-12-07
*/
public interface RecordService extends IService<Record> {
IPage pageCC(IPage<Record> page, Wrapper wrapper);
}
package com.wms.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.wms.entity.Record;
import com.wms.mapper.RecordMapper;
import com.wms.service.RecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author wms
* @since 2024-12-07
*/
@Service
public class RecordServiceImpl extends ServiceImpl<RecordMapper, Record> implements RecordService {
@Resource
private RecordMapper recordMapper;
@Override
public IPage pageCC(IPage<Record> page, Wrapper wrapper) {
return recordMapper.pageCC(page, wrapper);
}
}
package com.wms.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.wms.entity.Record;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* <p>
* Mapper 接口
* </p>
*
* @author wms
* @since 2024-12-07
*/
@Mapper
public interface RecordMapper extends BaseMapper<Record> {
IPage pageCC(IPage<Record> page, @Param(Constants.WRAPPER) Wrapper wrapper);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wms.mapper.RecordMapper">
<select id="pageCC" resultType="com.wms.entity.Record">
select * from record ${ew.customSqlSegment}
</select>
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.wms.entity.Record">
<id column="id" property="id" />
<result column="goods" property="goods" />
<result column="userId" property="userid" />
<result column="admin_id" property="adminId" />
<result column="count" property="count" />
<result column="createtime" property="createtime" />
<result column="remark" property="remark" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, goods, userId, admin_id, count, createtime, remark
</sql>
</mapper>

!!!!!!!!!!!!!!!!!!!!!!!!!!!这里写点话大概16.00-19.30
RecordMapper.xml修改为
<select id="pageCC" resultType="com.wms.entity.RecordRes">
select
a.*,
(select u.name from user u where u.id=a.userid) as username,
(select u.name from user u where u.id=a.admin_id) as adminname
from record a
${ew.customSqlSegment}
</select>
在entity中添加RecordRes
package com.wms.entity;
import lombok.Data;
@Data
public class RecordRes extends Record{
private String username;
private String adminname;
}
接下来弄前面三个 RecordMapper.java
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wms.mapper.RecordMapper">
<select id="pageCC" resultType="com.wms.entity.RecordRes">
select a.*,b.name goodsname,c.name storagename,d.name goodstypename,
(select u.name from user u where u.id=a.userid)username,
(select u.name from user u where u.id=a.admin_id)adminname
from record a ,goods b,storage c,goodsType d where a.goods=b.id
and b.storage=c.id and b.goodsType=d.id
${ew.customSqlSegment}
</select>
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.wms.entity.Record">
<id column="id" property="id" />
<result column="goods" property="goods" />
<result column="userId" property="userid" />
<result column="admin_id" property="adminId" />
<result column="count" property="count" />
<result column="createtime" property="createtime" />
<result column="remark" property="remark" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, goods, userId, admin_id, count, createtime, remark
</sql>
</mapper>
完全不建议这么写sql,直接在代码层取到所有的key,然后分别去查各个表,这样在企业中,即使换另一个开发过来维护,也更清晰些
RecordRes.java新加几条
package com.wms.entity; import lombok.Data; @Data public class RecordRes extends Record{ private String username; private String adminname; private String goodsname; private String storagename; private String goodstypename; }
修改RecordManage.vue,添加几个变量使得适配
<el-table-column prop="id" label="ID" width="60">
</el-table-column>
<el-table-column prop="goodsname" label="物品名" width="80">
</el-table-column>
<el-table-column prop="storagename" label="仓库" >
</el-table-column>
<el-table-column prop="goodstypename" label="分类" >
</el-table-column>
<el-table-column prop="adminname" label="操作人" >
</el-table-column>
<el-table-column prop="username" label="申请人" >
</el-table-column>
<el-table-column prop="count" label="数量">
</el-table-column>
<el-table-column prop="createtime" label="操作时间">
</el-table-column>
<el-table-column prop="remark" label="备注">
</el-table-column>
RecordController.java
package com.wms.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wms.common.QueryPageParam;
import com.wms.common.Result;
import com.wms.entity.Goods;
import com.wms.entity.Record;
import com.wms.service.RecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
/**
* <p>
* 前端控制器
* </p>
*
* @author wms
* @since 2024-12-07
*/
@RestController
@RequestMapping("/record")
public class RecordController {
@Autowired
private RecordService recordService;
@PostMapping("/listPage")
public Result listPage(@RequestBody QueryPageParam query) {
HashMap param = query.getParam();
String name = (String) param.get("name");
String storage = (String) param.get("storage");
String goodstype = (String) param.get("goodstype");
Page<Record> page = new Page();
page.setCurrent(query.getPageNum());
page.setSize(query.getPageSize());
QueryWrapper<Record> queryWrapper = new QueryWrapper();
queryWrapper.apply(" a.goods=b.id and b.storage=c.id and b.goodsType=d.id ");
if(StringUtils.isNotBlank(name)&&!"null".equals(name)) {
//lambdaQueryWrapper.like(Record::getName, name);
queryWrapper.like("b.name",name);
}
if(StringUtils.isNotBlank(storage)&&!"null".equals(storage)) {
//lambdaQueryWrapper.eq(Record::getStorage, storage);
}
if(StringUtils.isNotBlank(goodstype)&&!"null".equals(goodstype)) {
//lambdaQueryWrapper.eq(Record::getGoodstype, goodstype);
}
IPage result=recordService.pageCC(page,QueryWrapper);
return Result.success(result.getRecords(),result.getTotal());
}
}
与此同时,把RecordMapper.xml的 这一段注释掉.
/*where a.goods=b.id and b.storage=c.id and b.goodsType=d.id*/
继续配套的写后端,最后5min讲了一下
package com.wms.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wms.common.QueryPageParam;
import com.wms.common.Result;
import com.wms.entity.Goods;
import com.wms.entity.Record;
import com.wms.service.RecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
/**
* <p>
* 前端控制器
* </p>
*
* @author wms
* @since 2024-12-07
*/
@RestController
@RequestMapping("/record")
public class RecordController {
@Autowired
private RecordService recordService;
@PostMapping("/listPage")
public Result listPage(@RequestBody QueryPageParam query) {
HashMap param = query.getParam();
String name = (String) param.get("name");
String storage = (String) param.get("storage");
String goodstype = (String) param.get("goodstype");
Page<Record> page = new Page();
page.setCurrent(query.getPageNum());
page.setSize(query.getPageSize());
QueryWrapper<Record> queryWrapper = new QueryWrapper();
queryWrapper.apply(" a.goods=b.id and b.storage=c.id and b.goodsType=d.id ");
if(StringUtils.isNotBlank(name)&&!"null".equals(name)) {
//lambdaQueryWrapper.like(Record::getName, name);
queryWrapper.like("b.name",name);
}
if(StringUtils.isNotBlank(storage)&&!"null".equals(storage)) {
queryWrapper.eq("c.id",storage);
}
if(StringUtils.isNotBlank(goodstype)&&!"null".equals(goodstype)) {
queryWrapper.eq("d.id",goodstype);
}
IPage result=recordService.pageCC(page,queryWrapper);
return Result.success(result.getRecords(),result.getTotal());
}
}
RecordController.vue
<template>
<div>
<div style="margin-left:5px">
<el-input v-model="name" placeholder="请输入物品名:" suffix-icon="el-icon-search" style="width:200px;"
@keyup.enter.native="loadPost"></el-input>
<el-select v-model="storage" placehoLder="请选择仓库" style="margin-left: 5px;">
<el-option
v-for="item in storageData"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
<el-select v-model="goodstype" placeholder="请选择分类" style="margin-left: 5px;">
<el-option
v-for="item in goodstypeData"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
<el-button type="primary" style="margin-left:5px" @click="loadPost">查询</el-button>
<el-button type="success" @click="resetParam">重置</el-button>
</div>
<el-table :data="tableData"
:header-cell-style="{background:'#f2f5fc',color:'#555'}"
border
>
<el-table-column prop="id" label="ID" width="60">
</el-table-column>
<el-table-column prop="goodsname" label="物品名" width="80">
</el-table-column>
<el-table-column prop="storagename" label="仓库" >
</el-table-column>
<el-table-column prop="goodstypename" label="分类" >
</el-table-column>
<el-table-column prop="adminname" label="操作人" >
</el-table-column>
<el-table-column prop="username" label="申请人" >
</el-table-column>
<el-table-column prop="count" label="数量">
</el-table-column>
<el-table-column prop="createtime" label="操作时间">
</el-table-column>
<el-table-column prop="remark" label="备注">
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[5, 10, 20, 50]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</template>
<style scoped>
</style>
<script>
export default {
name: "RecordManage",
data() {
return {
storageData: [],
tableData: [],
goodstypeData: [],
pageSize: 10,
pageNum: 1,
storage: '',
goodstype: '',
total: 0,
name: '',
centerDialogVisible: false,
form: {
id: '',
name: '',
remark: '',
count: '',
storage: '',
goodstype: '',
},
}
},
methods: {
formatStorage(row) {
let temp = this.storageData.find(item => {
return item.id === row.storage
})
return temp && temp.name
},
formatGoodsType(row) {
let temp = this.goodstypeData.find(item => {
return item.id === row.goodstype
})
return temp && temp.name
},
add() {
this.centerDialogVisible = true
this.$nextTick(() => {
this.resetForm()
this.form.id = ''
})
},
mod(row) {
//this.form=row就可以了
this.centerDialogVisible = true
this.$nextTick(() => {
this.form.id = row.id;
this.form.remark = row.remark;
this.form.name = row.name;
this.form.storage = row.storage;
this.form.goodstype = row.goodstype;
this.form.count = row.count;
})
},
del(id) {
this.$axios.get(this.$httpUrl + '/goods/del?id=' + id).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.loadPost();
} else {
this.$message({
message: '操作失败!请返回重新操作...',
type: 'error'
});
}
});
},
resetForm() {
this.centerDialogVisible = true
this.$refs.form.resetFields();
this.form.id = '';
},
doSave() {
this.$axios.post(this.$httpUrl + '/goods/save', this.form).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.centerDialogVisible = false
this.loadPost();
this.resetForm()
} else {
this.$message({
message: '操作失败!请返回重新操作...',
type: 'error'
});
}
});
},
doMod() {
this.$axios.post(this.$httpUrl + '/goods/update', this.form).then(res => res.data).then(res => {
console.log(res);
if (res.code == 200) {
this.$message({
message: '操作成功!',
type: 'success'
});
this.centerDialogVisible = false;
this.loadPost();
this.resetForm();
} else {
this.$message({
message: '操作失败!',
type: 'error'
});
}
});
},
save() {
this.$refs.form.validate((valid) => {
if (valid) {
if (this.form.id) {
this.doMod();
} else {
this.doSave();
}
} else {
console.log('error submit!!');
return false;
}
});
},
loadPost() {
this.$axios.post(this.$httpUrl + '/record/listPage', {
pageSize: this.pageSize,
pageNum: this.pageNum,
param: {
name: this.name,
goodstype: this.goodstype + '',//string和int强转一下
storage: this.storage + ''
}
}).then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.tableData = res.data
this.total = res.total
} else {
alert('获取数据失败!请刷新页面')
}
})
},
loadStorage() {
this.$axios.get(this.$httpUrl + '/storage/list').then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.storageData = res.data
} else {
alert('获取数据失败!请刷新页面')
}
})
},
loadGoodsType() {
this.$axios.get(this.$httpUrl + '/goodstype/list').then(res => res.data).then(res => {
console.log(res)
if (res.code === 200) {
this.goodstypeData = res.data
} else {
alert('获取数据失败!请刷新页面')
}
})
},
resetParam() {
this.name = ''
this.storage = ''
this.goodstype = ''
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageNum = 1//这个错误是先翻到第二页在调页面条数,显示无数据
this.pageSize = val
this.loadPost()
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
this.pageNum = val
this.loadPost()
}
},
beforeMount() {
this.loadGoodsType()
this.loadStorage()
this.loadPost()
}
}
</script>
Comments NOTHING