ElasticSearch_Hotel/target/classes/static/index.html

540 lines
22 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>黑马旅游</title>
<link rel="stylesheet" href="https://a.amap.com/jsapi_demos/static/demo-center/css/demo-center.css"/>
<link rel="stylesheet" href="./css/index.css"/>
<link rel="stylesheet" href="./css/banner.css"/>
</head>
<body>
<div id="app" @click="showOps=false">
<div style="width: 70%;text-align: center;margin: auto;">
<div class="banner">
<div class="logo">
<img src="./img/heima.png" alt="1"/>
<span>
<div class="logo-ch">黑马旅游</div>
<div class="logo-en">www.itheima.com</div>
</span>
</div>
<div >
<input type="checkbox" id="toggle-button" v-model="isTest">
<!--label中的for跟input的id绑定。作用是在点击label时选中input或者取消选中input-->
<label for="toggle-button" class="button-label">
<span class="circle"></span>
<span class="text on">测试</span>
<span class="text off">正式</span>
</label>
</div>
</div>
<!--关键字搜索-->
<div class="search-bar">
<div class="input-box">
<input title="输入关键字搜索酒店" v-model="params.key" type="text" @click.stop="" @focus="showOps=true"
@keyup="handleKeyUp($event)">
<button @click="handleSearch">搜索</button>
</div>
<div id="complete-box" v-show="showOps && ops.length > 0">
<div v-for="(item, i) in ops" :key="i" @click="handleSearch" @mouseover="opsIndex = i"
:style='{"background-color": opsIndex===i ? "#EEE" : "#fff"}'>{{item}}
</div>
</div>
</div>
<!-- 已选择过滤项 -->
<div class="selected-ops">
<div class="open">全部结果:</div>
<div class="selected-op" v-for="(v, k) in params.filters" :key="k" @click="deleteFilter(k)">
{{filterNames[k]}}<span>{{v}} <span class='close'>×</span></span>
</div>
</div>
<!--过滤项-->
<div class="filter-list">
<div v-for="(v, k) in remainFilter" :key="k">
<div class="filter-box">
<div class="f-key"><strong>{{filterNames[k]}}</strong></div>
<div class="column-divider"></div>
<div class="f-items">
<div class="f-item" @click="clickFilter(k, o)" v-for="(o, j) in v" :key="j"><a href="javascript:void(0)">
{{o}}</a></div>
</div>
</div>
<div class="row-divider"></div>
</div>
<div class="filter-box">
<div class="f-key"><strong>价格</strong></div>
<div class="column-divider"></div>
<div class="f-items">
<div class="f-item" @click="clickFilter('price','0-100')"><a href="javascript:void(0)">100元以下</a></div>
<div class="f-item" @click="clickFilter('price','100-300')"><a href="javascript:void(0)">100-300元</a></div>
<div class="f-item" @click="clickFilter('price','300-600')"><a href="javascript:void(0)">300-600元</a></div>
<div class="f-item" @click="clickFilter('price','600-1500')"><a href="javascript:void(0)">600-1500元</a></div>
<div class="f-item" @click="clickFilter('price','1500-0')"><a href="javascript:void(0)">1500元以上</a></div>
</div>
</div>
</div>
<!-- 排序 -->
<div class="top-ban">
<!--排序条件-->
<div class="sort-items">
<div class="sort-item" v-for="(item, i) in sortItems" :key="i">
<a :class="{selected: params.sortBy===item.key}" @click="params.sortBy=item.key"
href="javascript:void(0)">{{item.text}}</a>
|
</div>
</div>
<!--分页条-->
<div class="top-pagination">
<span><i style="color: #222;">{{total}}</i> 家酒店</span>
<span><i style="color: red;">{{params.page}}</i>/{{totalPage}}</span>
<a class="btn-arrow" href="#" style="display: inline-block" @click="prePage">&lt;</a>
<a class="btn-arrow" href="#" style="display: inline-block" @click="nextPage">&gt;</a>
</div>
</div>
<div class="row-divider" style="margin-bottom: 5px; width: 100%"></div>
<!--酒店列表-->
<div style="display: flex; justify-content: space-between;">
<div class="hotel-list">
<div class="hotel-box" v-for="(hotel,i) in hotels" :key="i"
style="display: flex;justify-content: space-between;" @mouseover="handleMarkerFocus(hotel)">
<div class="ad-mark" v-if="hotel.isAD">
<img src="./img/ad.png" width="25"/>
</div>
<div style="width: 0;"></div>
<div style="width: 25%"><img width="100%" :src="hotel.pic"></div>
<div class="hotel-info">
<div class="hotel-name" v-html="hotel.name">
</div>
<div class="star-name"> {{hotel.starName}}</div>
<div class="address">
位于 <span style="color: #BC8516;">{{hotel.business}}</span> 周边,{{hotel.address}}
</div>
<div class="order"> 1分钟前有人预订了该酒店</div>
<div v-if="hotel.distance" class="address">距离您 {{hotel.distance.toFixed(2)}} km</div>
</div>
<div style="text-align: left; width: 15%;">
<div>
<b style="color: #f60;"></b> <span id='hotel-price'>{{hotel.price}}</span> <span
style="font-size: 0.2em; color: #999;"></span>
</div>
<div class='btn'>立即预定</div>
<div>
<span class="hotel-score">{{hotel.score / 10}}分</span> /<span>5分</span>
</div>
</div>
</div>
</div>
<div :class='{"map-box": true, "fixed-map": isFixed}' :style="{left: ml + 'px'}">
<div class="map-head">地图预览</div>
<div class="amap" id="container"></div>
<div class="map-geo" @click="getGeoLoc">
<img src="https://a.amap.com/jsapi/static/image/plugin/waite.png" v-show="loading">
</div>
</div>
</div>
</div>
</div>
<script src="./js/vue.js"></script>
<script src="./js/axios.min.js"></script>
<script src="./js/amap.min.js"></script>
<script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key=ddd292c88aa1bad9c04891a47724f40a"></script>
<script>
// 设置后台服务地址
axios.defaults.baseURL = "http://localhost:8089";
axios.defaults.timeout = 3000;
let app = new Vue({
el: "#app",
data: {
isTest: false,
filterNames: {
brand: "品牌",
city: "城市",
starName: "星级",
price: "价格",
},
filterList: {},// 过滤项的假数据
sortItems: [
{
key: "default",
text: "默认",
},
{
key: "score",
text: "评价",
},
{
key: "price",
text: "价格",
}
],// 排序字段的假数据
hotels: [],// 酒店数据
total: 0, // 总条数
totalPage: 0, // 总页数
params: {
key: "", // 搜索关键字
page: 1, // 当前页码
size: 5, // 每页大小
sortBy: "default",// 排序字段
filters: {}, // 过滤字段
},
map: {},// 地图对象
loc: "", // 地图标记
ml: 0, // 控制地图位置
geolocation:{}, // 定位系统
loading: false, // 是否在定位
currentHotel: {},
ops: [],
showOps: false,
opsIndex: -1,
isFixed: false,
testFilterData: {
"city": ["上海", "北京", "深圳", "杭州"],
"starName": ["四星","五星","二钻","三钻","四钻","五钻"],
"brand": ["7天酒店", "如家","速8", "皇冠假日","华美达","万怡","喜来登","万豪","和颐","希尔顿"],
},
},
watch: {
"params.sortBy"() {
// 每当page改变当前代码就会执行。搜索一下
this.search(this.loc);
},
"params.page"() {
// 每当page改变当前代码就会执行。搜索一下
this.search(this.loc);
},
"params.filters": {
deep: true,
handler() {
this.search();
// 获取过滤项
this.getFilter();
}
},
opsIndex() {
if (this.opsIndex !== -1) {
this.params.key = this.ops[this.opsIndex]
}
}
},
created() {
// 页面加载时,先搜索一下
this.search();
// 获取过滤项
this.getFilter();
},
mounted() {
//初始化地图
this.map = new AMap.Map('container', {
resizeEnable: true, //是否监控地图容器尺寸变化
zoom: 11, //初始地图级别
center: [120.0, 32.0], //初始地图中心点
});
// 初始化定位系统
AMap.plugin('AMap.Geolocation', () => {
this.geolocation = new AMap.Geolocation({
position: 'RT', //定位按钮的停靠位置
buttonOffset: new AMap.Pixel(10, 20),//定位按钮与设置的停靠位置的偏移量默认Pixel(10, 20)
zoomToAccuracy: true, //定位成功后是否自动调整地图视野到定位点
});
// AMap.Event.addListener(geolocation, 'complete', result => {
// if (this.params.page !== 1) {
// this.params.page = 1;
// this.loc = result.position.lat + ", " + result.position.lng;
// } else {
// this.searchByMap(result.position.lat + ", " + result.position.lng);
// }
//
// });//返回定位信息
// AMap.Event.addListener(geolocation, 'error', err => console.log(err)); //返回定位出错信息
});
let oDiv = document.querySelector(".map-box"),
H = 0,
Y = oDiv;
while (Y) {
H += Y.offsetTop;
Y = Y.offsetParent;
}
window.addEventListener('scroll', () => this.handleScroll(H, oDiv));
},
methods: {
handleScroll(h, o) {
let s = document.body.scrollTop || document.documentElement.scrollTop
this.isFixed = s > h;
this.ml = o.offsetLeft;
},
handleKeyUp(e) {
if ((e.keyCode >= 48 && e.keyCode <= 57) || (e.keyCode >= 65 && e.keyCode <= 90) || e.keyCode === 8) {
// 用户输入的字符,需要自动补全
this.getSuggestion();
} else if (e.keyCode === 13) {
// 用户按回车,需要搜索
this.search();
this.getFilter();
} else if (e.keyCode === 38) {
if (this.opsIndex > 0) {
this.opsIndex--;
} else {
this.opsIndex = this.ops.length - 1;
}
} else if (e.keyCode === 40) {
this.opsIndex = (this.opsIndex + 1) % this.ops.length;
} else if (e.keyCode === 27) {
this.show = false
}
},
handleSearch(){
this.search();
this.getFilter();
},
getSuggestion() { // 查询自动补全
if (!this.params.key) {
// key没有值不去搜索了
this.ops = [];
return;
}
axios.get("/hotel/suggestion?key=" + this.params.key)
.then(resp => {
this.ops = resp.data;
})
.catch(e => {
if(this.isTest){
this.ops = ["万豪", "如家", "喜来登"]
}else{
this.ops = []
}
console.log(e);
})
},
getFilter() {
if(this.isTest){
this.filterList = this.testFilterData;
return;
}
// 准备参数
const {filters: {price: ps, ... fs}, ...params} = this.params;
for( _k in fs){
params[_k] = fs[_k];
}
// 处理价格
if(ps){
let pArr = ps.split("-");
params.minPrice = parseInt(pArr[0]);
let max = parseInt(pArr[1]);
params.maxPrice = max === 0 ? 999999 : max;
}
axios.post("/hotel/filters", params)
.then(resp => {
this.filterList = resp.data;
})
.catch(err => {
console.log(err);
this.filterList = this.testFilterData;
})
},
searchByMap(location) {
// 准备参数
const {filters: {price: ps, ... fs}, ...params} = this.params;
for( _k in fs){
params[_k] = fs[_k];
}
// 处理价格
if(ps){
let pArr = ps.split("-");
params.minPrice = parseInt(pArr[0]);
let max = parseInt(pArr[1]);
params.maxPrice = max === 0 ? 999999 : max;
}
// 准备地址
if (location) {
params.location = location;
this.loc = location;
}
axios.post("/hotel/list", params)
.then(resp => {
if(!resp.data.hotels){
this.hotels = resp.data;
this.total = 271;
this.totalPage = 28;
}else{
this.hotels = resp.data.hotels;
this.total = resp.data.total;
this.totalPage = Math.ceil((this.total + 5 - 1) / 5);
}
if (location) {
this.setMapCenter(location);
} else {
this.setMapCenter(this.hotels[0].location);
}
this.initMarker();
})
.catch(err => {
console.log(err)
this.hotels = [{"id":60223,"name":"上海希尔顿酒店","address":"静安华山路250号","price":2688,"score":37,"brand":"希尔顿","city":"上海","starName":"五星级","business":"静安寺地区","location":"31.219306, 121.445427","pic":"https://m.tuniucdn.com/filebroker/cdn/res/92/10/9210e74442aceceaf6e196d61fc3b6b1_w200_h200_c1_t0.jpg"},{"id":60922,"name":"上海虹桥祥源希尔顿酒店","address":"红松东路1116号","price":1108,"score":45,"brand":"希尔顿","city":"上海","starName":"五钻","business":"虹桥地区","location":"31.18746, 121.395312","pic":"https://m.tuniucdn.com/fb3/s1/2n9c/tQRqDTFkHnHzMZiDKjcGV81ekvc_w200_h200_c1_t0.jpg"},{"id":309208,"name":"北京王府井希尔顿酒店","address":"王府井东街8号","price":1679,"score":46,"brand":"希尔顿","city":"北京","starName":"五钻","business":"天安门/王府井地区","location":"39.914539, 116.413392","pic":"https://m.tuniucdn.com/fb2/t1/G6/M00/52/10/Cii-TF3ePt2IX9UEAALb6VYBSmoAAGKMgGsuW8AAtwB147_w200_h200_c1_t0.jpg"},{"id":395434,"name":"北京希尔顿酒店","address":"东三环北路东方路1号","price":350,"score":45,"brand":"希尔顿","city":"北京","starName":"五星级","business":"燕莎/朝阳公园商业区","location":"39.952703, 116.462387","pic":"https://m.tuniucdn.com/fb3/s1/2n9c/3fwNbKGhk6XCrkdVyxwhC5uGpLVy_w200_h200_c1_t0.jpg"},{"id":395702,"name":"北京首都机场希尔顿酒店","address":"首都机场3号航站楼三经路1号","price":222,"score":46,"brand":"希尔顿","city":"北京","starName":"五钻","business":"首都机场/新国展地区","location":"40.048969, 116.619566","pic":"https://m.tuniucdn.com/fb2/t1/G6/M00/52/10/Cii-U13ePtuIMRSjAAFZ58NGQrMAAGKMgADZ1QAAVn_167_w200_h200_c1_t0.jpg"},{"id":615175,"name":"千岛湖滨江希尔顿度假酒店","address":"环湖北路600号","price":1265,"score":47,"brand":"希尔顿","city":"杭州","starName":"五钻","business":"千岛湖镇","location":"29.603634, 119.077596","pic":"https://m.tuniucdn.com/fb3/s1/2n9c/6qzYeUrrXsH5H3cd9bMXLz8MJtT_w200_h200_c1_t0.jpg"},{"id":2351601,"name":"深圳蛇口希尔顿南海酒店","address":"望海路1177号","price":509,"score":47,"brand":"希尔顿","city":"深圳","starName":"五钻","business":"深圳湾口岸/蛇口","location":"22.479373, 113.916013","pic":"https://m.tuniucdn.com/fb2/t1/G6/M00/45/EA/Cii-TF3ZpXOIfa6fAAJjiUOiuYgAAFrtgDtgpQAAmOh799_w200_h200_c1_t0.jpg"},{"id":368701368,"name":"深圳大中华希尔顿酒店","address":"福田深南大道1003号","price":1666,"score":46,"brand":"希尔顿","city":"深圳","starName":"五钻","business":"会展中心/CBD","location":"22.539313, 114.069763","pic":"https://m.tuniucdn.com/fb3/s1/2n9c/4EnHseZ73LXdFJY7DSdJ8xqAcjXe_w200_h200_c1_t0.jpg"},{"id":2048042240,"name":"北京大兴希尔顿酒店","address":"高米店南里18号楼","price":1283,"score":48,"brand":"希尔顿","city":"北京","starName":"五钻","business":"大兴北京新机场地区","location":"39.76875, 116.339199","pic":"https://m.tuniucdn.com/fb3/s1/2n9c/3B32F8zSU2CJCWzs1hoH2o4WcquR_w200_h200_c1_t0.jpg"},{"id":2056105938,"name":"北京通州北投希尔顿酒店","address":"新华东街289号2号楼","price":1068,"score":48,"brand":"希尔顿","city":"北京","starName":"五钻","business":"果园环岛/通州区","location":"39.908805, 116.659748","pic":"https://m.tuniucdn.com/fb3/s1/2n9c/NGKdpec3tZJNUUNWJ5pd67Cp5AY_w200_h200_c1_t0.png"}]
this.total = 271;
this.totalPage = 28;
})
},
search(location) {
// 发送ajax
this.searchByMap(location);
},
prePage() {
if (this.params.page > 1) {
this.params.page--
}
},
nextPage() {
if (this.params.page < this.totalPage) {
this.params.page++
}
},
clickPrice(min, max) {
this.params.minPrice = min;
this.params.maxPrice = max;
},
clickFilter(key, option) {
this.loc = "";
const {...obj} = this.params.filters;
obj[key] = option;
this.params.filters = obj;
},
deleteFilter(k) {
this.loc = "";
const {...obj} = this.params.filters;
delete obj[k];
this.params.filters = obj;
},
location(loc) {
let arr = loc.split(", ");
let json = '[' + arr[1] + ', ' + arr[0] + ']'
return JSON.parse(json);
},
initMarker() {
if (!this.loc) {
this.map.clearMap();
}
this.markHotels();
},
setMapCenter(location){
this.map.setCenter(this.location(location));
},
markHotels(){
this.hotels.forEach((h, i) => {
// 将创建的点标记添加到已有的地图实例:
let marker = new AMap.Marker({
position: this.location(h.location), // 经纬度构成的一维数组[116.39, 39.9]
title: h.name,
offset: new AMap.Pixel(0, 0),
anchor:'bottom-center'
});
marker.vid = h.id;
this.map.add(marker);
});
},
handleMarkerFocus(h) {
this.map.setCenter(this.location(h.location));
let old = this.currentHotel;
let oldMarker = this.map.getAllOverlays("marker").find(m => m.vid === old.id);
if (oldMarker) {
this.updateMarker(oldMarker, "//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png", "", this.location(old.location), old.id);
}
this.currentHotel = h;
let marker = this.map.getAllOverlays("marker").find(m => m.vid === h.id);
this.updateMarker(marker, "//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-red.png", h.name, this.location(h.location), h.id);
},
updateMarker(marker, icon, text, position, id) {
// 自定义点标记内容
var markerContent = document.createElement("div");
// 点标记中的图标
var markerImg = document.createElement("img");
markerImg.className = "markerlnglat";
markerImg.src = icon;
markerImg.setAttribute('width', '25px');
markerImg.setAttribute('height', '34px');
markerContent.appendChild(markerImg);
// 点标记中的文本
if (text) {
var markerSpan = document.createElement("span");
markerSpan.className = 'marker';
markerSpan.innerHTML = text;
markerContent.appendChild(markerSpan);
}
marker.setContent(markerContent);
marker.setPosition(position);
marker.vid = id;
},
getGeoLoc(){
this.loading = true;
this.geolocation.getCurrentPosition((status,result) => {
this.loading = false;
if(status === 'complete'){
console.log("successs")
// https://a.amap.com/jsapi/static/image/plugin/point.png
this.addMaker('//a.amap.com/jsapi/static/image/plugin/point.png', result.position.lng,result.position.lat);
if (this.params.page !== 1) {
this.params.page = 1;
this.loc = result.position.lat + ", " + result.position.lng;
} else {
this.searchByMap(result.position.lat + ", " + result.position.lng);
}
}else{
console.log("err", status)
}
});
},
addMaker(iconUrl, lng, lat){
// 创建 AMap.Icon 实例:
let icon = new AMap.Icon({
size: new AMap.Size(25, 25), // 图标尺寸
image: iconUrl, // Icon的图像
imageOffset: new AMap.Pixel(0, 0), // 图像相对展示区域的偏移量,适于雪碧图等
imageSize: new AMap.Size(25, 25) // 根据所设置的大小拉伸或压缩图片
});
// 将 Icon 实例添加到 marker 上:
let marker = new AMap.Marker({
position: new AMap.LngLat(lng, lat),
offset: new AMap.Pixel(0, 0),
icon: icon, // 添加 Icon 实例
title: '北京',
zoom: 13,
anchor:"center"
});
this.map.add(marker);
}
},
computed: {
remainFilter() {
let keys = Object.keys(this.params.filters);
let obj = {};
Object.keys(this.filterList).forEach(key => {
if (!keys.includes(key) && this.filterList[key].length > 1) {
obj[key] = this.filterList[key];
}
})
return obj;
}
}
})
</script>
</body>
</html>