四、12306系统会员基础功能的实现

乘车人表的设计

新增/修改时间保存到毫秒

drop table if exists `passenger`;
create table `passenger` (
  `id` bigint not null comment 'id',
  `member_id` bigint not null comment '会员id',
  `name` varchar(20) not null comment '姓名',
  `id_card` varchar(18) not null comment '身份证',
  `type` char(1) not null comment '旅客类型|枚举[PassengerTypeEnum]',
  `create_time` datetime(3) comment '新增时间',
  `update_time` datetime(3) comment '修改时间',
   primary key (`id`),
   index `member_id_index` (`member_id`)
) engine=innodb default charset=utf8mb4 comment='乘车人';

用generator-config-member.xml生成持久层代码

<table tableName="passenger" domainObjectName="Passenger"/>

打开方式Maven--generator--Plugins--mybatis-generator--双击

增加乘车人类型枚举

 1 package com.zihans.train.member.enums;
 2 
 3 import java.util.ArrayList;
 4 import java.util.EnumSet;
 5 import java.util.HashMap;
 6 import java.util.List;
 7 
 8 public enum PassengerTypeEnum {
 9 
10     ADULT("1", "成人"),
11     CHILD("2", "儿童"),
12     STUDENT("3", "学生");
13 
14     private String code;
15 
16     private String desc;
17 
18     PassengerTypeEnum(String code, String desc) {
19         this.code = code;
20         this.desc = desc;
21     }
22 
23     public String getCode() {
24         return code;
25     }
26 
27     public void setCode(String code) {
28         this.code = code;
29     }
30 
31     public void setDesc(String desc) {
32         this.desc = desc;
33     }
34 
35     public String getDesc() {
36         return desc;
37     }
38 
39     public static List<HashMap<String,String>> getEnumList() {
40         List<HashMap<String, String>> list = new ArrayList<>();
41         for (PassengerTypeEnum anEnum : EnumSet.allOf(PassengerTypeEnum.class)) {
42             HashMap<String, String> map = new HashMap<>();
43             map.put("code",anEnum.code);
44             map.put("desc",anEnum.desc);
45             list.add(map);
46         }
47         return list;
48     }
49 }
PassengerTypeEnum.java

乘车人新增接口开发

暂时与Passager相同,设置属性不为空。

 1 package com.zihans.train.member.req;
 2 
 3 import jakarta.validation.constraints.NotBlank;
 4 
 5 import java.util.Date;
 6 
 7 public class PassengerSaveReq {
 8     private Long id;
 9 
10     //@NotNull(message = "【会员ID】不能为空")
11     private Long memberId;
12 
13     @NotBlank(message = "【名字】不能为空")
14     private String name;
15 
16     @NotBlank(message = "【身份证】不能为空")
17     private String idCard;
18 
19     @NotBlank(message = "【旅客类型】不能为空")
20     private String type;
21 
22     private Date createTime;
23 
24     private Date updateTime;
25 
26     public Long getId() {
27         return id;
28     }
29 
30     public void setId(Long id) {
31         this.id = id;
32     }
33 
34     public Long getMemberId() {
35         return memberId;
36     }
37 
38     public void setMemberId(Long memberId) {
39         this.memberId = memberId;
40     }
41 
42     public String getName() {
43         return name;
44     }
45 
46     public void setName(String name) {
47         this.name = name;
48     }
49 
50     public String getIdCard() {
51         return idCard;
52     }
53 
54     public void setIdCard(String idCard) {
55         this.idCard = idCard;
56     }
57 
58     public String getType() {
59         return type;
60     }
61 
62     public void setType(String type) {
63         this.type = type;
64     }
65 
66     public Date getCreateTime() {
67         return createTime;
68     }
69 
70     public void setCreateTime(Date createTime) {
71         this.createTime = createTime;
72     }
73 
74     public Date getUpdateTime() {
75         return updateTime;
76     }
77 
78     public void setUpdateTime(Date updateTime) {
79         this.updateTime = updateTime;
80     }
81 
82     @Override
83     public String toString() {
84         StringBuilder sb = new StringBuilder();
85         sb.append(getClass().getSimpleName());
86         sb.append(" [");
87         sb.append("Hash = ").append(hashCode());
88         sb.append(", id=").append(id);
89         sb.append(", memberId=").append(memberId);
90         sb.append(", name=").append(name);
91         sb.append(", idCard=").append(idCard);
92         sb.append(", type=").append(type);
93         sb.append(", createTime=").append(createTime);
94         sb.append(", updateTime=").append(updateTime);
95         sb.append("]");
96         return sb.toString();
97     }
98 }
PassengerSaveReq.java

在service层新建save保存方法,用于在数据库保存Passenger信息。

 1 package com.zihans.train.member.service;
 2 
 3 import cn.hutool.core.bean.BeanUtil;
 4 import cn.hutool.core.date.DateTime;
 5 import com.zihans.train.common.util.SnowUtil;
 6 import com.zihans.train.member.domain.Passenger;
 7 import com.zihans.train.member.mapper.PassengerMapper;
 8 import com.zihans.train.member.req.PassengerSaveReq;
 9 import jakarta.annotation.Resource;
10 import org.springframework.stereotype.Service;
11 
12 @Service
13 public class PassengerService {
14 
15     @Resource
16     private PassengerMapper passengerMapper;
17 
18     public void save(PassengerSaveReq req) {
19         DateTime now = DateTime.now();
20         Passenger passenger = BeanUtil.copyProperties(req, Passenger.class);
21         passenger.setId(SnowUtil.getSnowflakeNextId());
22         passenger.setCreateTime(now);
23         passenger.setUpdateTime(now);
24         passengerMapper.insert(passenger);
25     }
26 }
PassengerService.java

controller

 1 package com.zihans.train.member.controller;
 2 
 3 
 4 import com.zihans.train.common.resp.CommonResp;
 5 import com.zihans.train.member.req.PassengerSaveReq;
 6 import com.zihans.train.member.service.PassengerService;
 7 import jakarta.annotation.Resource;
 8 import jakarta.validation.Valid;
 9 import org.springframework.web.bind.annotation.PostMapping;
10 import org.springframework.web.bind.annotation.RequestBody;
11 import org.springframework.web.bind.annotation.RequestMapping;
12 import org.springframework.web.bind.annotation.RestController;
13 
14 @RestController
15 @RequestMapping("/passenger")
16 public class PassengerController {
17 
18     @Resource
19     private PassengerService passengerService;
20 
21     @PostMapping("/save")
22     public CommonResp<Object> save(@Valid @RequestBody PassengerSaveReq req) {
23         passengerService.save(req);
24         return new CommonResp<>();
25     }
26 
27 }
PassengerController.java

使用HTTPClient保存用户登录信息

如果使用gateway拦截器登录,每次请求都需要手动增加token,很不方便,可以用HTTPClient内置的全局变量返回token。

login请求时添加将token保存在全局变量。

> {%
client.log(JSON.stringify(response.body));
client.log(JSON.stringify(response.body.content.token));
client.global.set("token", response.body.content.token);
%}

读取

POST http://localhost:8001/member/passenger/save
Content-Type: application/json
token: {{token}}


{
  "memberId": "1",
  "name": "test",
  "idCard": "123321",
  "type": "1"
}

使用线程本地变量存储会员信息

功能实现流程:

  • 使用spring拦截器,获得登录会员信息
  • 增加专用的日志拦截器,统—设置日志流水号
  • 使用ThreadLocal保存登录信息

ThreadLocal可以方便线程内,多个方法传递参数。
本节方案:在接口入口获取会员信息,并放到线程本地变量,则在controller、service都可直接从线程本地变量获取会员信息

之前保存passenger需要前端传入member_id,这个不应该直接传递,要从token中拿,可以使用拦截器来实现。

gateway的拦截器只在gateway有效,而且gateway只是校验,并没有取东西,需要在member中添加拦截器,在controller处进行拦截。

拦截器是通用的,很多地方都要member_id,所以放在common模块。

common中新增拦截器MemberInterceptor拦截token。

 1 package com.zihans.train.common.interceptor;
 2 
 3 
 4 import cn.hutool.core.util.StrUtil;
 5 import cn.hutool.json.JSONObject;
 6 import cn.hutool.json.JSONUtil;
 7 import com.zihans.train.common.context.LoginMemberContext;
 8 import com.zihans.train.common.resp.MemberLoginResp;
 9 import com.zihans.train.common.util.JwtUtil;
10 import jakarta.servlet.http.HttpServletRequest;
11 import jakarta.servlet.http.HttpServletResponse;
12 import org.slf4j.Logger;
13 import org.slf4j.LoggerFactory;
14 import org.springframework.stereotype.Component;
15 import org.springframework.web.servlet.HandlerInterceptor;
16 
17 /**
18  * 拦截器:Spring框架特有的,常用于登录校验,权限校验,请求日志打印
19  */
20 @Component
21 public class MemberInterceptor implements HandlerInterceptor {
22 
23     private static final Logger LOG = LoggerFactory.getLogger(MemberInterceptor.class);
24 
25     @Override
26     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
27         //获取header的token参数
28         String token = request.getHeader("token");
29         if (StrUtil.isNotBlank(token)) {
30             LOG.info("获取会员登录token:{}", token);
31             JSONObject loginMember = JwtUtil.getJSONObject(token);
32             LOG.info("当前登录会员:{}", loginMember);
33             MemberLoginResp member = JSONUtil.toBean(loginMember, MemberLoginResp.class);
34             LoginMemberContext.setMember(member);
35         }
36         return true;
37     }
38 
39 }
MemberInterceptor.java

LoginMemberContext.java上下文来保存和使用本地变量。

 1 package com.zihans.train.common.context;
 2 
 3 
 4 import com.zihans.train.common.resp.MemberLoginResp;
 5 import org.slf4j.Logger;
 6 import org.slf4j.LoggerFactory;
 7 
 8 public class LoginMemberContext {
 9     private static final Logger LOG = LoggerFactory.getLogger(LoginMemberContext.class);
10 
11     private static ThreadLocal<MemberLoginResp> member = new ThreadLocal<>();
12 
13     public static MemberLoginResp getMember() {
14         return member.get();
15     }
16 
17     public static void setMember(MemberLoginResp member) {
18         LoginMemberContext.member.set(member);
19     }
20 
21     public static Long getId() {
22         try {
23             return member.get().getId();
24         } catch (Exception e) {
25             LOG.error("获取登录会员信息异常", e);
26             throw e;
27         }
28     }
29 
30 }
LoginMemberContext.java

需要配置让拦截器生效。member模块新增SpringMvcConfig实现WebMvcConfigurer接口,使拦截器生效。

 1 package com.zihans.train.member.config;
 2 
 3 import com.zihans.train.common.interceptor.MemberInterceptor;
 4 import jakarta.annotation.Resource;
 5 import org.springframework.context.annotation.Configuration;
 6 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 7 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 8 
 9 @Configuration
10 public class SpringMvcConfig implements WebMvcConfigurer {
11 
12     @Resource
13     MemberInterceptor memberInterceptor;
14 
15     @Override
16     public void addInterceptors(InterceptorRegistry registry) {
17         registry.addInterceptor(memberInterceptor)
18                 .addPathPatterns("/**")
19                 .excludePathPatterns(
20                         "/member/hello",
21                         "/member/member/send-code",
22                         "/member/member/login"
23                 );
24     }
25 }
SpringMvcConfig.java
 1 package com.zihans.train.member.resp;
 2 
 3 public class MemberLoginResp {
 4     private Long id;
 5 
 6     private String mobile;
 7 
 8     private String token;
 9 
10     public String getToken() {
11         return token;
12     }
13 
14     public void setToken(String token) {
15         this.token = token;
16     }
17 
18     public Long getId() {
19         return id;
20     }
21 
22     public void setId(Long id) {
23         this.id = id;
24     }
25 
26     public String getMobile() {
27         return mobile;
28     }
29 
30     public void setMobile(String mobile) {
31         this.mobile = mobile;
32     }
33 
34     @Override
35     public String toString() {
36         final StringBuffer sb = new StringBuffer("MemberLoginResp{");
37         sb.append("id=").append(id);
38         sb.append(", mobile='").append(mobile).append('\'');
39         sb.append(", token='").append(token).append('\'');
40         sb.append('}');
41         return sb.toString();
42     }
43 }
MemberLoginResp.java

这时,就可以在PassengerService中通过拦截器获得member_id。

 1 package com.zihans.train.member.service;
 2 
 3 import cn.hutool.core.bean.BeanUtil;
 4 import cn.hutool.core.date.DateTime;
 5 import com.zihans.train.common.context.LoginMemberContext;
 6 import com.zihans.train.common.util.SnowUtil;
 7 import com.zihans.train.member.domain.Passenger;
 8 import com.zihans.train.member.mapper.PassengerMapper;
 9 import com.zihans.train.member.req.PassengerSaveReq;
