/TicketSystem-2021

ACM2021-homework

Primary LanguageJavaScript

火车票管理系统


队伍概述

Team name: “关于Libro想要写火车票前端这件事”

Contributor Responsible for
Fourest Backend logic
walotta Backend database(BPlusTree) & FrontEnd

项目概况

实现内容

本项目实现了一个类似于12306的火车票订票系统,该系统能将用户数据、购票数据、车次数据进行本地存储,并对其进行高效操作。

程序结构

后端程序实现了文档中要求的接口,并且在接受完整命令后立即输出结果并再次进入响应输入的状态。后端程序使用C++实现。

前端程序

对外接口与指令的说明

用户相关

一个用户有以下数据:

  • username:用户的唯一标识符,由字母开头,字母、数字和下划线组成的字符串,长度不超过20。
  • password:由字母、数字和下划线组成的字符串,长度不低于6,不超过30。
  • name:由二至五个汉字组成的字符串。
  • mailAddr:同一般邮箱地址格式,且仅含数字、大小写字母,@.,长度不超过30。(无需检验邮箱格式的合法性)
  • privilege:所处用户组优先级,为一个0~10的整数。

车次相关

一个车次有以下属性:

  • trainID:车次的唯一标识符,由字母开头,字母、数字和下划线组成的字符串,长度不超过20。

  • stationNum:车次经过的车站数量,为大于1且不超过100的整数。

  • stations:车次经过的所有车站名,共stationNum项,站名由汉字组成,不超过10个汉字。

    格式为:station_1 station_2 station_3 ... station_stationNum

  • seatNum:该车次的座位数,为不超过100000的整数。

  • prices:每两站之间的票价,共(stationNum - 1)项,第i项表示station_istation_(i+1)的票价,是一个不超过100000的整数。

    格式为:price_1 price_2 price_3 ... price_(stationNum - 1)

  • startTime:列车每日的发车时间,时间格式为hr:mi。如:23:51

  • travelTimes:每两站之间行车所用的时间(单位为分钟),共(stationNum - 1)项,每一项是一个不超过10000的整数。

  • stopoverTimes:除始发站和终点站之外,列车在每一站停留的时间(单位为分钟),共(stationNum - 2)项,每一项是一个不超过10000的整数。

  • saleDate:车次的售卖时间区间(闭区间),在时间区间内,每天都有相同的此车次。共2项,每一项均为2021年6月至8月的某一天,日期格式为mm-dd。如:06-07

  • train_type:列车类型,为一个大写字母。

指令

每一条指令有一个“常用度”参数,为其在实际情况中的常用程度,也是它在压力测试中的大致出现比例,分为以下几个等级,你可以将其作为设计算法的依据。

  • SF:Super frequently used. (~1000000)
  • F:Frequently used. (~100000)
  • N:Normally used. (~10000)
  • R:Rarely used. (~100)

参数的格式为-<key> <argument>,其中<key>是一个小写字母。为简化描述,在参数列表中省略<argument>并在说明中以-<key>代指其对应的参数。若不做特殊说明,每个参数都是一个不含空格的字符串。

参数列表的顺序不限,可选参数可以省略,在说明中有可选参数的初始值(如果不为空的话)。

