《苍穹外卖》前端课程知识点记录

慈云数据 2024-05-09 技术支持 35 0

一、VUE基础知识

基于脚手架创建前端工程

1. 环境要求

安装node.js:Node.js安装与配置(详细步骤)_nodejs安装及环境配置-CSDN博客
查看node和npm的版本号

安装Vue CLI:Vue.js安装与创建默认项目(详细步骤)_nodejs安装及环境配置-CSDN博客

查看vue版本

使用Vue CLI创建前端工程

  • 方式一:vue create项目名称

      ① 创建一个不带中文的文件夹,如下图:

    ② 创建工程---选择Vue 2

    ③ 选择npm

    ④ 如果中间有报错,如下:

    npm ERR! code EPERM

    npm ERR! syscall mkdir

    npm ERR! path C:\Program Files\nodejs\node_cache\_cacache\index-v5\ee\aa

    npm ERR! errno -4048

    npm ERR! Error: EPERM: operation not permitted, mkdir 'C:\Program Files\nodejs\node_cache\_cacache\index-v5\ee\aa'

    找到nodejs的安装目录,右击属性->安全->编辑->把所有权限都勾选上

    ⑤ 结果:

    • 方式二:vue ui

      ①打开ui界面

      ② 点击创建

      ③ 填写项目信息

      ④ 选择vue2,创建项目

      ⑤结果:

      项目结构

      运行项目

      npm run serve

      命令的最后一个单词并不是固定的,与package.json下写的这一项相关,如下

      如果8080端口号被占用,可以在vue.config.js中更改端口号

      如果上面这种方式不起作用的,可以到项目对应文件夹用cmd试试

      退出运行:Ctrl + C

      vue基本使用方式

      Vue组件(Vue2)

      Vue的组件文件以.vue结尾,每个组件由三部分组成:结构、样式、逻辑。

      示例

      Vue 2:一个Vue组件的模板只能有一个根元素。这是因为Vue 2使用的是基于AST(抽象语法树)的模板编译方式,需要将模板编译为render函数,而render函数只能返回一个根节点。

      Vue 3 : Vue的模板编译器进行了重大改进,支持多个根元素。Vue 3使用了基于编译器的模板编译方式,这意味着在Vue 3中,一个组件的模板可以有多个根元素,而不再需要包裹在一个单独的根元素内。

      文本插值

      作用:用来绑定 data 方法返回的对象属性

      用法:{{}}

      属性绑定

      作用:为标签的属性绑定data方法中返回的属性

      用法:v-bind:xxx,简写为 :xxx

      事件绑定

      作用:为元素绑定对应的事件

      用法:v-on:xxx,简写为@xxx

      双向绑定

      作用:表单输入项和data方法中的属性进行绑定,任意一方改变都会同步给另一方

      用法:v-model

      条件渲染

      作用:根据表达式的值来动态渲染页面元素

      用法:v-if、v-else、v-else-if

      axios

      Axios是一个基于promise的网络请求库,作用于浏览器和node.js中

      安装命令:npm install axios

      导入命令:import axios from 'axios'

      axios的API列表:

      请求备注
      axios.get(url[, config])
      axios.delete(url[, config])
      axios.head(url[, config])
      axios.options(url[, config])
      axios.post(url[, data[, config]])
      axios.put(url, data[, config]])
      axios.patch(url[, data[, config]])

      参数说明:

      • url:请求路径
      • data:请求体数据,最常见的是JSON格式数据
      • config:配置对象,可以设置查询参数、请求体信息

        为了解决跨域问题,可以在vue.config.js文件中配置代理:

         axios统一使用方式:axios(config)

        请求配置

        网址:请求配置 | Axios中文文档 | Axios中文网 (axios-http.cn)

        {
          // `url` 是用于请求的服务器 URL
          url: '/user',
          // `method` 是创建请求时使用的方法
          method: 'get', // 默认值
          // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
          // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
          baseURL: 'https://some-domain.com/api/',
          // `transformRequest` 允许在向服务器发送前,修改请求数据
          // 它只能用于 'PUT', 'POST' 和 'PATCH' 这几个请求方法
          // 数组中最后一个函数必须返回一个字符串, 一个Buffer实例,ArrayBuffer,FormData,或 Stream
          // 你可以修改请求头。
          transformRequest: [function (data, headers) {
            // 对发送的 data 进行任意转换处理
            return data;
          }],
          // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
          transformResponse: [function (data) {
            // 对接收的 data 进行任意转换处理
            return data;
          }],
          // 自定义请求头
          headers: {'X-Requested-With': 'XMLHttpRequest'},
          // `params` 是与请求一起发送的 URL 参数
          // 必须是一个简单对象或 URLSearchParams 对象
          params: {
            ID: 12345
          },
          // `paramsSerializer`是可选方法,主要用于序列化`params`
          // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
          paramsSerializer: function (params) {
            return Qs.stringify(params, {arrayFormat: 'brackets'})
          },
          // `data` 是作为请求体被发送的数据
          // 仅适用 'PUT', 'POST', 'DELETE 和 'PATCH' 请求方法
          // 在没有设置 `transformRequest` 时,则必须是以下类型之一:
          // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
          // - 浏览器专属: FormData, File, Blob
          // - Node 专属: Stream, Buffer
          data: {
            firstName: 'Fred'
          },
          
          // 发送请求体数据的可选语法
          // 请求方式 post
          // 只有 value 会被发送,key 则不会
          data: 'Country=Brasil&City=Belo Horizonte',
          // `timeout` 指定请求超时的毫秒数。
          // 如果请求时间超过 `timeout` 的值,则请求会被中断
          timeout: 1000, // 默认值是 `0` (永不超时)
          // `withCredentials` 表示跨域请求时是否需要使用凭证
          withCredentials: false, // default
          // `adapter` 允许自定义处理请求,这使测试更加容易。
          // 返回一个 promise 并提供一个有效的响应 (参见 lib/adapters/README.md)。
          adapter: function (config) {
            /* ... */
          },
          // `auth` HTTP Basic Auth
          auth: {
            username: 'janedoe',
            password: 's00pers3cret'
          },
          // `responseType` 表示浏览器将要响应的数据类型
          // 选项包括: 'arraybuffer', 'document', 'json', 'text', 'stream'
          // 浏览器专属:'blob'
          responseType: 'json', // 默认值
          // `responseEncoding` 表示用于解码响应的编码 (Node.js 专属)
          // 注意:忽略 `responseType` 的值为 'stream',或者是客户端请求
          // Note: Ignored for `responseType` of 'stream' or client-side requests
          responseEncoding: 'utf8', // 默认值
          // `xsrfCookieName` 是 xsrf token 的值,被用作 cookie 的名称
          xsrfCookieName: 'XSRF-TOKEN', // 默认值
          // `xsrfHeaderName` 是带有 xsrf token 值的http 请求头名称
          xsrfHeaderName: 'X-XSRF-TOKEN', // 默认值
          // `onUploadProgress` 允许为上传处理进度事件
          // 浏览器专属
          onUploadProgress: function (progressEvent) {
            // 处理原生进度事件
          },
          // `onDownloadProgress` 允许为下载处理进度事件
          // 浏览器专属
          onDownloadProgress: function (progressEvent) {
            // 处理原生进度事件
          },
          // `maxContentLength` 定义了node.js中允许的HTTP响应内容的最大字节数
          maxContentLength: 2000,
          // `maxBodyLength`(仅Node)定义允许的http请求内容的最大字节数
          maxBodyLength: 2000,
          // `validateStatus` 定义了对于给定的 HTTP状态码是 resolve 还是 reject promise。
          // 如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),
          // 则promise 将会 resolved,否则是 rejected。
          validateStatus: function (status) {
            return status >= 200 && status  
         
        

        示例——配置代理

        记得要先运行后端服务,启动redis

        HelloWorld.vue

          
            
            
            
          
        
        
        import axiox from 'axios'
        export default {
          name: 'HelloWorld',
          props: {
            msg: String
          },
          methods: {
            handleSendPOST() {
              // 通过axios发送异域POST方式的http请求
              axiox.post('/api/admin/employee/login', {
                username: 'admin',
                password: '123456'
              }).then(res => {
                console.log(res.data)
              }).catch(error => {
                console.log(error.response)
              })
            },
            handleSendGET() {
              // 通过axios发送GET方式请求
              axiox.get('/api/admin/shop/status', {
                headers: {
                  token: 'eyJhbGciOiJIUzI1NiJ9.eyJlbXBJZCI6MSwiZXhwIjoxNzE0MzIyNDAyfQ.gMfQXajaBTKnMuz19_BsmhWLGWov24rqZDLcPLwZCSA'
                }
              }).then(res => {
                console.log(res.data)
              })
            },
            handleSend() {
              // 使用axios提供的统一调用方式发送请求
              axiox({
                url: '/api/admin/employee/login',
                method: 'post',
                data: {  // data表示通过请求体传参
                  username: 'admin',
                  password: '123456'
                }
              }).then(res => {
                console.log(res.data.data.token)
                axiox({
                  url: '/api/admin/shop/status',
                  method: 'get',
                  headers: {
                    token: res.data.data.token
                  }
                })
              })
            }
          }
        }
        
        
        
        h3 {
          margin: 40px 0 0;
        }
        ul {
          list-style-type: none;
          padding: 0;
        }
        li {
          display: inline-block;
          margin: 0 10px;
        }
        a {
          color: #42b983;
        }
        
        

        vue.config.js

        const { defineConfig } = require('@vue/cli-service')
        module.exports = defineConfig({
          transpileDependencies: true,
          devServer:{
            port:8082,
            proxy: {
              '/api' : {
                target: 'http://localhost:8081',
                pathRewrite: {
                  '^/api' : ''
                }
              }
            }
          }
        })
        

        结果

        二、VUE进阶(router、vuex、typescript)

        路由 Vue-Router

        Vue-Router介绍

        vue属于单页面应用,所谓的路由,就是根据浏览器路径不同,用不同的视图组件替换这个页面内容。

        vue应用中如何实现路由?

        • 通过vue-router实现路由功能,需要安装js库(npm install vue-router)

          基于Vue CLI创建带有路由功能的前端项目

          命令:vue ui

          包管理器选择:npm

          ②预设选择:手动

          ③功能添加:Router

          ④配置版本选择:2.x,linter config选择:ESLint with error prevention only

          ⑤选择创建项目,不保存预设

          ⑥查看创建结果

          ⑦运行项目

          路由配置

          路由组成

          VueRouter:路由器,根据路由请求在路由视图中动态渲染对应的视图组件

          :路由链接组件,浏览器会解析成

          :路由视图组件,用来展示与路由匹配的视图组件

          路由跳转

          • 标签式
          • 编程式

            如果请求的路径不存在,应该如何处理?

            ①当上面的路径都匹配不到时,重定向到最后一项

            嵌套路由

            嵌套路由:组件内要切换内容,就需要用到嵌套路由(子路由)

            实现步骤:

            • 安装并导入elementui,实现页面布局(Container布局容器)---ContainerView.vue
              npm i element-ui -S

               

            • 提供子视图组件,用于效果展示 ---P1View.vue、P2View.vue、P3View.vue
              view/container/ContainerView.vue
                
                  Header
                  
                    Aside
                    Main
                  
                
              
              
              export default {};
              
              
                .el-header, .el-footer {
                  background-color: #B3C0D1;
                  color: #333;
                  text-align: center;
                  line-height: 60px;
                }
                
                .el-aside {
                  background-color: #D3DCE6;
                  color: #333;
                  text-align: center;
                  line-height: 200px;
                }
                
                .el-main {
                  background-color: #E9EEF3;
                  color: #333;
                  text-align: center;
                  line-height: 160px;
                }
                
                body > .el-container {
                  margin-bottom: 40px;
                }
                
                .el-container:nth-child(5) .el-aside,
                .el-container:nth-child(6) .el-aside {
                  line-height: 260px;
                }
                
                .el-container:nth-child(7) .el-aside {
                  line-height: 320px;
                }
              
            • 在src/router/index.js中配置路由映射规则(嵌套路由配置)
            • 在布局容器视图中添加,实现子视图组件展示
            • 在布局容器视图中添加,实现路由请求

              注意事项:子路由变化,切换的是【ContainerView组件】中‘’部分的内容。

              思考

              1. 对于前面的案例,如果用户访问的路由是/c,会有什么效果呢?

              2. 如果实现在访问/c时,默认就展示某个子视图组件呢?

              状态管理vuex

              vuex介绍

              • vuex是一个专为Vue.js应用程序开发的状态管理库
              • vuex可以在多个组件之间共享数据,并且共享的数据是响应式的,即数据的变更能及时渲染到模板
              • vuex采用集中式存储管理所有组件的状态

                安装

                npm install vuex@next --save

                核心概念

                • state:状态对象,集中定义各个组件共享的数据
                • mutations:类似于一个事件,用于修改共享数据,要求必须是同步函数
                • actions:类似于mutation,可以包含异步操作,通过调用mutation来改变共享数据

                  使用方式

                  ①创建带有vuex功能的脚手架工程

                  ②src/store/index.js

                  import Vue from 'vue'
                  import Vuex from 'vuex'
                  Vue.use(Vuex)
                  // 集中管理多个组件共享的数据
                  export default new Vuex.Store({
                    state: {
                    },
                    getters: {
                    },
                    mutations: {
                    },
                    actions: {
                    },
                    modules: {
                    }
                  })
                  

                  ③src/main.js

                  import Vue from 'vue'
                  import App from './App.vue'
                  import store from './store'
                  Vue.config.productionTip = false
                  new Vue({
                    // 使用vuex功能
                    store,
                    render: h => h(App)
                  }).$mount('#app')
                  

                  ④定义和展示共享数据

                  import Vue from 'vue'
                  import Vuex from 'vuex'
                  Vue.use(Vuex)
                  // 集中管理多个组件共享的数据
                  export default new Vuex.Store({
                    // 集中定义共享数据
                    state: {
                      name: '未登录游客'
                    },
                    getters: {
                    },
                    mutations: {
                    },
                    actions: {
                    },
                    modules: {
                    }
                  })
                  

                  ⑤在mutations中定义函数,修改共享数据

                  import Vue from 'vue'
                  import Vuex from 'vuex'
                  Vue.use(Vuex)
                  // 集中管理多个组件共享的数据
                  export default new Vuex.Store({
                    // 集中定义共享数据
                    state: {
                      name: '未登录游客'
                    },
                    getters: {
                    },
                    // 修改共享数据只能通过mutation实现,必须是同步操作
                    mutations: {
                      setName(state, newName) {
                        state.name = newName
                      }
                    },
                    // 通过actions可以调用mutations,在action中可以进行异步操作
                    actions: {
                    },
                    modules: {
                    }
                  })
                  
                    
                      欢迎您,{{$store.state.name}}
                      
                      Vue logo
                      
                    
                  
                  
                  import HelloWorld from './components/HelloWorld.vue'
                  export default {
                    name: 'App',
                    components: {
                      HelloWorld
                    },
                    methods: {
                      handleUpdate() {
                        // mutations中定义的函数不能直接调用,必须通过这种方式来调用
                        // setName为mutations中定义的函数名称,lisi为需要传递的参数
                        this.$store.commit('setName', 'lisi')
                      }
                    }
                  }
                  
                  
                  #app {
                    font-family: Avenir, Helvetica, Arial, sans-serif;
                    -webkit-font-smoothing: antialiased;
                    -moz-osx-font-smoothing: grayscale;
                    text-align: center;
                    color: #2c3e50;
                    margin-top: 60px;
                  }
                  
                  

                  ④在actions中定义函数,用于调用mutation

                  先安装axios

                  npm install axios
                  // src/store/index.js
                  import Vue from 'vue'
                  import Vuex from 'vuex'
                  import axios from 'axios'
                  Vue.use(Vuex)
                  // 集中管理多个组件共享的数据
                  export default new Vuex.Store({
                    // 集中定义共享数据
                    state: {
                      name: '未登录游客'
                    },
                    getters: {
                    },
                    // 修改共享数据只能通过mutation实现,必须是同步操作
                    mutations: {
                      setName(state, newName) {
                        state.name = newName
                      }
                    },
                    // 通过actions可以调用mutations,在action中可以进行异步操作
                    actions: {
                      setNameByAxios(context) {
                        axios ({
                          url: '/api/admin/employee/login',
                          method: 'post',
                          data: {
                            username: 'admin',
                            password: '123456'
                          }
                        }).then(res => {
                          if(res.data.code == 1) {
                            // 异步请求后,需要修改共享数据
                            // 调用mutation中定义的setName函数
                            context.commit('setName', res.data.data.name)
                          }
                        })
                      }
                    },
                    modules: {
                    }
                  })
                  
                  // App.vue
                  
                    
                      欢迎您,{{$store.state.name}}
                      
                      
                      Vue logo
                      
                    
                  
                  
                  import HelloWorld from './components/HelloWorld.vue'
                  export default {
                    name: 'App',
                    components: {
                      HelloWorld
                    },
                    methods: {
                      handleUpdate() {
                        // mutations中定义的函数不能直接调用,必须通过这种方式来调用
                        // setName为mutations中定义的函数名称,lisi为需要传递的参数
                        this.$store.commit('setName', 'lisi')
                      },
                      handleCallAction() {
                        // 调用actions中定义的函数,setNameByAxios为函数名
                        this.$store.dispatch('setNameByAxios')
                      }
                    }
                  }
                  
                  
                  #app {
                    font-family: Avenir, Helvetica, Arial, sans-serif;
                    -webkit-font-smoothing: antialiased;
                    -moz-osx-font-smoothing: grayscale;
                    text-align: center;
                    color: #2c3e50;
                    margin-top: 60px;
                  }
                  
                  
                  // vue.config.js
                  const { defineConfig } = require('@vue/cli-service')
                  module.exports = defineConfig({
                    transpileDependencies: true,
                    devServer: {
                      port:8082,
                      proxy: {
                        '/api': {
                          target: 'http://location:8081',
                          pathRewrite: {
                            '^/api': ''
                          }
                        }
                      }
                    }
                  })
                  

                  思考

                  1. 如何理解vuex?

                  • 实现多个组件之间的数据共享
                  • 共享数据是响应式的,实时渲染到模板
                  • 可以集中管理共享数据

                    2. 如何使用vuex?

                    • 在store对象的state属性中定义共享数据
                    • 在store对象的mutations属性中定义修改共享数据的函数
                    • 在store对象的actions属性中定义调用mutation的函数,可以进行异或操作
                    • mutations中的函数不能直接调用,只能通过store对象的commit方法调用
                    • actions中定义的函数不能直接调用,只能通过store对象的dispatch方法调用

                      TypeScript

                      TypeScript介绍

                      • TypeScript(简称:TS)是微软推出的开源语言
                      • TypeScript是JavaScript的超集(JS有的TS都有)
                      • TypeScript = Type + JavaScript(在JS基础上增加了类型支持)
                      • TypeScript文件扩展名为ts
                      • TypeScript可编译成标准的JavaScript,并且在编译时进行类型检查

                        安装typescript(全局安装)

                        如果安装失败,以管理员身份运行命令行窗口,可以在安装命令后加上 @5.0.2,以指定版本

                        npm install -g typescript

                        查看TS版本

                        tsc -v

                        示例

                        // 通过ts代码,指定函数的参数类型为string
                        function hello(msg:string) {
                                console.log(msg)
                        }
                        // 传入的参数类型为number
                        hello(123)

                        编译:tsc + 文件名

                        改正后(传参为:'123')

                        思考

                        1. TS为什么要增加类型支持?

                        • TS属于静态类型编程语言,JS属于动态类型编程语言
                        • 静态类型在编译期做类型检查,动态类型在执行期间做类型检查
                        • 对于JS来说,需要等到代码执行的时候才可以发现错误(晚)
                        • 对于TS来说,在代码编译的时候就可以发现错误(早)
                        • 配合VSCode开发工具,TS可以提前在编写代码的同时就发现代码中的错误,减少找Bug、改Bug的时间

                          2. 如何理解TypeScript?

                          • 是JavaScript的超集,兼容JavaScript
                          • 扩展了JavaScript的语法,文件扩展名为ts
                          • 可以编译成标准的JavaScript,并且可以在编译时进行类型检查
                          • 全局安装npm install -g typescript
                          • 视图tsc命令将ts文件编译成js文件
                          • 使用node命令运行js文件

                            TypeScript常用类型

                            类型备注
                            字符串类型string
                            数字类型number
                            布尔类型boolean
                            数组类型number[], string[], boolean[]依此类推
                            任意类型any相当于又回到了没有类型的时代
                            复杂类型type与interface
                            函数类型() => void对函数的参数和返回值进行说明
                            字面量类型"a"|"b"|"c"限制变量或参数的取值
                            class类class Animal

                            类型标注的位置

                            • 标注变量
                            • 标注参数
                            • 标注返回值

                              项目示例

                              1. 创建项目时勾选上TypeScript、Router、Vuex

                              2. 字符串类型、布尔类型、数字类型

                              // 字符串类型
                              let username: string = 'itcast'
                              // 数字类型
                              let age: number = 20
                              // 布尔类型
                              let isTrue: boolean = true
                              console.log(username)
                              console.log(age)
                              console.log(isTrue)

                              3. 字面量类型

                              // 字面量类型
                              function printText(s: string, alignment: 'left'|'right'|'center') {
                                  console.log(s, alignment)
                              }
                              printText('hello', 'left')
                              printText('hello', 'right')

                              4. 复杂类型——interface

                              小技巧:可以通过在属性名后面加上?,表示当前属性为可选

                              // 定义接口
                              interface Cat {
                                  name: string,
                                  age: number
                              }
                              // 定义变量为Cat类型
                              const c1: Cat = {name: '小白', age: 1}
                              // const c2: Cat = {name: '小白'}  // 错误:缺少age属性
                              // const c3: Cat = {name: '小白', age: 1, sex: '公'}  // 错误:多了sex属性
                              console.log(c1)

                              5. class类

                              注意:使用class关键字来定义类,类中可以包含属性、构造方法、普通方法

                              // 定义一个类,使用class关键字
                              class User {
                                  name: string;  // 属性
                                  constructor(name: string) {
                                      // 构造方法
                                      this.name = name
                                  }
                                  // 方法
                                  study() {
                                      console.log(this.name + '正在学习')
                                  }
                              }
                              // 使用User类型
                              const user = new User('张三')
                              // 输出类中的属性
                              console.log(user.name)
                              // 调用类中的方法
                              user.study()

                              6. Class类实现interface

                              interface Animal {
                                  name: string
                                  eat(): void
                              }
                              // 定义一个类Bird,实现上面的Animal接口
                              class Bird implements Animal {
                                  name: string
                                  constructor(name: string) {
                                      this.name = name
                                  }
                                  eat(): void {
                                      console.log(this.name + ' eat')
                                  }
                              }
                              // 创建类型为Bird的对象
                              const b1 = new Bird('杜鹃')
                              console.log(b1.name)
                              b1.eat()

                              7. class类——类的继承

                              // 定义一个类Bird,实现上面的Animal接口
                              class Bird implements Animal {
                                  name: string
                                  constructor(name: string) {
                                      this.name = name
                                  }
                                  eat(): void {
                                      console.log(this.name + ' eat')
                                  }
                              }
                              // 定义Parrot类,并且继承Bird类
                              class Parrot extends Bird {
                                  say():void {
                                      console.log(this.name + ' say hello')
                                  }
                              }
                              const myParrot = new Parrot('Polly')
                              myParrot.say()
                              myParrot.eat()

                              小结

                              1.TypeScript的常用类型有哪些?

                              • string、number、boolean
                              • 字面量、void
                              • interface、class

                                2. TypeScript文件能直接运行吗?

                                • 需要将TS文件编译为JS文件才能运行
                                • 编译后的JS文件中类型会擦除

                                  三、苍穹外卖前端项目环境搭建、员工管理

                                  技术选型

                                  • node.js
                                  • vue
                                  • ElementUI
                                  • axios
                                  • vuex
                                  • vue-router
                                  • typescript

                                    熟悉前端代码结构

                                    1. 代码导入:直接导入课程资料中提供的前端工程,在此基础上开发即可

                                    在苍穹外卖前端课程->资料->day02->资料->苍穹外卖前端初始工程

                                    2. 重点文件/目录

                                    3. 通过登录功能梳理前端代码

                                    ①先运行后端服务

                                    ②下载前端中的依赖(不需要指定安装哪些包,会自动扫描):npm install

                                    ③把nodejs的版本降级到12版本,如果出现安全性问题,代开cmd执行下面的命令

                                    可以参考这篇文章:node.js安装配置详细介绍以及nodejs版本降级_nodejs低版本-CSDN博客

                                    我是把node.js降级到了12.22.12

                                    npm config set strict-ssl false


                                    npm install

                                    ④修改后端服务的地址(如果前面课程中修改了后端服务的端口号)

                                    ⑤npm run serve,前端的端口号为8888

                                    ⑥通过登录功能梳理前端代码

                                    • 获得登录页面路由地址
                                    • 从main.ts中找到路由文件
                                    • 从路由文件中找到登录视图组件
                                    • 从登录视图组件中找到登录方法
                                    • 跟踪登录方法的执行过程

                                      员工分页查询

                                      需求分析和接口设计

                                      业务规则

                                      根据页码展示员工信息

                                      每页展示10条数据

                                      分页查询可以根据需要,输入员工姓名进行查询

                                      接口设计

                                      代码开发

                                      ①从路由文件router.ts中找到员工管理页面(组件)

                                      ②初始页面

                                      ③制作页面头部效果

                                          
                                            
                                              员工姓名:
                                              
                                              查询
                                               + 添加员工
                                            
                                          

                                      注意

                                      • 输入框和按钮都是使用ElementUI提供的组件
                                      • 对于前端的组件只需要参考ElementUI提供的文档,进行修改即可

                                        链接:Element - The world's most popular Vue UI framework

                                        ④员工分页查询

                                        src/api/employee.ts

                                        // 分页查询
                                        export const getEmployeeList = (params: any) =>
                                          request({
                                            'url': `/employee/page`,
                                            'method': 'get',
                                            'params': params
                                          })

                                        src/view/employee/index.vue

                                          
                                            
                                              
                                                员工姓名:
                                                
                                                查询
                                                 + 添加员工
                                              
                                              
                                                
                                                
                                                
                                                
                                                 
                                                
                                                  
                                                    {{ scope.row.status === 0 ? '禁用' : '启用' }}
                                                  
                                                
                                                
                                                
                                                
                                                  
                                                    修改
                                                    {{
                                                      scope.row.status === 1 ? '禁用' : '启用'
                                                    }}
                                                  
                                                
                                              
                                              
                                              
                                            
                                          
                                        
                                        
                                        import { getEmployeeList } from '@/api/employee'
                                        export default {
                                          // 模型数据
                                          data() {
                                            return {
                                              name: '', // 员工姓名,对应上面的输入框
                                              page: 1, // 页码
                                              pageSize: 10, // 每页记录数
                                              total: 0, // 总记录数
                                              records: [], // 当前页要展示的数据集合
                                            }
                                          },
                                          // 自动调用pageQuery方法
                                          // 这段代码是 Vue.js 组件中的生命周期钩子函数 created()。在 Vue.js 组件中,created() 是一个生命周期钩子函数,在组件实例被创建之后立即调用。这个钩子函数通常用于在组件实例创建后执行一些初始化任务。
                                          created() {
                                            this.pageQuery()
                                          },
                                          methods: {
                                            // 分页查询
                                            pageQuery() {
                                              // 准备请求参数
                                              const params = {
                                                name: this.name,
                                                page: this.page,
                                                pageSize: this.pageSize,
                                              }
                                              // 发送Ajax请求,访问后端服务,获取分页数据
                                              getEmployeeList(params)
                                                .then((res) => {
                                                  if (res.data.code === 1) {
                                                    this.total = res.data.data.total
                                                    this.records = res.data.data.records
                                                  }
                                                })
                                                .catch((err) => {
                                                  this.$message.console.error('请求出错了:' + err.message)
                                                })
                                            },
                                            // pageSize发送变化时触发
                                            handleSizeChange(pageSize) {
                                              this.pageSize = pageSize
                                              this.pageQuery()
                                            },
                                            // page发生变化时触发
                                            handleCurrentChange(page) {
                                              this.page = page
                                              this.pageQuery()
                                            },
                                          },
                                        }
                                        
                                        
                                        .disabled-text {
                                          color: #bac0cd !important;
                                        }
                                        
                                        

                                        功能测试

                                        启用、禁用员工账号

                                        需求分析和接口设计

                                        业务规则

                                        可以对状态为“启用”的员工账号进行“禁用”操作

                                        可以对状态为“禁用”的员工账号进行“启用”操作

                                        状态为“禁用”的员工账号不能登录系统

                                        接口设计

                                        代码开发

                                        ①src/api/employee.ts

                                        // 启用禁用员工账号
                                        export const enableOrDisableEmployee = (params: any) =>
                                          request({
                                            'url': `/employee/status/${params.status}`,
                                            'method': 'post',
                                            'params': {id: params.id}
                                          })

                                        ②src/view/employee/index.vue

                                          
                                            
                                              
                                                员工姓名:
                                                
                                                查询
                                                 + 添加员工
                                              
                                              
                                                
                                                
                                                
                                                
                                                 
                                                
                                                  
                                                    {{ scope.row.status === 0 ? '禁用' : '启用' }}
                                                  
                                                
                                                
                                                
                                                
                                                  
                                                    修改
                                                    {{scope.row.status === 1 ? '禁用' : '启用'}}
                                                  
                                                
                                              
                                              
                                              
                                            
                                          
                                        
                                        
                                        import { getEmployeeList, enableOrDisableEmployee} from '@/api/employee'
                                        export default {
                                          // 模型数据
                                          data() {
                                            return {
                                              name: '', // 员工姓名,对应上面的输入框
                                              page: 1, // 页码
                                              pageSize: 10, // 每页记录数
                                              total: 0, // 总记录数
                                              records: [], // 当前页要展示的数据集合
                                            }
                                          },
                                          // 自动调用pageQuery方法
                                          created() {
                                            this.pageQuery()
                                          },
                                          methods: {
                                            // 分页查询
                                            pageQuery() {
                                              // 准备请求参数
                                              const params = {
                                                name: this.name,
                                                page: this.page,
                                                pageSize: this.pageSize,
                                              }
                                              // 发送Ajax请求,访问后端服务,获取分页数据
                                              getEmployeeList(params)
                                                .then((res) => {
                                                  if (res.data.code === 1) {
                                                    this.total = res.data.data.total
                                                    this.records = res.data.data.records
                                                  }
                                                })
                                                .catch((err) => {
                                                  this.$message.console.error('请求出错了:' + err.message)
                                                })
                                            },
                                            // pageSize发送变化时触发
                                            handleSizeChange(pageSize) {
                                              this.pageSize = pageSize
                                              this.pageQuery()
                                            },
                                            // page发生变化时触发
                                            handleCurrentChange(page) {
                                              this.page = page
                                              this.pageQuery()
                                            },
                                            // 启用禁用员工账号
                                            handleStartOrStop(row) {
                                              if(row.username === 'admin') {
                                                this.$message.error('admin为系统的管理员账号,不能更改帐号状态!')
                                                return
                                              }
                                                // alert(`id=${row.id} status=${row.status}`)
                                                // 弹出确认提示框
                                                this.$confirm('确认要修改当前员工账号的状态吗?', '提示', {
                                                  confirmButtonText: '确定',
                                                  cancelButtonText: '取消',
                                                  type: 'warning'
                                                }).then(() => {
                                                  const p = {
                                                    id: row.id,
                                                    status: !row.status ? 1 : 0
                                                  }
                                                  enableOrDisableEmployee(p).then(res => {
                                                    if(res.data.code === 1) {
                                                      this.$message.success('员工的账号状态修改成功!')
                                                      this.pageQuery()
                                                    }
                                                  })
                                                })
                                            }
                                          },
                                        }
                                        
                                        
                                        .disabled-text {
                                          color: #bac0cd !important;
                                        }
                                        
                                        

                                        功能测试

                                        添加员工

                                        需求分析和接口设计

                                        产品原型

                                        接口设计

                                        代码开发

                                        添加员工操作步骤

                                        • 点击“添加员工”按钮,跳转到新增页面
                                        • 在新增员工页面录入员工相关信息
                                        • 点击“保存”按钮完成新增操作

                                          ①为“添加员工”按钮绑定单击事件:src/views/employee/index.vue

                                          ②提供handleAddEmp方法,进行路由跳转

                                          ③src/api/employee.ts

                                            // 新增员工
                                          export const addEmployee = (params: any) =>
                                            request({
                                              'url': '/employee',
                                              'method': 'post',
                                              'data': params
                                            })

                                          ④src/views/employee/addEmployee.vue

                                            
                                              
                                                
                                                  
                                                    
                                                  
                                                  
                                                    
                                                  
                                                  
                                                    
                                                  
                                                  
                                                      男
                                                      女
                                                  
                                                  
                                                    
                                                  
                                                  
                                                    保存
                                                    保存并继续添加员工
                                                    
                                                    返回
                                                  
                                                
                                              
                                            
                                          
                                          
                                          import {addEmployee} from '@/api/employee'
                                          export default {
                                            data() {
                                              return {
                                                optType: 'add',
                                                ruleForm: {
                                                  name: '',
                                                  username: '',
                                                  sex: '1',
                                                  phone: '',
                                                  idNumber: ''
                                                },
                                                rules: {
                                                  name: [
                                                      { required: true, message: '请输入员工姓名', trigger: 'blur' }
                                                  ],
                                                  username: [
                                                      { required: true, message: '请输入员工账号', trigger: 'blur' }
                                                  ],
                                                  phone: [
                                                      { required: true, trigger: 'blur', validator: (rule, value, callback) => {
                                                        if(value === '' || (!/^1(3|4|5|6|7|8)\d{9}$/.test(value))) {
                                                          callback(new Error('请输入正确的手机号!'))
                                                        } else {
                                                          callback()
                                                        }
                                                      }}
                                                  ],
                                                  idNumber: [
                                                      { required: true, trigger: 'blur', validator: (rule, value, callback) => {
                                                        if(value === '' || (!/(^\d{15}$)|(^\d{18}$)|(^\d{17}(X|x)$)/.test(value))) {
                                                          callback(new Error('请输入正确的身份证号!'))
                                                        } else {
                                                          callback()
                                                        }
                                                      }}
                                                  ]
                                                }
                                              }
                                            },
                                            methods: {
                                              submitForm(formName, isContinue) {
                                                // 进行表单校验
                                                this.$refs[formName].validate((valid) => {
                                                  if(valid) {
                                                    // alert('所有表单项都符合要求')
                                                    // 表单校验通过,发起Ajax请求,将数据提交到后端
                                                    addEmployee(this.ruleForm).then((res) => {
                                                      if(res.data.code === 1) {
                                                        this.$message.success('员工添加成功!')
                                                        if(isContinue) {  // 保存并继续添加
                                                        this.ruleForm = {
                                                          name: '',
                                                          username: '',
                                                          sex: '1',
                                                          phone: '',
                                                          idNumber: ''
                                                        }
                                                        } else {
                                                          this.$router.push('/employee')
                                                        }
                                                      } else {
                                                        this.$message.error(res.data.msg)
                                                      }
                                                    })
                                                  }
                                                })
                                              }
                                            }
                                          }
                                          
                                          
                                          .addBrand {
                                            &-container {
                                              margin: 30px;
                                              margin-top: 30px;
                                              .HeadLable {
                                                background-color: transparent;
                                                margin-bottom: 0px;
                                                padding-left: 0px;
                                              }
                                              .container {
                                                position: relative;
                                                z-index: 1;
                                                background: #fff;
                                                padding: 30px;
                                                border-radius: 4px;
                                                // min-height: 500px;
                                                .subBox {
                                                  padding-top: 30px;
                                                  text-align: center;
                                                  border-top: solid 1px $gray-5;
                                                }
                                              }
                                              .idNumber {
                                                margin-bottom: 39px;
                                              }
                                              .el-form-item {
                                                margin-bottom: 29px;
                                              }
                                              .el-input {
                                                width: 293px;
                                              }
                                            }
                                          }
                                          
                                          

                                          功能测试

                                          修改员工

                                          需求分析和接口设计

                                          产品原型

                                          编辑员工功能涉及到两个接口:

                                          • 根据id查询员工信息
                                          • 编辑员工信息

                                            代码开发

                                            修改员工操作步骤:

                                            • 点击“修改”按钮,跳转到修改页面
                                            • 在修改员工页面录入员工相关信息
                                            • 点击“保存”按钮完成修改操作

                                              注意

                                              • 由于添加员工和修改员工的表单项非常类似,所以添加和修改操作可以共用同一个页面addEmployee.vue
                                              • 修改员工设计原数据回显,所以需要传递员工id作为参数

                                                ①src/views/employee/index.vue,在员工管理页面中,为“修改”按钮绑定单击事件,用于跳转到修改页面

                                                    // 跳转到修改员工页面(组件)
                                                    handleUpdateEmp(row) {
                                                      if(row.username === 'admin') {
                                                        // 如果是内置管理员账号,不允许修改
                                                        this.$message.error('admin为系统的管理员账号,不能修改!')
                                                        return
                                                      }
                                                      // 跳转到修改页面,通过地址栏传递参数
                                                      this.$router.push({
                                                        path: '/employee/add',
                                                        query: {id: row.id}
                                                      })
                                                    }

                                                ②由于addEmployee.vue为新增和修改共用页面,需要能够区分当前操作:

                                                • 如果路由中传递了id参数,则当前操作为修改
                                                • 如果路由中没有传递id参数,则当前操作为新增

                                                  ③根据id查询员工,src/api/employee.ts

                                                    // 根据id查询员工
                                                  export const queryEmployeeById = (id: number) =>
                                                    request({
                                                      'url': `/employee/${id}`,
                                                      'method': 'get'
                                                    })

                                                  ④数据回显,src/views/employee/addEmployee.vue

                                                  ⑤修改员工信息,src/api/employee.ts

                                                  // 修改员工
                                                  export const updateEmployee = (params: any) =>
                                                    request({
                                                      'url': '/employee',
                                                      'method': 'put',
                                                      'data': params
                                                    })

                                                  ⑥src/views/employee/addEmployee.vue

                                                  import { addEmployee, queryEmployeeById, updateEmployee} from '@/api/employee'
                                                  export default {
                                                    data() {
                                                      return {
                                                        optType: '', // 当前新增的类型为新增或者修改
                                                        ruleForm: {
                                                          name: '',
                                                          username: '',
                                                          sex: '1',
                                                          phone: '',
                                                          idNumber: '',
                                                        },
                                                        rules: {
                                                          name: [{ required: true, message: '请输入员工姓名', trigger: 'blur' }],
                                                          username: [
                                                            { required: true, message: '请输入员工账号', trigger: 'blur' },
                                                          ],
                                                          phone: [
                                                            {
                                                              required: true,
                                                              trigger: 'blur',
                                                              validator: (rule, value, callback) => {
                                                                if (value === '' || !/^1(3|4|5|6|7|8)\d{9}$/.test(value)) {
                                                                  callback(new Error('请输入正确的手机号!'))
                                                                } else {
                                                                  callback()
                                                                }
                                                              },
                                                            },
                                                          ],
                                                          idNumber: [
                                                            {
                                                              required: true,
                                                              trigger: 'blur',
                                                              validator: (rule, value, callback) => {
                                                                if (
                                                                  value === '' ||
                                                                  !/(^\d{15}$)|(^\d{18}$)|(^\d{17}(X|x)$)/.test(value)
                                                                ) {
                                                                  callback(new Error('请输入正确的身份证号!'))
                                                                } else {
                                                                  callback()
                                                                }
                                                              },
                                                            },
                                                          ],
                                                        },
                                                      }
                                                    },
                                                    // 页面加载完成执行的代码
                                                    created() {
                                                      // 获取路由参数{id},如果有则为修改操作,否则为新增操作
                                                      this.optType = this.$route.query.id ? 'update' : 'add'
                                                      if (this.optType === 'update') {
                                                        // 修改操作,需要根据id查询员工信息用于页面回显
                                                        queryEmployeeById(this.$route.query.id).then((res) => {
                                                          if (res.data.code === 1) {
                                                            this.ruleForm = res.data.data
                                                          }
                                                        })
                                                      }
                                                    },
                                                    methods: {
                                                      submitForm(formName, isContinue) {
                                                        // 进行表单校验
                                                        this.$refs[formName].validate((valid) => {
                                                          if (valid) {
                                                            // alert('所有表单项都符合要求')
                                                            // 表单校验通过,发起Ajax请求,将数据提交到后端
                                                            if (this.optType === 'add') {
                                                              // 新增操作
                                                              addEmployee(this.ruleForm).then((res) => {
                                                                if (res.data.code === 1) {
                                                                  this.$message.success('员工添加成功!')
                                                                  if (isContinue) {
                                                                    // 保存并继续添加
                                                                    this.ruleForm = {
                                                                      name: '',
                                                                      username: '',
                                                                      sex: '1',
                                                                      phone: '',
                                                                      idNumber: '',
                                                                    }
                                                                  } else {
                                                                    this.$router.push('/employee')
                                                                  }
                                                                } else {
                                                                  this.$message.error(res.data.msg)
                                                                }
                                                              })
                                                            } else {
                                                              // 修改操作
                                                              updateEmployee(this.ruleForm).then(res => {
                                                                if(res.data.code == 1) {
                                                                  this.$message.success('员工信息修改成功!')
                                                                  this.$router.push('/employee')
                                                                }
                                                              })
                                                            }
                                                          }
                                                        })
                                                      },
                                                    },
                                                  }

                                                  功能测试

                                                  四、套餐管理

                                                  套餐分页查询

                                                  需求分析和接口设计

                                                  产品原型

                                                  业务规则

                                                  • 根据页码展示套餐信息
                                                  • 每页展示10条数据
                                                  • 分页查询时可以根据需要输入套餐名称、套餐分类、售卖状态进行查询

                                                    接口设计

                                                    • 套餐分页查询接口
                                                    • 分类查询接口(用于下拉框中分类数据显示)

                                                      代码开发

                                                      ①从路由文件router.ts中找到套餐管理页面(组件)

                                                      ②制作页面头部效果,src/views/setmeal/index.vue

                                                        
                                                          
                                                            
                                                              
                                                                套餐名称:
                                                                
                                                                
                                                                套餐分类:
                                                                
                                                                  
                                                                  
                                                                
                                                                售卖状态:
                                                                
                                                                  
                                                                  
                                                                
                                                                查询
                                                                
                                                                  批量删除
                                                                  +新建套餐
                                                                
                                                              
                                                            
                                                          
                                                        
                                                      
                                                      
                                                      export default {
                                                        // 模型数据
                                                        data() {
                                                          return {
                                                            name: '', // 套餐名称,对应上面的输入框
                                                            page: 1, // 页码
                                                            pageSize: 10, // 每页记录数
                                                            total: 0, // 总记录数
                                                            records: [], // 当前页要展示的数据集合
                                                            options: [{
                                                                value: '选项1',
                                                                label: '黄金糕'
                                                              }, {
                                                                value: '选项2',
                                                                label: '双皮奶'
                                                              }, {
                                                                value: '选项3',
                                                                label: '蚵仔煎'
                                                              }, {
                                                                value: '选项4',
                                                                label: '龙须面'
                                                              }, {
                                                                value: '选项5',
                                                                label: '北京烤鸭'
                                                              }],
                                                              value: '',
                                                              saleStatusArr:[{
                                                                value: '1',
                                                                label: '起售'
                                                              }, {
                                                                value: '0',
                                                                label: '停售'
                                                              }],
                                                              saleStatus: ''
                                                          }
                                                        },
                                                      }
                                                      
                                                      
                                                      .el-table-column--selection .cell {
                                                        padding-left: 10px;
                                                      }
                                                      
                                                      
                                                      .dashboard {
                                                        &-container {
                                                          margin: 30px;
                                                          .container {
                                                            background: #fff;
                                                            position: relative;
                                                            z-index: 1;
                                                            padding: 30px 28px;
                                                            border-radius: 4px;
                                                            .tableBar {
                                                              margin-bottom: 20px;
                                                              .tableLab {
                                                                float: right;
                                                                span {
                                                                  cursor: pointer;
                                                                  display: inline-block;
                                                                  font-size: 14px;
                                                                  padding: 0 20px;
                                                                  color: $gray-2;
                                                                }
                                                              }
                                                            }
                                                            .tableBox {
                                                              width: 100%;
                                                              border: 1px solid $gray-5;
                                                              border-bottom: 0;
                                                            }
                                                            .pageList {
                                                              text-align: center;
                                                              margin-top: 30px;
                                                            }
                                                            //查询黑色按钮样式
                                                            .normal-btn {
                                                              background: #333333;
                                                              color: white;
                                                              margin-left: 20px;
                                                            }
                                                          }
                                                        }
                                                      }
                                                      
                                                      

                                                      注意

                                                      • 输入框、按钮、下拉框都是使用ElementUI提供的组件
                                                      • 对于前端的组件只需要参考ElementUI提供的文档,进行修改即可

                                                        ③导入查询套餐分类的JS方法,动态填充套餐分类下拉框,src/views/setmeal/index.vue

                                                        完整代码(做了一些小调整)

                                                          
                                                            
                                                              
                                                                
                                                                  套餐名称:
                                                                  
                                                                  
                                                                  套餐分类:
                                                                  
                                                                    
                                                                    
                                                                  
                                                                  售卖状态:
                                                                  
                                                                    
                                                                    
                                                                  
                                                                  查询
                                                                  
                                                                    批量删除
                                                                    +新建套餐
                                                                  
                                                                
                                                              
                                                            
                                                          
                                                        
                                                        
                                                        import {getCategoryByType} from '@/api/category'
                                                        export default {
                                                          // 模型数据
                                                          data() {
                                                            return {
                                                              name: '', // 套餐名称,对应上面的输入框
                                                              page: 1, // 页码
                                                              pageSize: 10, // 每页记录数
                                                              total: 0, // 总记录数
                                                              records: [], // 当前页要展示的数据集合
                                                              options: [],
                                                              categoryId: '',  // 分类id
                                                              statusArr:[{
                                                                value: '1',
                                                                label: '起售'
                                                              }, {
                                                                value: '0',
                                                                label: '停售'
                                                              }],
                                                              status: ''  // 售卖状态
                                                            }
                                                          },
                                                          created() {
                                                            // 查询套餐分类,用于填充查询页面的下拉框
                                                            getCategoryByType({type:2}).then(res => {
                                                              if(res.data.code == 1) {
                                                                this.options = res.data.data
                                                              }
                                                            })
                                                          }
                                                        }
                                                        
                                                        
                                                        .el-table-column--selection .cell {
                                                          padding-left: 10px;
                                                        }
                                                        
                                                        
                                                        .dashboard {
                                                          &-container {
                                                            margin: 30px;
                                                            .container {
                                                              background: #fff;
                                                              position: relative;
                                                              z-index: 1;
                                                              padding: 30px 28px;
                                                              border-radius: 4px;
                                                              .tableBar {
                                                                margin-bottom: 20px;
                                                                .tableLab {
                                                                  float: right;
                                                                  span {
                                                                    cursor: pointer;
                                                                    display: inline-block;
                                                                    font-size: 14px;
                                                                    padding: 0 20px;
                                                                    color: $gray-2;
                                                                  }
                                                                }
                                                              }
                                                              .tableBox {
                                                                width: 100%;
                                                                border: 1px solid $gray-5;
                                                                border-bottom: 0;
                                                              }
                                                              .pageList {
                                                                text-align: center;
                                                                margin-top: 30px;
                                                              }
                                                              //查询黑色按钮样式
                                                              .normal-btn {
                                                                background: #333333;
                                                                color: white;
                                                                margin-left: 20px;
                                                              }
                                                            }
                                                          }
                                                        }
                                                        
                                                        

                                                        src/api/category.ts

                                                        // 根据类型查询分类:1为菜品分类 2为套餐分类
                                                        export const getCategoryByType = (params: any) => {
                                                          return request({
                                                            url: `/category/list`,
                                                            method: 'get',
                                                            params: params
                                                          })
                                                        }

                                                        ④为查询按钮绑定事件,发送Ajax请求获取分页数据

                                                        src/api/setMeal.js

                                                        //套餐分页查询
                                                        export const getSetmealPage = (params: any) => {
                                                            return request({
                                                                url: '/setmeal/page',
                                                                method: 'GET',
                                                                params: params
                                                            })
                                                        }

                                                        src/views/setmeal/index.vue

                                                        ⑤分页查询,src/views/setmeal/index.vue

                                                                
                                                                  
                                                                  
                                                                  
                                                                    
                                                                      
                                                                    
                                                                  
                                                                  
                                                                  
                                                                  
                                                                    
                                                                      
                                                                        {{ scope.row.status === 0 ? '停售' : '启售' }}
                                                                      
                                                                    
                                                                  
                                                                  
                                                                  
                                                                    
                                                                       修改 
                                                                      
                                                                        {{ scope.row.status == '1' ? '停售' : '启售' }}
                                                                      
                                                                       删除 
                                                                    
                                                                  
                                                                
                                                                

                                                        功能测试

                                                        启售停售套餐

                                                        需求分析和接口设计

                                                        产品原型

                                                        业务规则

                                                        • 可以对状态为“启售”的套餐进行“停售:操作
                                                        • 可以对状态为”停售“的套餐进行”启售“操作

                                                          接口设计

                                                          代码开发

                                                          ①为启售、停售按钮绑定单击事件,src/views/setmeal/index.vue

                                                          import {getSetmealPage, enableOrDisableSetmeal, deleteSetmeal } from '@/api/setMeal'
                                                              handleStartOrStop(row) {
                                                                // alert(`id=${row.id} status=${row.status}`) 
                                                                 this.$confirm('确认调整该套餐的售卖状态?', '提示', {
                                                                  confirmButtonText: '确定',
                                                                  cancelButtonText: '取消',
                                                                  type: 'warning',
                                                                }).then(() => {
                                                                  enableOrDisableSetmeal({ id: row.id, status: !row.status ? 1 : 0 })
                                                                    .then((res) => {
                                                                      if (res.status === 200) {
                                                                        this.$message.success('套餐售卖状态更改成功!')
                                                                        this.pageQuery()
                                                                      }
                                                                    })
                                                                    .catch((err) => {
                                                                      this.$message.error('请求出错了:' + err.message)
                                                                    })
                                                                })
                                                              }

                                                          src/api/setMeal.ts

                                                          //套餐启售停售
                                                          export const enableOrDisableSetmeal = (params: any) => {
                                                              return request({
                                                                  url: `/setmeal/status/${params.status}`,
                                                                  method: 'POST',
                                                                  params: {id: params.id}
                                                              })
                                                          }

                                                          注意:这里测试时要运行redis-server,否则会出现下面的错误

                                                          功能测试

                                                          删除套餐

                                                          需求分析和设计

                                                          产品原型

                                                          业务规则

                                                          • 点击删除按钮,删除指定的一个套餐
                                                          • 勾选需要删除的套餐,点击批量删除按钮,删除选中的一个或多个套餐

                                                            接口设计

                                                            代码开发

                                                            ①在src/api/setMeal.ts中封装删除套餐方法,发送Ajax请求

                                                            //删除套餐
                                                            export const deleteSetmeal = (ids: string) => {//1,2,3
                                                                return request({
                                                                    url: '/setmeal',
                                                                    method: 'DELETE',
                                                                    params: {ids: ids}
                                                                })
                                                            }

                                                            ②在src/views/setmeal/index.vue书写删除按钮单击事件

                                                                // 删除套餐
                                                                handleDelete(type:string, id:string) {
                                                                    deleteSetmeal(id).then(res => {
                                                                      if(res.data.code === 1) {
                                                                        this.$message.success('删除成功!')
                                                                        this.pageQuery()
                                                                      } else {
                                                                        this.$message.error(res.data.msg)
                                                                      }
                                                                    })
                                                                }

                                                            ③批量删除

                                                            在src/views/setmeal/index.vue中添加模型数据

                                                            为批量删除按钮绑定单击事件

                                                                // 删除套餐
                                                                handleDelete(type:string, id:string) {
                                                                  this.$confirm('确认删除当前指定的套餐,是否继续?', '提示', {
                                                                    confirmButtonText: '确定',
                                                                    cancelButtonText: '取消',
                                                                    type: 'warning',
                                                                  }).then(() => {
                                                                    let param = ''
                                                                    if(type == 'B') {
                                                                      // 批量删除
                                                                      // alert(this.multipleSelection.length)
                                                                      const arr = new Array
                                                                      this.multipleSelection.forEach(element => {
                                                                        arr.push(element.id)
                                                                      })
                                                                      param = arr.join(',')
                                                                    } else {
                                                                      // 单一删除
                                                                      param = id
                                                                    }
                                                                    deleteSetmeal(param).then(res => {
                                                                      if(res.data.code === 1) {
                                                                        this.$message.success('删除成功!')
                                                                        this.pageQuery()
                                                                      } else {
                                                                        this.$message.error(res.data.msg)
                                                                      }
                                                                    })
                                                                  })
                                                                },

                                                            功能测试

                                                            新增套餐

                                                            需求分析和接口设计

                                                            产品原型

                                                            接口设计

                                                            • 根据类型查询分类接口
                                                            • 根据分类查询菜品接口
                                                            • 文件上传接口
                                                            • 新增套餐接口

                                                              代码解读

                                                              新增套餐操作步骤

                                                              ①点击”新建套餐“按钮,跳转到新增页面,src/views/setmeal/index.vue

                                                              src/router.ts

                                                              ②在套餐页面录入套餐相关信息,src/views/setmeal/addSetmeal.vue

                                                                
                                                                  
                                                                    
                                                                      
                                                                        
                                                                          
                                                                        
                                                                        
                                                                          
                                                                            
                                                                          
                                                                        
                                                                      
                                                                      
                                                                        
                                                                          
                                                                        
                                                                      
                                                                      
                                                                        
                                                                          
                                                                            
                                                                              
                                                                                + 添加菜品
                                                                              
                                                                                
                                                                                  + 添加菜品
                                                                                
                                                                                
                                                                                  
                                                                                    
                                                                                    
                                                                                      
                                                                                        {{ (Number(scope.row.price).toFixed(2) * 100) / 100 }}
                                                                                      
                                                                                    
                                                                                    
                                                                                      
                                                                                        
                                                                                      
                                                                                    
                                                                                    
                                                                                      
                                                                                        
                                                                                          删除
                                                                                        
                                                                                      
                                                                                    
                                                                                  
                                                                                
                                                                              
                                                                            
                                                                          
                                                                        
                                                                      
                                                                      
                                                                        
                                                                          
                                                                            图片大小不超过2M
                                                              仅能上传 PNG JPEG JPG类型图片
                                                              建议上传200*200或300*300尺寸的图片 取消 保存 保存并继续添加 取 消 添 加 import { Component, Vue } from 'vue-property-decorator' import HeadLable from '@/components/HeadLable/index.vue' import ImageUpload from '@/components/ImgUpload/index.vue' import AddDish from './components/AddDish.vue' import { querySetmealById, addSetmeal, editSetmeal } from '@/api/setMeal' import { getCategoryList } from '@/api/dish' import { baseUrl } from '@/config.json' @Component({ name: 'addShop', components: { HeadLable, AddDish, ImageUpload } }) export default class extends Vue { private value: string = '' private setMealList: [] = [] private seachKey: string = '' private dishList: [] = [] private imageUrl: string = '' private actionType: string = '' private dishTable: [] = [] private dialogVisible: boolean = false private checkList: any[] = [] private ruleForm = { name: '', categoryId: '', price: '', code: '', image: '', description: '', dishList: [], status: true, idType: '' } get rules() { return { name: { required: true, validator: (rule: any, value: string, callback: Function) => { if (!value) { callback(new Error('请输入套餐名称')) } else { const reg = /^([A-Za-z0-9\u4e00-\u9fa5]){2,20}$/ if (!reg.test(value)) { callback(new Error('套餐名称输入不符,请输入2-20个字符')) } else { callback() } } }, trigger: 'blur' }, idType: { required: true, message: '请选择套餐分类', trigger: 'change' }, image: { required: true, message: '菜品图片不能为空' }, price: { required: true, // 'message': '请输入套餐价格', validator: (rules: any, value: string, callback: Function) => { const reg = /^([1-9]\d{0,5}|0)(\.\d{1,2})?$/ if (!reg.test(value) || Number(value) { if (res && res.data && res.data.code === 1) { this.ruleForm = res.data.data this.ruleForm.status = res.data.data.status == '1' ;(this.ruleForm as any).price = res.data.data.price // this.imageUrl = `http://172.17.2.120:8080/common/download?name=${res.data.data.image}` this.imageUrl = res.data.data.image this.checkList = res.data.data.setmealDishes this.dishTable = res.data.data.setmealDishes.reverse() this.ruleForm.idType = res.data.data.categoryId } else { this.$message.error(res.data.msg) } }) } private seachHandle() { this.seachKey = this.value } // 获取套餐分类 private getDishTypeList() { getCategoryList({ type: 2, page: 1, pageSize: 1000 }).then(res => { if (res && res.data && res.data.code === 1) { this.setMealList = res.data.data.map((obj: any) => ({ ...obj, idType: obj.id })) } else { this.$message.error(res.data.msg) } }) } // 通过套餐ID获取菜品列表分类 // private getDishList (id:number) { // getDishListType({id}).then(res => { // if (res.data.code == 200) { // const { data } = res.data // this.dishList = data // } else { // this.$message.error(res.data.desc) // } // }) // } // 删除套餐菜品 delDishHandle(index: any) { this.dishTable.splice(index, 1) this.checkList = this.dishTable // this.checkList.splice(index, 1) } // 获取添加菜品数据 - 确定加菜倒序展示 private getCheckList(value: any) { this.checkList = [...value].reverse() } // 添加菜品 openAddDish(st: string) { this.seachKey = '' this.dialogVisible = true } // 取消添加菜品 handleClose(done: any) { // this.$refs.adddish.close() this.dialogVisible = false this.checkList = JSON.parse(JSON.stringify(this.dishTable)) // this.dialogVisible = false } // 保存添加菜品列表 public addTableList() { this.dishTable = JSON.parse(JSON.stringify(this.checkList)) this.dishTable.forEach((n: any) => { n.copies = 1 }) this.dialogVisible = false } public submitForm(formName: any, st: any) { ;(this.$refs[formName] as any).validate((valid: any) => { if (valid) { if (this.dishTable.length === 0) { return this.$message.error('套餐下菜品不能为空') } if (!this.ruleForm.image) return this.$message.error('套餐图片不能为空') let prams = { ...this.ruleForm } as any prams.setmealDishes = this.dishTable.map((obj: any) => ({ copies: obj.copies, dishId: obj.dishId, name: obj.name, price: obj.price })) ;(prams as any).status = this.actionType === 'add' ? 0 : this.ruleForm.status ? 1 : 0 prams.categoryId = this.ruleForm.idType // delete prams.dishList if (this.actionType == 'add') { delete prams.id addSetmeal(prams) .then(res => { if (res && res.data && res.data.code === 1) { this.$message.success('套餐添加成功!') if (!st) { this.$router.push({ path: '/setmeal' }) } else { ;(this as any).$refs.ruleForm.resetFields() this.dishList = [] this.dishTable = [] this.ruleForm = { name: '', categoryId: '', price: '', code: '', image: '', description: '', dishList: [], status: true, id: '', idType: '' } as any this.imageUrl = '' } } else { this.$message.error(res.data.msg) } }) .catch(err => { this.$message.error('请求出错了:' + err.message) }) } else { delete prams.updateTime editSetmeal(prams) .then(res => { if (res.data.code === 1) { this.$message.success('套餐修改成功!') this.$router.push({ path: '/setmeal' }) } else { // this.$message.error(res.data.desc || res.data.message) } }) .catch(err => { this.$message.error('请求出错了:' + err.message) }) } } else { // console.log('error submit!!') return false } }) } imageChange(value: any) { this.ruleForm.image = value } } .avatar-uploader .el-icon-plus:after { position: absolute; display: inline-block; content: ' ' !important; left: calc(50% - 20px); top: calc(50% - 40px); width: 40px; height: 40px; background: url('./../../assets/icons/icon_upload@2x.png') center center no-repeat; background-size: 20px; } // .el-form-item__error { // top: 90%; // } .addBrand-container { .avatar-uploader .el-upload { border: 1px dashed #d9d9d9; border-radius: 6px; cursor: pointer; position: relative; overflow: hidden; } .avatar-uploader .el-upload:hover { border-color: #ffc200; } .avatar-uploader-icon { font-size: 28px; color: #8c939d; width: 200px; height: 160px; line-height: 160px; text-align: center; } .avatar { width: 200px; height: 160px; display: block; } // .el-form--inline .el-form-item__content { // width: 293px; // } .el-input { width: 293px; } .address { .el-form-item__content { width: 777px !important; } } .el-input__prefix { top: 2px; } .addDish { .el-input { width: 130px; } .el-input-number__increase { border-left: solid 1px #fbe396; background: #fffbf0; } .el-input-number__decrease { border-right: solid 1px #fbe396; background: #fffbf0; } input { border: 1px solid #fbe396; } .table { border: solid 1px #ebeef5; border-radius: 3px; th { padding: 5px 0; } td { padding: 7px 0; } } } .addDishList { .seachDish { position: absolute; top: 12px; right: 20px; } .el-dialog__footer { padding-top: 27px; } .el-dialog__body { padding: 0; border-bottom: solid 1px #efefef; } .seachDish { .el-input__inner { height: 40px; line-height: 40px; } } } } .addBrand { &-container { margin: 30px; .container { position: relative; z-index: 1; background: #fff; padding: 30px; border-radius: 4px; min-height: 500px; .subBox { padding-top: 30px; text-align: center; border-top: solid 1px $gray-5; } .el-input { width: 350px; } .addDish { width: 777px; .addBut { background: #ffc200; display: inline-block; padding: 0px 20px; border-radius: 3px; line-height: 40px; cursor: pointer; border-radius: 4px; color: #333333; font-weight: 500; } .content { background: #fafafb; padding: 20px; border: solid 1px #d8dde3; border-radius: 3px; } } } } }

                                                              src/views/setmeal/components/AddDish.vue

                                                                
                                                                  
                                                                    
                                                                      {{ item.name }}
                                                                    
                                                                    
                                                                      
                                                                        
                                                                          
                                                                        
                                                                        
                                                                          
                                                                            
                                                                              
                                                                                {{
                                                                                  item.dishName
                                                                                }}
                                                                                {{ item.status == 0 ? '停售' : '在售' }}
                                                                                {{ (Number(item.price) ).toFixed(2)*100/100 }}
                                                                              
                                                                            
                                                                          
                                                                        
                                                                      
                                                                    
                                                                  
                                                                  
                                                                    
                                                                      已选菜品({{ checkedListAll.length }})
                                                                    
                                                                    
                                                                      
                                                                        {{ item.dishName || item.name }}
                                                                        ¥ {{ (Number(item.price) ).toFixed(2)*100/100 }} 
                                                                        
                                                                          
                                                                        
                                                                      
                                                                    
                                                                  
                                                                
                                                              
                                                              
                                                              import { Component, Prop, Vue, Watch } from 'vue-property-decorator'
                                                              // import {getDishTypeList, getDishListType} from '@/api/dish';
                                                              import { getCategoryList, queryDishList } from '@/api/dish'
                                                              import Empty from '@/components/Empty/index.vue'
                                                              @Component({
                                                                name: 'selectInput',
                                                                components: {
                                                                  Empty
                                                                }
                                                              })
                                                              export default class extends Vue {
                                                                @Prop({ default: '' }) private value!: number
                                                                @Prop({ default: [] }) private checkList!: any[]
                                                                @Prop({ default: '' }) private seachKey!: string
                                                                private dishType: [] = []
                                                                private dishList: [] = []
                                                                private allDishList: any[] = []
                                                                private dishListCache: any[] = []
                                                                private keyInd = 0
                                                                private searchValue: string = ''
                                                                public checkedList: any[] = []
                                                                private checkedListAll: any[] = []
                                                                private ids: any = new Set()
                                                                created() {
                                                                  this.init()
                                                                }
                                                                @Watch('seachKey')
                                                                private seachKeyChange(value: any) {
                                                                  if (value.trim()) {
                                                                    this.getDishForName(this.seachKey)
                                                                  }
                                                                }
                                                                public init() {
                                                                  // 菜单列表数据获取
                                                                  this.getDishType()
                                                                  // 初始化选项
                                                                  this.checkedList = this.checkList.map((it: any) => it.name)
                                                                  // 已选项的菜品-详细信息
                                                                  this.checkedListAll = this.checkList.reverse()
                                                                }
                                                                // 获取套餐分类
                                                                public getDishType() {
                                                                  getCategoryList({ type: 1 }).then(res => {
                                                                    if (res && res.data && res.data.code === 1) {
                                                                      this.dishType = res.data.data
                                                                      this.getDishList(res.data.data[0].id)
                                                                    } else {
                                                                      this.$message.error(res.data.msg)
                                                                    }
                                                                    // if (res.data.code == 200) {
                                                                    //   const { data } = res.data
                                                                    //   this.   = data
                                                                    //   this.getDishList(data[0].category_id)
                                                                    // } else {
                                                                    //   this.$message.error(res.data.desc)
                                                                    // }
                                                                  })
                                                                }
                                                                // 通过套餐ID获取菜品列表分类
                                                                private getDishList(id: number) {
                                                                  queryDishList({ categoryId: id }).then(res => {
                                                                    if (res && res.data && res.data.code === 1) {
                                                                      if (res.data.data.length == 0) {
                                                                        this.dishList = []
                                                                        return
                                                                      }
                                                                      let newArr = res.data.data
                                                                      newArr.forEach((n: any) => {
                                                                        n.dishId = n.id
                                                                        n.copies = 1
                                                                        // n.dishCopies = 1
                                                                        n.dishName = n.name
                                                                      })
                                                                      this.dishList = newArr
                                                                      if (!this.ids.has(id)) {
                                                                        this.allDishList = [...this.allDishList, ...newArr]
                                                                      }
                                                                      this.ids.add(id)
                                                                    } else {
                                                                      this.$message.error(res.data.msg)
                                                                    }
                                                                  })
                                                                }
                                                                // 关键词收搜菜品列表分类
                                                                private getDishForName(name: any) {
                                                                  queryDishList({ name }).then(res => {
                                                                    if (res && res.data && res.data.code === 1) {
                                                                      let newArr = res.data.data
                                                                      newArr.forEach((n: any) => {
                                                                        n.dishId = n.id
                                                                        n.dishName = n.name
                                                                      })
                                                                      this.dishList = newArr
                                                                    } else {
                                                                      this.$message.error(res.data.msg)
                                                                    }
                                                                  })
                                                                }
                                                                // 点击分类
                                                                private checkTypeHandle(ind: number, id: any) {
                                                                  this.keyInd = ind
                                                                  this.getDishList(id)
                                                                }
                                                                // 添加菜品
                                                                private checkedListHandle(value: [string]) {
                                                                  // TODO 实现倒序 由于value是组件内封装无法从前面添加 所有取巧处理倒序添加
                                                                  // 倒序展示 - 数据处理前反正 为正序
                                                                  this.checkedListAll.reverse()
                                                                  // value 是一个只包含菜品名的数组 需要从 dishList中筛选出 对应的详情
                                                                  // 操作添加菜品
                                                                  const list = this.allDishList.filter((item: any) => {
                                                                    let data
                                                                    value.forEach((it: any) => {
                                                                      if (item.name == it) {
                                                                        data = item
                                                                      }
                                                                    })
                                                                    return data
                                                                  })
                                                                  // 编辑的时候需要与已有菜品合并
                                                                  // 与当前请求下的选择性 然后去重就是当前的列表
                                                                  const dishListCat = [...this.checkedListAll, ...list]
                                                                  let arrData: any[] = []
                                                                  this.checkedListAll = dishListCat.filter((item: any) => {
                                                                    let allArrDate
                                                                    if (arrData.length == 0) {
                                                                      arrData.push(item.name)
                                                                      allArrDate = item
                                                                    } else {
                                                                      const st = arrData.some(it => item.name == it)
                                                                      if (!st) {
                                                                        arrData.push(item.name)
                                                                        allArrDate = item
                                                                      }
                                                                    }
                                                                    return allArrDate
                                                                  })
                                                                  // 如果是减菜 走这里
                                                                  if (value.length  {
                                                                      if (value.some(it => it == item.name)) {
                                                                        return item
                                                                      }
                                                                    })
                                                                  }
                                                                  this.$emit('checkList', this.checkedListAll)
                                                                  // 数据处理完反转为倒序
                                                                  this.checkedListAll.reverse()
                                                                }
                                                                open(done: any) {
                                                                  this.dishListCache = JSON.parse(JSON.stringify(this.checkList))
                                                                }
                                                                close(done: any) {
                                                                  this.checkList = this.dishListCache
                                                                }
                                                                // 删除
                                                                private delCheck(name: any) {
                                                                  const index = this.checkedList.findIndex(it => it === name)
                                                                  const indexAll = this.checkedListAll.findIndex(
                                                                    (it: any) => it.name === name
                                                                  )
                                                                  this.checkedList.splice(index, 1)
                                                                  this.checkedListAll.splice(indexAll, 1)
                                                                  this.$emit('checkList', this.checkedListAll)
                                                                }
                                                              }
                                                              
                                                              
                                                              .addDish {
                                                                .el-checkbox__label {
                                                                  width: 100%;
                                                                }
                                                                .empty-box {
                                                                  margin-top: 50px;
                                                                  margin-bottom: 0px;
                                                                }
                                                              }
                                                              
                                                              
                                                              .addDish {
                                                                padding: 0 20px;
                                                                display: flex;
                                                                line-height: 40px;
                                                                .empty-box {
                                                                  img {
                                                                    width: 190px;
                                                                    height: 147px;
                                                                  }
                                                                }
                                                                .borderNone {
                                                                  border: none !important;
                                                                }
                                                                span,
                                                                .tit {
                                                                  color: #333;
                                                                }
                                                                .leftCont {
                                                                  display: flex;
                                                                  border-right: solid 1px #efefef;
                                                                  width: 60%;
                                                                  padding: 15px;
                                                                  .tabBut {
                                                                    width: 110px;
                                                                    font-weight: bold;
                                                                    border-right: solid 2px #f4f4f4;
                                                                    span {
                                                                      display: block;
                                                                      text-align: center;
                                                                      // border-right: solid 2px #f4f4f4;
                                                                      cursor: pointer;
                                                                      position: relative;
                                                                    }
                                                                  }
                                                                  .act {
                                                                    border-color: $mine !important;
                                                                    color: $mine !important;
                                                                  }
                                                                  .act::after {
                                                                    content: ' ';
                                                                    display: inline-block;
                                                                    background-color: $mine;
                                                                    width: 2px;
                                                                    height: 40px;
                                                                    position: absolute;
                                                                    right: -2px;
                                                                  }
                                                                  .tabList {
                                                                    flex: 1;
                                                                    padding: 15px;
                                                                    height: 400px;
                                                                    overflow-y: scroll;
                                                                    .table {
                                                                      border: solid 1px #f4f4f4;
                                                                      border-bottom: solid 1px #f4f4f4;
                                                                      .items {
                                                                        border-bottom: solid 1px #f4f4f4;
                                                                        padding: 0 10px;
                                                                        display: flex;
                                                                        .el-checkbox,
                                                                        .el-checkbox__label {
                                                                          width: 100%;
                                                                        }
                                                                        .item {
                                                                          display: flex;
                                                                          padding-right: 20px;
                                                                          span {
                                                                            display: inline-block;
                                                                            text-align: center;
                                                                            flex: 1;
                                                                            font-weight: normal;
                                                                          }
                                                                        }
                                                                      }
                                                                    }
                                                                  }
                                                                }
                                                                .ritCont {
                                                                  width: 40%;
                                                                  .tit {
                                                                    margin: 0 15px;
                                                                    font-weight: bold;
                                                                  }
                                                                  .items {
                                                                    height: 338px;
                                                                    padding: 4px 15px;
                                                                    overflow: scroll;
                                                                  }
                                                                  .item {
                                                                    box-shadow: 0px 1px 4px 3px rgba(0, 0, 0, 0.03);
                                                                    display: flex;
                                                                    text-align: center;
                                                                    padding: 0 10px;
                                                                    margin-bottom: 20px;
                                                                    border-radius: 6px;
                                                                    color: #818693;
                                                                    span:first-child {
                                                                      text-align: left;
                                                                      color: #20232a;
                                                                      flex: 70%;
                                                                    }
                                                                    .price {
                                                                      display: inline-block;
                                                                      flex: 70%;
                                                                      text-align: left;
                                                                    }
                                                                    .del {
                                                                      cursor: pointer;
                                                                      img {
                                                                        position: relative;
                                                                        top: 5px;
                                                                        width: 20px;
                                                                      }
                                                                    }
                                                                  }
                                                                }
                                                              }
                                                              
                                                              

                                                              src/api/setMeals.ts

                                                              // 修改数据接口
                                                              export const editSetmeal = (params: any) => {
                                                                  return request({
                                                                      url: '/setmeal',
                                                                      method: 'put',
                                                                      data: { ...params }
                                                                  })
                                                              }
                                                              // 新增数据接口
                                                              export const addSetmeal = (params: any) => {
                                                                  return request({
                                                                      url: '/setmeal',
                                                                      method: 'post',
                                                                      data: { ...params }
                                                                  })
                                                              }
                                                              // 查询详情接口
                                                              export const querySetmealById = (id: string | (string | null)[]) => {
                                                                  return request({
                                                                      url: `/setmeal/${id}`,
                                                                      method: 'get'
                                                                  })
                                                              }

                                                              src/api/dish.ts

                                                              import request from '@/utils/request'
                                                              /**
                                                               *
                                                               * 菜品管理
                                                               *
                                                               **/
                                                              // 查询列表接口
                                                              export const getDishPage = (params: any) => {
                                                                return request({
                                                                  url: '/dish/page',
                                                                  method: 'get',
                                                                  params
                                                                })
                                                              }
                                                              // 删除接口
                                                              export const deleteDish = (ids: string) => {
                                                                return request({
                                                                  url: '/dish',
                                                                  method: 'delete',
                                                                  params: { ids }
                                                                })
                                                              }
                                                              // 修改接口
                                                              export const editDish = (params: any) => {
                                                                return request({
                                                                  url: '/dish',
                                                                  method: 'put',
                                                                  data: { ...params }
                                                                })
                                                              }
                                                              // 新增接口
                                                              export const addDish = (params: any) => {
                                                                return request({
                                                                  url: '/dish',
                                                                  method: 'post',
                                                                  data: { ...params }
                                                                })
                                                              }
                                                              // 查询详情
                                                              export const queryDishById = (id: string | (string | null)[]) => {
                                                                return request({
                                                                  url: `/dish/${id}`,
                                                                  method: 'get'
                                                                })
                                                              }
                                                              // 获取菜品分类列表
                                                              export const getCategoryList = (params: any) => {
                                                                return request({
                                                                  url: '/category/list',
                                                                  method: 'get',
                                                                  params
                                                                })
                                                              }
                                                              // 查菜品列表的接口
                                                              export const queryDishList = (params: any) => {
                                                                return request({
                                                                  url: '/dish/list',
                                                                  method: 'get',
                                                                  params
                                                                })
                                                              }
                                                              // 文件down预览
                                                              export const commonDownload = (params: any) => {
                                                                return request({
                                                                  headers: {
                                                                    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
                                                                  },
                                                                  url: '/common/download',
                                                                  method: 'get',
                                                                  params
                                                                })
                                                              }
                                                              // 起售停售---批量起售停售接口
                                                              export const dishStatusByStatus = (params: any) => {
                                                                return request({
                                                                  url: `/dish/status/${params.status}`,
                                                                  method: 'post',
                                                                  params: { id: params.id }
                                                                })
                                                              }
                                                              //菜品分类数据查询
                                                              export const dishCategoryList = (params: any) => {
                                                                return request({
                                                                  url: `/category/list`,
                                                                  method: 'get',
                                                                  params: { ...params }
                                                                })
                                                              }
                                                              

                                                              ③点击”保存“按钮完成新增操作

                                                              功能测试

                                                              完结!!!

                                                              前端完整源码:https://pan.baidu.com/s/1JAI65SyP8qIIeLxh2U923g?pwd=ewap 

                                                              后端完整源码:https://pan.baidu.com/s/1hHnA-H_xOFiVEeIVi92A3Q?pwd=0k80 

                                                               

微信扫一扫加客服

微信扫一扫加客服

点击启动AI问答
Draggable Icon