10 import jakarta.annotation.Resource;
11 import org.springframework.stereotype.Service;
12 
13 @Service
14 public class PassengerService {
15 
16     @Resource
17     private PassengerMapper passengerMapper;
18 
19     public void save(PassengerSaveReq req) {
20         DateTime now = DateTime.now();
21         Passenger passenger = BeanUtil.copyProperties(req, Passenger.class);
22         passenger.setMemberId(LoginMemberContext.getId());
23         passenger.setId(SnowUtil.getSnowflakeNextId());
24         passenger.setCreateTime(now);
25         passenger.setUpdateTime(now);
26         passengerMapper.insert(passenger);
27     }
28 }
PassengerService.java

测试

POST http://localhost:8001/member/passenger/save
Content-Type: application/json
token: {{token}}


{
  "name": "test",
  "idCard": "123321",
  "type": "1"
}

此时拦截器的日志并没有打印,因为拦截器发生在AOP之前,新建一个日志拦截器类,专门用来打印日志,并将该拦截器注入相应模块。

 1 package com.zihans.train.common.interceptor;
 2 
 3 import cn.hutool.core.util.RandomUtil;
 4 import jakarta.servlet.http.HttpServletRequest;
 5 import jakarta.servlet.http.HttpServletResponse;
 6 import org.slf4j.MDC;
 7 import org.springframework.stereotype.Component;
 8 import org.springframework.web.servlet.HandlerInterceptor;
 9 
10 /**
11  * 日志拦截器
12  */
13 @Component
14 public class LogInterceptor implements HandlerInterceptor {
15 
16     @Override
17     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
18         // 增加日志流水号
19         MDC.put("LOG_ID", System.currentTimeMillis() + RandomUtil.randomString(3));
20         return true;
21     }
22 
23 }
LoginInterceptor.java

前端二级路由页面开发

新增views/main/welcome.vue制作欢迎页面。

 1 <template>
 2   <h1>欢迎使用模拟12306售票系统</h1>
 3 </template>
 4 <script>
 5 import { defineComponent } from 'vue';
 6 
 7 export default defineComponent({
 8   setup() {
 9     return {
10     };
11   },
12 });
13 </script>
14 <style>
15 </style>
welcome.vue

router/index.js中增加二级路由(children中的welcome),也就是一级路由"/"+"welcome"。

 1 import { createRouter, createWebHistory } from 'vue-router'
 2 import store from "@/store";
 3 import {notification} from "ant-design-vue";
 4 
 5 const routes = [
 6   {
 7     path: '/login',
 8     component: () => import('../views/login.vue')
 9   },
10   {
11     path: '/',
12     component: () => import('../views/main.vue'),
13     meta: {
14       loginRequire: true
15     },
16     children: [{
17       path: 'welcome',
18       component: () => import('../views/main/welcome.vue'),
19     }]
20   },
21   {
22     path: '',
23     redirect: '/welcome'
24   },
25 ]
26 
27 const router = createRouter({
28   history: createWebHistory(process.env.BASE_URL),
29   routes
30 })
31 
32 // 路由登录拦截
33 router.beforeEach((to, from, next) => {
34   // 要不要对meta.loginRequire属性做监控拦截
35   if (to.matched.some(function (item) {
36     console.log(item, "是否需要登录校验:", item.meta.loginRequire || false);
37     return item.meta.loginRequire
38   })) {
39     const _member = store.state.member;
40     console.log("页面登录校验开始:", _member);
41     if (!_member.token) {
42       console.log("用户未登录或登录超时!");
43       notification.error({ description: "未登录或登录超时" });
44       next('/login');
45     } else {
46       next();
47     }
48   } else {
49     next();
50   }
51 });
52 
53 export default router
index.js

一级路由到main.vue,二级路由到welcome.vue。

 1 <template>
 2   <a-layout id="components-layout-demo-top-side-2">
 3     <the-header-view></the-header-view>
 4     <a-layout>
 5       <the-sider-view></the-sider-view>
 6       <a-layout-content
 7           :style="{ background: '#fff', padding: '24px', margin: 0, minHeight: '280px' }"
 8       >
 9         <router-view></router-view>
10       </a-layout-content>
11     </a-layout>
12   </a-layout>
13 </template>
14 <script>
15 import { defineComponent } from 'vue';
16 import TheHeaderView from "@/components/the-header";
17 import TheSiderView from "@/components/the-sider";
18 
19 export default defineComponent({
20   components: {
21     TheSiderView,
22     TheHeaderView,
23   },
24   setup() {
25     return {
26     };
27   },
28 });
29 </script>
30 <style>
31 #components-layout-demo-top-side-2 .logo {
32   float: left;
33   width: 120px;
34   height: 31px;
35   margin: 16px 24px 16px 0;
36   background: rgba(255, 255, 255, 0.3);
37 }
38 
39 .ant-row-rtl #components-layout-demo-top-side-2 .logo {
40   float: right;
41   margin: 16px 0 16px 24px;
42 }
43 
44 .site-layout-background {
45   background: #fff;
46 }
47 </style>
main.vue

login.vue登陆成功直接跳到welcome页。

  1 <template>
  2   <a-row class="login">
  3     <a-col :span="8" :offset="8" class="login-main">
  4       <h1 style="text-align: center"><car-two-tone />&nbsp;模拟12306售票系统</h1>
  5       <a-form
  6           :model="loginForm"
  7           name="basic"
  8           autocomplete="off"
  9       >
 10         <a-form-item
 11             label=""
 12             name="mobile"
 13             :rules="[{ required: true, message: '请输入手机号!' }]"
 14         >
 15           <a-input v-model:value="loginForm.mobile" placeholder="手机号"/>
 16         </a-form-item>
 17 
 18         <a-form-item
 19             label=""
 20             name="code"
 21             :rules="[{ required: true, message: '请输入验证码!' }]"
 22         >
 23           <a-input v-model:value="loginForm.code">
 24             <template #addonAfter>
 25               <a @click="sendCode">获取验证码</a>
 26             </template>
 27           </a-input>
 28           <!--<a-input v-model:value="loginForm.code" placeholder="验证码"/>-->
 29         </a-form-item>
 30 
 31         <a-form-item>
 32           <a-button type="primary" block @click="login">登录</a-button>
 33         </a-form-item>
 34 
 35       </a-form>
 36     </a-col>
 37   </a-row>
 38 </template>
 39 
 40 <script>
 41 import { defineComponent, reactive } from 'vue';
 42 import axios from 'axios';
 43 import { notification } from 'ant-design-vue';
 44 import { useRouter } from 'vue-router'
 45 import store from "@/store";
 46 
 47 export default defineComponent({
 48   name: "login-view",
 49   setup() {
 50     const router = useRouter();
 51 
 52     const loginForm = reactive({
 53       mobile: '13000000000',
 54       code: '',
 55     });
 56 
 57     const sendCode = () => {
 58       axios.post("/member/member/send-code", {
 59         mobile: loginForm.mobile
 60       }).then(response => {
 61         let data = response.data;
 62         if (data.success) {
 63           notification.success({ description: '发送验证码成功!' });
 64           loginForm.code = "8888";
 65         } else {
 66           notification.error({ description: data.message });
 67         }
 68       });
 69     };
 70 
 71     const login = () => {
 72       axios.post("/member/member/login", loginForm).then((response) => {
 73         let data = response.data;
 74         if (data.success) {
 75           notification.success({ description: '登录成功!' });
 76           // 登录成功,跳到控台主页
 77           router.push("/welcome");
 78           store.commit("setMember", data.content);
 79         } else {
 80           notification.error({ description: data.message });
 81         }
 82       })
 83     };
 84 
 85     return {
 86       loginForm,
 87       sendCode,
 88       login
 89     };
 90   },
 91 });
 92 </script>
 93 
 94 <style>
 95 .login-main h1 {
 96   font-size: 25px;
 97   font-weight: bold;
 98 }
 99 .login-main {
100   margin-top: 100px;
101   padding: 30px 30px 20px;
102   border: 2px solid grey;
103   border-radius: 10px;
104   background-color: #fcfcfc;
105 }
106 </style>
login.vue

新增乘车人管理页面

 1 <template>
 2   <h1>乘车人管理</h1>
 3 </template>
 4 <script>
 5 import { defineComponent } from 'vue';
 6 
 7 export default defineComponent({
 8   setup() {
 9     return {
10     };
11   },
12 });
13 </script>
14 <style>
15 </style>
passenger.vue

index.js增加passenger二级路由(目前只能手打进入)

 1 import { createRouter, createWebHistory } from 'vue-router'
 2 import store from "@/store";
 3 import {notification} from "ant-design-vue";
 4 
 5 const routes = [{
 6     path: '/login',
 7     component: () => import('../views/login.vue')
 8   }, {
 9     path: '/',
10     component: () => import('../views/main.vue'),
11     meta: {
12       loginRequire: true
13     },
14     children: [{
15       path: 'welcome',
16       component: () => import('../views/main/welcome.vue'),
17     }, {
18       path: 'passenger',
19       component: () => import('../views/main/passenger.vue'),
20     }]
21   }, {
22     path: '',
23     redirect: '/welcome'
24   }];
25 
26 const router = createRouter({
27   history: createWebHistory(process.env.BASE_URL),
28   routes
29 })
30 
31 // 路由登录拦截
32 router.beforeEach((to, from, next) => {
33   // 要不要对meta.loginRequire属性做监控拦截
34   if (to.matched.some(function (item) {
35     console.log(item, "是否需要登录校验:", item.meta.loginRequire || false);
36     return item.meta.loginRequire
37   })) {
38     const _member = store.state.member;
39     console.log("页面登录校验开始:", _member);
40     if (!_member.token) {
41       console.log("用户未登录或登录超时!");
42       notification.error({ description: "未登录或登录超时" });
43       next('/login');
44     } else {
45       next();
46     }
47   } else {
48     next();
49   }
50 });
51 
52 export default router
index.js

修改菜单,实现页面切换,实现菜单同步激活。

 1 <template>
 2   <a-layout-header class="header">
 3     <div class="logo" />
 4     <div style="float: right; color: white;">
 5       您好:{{member.mobile}} &nbsp;&nbsp;
 6       <router-link to="/login" style="color: white;">
 7         退出登录
 8       </router-link>
 9     </div>
10     <a-menu
11         v-model:selectedKeys="selectedKeys"
12         theme="dark"
13         mode="horizontal"
14         :style="{ lineHeight: '64px' }"
15     >
16       <a-menu-item key="/welcome">
17         <router-link to="/welcome">
18           <coffee-outlined /> &nbsp; 欢迎
19         </router-link>
20       </a-menu-item>
21       <a-menu-item key="/passenger">
22         <router-link to="/passenger">
23           <user-outlined /> &nbsp; 乘车人管理
24         </router-link>
25       </a-menu-item>
26     </a-menu>
27   </a-layout-header>
28 </template>
29 
30 <script>
31 import {defineComponent, ref, watch} from 'vue';
32 import store from "@/store";
33 import router from '@/router'
34 
35 export default defineComponent({
36   name: "the-header-view",
37   setup() {
38     let member = store.state.member;
39     const selectedKeys = ref([]);
40 
41     watch(() => router.currentRoute.value.path, (newValue) => {
42       console.log('watch', newValue);
43       selectedKeys.value = [];
44       selectedKeys.value.push(newValue);
45     }, {immediate: true});
46     return {
47       member,
48       selectedKeys
49     };
50   },
51 });
52 </script>
53 
54 <!-- Add "scoped" attribute to limit CSS to this component only -->
55 <style scoped>
56 
57 </style>
the-header.vue
 1 <template>
 2   <a-layout-sider width="200" style="background: #fff">
 3     <a-menu
 4         v-model:selectedKeys="selectedKeys"
 5         mode="inline"
 6         :style="{ height: '100%', borderRight: 0 }"
 7     >
 8       <a-menu-item key="/welcome">
 9         <router-link to="/welcome">
10           <coffee-outlined /> &nbsp; 欢迎
11         </router-link>
12       </a-menu-item>
13       <a-menu-item key="/passenger">
14         <router-link to="/passenger">
15           <user-outlined /> &nbsp; 乘车人管理
16         </router-link>
17       </a-menu-item>
18     </a-menu>
19   </a-layout-sider>
20 </template>
21 
22 <script>
23 import {defineComponent, ref, watch} from 'vue';
24 import router from "@/router";
25 
26 export default defineComponent({
27   name: "the-sider-view",
28   setup() {
29     const selectedKeys = ref([]);
30 
31     watch(() => router.currentRoute.value.path, (newValue) => {
32       console.log('watch', newValue);
33       selectedKeys.value = [];
34       selectedKeys.value.push(newValue);
35     }, {immediate: true});
36     return {
37       selectedKeys
38     };
39   },
40 });
41 </script>
42 
43 <!-- Add "scoped" attribute to limit CSS to this component only -->
44 <style scoped>
45 
46 </style>
the-side.vue

