仿12306购票系统(3)

news/2025/3/4 7:45:32/

前面完成了乘车人登录功能的实现,本篇主要是控制台方面的管理

对于整体的控制台的设计,为了能够快速的检验,不进行登录拦截,在控制台的这个模块的controller层增加admin,以及在登录界面的拦截器排除掉admin.

车站

即都有那些车站

create table `station` (`id` bigint not null comment 'id',`name` varchar(20) not null comment '站名',`name_pinyin` varchar(50) not null comment '站名拼音',`name_py` varchar(50) not null comment '站名拼音首字母',`create_time` datetime(3) comment '新增时间',`update_time` datetime(3) comment '修改时间',primary key (`id`),unique key `name_unique` (`name`)
) engine=innodb default charset=utf8mb4 comment='车站';

首先,使用bigint类型的id作为主键,可以支持大量的车站记录。使用唯一标识进行每个车站的管理,便于数据库管理和关联其他表。为了方便查询车站,添加了站名,站名拼音和站名拼音首字母。

火车基础数据的管理

就是一辆火车的数据,这里设计如下

drop table if exists `train`;
create table `train` (`id` bigint not null comment 'id',`code` varchar(20) not null comment '车次编号',`type` char(1) not null comment '车次类型|枚举[TrainTypeEnum]',`start` varchar(20) not null comment '始发站',`start_pinyin` varchar(50) not null comment '始发站拼音',`start_time` time not null comment '出发时间',`end` varchar(20) not null comment '终点站',`end_pinyin` varchar(50) not null comment '终点站拼音',`end_time` time not null comment '到站时间',`create_time` datetime(3) comment '新增时间',`update_time` datetime(3) comment '修改时间',primary key (`id`),unique key `code_unique` (`code`)
) engine=innodb default charset=utf8mb4 comment='车次';

其中的车次类型是因为火车不仅仅有动车,还有高铁,普通列车等。可以仿照乘客表的乘客类型来进行车次车次类型的设计。为了计算不同车次的票价,在枚举类中为不同的车次类型增加系数,例如,高铁为1.2,表示票价=1.2*每公里单价*公里,实际上可能更加的复杂。这里只是基础讨论功能的实现。看上面的事件类型发现,出发时间,到站时间和新增时间与修改时间的类型不同,其中datatime类型非常适合需要同时记录具体哪一天的什么时候发生的场景。time类型记录事件发生的具体时间。这样设计是因为此时是基础的数据功能,并不是每日的车次,火车每天出发的时间是一定的,因此不需要记录具体的日期。

为了是选择时间,而不是手动的输入时间,可以在前端增加控件,如果是time类型,增加a-time-picker,如果是time类型,增加a-datepicker,为了方便,可以在自定义的代码生成器实现。

<#elseif field.javaType=='Date'><#if field.type=='time'><a-time-picker v-model:value="${domain}.${field.nameHump}" valueFormat="HH:mm:ss" placeholder="请选择时间" /><#elseif field.type=='date'><a-date-picker v-model:value="${domain}.${field.nameHump}" valueFormat="YYYY-MM-DD" placeholder="请选择日期" /><#else><a-date-picker v-model:value="${domain}.${field.nameHump}" valueFormat="YYYY-MM-DD HH:mm:ss" show-time placeholder="请选择日期" /></#if>

火车车站的管理

就是车次的车站,一列火车要经过那些车站。

create table `train_station` (`id` bigint not null comment 'id',`train_code` varchar(20) not null comment '车次编号',`index` int not null comment '站序',`name` varchar(20) not null comment '站名',`name_pinyin` varchar(50) not null comment '站名拼音',`in_time` time comment '进站时间',`out_time` time comment '出站时间',`stop_time` time comment '停站时长',`km` decimal(8, 2) not null comment '里程(公里)|从上一站到本站的距离',`create_time` datetime(3) comment '新增时间',`update_time` datetime(3) comment '修改时间',primary key (`id`),unique key `train_code_index_unique` (`train_code`, `index`),unique key `train_code_name_unique` (`train_code`, `name`)
) engine=innodb default charset=utf8mb4 comment='火车车站';

其中的车次编号和某辆火车进行关联,站序指的是从始发站到终点站经过的车站顺序的排列。停站时常是可以通过进站和出站时间进行计算,为了方便查询,将id作为主键。在实际的情况中,一辆火车从起点到终点不会经过某个站两次,因此需要增加唯一键来进行数据的检验。如何将这两张表进行关联呢,在train表中一个唯一键code,使用唯一键进行关联,方便业务上的一些功能,train_code的起名就是和train这张表的code字段进行关联。当然如果没有设计唯一键,可以考虑使用id进行关联。

火车车厢