指令的返回值为命令行交互中输出在标准输出流中的执行结果。

  • [N] add_user

    • 参数列表

      -c -u -p -n -m -g

    • 说明

      当前用户<cur_username>-c,创建一个<username>-u<password>-p<name>-n<mailAddr>-m<privilege>-g的用户。

      权限要求:-c已登录,且新用户的权限低于-c的权限。

      特别地,创建第一个用户时,新用户权限为10,不受上述权限规则约束。具体来讲,当创建第一个用户时,忽略-c-g参数,并认为新用户优先级为10。

    • 返回值

      注册成功:0

      注册失败:-1

  • [F] login

    • 参数列表

      -u -p

    • 说明

      -u<username>-p<password>登录。若登录成功,当前用户列表增加此用户。第一次进入系统时,当前用户为空。

    • 返回值

      登录成功:0

      登录失败:-1

  • [F] logout

    • 参数列表

      -u

    • 说明

      <username>-u的用户退出登录。若退出成功,将此用户移出当前用户列表。

    • 返回值

      登出成功:0

      登出失败:-1

  • [SF] query_profile

    • 参数列表

      -c -u

    • 说明

      <username>-c的用户查询<username>-u的用户信息。

      权限要求:-c已登录,且「-c的权限大于-u的权限,或是-c-u相同」。

    • 返回值

      查询成功:一行字符串,依次为被查询用户的<username><name><mailAddr><privilege>,用一个空格隔开。

      查询失败:-1

  • [F] modify_profile

    • 参数列表

      -c -u (-p) (-n) (-m) (-g)

    • 说明

      <username>-c的用户修改<username>-u的用户信息。修改参数同注册参数,且均可以省略。

      权限要求:-c已登录,且「-c的权限大于-u的权限,或是-c-u相同」,且-g需低于-c的权限。

    • 返回值

      修改成功:返回被修改用户的信息,格式同query_profile

      修改失败:-1

  • [N] add_train

    • 参数列表

      -i -n -m -s -p -x -t -o -d -y

    • 说明

      添加<trainID>-i<stationNum>-n<seatNum>-m<stations>-s<prices>-p<startTime>-x<travelTimes>-t<stopoverTimes>-o<saleDate>-d<train_type>-y的车次。

      由于-s-p-t-o-d由多个值组成,输入时两个值之间以|隔开(仍是一个不含空格的字符串)。

    • 返回值

      添加成功:0

      添加失败:-1

    • 举例:

      > add_train -i HAPPY_TRAIN -n 3 -m 1000 -s 上院|中院|下院 -p 115|514 -x 19:19 -t 600|600 -o 5 -d 06-01|08-17 -y G

      0

  • [N] release_train

    • 参数列表

      -i

    • 说明

      <trainID>-i的车次发布。发布前的车次可被删除,不可发售车票;发售后的车次不可被删除,可发售车票。

    • 返回值

      发布成功:0

      发布失败:-1

    • 举例:

      > release_train -i HAPPY_TRAIN

      0

  • [N] query_train

    • 参数列表

      -i -d

    • 说明

      查询在日期-d发车的,<trainID>-i的车次的情况,-d的格式为mm-dd

    • 返回值

      查询成功:输出共(<stationNum> + 1)行。

      ​ 第一行为<trainID> <train_type>

      ​ 接下来<stationNum>行,第i行为<stations[i]> <ARRIVING_TIME> -> <LEAVING_TIME> <PRICE> <SEAT>,其中<ARRIVING_TIME><LEAVING_TIME>为列车到达本站和离开本站的绝对时间,格式为mm-dd hr:mi<PRICE>为从始发站乘坐至该站的累计票价,<SEAT>为从该站到下一站的剩余票数。对于始发站的到达时间和终点站的出发时间,所有数字均用x代替;终点站的剩余票数用x代替。

      查询失败:-1

    • 举例

      (上接添加列车的例子)

      > query_train -d 07-01 -i HAPPY_TRAIN

      HAPPY_TRAIN G

      上院 xx-xx xx:xx -> 07-01 19:19 0 1000

      中院 07-02 05:19 -> 07-02 05:24 114 1000

      下院 07-02 15:24 -> xx-xx xx:xx 628 x

  • [N] delete_train

    • 参数列表

      -i

    • 说明

      删除<trainID>-i的车次。

    • 返回值

      删除成功:0

      删除失败:-1

  • [SF] query_ticket

    • 参数列表

      -s -t -d (-p time)

    • 说明

      查询日期为-d时从-s出发,并到达-t的车票。请注意:这里的日期是列车从-s出发的日期,不是从列车始发站出发的日期。

      -p的值为timecost中的一个,若为time表示输出按照该车次所需时间从小到大排序,否则按照票价从低到高排序。

    • 返回值

      查询成功: 第一行输出一个整数,表示符合要求的车次数量。

      接下来每一行输出一个符合要求的车次,按要求排序。格式为<trainID> <FROM> <LEAVING_TIME> -> <TO> <ARRIVING_TIME> <PRICE> <SEAT>,其中出发时间、到达时间格式同query_train<FROM><TO>为出发站和到达站,<PRICE>为累计价格,<SEAT>为最多能购买的票数。

      查询失败:-1

    • 样例

      (上接查询列车的例子)

      > query_ticket -s 中院 -t 下院 -d 08-17

      1

      HAPPY_TRAIN 中院 08-17 05:24 -> 下院 08-17 15:24 514 1000

  • [N] query_transfer

    参数列表及其意义同query_ticket

    • 说明

      在恰好换乘一次的情况下查询符合条件的车次,仅输出最优解。

    • 返回值

      查询失败(没有符合要求的车次):0

      查询成功:输出2行,换乘中搭乘的两个车次,格式同query_ticket

  • [SF] buy_ticket

    • 参数列表 -u -i -d -n -f -t (-q false)

    • 说明

      <username>-u的用户购买:<trainID>-i,日期为-d,从站-f到站-t的车票-n张。

      -q可选falsetrue,若为true,表明在余票不足的情况下愿意接受候补购票,当有余票时立即视为此用户购买了车票。

      权限要求:-u已登录。

    • 返回值

      购买成功:一个整数,表示订单总价。

      加入候补:queue

      购票失败:-1

    • 样例

      (上接查询车票的例子,假设用户均已登录)

      > buy_ticket -u Texas -i HAPPY_TRAIN -d 08-17 -n 800 -f 中院 -t 下院

      257000

      > buy_ticket -u Lappland -i HAPPY_TRAIN -d 08-16 -n 500 -f 上院 -t 下院 -q true

      queue

  • [F] query_order

    • 参数列表

      -u

    • 说明

      查询<username>-u的用户的所有订单信息,按照交易时间顺序从新到旧排序(候补订单即使补票成功,交易时间也以下单时刻为准)。

      权限要求:-u已登录。

    • 返回值

      查询成功:第一行输出一个整数,表示订单数量。

      接下来每一行表示一个订单,格式为[<Status>] <trainID> <FROM> <LEAVING_TIME> -> <TO> <ARRIVING_TIME> <PRICE> <NUM>,其中<NUM>为购票数量,<IS_PENDING>表示该订单的状态,可能的值为:success(购票已成功)、pending(位于候补购票队列中)和refunded(已经退票)。

      查询失败:-1

    • 样例

      > query_order -u Lappland

      1

      [pending] HAPPY_TRAIN 上院 08-17 05:24 -> 下院 08-17 15:24 628 500

  • [N] refund_ticket

    • 参数列表

      -u (-n 1)

    • 说明

      <username>-u的用户退订从新到旧(即query_order的返回顺序)第-n个订单。

      权限要求:-u已登录。

    • 返回值

      退票成功:0

      退票失败:-1

  • [R] clean

    • 参数列表

    • 说明

      清除所有数据。

    • 返回值

      0

  • [R] exit

    • 参数列表

    • 说明

      退出程序,所有在线用户均下线。

    • 返回值

      bye