乘车人新增界面开发

乘车人新增界面开发,增加【新增】按钮,点击弹出Modal

 1 <template>
 2   <a-button type="primary" @click="showModal">新增</a-button>
 3   <a-modal v-model:visible="visible" title="乘车人" @ok="handleOk">
 4     <p>Some contents...</p>
 5     <p>Some contents...</p>
 6     <p>Some contents...</p>
 7   </a-modal>
 8 </template>
 9 <script>
10 import { defineComponent, ref } from 'vue';
11 
12 export default defineComponent({
13   setup() {
14     const visible = ref(false);
15 
16     const showModal = () => {
17       visible.value = true;
18     };
19 
20     const handleOk = e => {
21       console.log(e);
22       visible.value = false;
23     };
24     return {
25       visible,
26       showModal,
27       handleOk,
28     };
29   },
30 });
31 </script>
32 <style>
33 </style>
passenger.vue

乘车人新增界面开发,增加乘车人表单

 1 <template>
 2   <a-button type="primary" @click="showModal">新增</a-button>
 3   <a-modal v-model:visible="visible" title="乘车人" @ok="handleOk"
 4            ok-text="确认" cancel-text="取消">
 5     <a-form :model="passenger" :label-col="{span: 4}" :wrapper-col="{ span: 20 }">
 6       <a-form-item label="姓名">
 7         <a-input v-model:value="passenger.name" />
 8       </a-form-item>
 9       <a-form-item label="身份证">
10         <a-input v-model:value="passenger.idCard" />
11       </a-form-item>
12       <a-form-item label="类型">
13         <a-select v-model:value="passenger.type">
14           <a-select-option value="1">成人</a-select-option>
15           <a-select-option value="2">儿童</a-select-option>
16           <a-select-option value="3">学生</a-select-option>
17         </a-select>
18       </a-form-item>
19     </a-form>
20   </a-modal>
21 </template>
22 <script>
23 import { defineComponent, ref, reactive } from 'vue';
24 
25 export default defineComponent({
26   setup() {
27     const visible = ref(false);
28     const passenger = reactive({
29       id: undefined,
30       memberId: undefined,
31       name: undefined,
32       idCard: undefined,
33       type: undefined,
34       createTime: undefined,
35       updateTime: undefined,
36     });
37 
38     const showModal = () => {
39       visible.value = true;
40     };
41 
42     const handleOk = e => {
43       console.log(e);
44       visible.value = false;
45     };
46     return {
47       passenger,
48       visible,
49       showModal,
50       handleOk,
51     };
52   },
53 });
54 </script>
55 <style>
56 </style>
passenger.vue

乘车人新增界面开发,完成保存功能

 1 <template>
 2   <a-button type="primary" @click="showModal">新增</a-button>
 3   <a-modal v-model:visible="visible" title="乘车人" @ok="handleOk"
 4            ok-text="确认" cancel-text="取消">
 5     <a-form :model="passenger" :label-col="{span: 4}" :wrapper-col="{ span: 20 }">
 6       <a-form-item label="姓名">
 7         <a-input v-model:value="passenger.name" />
 8       </a-form-item>
 9       <a-form-item label="身份证">
10         <a-input v-model:value="passenger.idCard" />
11       </a-form-item>
12       <a-form-item label="类型">
13         <a-select v-model:value="passenger.type">
14           <a-select-option value="1">成人</a-select-option>
15           <a-select-option value="2">儿童</a-select-option>
16           <a-select-option value="3">学生</a-select-option>
17         </a-select>
18       </a-form-item>
19     </a-form>
20   </a-modal>
21 </template>
22 <script>
23 import { defineComponent, ref, reactive } from 'vue';
24 import {notification} from "ant-design-vue";
25 import axios from "axios";
26 
27 export default defineComponent({
28   setup() {
29     const visible = ref(false);
30     const passenger = reactive({
31       id: undefined,
32       memberId: undefined,
33       name: undefined,
34       idCard: undefined,
35       type: undefined,
36       createTime: undefined,
37       updateTime: undefined,
38     });
39 
40     const showModal = () => {
41       visible.value = true;
42     };
43 
44     const handleOk = () => {
45       axios.post("/member/passenger/save", passenger).then((response) => {
46         let data = response.data;
47         if (data.success) {
48           notification.success({description: "保存成功!"});
49           visible.value = false;
50         } else {
51           notification.error({description: data.message});
52         }
53       });
54     };
55 
56     return {
57       passenger,
58       visible,
59       showModal,
60       handleOk,
61     };
62   },
63 });
64 </script>
65 <style>
66 </style>
passenger.vue

乘车人列表查询接口开发

所有的列表查询接口,都要注意查询的数据量,不能因为查询量太大,把内存打爆,也不能因为数据量太大,而把带宽打爆,特别注意是否有大字段,如多媒体字段。
控台接口、会员接口、第三方接口等,不同的接口用不同的前缀,比如控台前面是/admin/xxx,第三方全部是/api/xxx,做接口隔离不要混用。

增加乘车人列表查询接口,只能查看当前全员自己添加的乘客

 1 package com.zihans.train.member.resp;
 2 
 3 import java.util.Date;
 4 
 5 public class PassengerQueryResp {
 6     private Long id;
 7 
 8     private Long memberId;
 9 
10     private String name;
11 
12     private String idCard;
13 
14     private String type;
15 
16     private Date createTime;
17 
18     private Date updateTime;
19 
20     public Long getId() {
21         return id;
22     }
23 
24     public void setId(Long id) {
25         this.id = id;
26     }
27 
28     public Long getMemberId() {
29         return memberId;
30     }
31 
32     public void setMemberId(Long memberId) {
33         this.memberId = memberId;
34     }
35 
36     public String getName() {
37         return name;
38     }
39 
40     public void setName(String name) {
41         this.name = name;
42     }
43 
44     public String getIdCard() {
45         return idCard;
46     }
47 
48     public void setIdCard(String idCard) {
49         this.idCard = idCard;
50     }
51 
52     public String getType() {
53         return type;
54     }
55 
56     public void setType(String type) {
57         this.type = type;
58     }
59 
60     public Date getCreateTime() {
61         return createTime;
62     }
63 
64     public void setCreateTime(Date createTime) {
65         this.createTime = createTime;
66     }
67 
68     public Date getUpdateTime() {
69         return updateTime;
70     }
71 
72     public void setUpdateTime(Date updateTime) {
73         this.updateTime = updateTime;
74     }
75 
76     @Override
77     public String toString() {
78         StringBuilder sb = new StringBuilder();
79         sb.append(getClass().getSimpleName());
80         sb.append(" [");
81         sb.append("Hash = ").append(hashCode());
82         sb.append(", id=").append(id);
83         sb.append(", memberId=").append(memberId);
84         sb.append(", name=").append(name);
85         sb.append(", idCard=").append(idCard);
86         sb.append(", type=").append(type);
87         sb.append(", createTime=").append(createTime);
88         sb.append(", updateTime=").append(updateTime);
89         sb.append("]");
90         return sb.toString();
91     }
92 }
PassengerQueryReq.java
 1 package com.zihans.train.member.resp;
 2 
 3 import java.util.Date;
 4 
 5 public class PassengerQueryResp {
 6     private Long id;
 7 
 8     private Long memberId;
 9 
10     private String name;
11 
12     private String idCard;
13 
14     private String type;
15 
16     private Date createTime;
17 
18     private Date updateTime;
19 
20     public Long getId() {
21         return id;
22     }
23 
24     public void setId(Long id) {
25         this.id = id;
26     }
27 
28     public Long getMemberId() {
29         return memberId;
30     }
31 
32     public void setMemberId(Long memberId) {
33         this.memberId = memberId;
34     }
35 
36     public String getName() {
37         return name;
38     }
39 
40     public void setName(String name) {
41         this.name = name;
42     }
43 
44     public String getIdCard() {
45         return idCard;
46     }
47 
48     public void setIdCard(String idCard) {
49         this.idCard = idCard;
50     }
51 
52     public String getType() {
53         return type;
54     }
55 
56     public void setType(String type) {
57         this.type = type;
58     }
59 
60     public Date getCreateTime() {
61         return createTime;
62     }
63 
64     public void setCreateTime(Date createTime) {
65         this.createTime = createTime;
66     }
67 
68     public Date getUpdateTime() {
69         return updateTime;
70     }
71 
72     public void setUpdateTime(Date updateTime) {
73         this.updateTime = updateTime;
74     }
75 
76     @Override
77     public String toString() {
78         StringBuilder sb = new StringBuilder();
79         sb.append(getClass().getSimpleName());
80         sb.append(" [");
81         sb.append("Hash = ").append(hashCode());
82         sb.append(", id=").append(id);
83         sb.append(", memberId=").append(memberId);
84         sb.append(", name=").append(name);
85         sb.append(", idCard=").append(idCard);
86         sb.append(", type=").append(type);
87         sb.append(", createTime=").append(createTime);
88         sb.append(", updateTime=").append(updateTime);
89         sb.append("]");
90         return sb.toString();
91     }
92 }
PassengerQueryResp.java

PassengerService新增查询方法

    public List<PassengerQueryResp> queryList(PassengerQueryReq req) {
        PassengerExample passengerExample = new PassengerExample();
        PassengerExample.Criteria criteria = passengerExample.createCriteria();
        if (ObjectUtil.isNotNull(req.getMemberId())) {
            criteria.andMemberIdEqualTo(req.getMemberId());
        }
        List<Passenger> passengerList = passengerMapper.selectByExample(passengerExample);
        return BeanUtil.copyToList(passengerList, PassengerQueryResp.class);
    }

PassengerController也新增查询方法

    @GetMapping("/query-list")
    public CommonResp<List<PassengerQueryResp>> queryList(@Valid PassengerQueryReq req) {
        req.setMemberId(LoginMemberContext.getId());
        List<PassengerQueryResp> list = passengerService.queryList(req);
        return new CommonResp<>(list);
    }

测试

GET http://localhost:8000/member/passenger/query-list
Accept: application/json
token: {{token}}

集成PageHelper实现后端分页

列表接口要做分页,否则容易因为数据量大而把内存打爆或把带宽打爆。
PageHelper.startPage只对第—条遇到的sql起作用,使用时,要紧跟着查询语句。

父pom新增插件,用来mybatis分页,common模块也使用。

<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter -->
<dependency>
     <groupId>com.github.pagehelper</groupId>
     <artifactId>pagehelper-spring-boot-starter</artifactId>
     <version>1.4.6</version>
</dependency>

在Passenger中执行sql的地方上方插入分页代码(第一页查两条)

PageHelper.startPage(1,2);
List<Passenger> passengerList = passengerMapper.selectByExample(passengerExample);

封装分页参数请求

 1 package com.zihans.train.common.req;
 2 
 3 import jakarta.validation.constraints.Max;
 4 import jakarta.validation.constraints.NotNull;
 5 
 6 public class PageReq {
 7 
 8     @NotNull(message = "【页码】不能为空")
 9     private Integer page;
10 
11     @NotNull(message = "【每页条数】不能为空")
12     @Max(value = 100, message = "【每页条数】不能超过100")
13     private Integer size;
14 
15     public Integer getPage() {
16         return page;
17     }
18 
19     public void setPage(Integer page) {
20         this.page = page;
21     }
22 
23     public Integer getSize() {
24         return size;
25     }
26 
27     public void setSize(Integer size) {
28         this.size = size;
29     }
30 
31     @Override
32     public String toString() {
33         return "PageReq{" +
34                 "page=" + page +
35                 ", size=" + size +
36                 '}';
37     }
38 }
PageReq

PassengerQueryReq继承PageReq

public class PassengerQueryReq extends PageReq{

PassengerService修改分页请求参数,跟随url传入

-       PageHelper.startPage(2, 2);
+       PageHelper.startPage(req.getPage(), req.getSize());

查询

GET http://localhost:8000/member/passenger/query-list?page=2&size=200

封装分页返回结果

 1 import java.io.Serializable;
 2 import java.util.List;
 3 
 4 public class PageResp<T> implements Serializable {
 5 
 6     /**
 7      * 总条数
 8      */
 9     private Long total;
10 
11     /**
12      * 当前页的列表
13      */
14     private List<T> list;
15 
16     public Long getTotal() {
17         return total;
18     }
19 
20     public void setTotal(Long total) {
21         this.total = total;
22     }
23 
24     public List<T> getList() {
25         return list;
26     }
27 
28     public void setList(List<T> list) {
29         this.list = list;
30     }
31 
32     @Override
33     public String toString() {
34         return "PageResp{" +
35                 "total=" + total +
36                 ", list=" + list +
37                 '}';
38     }
39 }
PageResp.java

service层

