Java项目苍穹外卖:前端开发

苍穹外卖

苍穹外卖前端开发

Vue基础

基于脚手架创建前端工程

1.环境要求:

  • node.js:前端项目的运行环境。
  • npmJavaScript的包管理工具。
  • Vue CLI:基于Vue进行快速开发的完整系统,实现交互式的项目脚手架。

2.使用Vue CLI创建前端工程:

  • 方式一:vue create 项目名称
  • 方式二:vue ui

3.项目结构

4.启动前端项目:npm run serve

5.前端项目启动后,服务端口默认为8080,很容易和后端tomcat端口号冲突。可以修改前端服务的端口号。

vue.config.js中配置前端服务端口号:

1
2
3
4
5
6
7
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
port: 7070
}
})

Vue基本使用方式

Vue组件

Vue的组件文件以.vue结尾,每个组件由三部分组成:

  1. 结构<template>:只有一个根元素,由它生成HTML代码。
  2. 样式<style>:编写CSS,控制页面展示效果,全局样式,影响所有组件,局部样式,只作用于当前组件。
  3. 逻辑<script>:编写JS代码,控制模版的数据来源和行为。
文本插值

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

用法:{{}}

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
    <div>
        <h1>{{ name }}</h1>
        <h1>{{ age > 60 ? '老年' : '青年' }}</h1>
    </div>
</template>
<script>
    export default {
        data() {
            return { name: '张三', age: 30 };
        }
    };
</script>
属性绑定

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
    <div>
        <div><input type="text" v-bind:value="name"></div>
        <div><input type="text" :value="age"></div>
        <div><img :src="url"/></div>
    </div>
</template>
<script>
export default {
    data () {
        return {
            name: '王五',
            age: 20,
            src: 'https://www.itcast.cn/2018czgw/images/logo2.png'
        };
    }
}
</script>
事件绑定

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
    <div>
      <div>
        <input type="button" value="保存" v-on:click="handleSave"/>
        <input type="button" value="保存" @click="handleSave"/><br>
      </div>
    </div>
  </template>
<script>
export default {
    data(){ return { name: ‘张三’}
    },
    methods: {
        handleSave(){
            alert(this.name)
        }
    }
}
</script>
双向绑定

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

用法:v-model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
    <div>
        <div>
            双向绑定:{{ name }}
            <input type="text" v-model="name" />
            <input type="button" value="改变" @click="handleChange"/>
        </div>
    </div>
  </template>
<script>
export default {
    data(){return {name: '张三'}
    },
    methods: {
        handleChange(){
            this.name = '李四'
        }
    }
}
</script>
条件渲染

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

用法:v-ifv-elsev-else-if

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
    <div>
        <div v-if="sex == 1">
            男
        </div>
        <div v-else-if="sex == 2">
            女
        </div>
        <div v-else>
            未知
        </div>
    </div>
  </template>
 
<script>
export default {
    data(){
        return {sex: 1}
    }
}
</script>
axios

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

安装命令:npm install axios

导入命令:import axios from 'axios'

axiosAPI列表:

参数说明:

  • url:请求路径。
  • data:请求体数据,最常见的是JSON格式数据。
  • config:配置对象,可以设置查询参数、请求头信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<template>
<div>
<input type="button" value="发送POST请求" @click="handleSendPOST" />
<input type="button" value="发送GET请求" @click="handleSendGET" />
<input type="button" value="统一请求方式" @click="handleSend" />
</div>
</template>

<script>
import axios from 'axios'

export default {
methods: {
handleSendPOST(){
axios.post('/api/admin/employee/login', {
username: 'admin',
password: '123456'
}).then(res => {
console.log(res.data)
}).catch(error => {
console.log(error.response)
})
},

handleSendGET(){
axios.get('api/admin/shop/status', {
headers: {
token: "eyJhbGciOiJIUzI1NiJ9.eyJlbXBJZCI6MSwiZXhwIjoxNzMwNzgxODY0fQ.F9E5ntRqyRP2sVa4-95ZjErIfuDEV6q4Oi3Btya17Qg"
}
}).then(res => {
console.log(res.data)
})
},

handleSend(){ //axios统一调用方式发送请求
axios({
url: '/api/admin/employee/login',
method: 'post',
data: {
username: 'admin',
password: '123456'
}
}).then(res => {
console.log(res.data.data.token)
axios({
url: 'api/admin/shop/status',
method: 'get',
headers: {
token: res.data.data.token
}
})
})
}
}
}
</script>
解决跨域问题

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
port: 7070,
proxy: { //配置前端代理
'/api': { //前端请求路径前缀api
target: 'http://localhost:8080', //路径转发
pathRewrite: { //路径重写
'^/api' : ''
}
}
}
}
})

