非常简单实用的前后端分离项目-仓库管理系统(Springboot+Vue)part 3

eve2333 发布于 2024-12-10 94 次阅读


 二十二、登录

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>