 1 public PageResp<PassengerQueryResp> queryList(PassengerQueryReq req) {
 2         PassengerExample passengerExample = new PassengerExample();
 3         PassengerExample.Criteria criteria = passengerExample.createCriteria();
 4         if (ObjectUtil.isNotNull(req.getMemberId())) {
 5             criteria.andMemberIdEqualTo(req.getMemberId());
 6         }
 7 
 8         LOG.info("查询页码:{}", req.getPage());
 9         LOG.info("每页条数:{}", req.getSize());
10         PageHelper.startPage(req.getPage(), req.getSize());
11         List<Passenger> passengerList = passengerMapper.selectByExample(passengerExample);
12 
13         PageInfo<Passenger> pageInfo = new PageInfo<>(passengerList);
14         LOG.info("总行数:{}", pageInfo.getTotal());
15         LOG.info("总页数:{}", pageInfo.getPages());
16 
17         List<PassengerQueryResp> list = BeanUtil.copyToList(passengerList, PassengerQueryResp.class);
18 
19         PageResp<PassengerQueryResp> pageResp = new PageResp<>();
20         pageResp.setTotal(pageInfo.getTotal());
21         pageResp.setList(list);
22         return pageResp;
23     }
PassengerService.java

controller层

1 @GetMapping("/query-list")
2     public CommonResp<PageResp<PassengerQueryResp>> queryList(@Valid PassengerQueryReq req) {
3         req.setMemberId(LoginMemberContext.getId());
4         PageResp<PassengerQueryResp> list = passengerService.queryList(req);
5         return new CommonResp<>(list);
6     }
PassengerController.java

格式化PassengerQueryResp.java中的日期字段

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date updateTime;

乘车人列表前端开发

引入表格组件

 1 <template>
 2   <p>
 3     <a-button type="primary" @click="showModal">新增</a-button>
 4   </p>
 5   <a-table :dataSource="dataSource" :columns="columns" />
 6   <a-modal v-model:visible="visible" title="乘车人" @ok="handleOk"
 7            ok-text="确认" cancel-text="取消">
 8     <a-form :model="passenger" :label-col="{span: 4}" :wrapper-col="{ span: 20 }">
 9       <a-form-item label="姓名">
10         <a-input v-model:value="passenger.name" />
11       </a-form-item>
12       <a-form-item label="身份证">
13         <a-input v-model:value="passenger.idCard" />
14       </a-form-item>
15       <a-form-item label="类型">
16         <a-select v-model:value="passenger.type">
17           <a-select-option value="1">成人</a-select-option>
18           <a-select-option value="2">儿童</a-select-option>
19           <a-select-option value="3">学生</a-select-option>
20         </a-select>
21       </a-form-item>
22     </a-form>
23   </a-modal>
24 </template>
25 <script>
26 import { defineComponent, ref, reactive } from 'vue';
27 import {notification} from "ant-design-vue";
28 import axios from "axios";
29 
30 export default defineComponent({
31   setup() {
32     const visible = ref(false);
33     const passenger = reactive({
34       id: undefined,
35       memberId: undefined,
36       name: undefined,
37       idCard: undefined,
38       type: undefined,
39       createTime: undefined,
40       updateTime: undefined,
41     });
42     const dataSource = [{
43         key: '1',
44         name: '胡彦斌',
45         age: 32,
46         address: '西湖区湖底公园1号',
47       }, {
48         key: '2',
49         name: '胡彦祖',
50         age: 42,
51         address: '西湖区湖底公园1号',
52       }];
53     const columns = [{
54         title: '姓名',
55         dataIndex: 'name',
56         key: 'name',
57       }, {
58         title: '年龄',
59         dataIndex: 'age',
60         key: 'age',
61       }, {
62         title: '住址',
63         dataIndex: 'address',
64         key: 'address',
65       }];
66 
67     const showModal = () => {
68       visible.value = true;
69     };
70 
71     const handleOk = () => {
72       axios.post("/member/passenger/save", passenger).then((response) => {
73         let data = response.data;
74         if (data.success) {
75           notification.success({description: "保存成功!"});
76           visible.value = false;
77         } else {
78           notification.error({description: data.message});
79         }
80       });
81     };
82 
83     return {
84       passenger,
85       visible,
86       showModal,
87       handleOk,
88       dataSource,
89       columns
90     };
91   },
92 });
93 </script>
94 <style>
95 </style>
passenger.vue

使用axios调用后端查询接口

  1 <template>
  2   <p>
  3     <a-button type="primary" @click="showModal">新增</a-button>
  4   </p>
  5   <a-table :dataSource="passengers" :columns="columns" />
  6   <a-modal v-model:visible="visible" title="乘车人" @ok="handleOk"
  7            ok-text="确认" cancel-text="取消">
  8     <a-form :model="passenger" :label-col="{span: 4}" :wrapper-col="{ span: 20 }">
  9       <a-form-item label="姓名">
 10         <a-input v-model:value="passenger.name" />
 11       </a-form-item>
 12       <a-form-item label="身份证">
 13         <a-input v-model:value="passenger.idCard" />
 14       </a-form-item>
 15       <a-form-item label="类型">
 16         <a-select v-model:value="passenger.type">
 17           <a-select-option value="1">成人</a-select-option>
 18           <a-select-option value="2">儿童</a-select-option>
 19           <a-select-option value="3">学生</a-select-option>
 20         </a-select>
 21       </a-form-item>
 22     </a-form>
 23   </a-modal>
 24 </template>
 25 <script>
 26 import { defineComponent, ref, reactive, onMounted } from 'vue';
 27 import {notification} from "ant-design-vue";
 28 import axios from "axios";
 29 
 30 export default defineComponent({
 31   setup() {
 32     const visible = ref(false);
 33     const passenger = reactive({
 34       id: undefined,
 35       memberId: undefined,
 36       name: undefined,
 37       idCard: undefined,
 38       type: undefined,
 39       createTime: undefined,
 40       updateTime: undefined,
 41     });
 42     const passengers = ref([]);
 43     const columns = [{
 44       title: '姓名',
 45       dataIndex: 'name',
 46       key: 'name',
 47     }, {
 48       title: '身份证',
 49       dataIndex: 'idCard',
 50       key: 'idCard',
 51     }, {
 52       title: '类型',
 53       dataIndex: 'type',
 54       key: 'type',
 55     }];
 56 
 57     const showModal = () => {
 58       visible.value = true;
 59     };
 60 
 61     const handleOk = () => {
 62       axios.post("/member/passenger/save", passenger).then((response) => {
 63         let data = response.data;
 64         if (data.success) {
 65           notification.success({description: "保存成功!"});
 66           visible.value = false;
 67         } else {
 68           notification.error({description: data.message});
 69         }
 70       });
 71     };
 72 
 73     const handleQuery = (param) => {
 74       axios.get("/member/passenger/query-list", {
 75         params: {
 76           page: param.page,
 77           size: param.size
 78         }
 79       }).then((response) => {
 80         let data = response.data;
 81         if (data.success) {
 82           passengers.value = data.content.list;
 83         } else {
 84           notification.error({description: data.message});
 85         }
 86       });
 87     };
 88 
 89     onMounted(() => {
 90       handleQuery({
 91         page: 1,
 92         size: 2
 93       });
 94     });
 95 
 96     return {
 97       passenger,
 98       visible,
 99       showModal,
100       handleOk,
101       passengers,
102       columns
103     };
104   },
105 });
106 </script>
107 <style>
108 </style>
passenger.vue

显示分页页码

  1 <template>
  2   <p>
  3     <a-button type="primary" @click="showModal">新增</a-button>
  4   </p>
  5   <a-table :dataSource="passengers" :columns="columns" :pagination="pagination"/>
  6   <a-modal v-model:visible="visible" title="乘车人" @ok="handleOk"
  7            ok-text="确认" cancel-text="取消">
  8     <a-form :model="passenger" :label-col="{span: 4}" :wrapper-col="{ span: 20 }">
  9       <a-form-item label="姓名">
 10         <a-input v-model:value="passenger.name" />
 11       </a-form-item>
 12       <a-form-item label="身份证">
 13         <a-input v-model:value="passenger.idCard" />
 14       </a-form-item>
 15       <a-form-item label="类型">
 16         <a-select v-model:value="passenger.type">
 17           <a-select-option value="1">成人</a-select-option>
 18           <a-select-option value="2">儿童</a-select-option>
 19           <a-select-option value="3">学生</a-select-option>
 20         </a-select>
 21       </a-form-item>
 22     </a-form>
 23   </a-modal>
 24 </template>
 25 <script>
 26 import { defineComponent, ref, reactive, onMounted } from 'vue';
 27 import {notification} from "ant-design-vue";
 28 import axios from "axios";
 29 
 30 export default defineComponent({
 31   setup() {
 32     const visible = ref(false);
 33     const passenger = reactive({
 34       id: undefined,
 35       memberId: undefined,
 36       name: undefined,
 37       idCard: undefined,
 38       type: undefined,
 39       createTime: undefined,
 40       updateTime: undefined,
 41     });
 42     const passengers = ref([]);
 43     // 分页的三个属性名是固定的
 44     const pagination = reactive({
 45       total: 0,
 46       current: 1,
 47       pageSize: 2,
 48     });
 49     const columns = [{
 50       title: '姓名',
 51       dataIndex: 'name',
 52       key: 'name',
 53     }, {
 54       title: '身份证',
 55       dataIndex: 'idCard',
 56       key: 'idCard',
 57     }, {
 58       title: '类型',
 59       dataIndex: 'type',
 60       key: 'type',
 61     }];
 62 
 63     const showModal = () => {
 64       visible.value = true;
 65     };
 66 
 67     const handleOk = () => {
 68       axios.post("/member/passenger/save", passenger).then((response) => {
 69         let data = response.data;
 70         if (data.success) {
 71           notification.success({description: "保存成功!"});
 72           visible.value = false;
 73         } else {
 74           notification.error({description: data.message});
 75         }
 76       });
 77     };
 78 
 79     const handleQuery = (param) => {
 80       axios.get("/member/passenger/query-list", {
 81         params: {
 82           page: param.page,
 83           size: param.size
 84         }
 85       }).then((response) => {
 86         let data = response.data;
 87         if (data.success) {
 88           passengers.value = data.content.list;
 89           pagination.total = data.content.total;
 90         } else {
 91           notification.error({description: data.message});
 92         }
 93       });
 94     };
 95 
 96     onMounted(() => {
 97       handleQuery({
 98         page: 1,
 99         size: 2
100       });
101     });
102 
103     return {
104       passenger,
105       visible,
106       showModal,
107       handleOk,
108       passengers,
109       pagination,
110       columns
111     };
112   },
113 });
114 </script>
115 <style>
116 </style>
passenger.vue

增加表格分页点击事件

  1 <template>
  2   <p>
  3     <a-button type="primary" @click="showModal">新增</a-button>
  4   </p>
  5   <a-table :dataSource="passengers" :columns="columns" :pagination="pagination" @change="handleTableChange"/>
  6   <a-modal v-model:visible="visible" title="乘车人" @ok="handleOk"
  7            ok-text="确认" cancel-text="取消">
  8     <a-form :model="passenger" :label-col="{span: 4}" :wrapper-col="{ span: 20 }">
  9       <a-form-item label="姓名">
 10         <a-input v-model:value="passenger.name" />
 11       </a-form-item>
 12       <a-form-item label="身份证">
 13         <a-input v-model:value="passenger.idCard" />
 14       </a-form-item>
 15       <a-form-item label="类型">
 16         <a-select v-model:value="passenger.type">
 17           <a-select-option value="1">成人</a-select-option>
 18           <a-select-option value="2">儿童</a-select-option>
 19           <a-select-option value="3">学生</a-select-option>
 20         </a-select>
 21       </a-form-item>
 22     </a-form>
 23   </a-modal>
 24 </template>
 25 <script>
 26 import { defineComponent, ref, reactive, onMounted } from 'vue';
 27 import {notification} from "ant-design-vue";
 28 import axios from "axios";
 29 
 30 export default defineComponent({
 31   setup() {
 32     const visible = ref(false);
 33     const passenger = reactive({
 34       id: undefined,
 35       memberId: undefined,
 36       name: undefined,
 37       idCard: undefined,
 38       type: undefined,
 39       createTime: undefined,
 40       updateTime: undefined,
 41     });
 42     const passengers = ref([]);
 43     // 分页的三个属性名是固定的
 44     const pagination = reactive({
 45       total: 0,
 46       current: 1,
 47       pageSize: 2,
 48     });
 49     const columns = [{
 50       title: '姓名',
 51       dataIndex: 'name',
 52       key: 'name',
 53     }, {
 54       title: '身份证',
 55       dataIndex: 'idCard',
 56       key: 'idCard',
 57     }, {
 58       title: '类型',
 59       dataIndex: 'type',
 60       key: 'type',
 61     }];
 62 
 63     const showModal = () => {
 64       visible.value = true;
 65     };
 66 
 67     const handleOk = () => {
 68       axios.post("/member/passenger/save", passenger).then((response) => {
 69         let data = response.data;
 70         if (data.success) {
 71           notification.success({description: "保存成功!"});
 72           visible.value = false;
 73         } else {
 74           notification.error({description: data.message});
 75         }
 76       });
 77     };
 78 
 79     const handleQuery = (param) => {
 80       axios.get("/member/passenger/query-list", {
 81         params: {
 82           page: param.page,
 83           size: param.size
 84         }
 85       }).then((response) => {
 86         let data = response.data;
 87         if (data.success) {
 88           passengers.value = data.content.list;
 89           // 设置分页控件的值
 90           pagination.current = param.page;
 91           pagination.total = data.content.total;
 92         } else {
 93           notification.error({description: data.message});
 94         }
 95       });
 96     };
 97 
 98     const handleTableChange = (pagination) => {
 99       // console.log("看看自带的分页参数都有啥:" + pagination);
100       handleQuery({
101         page: pagination.current,
102         size: pagination.pageSize
103       });
104     };
105 
106     onMounted(() => {
107       handleQuery({
108         page: 1,
109         size: pagination.pageSize
110       });
111     });
112 
113     return {
114       passenger,
115       visible,
116       showModal,
117       handleOk,
118       passengers,
119       pagination,
120       columns,
121       handleTableChange
122     };
123   },
124 });
125 </script>
126 <style>
127 </style>
passenger.vue

增加刷新按钮,点击查询第1页