路由Vue-Router

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

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

路由配置

路由组成:

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

<router-link>:路由链接组件,浏览器会解析成<a>

<router-view>:路由视图组件,用来展示与路由路径匹配的视图组件。

路由跳转
  • 标签式

    1
    <router-link to="/">Home</router-link>
  • 编程式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <template>
    <div id="app">
    <nav>
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link> |
    <input type="button" value="编程式路由跳转" @click="jump"/>
    </nav>
    <!-- 视图组件展示的位置 -->
    <router-view/>
    </div>
    </template>

    <script>
    export default{
    methods: {
    jump(){
    //使用编程式路由跳转方式
    this.$router.push('about') //this.$router 是获取到路由对象,push方法是根据url进行跳转

    }
    }
    }
    </script>
404页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//index.js
//维护路由表,某个路由路径对应哪个视图组件
const routes = [
{
path: '/',
name: 'home',
component: HomeView //静态导入
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue') //懒加载,动态导入
},
{
path: '/404',
component: () => import('../views/404View.vue')
},
{
path: '*', //前面的都匹配不到,就会走到这
redirect: '/404' //重定向到404
}
]
1
2
3
4
5
6
<!-- 404View.vue -->
<template>
<div class="about">
<h1>您请求的资源不存在</h1>
</div>
</template>
嵌套路由

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

实现步骤:

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<template>
<div>
<el-container>
<el-header>Header</el-header>
<el-container>
<el-aside width="200px">
<router-link to="/c/p1">P1</router-link> <br>
<router-link to="/c/p2">P2</router-link> <br>
<router-link to="/c/p3">P3</router-link> <br>
</el-aside>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</div>
</template>

<script>
export default {

}
</script>

<style>
.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;
}
</style>

2.提供子视图组件,用于效果展示:P1View.vueP2View.vueP3View.vue

1
2
3
4
5
<template>
<div>
P1View <!-- 三个组件更换这部分内容即可 -->
</div>
</template>

3.在src/router/index.js中配置路由映射规则(嵌套路由配置)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
path: '/c',
component: () => import('../views/container/ContainerView.vue'),
redirect: '/c/p1',
//嵌套路由(子路由),对应的组件会展示在当前组件内部
children: [
{
path: '/c/p1',
component: () => import('../views/container/P1View.vue')
},
{
path: '/c/p2',
component: () => import('../views/container/P2View.vue')
},
{
path: '/c/p3',
component: () => import('../views/container/P3View.vue')
}
]
},

4.在布局容器视图中添加<router-view>,实现子视图组件展示。

5.在布局容器视图中添加<router-link>,实现路由请求。

注意:子路由变化,切换的是【ContainerView组件】中 <router-view></router-view> 部分的内容。

状态管理vuex

介绍

vuex是一个专为Vue.js应用程序开发的状态管理库。

vuex可以在多个组件之间共享数据,并且共享的数据是响应式的,即数据的变更能及时渲染到模板。

vuex采用集中式存储管理所有组件的状态。