create table `train_carriage` (`id` bigint not null comment 'id',`train_code` varchar(20) not null comment '车次编号',`index` int not null comment '厢号',`seat_type` char(1) not null comment '座位类型|枚举[SeatTypeEnum]',`seat_count` int not null comment '座位数',`row_count` int not null comment '排数',`col_count` int not null comment '列数',`create_time` datetime(3) comment '新增时间',`update_time` datetime(3) comment '修改时间',unique key `train_code_index_unique` (`train_code`, `index`),primary key (`id`)
) engine=innodb default charset=utf8mb4 comment='火车车厢';

每一列车厢都要对应一列火车,因此需要根火车表进行关联,即train_index,由于不可能发生一列火车有两个相同编号的车厢,因此需要进行车次编号和厢号的关联。由于不同的车厢有不同的作为类型,因此可以将其进行枚举。

座位表

        对于一辆火车来说,没有座位表是不完整的,由于座位属于某个车次,因此需要和火车进行关联,座位应该属于某个车厢,因此应该和车厢有所关联。同车厢内,每个座位可以按照行和列进行唯一的查找,每一个车厢都是从123往后排的,因此需要一个同车厢坐序。

        在进行枚举座位行类中,设定一等座一排四个,二等座一排5个,增加code和desc,最后要增加一个type,来描述是什么类型。这个type就是对于的SeatType的枚举类,假设传入一个一等座,可以根据type等于1查出一等座对应的列,这样前端做一些下拉框就比较方便,知道一等座,就能知道有那些可以选择。

java">    /*** 根据车箱的座位类型,筛选出所有的列,比如车箱类型是一等座,则筛选出columnList={ACDF}*/public static List<SeatColEnum> getColsByType(String seatType) {List<SeatColEnum> colList = new ArrayList<>();EnumSet<SeatColEnum> seatColEnums = EnumSet.allOf(SeatColEnum.class);for (SeatColEnum anEnum : seatColEnums) {if (seatType.equals(anEnum.getType())) {colList.add(anEnum);}}return colList;}

优化

输入车站名称后自动显示拼音,前端可以引入"pinyin-pro"组件

java">watch(()=> station.value.name, () => {if (Tool.isNotEmpty(station.value.name)) {station.value.namePinyin = pinyin(station.value.name, {toneType: 'none'}).replaceAll(" ", "");station.value.namePy = pinyin(station.value.name, {pattern: 'first',toneType: 'none'}).replaceAll(" ","");}},{immediate: true});

利用watch函数监听响应式数据的变化。监听的是station.value.name的变化,并在变化时更新station.value.namePinyinstation.value.namePy两个属性。第一个参数是要监听的数据,第二个参数是回调函数,表示如果发生变换,立即执行回调函数

火车车站的车次编号应该座位下拉框:首先后端提供一个接口查询所有的车次,然后前端界面的更改。对于查询接口来说,不需要参数,将查到的车站按照降序排列,以List形式进行返回。

java">    public List<TrainQueryResp> queryAll() {TrainExample trainExample = new TrainExample();trainExample.setOrderByClause("code desc");List<Train> trainList= trainMapper.selectByExample(trainExample);return BeanUtil.copyToList(trainList, TrainQueryResp.class);}@GetMapping("/query-all")public CommonResp<List<TrainQueryResp>> queryList() {List<TrainQueryResp> list = trainService.queryAll();return new CommonResp<>(list);}

然后前端去拿到后端的数据

java">const queryTrainCode = () => {axios.get("/business/admin/train/query-all").then((response) => {let data = response.data;if (data.success) {console.log(data.content);} else {notification.error({description: data.message});}});};
java">        <a-select v-model:value="trainStation.trainCode" show-search:filterOption="filterTrainCodeOption"><a-select-option v-for="item in trains" :key="item.code" :value="item.code" :label="item.code + item.start + item.end">{{item.code}} | {{item.start}} ~ {{item.end}}</a-select-option></a-select>const filterTrainCodeOption = (input, option) => {console.log(input, option)return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;};
  • v-model:value="trainStation.trainCode": 将选择器的值绑定到trainStation对象的trainCode属性上,当选择一个选项时,trainStation.trainCode会自动更新为所选的值。
  • show-search: 启用搜索框,允许通过输入来过滤列表中的选项。
  • :filterOption="filterTrainCodeOption": 使用自定义的过滤函数filterTrainCodeOption来决定哪些选项应该在用户输入时显示。
  • v-for="item in trains": 遍历trains数组
  • :key="item.code": 为每个选项指定一个唯一的键,这里使用的是列车代码。
  • :value="item.code": 设置选项的值为列车代码,这将与v-model绑定的值对应。
  • :label="item.code + item.start + item.end": 定义选项的标签,这里是将列车代码、始发站和终点站的信息组合起来作为选项的显示文本。
  • {{item.code}} | {{item.start}} ~ {{item.end}}: 更好地显示
  • filterTrainCodeOption筛选列车选项的函数