  1 <template>
  2   <p>
  3     <a-space>
  4       <a-button type="primary" @click="handleQuery()">刷新</a-button>
  5       <a-button type="primary" @click="showModal">新增</a-button>
  6     </a-space>
  7   </p>
  8   <a-table :dataSource="passengers" :columns="columns" :pagination="pagination" @change="handleTableChange"/>
  9   <a-modal v-model:visible="visible" title="乘车人" @ok="handleOk"
 10            ok-text="确认" cancel-text="取消">
 11     <a-form :model="passenger" :label-col="{span: 4}" :wrapper-col="{ span: 20 }">
 12       <a-form-item label="姓名">
 13         <a-input v-model:value="passenger.name" />
 14       </a-form-item>
 15       <a-form-item label="身份证">
 16         <a-input v-model:value="passenger.idCard" />
 17       </a-form-item>
 18       <a-form-item label="类型">
 19         <a-select v-model:value="passenger.type">
 20           <a-select-option value="1">成人</a-select-option>
 21           <a-select-option value="2">儿童</a-select-option>
 22           <a-select-option value="3">学生</a-select-option>
 23         </a-select>
 24       </a-form-item>
 25     </a-form>
 26   </a-modal>
 27 </template>
 28 <script>
 29 import { defineComponent, ref, reactive, onMounted } from 'vue';
 30 import {notification} from "ant-design-vue";
 31 import axios from "axios";
 32 
 33 export default defineComponent({
 34   setup() {
 35     const visible = ref(false);
 36     const passenger = reactive({
 37       id: undefined,
 38       memberId: undefined,
 39       name: undefined,
 40       idCard: undefined,
 41       type: undefined,
 42       createTime: undefined,
 43       updateTime: undefined,
 44     });
 45     const passengers = ref([]);
 46     // 分页的三个属性名是固定的
 47     const pagination = reactive({
 48       total: 0,
 49       current: 1,
 50       pageSize: 2,
 51     });
 52     const columns = [{
 53       title: '姓名',
 54       dataIndex: 'name',
 55       key: 'name',
 56     }, {
 57       title: '身份证',
 58       dataIndex: 'idCard',
 59       key: 'idCard',
 60     }, {
 61       title: '类型',
 62       dataIndex: 'type',
 63       key: 'type',
 64     }];
 65 
 66     const showModal = () => {
 67       visible.value = true;
 68     };
 69 
 70     const handleOk = () => {
 71       axios.post("/member/passenger/save", passenger).then((response) => {
 72         let data = response.data;
 73         if (data.success) {
 74           notification.success({description: "保存成功!"});
 75           visible.value = false;
 76         } else {
 77           notification.error({description: data.message});
 78         }
 79       });
 80     };
 81 
 82     const handleQuery = (param) => {
 83       if (!param) {
 84         param = {
 85           page: 1,
 86           size: pagination.pageSize
 87         };
 88       }
 89       axios.get("/member/passenger/query-list", {
 90         params: {
 91           page: param.page,
 92           size: param.size
 93         }
 94       }).then((response) => {
 95         let data = response.data;
 96         if (data.success) {
 97           passengers.value = data.content.list;
 98           // 设置分页控件的值
 99           pagination.current = param.page;
100           pagination.total = data.content.total;
101         } else {
102           notification.error({description: data.message});
103         }
104       });
105     };
106 
107     const handleTableChange = (pagination) => {
108       // console.log("看看自带的分页参数都有啥:" + pagination);
109       handleQuery({
110         page: pagination.current,
111         size: pagination.pageSize
112       });
113     };
114 
115     onMounted(() => {
116       handleQuery({
117         page: 1,
118         size: pagination.pageSize
119       });
120     });
121 
122     return {
123       passenger,
124       visible,
125       showModal,
126       handleOk,
127       passengers,
128       pagination,
129       columns,
130       handleTableChange,
131       handleQuery
132     };
133   },
134 });
135 </script>
136 <style>
137 </style>
passenger.vue

增加loading效果

  1 <template>
  2   <p>
  3     <a-space>
  4       <a-button type="primary" @click="handleQuery()">刷新</a-button>
  5       <a-button type="primary" @click="showModal">新增</a-button>
  6     </a-space>
  7   </p>
  8   <a-table :dataSource="passengers"
  9            :columns="columns"
 10            :pagination="pagination"
 11            @change="handleTableChange"
 12            :loading="loading"/>
 13   <a-modal v-model:visible="visible" title="乘车人" @ok="handleOk"
 14            ok-text="确认" cancel-text="取消">
 15     <a-form :model="passenger" :label-col="{span: 4}" :wrapper-col="{ span: 20 }">
 16       <a-form-item label="姓名">
 17         <a-input v-model:value="passenger.name" />
 18       </a-form-item>
 19       <a-form-item label="身份证">
 20         <a-input v-model:value="passenger.idCard" />
 21       </a-form-item>
 22       <a-form-item label="类型">
 23         <a-select v-model:value="passenger.type">
 24           <a-select-option value="1">成人</a-select-option>
 25           <a-select-option value="2">儿童</a-select-option>
 26           <a-select-option value="3">学生</a-select-option>
 27         </a-select>
 28       </a-form-item>
 29     </a-form>
 30   </a-modal>
 31 </template>
 32 <script>
 33 import { defineComponent, ref, reactive, onMounted } from 'vue';
 34 import {notification} from "ant-design-vue";
 35 import axios from "axios";
 36 
 37 export default defineComponent({
 38   setup() {
 39     const visible = ref(false);
 40     const passenger = reactive({
 41       id: undefined,
 42       memberId: undefined,
 43       name: undefined,
 44       idCard: undefined,
 45       type: undefined,
 46       createTime: undefined,
 47       updateTime: undefined,
 48     });
 49     const passengers = ref([]);
 50     // 分页的三个属性名是固定的
 51     const pagination = reactive({
 52       total: 0,
 53       current: 1,
 54       pageSize: 2,
 55     });
 56     let loading = ref(false);
 57     const columns = [{
 58       title: '姓名',
 59       dataIndex: 'name',
 60       key: 'name',
 61     }, {
 62       title: '身份证',
 63       dataIndex: 'idCard',
 64       key: 'idCard',
 65     }, {
 66       title: '类型',
 67       dataIndex: 'type',
 68       key: 'type',
 69     }];
 70 
 71     const showModal = () => {
 72       visible.value = true;
 73     };
 74 
 75     const handleOk = () => {
 76       axios.post("/member/passenger/save", passenger).then((response) => {
 77         let data = response.data;
 78         if (data.success) {
 79           notification.success({description: "保存成功!"});
 80           visible.value = false;
 81         } else {
 82           notification.error({description: data.message});
 83         }
 84       });
 85     };
 86 
 87     const handleQuery = (param) => {
 88       if (!param) {
 89         param = {
 90           page: 1,
 91           size: pagination.pageSize
 92         };
 93       }
 94       loading.value = true;
 95       axios.get("/member/passenger/query-list", {
 96         params: {
 97           page: param.page,
 98           size: param.size
 99         }
100       }).then((response) => {
101         loading.value = false;
102         let data = response.data;
103         if (data.success) {
104           passengers.value = data.content.list;
105           // 设置分页控件的值
106           pagination.current = param.page;
107           pagination.total = data.content.total;
108         } else {
109           notification.error({description: data.message});
110         }
111       });
112     };
113 
114     const handleTableChange = (pagination) => {
115       // console.log("看看自带的分页参数都有啥:" + pagination);
116       handleQuery({
117         page: pagination.current,
118         size: pagination.pageSize
119       });
120     };
121 
122     onMounted(() => {
123       handleQuery({
124         page: 1,
125         size: pagination.pageSize
126       });
127     });
128 
129     return {
130       passenger,
131       visible,
132       showModal,
133       handleOk,
134       passengers,
135       pagination,
136       columns,
137       handleTableChange,
138       handleQuery,
139       loading
140     };
141   },
142 });
143 </script>
144 <style>
145 </style>
passenger.vue

保存成功后刷新列表

  1 <template>
  2   <p>
  3     <a-space>
  4       <a-button type="primary" @click="handleQuery()">刷新</a-button>
  5       <a-button type="primary" @click="showModal">新增</a-button>
  6     </a-space>
  7   </p>
  8   <a-table :dataSource="passengers"
  9            :columns="columns"
 10            :pagination="pagination"
 11            @change="handleTableChange"
 12            :loading="loading"/>
 13   <a-modal v-model:visible="visible" title="乘车人" @ok="handleOk"
 14            ok-text="确认" cancel-text="取消">
 15     <a-form :model="passenger" :label-col="{span: 4}" :wrapper-col="{ span: 20 }">
 16       <a-form-item label="姓名">
 17         <a-input v-model:value="passenger.name" />
 18       </a-form-item>
 19       <a-form-item label="身份证">
 20         <a-input v-model:value="passenger.idCard" />
 21       </a-form-item>
 22       <a-form-item label="类型">
 23         <a-select v-model:value="passenger.type">
 24           <a-select-option value="1">成人</a-select-option>
 25           <a-select-option value="2">儿童</a-select-option>
 26           <a-select-option value="3">学生</a-select-option>
 27         </a-select>
 28       </a-form-item>
 29     </a-form>
 30   </a-modal>
 31 </template>
 32 <script>
 33 import { defineComponent, ref, reactive, onMounted } from 'vue';
 34 import {notification} from "ant-design-vue";
 35 import axios from "axios";
 36 
 37 export default defineComponent({
 38   setup() {
 39     const visible = ref(false);
 40     const passenger = reactive({
 41       id: undefined,
 42       memberId: undefined,
 43       name: undefined,
 44       idCard: undefined,
 45       type: undefined,
 46       createTime: undefined,
 47       updateTime: undefined,
 48     });
 49     const passengers = ref([]);
 50     // 分页的三个属性名是固定的
 51     const pagination = reactive({
 52       total: 0,
 53       current: 1,
 54       pageSize: 2,
 55     });
 56     let loading = ref(false);
 57     const columns = [{
 58       title: '姓名',
 59       dataIndex: 'name',
 60       key: 'name',
 61     }, {
 62       title: '身份证',
 63       dataIndex: 'idCard',
 64       key: 'idCard',
 65     }, {
 66       title: '类型',
 67       dataIndex: 'type',
 68       key: 'type',
 69     }];
 70 
 71     const showModal = () => {
 72       visible.value = true;
 73     };
 74 
 75     const handleOk = () => {
 76       axios.post("/member/passenger/save", passenger).then((response) => {
 77         let data = response.data;
 78         if (data.success) {
 79           notification.success({description: "保存成功!"});
 80           visible.value = false;
 81           handleQuery({
 82             page: pagination.current,
 83             size: pagination.pageSize
 84           });
 85         } else {
 86           notification.error({description: data.message});
 87         }
 88       });
 89     };
 90 
 91     const handleQuery = (param) => {
 92       if (!param) {
 93         param = {
 94           page: 1,
 95           size: pagination.pageSize
 96         };
 97       }
 98       loading.value = true;
 99       axios.get("/member/passenger/query-list", {
100         params: {
101           page: param.page,
102           size: param.size
103         }
104       }).then((response) => {
105         loading.value = false;
106         let data = response.data;
107         if (data.success) {
108           passengers.value = data.content.list;
109           // 设置分页控件的值
110           pagination.current = param.page;
111           pagination.total = data.content.total;
112         } else {
113           notification.error({description: data.message});
114         }
115       });
116     };
117 
118     const handleTableChange = (pagination) => {
119       // console.log("看看自带的分页参数都有啥:" + pagination);
120       handleQuery({
121         page: pagination.current,
122         size: pagination.pageSize
123       });
124     };
125 
126     onMounted(() => {
127       handleQuery({
128         page: 1,
129         size: pagination.pageSize
130       });
131     });
132 
133     return {
134       passenger,
135       visible,
136       showModal,
137       handleOk,
138       passengers,
139       pagination,
140       columns,
141       handleTableChange,
142       handleQuery,
143       loading
144     };
145   },
146 });
147 </script>
148 <style>
149 </style>
passenger.vue

PassengerService.java新增

+         PassengerExample passengerExample = new PassengerExample();
          passengerExample.setOrderByClause("id desc");

解决Long类型精度丢失问题

不同的语言,虽然都有int long等类型,但他们的精度不太一样,在数据传递时需要特别注意精度丢失。
解决方法:将long传成string

两种方法

第一种是统一注解。把许多小的long也转换了,不是很好。会多很多警告。