Q&A

注:若文档有更新,也会在这里列出对应的修改。

  • Q: 有没有隔天的车?

    A: 有的,且售票日期区间所指的为起点站发车的时刻所在的日期,查询或购买车票所指的为上车的站发车的时刻所在的日期。

  • Q: 再读入时需要判断各种信息的格式是否合法吗?

    A: 不需要,保证输入格式合法。

  • Q: 候补购票队列优先级是先下单的先满足,不能满足就看下一个可不可以满足吗?

    A: 是的。

  • Q: 同优先级的用户可以相互修改吗?

    A: 不可以,见modify_profile权限说明(-c的权限大于-u的权限,或是-c-u相同)。

  • Q: 有49张票要买50张票,这个50张票的订单全部进入候补队列吗?

    A: 是的,订单为购票和候补的最小单位,均只会完全满足

  • Q: 退订第n个订单,序号n是已退订单在内的序号吗?

    A: 是的,相当于query_order输出的第n个订单。

  • Q: exit是真的退出程序还是只在线用户下线?

    A: 退出程序。

  • Q: 有没有火车多次经过一个站?

    A: 没有。

  • Q: 换乘可以是同一辆车换成同一辆车吗?

    A: 不可以。

  • Q: query_transfer最优解是指-ptime时时间最优解,-pcost时空间最优解吗?

    A: 是的。

  • Q: 查票的时候没有余票情况也要显示该车次吗?

    A: 是的。

  • Q: 车次在release之前可以查询,在release后可以查询、购票吗?

    A: 车次在release之前可以:查询车次,删除车次(没有查询车票);在release之后可以进行删除车次外的任何操作。

  • Q: 在后端的接口中,允许多个用户登录到系统,那么在前端的网页实现中,是否也要实现多个用户同时登录的功能?还是按照正常的账户惯例,一次只能登录一个用户?

    A: 每一个前端客户端都可以登录一个用户,可以有很多前端同时打开,且它们的登录状态可以共存(这也就是为什么当前用户列表是一个集合而不是某个特定的用户了)。 对后端来讲,不同前端发送命令的-c或-u不同,因此对于一个前端只需要判断当前登录的是哪【一个】用户,并且把这个信息作为指令的操作者告诉后端就好了。

  • Q: 非第一个用户的时候要求-c已登录吗?

    A: 需要,新用户的权限应当【低于】当前用户而非【不高于】。

  • Q: 车次经过车站数有限制吗?

    A: 有,至少经过两个站(始发站和终点站),最多经过100个站。

  • Q: 车次运行时间长度有限制吗?

    A: 有,不超过3天。

  • Q: add_train什么情况下会失败吗?

    A: 在train id冲突的时候。

  • Q: 添加用户时id冲突会失败吗?

    A: 会。

  • Q: 保证所有输入(指所有操作的输入)的日期都为2021年6月至8月的某一天吗?

    A: 保证时间合法且在2021年范围内。

  • Q: query_order在-u没有登陆时应该会操作失败吧?

    A: 会。

  • Q: 命令失败主要是哪些形式呢?

    A: 主要是添加时键值冲突,输入不合法(指输入的车站不存在等)或是不符合权限要求。

  • Q: query_ticket和query_order失败时返回值?

    A: -1

  • Q: 评测提交方式?

    A: 通过git提交,在仓库根目录提供Makefile或者cmakelist即可。

  • Q: modify_profile中,被修改至的权限有限制吗?

    A: 有的,需要低于-c的权限。

  • Q: buy_ticket的时间是指?

    A: 和查询一致,是指乘车的时间而非列车从始发站发车的时间。

  • Q: 对于只有两站的车次,-o参数是什么?

    A: -o参数内容为一个下划线(-o _

  • Q: query_ticket会失败吗?

    A: 不会。车站不存在不视为查询失败,而是认为没有符合条件的车次,因此返回0

  • Q: 查票操作,时间、票价排序的时候相同的怎么办?

    A: 以train ID字典序为第二排序关键字。如果query_transfer有并列结果,尽量选择在train 1(经过始发站的列车)上乘坐时间更少的方案。

  • Q: 如果购票数量大于列车最大座位数还可以候补吗?

    A: 不可以。