安装vuexnpm install vuex@next --save。(可以创建带有vuex功能的脚手架工程来使用vuex

核心概念:

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

store对象的state属性中定义共享数据。

store对象的mutations属性中定义修改共享数据的函数。

store对象的actions属性中定义调用mutation的函数,可以进行异步操作。

mutations中的函数不能直接调用,只能通过store对象的commit方法调用。

actions中定义的函数不能直接调用,只能通过store对象的dispatch方法调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//index.js
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

Vue.use(Vuex) //导入vuex,在次文件中统一管理共享数据

//集中管理多个组件共享的数据
export default new Vuex.Store({
state: { //集中定义共享数据
name: '未登录游客'
},
getters: {},
mutations: { //修改共享数据只能通过mutations实现,必须是同步操作
setName(state, newName){
state.name = newName
}
},
actions: { //通过actions可以调用到mutations,在actions中可以进行异步操作
setNameByAxios(context){
axios({
url: '/api/admin/employee/login',
method: 'post',
data: {
username: 'admin',
password: '123456'
}
}).then( res => {
if(res.data.code == 1){
//异步请求后,需要修改共享数据
//在actions中调用mutation中定义的setName函数
context.commit('setName', res.data.data.name)
}
})
}
},
modules: {}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<!-- App.vue -->
<template>
<div id="app">
欢迎你,{{ $store.state.name }}
<input type="button" value="通过mutations修改共享数据" @click="handleUpdate"/>
<input type="button" value="通过actions修改共享数据" @click="handleCallAction"/>

<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App" />
</div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
name: 'App',
components: {
HelloWorld
},
methods: {
handleUpdate(){
//mutations中定义的函数不能直接调用,必须通过这种方式来调用
//第一个参数为mutations中定义的函数名称,第二个参数为传递的参数
this.$store.commit('setName', '李四')
},
handleCallAction(){
//调用actions中定义的函数
this.$store.dispatch('setNameByAxios')
}
}
}
</script>

<style>
#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;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//vue.config.js文件,配置代理
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
port: 7777,
proxy: {
'/api' : {
target: 'http://localhost:8080',
pathRewrite: {
'^/api' : ''
}
}
}
}
})

TypeScript

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

在前端项目中使用TypeScript,需要进行安装,命令为:npm install -g typescript

查看TypeScript版本:tsc -v

入门

1.创建hello.ts文件。

1
2
3
4
5
6
7
//定义一个函数 hello,并且指定参数类型为string
function hello(msg:string) {
console.log(msg)
}

//调用上面的函数,传递非string类型的参数
hello(123)

2.使用tsc命令编译hello.ts文件。

1
2
3
4
5
6
7
8
PS E:\2_learn\Java-waimai\code\vue_project\ts-demo> tsc .\hello.ts
hello.ts:7:7 - error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.

7 hello(123)
~~~


Found 1 error in hello.ts:7

可以看到编译报错,提示参数类型不匹配。这说明在编译时TS会进行类型检查。需要注意的是在编译为JS文件后,类型会被擦除。

编译后:

1
2
3
4
5
6
//定义一个函数 hello,并且指定参数类型为string
function hello(msg) {
console.log(msg);
}
//调用上面的函数,传递非string类型的参数
hello("hi");

TypeScriptJavaScript的区别:

  • TS属于静态类型编程语言,JS属于动态类型编程语言。
  • 静态类型在编译期做类型检查,动态类型在执行期做类型检查。
  • 对于JS来说,需要等到代码执行的时候才能发现错误(晚)。
  • 对于TS来说,在代码编译的时候就可以发现错误(早)。
  • 配合VSCode开发工具,TS可以提前到在编写代码的同时就发现代码中的错误,减少找Bug、改Bug的时间。
TypeScript 常用类型
类型 备注
字符串类型 string
数字类型 number
布尔类型 boolean
数组类型 number[],string[], boolean[] 依此类推
任意类型 any 相当于又回到了没有类型的时代
复杂类型 type 与 interface
函数类型 () => void 对函数的参数和返回值进行说明
字面量类型 “a”|”b”|”c” 限制变量或参数的取值
class 类 class Animal

基于TS进行前端开发时,类型标注的位置有如下3个:标注变量、标注参数、标注返回值。

1
2
3
4
5
6
//标注变量,指定变量msg的类型为string
let msg:string='hello ts !'
//标注参数和返回值,指定m2函数的参数类型为string,并且返回值也为string
const m2 = (name : string) : string => {
return name.toLowerCase() + msg
}
字符串、数字、布尔类型
1
2
3
4
5
6
7
8
9
10
11
12
//字符串类型
let username: string = 'itcast'