 1  package com.zihans.train.common.config;
 2 
 3  import com.fasterxml.jackson.databind.ObjectMapper;
 4  import com.fasterxml.jackson.databind.module.SimpleModule;
 5  import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 6  import org.springframework.context.annotation.Bean;
 7  import org.springframework.context.annotation.Configuration;
 8  import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
 9 
10  /**
11   * 统一注解,解决前后端交互Long类型精度丢失的问题
12   */
13  @Configuration
14  public class JacksonConfig {
15      @Bean
16      public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
17          ObjectMapper objectMapper = builder.createXmlMapper(false).build();
18          SimpleModule simpleModule = new SimpleModule();
19          simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
20          objectMapper.registerModule(simpleModule);
21          return objectMapper;
22      }
23  }
JacksonConfig.java

第二种在返回结果加注解,用雪花算法生成的大long都加。

public class PassengerQueryResp {
    @JsonSerialize(using= ToStringSerializer.class)
    private Long id;

    @JsonSerialize(using= ToStringSerializer.class)
    private Long memberId;

 乘车人编辑接口开发

编辑接口和新增接口相同,只要修改新增接口的内容,因为前端调用同一个接口。

修改PassengerService的save方法。

如果id是空,则保存,否则是编辑。

 1 public void save(PassengerSaveReq req) {
 2         DateTime now = DateTime.now();
 3         Passenger passenger = BeanUtil.copyProperties(req, Passenger.class);
 4         if (ObjectUtil.isNull(passenger.getId())) {
 5             passenger.setMemberId(LoginMemberContext.getId());
 6             passenger.setId(SnowUtil.getSnowflakeNextId());
 7             passenger.setCreateTime(now);
 8             passenger.setUpdateTime(now);
 9             passengerMapper.insert(passenger);
10         } else {
11             passenger.setUpdateTime(now);
12             passengerMapper.updateByPrimaryKey(passenger);
13         }
14     }
PassengerService.java

测试方法

###
POST http://localhost:8000/member/passenger/save
Content-Type: application/json
token: {{token}}

{
  "id": 1628627322414436352,
  "memberId": 1624581077500825600,
  "name": "test1",
  "idCard": "123321",
  "type": "1"
}

 乘车人编辑界面开发

reactive改为ref,reactive需要再封装一层属性才能实现双向绑定

  1 <template>
  2   <p>
  3     <a-space>
  4       <a-button type="primary" @click="handleQuery()">刷新</a-button>
  5       <a-button type="primary" @click="onAdd">新增</a-button>
  6     </a-space>
  7   </p>
  8   <a-table :dataSource="passengers"
  9            :columns="columns"
 10            :pagination="pagination"
 11            @change="handleTableChange"
 12            :loading="loading">
 13     <template #bodyCell="{ column, record }">
 14       <template v-if="column.dataIndex === 'operation'">
 15         <a-space>
 16           <a @click="onEdit(record)">编辑</a>
 17         </a-space>
 18       </template>
 19     </template>
 20   </a-table>
 21   <a-modal v-model:visible="visible" title="乘车人" @ok="handleOk"
 22            ok-text="确认" cancel-text="取消">
 23     <a-form :model="passenger" :label-col="{span: 4}" :wrapper-col="{ span: 20 }">
 24       <a-form-item label="姓名">
 25         <a-input v-model:value="passenger.name" />
 26       </a-form-item>
 27       <a-form-item label="身份证">
 28         <a-input v-model:value="passenger.idCard" />
 29       </a-form-item>
 30       <a-form-item label="类型">
 31         <a-select v-model:value="passenger.type">
 32           <a-select-option value="1">成人</a-select-option>
 33           <a-select-option value="2">儿童</a-select-option>
 34           <a-select-option value="3">学生</a-select-option>
 35         </a-select>
 36       </a-form-item>
 37     </a-form>
 38   </a-modal>
 39 </template>
 40 <script>
 41 import { defineComponent, ref, onMounted } from 'vue';
 42 import {notification} from "ant-design-vue";
 43 import axios from "axios";
 44 
 45 export default defineComponent({
 46   setup() {
 47     const visible = ref(false);
 48     let passenger = ref({
 49       id: undefined,
 50       memberId: undefined,
 51       name: undefined,
 52       idCard: undefined,
 53       type: undefined,
 54       createTime: undefined,
 55       updateTime: undefined,
 56     });
 57     const passengers = ref([]);
 58     // 分页的三个属性名是固定的
 59     const pagination = ref({
 60       total: 0,
 61       current: 1,
 62       pageSize: 2,
 63     });
 64     let loading = ref(false);
 65     const columns = [{
 66       title: '姓名',
 67       dataIndex: 'name',
 68       key: 'name',
 69     }, {
 70       title: '身份证',
 71       dataIndex: 'idCard',
 72       key: 'idCard',
 73     }, {
 74       title: '类型',
 75       dataIndex: 'type',
 76       key: 'type',
 77     }, {
 78       title: '操作',
 79       dataIndex: 'operation'
 80     }];
 81 
 82     const onAdd = () => {
 83       visible.value = true;
 84     };
 85 
 86     const onEdit = (record) => {
 87       passenger.value = record;
 88       visible.value = true;
 89     };
 90 
 91     const handleOk = () => {
 92       axios.post("/member/passenger/save", passenger.value).then((response) => {
 93         let data = response.data;
 94         if (data.success) {
 95           notification.success({description: "保存成功!"});
 96           visible.value = false;
 97           handleQuery({
 98             page: pagination.value.current,
 99             size: pagination.value.pageSize
100           });
101         } else {
102           notification.error({description: data.message});
103         }
104       });
105     };
106 
107     const handleQuery = (param) => {
108       if (!param) {
109         param = {
110           page: 1,
111           size: pagination.value.pageSize
112         };
113       }
114       loading.value = true;
115       axios.get("/member/passenger/query-list", {
116         params: {
117           page: param.page,
118           size: param.size
119         }
120       }).then((response) => {
121         loading.value = false;
122         let data = response.data;
123         if (data.success) {
124           passengers.value = data.content.list;
125           // 设置分页控件的值
126           pagination.value.current = param.page;
127           pagination.value.total = data.content.total;
128         } else {
129           notification.error({description: data.message});
130         }
131       });
132     };
133 
134     const handleTableChange = (pagination) => {
135       // console.log("看看自带的分页参数都有啥:" + pagination);
136       handleQuery({
137         page: pagination.current,
138         size: pagination.pageSize
139       });
140     };
141 
142     onMounted(() => {
143       handleQuery({
144         page: 1,
145         size: pagination.value.pageSize
146       });
147     });
148 
149     return {
150       passenger,
151       visible,
152       onAdd,
153       handleOk,
154       passengers,
155       pagination,
156       columns,
157       handleTableChange,
158       handleQuery,
159       loading,
160       onEdit
161     };
162   },
163 });
164 </script>
165 <style>
166 </style>
passenger.vue

解决没保存也会同步修改列表的问题

public/js新增tool.js

 1 Tool = {
 2   /**
 3    * 空校验 null或""都返回true
 4    */
 5   isEmpty: (obj) => {
 6     if ((typeof obj === 'string')) {
 7       return !obj || obj.replace(/\s+/g, "") === ""
 8     } else {
 9       return (!obj || JSON.stringify(obj) === "{}" || obj.length === 0);
10     }
11   },
12 
13   /**
14    * 非空校验
15    */
16   isNotEmpty: (obj) => {
17     return !Tool.isEmpty(obj);
18   },
19 
20   /**
21    * 对象复制
22    * @param obj
23    */
24   copy: (obj) => {
25     if (Tool.isNotEmpty(obj)) {
26       return JSON.parse(JSON.stringify(obj));
27     }
28   },
29 
30   /**
31    * 使用递归将数组转为树形结构
32    * 父ID属性为parent
33    */
34   array2Tree: (array, parentId) => {
35     if (Tool.isEmpty(array)) {
36       return [];
37     }
38 
39     const result = [];
40     for (let i = 0; i < array.length; i++) {
41       const c = array[i];
42       // console.log(Number(c.parent), Number(parentId));
43       if (Number(c.parent) === Number(parentId)) {
44         result.push(c);
45 
46         // 递归查看当前节点对应的子节点
47         const children = Tool.array2Tree(array, c.id);
48         if (Tool.isNotEmpty(children)) {
49           c.children = children;
50         }
51       }
52     }
53     return result;
54   },
55 
56   /**
57    * 随机生成[len]长度的[radix]进制数
58    * @param len
59    * @param radix 默认62
60    * @returns {string}
61    */
62   uuid: (len, radix = 62) => {
63     const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
64     const uuid = [];
65     radix = radix || chars.length;
66 
67     for (let i = 0; i < len; i++) {
68       uuid[i] = chars[0 | Math.random() * radix];
69     }
70 
71     return uuid.join('');
72   }
73 };
tool.js
  1 <template>
  2   <p>
  3     <a-space>
  4       <a-button type="primary" @click="handleQuery()">刷新</a-button>
  5       <a-button type="primary" @click="onAdd">新增</a-button>
  6     </a-space>
  7   </p>
  8   <a-table :dataSource="passengers"
  9            :columns="columns"
 10            :pagination="pagination"
 11            @change="handleTableChange"
 12            :loading="loading">
 13     <template #bodyCell="{ column, record }">
 14       <template v-if="column.dataIndex === 'operation'">
 15         <a-space>
 16           <a @click="onEdit(record)">编辑</a>
 17         </a-space>
 18       </template>
 19     </template>
 20   </a-table>
 21   <a-modal v-model:visible="visible" title="乘车人" @ok="handleOk"
 22            ok-text="确认" cancel-text="取消">
 23     <a-form :model="passenger" :label-col="{span: 4}" :wrapper-col="{ span: 20 }">
 24       <a-form-item label="姓名">
 25         <a-input v-model:value="passenger.name" />
 26       </a-form-item>
 27       <a-form-item label="身份证">
 28         <a-input v-model:value="passenger.idCard" />
 29       </a-form-item>
 30       <a-form-item label="类型">
 31         <a-select v-model:value="passenger.type">
 32           <a-select-option value="1">成人</a-select-option>
 33           <a-select-option value="2">儿童</a-select-option>
 34           <a-select-option value="3">学生</a-select-option>
 35         </a-select>
 36       </a-form-item>
 37     </a-form>
 38   </a-modal>
 39 </template>
 40 <script>
 41 import { defineComponent, ref, onMounted } from 'vue';
 42 import {notification} from "ant-design-vue";
 43 import axios from "axios";
 44 
 45 export default defineComponent({
 46   setup() {
 47     const visible = ref(false);
 48     let passenger = ref({
 49       id: undefined,
 50       memberId: undefined,
 51       name: undefined,
 52       idCard: undefined,
 53       type: undefined,
 54       createTime: undefined,
 55       updateTime: undefined,
 56     });
 57     const passengers = ref([]);
 58     // 分页的三个属性名是固定的
 59     const pagination = ref({
 60       total: 0,
 61       current: 1,
 62       pageSize: 2,
 63     });
 64     let loading = ref(false);
 65     const columns = [{
 66       title: '姓名',
 67       dataIndex: 'name',
 68       key: 'name',
 69     }, {
 70       title: '身份证',
 71       dataIndex: 'idCard',
 72       key: 'idCard',
 73     }, {
 74       title: '类型',
 75       dataIndex: 'type',
 76       key: 'type',
 77     }, {
 78       title: '操作',
 79       dataIndex: 'operation'
 80     }];
 81 
 82     const onAdd = () => {
 83       passenger.value = {};
 84       visible.value = true;
 85     };
 86 
 87     const onEdit = (record) => {
 88       passenger.value = window.Tool.copy(record);
 89       visible.value = true;
 90     };
 91 
 92     const handleOk = () => {
 93       axios.post("/member/passenger/save", passenger.value).then((response) => {
 94         let data = response.data;
 95         if (data.success) {
 96           notification.success({description: "保存成功!"});
 97           visible.value = false;
 98           handleQuery({
 99             page: pagination.value.current,
100             size: pagination.value.pageSize
101           });
102         } else {
103           notification.error({description: data.message});
104         }
105       });
106     };
107 
108     const handleQuery = (param) => {
109       if (!param) {
110         param = {
111           page: 1,
112           size: pagination.value.pageSize
113         };
114       }
115       loading.value = true;
116       axios.get("/member/passenger/query-list", {
117         params: {
118           page: param.page,
119           size: param.size
120         }
121       }).then((response) => {
122         loading.value = false;
123         let data = response.data;
124         if (data.success) {
125           passengers.value = data.content.list;
126           // 设置分页控件的值
127           pagination.value.current = param.page;
128           pagination.value.total = data.content.total;
129         } else {
130           notification.error({description: data.message});
131         }
132       });
133     };
134 
135     const handleTableChange = (pagination) => {
136       // console.log("看看自带的分页参数都有啥:" + pagination);
137       handleQuery({
138         page: pagination.current,
139         size: pagination.pageSize
140       });
141     };
142 
143     onMounted(() => {
144       handleQuery({
145         page: 1,
146         size: pagination.value.pageSize
147       });
148     });
149 
150     return {
151       passenger,
152       visible,
153       onAdd,
154       handleOk,
155       passengers,
156       pagination,
157       columns,
158       handleTableChange,
159       handleQuery,
160       loading,
161       onEdit
162     };
163   },
164 });
165 </script>
166 <style>
167 </style>
passenger.vue

index.html新增

<script src="<%= BASE_URL %>js/tool.js"></script>

乘车人删除接口开发

service层,按id删除,id不必要封装成一个类。