为了方便,可以将车次制作成一个组件,然后引入到各个模块,然后车站也可以做出下拉框组件,引入到各个模块。限于篇幅,这里不在赘述。

查询

        由于火车各部分的数据量庞大,如果将所有数据全部显示,将会给系统带来显著的性能压力,并可能影响体验。因此,引入了条件查询机制,以便根据用户的具体需求动态加载和展示相关数据,从而优化性能并提升系统的响应速度。

对于后端的车站查询接口来说,如果是传入的train_code不为空,就根据请求参数得到的trainCode来进行查询,座位和车厢同理,只需要修改service层代码,以及增加参数的请求类型。

java">if(ObjectUtil.isNotEmpty(req.getTrainCode())) {criteria.andTrainCodeEqualTo(req.getTrainCode());
}package com.month.train.business.req;import com.month.train.common.req.PageReq;public class TrainSeatQueryReq extends PageReq {private String trainCode;public String getTrainCode() {return trainCode;}public void setTrainCode(String trainCode) {this.trainCode = trainCode;}@Overridepublic String toString() {return "TrainSeatQueryReq{" +"trainCode='" + trainCode + '\'' +"} " + super.toString();}
}


http://www.ppmy.cn/news/1576490.html

相关文章

正式页面开发-登录注册页面

整体路由设计&#xff1a; 登录和注册的切换是切换组件或者是切换内容&#xff08;v-if和 v-else)&#xff0c;因为点击两个之间路径是没有变化的。也就是登录和注册共用同一个路由。登录是独立的一级路由。登录之后进到首页&#xff0c;有三个大模块&#xff1a;文章分类&…

无人机研发企业内容卷严重,如何突破困境?

无人机研发企业面临内容卷&#xff08;即行业内竞争激烈、同质化严重&#xff09;的困境时&#xff0c;可以从以下几个方面寻求突破&#xff1a; 一、明确市场定位与差异化竞争 1. 市场细分&#xff1a;深入研究无人机市场&#xff0c;明确目标客户群体和应用场景&#xff0c;…

【深度学习】Hopfield网络:模拟联想记忆

Hopfield网络是一种经典的循环神经网络&#xff0c;由物理学家John Hopfield在1982年提出。它的核心功能是模拟联想记忆&#xff0c;类似于人类大脑通过部分信息回忆完整记忆的能力。以下是通俗易懂的解释&#xff1a; 1. 核心思想 想象你看到一张模糊的老照片&#xff0c;虽然…

APP爬虫:Airtest的使用和爬取实战详解

文章目录 一、引言二、Airtest简介2.1 什么是Airtest?2.2 Airtest的主要功能2.3 Airtest 的核心组件三、Airtest的安装与配置3.1 安装Airtest3.2 配置设备四、Airtest的基本使用4.1 第一个Airtest脚本4.2 图像识别4.3 使用 Poco 定位元素4.4 常用操作4.5 处理动态加载内容4.6 …

【金融量化】解读量化投资回测指标

量化投资回测指标全解析&#xff1a;理解策略表现的关键 在量化投资中。通过回测&#xff0c;可以了解策略在历史数据上的表现&#xff0c;并通过一系列指标来衡量其优劣。 一个优秀的量化策略通常具有以下特点&#xff1a; 高策略收益和年化收益。高Alpha和低Beta&#xff0…

Oracle 字符串分割革命:正则表达式与 Lateral Join 的优雅解法

摘要&#xff1a;Oracle 12c 引入的 Lateral Join 技术彻底改变了字符串分割的实现范式&#xff0c;本文通过对比传统方案与正则表达式新特性&#xff0c;揭示如何用一行 SQL 完成复杂行列转换&#xff0c;为数据库研究者提供范式转换的典型案例。 一、传统分割方案的技术债 …

TCP的四次挥⼿为什么是四次?为什么不能是三 次

TCP 四次挥手&#xff08;Four-way Handshake&#xff09;用于终止一个已经建立的 TCP 连接。之所以是四次挥手&#xff0c;而不是三次&#xff0c;是因为 TCP 是全双工的&#xff08;full-duplex&#xff09;&#xff0c;这意味着数据可以在两个方向上同时传输。因此&#xff…

java2025热点面试题之springmvc

1. 请解释Spring MVC的工作原理。 答案&#xff1a; Spring MVC是一个基于Java的MVC框架&#xff0c;用于构建Web应用程序。其工作原理如下&#xff1a; 客户端发送请求到DispatcherServlet&#xff0c;它是Spring MVC的前端控制器。DispatcherServlet查询HandlerMapping&…