//数字类型
let age: number = 20

//布尔类型
let isTrue: boolean = true

console.log(username)
console.log(age)
console.log(isTrue)
字面量类型

字面量类型用于限定数据的取值范围,类似于java中的枚举。

1
2
3
4
5
6
7
//字面量类型
function printText(s: string, alignment: 'left'|'right'|'center'){
console.log(s,alignment)
}

printText('hello','left')
//printText('hello','aaa')
interface类型

interface类型是TS中的复杂类型,它让TypeScript具备了JavaScript所缺少的、描述较为复杂数据结构的能力。

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

1
2
3
4
5
6
7
8
9
10
//定义接口
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属性
class 类型

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//定义一个类,使用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()

在定义类时,可以使用implments关键字实现接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//定义接口
interface Animal {
name: string
eat(): void
}

//定义一个类,实现上面的接口
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()

在定义类时,可以使用extends关键字 继承其他类。

1
2
3
4
5
6
7
8
9
10
11
12
//定义一个类,继承上面的类
class Parrot extends Bird {
say() {
console.log(this.name + ' say hello')
}
}

const myParrot = new Parrot('Polly')

myParrot.eat()
myParrot.say()
console.log(myParrot.name)

前端环境搭建

代码导入

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

使用的node版本为12.22.0可以成功npm install所需的包。

前端代码结构

  • api:存放封装了Ajax请求文件的目录。
  • components:公共组件存放目录。
  • views:存放视图组件的目录。
  • App.vue:项目的主组件,页面的入口文件。
  • main.ts:整个项目的入口文件。
  • router.ts:路由文件。

员工管理

员工分页查询

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

1
2
3
4
5
6
7
8
{
path: "employee",
component: () => import("@/views/employee/index.vue"),
meta: {
title: "员工管理",
icon: "icon-employee"
}
},

2.制作页面头部效果,为查询按钮绑定事件,发送Ajax请求获取分页数据。

输入框和按钮都是使用ElementUI提供的组件。

对于前端的组件只需要参考ElementUI提供的文档,进行修改即可。

1
2
3
4
5
6
7
8
<div class="tableBar">
<label style="margin-right: 5px;">
员工姓名:
</label>
<el-input placeholder="请输入员工姓名" style="width: 15%;" v-model="name" />
<el-button type="primary" style="margin-left: 25px;" @click="pageQuery()">查询</el-button>
<el-button type="primary" style="float: right;">+添加员工</el-button>
</div>

3.在src/api/employee.ts中定义方法,发送Ajax请求获取分页数据。

1
2
3
4
5
6
7
// 分页查询员工
export const getEmployeeList = (params: any) =>
request({
'url': `/employee/page`,
'method': 'GET',
'params': params
})

3.(1)定义pageQuery方法,发送Ajax请求获取分页数据。

先验证当前pageQuery方法能否正常执行。按照规范,真正发送Ajax请求的代码需要封装到api目录下的ts文件中(src/api/employee.ts)。pageQuery方法中调用getEmployeeList方法。

(2)在员工管理组件中导入employee.ts中定义的方法,并在data() 方法中定义分页相关的模型数据。

注意:需要将name属性和上面的输入框进行双向绑定。

(3)提供vue的初始化方法created(),在页面加载后就查询分页数据。

(4)使用ElementUI提供的表格组件展示分页数据。

(5)动态展示启用、禁用按钮:

  • 如果当前员工的状态为启用,则展示为【禁用】按钮。
  • 如果当前员工的状态为禁用,则展示为【启用】按钮。

(6)使用ElementUI提供的分页条组件,并绑定事件处理函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<script lang="ts">
import { getEmployeeList } from '@/api/employee'

export default {
data() {
return {
name: '', //员工姓名,对应上面的输入框
page: 1, //页码
pageSize: 10, //每页记录数
total: 0, //总记录数
records: [] //当前页要展示的数据集合
}
},
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.error("请求出错了:" + err.message)
})
},

