完成大作业服务端代码,新建管理端,管理端不可用
This commit is contained in:
parent
ad767a806b
commit
cfbaf585a7
208
Project/Manager/data_source/airports/airports.csv
Normal file
208
Project/Manager/data_source/airports/airports.csv
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
ID,Name,City
|
||||||
|
NAY,北京南苑机场,北京
|
||||||
|
PEK,北京首都国际机场,北京
|
||||||
|
TSN,天津滨海国际机场,天津
|
||||||
|
ZQZ,张家口宁远机场,张家口
|
||||||
|
HDG,邯郸机场,邯郸
|
||||||
|
SHP,秦皇岛山海关机场,秦皇岛
|
||||||
|
TVS,唐山三女河机场,唐山
|
||||||
|
XNT,邢台褡裢机场,邢台
|
||||||
|
SJW,石家庄正定国际机场,石家庄
|
||||||
|
TYN,太原武宿国际机场,太原
|
||||||
|
LLV,吕梁机场,吕梁
|
||||||
|
CIH,长治王村机场,长治
|
||||||
|
DAT,大同云冈机场,大同
|
||||||
|
YCU,运城机场,运城
|
||||||
|
AXF,阿拉善左旗巴彦浩特机场,阿拉善左旗
|
||||||
|
RHT,阿拉善右旗巴丹吉林机场,阿拉善右旗
|
||||||
|
BAV,包头二里半机场,包头
|
||||||
|
CIF,赤峰玉龙机场,赤峰
|
||||||
|
DSN,鄂尔多斯伊金霍洛机场,鄂尔多斯
|
||||||
|
EJN,额济纳旗桃来机场,额济纳旗
|
||||||
|
ERL,二连浩特赛乌苏机场,二连浩特
|
||||||
|
NZH,满洲里西郊机场,满洲里
|
||||||
|
WUA,乌海机场,乌海
|
||||||
|
YIE,阿尔山伊尔施机场,阿尔山
|
||||||
|
RLK,巴彦淖尔天吉泰机场,巴彦淖尔
|
||||||
|
HET,呼和浩特白塔国际机场,呼和浩特
|
||||||
|
HLD,呼伦贝尔海拉尔机场,呼伦贝尔
|
||||||
|
TGO,通辽机场,通辽
|
||||||
|
HLH,乌兰浩特机场,乌兰浩特
|
||||||
|
XIL,锡林浩特机场,锡林浩特
|
||||||
|
AOG,鞍山腾鳌机场,鞍山
|
||||||
|
CNI,长海大长山岛机场,长海
|
||||||
|
CHG,朝阳机场,朝阳
|
||||||
|
DLC,大连周水子国际机场,大连
|
||||||
|
DDG,丹东浪头机场,丹东
|
||||||
|
JNZ,锦州小岭子机场,锦州
|
||||||
|
SHE,沈阳桃仙国际机场,沈阳
|
||||||
|
TNH,通化三源浦机场,通化
|
||||||
|
NBS,长白山机场,白山
|
||||||
|
YNJ,延吉朝阳川机场,延边
|
||||||
|
CGQ,长春龙嘉国际机场,长春
|
||||||
|
JXA,鸡西兴凯湖机场,鸡西
|
||||||
|
JMU,佳木斯东郊机场,佳木斯
|
||||||
|
MDG,牡丹江海浪机场,牡丹江
|
||||||
|
LDS,伊春林都机场,伊春
|
||||||
|
HEK,黑河机场,黑河
|
||||||
|
DQA,大庆萨尔图机场,大庆
|
||||||
|
JGD,加格达奇机场,大兴安岭
|
||||||
|
HRB,哈尔滨太平国际机场,哈尔滨
|
||||||
|
OHE,漠河古莲机场,漠河
|
||||||
|
NDG,齐齐哈尔三家子机场,齐齐哈尔
|
||||||
|
SHA,上海虹桥国际机场,上海
|
||||||
|
PVG,上海浦东国际机场,上海
|
||||||
|
HIA,淮安涟水机场,淮安
|
||||||
|
NTG,南通兴东机场,南通
|
||||||
|
YNZ,盐城南洋机场,盐城
|
||||||
|
YTY,扬州泰州机场,扬州
|
||||||
|
NKG,南京禄口国际机场,南京
|
||||||
|
XUZ,徐州观音机场,徐州
|
||||||
|
LYG,连云港白塔埠机场,连云港
|
||||||
|
CZX,常州奔牛机场,常州
|
||||||
|
WUX,苏南硕放国际机场,无锡
|
||||||
|
WNZ,温州龙湾国际机场,温州
|
||||||
|
JUZ,衢州机场,衢州
|
||||||
|
HYN,台州路桥机场,台州
|
||||||
|
HSN,舟山普陀山机场,舟山
|
||||||
|
HGH,杭州萧山国际机场,杭州
|
||||||
|
YIW,义乌机场,金华
|
||||||
|
NGB,宁波栎社国际机场,宁波
|
||||||
|
AQG,安庆天柱山机场,安庆
|
||||||
|
JUH,池州九华山机场,池州
|
||||||
|
TXN,黄山屯溪机场,黄山
|
||||||
|
HFE,合肥新桥国际机场,合肥
|
||||||
|
FUG,阜阳西关机场,阜阳
|
||||||
|
FOC,福州长乐国际机场,福州
|
||||||
|
SQJ,三明沙县机场,沙县
|
||||||
|
LCX,连城冠豸山机场,龙岩
|
||||||
|
JJN,泉州晋江机场,泉州
|
||||||
|
WUS,武夷山机场,南平
|
||||||
|
XMN,厦门高崎国际机场,厦门
|
||||||
|
KOW,赣州黄金机场,赣州
|
||||||
|
JGS,井冈山机场,吉安
|
||||||
|
YIC,宜春明月山机场,宜春
|
||||||
|
KHN,南昌昌北国际机场,南昌
|
||||||
|
JDZ,景德镇罗家机场,景德镇
|
||||||
|
JIU,九江庐山机场,九江
|
||||||
|
JNG,济宁曲阜机场,济宁
|
||||||
|
WEF,潍坊机场,潍坊
|
||||||
|
TAO,青岛流亭国际机场,青岛
|
||||||
|
TNA,济南遥墙国际机场,济南
|
||||||
|
LYI,临沂沭埠岭机场,临沂
|
||||||
|
YNT,烟台莱山国际机场,烟台
|
||||||
|
DOY,东营胜利机场,东营
|
||||||
|
WEH,威海国际机场,威海
|
||||||
|
LYA,洛阳北郊机场,洛阳
|
||||||
|
CGO,郑州新郑国际机场,郑州
|
||||||
|
NNY,南阳姜营机场,南阳
|
||||||
|
WUH,武汉天河国际机场,武汉
|
||||||
|
YIH,宜昌三峡机场,宜昌
|
||||||
|
ENH,恩施许家坪机场,恩施
|
||||||
|
XFN,襄阳刘集机场,襄阳
|
||||||
|
CGD,常德桃花源机场,常德
|
||||||
|
HJJ,怀化芷江机场,怀化
|
||||||
|
DYG,张家界荷花国际机场,张家界
|
||||||
|
CSX,长沙黄花国际机场,长沙
|
||||||
|
LLF,永州零陵机场,永州
|
||||||
|
DGM,东莞机场,东莞
|
||||||
|
SZX,深圳宝安国际机场,深圳
|
||||||
|
HUZ,惠州机场,惠州
|
||||||
|
MXZ,梅县长岗岌机场,梅州
|
||||||
|
SWA,揭阳潮汕机场,揭阳
|
||||||
|
ZHA,湛江机场,湛江
|
||||||
|
FUO,佛山机场,佛山
|
||||||
|
HSC,韶关桂头机场,韶关
|
||||||
|
ZUH,珠海金湾机场,珠海
|
||||||
|
CAN,广州白云国际机场,广州
|
||||||
|
LZH,柳州白莲机场,柳州
|
||||||
|
AEB,百色巴马机场,百色
|
||||||
|
BHY,北海福成机场,北海
|
||||||
|
NNG,南宁吴圩国际机场,南宁
|
||||||
|
WUZ,梧州长洲岛机场,梧州
|
||||||
|
KWL,桂林两江国际机场,桂林
|
||||||
|
HAK,海口美兰国际机场,海口
|
||||||
|
SYX,三亚凤凰国际机场,三亚
|
||||||
|
CKG,重庆江北国际机场,重庆
|
||||||
|
WXN,万州五桥机场,万州
|
||||||
|
JIQ,黔江武陵山机场,黔江
|
||||||
|
DAX,达州河市机场,达州
|
||||||
|
DCY,稻城亚丁机场,稻城
|
||||||
|
JZH,九寨黄龙机场,九寨沟
|
||||||
|
NAO,南充高坪机场,南充
|
||||||
|
PZI,攀枝花保安营机场,攀枝花
|
||||||
|
CTU,成都双流国际机场,成都
|
||||||
|
SUN,遂宁机场,遂宁
|
||||||
|
GYS,广元盘龙机场,广元
|
||||||
|
KGT,甘孜康定机场,康定
|
||||||
|
MIG,绵阳南郊机场,绵阳
|
||||||
|
LZO,泸州蓝田机场,泸州
|
||||||
|
XIC,西昌青山机场,西昌
|
||||||
|
YBP,宜宾菜坝机场,宜宾
|
||||||
|
AVA,安顺黄果树机场,安顺
|
||||||
|
BFJ,毕节飞雄机场,毕节
|
||||||
|
KWE,贵阳龙洞堡国际机场,贵阳
|
||||||
|
ACX,兴义机场,黔西南
|
||||||
|
HZH,黎平机场,黎平
|
||||||
|
KJH,凯里黄平机场,黔东南
|
||||||
|
LLB,荔波机场,黔南
|
||||||
|
TEN,铜仁凤凰机场,铜仁
|
||||||
|
ZYI,遵义新舟机场,遵义
|
||||||
|
SYM,普洱思茅机场,普洱
|
||||||
|
TCZ,腾冲驼峰机场,腾冲
|
||||||
|
LNJ,临沧机场,临沧
|
||||||
|
JHG,西双版纳嘎洒国际机场,西双版纳
|
||||||
|
LJG,丽江三义机场,丽江
|
||||||
|
ZAT,昭通机场,昭通
|
||||||
|
BSD,保山云瑞机场,隆阳
|
||||||
|
DLU,大理机场,大理
|
||||||
|
LUM,德宏芒市机场,德宏
|
||||||
|
DIG,迪庆香格里拉机场,迪庆
|
||||||
|
KMG,昆明长水国际机场,昆明
|
||||||
|
WNH,文山普者黑机场,文山
|
||||||
|
NGQ,阿里昆莎机场,阿里
|
||||||
|
BPX,昌都邦达机场,昌都
|
||||||
|
RKZ,日喀则和平机场,日喀则
|
||||||
|
LXA,拉萨贡嘎机场,拉萨
|
||||||
|
LZY,林芝米林机场,林芝
|
||||||
|
XIY,西安咸阳国际机场,西安
|
||||||
|
UYN,榆林榆阳机场,榆林
|
||||||
|
HZG,汉中西关机场,汉中
|
||||||
|
AKA,安康五里铺机场,安康
|
||||||
|
ENY,延安二十里堡机场,延安
|
||||||
|
GXH,甘南夏河机场,甘南
|
||||||
|
JIC,金昌金川机场,金昌
|
||||||
|
YZY,张掖甘州机场,张掖
|
||||||
|
DNH,敦煌机场,敦煌
|
||||||
|
JGN,嘉峪关机场,嘉峪关
|
||||||
|
LHW,兰州中川机场,兰州
|
||||||
|
IQN,庆阳机场,庆阳
|
||||||
|
THQ,天水麦积山机场,天水
|
||||||
|
XNN,西宁曹家堡机场,西宁
|
||||||
|
GOQ,格尔木机场,格尔木
|
||||||
|
YUS,玉树巴塘机场,玉树
|
||||||
|
GYU,固原六盘山机场,固原
|
||||||
|
INC,银川河东国际机场,银川
|
||||||
|
ZHY,中卫沙坡头机场,中卫
|
||||||
|
AKU,阿克苏机场,阿克苏
|
||||||
|
AAT,阿勒泰机场,阿勒泰
|
||||||
|
FYN,富蕴机场,富蕴
|
||||||
|
HMI,哈密机场,哈密
|
||||||
|
HTN,和田机场,和田
|
||||||
|
KRL,库尔勒机场,库尔勒
|
||||||
|
IQM,且末机场,且末
|
||||||
|
TLQ,吐鲁番交河机场,吐鲁番
|
||||||
|
URC,乌鲁木齐地窝堡国际机场,乌鲁木齐
|
||||||
|
BPL,博乐阿拉山口机场,博尔塔拉
|
||||||
|
KJI,布尔津喀纳斯机场,布尔津
|
||||||
|
KHG,喀什机场,喀什
|
||||||
|
KRY,克拉玛依机场,克拉玛依
|
||||||
|
KCA,库车龟兹机场,库车
|
||||||
|
TCG,塔城机场,塔城
|
||||||
|
YIN,伊宁机场,伊宁
|
||||||
|
NLT,新源那拉提机场,新源
|
||||||
|
HKG,香港国际机场,香港
|
||||||
|
MFM,澳门国际机场,澳门
|
||||||
|
TSA,台北松山机场,台北
|
||||||
|
TPE,桃园国际机场,桃园
|
||||||
|
KHH,高雄国际机场,高雄
|
|
208
Project/Manager/data_source/airports/airports.sql
Normal file
208
Project/Manager/data_source/airports/airports.sql
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
INSERT INTO Airports (`ID`, `Name`, City) VALUES
|
||||||
|
('NAY', '北京南苑机场', '北京'),
|
||||||
|
('PEK', '北京首都国际机场', '北京'),
|
||||||
|
('TSN', '天津滨海国际机场', '天津'),
|
||||||
|
('ZQZ', '张家口宁远机场', '张家口'),
|
||||||
|
('HDG', '邯郸机场', '邯郸'),
|
||||||
|
('SHP', '秦皇岛山海关机场', '秦皇岛'),
|
||||||
|
('TVS', '唐山三女河机场', '唐山'),
|
||||||
|
('XNT', '邢台褡裢机场', '邢台'),
|
||||||
|
('SJW', '石家庄正定国际机场', '石家庄'),
|
||||||
|
('TYN', '太原武宿国际机场', '太原'),
|
||||||
|
('LLV', '吕梁机场', '吕梁'),
|
||||||
|
('CIH', '长治王村机场', '长治'),
|
||||||
|
('DAT', '大同云冈机场', '大同'),
|
||||||
|
('YCU', '运城机场', '运城'),
|
||||||
|
('AXF', '阿拉善左旗巴彦浩特机场', '阿拉善左旗'),
|
||||||
|
('RHT', '阿拉善右旗巴丹吉林机场', '阿拉善右旗'),
|
||||||
|
('BAV', '包头二里半机场', '包头'),
|
||||||
|
('CIF', '赤峰玉龙机场', '赤峰'),
|
||||||
|
('DSN', '鄂尔多斯伊金霍洛机场', '鄂尔多斯'),
|
||||||
|
('EJN', '额济纳旗桃来机场', '额济纳旗'),
|
||||||
|
('ERL', '二连浩特赛乌苏机场', '二连浩特'),
|
||||||
|
('NZH', '满洲里西郊机场', '满洲里'),
|
||||||
|
('WUA', '乌海机场', '乌海'),
|
||||||
|
('YIE', '阿尔山伊尔施机场', '阿尔山'),
|
||||||
|
('RLK', '巴彦淖尔天吉泰机场', '巴彦淖尔'),
|
||||||
|
('HET', '呼和浩特白塔国际机场', '呼和浩特'),
|
||||||
|
('HLD', '呼伦贝尔海拉尔机场', '呼伦贝尔'),
|
||||||
|
('TGO', '通辽机场', '通辽'),
|
||||||
|
('HLH', '乌兰浩特机场', '乌兰浩特'),
|
||||||
|
('XIL', '锡林浩特机场', '锡林浩特'),
|
||||||
|
('AOG', '鞍山腾鳌机场', '鞍山'),
|
||||||
|
('CNI', '长海大长山岛机场', '长海'),
|
||||||
|
('CHG', '朝阳机场', '朝阳'),
|
||||||
|
('DLC', '大连周水子国际机场', '大连'),
|
||||||
|
('DDG', '丹东浪头机场', '丹东'),
|
||||||
|
('JNZ', '锦州小岭子机场', '锦州'),
|
||||||
|
('SHE', '沈阳桃仙国际机场', '沈阳'),
|
||||||
|
('TNH', '通化三源浦机场', '通化'),
|
||||||
|
('NBS', '长白山机场', '白山'),
|
||||||
|
('YNJ', '延吉朝阳川机场', '延边'),
|
||||||
|
('CGQ', '长春龙嘉国际机场', '长春'),
|
||||||
|
('JXA', '鸡西兴凯湖机场', '鸡西'),
|
||||||
|
('JMU', '佳木斯东郊机场', '佳木斯'),
|
||||||
|
('MDG', '牡丹江海浪机场', '牡丹江'),
|
||||||
|
('LDS', '伊春林都机场', '伊春'),
|
||||||
|
('HEK', '黑河机场', '黑河'),
|
||||||
|
('DQA', '大庆萨尔图机场', '大庆'),
|
||||||
|
('JGD', '加格达奇机场', '大兴安岭'),
|
||||||
|
('HRB', '哈尔滨太平国际机场', '哈尔滨'),
|
||||||
|
('OHE', '漠河古莲机场', '漠河'),
|
||||||
|
('NDG', '齐齐哈尔三家子机场', '齐齐哈尔'),
|
||||||
|
('SHA', '上海虹桥国际机场', '上海'),
|
||||||
|
('PVG', '上海浦东国际机场', '上海'),
|
||||||
|
('HIA', '淮安涟水机场', '淮安'),
|
||||||
|
('NTG', '南通兴东机场', '南通'),
|
||||||
|
('YNZ', '盐城南洋机场', '盐城'),
|
||||||
|
('YTY', '扬州泰州机场', '扬州'),
|
||||||
|
('NKG', '南京禄口国际机场', '南京'),
|
||||||
|
('XUZ', '徐州观音机场', '徐州'),
|
||||||
|
('LYG', '连云港白塔埠机场', '连云港'),
|
||||||
|
('CZX', '常州奔牛机场', '常州'),
|
||||||
|
('WUX', '苏南硕放国际机场', '无锡'),
|
||||||
|
('WNZ', '温州龙湾国际机场', '温州'),
|
||||||
|
('JUZ', '衢州机场', '衢州'),
|
||||||
|
('HYN', '台州路桥机场', '台州'),
|
||||||
|
('HSN', '舟山普陀山机场', '舟山'),
|
||||||
|
('HGH', '杭州萧山国际机场', '杭州'),
|
||||||
|
('YIW', '义乌机场', '金华'),
|
||||||
|
('NGB', '宁波栎社国际机场', '宁波'),
|
||||||
|
('AQG', '安庆天柱山机场', '安庆'),
|
||||||
|
('JUH', '池州九华山机场', '池州'),
|
||||||
|
('TXN', '黄山屯溪机场', '黄山'),
|
||||||
|
('HFE', '合肥新桥国际机场', '合肥'),
|
||||||
|
('FUG', '阜阳西关机场', '阜阳'),
|
||||||
|
('FOC', '福州长乐国际机场', '福州'),
|
||||||
|
('SQJ', '三明沙县机场', '沙县'),
|
||||||
|
('LCX', '连城冠豸山机场', '龙岩'),
|
||||||
|
('JJN', '泉州晋江机场', '泉州'),
|
||||||
|
('WUS', '武夷山机场', '南平'),
|
||||||
|
('XMN', '厦门高崎国际机场', '厦门'),
|
||||||
|
('KOW', '赣州黄金机场', '赣州'),
|
||||||
|
('JGS', '井冈山机场', '吉安'),
|
||||||
|
('YIC', '宜春明月山机场', '宜春'),
|
||||||
|
('KHN', '南昌昌北国际机场', '南昌'),
|
||||||
|
('JDZ', '景德镇罗家机场', '景德镇'),
|
||||||
|
('JIU', '九江庐山机场', '九江'),
|
||||||
|
('JNG', '济宁曲阜机场', '济宁'),
|
||||||
|
('WEF', '潍坊机场', '潍坊'),
|
||||||
|
('TAO', '青岛流亭国际机场', '青岛'),
|
||||||
|
('TNA', '济南遥墙国际机场', '济南'),
|
||||||
|
('LYI', '临沂沭埠岭机场', '临沂'),
|
||||||
|
('YNT', '烟台莱山国际机场', '烟台'),
|
||||||
|
('DOY', '东营胜利机场', '东营'),
|
||||||
|
('WEH', '威海国际机场', '威海'),
|
||||||
|
('LYA', '洛阳北郊机场', '洛阳'),
|
||||||
|
('CGO', '郑州新郑国际机场', '郑州'),
|
||||||
|
('NNY', '南阳姜营机场', '南阳'),
|
||||||
|
('WUH', '武汉天河国际机场', '武汉'),
|
||||||
|
('YIH', '宜昌三峡机场', '宜昌'),
|
||||||
|
('ENH', '恩施许家坪机场', '恩施'),
|
||||||
|
('XFN', '襄阳刘集机场', '襄阳'),
|
||||||
|
('CGD', '常德桃花源机场', '常德'),
|
||||||
|
('HJJ', '怀化芷江机场', '怀化'),
|
||||||
|
('DYG', '张家界荷花国际机场', '张家界'),
|
||||||
|
('CSX', '长沙黄花国际机场', '长沙'),
|
||||||
|
('LLF', '永州零陵机场', '永州'),
|
||||||
|
('DGM', '东莞机场', '东莞'),
|
||||||
|
('SZX', '深圳宝安国际机场', '深圳'),
|
||||||
|
('HUZ', '惠州机场', '惠州'),
|
||||||
|
('MXZ', '梅县长岗岌机场', '梅州'),
|
||||||
|
('SWA', '揭阳潮汕机场', '揭阳'),
|
||||||
|
('ZHA', '湛江机场', '湛江'),
|
||||||
|
('FUO', '佛山机场', '佛山'),
|
||||||
|
('HSC', '韶关桂头机场', '韶关'),
|
||||||
|
('ZUH', '珠海金湾机场', '珠海'),
|
||||||
|
('CAN', '广州白云国际机场', '广州'),
|
||||||
|
('LZH', '柳州白莲机场', '柳州'),
|
||||||
|
('AEB', '百色巴马机场', '百色'),
|
||||||
|
('BHY', '北海福成机场', '北海'),
|
||||||
|
('NNG', '南宁吴圩国际机场', '南宁'),
|
||||||
|
('WUZ', '梧州长洲岛机场', '梧州'),
|
||||||
|
('KWL', '桂林两江国际机场', '桂林'),
|
||||||
|
('HAK', '海口美兰国际机场', '海口'),
|
||||||
|
('SYX', '三亚凤凰国际机场', '三亚'),
|
||||||
|
('CKG', '重庆江北国际机场', '重庆'),
|
||||||
|
('WXN', '万州五桥机场', '万州'),
|
||||||
|
('JIQ', '黔江武陵山机场', '黔江'),
|
||||||
|
('DAX', '达州河市机场', '达州'),
|
||||||
|
('DCY', '稻城亚丁机场', '稻城'),
|
||||||
|
('JZH', '九寨黄龙机场', '九寨沟'),
|
||||||
|
('NAO', '南充高坪机场', '南充'),
|
||||||
|
('PZI', '攀枝花保安营机场', '攀枝花'),
|
||||||
|
('CTU', '成都双流国际机场', '成都'),
|
||||||
|
('SUN', '遂宁机场', '遂宁'),
|
||||||
|
('GYS', '广元盘龙机场', '广元'),
|
||||||
|
('KGT', '甘孜康定机场', '康定'),
|
||||||
|
('MIG', '绵阳南郊机场', '绵阳'),
|
||||||
|
('LZO', '泸州蓝田机场', '泸州'),
|
||||||
|
('XIC', '西昌青山机场', '西昌'),
|
||||||
|
('YBP', '宜宾菜坝机场', '宜宾'),
|
||||||
|
('AVA', '安顺黄果树机场', '安顺'),
|
||||||
|
('BFJ', '毕节飞雄机场', '毕节'),
|
||||||
|
('KWE', '贵阳龙洞堡国际机场', '贵阳'),
|
||||||
|
('ACX', '兴义机场', '黔西南'),
|
||||||
|
('HZH', '黎平机场', '黎平'),
|
||||||
|
('KJH', '凯里黄平机场', '黔东南'),
|
||||||
|
('LLB', '荔波机场', '黔南'),
|
||||||
|
('TEN', '铜仁凤凰机场', '铜仁'),
|
||||||
|
('ZYI', '遵义新舟机场', '遵义'),
|
||||||
|
('SYM', '普洱思茅机场', '普洱'),
|
||||||
|
('TCZ', '腾冲驼峰机场', '腾冲'),
|
||||||
|
('LNJ', '临沧机场', '临沧'),
|
||||||
|
('JHG', '西双版纳嘎洒国际机场', '西双版纳'),
|
||||||
|
('LJG', '丽江三义机场', '丽江'),
|
||||||
|
('ZAT', '昭通机场', '昭通'),
|
||||||
|
('BSD', '保山云瑞机场', '隆阳'),
|
||||||
|
('DLU', '大理机场', '大理'),
|
||||||
|
('LUM', '德宏芒市机场', '德宏'),
|
||||||
|
('DIG', '迪庆香格里拉机场', '迪庆'),
|
||||||
|
('KMG', '昆明长水国际机场', '昆明'),
|
||||||
|
('WNH', '文山普者黑机场', '文山'),
|
||||||
|
('NGQ', '阿里昆莎机场', '阿里'),
|
||||||
|
('BPX', '昌都邦达机场', '昌都'),
|
||||||
|
('RKZ', '日喀则和平机场', '日喀则'),
|
||||||
|
('LXA', '拉萨贡嘎机场', '拉萨'),
|
||||||
|
('LZY', '林芝米林机场', '林芝'),
|
||||||
|
('XIY', '西安咸阳国际机场', '西安'),
|
||||||
|
('UYN', '榆林榆阳机场', '榆林'),
|
||||||
|
('HZG', '汉中西关机场', '汉中'),
|
||||||
|
('AKA', '安康五里铺机场', '安康'),
|
||||||
|
('ENY', '延安二十里堡机场', '延安'),
|
||||||
|
('GXH', '甘南夏河机场', '甘南'),
|
||||||
|
('JIC', '金昌金川机场', '金昌'),
|
||||||
|
('YZY', '张掖甘州机场', '张掖'),
|
||||||
|
('DNH', '敦煌机场', '敦煌'),
|
||||||
|
('JGN', '嘉峪关机场', '嘉峪关'),
|
||||||
|
('LHW', '兰州中川机场', '兰州'),
|
||||||
|
('IQN', '庆阳机场', '庆阳'),
|
||||||
|
('THQ', '天水麦积山机场', '天水'),
|
||||||
|
('XNN', '西宁曹家堡机场', '西宁'),
|
||||||
|
('GOQ', '格尔木机场', '格尔木'),
|
||||||
|
('YUS', '玉树巴塘机场', '玉树'),
|
||||||
|
('GYU', '固原六盘山机场', '固原'),
|
||||||
|
('INC', '银川河东国际机场', '银川'),
|
||||||
|
('ZHY', '中卫沙坡头机场', '中卫'),
|
||||||
|
('AKU', '阿克苏机场', '阿克苏'),
|
||||||
|
('AAT', '阿勒泰机场', '阿勒泰'),
|
||||||
|
('FYN', '富蕴机场', '富蕴'),
|
||||||
|
('HMI', '哈密机场', '哈密'),
|
||||||
|
('HTN', '和田机场', '和田'),
|
||||||
|
('KRL', '库尔勒机场', '库尔勒'),
|
||||||
|
('IQM', '且末机场', '且末'),
|
||||||
|
('TLQ', '吐鲁番交河机场', '吐鲁番'),
|
||||||
|
('URC', '乌鲁木齐地窝堡国际机场', '乌鲁木齐'),
|
||||||
|
('BPL', '博乐阿拉山口机场', '博尔塔拉'),
|
||||||
|
('KJI', '布尔津喀纳斯机场', '布尔津'),
|
||||||
|
('KHG', '喀什机场', '喀什'),
|
||||||
|
('KRY', '克拉玛依机场', '克拉玛依'),
|
||||||
|
('KCA', '库车龟兹机场', '库车'),
|
||||||
|
('TCG', '塔城机场', '塔城'),
|
||||||
|
('YIN', '伊宁机场', '伊宁'),
|
||||||
|
('NLT', '新源那拉提机场', '新源'),
|
||||||
|
('HKG', '香港国际机场', '香港'),
|
||||||
|
('MFM', '澳门国际机场', '澳门'),
|
||||||
|
('TSA', '台北松山机场', '台北'),
|
||||||
|
('TPE', '桃园国际机场', '桃园'),
|
||||||
|
('KHH', '高雄国际机场', '高雄');
|
32
Project/Manager/data_source/airports/make_data.py
Normal file
32
Project/Manager/data_source/airports/make_data.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
# 读取并处理数据
|
||||||
|
with open("./raw.txt", "r") as f:
|
||||||
|
data_list = f.readlines()
|
||||||
|
|
||||||
|
data_list = [data.strip() for data in data_list]
|
||||||
|
data = []
|
||||||
|
for line in data_list:
|
||||||
|
l = line.split('\t')
|
||||||
|
if len(l) < 2:
|
||||||
|
continue
|
||||||
|
data.append((l[1], l[3], l[0])) # Code, Airport, City
|
||||||
|
|
||||||
|
# 将数据转换为DataFrame
|
||||||
|
columns = ['ID', 'Name', 'City']
|
||||||
|
df = pd.DataFrame(data, columns=columns)
|
||||||
|
|
||||||
|
# 保存为CSV文件
|
||||||
|
df.to_csv('airports.csv', index=False)
|
||||||
|
|
||||||
|
# 生成SQL插入语句
|
||||||
|
insert_statements = 'INSERT INTO Airports (`ID`, `Name`, City) VALUES\n'
|
||||||
|
insert_statements += ',\n'.join([
|
||||||
|
f"('{row.ID}', '{row.Name}', '{row.City}')"
|
||||||
|
for row in df.itertuples(index=False)
|
||||||
|
])
|
||||||
|
insert_statements += ';'
|
||||||
|
|
||||||
|
# 保存SQL插入语句到文件
|
||||||
|
with open('airports.sql', 'w') as f:
|
||||||
|
f.write(insert_statements)
|
241
Project/Manager/data_source/airports/raw.txt
Normal file
241
Project/Manager/data_source/airports/raw.txt
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
北京市
|
||||||
|
北京 NAY ZBNY 北京南苑机场 NANYUAN
|
||||||
|
北京 PEK ZBAA 北京首都国际机场 BEIJING
|
||||||
|
天津市
|
||||||
|
天津 TSN ZBTJ 天津滨海国际机场 TIANJIN
|
||||||
|
河北省
|
||||||
|
张家口 ZQZ ZBZJ 张家口宁远机场 ZHANGJIAKOU
|
||||||
|
邯郸 HDG ZBHD 邯郸机场 HANDAN
|
||||||
|
秦皇岛 SHP ZBSH 秦皇岛山海关机场 QINHUANGDAO
|
||||||
|
唐山 TVS ZBTS 唐山三女河机场 TANGSHAN
|
||||||
|
邢台 XNT ZBXT 邢台褡裢机场 SHAHE
|
||||||
|
石家庄 SJW ZBSJ 石家庄正定国际机场 SHIJIAZHUANG
|
||||||
|
山西省
|
||||||
|
太原 TYN ZBYN 太原武宿国际机场 TAIYUAN
|
||||||
|
吕梁 LLV ZBLL 吕梁机场 LVLIANG
|
||||||
|
长治 CIH ZBCZ 长治王村机场 CHANGZHI
|
||||||
|
大同 DAT ZBDT 大同云冈机场 DATONG
|
||||||
|
运城 YCU ZBYC 运城机场 YUNCHENG
|
||||||
|
内蒙古自治区
|
||||||
|
阿拉善左旗 AXF 阿拉善左旗巴彦浩特机场 BAYANHAOTE
|
||||||
|
阿拉善右旗 RHT 阿拉善右旗巴丹吉林机场 BADANJILIN
|
||||||
|
包头 BAV ZBOW 包头二里半机场 BAOTOU
|
||||||
|
赤峰 CIF ZBCF 赤峰玉龙机场 CHIFENG
|
||||||
|
鄂尔多斯 DSN ZBDS 鄂尔多斯伊金霍洛机场 ORDOS
|
||||||
|
额济纳旗 EJN 额济纳旗桃来机场 ERJINA
|
||||||
|
二连浩特 ERL ZBER 二连浩特赛乌苏机场 ERLIANHOT
|
||||||
|
满洲里 NZH ZBMZ 满洲里西郊机场 MANZHOULI
|
||||||
|
乌海 WUA ZBUH 乌海机场 WUHAI
|
||||||
|
阿尔山 YIE ZBES 阿尔山伊尔施机场 ARXAN
|
||||||
|
巴彦淖尔 RLK ZBYZ 巴彦淖尔天吉泰机场 BAYANNUR
|
||||||
|
呼和浩特 HET ZBHH 呼和浩特白塔国际机场 HOHHOT
|
||||||
|
呼伦贝尔 HLD ZBLA 呼伦贝尔海拉尔机场 HAILAR
|
||||||
|
通辽 TGO ZBTL 通辽机场 TONGLIAO
|
||||||
|
乌兰浩特 HLH ZBUL 乌兰浩特机场 ULANHOT
|
||||||
|
锡林浩特 XIL ZBXH 锡林浩特机场 XILINHOT
|
||||||
|
辽宁省
|
||||||
|
鞍山 AOG ZYAS 鞍山腾鳌机场 ANSHAN
|
||||||
|
长海 CNI ZYCH 长海大长山岛机场 CHANGHAI
|
||||||
|
朝阳 CHG ZYCY 朝阳机场 CHAOYANG
|
||||||
|
大连 DLC ZYTL 大连周水子国际机场 DALIAN
|
||||||
|
丹东 DDG ZYDD 丹东浪头机场 DANDONG
|
||||||
|
锦州 JNZ ZYJZ 锦州小岭子机场 JINZHOU
|
||||||
|
沈阳 SHE ZYTX 沈阳桃仙国际机场 SHENYANG
|
||||||
|
吉林省
|
||||||
|
通化 TNH ZYTN 通化三源浦机场 TONGHUA
|
||||||
|
白山 NBS ZYBS 长白山机场 CHANGBAISHAN
|
||||||
|
延边 YNJ ZYYJ 延吉朝阳川机场 YANJI
|
||||||
|
长春 CGQ ZYCC 长春龙嘉国际机场 CHANGCHUN
|
||||||
|
黑龙江省
|
||||||
|
鸡西 JXA ZYJX 鸡西兴凯湖机场 JIXI
|
||||||
|
佳木斯 JMU ZYJM 佳木斯东郊机场 JIAMUSI
|
||||||
|
牡丹江 MDG ZYMD 牡丹江海浪机场 MUDANJIANG
|
||||||
|
伊春 LDS ZYLD 伊春林都机场 YICHUN
|
||||||
|
黑河 HEK ZYHE 黑河机场 HEIHE
|
||||||
|
大庆 DQA ZYDQ 大庆萨尔图机场 DAQING
|
||||||
|
大兴安岭 JGD ZYJD 加格达奇机场 JIAGEDAQI
|
||||||
|
哈尔滨 HRB ZYHB 哈尔滨太平国际机场 HARBIN
|
||||||
|
漠河 OHE ZYMH 漠河古莲机场 MOHE
|
||||||
|
齐齐哈尔 NDG ZYQQ 齐齐哈尔三家子机场 QIQIHAER
|
||||||
|
上海市
|
||||||
|
上海 SHA ZSSS 上海虹桥国际机场 HONGQIAO
|
||||||
|
上海 PVG ZSPD 上海浦东国际机场 PUDONG
|
||||||
|
江苏省
|
||||||
|
淮安 HIA ZSSH 淮安涟水机场 HUAIAN
|
||||||
|
南通 NTG ZSNT 南通兴东机场 NANTONG
|
||||||
|
盐城 YNZ ZSYN 盐城南洋机场 YANCHENG
|
||||||
|
扬州 YTY ZSYA 扬州泰州机场 YANGZHOU
|
||||||
|
南京 NKG ZSNJ 南京禄口国际机场 NANJING
|
||||||
|
徐州 XUZ ZSXZ 徐州观音机场 XUZHOU
|
||||||
|
连云港 LYG ZSLG 连云港白塔埠机场 LIANYUNGANG
|
||||||
|
常州 CZX ZSCG 常州奔牛机场 CHANGZHOU
|
||||||
|
无锡 WUX ZSWX 苏南硕放国际机场 WUXI
|
||||||
|
浙江省
|
||||||
|
温州 WNZ ZSWZ 温州龙湾国际机场 WENZHOU
|
||||||
|
衢州 JUZ ZSJU 衢州机场 QUZHOU
|
||||||
|
台州 HYN ZSLQ 台州路桥机场 TAIZHOU
|
||||||
|
舟山 HSN ZSZS 舟山普陀山机场 ZHOUSHAN
|
||||||
|
杭州 HGH ZSHC 杭州萧山国际机场 HANGZHOU
|
||||||
|
金华 YIW ZSYW 义乌机场 YIWU
|
||||||
|
宁波 NGB ZSNB 宁波栎社国际机场 NINGBO
|
||||||
|
安徽省
|
||||||
|
安庆 AQG ZSAQ 安庆天柱山机场 ANQING
|
||||||
|
池州 JUH ZSJH 池州九华山机场 CHIZHOU
|
||||||
|
黄山 TXN ZSTX 黄山屯溪机场 HUANGSHAN
|
||||||
|
合肥 HFE ZSOF 合肥新桥国际机场 HEFEI
|
||||||
|
阜阳 FUG ZSFY 阜阳西关机场 FUYANG
|
||||||
|
福建省
|
||||||
|
福州 FOC ZSFZ 福州长乐国际机场 FUZHOU
|
||||||
|
沙县 SQJ 三明沙县机场 SANMING
|
||||||
|
龙岩 LCX ZSLD 连城冠豸山机场 LONGYAN
|
||||||
|
泉州 JJN ZSQZ 泉州晋江机场 QUANZHOU
|
||||||
|
南平 WUS ZSWY 武夷山机场 WUYISHAN
|
||||||
|
厦门 XMN ZSAM 厦门高崎国际机场 XIAMEN
|
||||||
|
江西省
|
||||||
|
赣州 KOW ZSGZ 赣州黄金机场 GANZHOU
|
||||||
|
吉安 JGS ZSGS 井冈山机场 JINGGANGSHAN
|
||||||
|
宜春 YIC ZSYC 宜春明月山机场 YICHUN
|
||||||
|
南昌 KHN ZSCN 南昌昌北国际机场 NANCHANG
|
||||||
|
景德镇 JDZ ZSJD 景德镇罗家机场 JINGDEZHEN
|
||||||
|
九江 JIU ZSJJ 九江庐山机场 JIUJIANG
|
||||||
|
山东省
|
||||||
|
济宁 JNG ZSJG 济宁曲阜机场 JINING
|
||||||
|
潍坊 WEF ZSWF 潍坊机场 WEIFANG
|
||||||
|
青岛 TAO ZSQD 青岛流亭国际机场 QINGDAO
|
||||||
|
济南 TNA ZSJN 济南遥墙国际机场 JINAN
|
||||||
|
临沂 LYI ZSLY 临沂沭埠岭机场 LINYI
|
||||||
|
烟台 YNT ZSYT 烟台莱山国际机场 YANTAI
|
||||||
|
东营 DOY ZSDY 东营胜利机场 DONGYING
|
||||||
|
威海 WEH ZSWH 威海国际机场 WEIHAI
|
||||||
|
河南省
|
||||||
|
洛阳 LYA ZHLY 洛阳北郊机场 LUOYANG
|
||||||
|
郑州 CGO ZHCC 郑州新郑国际机场 ZHENGZHOU
|
||||||
|
南阳 NNY ZHNY 南阳姜营机场 NANYANG
|
||||||
|
湖北省
|
||||||
|
武汉 WUH ZHHH 武汉天河国际机场 WUHAN
|
||||||
|
宜昌 YIH ZHYC 宜昌三峡机场 YICHANG
|
||||||
|
恩施 ENH ZHES 恩施许家坪机场 ENSHI
|
||||||
|
襄阳 XFN ZHXF 襄阳刘集机场 XIANGYANG
|
||||||
|
湖南省
|
||||||
|
常德 CGD ZGCD 常德桃花源机场 CHANGDE
|
||||||
|
怀化 HJJ ZGCJ 怀化芷江机场 HUAIHUA
|
||||||
|
张家界 DYG ZGDY 张家界荷花国际机场 ZHANGJIAJIE
|
||||||
|
长沙 CSX ZGHA 长沙黄花国际机场 CHANGSHA
|
||||||
|
永州 LLF ZGLG 永州零陵机场 YONGZHOU
|
||||||
|
广东省
|
||||||
|
东莞 DGM 东莞机场 DONGGUAN
|
||||||
|
深圳 SZX ZGSZ 深圳宝安国际机场 SHENZHEN
|
||||||
|
惠州 HUZ ZGHZ 惠州机场 HUIZHOU
|
||||||
|
梅州 MXZ ZGMX 梅县长岗岌机场 MEIXIAN
|
||||||
|
揭阳 SWA ZGOW 揭阳潮汕机场 JIEYANG
|
||||||
|
湛江 ZHA ZGZJ 湛江机场 ZHANJIANG
|
||||||
|
佛山 FUO ZGFS 佛山机场 FOSHAN
|
||||||
|
韶关 HSC 韶关桂头机场 SHAOGUAN
|
||||||
|
珠海 ZUH ZGSD 珠海金湾机场 ZHUHAI
|
||||||
|
广州 CAN ZGGG 广州白云国际机场 GUANGZHOU
|
||||||
|
广西壮族自治区
|
||||||
|
柳州 LZH ZGZH 柳州白莲机场 LIUZHOU
|
||||||
|
百色 AEB ZGBS 百色巴马机场 BAISE
|
||||||
|
北海 BHY ZGBH 北海福成机场 BEIHAI
|
||||||
|
南宁 NNG ZGNN 南宁吴圩国际机场 NANNING
|
||||||
|
梧州 WUZ ZGWZ 梧州长洲岛机场 WUZHOU
|
||||||
|
桂林 KWL ZGKL 桂林两江国际机场 GUILIN
|
||||||
|
海南省
|
||||||
|
海口 HAK ZJHK 海口美兰国际机场 HAIKOU
|
||||||
|
三亚 SYX ZJSY 三亚凤凰国际机场 SANYA
|
||||||
|
重庆市
|
||||||
|
重庆 CKG ZUCK 重庆江北国际机场 CHONGQING
|
||||||
|
万州 WXN ZUWX 万州五桥机场 WANZHOU
|
||||||
|
黔江 JIQ ZUQJ 黔江武陵山机场 ZHOUBAI
|
||||||
|
四川省
|
||||||
|
达州 DAX ZUDX 达州河市机场 DAZHOU
|
||||||
|
稻城 DCY ZUDC 稻城亚丁机场 DAOCHENG
|
||||||
|
九寨沟 JZH ZUJZ 九寨黄龙机场 JIUZHAIGOU
|
||||||
|
南充 NAO ZUNC 南充高坪机场 NANCHONG
|
||||||
|
攀枝花 PZI ZUZI 攀枝花保安营机场 PANZHIHUA
|
||||||
|
成都 CTU ZUUU 成都双流国际机场 CHENGDU
|
||||||
|
遂宁 SUN ZNSU 遂宁机场 SUINING
|
||||||
|
广元 GYS ZUGU 广元盘龙机场 GUANGYUAN
|
||||||
|
康定 KGT ZUKD 甘孜康定机场 KANGDING
|
||||||
|
绵阳 MIG ZUMY 绵阳南郊机场 MIANYANG
|
||||||
|
泸州 LZO ZULZ 泸州蓝田机场 LUZHOU
|
||||||
|
西昌 XIC ZUXC 西昌青山机场 XICHANG
|
||||||
|
宜宾 YBP ZUYB 宜宾菜坝机场 YIBIN
|
||||||
|
贵州省
|
||||||
|
安顺 AVA ZUAS 安顺黄果树机场 ANSHUN
|
||||||
|
毕节 BFJ ZUBJ 毕节飞雄机场 BIJIE
|
||||||
|
贵阳 KWE ZUGY 贵阳龙洞堡国际机场 GUIYANG
|
||||||
|
黔西南 ACX ZUYI 兴义机场 XINGYI
|
||||||
|
黎平 HZH ZUNP 黎平机场 LIPING
|
||||||
|
黔东南 KJH ZUKJ 凯里黄平机场 KAILI
|
||||||
|
黔南 LLB ZULB 荔波机场 LIBO
|
||||||
|
铜仁 TEN ZUTR 铜仁凤凰机场 TONGREN
|
||||||
|
遵义 ZYI ZUZY 遵义新舟机场 ZUNYI
|
||||||
|
云南省
|
||||||
|
普洱 SYM ZPSM 普洱思茅机场 PUER
|
||||||
|
腾冲 TCZ ZUTC 腾冲驼峰机场 TENGCHONG
|
||||||
|
临沧 LNJ ZPLC 临沧机场 LINCANG
|
||||||
|
西双版纳 JHG ZPJH 西双版纳嘎洒国际机场 JINGHONG
|
||||||
|
丽江 LJG ZPLJ 丽江三义机场 LIJIANG
|
||||||
|
昭通 ZAT ZPZT 昭通机场 ZHAOTONG
|
||||||
|
隆阳 BSD ZPBS 保山云瑞机场 BAOSHAN
|
||||||
|
大理 DLU ZPDL 大理机场 DALIXIAGUAN
|
||||||
|
德宏 LUM ZPMS 德宏芒市机场 MANGSHI
|
||||||
|
迪庆 DIG ZPDQ 迪庆香格里拉机场 DIQING
|
||||||
|
昆明 KMG ZPPP 昆明长水国际机场 KUNMING
|
||||||
|
文山 WNH ZPWS 文山普者黑机场 WENSHAN
|
||||||
|
西藏自治区
|
||||||
|
阿里 NGQ ZUAL 阿里昆莎机场 SHIQUANHE
|
||||||
|
昌都 BPX ZUBD 昌都邦达机场 CHAMDO
|
||||||
|
日喀则 RKZ ZURK 日喀则和平机场 RIKAZE
|
||||||
|
拉萨 LXA ZULS 拉萨贡嘎机场 LHASA
|
||||||
|
林芝 LZY ZUNZ 林芝米林机场 NYINGCHI
|
||||||
|
陕西省
|
||||||
|
西安 XIY ZLXY 西安咸阳国际机场 XIAN
|
||||||
|
榆林 UYN ZLYL 榆林榆阳机场 YULIN
|
||||||
|
汉中 HZG ZLHZ 汉中西关机场 HANZHONG
|
||||||
|
安康 AKA ZLAK 安康五里铺机场 ANKANG
|
||||||
|
延安 ENY ZLYA 延安二十里堡机场 YANAN
|
||||||
|
甘肃省
|
||||||
|
甘南 GXH ZLXH 甘南夏河机场 XIAHE
|
||||||
|
金昌 JIC ZLJC 金昌金川机场 JINCHANG
|
||||||
|
张掖 YZY ZLZY 张掖甘州机场 ZHANGYE
|
||||||
|
敦煌 DNH ZLDH 敦煌机场 DUNHUANG
|
||||||
|
嘉峪关 JGN ZLJQ 嘉峪关机场 JIAYUGUAN
|
||||||
|
兰州 LHW ZLLL 兰州中川机场 LANZHOU
|
||||||
|
庆阳 IQN ZLQY 庆阳机场 QINGYANG
|
||||||
|
天水 THQ ZLTS 天水麦积山机场 TIANSHUI
|
||||||
|
青海省
|
||||||
|
西宁 XNN ZLXN 西宁曹家堡机场 XINING
|
||||||
|
格尔木 GOQ ZLGM 格尔木机场 GOLMUD
|
||||||
|
玉树 YUS ZLYS 玉树巴塘机场 YUSHU
|
||||||
|
宁夏回族自治区
|
||||||
|
固原 GYU ZLGY 固原六盘山机场 GUYUAN
|
||||||
|
银川 INC ZLIC 银川河东国际机场 YINCHUAN
|
||||||
|
中卫 ZHY ZLZW 中卫沙坡头机场 ZHONGWEI
|
||||||
|
新疆维吾尔自治区
|
||||||
|
阿克苏 AKU ZWAK 阿克苏机场 AKSU
|
||||||
|
阿勒泰 AAT ZWAT 阿勒泰机场 ALTAY
|
||||||
|
富蕴 FYN ZWFY 富蕴机场 FUYUN
|
||||||
|
哈密 HMI ZWHM 哈密机场 HAMI
|
||||||
|
和田 HTN ZWTN 和田机场 HETIAN
|
||||||
|
库尔勒 KRL ZWKL 库尔勒机场 KORLA
|
||||||
|
且末 IQM ZWCM 且末机场 QIEMO
|
||||||
|
吐鲁番 TLQ ZWTP 吐鲁番交河机场 TULUFAN
|
||||||
|
乌鲁木齐 URC ZWWW 乌鲁木齐地窝堡国际机场 URUMQI
|
||||||
|
博尔塔拉 BPL ZWBL 博乐阿拉山口机场 BOLE
|
||||||
|
布尔津 KJI ZWKN 布尔津喀纳斯机场 BUERJIN
|
||||||
|
喀什 KHG ZWSH 喀什机场 KASHGAR
|
||||||
|
克拉玛依 KRY ZWKM 克拉玛依机场 KARAMAY
|
||||||
|
库车 KCA ZWKC 库车龟兹机场 KUQA
|
||||||
|
塔城 TCG ZWTC 塔城机场 TACHENG
|
||||||
|
伊宁 YIN ZWYN 伊宁机场 YINING
|
||||||
|
新源 NLT ZWNL 新源那拉提机场 NALATI
|
||||||
|
香港特别行政区
|
||||||
|
香港 HKG VHHH 香港国际机场 HONG KONG
|
||||||
|
澳门特别行政区
|
||||||
|
澳门 MFM VMMC 澳门国际机场 MACAU
|
||||||
|
台湾省
|
||||||
|
台北 TSA RCSS 台北松山机场 TAIBEI
|
||||||
|
桃园 TPE RCTP 桃园国际机场 TAOYUAN
|
||||||
|
高雄 KHH RCKH 高雄国际机场 GAOXIONG
|
105
Project/Manager/data_source/flights/flights.sql
Normal file
105
Project/Manager/data_source/flights/flights.sql
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
INSERT INTO Flights (ID, Airline, Departure_airport, Arrival_airport, Departure_time, Arrival_time, First_class_seats_remaining, Business_class_seats_remaining, Economy_class_seats_remaining, First_class_price, Business_class_price, Economy_class_price, `Status`) VALUES
|
||||||
|
('FL001', 'AirlineA', 'PEK', 'SHA', '2024-06-14 08:00:00', '2024-06-14 10:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '已降落'),
|
||||||
|
('FL002', 'AirlineB', 'TSN', 'PVG', '2024-06-14 09:00:00', '2024-06-14 11:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '已降落'),
|
||||||
|
('FL003', 'AirlineC', 'SHA', 'SZX', '2024-06-14 07:00:00', '2024-06-14 09:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '已降落'),
|
||||||
|
('FL004', 'AirlineD', 'PVG', 'CAN', '2024-06-14 06:00:00', '2024-06-14 08:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '已降落'),
|
||||||
|
('FL005', 'AirlineE', 'SZX', 'CTU', '2024-06-14 10:00:00', '2024-06-14 12:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '已降落'),
|
||||||
|
('FL006', 'AirlineF', 'CAN', 'KWE', '2024-06-14 11:00:00', '2024-06-14 13:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '已降落'),
|
||||||
|
('FL007', 'AirlineG', 'CTU', 'XIY', '2024-06-14 12:00:00', '2024-06-14 14:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '已降落'),
|
||||||
|
('FL008', 'AirlineH', 'KWE', 'LHW', '2024-06-14 13:00:00', '2024-06-14 15:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '已降落'),
|
||||||
|
('FL009', 'AirlineI', 'XIY', 'PEK', '2024-06-14 14:00:00', '2024-06-14 16:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '已降落'),
|
||||||
|
('FL010', 'AirlineJ', 'LHW', 'TSN', '2024-06-14 15:00:00', '2024-06-14 17:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '已降落'),
|
||||||
|
('FL210', 'AirlineJ', 'LHW', 'TSN', '2024-06-14 21:00:00', '2024-06-14 23:50:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '开始检票'),
|
||||||
|
('FL011', 'AirlineA', 'PEK', 'CAN', '2024-06-15 08:00:00', '2024-06-15 10:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '候机中'),
|
||||||
|
('FL012', 'AirlineB', 'TSN', 'CTU', '2024-06-15 09:00:00', '2024-06-15 11:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '延误'),
|
||||||
|
('FL013', 'AirlineC', 'SHA', 'KWE', '2024-06-15 07:00:00', '2024-06-15 09:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '候机中'),
|
||||||
|
('FL014', 'AirlineD', 'PVG', 'XIY', '2024-06-15 06:00:00', '2024-06-15 08:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '候机中'),
|
||||||
|
('FL015', 'AirlineE', 'SZX', 'LHW', '2024-06-15 10:00:00', '2024-06-15 12:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '延误'),
|
||||||
|
('FL016', 'AirlineF', 'CAN', 'PEK', '2024-06-15 11:00:00', '2024-06-15 13:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '候机中'),
|
||||||
|
('FL017', 'AirlineG', 'CTU', 'TSN', '2024-06-15 12:00:00', '2024-06-15 14:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '候机中'),
|
||||||
|
('FL018', 'AirlineH', 'KWE', 'SHA', '2024-06-15 13:00:00', '2024-06-15 15:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '延误'),
|
||||||
|
('FL019', 'AirlineI', 'XIY', 'PVG', '2024-06-15 14:00:00', '2024-06-15 16:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '候机中'),
|
||||||
|
('FL020', 'AirlineJ', 'LHW', 'SZX', '2024-06-15 15:00:00', '2024-06-15 17:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '候机中'),
|
||||||
|
('FL021', 'AirlineA', 'PEK', 'SHA', '2024-06-16 08:00:00', '2024-06-16 10:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '延误'),
|
||||||
|
('FL121', 'AirlineB', 'NAY', 'SHA', '2024-06-16 09:00:00', '2024-06-16 12:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '未知'),
|
||||||
|
('FL221', 'AirlineC', 'PEK', 'PVG', '2024-06-16 11:00:00', '2024-06-16 12:30:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '未知'),
|
||||||
|
('FL022', 'AirlineB', 'TSN', 'PVG', '2024-06-16 09:00:00', '2024-06-16 11:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '延误'),
|
||||||
|
('FL023', 'AirlineC', 'SHA', 'SZX', '2024-06-16 07:00:00', '2024-06-16 09:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '延误'),
|
||||||
|
('FL024', 'AirlineD', 'PVG', 'CAN', '2024-06-16 06:00:00', '2024-06-16 08:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '延误'),
|
||||||
|
('FL025', 'AirlineE', 'SZX', 'CTU', '2024-06-16 10:00:00', '2024-06-16 12:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '延误'),
|
||||||
|
('FL026', 'AirlineF', 'CAN', 'KWE', '2024-06-16 11:00:00', '2024-06-16 13:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '延误'),
|
||||||
|
('FL027', 'AirlineG', 'CTU', 'XIY', '2024-06-16 12:00:00', '2024-06-16 14:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '未知'),
|
||||||
|
('FL028', 'AirlineH', 'KWE', 'LHW', '2024-06-16 13:00:00', '2024-06-16 15:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '未知'),
|
||||||
|
('FL029', 'AirlineI', 'XIY', 'PEK', '2024-06-16 14:00:00', '2024-06-16 16:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '未知'),
|
||||||
|
('FL030', 'AirlineJ', 'LHW', 'TSN', '2024-06-16 15:00:00', '2024-06-16 17:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '未知'),
|
||||||
|
('FL031', 'AirlineA', 'PEK', 'CAN', '2024-06-17 08:00:00', '2024-06-17 10:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '未知'),
|
||||||
|
('FL032', 'AirlineB', 'TSN', 'CTU', '2024-06-17 09:00:00', '2024-06-17 11:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '未知'),
|
||||||
|
('FL033', 'AirlineC', 'SHA', 'KWE', '2024-06-17 07:00:00', '2024-06-17 09:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '未知'),
|
||||||
|
('FL034', 'AirlineD', 'PVG', 'XIY', '2024-06-17 06:00:00', '2024-06-17 08:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '未知'),
|
||||||
|
('FL035', 'AirlineE', 'SZX', 'LHW', '2024-06-17 10:00:00', '2024-06-17 12:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '未知'),
|
||||||
|
('FL036', 'AirlineF', 'CAN', 'PEK', '2024-06-17 11:00:00', '2024-06-17 13:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '未知'),
|
||||||
|
('FL037', 'AirlineG', 'CTU', 'TSN', '2024-06-17 12:00:00', '2024-06-17 14:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '未知'),
|
||||||
|
('FL038', 'AirlineH', 'KWE', 'SHA', '2024-06-17 13:00:00', '2024-06-17 15:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '未知'),
|
||||||
|
('FL039', 'AirlineI', 'XIY', 'PVG', '2024-06-17 14:00:00', '2024-06-17 16:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '未知'),
|
||||||
|
('FL040', 'AirlineJ', 'LHW', 'SZX', '2024-06-17 15:00:00', '2024-06-17 17:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '未知'),
|
||||||
|
('FL041', 'AirlineA', 'PEK', 'SHA', '2024-06-18 08:00:00', '2024-06-18 10:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '未知'),
|
||||||
|
('FL042', 'AirlineB', 'TSN', 'PVG', '2024-06-18 09:00:00', '2024-06-18 11:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '未知'),
|
||||||
|
('FL043', 'AirlineC', 'SHA', 'SZX', '2024-06-18 07:00:00', '2024-06-18 09:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '未知'),
|
||||||
|
('FL044', 'AirlineD', 'PVG', 'CAN', '2024-06-18 06:00:00', '2024-06-18 08:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '未知'),
|
||||||
|
('FL045', 'AirlineE', 'SZX', 'CTU', '2024-06-18 10:00:00', '2024-06-18 12:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '未知'),
|
||||||
|
('FL046', 'AirlineF', 'CAN', 'KWE', '2024-06-18 11:00:00', '2024-06-18 13:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '未知'),
|
||||||
|
('FL047', 'AirlineG', 'CTU', 'XIY', '2024-06-18 12:00:00', '2024-06-18 14:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '未知'),
|
||||||
|
('FL048', 'AirlineH', 'KWE', 'LHW', '2024-06-18 13:00:00', '2024-06-18 15:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '未知'),
|
||||||
|
('FL049', 'AirlineI', 'XIY', 'PEK', '2024-06-18 14:00:00', '2024-06-18 16:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '未知'),
|
||||||
|
('FL050', 'AirlineJ', 'LHW', 'TSN', '2024-06-18 15:00:00', '2024-06-18 17:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '未知'),
|
||||||
|
('FL051', 'AirlineA', 'PEK', 'CAN', '2024-06-19 08:00:00', '2024-06-19 10:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '未知'),
|
||||||
|
('FL052', 'AirlineB', 'TSN', 'CTU', '2024-06-19 09:00:00', '2024-06-19 11:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '未知'),
|
||||||
|
('FL053', 'AirlineC', 'SHA', 'KWE', '2024-06-19 07:00:00', '2024-06-19 09:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '未知'),
|
||||||
|
('FL054', 'AirlineD', 'PVG', 'XIY', '2024-06-19 06:00:00', '2024-06-19 08:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '未知'),
|
||||||
|
('FL055', 'AirlineE', 'SZX', 'LHW', '2024-06-19 10:00:00', '2024-06-19 12:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '未知'),
|
||||||
|
('FL056', 'AirlineF', 'CAN', 'PEK', '2024-06-19 11:00:00', '2024-06-19 13:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '未知'),
|
||||||
|
('FL057', 'AirlineG', 'CTU', 'TSN', '2024-06-19 12:00:00', '2024-06-19 14:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '未知'),
|
||||||
|
('FL058', 'AirlineH', 'KWE', 'SHA', '2024-06-19 13:00:00', '2024-06-19 15:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '未知'),
|
||||||
|
('FL059', 'AirlineI', 'XIY', 'PVG', '2024-06-19 14:00:00', '2024-06-19 16:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '未知'),
|
||||||
|
('FL060', 'AirlineJ', 'LHW', 'SZX', '2024-06-19 15:00:00', '2024-06-19 17:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '未知'),
|
||||||
|
('FL061', 'AirlineA', 'PEK', 'SHA', '2024-06-20 08:00:00', '2024-06-20 10:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '未知'),
|
||||||
|
('FL062', 'AirlineB', 'TSN', 'PVG', '2024-06-20 09:00:00', '2024-06-20 11:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '未知'),
|
||||||
|
('FL063', 'AirlineC', 'SHA', 'SZX', '2024-06-20 07:00:00', '2024-06-20 09:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '未知'),
|
||||||
|
('FL064', 'AirlineD', 'PVG', 'CAN', '2024-06-20 06:00:00', '2024-06-20 08:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '未知'),
|
||||||
|
('FL065', 'AirlineE', 'SZX', 'CTU', '2024-06-20 10:00:00', '2024-06-20 12:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '未知'),
|
||||||
|
('FL066', 'AirlineF', 'CAN', 'KWE', '2024-06-20 11:00:00', '2024-06-20 13:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '未知'),
|
||||||
|
('FL067', 'AirlineG', 'CTU', 'XIY', '2024-06-20 12:00:00', '2024-06-20 14:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '未知'),
|
||||||
|
('FL068', 'AirlineH', 'KWE', 'LHW', '2024-06-20 13:00:00', '2024-06-20 15:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '未知'),
|
||||||
|
('FL069', 'AirlineI', 'XIY', 'PEK', '2024-06-20 14:00:00', '2024-06-20 16:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '未知'),
|
||||||
|
('FL070', 'AirlineJ', 'LHW', 'TSN', '2024-06-20 15:00:00', '2024-06-20 17:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '未知'),
|
||||||
|
('FL071', 'AirlineA', 'PEK', 'CAN', '2024-06-21 08:00:00', '2024-06-21 10:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '未知'),
|
||||||
|
('FL072', 'AirlineB', 'TSN', 'CTU', '2024-06-21 09:00:00', '2024-06-21 11:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '未知'),
|
||||||
|
('FL073', 'AirlineC', 'SHA', 'KWE', '2024-06-21 07:00:00', '2024-06-21 09:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '未知'),
|
||||||
|
('FL074', 'AirlineD', 'PVG', 'XIY', '2024-06-21 06:00:00', '2024-06-21 08:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '未知'),
|
||||||
|
('FL075', 'AirlineE', 'SZX', 'LHW', '2024-06-21 10:00:00', '2024-06-21 12:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '未知'),
|
||||||
|
('FL076', 'AirlineF', 'CAN', 'PEK', '2024-06-21 11:00:00', '2024-06-21 13:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '未知'),
|
||||||
|
('FL077', 'AirlineG', 'CTU', 'TSN', '2024-06-21 12:00:00', '2024-06-21 14:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '未知'),
|
||||||
|
('FL078', 'AirlineH', 'KWE', 'SHA', '2024-06-21 13:00:00', '2024-06-21 15:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '未知'),
|
||||||
|
('FL079', 'AirlineI', 'XIY', 'PVG', '2024-06-21 14:00:00', '2024-06-21 16:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '未知'),
|
||||||
|
('FL080', 'AirlineJ', 'LHW', 'SZX', '2024-06-21 15:00:00', '2024-06-21 17:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '未知'),
|
||||||
|
('FL081', 'AirlineA', 'PEK', 'SHA', '2024-06-22 08:00:00', '2024-06-22 10:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '未知'),
|
||||||
|
('FL082', 'AirlineB', 'TSN', 'PVG', '2024-06-22 09:00:00', '2024-06-22 11:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '未知'),
|
||||||
|
('FL083', 'AirlineC', 'SHA', 'SZX', '2024-06-22 07:00:00', '2024-06-22 09:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '未知'),
|
||||||
|
('FL084', 'AirlineD', 'PVG', 'CAN', '2024-06-22 06:00:00', '2024-06-22 08:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '未知'),
|
||||||
|
('FL085', 'AirlineE', 'SZX', 'CTU', '2024-06-22 10:00:00', '2024-06-22 12:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '未知'),
|
||||||
|
('FL086', 'AirlineF', 'CAN', 'KWE', '2024-06-22 11:00:00', '2024-06-22 13:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '未知'),
|
||||||
|
('FL087', 'AirlineG', 'CTU', 'XIY', '2024-06-22 12:00:00', '2024-06-22 14:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '未知'),
|
||||||
|
('FL088', 'AirlineH', 'KWE', 'LHW', '2024-06-22 13:00:00', '2024-06-22 15:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '未知'),
|
||||||
|
('FL089', 'AirlineI', 'XIY', 'PEK', '2024-06-22 14:00:00', '2024-06-22 16:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '未知'),
|
||||||
|
('FL090', 'AirlineJ', 'LHW', 'TSN', '2024-06-22 15:00:00', '2024-06-22 17:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '未知'),
|
||||||
|
('FL091', 'AirlineA', 'PEK', 'SHA', '2024-06-23 08:00:00', '2024-06-23 10:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '未知'),
|
||||||
|
('FL092', 'AirlineB', 'TSN', 'PVG', '2024-06-23 09:00:00', '2024-06-23 11:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '未知'),
|
||||||
|
('FL093', 'AirlineC', 'SHA', 'SZX', '2024-06-23 07:00:00', '2024-06-23 09:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '未知'),
|
||||||
|
('FL094', 'AirlineD', 'PVG', 'CAN', '2024-06-23 06:00:00', '2024-06-23 08:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '未知'),
|
||||||
|
('FL095', 'AirlineE', 'SZX', 'CTU', '2024-06-23 10:00:00', '2024-06-23 12:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '未知'),
|
||||||
|
('FL096', 'AirlineF', 'CAN', 'KWE', '2024-06-23 11:00:00', '2024-06-23 13:00:00', 5, 10, 100, 2000.00, 1000.00, 500.00, '未知'),
|
||||||
|
('FL097', 'AirlineG', 'CTU', 'XIY', '2024-06-23 12:00:00', '2024-06-23 14:00:00', 3, 15, 80, 2100.00, 1100.00, 600.00, '未知'),
|
||||||
|
('FL098', 'AirlineH', 'KWE', 'LHW', '2024-06-23 13:00:00', '2024-06-23 15:00:00', 2, 12, 70, 2200.00, 1200.00, 550.00, '未知'),
|
||||||
|
('FL099', 'AirlineI', 'XIY', 'PEK', '2024-06-23 14:00:00', '2024-06-23 16:00:00', 4, 8, 90, 2300.00, 1300.00, 600.00, '未知'),
|
||||||
|
('FL100', 'AirlineJ', 'LHW', 'TSN', '2024-06-23 15:00:00', '2024-06-23 17:00:00', 1, 10, 60, 2400.00, 1400.00, 650.00, '未知');
|
||||||
|
|
9
Project/Manager/data_source/init_manager_db.sql
Normal file
9
Project/Manager/data_source/init_manager_db.sql
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
DROP TABLE IF EXISTS Managers;
|
||||||
|
|
||||||
|
CREATE TABLE Managers (
|
||||||
|
ID VARCHAR(255) PRIMARY KEY,
|
||||||
|
`Password` VARCHAR(255) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO Managers
|
||||||
|
VALUES ('Admin', 'e10adc3949ba59abbe56e057f20f883e');
|
@ -1,14 +1,15 @@
|
|||||||
DROP TABLE IF EXISTS Tickets;
|
DROP TABLE IF EXISTS Tickets;
|
||||||
|
DROP TABLE IF EXISTS Orders;
|
||||||
|
DROP TABLE IF EXISTS Users;
|
||||||
DROP TABLE IF EXISTS Flights;
|
DROP TABLE IF EXISTS Flights;
|
||||||
DROP TABLE IF EXISTS Airports;
|
DROP TABLE IF EXISTS Airports;
|
||||||
DROP TABLE IF EXISTS Users;
|
|
||||||
DROP TABLE IF EXISTS Passengers;
|
DROP TABLE IF EXISTS Passengers;
|
||||||
|
|
||||||
CREATE TABLE Passengers (
|
CREATE TABLE Passengers (
|
||||||
ID BIGINT PRIMARY KEY,
|
ID VARCHAR(18) PRIMARY KEY,
|
||||||
`Name` VARCHAR(255) NOT NULL,
|
`Name` VARCHAR(255) NOT NULL,
|
||||||
Phone_number BIGINT NOT NULL,
|
Phone_number BIGINT NOT NULL,
|
||||||
CHECK (REGEXP_LIKE(ID, '^\\d{18}$')),
|
CHECK (REGEXP_LIKE(ID, '^[1-9]\\d{5}(19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[1-2]\\d|3[0-1])\\d{3}([0-9]|x)$')),
|
||||||
CHECK (REGEXP_LIKE(Phone_number, '^\\d{11}$'))
|
CHECK (REGEXP_LIKE(Phone_number, '^\\d{11}$'))
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -20,17 +21,16 @@ CREATE TABLE Users (
|
|||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE Airports (
|
CREATE TABLE Airports (
|
||||||
ID INT AUTO_INCREMENT PRIMARY KEY,
|
ID VARCHAR(3) PRIMARY KEY, -- 机场三字码
|
||||||
`Name` VARCHAR(255) UNIQUE NOT NULL,
|
`Name` VARCHAR(255) UNIQUE NOT NULL,
|
||||||
Country VARCHAR(255) NOT NULL,
|
|
||||||
City VARCHAR(255) NOT NULL
|
City VARCHAR(255) NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE Flights (
|
CREATE TABLE Flights (
|
||||||
ID VARCHAR(255) PRIMARY KEY,
|
ID VARCHAR(255) PRIMARY KEY,
|
||||||
Airline VARCHAR(255) NOT NULL,
|
Airline VARCHAR(255) NOT NULL,
|
||||||
Departure_airport INT NOT NULL,
|
Departure_airport VARCHAR(3) NOT NULL,
|
||||||
Arrival_airport INT NOT NULL,
|
Arrival_airport VARCHAR(3) NOT NULL,
|
||||||
Departure_time DATETIME NOT NULL,
|
Departure_time DATETIME NOT NULL,
|
||||||
Arrival_time DATETIME NOT NULL,
|
Arrival_time DATETIME NOT NULL,
|
||||||
First_class_seats_remaining INT NOT NULL, -- 头等舱剩余座位
|
First_class_seats_remaining INT NOT NULL, -- 头等舱剩余座位
|
||||||
@ -39,20 +39,29 @@ CREATE TABLE Flights (
|
|||||||
First_class_price DECIMAL(7, 2) NOT NULL, -- 头等舱价格
|
First_class_price DECIMAL(7, 2) NOT NULL, -- 头等舱价格
|
||||||
Business_class_price DECIMAL(7, 2) NOT NULL, -- 商务舱价格
|
Business_class_price DECIMAL(7, 2) NOT NULL, -- 商务舱价格
|
||||||
Economy_class_price DECIMAL(7, 2) NOT NULL, -- 经济舱价格
|
Economy_class_price DECIMAL(7, 2) NOT NULL, -- 经济舱价格
|
||||||
`Status` VARCHAR(255) NOT NULL CHECK (`Status` IN ('候机中', '延误', '已起飞', '已降落', '开始检票')), -- 航班状态
|
`Status` VARCHAR(255) NOT NULL CHECK (`Status` IN ('候机中', '延误', '已起飞', '已降落', '开始检票', '未知')), -- 航班状态
|
||||||
FOREIGN KEY (Departure_airport) REFERENCES Airports(ID) ON DELETE CASCADE,
|
FOREIGN KEY (Departure_airport) REFERENCES Airports(ID) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (Arrival_airport) REFERENCES Airports(ID) ON DELETE CASCADE,
|
FOREIGN KEY (Arrival_airport) REFERENCES Airports(ID) ON DELETE CASCADE,
|
||||||
CHECK (Departure_time < Arrival_time)
|
CHECK (Departure_time < Arrival_time)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE Orders (
|
||||||
|
ID INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
Order_time DATETIME NOT NULL,
|
||||||
|
Paid TINYINT NOT NULL,
|
||||||
|
User_phone_number BIGINT NOT NULL,
|
||||||
|
FOREIGN KEY (User_phone_number) REFERENCES Users(Phone_number) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
CREATE TABLE Tickets (
|
CREATE TABLE Tickets (
|
||||||
ID INT AUTO_INCREMENT PRIMARY KEY,
|
ID INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
Price DECIMAL(7, 2) NOT NULL,
|
Price DECIMAL(7, 2) NOT NULL,
|
||||||
FlightID VARCHAR(255) NOT NULL,
|
FlightID VARCHAR(255) NOT NULL,
|
||||||
Seat_class VARCHAR(255) NOT NULL, -- 级别信息
|
Seat_class VARCHAR(255) NOT NULL, -- 级别信息
|
||||||
PassengerID BIGINT NOT NULL,
|
PassengerID VARCHAR(18) NOT NULL,
|
||||||
Paid TINYINT NOT NULL,
|
OrderID INT NOT NULL,
|
||||||
FOREIGN KEY (FlightID) REFERENCES Flights(ID) ON DELETE CASCADE,
|
FOREIGN KEY (FlightID) REFERENCES Flights(ID) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (PassengerID) REFERENCES Passengers(ID) ON DELETE CASCADE,
|
FOREIGN KEY (PassengerID) REFERENCES Passengers(ID) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (OrderID) REFERENCES Orders(ID) ON DELETE CASCADE,
|
||||||
CHECK (Seat_class IN ('First Class', 'Business Class', 'Economy Class'))
|
CHECK (Seat_class IN ('First Class', 'Business Class', 'Economy Class'))
|
||||||
);
|
);
|
9
Project/Manager/func/config.py
Normal file
9
Project/Manager/func/config.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
db = {
|
||||||
|
'host':'localhost',
|
||||||
|
'user':'kejingfan',
|
||||||
|
'password':'KJF2811879',
|
||||||
|
'database':'TESTDB'
|
||||||
|
}
|
||||||
|
|
||||||
|
SECRET_KEY = 'ILOVEDATABASETECH'
|
||||||
|
|
32
Project/Manager/func/index.py
Normal file
32
Project/Manager/func/index.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
from flask import render_template, request, g, redirect, url_for, session
|
||||||
|
from .config import db
|
||||||
|
import pymysql
|
||||||
|
|
||||||
|
def index():
|
||||||
|
if request.method == 'GET':
|
||||||
|
if not g.user:
|
||||||
|
return redirect(url_for("login"))
|
||||||
|
flightID = request.args.get('flightID')
|
||||||
|
|
||||||
|
conn = pymysql.connect(**db)
|
||||||
|
cursor = conn.cursor(pymysql.cursors.DictCursor)
|
||||||
|
|
||||||
|
search_sql = """ """
|
||||||
|
cursor.execute(search_sql, (flightID, ))
|
||||||
|
flights = cursor.fetchall()
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
'search.html',
|
||||||
|
flights=flights,
|
||||||
|
username=g.user
|
||||||
|
)
|
||||||
|
|
||||||
|
def logout():
|
||||||
|
session.clear()
|
||||||
|
session.pop('user_id', None)
|
||||||
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
|
def modify():
|
||||||
|
pass
|
34
Project/Manager/func/login.py
Normal file
34
Project/Manager/func/login.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
from flask import request, jsonify, session, url_for, render_template
|
||||||
|
from .config import db
|
||||||
|
import pymysql
|
||||||
|
|
||||||
|
|
||||||
|
def connect(managerID, encrypted_password):
|
||||||
|
conn = pymysql.connect(**db)
|
||||||
|
cursor = conn.cursor(pymysql.cursors.DictCursor)
|
||||||
|
args = (managerID, encrypted_password)
|
||||||
|
verify_sql = "SELECT COUNT(*) FROM Managers WHERE ID = %s AND `Password` = %s;"
|
||||||
|
cursor.execute(verify_sql, args)
|
||||||
|
verified = cursor.fetchone()
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
return verified['COUNT(*)'] > 0
|
||||||
|
|
||||||
|
def login():
|
||||||
|
if request.method == 'GET':
|
||||||
|
return render_template('login.html')
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
session.pop('user_id', None)
|
||||||
|
managerID = request.json.get('username')
|
||||||
|
encrypted_password = request.json.get('password')
|
||||||
|
try:
|
||||||
|
user = connect(managerID, encrypted_password)
|
||||||
|
if not user:
|
||||||
|
return jsonify({'message': '账号或密码错误'}), 401
|
||||||
|
session['user_id'] = managerID
|
||||||
|
session.modified = True
|
||||||
|
return jsonify({'redirect': url_for('index')})
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
return jsonify({'message': '数据库错误,请稍后再试'}), 500
|
49
Project/Manager/main.py
Normal file
49
Project/Manager/main.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
from flask import Flask, redirect, url_for, session, g
|
||||||
|
from flask_httpauth import HTTPTokenAuth
|
||||||
|
from flask_cors import CORS
|
||||||
|
from func.config import SECRET_KEY
|
||||||
|
|
||||||
|
import func.login
|
||||||
|
import func.index
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config["SECRET_KEY"] = SECRET_KEY
|
||||||
|
app.config["JSON_AS_ASCII"] = False
|
||||||
|
app.config['SESSION_COOKIE_HTTPONLY'] = True
|
||||||
|
app.config['SESSION_COOKIE_SECURE'] = False
|
||||||
|
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'
|
||||||
|
CORS(app, supports_credentials=True)
|
||||||
|
auth = HTTPTokenAuth(scheme='Bearer')
|
||||||
|
|
||||||
|
@app.before_request
|
||||||
|
def before_request():
|
||||||
|
g.user = None
|
||||||
|
if 'user_id' in session:
|
||||||
|
g.user = session.get('user_id')
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def home():
|
||||||
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
|
@app.route("/index", methods=['GET'])
|
||||||
|
def index():
|
||||||
|
return func.index.index()
|
||||||
|
|
||||||
|
@app.route("/modify", methods=['POST'])
|
||||||
|
def modify():
|
||||||
|
return func.index.modify()
|
||||||
|
|
||||||
|
@app.route("/login", methods=['GET', 'POST'])
|
||||||
|
def login():
|
||||||
|
return func.login.login()
|
||||||
|
|
||||||
|
@app.route('/logout')
|
||||||
|
def logout():
|
||||||
|
return func.index.logout()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(
|
||||||
|
host="0.0.0.0",
|
||||||
|
port=8889,
|
||||||
|
debug=True
|
||||||
|
)
|
251
Project/Manager/static/css/index.css
Normal file
251
Project/Manager/static/css/index.css
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
padding: 20px;
|
||||||
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons a {
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons a:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu span {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropbtn {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
min-width: 160px;
|
||||||
|
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||||
|
z-index: 1;
|
||||||
|
right: 0; /* 确保下拉菜单靠右对齐 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content a {
|
||||||
|
color: black;
|
||||||
|
padding: 12px 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content a:hover {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown:hover .dropdown-content {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
flex: 1;
|
||||||
|
width: 80%;
|
||||||
|
margin: 20px auto;
|
||||||
|
padding-top: 80px; /* 给主内容增加顶部填充,以避免被固定导航栏遮挡 */
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
text-align: center;
|
||||||
|
color: #1c6cb2;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table, th, td {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-results {
|
||||||
|
text-align: center;
|
||||||
|
color: red;
|
||||||
|
font-size: 18px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 0;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
margin-top: auto; /* 将footer推到页面底部 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
text-align: center;
|
||||||
|
width: 80%;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 20px auto;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabcontent {
|
||||||
|
display: block;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start; /* Left-align the form items */
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row label {
|
||||||
|
flex: 0 0 120px; /* Fixed width for labels */
|
||||||
|
margin-right: 10px;
|
||||||
|
text-align: right;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row input,
|
||||||
|
.form-row select {
|
||||||
|
flex: 1;
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row.form-row-center {
|
||||||
|
justify-content: center; /* Center-align the button */
|
||||||
|
}
|
||||||
|
|
||||||
|
.passenger-input {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.passenger-input button {
|
||||||
|
padding: 5px 10px;
|
||||||
|
font-size: 18px;
|
||||||
|
background-color: #1c6cb2;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.passenger-input button:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.passenger-input input {
|
||||||
|
width: 50px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 16px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: #1c6cb2;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: red;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 5px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add animations for flight rows */
|
||||||
|
.flight-row {
|
||||||
|
transition: transform 0.3s ease, box-shadow 0.3s ease, border-radius 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flight-row:hover {
|
||||||
|
transform: scale(1.02);
|
||||||
|
box-shadow: 0 0 10px rgba(28, 108, 178, 0.5);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
93
Project/Manager/static/css/login.css
Normal file
93
Project/Manager/static/css/login.css
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #ffffff;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
padding: 20px 0;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
text-align: center;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: #1c6cb2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form input {
|
||||||
|
display: block;
|
||||||
|
margin: 10px auto;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
width: 80%;
|
||||||
|
max-width: 300px;
|
||||||
|
margin-bottom: 20px; /* 增加外边距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form button,
|
||||||
|
.btn {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: #1c6cb2;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form button:hover,
|
||||||
|
.btn:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: red;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: left;
|
||||||
|
margin-top: -10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
42
Project/Manager/static/js/index.js
Normal file
42
Project/Manager/static/js/index.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
function validateForm() {
|
||||||
|
var departure = document.getElementById('departure').value;
|
||||||
|
var destination = document.getElementById('destination').value;
|
||||||
|
var warning = document.getElementById('destination-warning');
|
||||||
|
if (departure === destination) {
|
||||||
|
warning.textContent = '出发地和目的地不能相同';
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
warning.textContent = '';
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function increment() {
|
||||||
|
var passengers = document.getElementById("passengers");
|
||||||
|
var value = parseInt(passengers.value, 10);
|
||||||
|
if (value < 50) {
|
||||||
|
passengers.value = value + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function decrement() {
|
||||||
|
var passengers = document.getElementById("passengers");
|
||||||
|
var value = parseInt(passengers.value, 10);
|
||||||
|
if (value > 1) {
|
||||||
|
passengers.value = value - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Set default date to tomorrow
|
||||||
|
var departureDate = document.getElementById('departure-date');
|
||||||
|
if (!departureDate.value) {
|
||||||
|
var today = new Date();
|
||||||
|
var tomorrow = new Date(today);
|
||||||
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||||
|
var month = ('0' + (tomorrow.getMonth() + 1)).slice(-2);
|
||||||
|
var day = ('0' + tomorrow.getDate()).slice(-2);
|
||||||
|
var year = tomorrow.getFullYear();
|
||||||
|
departureDate.value = `${year}-${month}-${day}`;
|
||||||
|
}
|
||||||
|
});
|
80
Project/Manager/static/js/login.js
Normal file
80
Project/Manager/static/js/login.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
window.onload = function() {
|
||||||
|
autoLogin();
|
||||||
|
};
|
||||||
|
|
||||||
|
var checkInfo = {};
|
||||||
|
|
||||||
|
checkInfo.checkUsername = function() {
|
||||||
|
let username = document.getElementById('username').value;
|
||||||
|
if (username.length < 1) {
|
||||||
|
document.getElementById('usernameError').textContent = '用户名不能为空';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
document.getElementById('usernameError').textContent = '';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkInfo.checkPassword = function() {
|
||||||
|
let password = document.getElementById('password').value;
|
||||||
|
let regexPassword = /^[A-Za-z0-9\W_]{6,20}$/;
|
||||||
|
if (!regexPassword.test(password)) {
|
||||||
|
document.getElementById('loginError').textContent = "密码须为长度为6-20位字母、数字或符号";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
document.getElementById('loginError').textContent = '';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitForm() {
|
||||||
|
if (checkInfo.checkUsername() && checkInfo.checkPassword()) {
|
||||||
|
document.getElementById('encryptedPassword').value = md5(
|
||||||
|
document.getElementById('password').value
|
||||||
|
);
|
||||||
|
login();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录函数
|
||||||
|
async function login() {
|
||||||
|
const username = document.getElementById('username').value;
|
||||||
|
const encryptedPassword = document.getElementById('encryptedPassword').value;
|
||||||
|
try {
|
||||||
|
const response = await fetch('/login', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ username: username, password: encryptedPassword }),
|
||||||
|
credentials: 'include' // 确保请求包含凭据(cookies)
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
if (response.ok) {
|
||||||
|
alert('登录成功');
|
||||||
|
// 自动跳转到主页
|
||||||
|
window.location.href = data.redirect;
|
||||||
|
} else {
|
||||||
|
document.getElementById('loginError').textContent = data.message;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert('数据库错误,请稍后再试');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动登录函数
|
||||||
|
async function autoLogin() {
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
|
if (token) {
|
||||||
|
const response = await fetch('/index', {
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + token
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (response.ok) {
|
||||||
|
document.getElementById('content').innerText = '已自动登录';
|
||||||
|
} else {
|
||||||
|
document.getElementById('content').innerText = '自动登录失败';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,7 @@
|
|||||||
<div class="logo">KJF航班订票</div>
|
<div class="logo">KJF航班订票</div>
|
||||||
<div class="nav-buttons">
|
<div class="nav-buttons">
|
||||||
<a href="{{ url_for('index') }}">首页</a>
|
<a href="{{ url_for('index') }}">首页</a>
|
||||||
<a href="{{ url_for('orders') }}">我的订单</a>
|
<a href="{{ url_for('order_list') }}">我的订单</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="user-menu">
|
<div class="user-menu">
|
||||||
<span>{{ username }}</span>
|
<span>{{ username }}</span>
|
||||||
@ -46,23 +46,24 @@
|
|||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="departure">出发地:</label>
|
<label for="departure">出发地:</label>
|
||||||
<select id="departure" name="departure">
|
<select id="departure" name="departure">
|
||||||
<option value="北京">北京</option>
|
{% for city in cities %}
|
||||||
<option value="上海">上海</option>
|
<option value="{{ city }}" {% if city == "北京" %}selected{% endif %}>{{ city }}</option>
|
||||||
<option value="广州">广州</option>
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="destination">目的地:</label>
|
<label for="destination">目的地:</label>
|
||||||
<select id="destination" name="destination">
|
<select id="destination" name="destination">
|
||||||
<option value="北京">北京</option>
|
{% for city in cities %}
|
||||||
<option value="上海">上海</option>
|
<option value="{{ city }}" {% if city == "上海" %}selected{% endif %}>{{ city }}</option>
|
||||||
<option value="广州">广州</option>
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<div id="destination-warning" class="error-message"></div>
|
<div id="destination-warning" class="error-message"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="departure-date">出发日期:</label>
|
<label for="departure-date">出发日期:</label>
|
||||||
<input type="date" id="departure-date" name="departure-date">
|
<input type="date" id="departure-date" name="departure-date" required>
|
||||||
|
<div id="date-warning" class="error-message"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="passengers">乘客人数:</label>
|
<label for="passengers">乘客人数:</label>
|
||||||
@ -72,7 +73,7 @@
|
|||||||
<button type="button" onclick="increment()">+</button>
|
<button type="button" onclick="increment()">+</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row form-row-center">
|
||||||
<button type="submit" class="btn">立即查询</button>
|
<button type="submit" class="btn">立即查询</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@ -88,27 +89,28 @@
|
|||||||
var departure = document.getElementById('departure').value;
|
var departure = document.getElementById('departure').value;
|
||||||
var destination = document.getElementById('destination').value;
|
var destination = document.getElementById('destination').value;
|
||||||
var warning = document.getElementById('destination-warning');
|
var warning = document.getElementById('destination-warning');
|
||||||
|
var dateWarning = document.getElementById('date-warning');
|
||||||
|
var departureDate = document.getElementById('departure-date').value;
|
||||||
|
|
||||||
|
var today = new Date();
|
||||||
|
var selectedDate = new Date(departureDate);
|
||||||
|
today.setHours(0, 0, 0, 0); // Ensure time comparison is not affected
|
||||||
|
|
||||||
if (departure === destination) {
|
if (departure === destination) {
|
||||||
warning.textContent = '出发地和目的地不能相同';
|
warning.textContent = '出发地和目的地不能相同';
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
warning.textContent = '';
|
warning.textContent = '';
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function openTab(evt, tabName) {
|
if (selectedDate < today) {
|
||||||
var i, tabcontent, tablinks;
|
dateWarning.textContent = '出发日期不能早于今天';
|
||||||
tabcontent = document.getElementsByClassName("tabcontent");
|
return false;
|
||||||
for (i = 0; i < tabcontent.length; i++) {
|
} else {
|
||||||
tabcontent[i].style.display = "none";
|
dateWarning.textContent = '';
|
||||||
}
|
}
|
||||||
tablinks = document.getElementsByClassName("tablinks");
|
|
||||||
for (i = 0; i < tablinks.length; i++) {
|
return true;
|
||||||
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
|
||||||
}
|
|
||||||
document.getElementById(tabName).style.display = "block";
|
|
||||||
evt.currentTarget.className += " active";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function increment() {
|
function increment() {
|
||||||
@ -126,6 +128,19 @@
|
|||||||
passengers.value = value - 1;
|
passengers.value = value - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Set default date to tomorrow
|
||||||
|
var departureDate = document.getElementById('departure-date');
|
||||||
|
var today = new Date();
|
||||||
|
var tomorrow = new Date(today);
|
||||||
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||||
|
var month = ('0' + (tomorrow.getMonth() + 1)).slice(-2);
|
||||||
|
var day = ('0' + tomorrow.getDate()).slice(-2);
|
||||||
|
var year = tomorrow.getFullYear();
|
||||||
|
departureDate.value = `${year}-${month}-${day}`;
|
||||||
|
departureDate.setAttribute('min', `${year}-${month}-${day}`);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
34
Project/Manager/templates/login.html
Normal file
34
Project/Manager/templates/login.html
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>管理员登录 - KJF航班订票</title>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/login.css') }}">
|
||||||
|
<script src="{{ url_for('static', filename='js/login.js') }}" defer></script>
|
||||||
|
<script src="https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>KJF航班订票</h1>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<div class="content">
|
||||||
|
<h2>管理员登录</h2>
|
||||||
|
<div class="login-form">
|
||||||
|
<input type="text" id="username" placeholder="用户名">
|
||||||
|
<div id="usernameError" class="error-message"></div>
|
||||||
|
<input type="password" id="password" placeholder="密码">
|
||||||
|
<div id="loginError" class="error-message"></div>
|
||||||
|
<input type="hidden" id="encryptedPassword">
|
||||||
|
<div class="buttons">
|
||||||
|
<button onclick="submitForm()">登录</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
<p>© 2024 KJF航班订票. 保留所有权利。</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
0
Project/Service/func/__init__.py
Normal file
0
Project/Service/func/__init__.py
Normal file
BIN
Project/Service/func/__pycache__/book.cpython-311.pyc
Normal file
BIN
Project/Service/func/__pycache__/book.cpython-311.pyc
Normal file
Binary file not shown.
BIN
Project/Service/func/__pycache__/cancel_order.cpython-311.pyc
Normal file
BIN
Project/Service/func/__pycache__/cancel_order.cpython-311.pyc
Normal file
Binary file not shown.
BIN
Project/Service/func/__pycache__/index.cpython-311.pyc
Normal file
BIN
Project/Service/func/__pycache__/index.cpython-311.pyc
Normal file
Binary file not shown.
BIN
Project/Service/func/__pycache__/modify.cpython-311.pyc
Normal file
BIN
Project/Service/func/__pycache__/modify.cpython-311.pyc
Normal file
Binary file not shown.
BIN
Project/Service/func/__pycache__/order.cpython-311.pyc
Normal file
BIN
Project/Service/func/__pycache__/order.cpython-311.pyc
Normal file
Binary file not shown.
BIN
Project/Service/func/__pycache__/order_list.cpython-311.pyc
Normal file
BIN
Project/Service/func/__pycache__/order_list.cpython-311.pyc
Normal file
Binary file not shown.
BIN
Project/Service/func/__pycache__/pay.cpython-311.pyc
Normal file
BIN
Project/Service/func/__pycache__/pay.cpython-311.pyc
Normal file
Binary file not shown.
BIN
Project/Service/func/__pycache__/pay_confirm.cpython-311.pyc
Normal file
BIN
Project/Service/func/__pycache__/pay_confirm.cpython-311.pyc
Normal file
Binary file not shown.
BIN
Project/Service/func/__pycache__/search.cpython-311.pyc
Normal file
BIN
Project/Service/func/__pycache__/search.cpython-311.pyc
Normal file
Binary file not shown.
BIN
Project/Service/func/__pycache__/signup.cpython-311.pyc
Normal file
BIN
Project/Service/func/__pycache__/signup.cpython-311.pyc
Normal file
Binary file not shown.
BIN
Project/Service/func/__pycache__/utils.cpython-311.pyc
Normal file
BIN
Project/Service/func/__pycache__/utils.cpython-311.pyc
Normal file
Binary file not shown.
92
Project/Service/func/book.py
Normal file
92
Project/Service/func/book.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
from flask import render_template, request, redirect, url_for, g, flash, session
|
||||||
|
from .config import db
|
||||||
|
import pymysql
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
def book():
|
||||||
|
flight_id = request.args.get('flight_id')
|
||||||
|
if request.method == 'GET':
|
||||||
|
if not g.user:
|
||||||
|
return redirect(url_for("login"))
|
||||||
|
conn = pymysql.connect(**db)
|
||||||
|
cursor = conn.cursor(pymysql.cursors.DictCursor)
|
||||||
|
flight_sql = """
|
||||||
|
SELECT f.*, d.Name as Departure_airport_name, a.Name as Arrival_airport_name
|
||||||
|
FROM Flights f
|
||||||
|
JOIN Airports d ON f.Departure_airport = d.ID
|
||||||
|
JOIN Airports a ON f.Arrival_airport = a.ID
|
||||||
|
WHERE f.ID = %s;
|
||||||
|
"""
|
||||||
|
cursor.execute(flight_sql, (flight_id,))
|
||||||
|
flight = cursor.fetchone()
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return render_template('book.html', flight=flight, username=g.name)
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
passengers = []
|
||||||
|
passenger_keys = ['card_code', 'name', 'phone_number', 'seat_class']
|
||||||
|
|
||||||
|
for i in range(len(request.form) // len(passenger_keys)):
|
||||||
|
passenger = {}
|
||||||
|
for key in passenger_keys:
|
||||||
|
passenger[key] = request.form.get(f'passengers[{i}][{key}]')
|
||||||
|
passengers.append(passenger)
|
||||||
|
|
||||||
|
conn = pymysql.connect(**db)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 插入订单记录
|
||||||
|
insert_order_sql = """
|
||||||
|
INSERT INTO Orders (Order_time, Paid, User_phone_number)
|
||||||
|
VALUES (%s, 0, %s)
|
||||||
|
"""
|
||||||
|
cursor.execute(insert_order_sql, (datetime.now(), g.user))
|
||||||
|
order_id = cursor.lastrowid
|
||||||
|
|
||||||
|
for passenger in passengers:
|
||||||
|
passenger_id = passenger['card_code']
|
||||||
|
name = passenger['name']
|
||||||
|
phone_number = passenger['phone_number']
|
||||||
|
seat_class = passenger['seat_class']
|
||||||
|
|
||||||
|
price_field = f"{seat_class.replace(' ', '_').lower()}_price"
|
||||||
|
price_sql = f"SELECT {price_field} FROM Flights WHERE ID = %s"
|
||||||
|
cursor.execute(price_sql, (flight_id,))
|
||||||
|
price = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
insert_passenger_sql = """
|
||||||
|
INSERT INTO Passengers (ID, Name, Phone_number)
|
||||||
|
VALUES (%s, %s, %s)
|
||||||
|
ON DUPLICATE KEY UPDATE Name=VALUES(Name), Phone_number=VALUES(Phone_number);
|
||||||
|
"""
|
||||||
|
cursor.execute(insert_passenger_sql, (passenger_id, name, phone_number))
|
||||||
|
|
||||||
|
update_seat_sql = f"""
|
||||||
|
UPDATE Flights
|
||||||
|
SET {seat_class.replace(' ', '_').lower()}_seats_remaining = {seat_class.replace(' ', '_').lower()}_seats_remaining - 1
|
||||||
|
WHERE ID = %s
|
||||||
|
"""
|
||||||
|
cursor.execute(update_seat_sql, (flight_id,))
|
||||||
|
|
||||||
|
insert_ticket_sql = """
|
||||||
|
INSERT INTO Tickets (Price, FlightID, Seat_class, PassengerID, OrderID)
|
||||||
|
VALUES (%s, %s, %s, %s, %s)
|
||||||
|
"""
|
||||||
|
cursor.execute(insert_ticket_sql, (price, flight_id, seat_class, passenger_id, order_id))
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
return redirect(url_for('order', order_id=order_id))
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
conn.rollback()
|
||||||
|
print(e)
|
||||||
|
flash("订票失败", "error")
|
||||||
|
return redirect(url_for('search'))
|
||||||
|
|
||||||
|
finally:
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
51
Project/Service/func/cancel_order.py
Normal file
51
Project/Service/func/cancel_order.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
from flask import request, redirect, url_for, g
|
||||||
|
from .config import db
|
||||||
|
import pymysql
|
||||||
|
|
||||||
|
def cancel_order():
|
||||||
|
order_id = request.args.get('order_id')
|
||||||
|
if not g.user:
|
||||||
|
return redirect(url_for("login"))
|
||||||
|
conn = pymysql.connect(**db)
|
||||||
|
cursor = conn.cursor(pymysql.cursors.DictCursor)
|
||||||
|
|
||||||
|
# 检查订单是否存在
|
||||||
|
check_order_sql = "SELECT ID FROM Orders WHERE ID = %s"
|
||||||
|
cursor.execute(check_order_sql, (order_id,))
|
||||||
|
order_exists = cursor.fetchone()
|
||||||
|
|
||||||
|
if not order_exists:
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
return redirect(url_for("order_list"))
|
||||||
|
|
||||||
|
# 查询订单中所有机票的航班ID和座位级别
|
||||||
|
tickets_sql = "SELECT FlightID, Seat_class FROM Tickets WHERE OrderID = %s"
|
||||||
|
cursor.execute(tickets_sql, (order_id,))
|
||||||
|
tickets = cursor.fetchall()
|
||||||
|
|
||||||
|
# 恢复航班的对应余座数
|
||||||
|
for ticket in tickets:
|
||||||
|
flight_id = ticket['FlightID']
|
||||||
|
seat_class = ticket['Seat_class']
|
||||||
|
seat_column = seat_class.replace(' ', '_').lower() + "_seats_remaining"
|
||||||
|
update_seat_sql = f"""
|
||||||
|
UPDATE Flights
|
||||||
|
SET {seat_column} = {seat_column} + 1
|
||||||
|
WHERE ID = %s
|
||||||
|
"""
|
||||||
|
cursor.execute(update_seat_sql, (flight_id,))
|
||||||
|
|
||||||
|
# 删除对应的机票
|
||||||
|
delete_tickets_sql = "DELETE FROM Tickets WHERE OrderID = %s"
|
||||||
|
cursor.execute(delete_tickets_sql, (order_id,))
|
||||||
|
|
||||||
|
# 删除订单
|
||||||
|
delete_order_sql = "DELETE FROM Orders WHERE ID = %s"
|
||||||
|
cursor.execute(delete_order_sql, (order_id,))
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return redirect(url_for('order_list'))
|
@ -1,13 +1,16 @@
|
|||||||
from flask import render_template, request, g, redirect, url_for, session
|
from flask import render_template, request, g, redirect, url_for, session
|
||||||
from .config import slideshow_images
|
from .config import slideshow_images
|
||||||
|
from .utils import get_cities
|
||||||
|
|
||||||
def index():
|
def index():
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
if not g.user:
|
if not g.user:
|
||||||
return redirect(url_for("login"))
|
return redirect(url_for("login"))
|
||||||
username = g.name
|
|
||||||
images = slideshow_images
|
images = slideshow_images
|
||||||
return render_template('index.html', images=images, username=username)
|
return render_template(
|
||||||
|
'index.html', cities=get_cities(),
|
||||||
|
images=images, username=g.name
|
||||||
|
)
|
||||||
|
|
||||||
def logout():
|
def logout():
|
||||||
session.clear()
|
session.clear()
|
@ -1,12 +1,8 @@
|
|||||||
from flask import render_template, request, flash, redirect, url_for, session
|
from flask import render_template, request, flash, redirect, url_for, session, g
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from pymysql.cursors import Cursor
|
from pymysql.cursors import Cursor
|
||||||
from .get_db import get_db
|
import pymysql
|
||||||
|
from .config import db
|
||||||
def get_current_user(cursor: Cursor, phone_number: str):
|
|
||||||
sql = "SELECT Username FROM Users WHERE Phone_number = %s"
|
|
||||||
cursor.execute(sql, (phone_number,))
|
|
||||||
return cursor.fetchone()
|
|
||||||
|
|
||||||
def verify_user(cursor: Cursor, phone_number: str, password: str) -> str:
|
def verify_user(cursor: Cursor, phone_number: str, password: str) -> str:
|
||||||
sql = """
|
sql = """
|
||||||
@ -23,7 +19,6 @@ def verify_user(cursor: Cursor, phone_number: str, password: str) -> str:
|
|||||||
class ModifyInfo:
|
class ModifyInfo:
|
||||||
def __init__(self, form: Dict[str, str], user_phone: str):
|
def __init__(self, form: Dict[str, str], user_phone: str):
|
||||||
self.phone_number = user_phone
|
self.phone_number = user_phone
|
||||||
print(form)
|
|
||||||
modifyType = form['modifyType']
|
modifyType = form['modifyType']
|
||||||
self.new_password = form.get('encryptedNewPassword', None)
|
self.new_password = form.get('encryptedNewPassword', None)
|
||||||
self.new_phone_number = form.get('mobileNo', None)
|
self.new_phone_number = form.get('mobileNo', None)
|
||||||
@ -74,20 +69,17 @@ class ModifyInfo:
|
|||||||
|
|
||||||
def modify():
|
def modify():
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
|
if not g.user:
|
||||||
|
return redirect(url_for("login"))
|
||||||
user_phone = session.get('user_id')
|
user_phone = session.get('user_id')
|
||||||
db = get_db()
|
return render_template('modify.html', current_user_phone=user_phone, current_username=g.name)
|
||||||
cursor = db.cursor()
|
|
||||||
current_user = get_current_user(cursor, user_phone)
|
|
||||||
if not current_user:
|
|
||||||
session.clear()
|
|
||||||
return redirect(url_for('login'))
|
|
||||||
return render_template('modify.html', current_user_phone=user_phone, current_username=current_user[0])
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
user_phone = session.get('user_id')
|
user_phone = session.get('user_id')
|
||||||
password = request.form['encryptedPassword']
|
password = request.form['encryptedPassword']
|
||||||
db = get_db()
|
conn = pymysql.connect(**db)
|
||||||
cursor = db.cursor()
|
cursor = conn.cursor(pymysql.cursors.DictCursor)
|
||||||
|
|
||||||
verify_info = verify_user(cursor, user_phone, password)
|
verify_info = verify_user(cursor, user_phone, password)
|
||||||
if verify_info == "NO_USER":
|
if verify_info == "NO_USER":
|
||||||
@ -95,7 +87,7 @@ def modify():
|
|||||||
return redirect(url_for('login'))
|
return redirect(url_for('login'))
|
||||||
elif verify_info == "WRONG_PASSWORD":
|
elif verify_info == "WRONG_PASSWORD":
|
||||||
flash("密码错误")
|
flash("密码错误")
|
||||||
db.close()
|
conn.close()
|
||||||
return redirect(url_for('modify'))
|
return redirect(url_for('modify'))
|
||||||
|
|
||||||
modifyInfo = ModifyInfo(request.form, user_phone)
|
modifyInfo = ModifyInfo(request.form, user_phone)
|
||||||
@ -105,14 +97,14 @@ def modify():
|
|||||||
cursor.execute(check_sql, (modifyInfo.new_phone_number,))
|
cursor.execute(check_sql, (modifyInfo.new_phone_number,))
|
||||||
if cursor.fetchone()[0] > 0:
|
if cursor.fetchone()[0] > 0:
|
||||||
flash("手机号已存在,请使用其他手机号")
|
flash("手机号已存在,请使用其他手机号")
|
||||||
db.close()
|
conn.close()
|
||||||
return redirect(url_for('modify'))
|
return redirect(url_for('modify'))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cursor.execute(modifyInfo.get_sql(), modifyInfo.get_args())
|
cursor.execute(modifyInfo.get_sql(), modifyInfo.get_args())
|
||||||
db.commit()
|
conn.commit()
|
||||||
flash(modifyInfo.get_ok_message())
|
flash(modifyInfo.get_ok_message())
|
||||||
db.close()
|
conn.close()
|
||||||
if modifyInfo.command in ['modify Phone_Number', 'modify Password', 'delete account']:
|
if modifyInfo.command in ['modify Phone_Number', 'modify Password', 'delete account']:
|
||||||
session.clear()
|
session.clear()
|
||||||
session.pop("user_id", None)
|
session.pop("user_id", None)
|
||||||
@ -120,8 +112,8 @@ def modify():
|
|||||||
elif modifyInfo.command == 'modify Username':
|
elif modifyInfo.command == 'modify Username':
|
||||||
return redirect(url_for('modify'))
|
return redirect(url_for('modify'))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
db.rollback()
|
conn.rollback()
|
||||||
print(e)
|
print(e)
|
||||||
flash(modifyInfo.get_fail_message())
|
flash(modifyInfo.get_fail_message())
|
||||||
db.close()
|
conn.close()
|
||||||
return redirect(url_for('modify'))
|
return redirect(url_for('modify'))
|
47
Project/Service/func/order.py
Normal file
47
Project/Service/func/order.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
from flask import render_template, request, redirect, url_for, g
|
||||||
|
from .config import db
|
||||||
|
import pymysql
|
||||||
|
|
||||||
|
def order():
|
||||||
|
order_id = request.args.get('order_id')
|
||||||
|
if not g.user:
|
||||||
|
return redirect(url_for("login"))
|
||||||
|
|
||||||
|
conn = pymysql.connect(**db)
|
||||||
|
cursor = conn.cursor(pymysql.cursors.DictCursor)
|
||||||
|
|
||||||
|
# 查询订单信息和航班信息
|
||||||
|
order_sql = """
|
||||||
|
SELECT o.*, f.*, d.Name as Departure_airport_name, a.Name as Arrival_airport_name
|
||||||
|
FROM Orders o
|
||||||
|
JOIN Tickets t ON o.ID = t.OrderID
|
||||||
|
JOIN Flights f ON t.FlightID = f.ID
|
||||||
|
JOIN Airports d ON f.Departure_airport = d.ID
|
||||||
|
JOIN Airports a ON f.Arrival_airport = a.ID
|
||||||
|
WHERE o.ID = %s
|
||||||
|
"""
|
||||||
|
cursor.execute(order_sql, (order_id,))
|
||||||
|
order_info = cursor.fetchone()
|
||||||
|
|
||||||
|
# 如果订单信息不存在,返回订单列表页面
|
||||||
|
if not order_info:
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
return redirect(url_for("order_list"))
|
||||||
|
|
||||||
|
# 查询乘客信息和票据信息
|
||||||
|
tickets_sql = """
|
||||||
|
SELECT t.*, p.Name, p.Phone_number
|
||||||
|
FROM Tickets t
|
||||||
|
JOIN Passengers p ON t.PassengerID = p.ID
|
||||||
|
WHERE t.OrderID = %s
|
||||||
|
"""
|
||||||
|
cursor.execute(tickets_sql, (order_id,))
|
||||||
|
tickets = cursor.fetchall()
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
total_price = sum(ticket['Price'] for ticket in tickets)
|
||||||
|
|
||||||
|
return render_template('order.html', order=order_info, tickets=tickets, total_price=total_price, username=g.name)
|
54
Project/Service/func/order_list.py
Normal file
54
Project/Service/func/order_list.py
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
from flask import render_template, request, redirect, url_for, g
|
||||||
|
from .config import db
|
||||||
|
import pymysql
|
||||||
|
|
||||||
|
def order_list():
|
||||||
|
if not g.user:
|
||||||
|
return redirect(url_for("login"))
|
||||||
|
|
||||||
|
conn = pymysql.connect(**db)
|
||||||
|
cursor = conn.cursor(pymysql.cursors.DictCursor)
|
||||||
|
|
||||||
|
# 查询用户关联的所有订单信息
|
||||||
|
orders_sql = """
|
||||||
|
SELECT o.ID as OrderID, o.Order_time, o.Paid, f.ID as FlightID, f.Airline,
|
||||||
|
d.Name as Departure_airport_name, a.Name as Arrival_airport_name,
|
||||||
|
f.Departure_time, f.Status, p.Name as PassengerName, t.Price
|
||||||
|
FROM Orders o
|
||||||
|
JOIN Tickets t ON o.ID = t.OrderID
|
||||||
|
JOIN Flights f ON t.FlightID = f.ID
|
||||||
|
JOIN Airports d ON f.Departure_airport = d.ID
|
||||||
|
JOIN Airports a ON f.Arrival_airport = a.ID
|
||||||
|
JOIN Passengers p ON t.PassengerID = p.ID
|
||||||
|
WHERE o.User_phone_number = %s
|
||||||
|
"""
|
||||||
|
cursor.execute(orders_sql, (g.user,))
|
||||||
|
orders = cursor.fetchall()
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
# 整理订单信息
|
||||||
|
order_dict = {}
|
||||||
|
for order in orders:
|
||||||
|
order_id = order['OrderID']
|
||||||
|
if order_id not in order_dict:
|
||||||
|
order_dict[order_id] = {
|
||||||
|
'OrderID': order_id,
|
||||||
|
'Order_time': order['Order_time'],
|
||||||
|
'Paid': order['Paid'],
|
||||||
|
'FlightID': order['FlightID'],
|
||||||
|
'Airline': order['Airline'],
|
||||||
|
'Departure_airport_name': order['Departure_airport_name'],
|
||||||
|
'Arrival_airport_name': order['Arrival_airport_name'],
|
||||||
|
'Departure_time': order['Departure_time'],
|
||||||
|
'Status': order['Status'],
|
||||||
|
'Passengers': [],
|
||||||
|
'TotalPrice': 0
|
||||||
|
}
|
||||||
|
order_dict[order_id]['Passengers'].append(order['PassengerName'])
|
||||||
|
order_dict[order_id]['TotalPrice'] += order['Price']
|
||||||
|
|
||||||
|
order_list = list(order_dict.values())
|
||||||
|
|
||||||
|
return render_template('order_list.html', orders=order_list, username=g.name)
|
30
Project/Service/func/pay_confirm.py
Normal file
30
Project/Service/func/pay_confirm.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
from flask import redirect, url_for, g, request
|
||||||
|
from .config import db
|
||||||
|
import pymysql
|
||||||
|
|
||||||
|
def pay_confirm():
|
||||||
|
order_id = request.args.get('order_id')
|
||||||
|
if not g.user:
|
||||||
|
return redirect(url_for("login"))
|
||||||
|
|
||||||
|
conn = pymysql.connect(**db)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# 检查订单是否存在
|
||||||
|
check_order_sql = "SELECT ID FROM Orders WHERE ID = %s"
|
||||||
|
cursor.execute(check_order_sql, (order_id,))
|
||||||
|
order_exists = cursor.fetchone()
|
||||||
|
|
||||||
|
if not order_exists:
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
return redirect(url_for("order_list"))
|
||||||
|
|
||||||
|
update_order_sql = "UPDATE Orders SET Paid = 1 WHERE ID = %s"
|
||||||
|
cursor.execute(update_order_sql, (order_id,))
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return redirect(url_for('order_list', order_id=order_id))
|
49
Project/Service/func/search.py
Normal file
49
Project/Service/func/search.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
from flask import render_template, request, g, abort, redirect, url_for
|
||||||
|
from .config import db
|
||||||
|
from .utils import get_cities
|
||||||
|
import pymysql
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
|
def search():
|
||||||
|
if not g.user:
|
||||||
|
return redirect(url_for("login"))
|
||||||
|
departure_city = request.args.get('departure')
|
||||||
|
destination_city = request.args.get('destination')
|
||||||
|
departure_date = request.args.get('departure-date')
|
||||||
|
passengers = int(request.args.get('passengers', 1))
|
||||||
|
|
||||||
|
# Date validation
|
||||||
|
try:
|
||||||
|
departure_date_obj = datetime.datetime.strptime(departure_date, '%Y-%m-%d').date()
|
||||||
|
if departure_date_obj < datetime.date.today():
|
||||||
|
abort(400, description="Departure date cannot be in the past.")
|
||||||
|
except ValueError:
|
||||||
|
abort(400, description="Invalid date format.")
|
||||||
|
|
||||||
|
conn = pymysql.connect(**db)
|
||||||
|
cursor = conn.cursor(pymysql.cursors.DictCursor)
|
||||||
|
|
||||||
|
search_sql = """
|
||||||
|
SELECT f.*, d.Name as Departure_airport_name, a.Name as Arrival_airport_name
|
||||||
|
FROM Flights f
|
||||||
|
JOIN Airports d ON f.Departure_airport = d.ID
|
||||||
|
JOIN Airports a ON f.Arrival_airport = a.ID
|
||||||
|
WHERE d.City = %s AND a.City = %s
|
||||||
|
AND DATE(f.Departure_time) = %s
|
||||||
|
AND (f.First_class_seats_remaining + f.Business_class_seats_remaining + f.Economy_class_seats_remaining) >= %s
|
||||||
|
AND f.Status NOT IN ('已起飞', '已降落');
|
||||||
|
"""
|
||||||
|
|
||||||
|
cursor.execute(search_sql, (departure_city, destination_city, departure_date, passengers))
|
||||||
|
flights = cursor.fetchall()
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
'search.html',
|
||||||
|
cities=get_cities(),
|
||||||
|
flights=flights,
|
||||||
|
username=g.name
|
||||||
|
)
|
@ -1,6 +1,7 @@
|
|||||||
from flask import render_template, request, redirect, url_for
|
from flask import render_template, request, redirect, url_for
|
||||||
from .get_db import get_db
|
from .config import db
|
||||||
import re
|
import re
|
||||||
|
import pymysql
|
||||||
|
|
||||||
def signup():
|
def signup():
|
||||||
error_messages = {
|
error_messages = {
|
||||||
@ -34,8 +35,8 @@ def signup():
|
|||||||
if any(error_messages.values()):
|
if any(error_messages.values()):
|
||||||
return render_template('signup.html', errors=error_messages)
|
return render_template('signup.html', errors=error_messages)
|
||||||
|
|
||||||
db = get_db()
|
conn = pymysql.connect(**db)
|
||||||
cursor = db.cursor()
|
cursor = conn.cursor(pymysql.cursors.DictCursor)
|
||||||
|
|
||||||
# 检查已有用户
|
# 检查已有用户
|
||||||
sql = """
|
sql = """
|
||||||
@ -44,7 +45,7 @@ def signup():
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
cursor.execute(sql, (phone_number,))
|
cursor.execute(sql, (phone_number,))
|
||||||
phone_exist = cursor.fetchall()[0][0]
|
phone_exist = cursor.fetchall()[0]['COUNT(*)']
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_messages['mobileNo'] = "数据库异常,查询失败"
|
error_messages['mobileNo'] = "数据库异常,查询失败"
|
||||||
print(e)
|
print(e)
|
||||||
@ -52,7 +53,7 @@ def signup():
|
|||||||
|
|
||||||
if phone_exist != 0:
|
if phone_exist != 0:
|
||||||
error_messages['mobileNo'] = "该手机号已注册,请勿重复注册"
|
error_messages['mobileNo'] = "该手机号已注册,请勿重复注册"
|
||||||
db.close()
|
conn.close()
|
||||||
return render_template('signup.html', errors=error_messages)
|
return render_template('signup.html', errors=error_messages)
|
||||||
|
|
||||||
# 插入
|
# 插入
|
||||||
@ -62,12 +63,12 @@ def signup():
|
|||||||
'''
|
'''
|
||||||
try:
|
try:
|
||||||
cursor.execute(sql, (phone_number, username, password))
|
cursor.execute(sql, (phone_number, username, password))
|
||||||
db.commit()
|
conn.commit()
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
db.rollback()
|
conn.rollback()
|
||||||
print(e)
|
print(e)
|
||||||
error_messages['mobileNo'] = "数据库异常,注册失败"
|
error_messages['mobileNo'] = "数据库异常,注册失败"
|
||||||
return render_template('signup.html', errors=error_messages)
|
return render_template('signup.html', errors=error_messages)
|
||||||
finally:
|
finally:
|
||||||
db.close()
|
conn.close()
|
20
Project/Service/func/utils.py
Normal file
20
Project/Service/func/utils.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from .config import db
|
||||||
|
import pymysql
|
||||||
|
from xpinyin import Pinyin
|
||||||
|
from pymysql.cursors import Cursor
|
||||||
|
|
||||||
|
def get_cities():
|
||||||
|
conn = pymysql.connect(**db)
|
||||||
|
cursor = conn.cursor(pymysql.cursors.DictCursor)
|
||||||
|
cursor.execute("SELECT DISTINCT City FROM Airports")
|
||||||
|
cities = [row['City'] for row in cursor.fetchall()]
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
p = Pinyin()
|
||||||
|
cities = [
|
||||||
|
(row, p.get_pinyin(row).replace("-", ""))
|
||||||
|
for row in cities
|
||||||
|
]
|
||||||
|
cities = sorted(cities, key=lambda x: x[1])
|
||||||
|
cities = [row[0] for row in cities]
|
||||||
|
return cities
|
@ -1,13 +1,19 @@
|
|||||||
from flask import Flask, redirect, url_for, session, render_template, request, g
|
from flask import Flask, redirect, url_for, session, g
|
||||||
from flask_httpauth import HTTPTokenAuth
|
from flask_httpauth import HTTPTokenAuth
|
||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
from func.config import db, SECRET_KEY, slideshow_images
|
from func.config import db, SECRET_KEY
|
||||||
import pymysql
|
import pymysql
|
||||||
|
|
||||||
import func.login
|
import func.login
|
||||||
import func.signup
|
import func.signup
|
||||||
import func.modify
|
import func.modify
|
||||||
import func.index
|
import func.index
|
||||||
|
import func.search
|
||||||
|
import func.book
|
||||||
|
import func.pay_confirm
|
||||||
|
import func.cancel_order
|
||||||
|
import func.order
|
||||||
|
import func.order_list
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config["SECRET_KEY"] = SECRET_KEY
|
app.config["SECRET_KEY"] = SECRET_KEY
|
||||||
@ -26,14 +32,14 @@ def before_request():
|
|||||||
conn = pymysql.connect(**db)
|
conn = pymysql.connect(**db)
|
||||||
cursor = conn.cursor(pymysql.cursors.DictCursor)
|
cursor = conn.cursor(pymysql.cursors.DictCursor)
|
||||||
args = (session.get('user_id'),)
|
args = (session.get('user_id'),)
|
||||||
verify_sql = "SELECT Phone_number, Username FROM Users WHERE Phone_number = %s;"
|
verify_sql = "SELECT Username FROM Users WHERE Phone_number = %s;"
|
||||||
cursor.execute(verify_sql, args)
|
cursor.execute(verify_sql, args)
|
||||||
res = cursor.fetchone()
|
res = cursor.fetchone()
|
||||||
if not res:
|
if not res:
|
||||||
g.user = None
|
g.user = None
|
||||||
g.name = None
|
g.name = None
|
||||||
else:
|
else:
|
||||||
g.user = res['Phone_number']
|
g.user = session.get('user_id')
|
||||||
g.name = res['Username']
|
g.name = res['Username']
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
@ -58,23 +64,35 @@ def signup():
|
|||||||
|
|
||||||
@app.route("/modify", methods=['GET', 'POST'])
|
@app.route("/modify", methods=['GET', 'POST'])
|
||||||
def modify():
|
def modify():
|
||||||
if request.method == 'GET':
|
|
||||||
if not g.user:
|
|
||||||
return redirect(url_for("login"))
|
|
||||||
return func.modify.modify()
|
return func.modify.modify()
|
||||||
|
|
||||||
@app.route("/search", methods=['GET'])
|
@app.route("/search", methods=['GET'])
|
||||||
def search():
|
def search():
|
||||||
# 处理搜索逻辑
|
return func.search.search()
|
||||||
return "搜索结果"
|
|
||||||
|
|
||||||
@app.route("/orders", methods=['GET', 'POST'])
|
@app.route("/book", methods=['GET', 'POST'])
|
||||||
def orders():
|
def book():
|
||||||
return "我的订单"
|
return func.book.book()
|
||||||
|
|
||||||
|
@app.route("/order", methods=['GET'])
|
||||||
|
def order():
|
||||||
|
return func.order.order()
|
||||||
|
|
||||||
|
@app.route('/cancel_order', methods=['POST'])
|
||||||
|
def cancel_order():
|
||||||
|
return func.cancel_order.cancel_order()
|
||||||
|
|
||||||
|
@app.route('/pay_confirm', methods=['POST'])
|
||||||
|
def pay_confirm():
|
||||||
|
return func.pay_confirm.pay_confirm()
|
||||||
|
|
||||||
|
@app.route("/order_list", methods=['GET', 'POST'])
|
||||||
|
def order_list():
|
||||||
|
return func.order_list.order_list()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(
|
app.run(
|
||||||
host="0.0.0.0",
|
host="0.0.0.0",
|
||||||
port=5000,
|
port=8888,
|
||||||
debug=True
|
debug=True
|
||||||
)
|
)
|
238
Project/Service/static/css/book.css
Normal file
238
Project/Service/static/css/book.css
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
padding: 20px;
|
||||||
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons a {
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons a:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu span {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropbtn {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
min-width: 160px;
|
||||||
|
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||||
|
z-index: 1;
|
||||||
|
right: 0; /* 确保下拉菜单靠右对齐 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content a {
|
||||||
|
color: black;
|
||||||
|
padding: 12px 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content a:hover {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown:hover .dropdown-content {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
flex: 1;
|
||||||
|
width: 80%;
|
||||||
|
margin: 20px auto;
|
||||||
|
padding-top: 80px; /* 给主内容增加顶部填充,以避免被固定导航栏遮挡 */
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
text-align: center;
|
||||||
|
color: #1c6cb2;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table, th, td {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flight-row {
|
||||||
|
transition: transform 0.3s ease, box-shadow 0.3s ease, border-radius 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flight-row:hover {
|
||||||
|
transform: scale(1.02);
|
||||||
|
box-shadow: 0 0 10px rgba(28, 108, 178, 0.5);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flight-info th, .flight-info td {
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.passenger {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
transition: transform 0.3s ease, box-shadow 0.3s ease, border-radius 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.passenger:hover {
|
||||||
|
transform: scale(1.02);
|
||||||
|
box-shadow: 0 0 10px rgba(28, 108, 178, 0.5);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.passenger h3 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-btn {
|
||||||
|
background-color: #ff4d4d;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 10px;
|
||||||
|
text-align: right;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, select {
|
||||||
|
flex: 2;
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: red;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.total-price {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: #1c6cb2;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 0;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
margin-top: auto; /* 将footer推到页面底部 */
|
||||||
|
}
|
@ -2,12 +2,9 @@ body {
|
|||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
background-color: #ffffff;
|
|
||||||
height: 100vh;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
min-height: 100vh;
|
||||||
overflow-x: hidden; /* 防止出现水平滚动条 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
@ -18,6 +15,9 @@ header {
|
|||||||
color: white;
|
color: white;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-content {
|
.header-content {
|
||||||
@ -99,10 +99,17 @@ header {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
margin: 20px auto;
|
||||||
|
padding-top: 80px; /* 给主内容增加顶部填充,以避免被固定导航栏遮挡 */
|
||||||
|
}
|
||||||
|
|
||||||
.slides {
|
.slides {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 400px;
|
height: 620px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +141,7 @@ header {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
margin: -50px auto 20px;
|
margin: -170px auto 20px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,12 +152,12 @@ header {
|
|||||||
|
|
||||||
.form-row {
|
.form-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: flex-start; /* Left-align the form items */
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-row label {
|
.form-row label {
|
||||||
flex: 1;
|
flex: 0 0 120px; /* Fixed width for labels */
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
@ -158,13 +165,17 @@ header {
|
|||||||
|
|
||||||
.form-row input,
|
.form-row input,
|
||||||
.form-row select {
|
.form-row select {
|
||||||
flex: 2;
|
flex: 1;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-row.form-row-center {
|
||||||
|
justify-content: center; /* Center-align the button */
|
||||||
|
}
|
||||||
|
|
||||||
.passenger-input {
|
.passenger-input {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -208,18 +219,19 @@ header {
|
|||||||
background-color: #155a8c;
|
background-color: #155a8c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: red;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 5px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
background-color: rgba(28, 108, 178, 0.9);
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
color: white;
|
color: white;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: auto;
|
position: relative;
|
||||||
}
|
margin-top: auto; /* 将footer推到页面底部 */
|
||||||
|
|
||||||
.error-message {
|
|
||||||
color: red;
|
|
||||||
font-size: 12px;
|
|
||||||
text-align: left;
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
}
|
@ -2,18 +2,22 @@ body {
|
|||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
background-color: #ffffff;
|
|
||||||
height: 100vh;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
background-color: rgba(28, 108, 178, 0.9);
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
color: white;
|
color: white;
|
||||||
padding: 20px 0;
|
padding: 20px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-content {
|
.header-content {
|
||||||
@ -50,11 +54,9 @@ header {
|
|||||||
|
|
||||||
main {
|
main {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
width: 80%;
|
||||||
align-items: center;
|
margin: 20px auto;
|
||||||
justify-content: center;
|
padding-top: 80px; /* 给主内容增加顶部填充,以避免被固定导航栏遮挡 */
|
||||||
width: 100%;
|
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
@ -64,6 +66,7 @@ main {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
width: 400px;
|
width: 400px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
@ -141,4 +144,6 @@ footer {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
margin-top: auto; /* 将footer推到页面底部 */
|
||||||
}
|
}
|
191
Project/Service/static/css/order.css
Normal file
191
Project/Service/static/css/order.css
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
padding: 20px;
|
||||||
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons a {
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons a:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu span {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropbtn {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
min-width: 160px;
|
||||||
|
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||||
|
z-index: 1;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content a {
|
||||||
|
color: black;
|
||||||
|
padding: 12px 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content a:hover {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown:hover .dropdown-content {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
flex: 1;
|
||||||
|
width: 80%;
|
||||||
|
margin: 20px auto;
|
||||||
|
padding-top: 80px; /* 给主内容增加顶部填充,以避免被固定导航栏遮挡 */
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
text-align: center;
|
||||||
|
color: #1c6cb2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-info, .passenger-info, .order-summary {
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-info p, .order-summary p {
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
table, th, td {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: #1c6cb2;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-btn {
|
||||||
|
background-color: #ff4d4d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-btn:hover {
|
||||||
|
background-color: #cc0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-btn {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
color: black;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-btn:hover {
|
||||||
|
background-color: #d9d9d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 0;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
margin-top: auto; /* 将footer推到页面底部 */
|
||||||
|
}
|
151
Project/Service/static/css/order_list.css
Normal file
151
Project/Service/static/css/order_list.css
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
padding: 20px;
|
||||||
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons a {
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons a:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu span {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropbtn {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
min-width: 160px;
|
||||||
|
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||||
|
z-index: 1;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content a {
|
||||||
|
color: black;
|
||||||
|
padding: 12px 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content a:hover {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown:hover .dropdown-content {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
flex: 1;
|
||||||
|
width: 80%;
|
||||||
|
margin: 20px auto;
|
||||||
|
padding-top: 80px; /* 给主内容增加顶部填充,以避免被固定导航栏遮挡 */
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
text-align: center;
|
||||||
|
color: #1c6cb2;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table, th, td {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 0;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
margin-top: auto; /* 将footer推到页面底部 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-row {
|
||||||
|
transition: transform 0.3s ease, box-shadow 0.3s ease, border-radius 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-row:hover {
|
||||||
|
transform: scale(1.02);
|
||||||
|
box-shadow: 0 0 10px rgba(28, 108, 178, 0.5);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
251
Project/Service/static/css/search.css
Normal file
251
Project/Service/static/css/search.css
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
padding: 20px;
|
||||||
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons a {
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons a:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu span {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropbtn {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
min-width: 160px;
|
||||||
|
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||||
|
z-index: 1;
|
||||||
|
right: 0; /* 确保下拉菜单靠右对齐 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content a {
|
||||||
|
color: black;
|
||||||
|
padding: 12px 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content a:hover {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown:hover .dropdown-content {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
flex: 1;
|
||||||
|
width: 80%;
|
||||||
|
margin: 20px auto;
|
||||||
|
padding-top: 80px; /* 给主内容增加顶部填充,以避免被固定导航栏遮挡 */
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
text-align: center;
|
||||||
|
color: #1c6cb2;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table, th, td {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-results {
|
||||||
|
text-align: center;
|
||||||
|
color: red;
|
||||||
|
font-size: 18px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 0;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
margin-top: auto; /* 将footer推到页面底部 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
text-align: center;
|
||||||
|
width: 80%;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 20px auto;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabcontent {
|
||||||
|
display: block;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start; /* Left-align the form items */
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row label {
|
||||||
|
flex: 0 0 120px; /* Fixed width for labels */
|
||||||
|
margin-right: 10px;
|
||||||
|
text-align: right;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row input,
|
||||||
|
.form-row select {
|
||||||
|
flex: 1;
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row.form-row-center {
|
||||||
|
justify-content: center; /* Center-align the button */
|
||||||
|
}
|
||||||
|
|
||||||
|
.passenger-input {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.passenger-input button {
|
||||||
|
padding: 5px 10px;
|
||||||
|
font-size: 18px;
|
||||||
|
background-color: #1c6cb2;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.passenger-input button:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.passenger-input input {
|
||||||
|
width: 50px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 16px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: #1c6cb2;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: red;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 5px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add animations for flight rows */
|
||||||
|
.flight-row {
|
||||||
|
transition: transform 0.3s ease, box-shadow 0.3s ease, border-radius 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flight-row:hover {
|
||||||
|
transform: scale(1.02);
|
||||||
|
box-shadow: 0 0 10px rgba(28, 108, 178, 0.5);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
42
Project/Service/static/js/search.js
Normal file
42
Project/Service/static/js/search.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
function validateForm() {
|
||||||
|
var departure = document.getElementById('departure').value;
|
||||||
|
var destination = document.getElementById('destination').value;
|
||||||
|
var warning = document.getElementById('destination-warning');
|
||||||
|
if (departure === destination) {
|
||||||
|
warning.textContent = '出发地和目的地不能相同';
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
warning.textContent = '';
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function increment() {
|
||||||
|
var passengers = document.getElementById("passengers");
|
||||||
|
var value = parseInt(passengers.value, 10);
|
||||||
|
if (value < 50) {
|
||||||
|
passengers.value = value + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function decrement() {
|
||||||
|
var passengers = document.getElementById("passengers");
|
||||||
|
var value = parseInt(passengers.value, 10);
|
||||||
|
if (value > 1) {
|
||||||
|
passengers.value = value - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Set default date to tomorrow
|
||||||
|
var departureDate = document.getElementById('departure-date');
|
||||||
|
if (!departureDate.value) {
|
||||||
|
var today = new Date();
|
||||||
|
var tomorrow = new Date(today);
|
||||||
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||||
|
var month = ('0' + (tomorrow.getMonth() + 1)).slice(-2);
|
||||||
|
var day = ('0' + tomorrow.getDate()).slice(-2);
|
||||||
|
var year = tomorrow.getFullYear();
|
||||||
|
departureDate.value = `${year}-${month}-${day}`;
|
||||||
|
}
|
||||||
|
});
|
281
Project/Service/templates/book.html
Normal file
281
Project/Service/templates/book.html
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>航班预定</title>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/book.css') }}">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="header-content">
|
||||||
|
<div class="logo">KJF航班订票</div>
|
||||||
|
<div class="nav-buttons">
|
||||||
|
<a href="{{ url_for('index') }}">首页</a>
|
||||||
|
<a href="{{ url_for('order_list') }}">我的订单</a>
|
||||||
|
</div>
|
||||||
|
<div class="user-menu">
|
||||||
|
<span>{{ username }}</span>
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="dropbtn">▼</button>
|
||||||
|
<div class="dropdown-content">
|
||||||
|
<a href="{{ url_for('modify') }}">修改账户信息</a>
|
||||||
|
<a href="{{ url_for('logout') }}">退出登录</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<h2>预定航班</h2>
|
||||||
|
<div class="flight-info">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>航班号</th>
|
||||||
|
<th>航空公司</th>
|
||||||
|
<th>出发机场</th>
|
||||||
|
<th>到达机场</th>
|
||||||
|
<th>出发时间</th>
|
||||||
|
<th>到达时间</th>
|
||||||
|
<th>头等舱剩余座位</th>
|
||||||
|
<th>商务舱剩余座位</th>
|
||||||
|
<th>经济舱剩余座位</th>
|
||||||
|
<th>头等舱价格</th>
|
||||||
|
<th>商务舱价格</th>
|
||||||
|
<th>经济舱价格</th>
|
||||||
|
<th>状态</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr class="flight-row">
|
||||||
|
<td>{{ flight.ID }}</td>
|
||||||
|
<td>{{ flight.Airline }}</td>
|
||||||
|
<td>{{ flight.Departure_airport_name }}</td>
|
||||||
|
<td>{{ flight.Arrival_airport_name }}</td>
|
||||||
|
<td>{{ flight.Departure_time }}</td>
|
||||||
|
<td>{{ flight.Arrival_time }}</td>
|
||||||
|
<td id="first-class-seats">{{ flight.First_class_seats_remaining }}</td>
|
||||||
|
<td id="business-class-seats">{{ flight.Business_class_seats_remaining }}</td>
|
||||||
|
<td id="economy-class-seats">{{ flight.Economy_class_seats_remaining }}</td>
|
||||||
|
<td id="first-class-price">{{ flight.First_class_price }}</td>
|
||||||
|
<td id="business-class-price">{{ flight.Business_class_price }}</td>
|
||||||
|
<td id="economy-class-price">{{ flight.Economy_class_price }}</td>
|
||||||
|
<td>{{ flight.Status }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<form id="booking-form" method="post" action="{{ url_for('book', flight_id=flight.ID) }}" onsubmit="return validateBookingForm()">
|
||||||
|
<div id="passenger-list">
|
||||||
|
<div class="passenger" data-index="0">
|
||||||
|
<h3>乘机人 1</h3>
|
||||||
|
<button type="button" class="delete-btn" onclick="removePassenger(this)">删除</button>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="card-code-0">身份证号:</label>
|
||||||
|
<input type="text" id="card-code-0" name="passengers[0][card_code]" oninput="validateCardCode(this)">
|
||||||
|
<div class="error-message" id="card-code-error-0"></div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="name-0">真实姓名:</label>
|
||||||
|
<input type="text" id="name-0" name="passengers[0][name]">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="phone-number-0">手机号:</label>
|
||||||
|
<input type="text" id="phone-number-0" name="passengers[0][phone_number]" oninput="validatePhoneNumber(this)">
|
||||||
|
<div class="error-message" id="phone-number-error-0"></div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="seat-class-0">座位级别:</label>
|
||||||
|
<select id="seat-class-0" name="passengers[0][seat_class]" onchange="updateSeatCount(this)">
|
||||||
|
<option value="" disabled selected>请选择座位级别</option>
|
||||||
|
<option value="First Class">头等舱</option>
|
||||||
|
<option value="Business Class">商务舱</option>
|
||||||
|
<option value="Economy Class">经济舱</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="total-price">
|
||||||
|
总价: <span id="total-price">0</span> 元
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn" onclick="addPassenger()">添加乘机人</button>
|
||||||
|
<button type="submit" class="btn">预定</button>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
<p>© 2024 KJF航班订票. 保留所有权利。</p>
|
||||||
|
</footer>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Initialize seat counts
|
||||||
|
var passengerCount = 1;
|
||||||
|
var firstClassSeats = {{ flight.First_class_seats_remaining }};
|
||||||
|
var businessClassSeats = {{ flight.Business_class_seats_remaining }};
|
||||||
|
var economyClassSeats = {{ flight.Economy_class_seats_remaining }};
|
||||||
|
var firstClassPrice = parseFloat(document.getElementById("first-class-price").textContent);
|
||||||
|
var businessClassPrice = parseFloat(document.getElementById("business-class-price").textContent);
|
||||||
|
var economyClassPrice = parseFloat(document.getElementById("economy-class-price").textContent);
|
||||||
|
|
||||||
|
window.addPassenger = function() {
|
||||||
|
passengerCount++;
|
||||||
|
const passengerList = document.getElementById('passenger-list');
|
||||||
|
const passengerDiv = document.createElement('div');
|
||||||
|
passengerDiv.classList.add('passenger');
|
||||||
|
passengerDiv.setAttribute('data-index', passengerCount - 1);
|
||||||
|
|
||||||
|
const disabledFirstClass = firstClassSeats <= 0 ? 'disabled' : '';
|
||||||
|
const disabledBusinessClass = businessClassSeats <= 0 ? 'disabled' : '';
|
||||||
|
const disabledEconomyClass = economyClassSeats <= 0 ? 'disabled' : '';
|
||||||
|
|
||||||
|
passengerDiv.innerHTML = `
|
||||||
|
<h3>乘机人 ${passengerCount}</h3>
|
||||||
|
<button type="button" class="delete-btn" onclick="removePassenger(this)">删除</button>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="card-code-${passengerCount - 1}">身份证号:</label>
|
||||||
|
<input type="text" id="card-code-${passengerCount - 1}" name="passengers[${passengerCount - 1}][card_code]" oninput="validateCardCode(this)">
|
||||||
|
<div class="error-message" id="card-code-error-${passengerCount - 1}"></div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="name-${passengerCount - 1}">真实姓名:</label>
|
||||||
|
<input type="text" id="name-${passengerCount - 1}" name="passengers[${passengerCount - 1}][name]">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="phone-number-${passengerCount - 1}">手机号:</label>
|
||||||
|
<input type="text" id="phone-number-${passengerCount - 1}" name="passengers[${passengerCount - 1}][phone_number]" oninput="validatePhoneNumber(this)">
|
||||||
|
<div class="error-message" id="phone-number-error-${passengerCount - 1}"></div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="seat-class-${passengerCount - 1}">座位级别:</label>
|
||||||
|
<select id="seat-class-${passengerCount - 1}" name="passengers[${passengerCount - 1}][seat_class]" onchange="updateSeatCount(this)">
|
||||||
|
<option value="" disabled selected>请选择座位级别</option>
|
||||||
|
<option value="First Class" ${disabledFirstClass}>头等舱</option>
|
||||||
|
<option value="Business Class" ${disabledBusinessClass}>商务舱</option>
|
||||||
|
<option value="Economy Class" ${disabledEconomyClass}>经济舱</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
passengerList.appendChild(passengerDiv);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.removePassenger = function(button) {
|
||||||
|
const passengerDiv = button.parentElement;
|
||||||
|
const index = passengerDiv.getAttribute('data-index');
|
||||||
|
const seatClassSelect = document.getElementById(`seat-class-${index}`);
|
||||||
|
const seatClass = seatClassSelect.value;
|
||||||
|
|
||||||
|
if (seatClass === 'First Class') firstClassSeats++;
|
||||||
|
else if (seatClass === 'Business Class') businessClassSeats++;
|
||||||
|
else if (seatClass === 'Economy Class') economyClassSeats++;
|
||||||
|
|
||||||
|
passengerDiv.remove();
|
||||||
|
updateSeatDisplay();
|
||||||
|
calculateTotalPrice();
|
||||||
|
};
|
||||||
|
|
||||||
|
window.validateCardCode = function(input) {
|
||||||
|
const regexCardCode = /^([1-6][1-9]|50)\d{4}(18|19|20)\d{2}((0[1-9])|10|11|12)(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;
|
||||||
|
const errorDiv = document.getElementById(`card-code-error-${input.id.split('-')[2]}`);
|
||||||
|
if (!regexCardCode.test(input.value)) {
|
||||||
|
errorDiv.textContent = '身份证号格式不正确';
|
||||||
|
} else {
|
||||||
|
errorDiv.textContent = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.validatePhoneNumber = function(input) {
|
||||||
|
const regexMobileNo = /^1[3-9]\d{9}$/;
|
||||||
|
const errorDiv = document.getElementById(`phone-number-error-${input.id.split('-')[2]}`);
|
||||||
|
if (!regexMobileNo.test(input.value)) {
|
||||||
|
errorDiv.textContent = '手机号格式不正确';
|
||||||
|
} else {
|
||||||
|
errorDiv.textContent = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.updateSeatCount = function(select) {
|
||||||
|
const index = select.id.split('-')[2];
|
||||||
|
const previousClass = select.getAttribute("data-previous-class");
|
||||||
|
const newClass = select.value;
|
||||||
|
|
||||||
|
if (previousClass) {
|
||||||
|
if (previousClass === 'First Class') firstClassSeats++;
|
||||||
|
else if (previousClass === 'Business Class') businessClassSeats++;
|
||||||
|
else if (previousClass === 'Economy Class') economyClassSeats++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newClass === 'First Class') {
|
||||||
|
if (firstClassSeats <= 0) {
|
||||||
|
alert("头等舱座位已满");
|
||||||
|
select.value = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
firstClassSeats--;
|
||||||
|
} else if (newClass === 'Business Class') {
|
||||||
|
if (businessClassSeats <= 0) {
|
||||||
|
alert("商务舱座位已满");
|
||||||
|
select.value = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
businessClassSeats--;
|
||||||
|
} else if (newClass === 'Economy Class') {
|
||||||
|
if (economyClassSeats <= 0) {
|
||||||
|
alert("经济舱座位已满");
|
||||||
|
select.value = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
economyClassSeats--;
|
||||||
|
}
|
||||||
|
|
||||||
|
select.setAttribute("data-previous-class", newClass);
|
||||||
|
updateSeatDisplay();
|
||||||
|
calculateTotalPrice();
|
||||||
|
};
|
||||||
|
|
||||||
|
function updateSeatDisplay() {
|
||||||
|
document.getElementById("first-class-seats").textContent = firstClassSeats;
|
||||||
|
document.getElementById("business-class-seats").textContent = businessClassSeats;
|
||||||
|
document.getElementById("economy-class-seats").textContent = economyClassSeats;
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateTotalPrice() {
|
||||||
|
let totalPrice = 0;
|
||||||
|
const seatClassSelects = document.querySelectorAll("select[id^='seat-class-']");
|
||||||
|
seatClassSelects.forEach(select => {
|
||||||
|
if (select.value === 'First Class') totalPrice += firstClassPrice;
|
||||||
|
else if (select.value === 'Business Class') totalPrice += businessClassPrice;
|
||||||
|
else if (select.value === 'Economy Class') totalPrice += economyClassPrice;
|
||||||
|
});
|
||||||
|
document.getElementById("total-price").textContent = totalPrice.toFixed(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.validateBookingForm = function() {
|
||||||
|
// Validate seat availability
|
||||||
|
if (firstClassSeats < 0 || businessClassSeats < 0 || economyClassSeats < 0) {
|
||||||
|
alert("预定的座位数不能超过余座数");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate all card codes and phone numbers
|
||||||
|
const cardCodes = document.querySelectorAll("input[id^='card-code-']");
|
||||||
|
const phoneNumbers = document.querySelectorAll("input[id^='phone-number-']");
|
||||||
|
for (let cardCode of cardCodes) {
|
||||||
|
validateCardCode(cardCode);
|
||||||
|
if (document.getElementById(`card-code-error-${cardCode.id.split('-')[2]}`).textContent !== '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let phoneNumber of phoneNumbers) {
|
||||||
|
validatePhoneNumber(phoneNumber);
|
||||||
|
if (document.getElementById(`phone-number-error-${phoneNumber.id.split('-')[2]}`).textContent !== '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
146
Project/Service/templates/index.html
Normal file
146
Project/Service/templates/index.html
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>KJF航班订票</title>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}">
|
||||||
|
<script src="{{ url_for('static', filename='js/index.js') }}" defer></script>
|
||||||
|
<script src="https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="header-content">
|
||||||
|
<div class="logo">KJF航班订票</div>
|
||||||
|
<div class="nav-buttons">
|
||||||
|
<a href="{{ url_for('index') }}">首页</a>
|
||||||
|
<a href="{{ url_for('order_list') }}">我的订单</a>
|
||||||
|
</div>
|
||||||
|
<div class="user-menu">
|
||||||
|
<span>{{ username }}</span>
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="dropbtn">▼</button>
|
||||||
|
<div class="dropdown-content">
|
||||||
|
<a href="{{ url_for('modify') }}">修改账户信息</a>
|
||||||
|
<a href="{{ url_for('logout') }}">退出登录</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<div class="slides">
|
||||||
|
<ul id="slide-container">
|
||||||
|
{% for image in images %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ image.link }}" target="_blank">
|
||||||
|
<img src="{{ image.src }}">
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div id="ticket" class="tabcontent" style="display: block;">
|
||||||
|
<form action="{{ url_for('search') }}" method="get" class="search-form" onsubmit="return validateForm()">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="departure">出发地:</label>
|
||||||
|
<select id="departure" name="departure">
|
||||||
|
{% for city in cities %}
|
||||||
|
<option value="{{ city }}" {% if city == "北京" %}selected{% endif %}>{{ city }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="destination">目的地:</label>
|
||||||
|
<select id="destination" name="destination">
|
||||||
|
{% for city in cities %}
|
||||||
|
<option value="{{ city }}" {% if city == "上海" %}selected{% endif %}>{{ city }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<div id="destination-warning" class="error-message"></div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="departure-date">出发日期:</label>
|
||||||
|
<input type="date" id="departure-date" name="departure-date" required>
|
||||||
|
<div id="date-warning" class="error-message"></div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="passengers">乘客人数:</label>
|
||||||
|
<div class="passenger-input">
|
||||||
|
<button type="button" onclick="decrement()">-</button>
|
||||||
|
<input type="number" id="passengers" name="passengers" value="1" min="1" max="50">
|
||||||
|
<button type="button" onclick="increment()">+</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row form-row-center">
|
||||||
|
<button type="submit" class="btn">立即查询</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
<p>© 2024 KJF航班订票. 保留所有权利。</p>
|
||||||
|
</footer>
|
||||||
|
<script src="{{ url_for('static', filename='js/slideshow.js') }}"></script>
|
||||||
|
<script>
|
||||||
|
function validateForm() {
|
||||||
|
var departure = document.getElementById('departure').value;
|
||||||
|
var destination = document.getElementById('destination').value;
|
||||||
|
var warning = document.getElementById('destination-warning');
|
||||||
|
var dateWarning = document.getElementById('date-warning');
|
||||||
|
var departureDate = document.getElementById('departure-date').value;
|
||||||
|
|
||||||
|
var today = new Date();
|
||||||
|
var selectedDate = new Date(departureDate);
|
||||||
|
today.setHours(0, 0, 0, 0); // Ensure time comparison is not affected
|
||||||
|
|
||||||
|
if (departure === destination) {
|
||||||
|
warning.textContent = '出发地和目的地不能相同';
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
warning.textContent = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedDate < today) {
|
||||||
|
dateWarning.textContent = '出发日期不能早于今天';
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
dateWarning.textContent = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function increment() {
|
||||||
|
var passengers = document.getElementById("passengers");
|
||||||
|
var value = parseInt(passengers.value, 10);
|
||||||
|
if (value < 50) {
|
||||||
|
passengers.value = value + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function decrement() {
|
||||||
|
var passengers = document.getElementById("passengers");
|
||||||
|
var value = parseInt(passengers.value, 10);
|
||||||
|
if (value > 1) {
|
||||||
|
passengers.value = value - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Set default date to tomorrow
|
||||||
|
var departureDate = document.getElementById('departure-date');
|
||||||
|
var today = new Date();
|
||||||
|
var tomorrow = new Date(today);
|
||||||
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||||
|
var month = ('0' + (tomorrow.getMonth() + 1)).slice(-2);
|
||||||
|
var day = ('0' + tomorrow.getDate()).slice(-2);
|
||||||
|
var year = tomorrow.getFullYear();
|
||||||
|
departureDate.value = `${year}-${month}-${day}`;
|
||||||
|
departureDate.setAttribute('min', `${year}-${month}-${day}`);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
83
Project/Service/templates/order.html
Normal file
83
Project/Service/templates/order.html
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>订单详情</title>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/order.css') }}">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="header-content">
|
||||||
|
<div class="logo">KJF航班订票</div>
|
||||||
|
<div class="nav-buttons">
|
||||||
|
<a href="{{ url_for('index') }}">首页</a>
|
||||||
|
<a href="{{ url_for('order_list') }}">我的订单</a>
|
||||||
|
</div>
|
||||||
|
<div class="user-menu">
|
||||||
|
<span>{{ username }}</span>
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="dropbtn">▼</button>
|
||||||
|
<div class="dropdown-content">
|
||||||
|
<a href="{{ url_for('modify') }}">修改账户信息</a>
|
||||||
|
<a href="{{ url_for('logout') }}">退出登录</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<button onclick="location.href='{{ url_for('order_list') }}'" class="back-btn">返回订单列表</button>
|
||||||
|
<h2>订单详情</h2>
|
||||||
|
<div class="order-info">
|
||||||
|
<h3>航班信息</h3>
|
||||||
|
<p>航班号: {{ order.FlightID }}</p>
|
||||||
|
<p>航空公司: {{ order.Airline }}</p>
|
||||||
|
<p>出发机场: {{ order.Departure_airport_name }}</p>
|
||||||
|
<p>到达机场: {{ order.Arrival_airport_name }}</p>
|
||||||
|
<p>出发时间: {{ order.Departure_time }}</p>
|
||||||
|
<p>状态: {{ order.Status }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="passenger-info">
|
||||||
|
<h3>乘机人信息</h3>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>身份证号</th>
|
||||||
|
<th>姓名</th>
|
||||||
|
<th>手机号</th>
|
||||||
|
<th>座位级别</th>
|
||||||
|
<th>票价</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for ticket in tickets %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ ticket.PassengerID }}</td>
|
||||||
|
<td>{{ ticket.Name }}</td>
|
||||||
|
<td>{{ ticket.Phone_number }}</td>
|
||||||
|
<td>{{ ticket.Seat_class }}</td>
|
||||||
|
<td>{{ ticket.Price }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="order-summary">
|
||||||
|
<p>订单总价: {{ total_price }}</p>
|
||||||
|
<p>支付状态: {% if order.Paid %}已支付{% else %}未支付{% endif %}</p>
|
||||||
|
</div>
|
||||||
|
<form method="post" action="{{ url_for('cancel_order', order_id=order.ID) }}">
|
||||||
|
<button type="submit" class="btn cancel-btn">取消订单</button>
|
||||||
|
</form>
|
||||||
|
{% if not order.Paid %}
|
||||||
|
<form method="post" action="{{ url_for('pay_confirm', order_id=order.ID) }}">
|
||||||
|
<button type="submit" class="btn pay-btn">支付订单</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
<p>© 2024 KJF航班订票. 保留所有权利。</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
72
Project/Service/templates/order_list.html
Normal file
72
Project/Service/templates/order_list.html
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>我的订单</title>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/order_list.css') }}">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="header-content">
|
||||||
|
<div class="logo">KJF航班订票</div>
|
||||||
|
<div class="nav-buttons">
|
||||||
|
<a href="{{ url_for('index') }}">首页</a>
|
||||||
|
<a href="{{ url_for('order_list') }}">我的订单</a>
|
||||||
|
</div>
|
||||||
|
<div class="user-menu">
|
||||||
|
<span>{{ username }}</span>
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="dropbtn">▼</button>
|
||||||
|
<div class="dropdown-content">
|
||||||
|
<a href="{{ url_for('modify') }}">修改账户信息</a>
|
||||||
|
<a href="{{ url_for('logout') }}">退出登录</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<h2>我的订单</h2>
|
||||||
|
<div class="order-list">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>航班号</th>
|
||||||
|
<th>航空公司</th>
|
||||||
|
<th>出发机场</th>
|
||||||
|
<th>到达机场</th>
|
||||||
|
<th>出发时间</th>
|
||||||
|
<th>状态</th>
|
||||||
|
<th>乘机人</th>
|
||||||
|
<th>订单总价</th>
|
||||||
|
<th>支付状态</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for order in orders %}
|
||||||
|
<tr class="order-row" onclick="location.href='{{ url_for('order', order_id=order.OrderID) }}'">
|
||||||
|
<td>{{ order.FlightID }}</td>
|
||||||
|
<td>{{ order.Airline }}</td>
|
||||||
|
<td>{{ order.Departure_airport_name }}</td>
|
||||||
|
<td>{{ order.Arrival_airport_name }}</td>
|
||||||
|
<td>{{ order.Departure_time }}</td>
|
||||||
|
<td>{{ order.Status }}</td>
|
||||||
|
<td>
|
||||||
|
{% for passenger in order.Passengers %}
|
||||||
|
{{ passenger }}<br>
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
<td>{{ order.TotalPrice }}</td>
|
||||||
|
<td>{% if order.Paid %}已支付{% else %}未支付{% endif %}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
<p>© 2024 KJF航班订票. 保留所有权利。</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
179
Project/Service/templates/search.html
Normal file
179
Project/Service/templates/search.html
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>航班搜索结果</title>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/search.css') }}">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="header-content">
|
||||||
|
<div class="logo">KJF航班订票</div>
|
||||||
|
<div class="nav-buttons">
|
||||||
|
<a href="{{ url_for('index') }}">首页</a>
|
||||||
|
<a href="{{ url_for('order_list') }}">我的订单</a>
|
||||||
|
</div>
|
||||||
|
<div class="user-menu">
|
||||||
|
<span>{{ username }}</span>
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="dropbtn">▼</button>
|
||||||
|
<div class="dropdown-content">
|
||||||
|
<a href="{{ url_for('modify') }}">修改账户信息</a>
|
||||||
|
<a href="{{ url_for('logout') }}">退出登录</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<div class="content">
|
||||||
|
<div id="ticket" class="tabcontent" style="display: block;">
|
||||||
|
<form action="{{ url_for('search') }}" method="get" class="search-form" onsubmit="return validateForm()">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="departure">出发地:</label>
|
||||||
|
<select id="departure" name="departure">
|
||||||
|
{% for city in cities %}
|
||||||
|
<option value="{{ city }}" {% if city == request.args.get('departure') %}selected{% endif %}>{{ city }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="destination">目的地:</label>
|
||||||
|
<select id="destination" name="destination">
|
||||||
|
{% for city in cities %}
|
||||||
|
<option value="{{ city }}" {% if city == request.args.get('destination') %}selected{% endif %}>{{ city }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<div id="destination-warning" class="error-message"></div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="departure-date">出发日期:</label>
|
||||||
|
<input type="date" id="departure-date" name="departure-date" value="{{ request.args.get('departure-date', '') }}" required>
|
||||||
|
<div id="date-warning" class="error-message"></div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="passengers">乘客人数:</label>
|
||||||
|
<div class="passenger-input">
|
||||||
|
<button type="button" onclick="decrement()">-</button>
|
||||||
|
<input type="number" id="passengers" name="passengers" value="{{ request.args.get('passengers', 1) }}" min="1" max="50">
|
||||||
|
<button type="button" onclick="increment()">+</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row form-row-center">
|
||||||
|
<button type="submit" class="btn">立即查询</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>航班搜索结果</h2>
|
||||||
|
{% if flights %}
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>航班号</th>
|
||||||
|
<th>航空公司</th>
|
||||||
|
<th>出发机场</th>
|
||||||
|
<th>到达机场</th>
|
||||||
|
<th>出发时间</th>
|
||||||
|
<th>到达时间</th>
|
||||||
|
<th>头等舱剩余座位</th>
|
||||||
|
<th>商务舱剩余座位</th>
|
||||||
|
<th>经济舱剩余座位</th>
|
||||||
|
<th>头等舱价格</th>
|
||||||
|
<th>商务舱价格</th>
|
||||||
|
<th>经济舱价格</th>
|
||||||
|
<th>状态</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for flight in flights %}
|
||||||
|
<tr class="flight-row" onclick="window.location.href='{{ url_for('book', flight_id=flight.ID) }}'">
|
||||||
|
<td>{{ flight.ID }}</td>
|
||||||
|
<td>{{ flight.Airline }}</td>
|
||||||
|
<td>{{ flight.Departure_airport_name }}</td>
|
||||||
|
<td>{{ flight.Arrival_airport_name }}</td>
|
||||||
|
<td>{{ flight.Departure_time }}</td>
|
||||||
|
<td>{{ flight.Arrival_time }}</td>
|
||||||
|
<td>{{ flight.First_class_seats_remaining }}</td>
|
||||||
|
<td>{{ flight.Business_class_seats_remaining }}</td>
|
||||||
|
<td>{{ flight.Economy_class_seats_remaining }}</td>
|
||||||
|
<td>{{ flight.First_class_price }}</td>
|
||||||
|
<td>{{ flight.Business_class_price }}</td>
|
||||||
|
<td>{{ flight.Economy_class_price }}</td>
|
||||||
|
<td>{{ flight.Status }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<p class="no-results">没有找到符合条件的航班。</p>
|
||||||
|
{% endif %}
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
<p>© 2024 KJF航班订票. 保留所有权利。</p>
|
||||||
|
</footer>
|
||||||
|
<script src="{{ url_for('static', filename='js/search.js') }}"></script>
|
||||||
|
<script>
|
||||||
|
function validateForm() {
|
||||||
|
var departure = document.getElementById('departure').value;
|
||||||
|
var destination = document.getElementById('destination').value;
|
||||||
|
var warning = document.getElementById('destination-warning');
|
||||||
|
var dateWarning = document.getElementById('date-warning');
|
||||||
|
var departureDate = document.getElementById('departure-date').value;
|
||||||
|
|
||||||
|
var today = new Date();
|
||||||
|
var selectedDate = new Date(departureDate);
|
||||||
|
today.setHours(0, 0, 0, 0); // Ensure time comparison is not affected
|
||||||
|
|
||||||
|
if (departure === destination) {
|
||||||
|
warning.textContent = '出发地和目的地不能相同';
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
warning.textContent = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedDate < today) {
|
||||||
|
dateWarning.textContent = '出发日期不能早于今天';
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
dateWarning.textContent = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function increment() {
|
||||||
|
var passengers = document.getElementById("passengers");
|
||||||
|
var value = parseInt(passengers.value, 10);
|
||||||
|
if (value < 50) {
|
||||||
|
passengers.value = value + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function decrement() {
|
||||||
|
var passengers = document.getElementById("passengers");
|
||||||
|
var value = parseInt(passengers.value, 10);
|
||||||
|
if (value > 1) {
|
||||||
|
passengers.value = value - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Set default date to tomorrow
|
||||||
|
var departureDate = document.getElementById('departure-date');
|
||||||
|
if (!departureDate.value) {
|
||||||
|
var today = new Date();
|
||||||
|
var tomorrow = new Date(today);
|
||||||
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||||
|
var month = ('0' + (tomorrow.getMonth() + 1)).slice(-2);
|
||||||
|
var day = ('0' + tomorrow.getDate()).slice(-2);
|
||||||
|
var year = tomorrow.getFullYear();
|
||||||
|
departureDate.value = `${year}-${month}-${day}`;
|
||||||
|
departureDate.setAttribute('min', `${year}-${month}-${day}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,7 +0,0 @@
|
|||||||
import pymysql
|
|
||||||
|
|
||||||
def get_db():
|
|
||||||
return pymysql.connect(
|
|
||||||
host='localhost', user='kejingfan',
|
|
||||||
password='KJF2811879', database='TESTDB'
|
|
||||||
)
|
|
@ -1,17 +0,0 @@
|
|||||||
import pymysql
|
|
||||||
|
|
||||||
db = pymysql.connect(
|
|
||||||
host='localhost', user='kejingfan',
|
|
||||||
password='KJF2811879', database='TESTDB'
|
|
||||||
)
|
|
||||||
|
|
||||||
cursor = db.cursor()
|
|
||||||
|
|
||||||
with open('db.sql', 'r') as f:
|
|
||||||
sql_commands = f.read().split(';')
|
|
||||||
for command in sql_commands:
|
|
||||||
if command.strip(): # 确保不执行空命令
|
|
||||||
cursor.execute(command)
|
|
||||||
|
|
||||||
db.close()
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user