    public void delete(Long id) {
        passengerMapper.deleteByPrimaryKey(id);
    }

controller层,@PathVariable注解为路径映射,将路径上的id映射下来。

    @DeleteMapping("/delete/{id}")
    public CommonResp<Object> delete(@PathVariable Long id) {
        passengerService.delete(id);
        return new CommonResp<>();
    }

测试。

###

DELETE http://localhost:8000/member/passenger/delete/1628627401883914240
Accept: application/json
token: {{token}}

乘车人删除界面开发

前端常用设计,对于重要的操作,如删除,需要增加确认,防止误点击,有些特别重要的,还要有二次确认

  1 <template>
  2   <p>
  3     <a-space>
  4       <a-button type="primary" @click="handleQuery()">刷新</a-button>
  5       <a-button type="primary" @click="onAdd">新增</a-button>
  6     </a-space>
  7   </p>
  8   <a-table :dataSource="passengers"
  9            :columns="columns"
 10            :pagination="pagination"
 11            @change="handleTableChange"
 12            :loading="loading">
 13     <template #bodyCell="{ column, record }">
 14       <template v-if="column.dataIndex === 'operation'">
 15         <a-space>
 16           <a-popconfirm
 17               title="删除后不可恢复,确认删除?"
 18               @confirm="onDelete(record)"
 19               ok-text="确认" cancel-text="取消">
 20             <a style="color: red">删除</a>
 21           </a-popconfirm>
 22           <a @click="onEdit(record)">编辑</a>
 23         </a-space>
 24       </template>
 25     </template>
 26   </a-table>
 27   <a-modal v-model:visible="visible" title="乘车人" @ok="handleOk"
 28            ok-text="确认" cancel-text="取消">
 29     <a-form :model="passenger" :label-col="{span: 4}" :wrapper-col="{ span: 20 }">
 30       <a-form-item label="姓名">
 31         <a-input v-model:value="passenger.name" />
 32       </a-form-item>
 33       <a-form-item label="身份证">
 34         <a-input v-model:value="passenger.idCard" />
 35       </a-form-item>
 36       <a-form-item label="类型">
 37         <a-select v-model:value="passenger.type">
 38           <a-select-option value="1">成人</a-select-option>
 39           <a-select-option value="2">儿童</a-select-option>
 40           <a-select-option value="3">学生</a-select-option>
 41         </a-select>
 42       </a-form-item>
 43     </a-form>
 44   </a-modal>
 45 </template>
 46 <script>
 47 import { defineComponent, ref, onMounted } from 'vue';
 48 import {notification} from "ant-design-vue";
 49 import axios from "axios";
 50 
 51 export default defineComponent({
 52   setup() {
 53     const visible = ref(false);
 54     let passenger = ref({
 55       id: undefined,
 56       memberId: undefined,
 57       name: undefined,
 58       idCard: undefined,
 59       type: undefined,
 60       createTime: undefined,
 61       updateTime: undefined,
 62     });
 63     const passengers = ref([]);
 64     // 分页的三个属性名是固定的
 65     const pagination = ref({
 66       total: 0,
 67       current: 1,
 68       pageSize: 2,
 69     });
 70     let loading = ref(false);
 71     const columns = [{
 72       title: '姓名',
 73       dataIndex: 'name',
 74       key: 'name',
 75     }, {
 76       title: '身份证',
 77       dataIndex: 'idCard',
 78       key: 'idCard',
 79     }, {
 80       title: '类型',
 81       dataIndex: 'type',
 82       key: 'type',
 83     }, {
 84       title: '操作',
 85       dataIndex: 'operation'
 86     }];
 87 
 88     const onAdd = () => {
 89       passenger.value = {};
 90       visible.value = true;
 91     };
 92 
 93     const onEdit = (record) => {
 94       passenger.value = window.Tool.copy(record);
 95       visible.value = true;
 96     };
 97 
 98     const onDelete = (record) => {
 99       axios.delete("/member/passenger/delete/" + record.id).then((response) => {
100         const data = response.data;
101         if (data.success) {
102           notification.success({description: "删除成功!"});
103           handleQuery({
104             page: pagination.value.current,
105             size: pagination.value.pageSize,
106           });
107         } else {
108           notification.error({description: data.message});
109         }
110       });
111     };
112 
113     const handleOk = () => {
114       axios.post("/member/passenger/save", passenger.value).then((response) => {
115         let data = response.data;
116         if (data.success) {
117           notification.success({description: "保存成功!"});
118           visible.value = false;
119           handleQuery({
120             page: pagination.value.current,
121             size: pagination.value.pageSize
122           });
123         } else {
124           notification.error({description: data.message});
125         }
126       });
127     };
128 
129     const handleQuery = (param) => {
130       if (!param) {
131         param = {
132           page: 1,
133           size: pagination.value.pageSize
134         };
135       }
136       loading.value = true;
137       axios.get("/member/passenger/query-list", {
138         params: {
139           page: param.page,
140           size: param.size
141         }
142       }).then((response) => {
143         loading.value = false;
144         let data = response.data;
145         if (data.success) {
146           passengers.value = data.content.list;
147           // 设置分页控件的值
148           pagination.value.current = param.page;
149           pagination.value.total = data.content.total;
150         } else {
151           notification.error({description: data.message});
152         }
153       });
154     };
155 
156     const handleTableChange = (pagination) => {
157       // console.log("看看自带的分页参数都有啥:" + pagination);
158       handleQuery({
159         page: pagination.current,
160         size: pagination.pageSize
161       });
162     };
163 
164     onMounted(() => {
165       handleQuery({
166         page: 1,
167         size: pagination.value.pageSize
168       });
169     });
170 
171     return {
172       passenger,
173       visible,
174       onAdd,
175       handleOk,
176       passengers,
177       pagination,
178       columns,
179       handleTableChange,
180       handleQuery,
181       loading,
182       onEdit,
183       onDelete
184     };
185   },
186 });
187 </script>
188 <style>
189 </style>
passenger.vue

前端枚举的解决方案

将下拉框的值提取成常量数组

  1 <template>
  2   <p>
  3     <a-space>
  4       <a-button type="primary" @click="handleQuery()">刷新</a-button>
  5       <a-button type="primary" @click="onAdd">新增</a-button>
  6     </a-space>
  7   </p>
  8   <a-table :dataSource="passengers"
  9            :columns="columns"
 10            :pagination="pagination"
 11            @change="handleTableChange"
 12            :loading="loading">
 13     <template #bodyCell="{ column, record }">
 14       <template v-if="column.dataIndex === 'operation'">
 15         <a-space>
 16           <a-popconfirm
 17               title="删除后不可恢复,确认删除?"
 18               @confirm="onDelete(record)"
 19               ok-text="确认" cancel-text="取消">
 20             <a style="color: red">删除</a>
 21           </a-popconfirm>
 22           <a @click="onEdit(record)">编辑</a>
 23         </a-space>
 24       </template>
 25     </template>
 26   </a-table>
 27   <a-modal v-model:visible="visible" title="乘车人" @ok="handleOk"
 28            ok-text="确认" cancel-text="取消">
 29     <a-form :model="passenger" :label-col="{span: 4}" :wrapper-col="{ span: 20 }">
 30       <a-form-item label="姓名">
 31         <a-input v-model:value="passenger.name" />
 32       </a-form-item>
 33       <a-form-item label="身份证">
 34         <a-input v-model:value="passenger.idCard" />
 35       </a-form-item>
 36       <a-form-item label="类型">
 37         <a-select v-model:value="passenger.type">
 38           <a-select-option v-for="item in PASSENGER_TYPE_ARRAY" :key="item.key" :value="item.key">{{item.value}}</a-select-option>
 39         </a-select>
 40       </a-form-item>
 41     </a-form>
 42   </a-modal>
 43 </template>
 44 <script>
 45 import { defineComponent, ref, onMounted } from 'vue';
 46 import {notification} from "ant-design-vue";
 47 import axios from "axios";
 48 
 49 export default defineComponent({
 50   setup() {
 51     const PASSENGER_TYPE_ARRAY = [{key: "1", value: "成人1"}, {key: "2", value: "儿童"}, {key: "3", value: "学生"}];
 52     const visible = ref(false);
 53     let passenger = ref({
 54       id: undefined,
 55       memberId: undefined,
 56       name: undefined,
 57       idCard: undefined,
 58       type: undefined,
 59       createTime: undefined,
 60       updateTime: undefined,
 61     });
 62     const passengers = ref([]);
 63     // 分页的三个属性名是固定的
 64     const pagination = ref({
 65       total: 0,
 66       current: 1,
 67       pageSize: 2,
 68     });
 69     let loading = ref(false);
 70     const columns = [{
 71       title: '姓名',
 72       dataIndex: 'name',
 73       key: 'name',
 74     }, {
 75       title: '身份证',
 76       dataIndex: 'idCard',
 77       key: 'idCard',
 78     }, {
 79       title: '类型',
 80       dataIndex: 'type',
 81       key: 'type',
 82     }, {
 83       title: '操作',
 84       dataIndex: 'operation'
 85     }];
 86 
 87     const onAdd = () => {
 88       passenger.value = {};
 89       visible.value = true;
 90     };
 91 
 92     const onEdit = (record) => {
 93       passenger.value = window.Tool.copy(record);
 94       visible.value = true;
 95     };
 96 
 97     const onDelete = (record) => {
 98       axios.delete("/member/passenger/delete/" + record.id).then((response) => {
 99         const data = response.data;
100         if (data.success) {
101           notification.success({description: "删除成功!"});
102           handleQuery({
103             page: pagination.value.current,
104             size: pagination.value.pageSize,
105           });
106         } else {
107           notification.error({description: data.message});
108         }
109       });
110     };
111 
112     const handleOk = () => {
113       axios.post("/member/passenger/save", passenger.value).then((response) => {
114         let data = response.data;
115         if (data.success) {
116           notification.success({description: "保存成功!"});
117           visible.value = false;
118           handleQuery({
119             page: pagination.value.current,
120             size: pagination.value.pageSize
121           });
122         } else {
123           notification.error({description: data.message});
124         }
125       });
126     };
127 
128     const handleQuery = (param) => {
129       if (!param) {
130         param = {
131           page: 1,
132           size: pagination.value.pageSize
133         };
134       }
135       loading.value = true;
136       axios.get("/member/passenger/query-list", {
137         params: {
138           page: param.page,
139           size: param.size
140         }
141       }).then((response) => {
142         loading.value = false;
143         let data = response.data;
144         if (data.success) {
145           passengers.value = data.content.list;
146           // 设置分页控件的值
147           pagination.value.current = param.page;
148           pagination.value.total = data.content.total;
149         } else {
150           notification.error({description: data.message});
151         }
152       });
153     };
154 
155     const handleTableChange = (pagination) => {
156       // console.log("看看自带的分页参数都有啥:" + pagination);
157       handleQuery({
158         page: pagination.current,
159         size: pagination.pageSize
160       });
161     };
162 
163     onMounted(() => {
164       handleQuery({
165         page: 1,
166         size: pagination.value.pageSize
167       });
168     });
169 
170     return {
171       PASSENGER_TYPE_ARRAY,
172       passenger,
173       visible,
174       onAdd,
175       handleOk,
176       passengers,
177       pagination,
178       columns,
179       handleTableChange,
180       handleQuery,
181       loading,
182       onEdit,
183       onDelete
184     };
185   },
186 });
187 </script>
188 <style>
189 </style>
passenger.vue

解决表格中枚举字段的显示