//pageSize发生变化时触发
handleSizeChange(pageSize){
this.pageSize = pageSize
this.pageQuery()
},
//page发生变化时出发
handleCurrentChange(page){
this.page = page
this.pageQuery()
}
}
}
</script>

启用禁用员工账号

1.为启用、禁用按钮绑定单击事件handleStartOrStop

1
2
3
4
5
6
7
8
<el-table-column label="操作">
<template slot-scope="scope">
<!-- type="text"表示看起来像文字,但本质是一个按钮 -->
<el-button type="text">修改</el-button>
<el-button type="text" @click="handleStartOrStop(scope.row)">{{ scope.row.status === 1 ? '禁用' : '启用'
}}</el-button>
</template>
</el-table-column>

2.编写handleStartOrStop`方法。

注意:如果是管理员账号则不允许更改账号状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//启用禁用员工账号
handleStartOrStop(row) {
//alert(`id=${row.id}, status=${row.status}`)
if (row.username === 'admin') {
this.$message.error('admin为系统的管理员账号,不能更改账号状态!')
return
}
//弹出确认提示框
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()
}
})
})
}

3.在employee.ts中封装启用禁用员工账号方法,发送Ajax请求。

1
2
3
4
5
6
7
// 启用禁用员工账号
export const enableOrDisableEmployee = (params: any) =>
request({
'url': `/employee/status/${params.status}`,
'method': 'POST',
'params': {id: params.id}
})

新增员工

添加员工操作步骤:

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

1.为 “添加员工”按钮绑定单击事件。(index.vue

1
<el-button type="primary" style="float: right;" @click="handleAddEmp()">+添加员工</el-button>

2.提供handleAddEmp方法,进行路由跳转。(index.vue

1
2
3
4
5
//跳转到新增员工页面(组件)
handleAddEmp() {
//路由跳转,跳转到新增员工组件
this.$router.push('/employee/add')
}

注意:在路由文件中已经配置了如下路由规则。

1
2
3
4
5
6
7
8
{
path: "/employee/add",
component: () => import("@/views/employee/addEmployee.vue"),
meta: {
title: "添加/修改员工",
hidden: true
}
},

3.根据产品原型,开发页面元素。(addEmployee.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<template>
<div class="addBrand-container">
<div class="container">
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="180px">
<el-form-item label="账号" prop="username">
<el-input v-model="ruleForm.username"></el-input>
</el-form-item>
<el-form-item label="员工姓名" prop="name">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="ruleForm.phone"></el-input>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-radio v-model="ruleForm.sex" label="1">男</el-radio>
<el-radio v-model="ruleForm.sex" label="2">女</el-radio>
</el-form-item>
<el-form-item label="身份证号" prop="idNumber">
<el-input v-model="ruleForm.idNumber"></el-input>
</el-form-item>
<div class="subBox">
<!-- submitForm中第一个参数对ruleForm再次校验;第二个参数,false:保存后跳转分页查询页面,true:保存后留在当前页面继续添加 -->
<el-button type="primary" @click="submitForm('ruleForm', false)">保存</el-button>
<!-- 通过this.optType区分新增和修改页面,add为新增,update为修改 -->
<el-button v-if="this.optType === 'add'" type="primary" @click="submitForm('ruleForm', true)">保存并继续添加员工
</el-button>
<el-button @click="() => this.$router.push('/employee')">返回</el-button>
</div>
</el-form>
</div>
</div>
</template>

<style lang="scss" scoped>
.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;
}
}
}
</style>

4.在employee.ts中封装新增员工方法,发送Ajax请求。

1
2
3
4
5
6
7
// 新增员工
export const addEmployee = (params: any) =>
request({
'url': `/employee`,
'method': 'POST',
'data': params //请求体传参
})

5.定义模型数据和表单校验规则。在methods中定义提交表单的方法。(addEmployee.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<script lang="ts">
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' } //失去焦点时,如果不输入该值,会报message中的错误
],
username: [
{ required: true, message: '请输入员工账号', trigger: 'blur' }
],
phone: [ //validator是校验器,rule:规则,value:当前用户输入,callback:回调
{
required: true, trigger: 'blur', validator: (rule, value, callback) => {
if (value === '' || (! /^1(3|4|5|6|7|8|9)\d{9}$/.test(value))) {
callback(new Error('请输入正确的手机号!'))
} else {
callback()
}
}
}
],
idNumber: [ //validator是校验器,rule:规则,value:当前用户输入,callback:回调
{
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(fromName, isContinue) {
//进行表单校验
//因为ref="ruleForm",所以通过$refs得到表单对象
this.$refs[fromName].validate((valid) => {
if (valid) {
//表单校验通过
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.message)
}
})
}
})
}
}
}
</script>

修改员工

修改员工操作步骤:

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

注意:

由于添加员工和修改员工的表单项非常类似,所以添加和修改操作可以共用同一个页面(addEmployee.vue)。

修改员工涉及到原始数据回显,所以需要传递员工id作为参数。

1.在员工管理页面index.vue中,为“修改”按钮绑定单击事件,用于跳转到修改页面。(index.vue

1
<el-button type="text" @click="handleUpdateEmp(scope.row)">修改</el-button>
1
2
3
4
5
6
7
8
9
10
11
12
13
//跳转到修改员工页面(组件)
handleUpdateEmp(row){
if(row.username === 'admin'){
this.$message.error("admin为系统的管理员账号,不能修改!")
return
}

//跳转到修改页面,通过地址栏传递参数
this.$router.push({
path: '/employee/add',
query: {id: row.id} //与增加组件的区别,传递了id参数
})
}

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

如果路由中传递了id参数,则当前操作为修改。

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

1
2
3
4
5
6
7
8
<div class="subBox">
<!-- submitForm中第一个参数对ruleForm再次校验;第二个参数,false:保存后跳转分页查询页面,true:保存后留在当前页面继续添加 -->
<el-button type="primary" @click="submitForm('ruleForm', false)">保存</el-button>
<!-- 通过this.optType区分新增和修改页面,add为新增,update为修改 -->
<el-button v-if="this.optType === 'add'" type="primary" @click="submitForm('ruleForm', true)">保存并继续添加员工
</el-button>
<el-button @click="() => this.$router.push('/employee')">返回</el-button>
</div>

3.如果是修改操作,需要根据id查询员工原始信息用于页面回显,在employee.ts中创建如下方法。

1
2
3
4
5
6
// 根据id查询员工
export const queryEmployeeById = (id: number) =>
request({
'url': `/employee/${id}`,
'method': 'GET'
})

4.在修改员工页面的created方法中查询员工原始信息用于页面数据回显。

1
2
3
4
5
6
7
8
9
10
11
12
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
}
})
}
},

5.如果是修改操作,“保存并继续添加员工”按钮则不需要显示。

1
2
3
4
5
6
7
8
<div class="subBox">
<!-- submitForm中第一个参数对ruleForm再次校验;第二个参数,false:保存后跳转分页查询页面,true:保存后留在当前页面继续添加 -->
<el-button type="primary" @click="submitForm('ruleForm', false)">保存</el-button>
<!-- 通过this.optType区分新增和修改页面,add为新增,update为修改 -->
<el-button v-if="this.optType === 'add'" type="primary" @click="submitForm('ruleForm', true)">保存并继续添加员工
</el-button>
<el-button @click="() => this.$router.push('/employee')">返回</el-button>
</div>

6.在employee.ts中创建方法,用于修改员工。

1
2
3
4
5
6
7
// 修改员工
export const updateEmployee = (params: any) =>
request({
'url': `/employee`,
'method': 'PUT',
'data': params //请求体传参
})

7.修改submitForm方法,需要根据当前操作类型执行新增或者修改操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
submitForm(fromName, isContinue) {
//进行表单校验
//因为ref="ruleForm",所以通过$refs得到表单对象
this.$refs[fromName].validate((valid) => {
if (valid) {
//表单校验通过
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')
}else{
this.$message.error(res.data.msg)
}
})
}
}
})
}

套餐管理

套餐分页查询


Java项目苍穹外卖:前端开发
http://surourou8.github.io/2024/11/21/Java项目苍穹外卖:前端开发/
作者
Su Rourou
发布于
2024年11月21日
许可协议