  1 <template>
  2   <p>
  3     <a-space>
  4       <a-button type="primary" @click="handleQuery()">刷新</a-button>
  5       <a-button type="primary" @click="onAdd">新增</a-button>
  6     </a-space>
  7   </p>
  8   <a-table :dataSource="passengers"
  9            :columns="columns"
 10            :pagination="pagination"
 11            @change="handleTableChange"
 12            :loading="loading">
 13     <template #bodyCell="{ column, record }">
 14       <template v-if="column.dataIndex === 'operation'">
 15         <a-space>
 16           <a-popconfirm
 17               title="删除后不可恢复,确认删除?"
 18               @confirm="onDelete(record)"
 19               ok-text="确认" cancel-text="取消">
 20             <a style="color: red">删除</a>
 21           </a-popconfirm>
 22           <a @click="onEdit(record)">编辑</a>
 23         </a-space>
 24       </template>
 25       <template v-else-if="column.dataIndex === 'type'">
 26         <span v-for="item in PASSENGER_TYPE_ARRAY" :key="item.key">
 27           <span v-if="item.key === record.type">
 28             {{item.value}}
 29           </span>
 30         </span>
 31       </template>
 32     </template>
 33   </a-table>
 34   <a-modal v-model:visible="visible" title="乘车人" @ok="handleOk"
 35            ok-text="确认" cancel-text="取消">
 36     <a-form :model="passenger" :label-col="{span: 4}" :wrapper-col="{ span: 20 }">
 37       <a-form-item label="姓名">
 38         <a-input v-model:value="passenger.name" />
 39       </a-form-item>
 40       <a-form-item label="身份证">
 41         <a-input v-model:value="passenger.idCard" />
 42       </a-form-item>
 43       <a-form-item label="类型">
 44         <a-select v-model:value="passenger.type">
 45           <a-select-option v-for="item in PASSENGER_TYPE_ARRAY" :key="item.key" :value="item.key">{{item.value}}</a-select-option>
 46         </a-select>
 47       </a-form-item>
 48     </a-form>
 49   </a-modal>
 50 </template>
 51 <script>
 52 import { defineComponent, ref, onMounted } from 'vue';
 53 import {notification} from "ant-design-vue";
 54 import axios from "axios";
 55 
 56 export default defineComponent({
 57   setup() {
 58     const PASSENGER_TYPE_ARRAY = [{key: "1", value: "成人"}, {key: "2", value: "儿童"}, {key: "3", value: "学生"}];
 59     const visible = ref(false);
 60     let passenger = ref({
 61       id: undefined,
 62       memberId: undefined,
 63       name: undefined,
 64       idCard: undefined,
 65       type: undefined,
 66       createTime: undefined,
 67       updateTime: undefined,
 68     });
 69     const passengers = ref([]);
 70     // 分页的三个属性名是固定的
 71     const pagination = ref({
 72       total: 0,
 73       current: 1,
 74       pageSize: 2,
 75     });
 76     let loading = ref(false);
 77     const columns = [{
 78       title: '姓名',
 79       dataIndex: 'name',
 80       key: 'name',
 81     }, {
 82       title: '身份证',
 83       dataIndex: 'idCard',
 84       key: 'idCard',
 85     }, {
 86       title: '类型',
 87       dataIndex: 'type',
 88       key: 'type',
 89     }, {
 90       title: '操作',
 91       dataIndex: 'operation'
 92     }];
 93 
 94     const onAdd = () => {
 95       passenger.value = {};
 96       visible.value = true;
 97     };
 98 
 99     const onEdit = (record) => {
100       passenger.value = window.Tool.copy(record);
101       visible.value = true;
102     };
103 
104     const onDelete = (record) => {
105       axios.delete("/member/passenger/delete/" + record.id).then((response) => {
106         const data = response.data;
107         if (data.success) {
108           notification.success({description: "删除成功!"});
109           handleQuery({
110             page: pagination.value.current,
111             size: pagination.value.pageSize,
112           });
113         } else {
114           notification.error({description: data.message});
115         }
116       });
117     };
118 
119     const handleOk = () => {
120       axios.post("/member/passenger/save", passenger.value).then((response) => {
121         let data = response.data;
122         if (data.success) {
123           notification.success({description: "保存成功!"});
124           visible.value = false;
125           handleQuery({
126             page: pagination.value.current,
127             size: pagination.value.pageSize
128           });
129         } else {
130           notification.error({description: data.message});
131         }
132       });
133     };
134 
135     const handleQuery = (param) => {
136       if (!param) {
137         param = {
138           page: 1,
139           size: pagination.value.pageSize
140         };
141       }
142       loading.value = true;
143       axios.get("/member/passenger/query-list", {
144         params: {
145           page: param.page,
146           size: param.size
147         }
148       }).then((response) => {
149         loading.value = false;
150         let data = response.data;
151         if (data.success) {
152           passengers.value = data.content.list;
153           // 设置分页控件的值
154           pagination.value.current = param.page;
155           pagination.value.total = data.content.total;
156         } else {
157           notification.error({description: data.message});
158         }
159       });
160     };
161 
162     const handleTableChange = (pagination) => {
163       // console.log("看看自带的分页参数都有啥:" + pagination);
164       handleQuery({
165         page: pagination.current,
166         size: pagination.pageSize
167       });
168     };
169 
170     onMounted(() => {
171       handleQuery({
172         page: 1,
173         size: pagination.value.pageSize
174       });
175     });
176 
177     return {
178       PASSENGER_TYPE_ARRAY,
179       passenger,
180       visible,
181       onAdd,
182       handleOk,
183       passengers,
184       pagination,
185       columns,
186       handleTableChange,
187       handleQuery,
188       loading,
189       onEdit,
190       onDelete
191     };
192   },
193 });
194 </script>
195 <style>
196 </style>
passenger.vue

将枚举数组放入单独的文件中

1 PASSENGER_TYPE_ARRAY = [{key: "1", value: "成人"}, {key: "2", value: "儿童"}, {key: "3", value: "学生"}];
assets/js/enums.js
  1 <template>
  2   <p>
  3     <a-space>
  4       <a-button type="primary" @click="handleQuery()">刷新</a-button>
  5       <a-button type="primary" @click="onAdd">新增</a-button>
  6     </a-space>
  7   </p>
  8   <a-table :dataSource="passengers"
  9            :columns="columns"
 10            :pagination="pagination"
 11            @change="handleTableChange"
 12            :loading="loading">
 13     <template #bodyCell="{ column, record }">
 14       <template v-if="column.dataIndex === 'operation'">
 15         <a-space>
 16           <a-popconfirm
 17               title="删除后不可恢复,确认删除?"
 18               @confirm="onDelete(record)"
 19               ok-text="确认" cancel-text="取消">
 20             <a style="color: red">删除</a>
 21           </a-popconfirm>
 22           <a @click="onEdit(record)">编辑</a>
 23         </a-space>
 24       </template>
 25       <template v-else-if="column.dataIndex === 'type'">
 26         <span v-for="item in PASSENGER_TYPE_ARRAY" :key="item.key">
 27           <span v-if="item.key === record.type">
 28             {{item.value}}
 29           </span>
 30         </span>
 31       </template>
 32     </template>
 33   </a-table>
 34   <a-modal v-model:visible="visible" title="乘车人" @ok="handleOk"
 35            ok-text="确认" cancel-text="取消">
 36     <a-form :model="passenger" :label-col="{span: 4}" :wrapper-col="{ span: 20 }">
 37       <a-form-item label="姓名">
 38         <a-input v-model:value="passenger.name" />
 39       </a-form-item>
 40       <a-form-item label="身份证">
 41         <a-input v-model:value="passenger.idCard" />
 42       </a-form-item>
 43       <a-form-item label="类型">
 44         <a-select v-model:value="passenger.type">
 45           <a-select-option v-for="item in PASSENGER_TYPE_ARRAY" :key="item.key" :value="item.key">{{item.value}}</a-select-option>
 46         </a-select>
 47       </a-form-item>
 48     </a-form>
 49   </a-modal>
 50 </template>
 51 <script>
 52 import { defineComponent, ref, onMounted } from 'vue';
 53 import {notification} from "ant-design-vue";
 54 import axios from "axios";
 55 
 56 export default defineComponent({
 57   setup() {
 58     const PASSENGER_TYPE_ARRAY = window.PASSENGER_TYPE_ARRAY;
 59     const visible = ref(false);
 60     let passenger = ref({
 61       id: undefined,
 62       memberId: undefined,
 63       name: undefined,
 64       idCard: undefined,
 65       type: undefined,
 66       createTime: undefined,
 67       updateTime: undefined,
 68     });
 69     const passengers = ref([]);
 70     // 分页的三个属性名是固定的
 71     const pagination = ref({
 72       total: 0,
 73       current: 1,
 74       pageSize: 2,
 75     });
 76     let loading = ref(false);
 77     const columns = [{
 78       title: '姓名',
 79       dataIndex: 'name',
 80       key: 'name',
 81     }, {
 82       title: '身份证',
 83       dataIndex: 'idCard',
 84       key: 'idCard',
 85     }, {
 86       title: '类型',
 87       dataIndex: 'type',
 88       key: 'type',
 89     }, {
 90       title: '操作',
 91       dataIndex: 'operation'
 92     }];
 93 
 94     const onAdd = () => {
 95       passenger.value = {};
 96       visible.value = true;
 97     };
 98 
 99     const onEdit = (record) => {
100       passenger.value = window.Tool.copy(record);
101       visible.value = true;
102     };
103 
104     const onDelete = (record) => {
105       axios.delete("/member/passenger/delete/" + record.id).then((response) => {
106         const data = response.data;
107         if (data.success) {
108           notification.success({description: "删除成功!"});
109           handleQuery({
110             page: pagination.value.current,
111             size: pagination.value.pageSize,
112           });
113         } else {
114           notification.error({description: data.message});
115         }
116       });
117     };
118 
119     const handleOk = () => {
120       axios.post("/member/passenger/save", passenger.value).then((response) => {
121         let data = response.data;
122         if (data.success) {
123           notification.success({description: "保存成功!"});
124           visible.value = false;
125           handleQuery({
126             page: pagination.value.current,
127             size: pagination.value.pageSize
128           });
129         } else {
130           notification.error({description: data.message});
131         }
132       });
133     };
134 
135     const handleQuery = (param) => {
136       if (!param) {
137         param = {
138           page: 1,
139           size: pagination.value.pageSize
140         };
141       }
142       loading.value = true;
143       axios.get("/member/passenger/query-list", {
144         params: {
145           page: param.page,
146           size: param.size
147         }
148       }).then((response) => {
149         loading.value = false;
150         let data = response.data;
151         if (data.success) {
152           passengers.value = data.content.list;
153           // 设置分页控件的值
154           pagination.value.current = param.page;
155           pagination.value.total = data.content.total;
156         } else {
157           notification.error({description: data.message});
158         }
159       });
160     };
161 
162     const handleTableChange = (pagination) => {
163       // console.log("看看自带的分页参数都有啥:" + pagination);
164       handleQuery({
165         page: pagination.current,
166         size: pagination.pageSize
167       });
168     };
169 
170     onMounted(() => {
171       handleQuery({
172         page: 1,
173         size: pagination.value.pageSize
174       });
175     });
176 
177     return {
178       PASSENGER_TYPE_ARRAY,
179       passenger,
180       visible,
181       onAdd,
182       handleOk,
183       passengers,
184       pagination,
185       columns,
186       handleTableChange,
187       handleQuery,
188       loading,
189       onEdit,
190       onDelete
191     };
192   },
193 });
194 </script>
195 <style>
196 </style>
passenger.vue

main.js  import

import './assets/js/enums';

package.json添加规则

"no-undef": 0

 

posted on 2023-04-17 15:38  夏雪冬蝉  阅读(70)  评论(0编辑  收藏  举报