UNPKG

client-search

Version:

客户端搜索

633 lines (556 loc) 17.5 kB
// tslint:disable-next-line:no-reference ///<reference path="index.d.ts" /> import { isString } from 'lodash'; import Controller from './Controller'; export default class ClientSearch extends Controller implements ClientSearchBase { public params: HouseListParams = { pageNum: 0, pageSize: 10, }; /** * 【强调!!!】获取位置成功后,必须手动设置当前位置的经纬度 * * @type {ILocationBaseParams} * @memberof ClientSearch */ public currentGeoLocation?: IGeolocationParams; public houseList: IHouseDetail[] = []; public mapHouseList: IHouseDetail[] = []; public recommendHouseList: IHouseDetail[] = []; /** * 用于显示当前选中的定位位置 * * @type {string} * @memberof ClientSearch */ public geoLocationCityName: string = ''; /** * 当前搜索地图时使用的最表 * * @type {string} * @memberof ClientSearch */ public mapCoord: IGeolocationParams | null = null; /** * 本次查询是否有下一页 (不包含地图查询 + 推荐查询) * * @type {boolean} * @memberof ClientSearch */ public hasNext: boolean = true; /** * 用户输入了的关键字 * * @type {string} * @memberof ClientSearch */ public inputKeywork: string = ''; get houseListIsEmpty() { return this.houseList.length; } constructor(protected option: IOptions) { super(option); } /** * 设置当前位置信息 * * @param {ILocationBaseParams} geo 定位数据, 包含经纬度 * @memberof ClientSearch */ public async setCurrentGeoLocation(geo: ILocationBaseParams) { this.currentGeoLocation = geo || {}; this.currentGeoLocation.cityName = await this.getCoordCityName(geo); } /** * 用户通过关键字查找 * * @param {string} keyword * @returns {Promise<[IAmapTips[], IHouseDetail[]]>} * @memberof ClientSearch */ public async onInputKeyword( keyword: string, ): Promise<[Array<IAmapTips | null>, IHouseDetail[], IApiListResponse<IHouseDetail>]> { const [addressResult, houseList] = await Promise.all([ this.service.batchSearchAddress(keyword), this.service.fetchHouseList({ keyword, pageSize: 5 }), ]); const tuples: [Array<IAmapTips | null>, IHouseDetail[], IApiListResponse<IHouseDetail>] = [[], [], {} as any]; tuples[0] = addressResult; tuples[1] = houseList.list; tuples[2] = houseList; this.inputKeywork = keyword; return tuples; } /** * 通过位置坐标房源 * * 与位置冲突,需要清空 areaCode, 坐标 * 有 location 无需使用 cityName 和 cityCode 查找 * @param {IGeolocationParams} params * @returns {Promise<IHouseDetail[]>} * @memberof ClientSearch */ public async searchByGeolocation(params: IGeolocationParams): Promise<IHouseDetail[]> { this.clearParams([ 'areaCode', 'areaName', 'longitude', 'latitude', 'keyword', 'secondLatitude', 'secondLongitude', // 无需使用城市+code 查找 'cityName', 'cityCode', ]); this.clearFilter(); this.params.pageNum = 1; this.params.latitude = params.latitude; this.params.longitude = params.longitude; this.params.distance = 6; this.geoLocationCityName = await this.getCoordCityName(params); const houseList = await this.fetchHouseListWithParams(); if (!houseList.length) { // 查询推荐房源 this.searchRecommendHouses(); } return houseList; } /** * 查找符合关键字的所有房源 * * 与坐标冲突,需要删除坐标 * @param {string} keyword 关键字 * @returns {Promise<IHouseDetail[]>} * @memberof ClientSearch */ public async searchByKeyword(keyword: string): Promise<IHouseDetail[]> { this.clearParams([ 'areaCode', 'areaName', 'longitude', 'latitude', 'keyword', 'secondLatitude', 'secondLongitude', // 无需使用城市+code 查找 'cityName', 'cityCode', ]); this.clearFilter(); this.params.pageNum = 1; this.params.keyword = keyword; this.params.keywordDummy = keyword; const houseList = await this.fetchHouseListWithParams(); if (!houseList.length) { // 查询推荐房源 this.searchRecommendHouses(); } return houseList; } /** * 通过日期查找房源 * * @param {IDateParams} date * @returns {Promise<IHouseDetail[]>} * @memberof ClientSearch */ public async searchByDate(date: IDateParams): Promise<IHouseDetail[]> { this.params.pageNum = 1; this.params.beginDate = date.beginDate; this.params.endDate = date.endDate; const houseList = await this.fetchHouseListWithParams(true); if (!houseList.length) { // 查询推荐房源 await this.searchRecommendHouses(); } return houseList; } /** * 通过筛选查找房源 * * @param {IFilterParams} filterCondition 筛选条件 * @param {boolean} [byMap=false] 是否查询地图 * @returns {Promise<IHouseDetail[]>} * @memberof ClientSearch */ public async searchByFilter(filterCondition: IFilterParams, byMap: boolean = false): Promise<IHouseDetail[]> { this.clearFilter(); this.params.pageNum = 1; this.params = { ...this.params, ...filterCondition }; const houseList = await this.fetchHouseListWithParams(true); if (byMap) { await this.searchMap(); } if (!houseList.length) { this.searchRecommendHouses(); } return houseList; } /** * 通过选中位置查询 * * 选中位置后需要清除关键字等数据 * @param {ILocationParams} params * @param {boolean} [byMap=false] * @returns {Promise<IHouseDetail[]>} * @memberof ClientSearch */ public async searchByLocation(locationParams: ILocationParams, byMap: boolean = false): Promise<IHouseDetail[]> { this.clearParams(['areaCode', 'areaName']); this.params.pageNum = 1; this.params = { ...this.params, ...locationParams }; const houseList = await this.fetchHouseListWithParams(true); if (byMap) { await this.searchMap(); } if (!houseList.length) { this.searchRecommendHouses(); } return houseList; } /** * 通过排序查询 * * 先清空所有排序方式 * @param {ISortParams} sortParams * @returns {Promise<IHouseDetail[]>} * @memberof ClientSearch */ public async searchBySort(sortParams: ISortParams): Promise<IHouseDetail[]> { this.clearParams(['starsSort', 'distanceSort', 'priceSort', 'rankingSort']); this.params.pageNum = 1; this.params = { ...this.params, ...sortParams }; const houseList = await this.fetchHouseListWithParams(true); if (!houseList.length) { this.searchRecommendHouses(); } return houseList; } /** * 通过城市查找房源 * * 先清空所有定位字段 * @param {ISortParams} sortParams * @returns {Promise<IHouseDetail[]>} * @memberof ClientSearch */ public async searchByCity(cityParams: ICityParams): Promise<IHouseDetail[]> { this.clearFilter(); this.clearParams(['longitude', 'latitude', 'secondLatitude', 'secondLongitude', 'areaCode', 'areaName', 'keyword']); this.geoLocationCityName = cityParams.cityName || ''; this.params.pageNum = 1; this.params = { ...this.params, ...cityParams }; const houseList = await this.fetchHouseListWithParams(); if (!houseList.length) { this.searchRecommendHouses(); } return houseList; } /** * 通过行政区编码查找 * * 先清空所有定位字段 * @param {ISortParams} sortParams * @returns {Promise<IHouseDetail[]>} * @memberof ClientSearch */ public async searchByAreaCode(areaCode: string, byMap: boolean = false): Promise<IHouseDetail[]> { this.clearFilter(); this.clearParams([ 'longitude', 'latitude', 'secondLatitude', 'secondLongitude', 'areaCode', 'areaName', 'keyword', 'cityName', 'cityCode', ]); this.params.pageNum = 1; this.params.areaCode = areaCode; if (byMap) { await this.searchMap(); } const houseList = await this.fetchHouseListWithParams(); if (!houseList.length) { this.searchRecommendHouses(); } return houseList; } /** * 通过行政区编码查找 * * 先清空所有定位字段 * @param {ISortParams} sortParams * @returns {Promise<IHouseDetail[]>} * @memberof ClientSearch */ public async immediatelySearchByAreaCode(areaCode: string, byMap: boolean = false): Promise<IHouseDetail[]> { this.clearFilter(); this.clearParams([ 'longitude', 'latitude', 'secondLatitude', 'secondLongitude', 'areaCode', 'areaName', 'keyword', 'cityName', 'cityCode', ]); this.params.pageNum = 1; this.params.areaCode = areaCode; if (byMap) { await this.searchMap(); } const houseList = await this.fetchHouseListWithParams(true); if (!houseList.length) { this.searchRecommendHouses(); } return houseList; } /** * 在地图上找房 * * 位置 & 筛选均需要先调用对应的查询方法 * * searchWithLocation() * searchMap() * @returns {Promise<[ILocationBaseParams, IHouseDetail[]]>} * @memberof ClientSearch */ public async searchMap(): Promise<[IGeolocationParams | null, IHouseDetail[]]> { const getCoord = async (): Promise<IGeolocationParams | null> => { let coord: IGeolocationParams | null = null; // 用户搜索了区域,通过区域查出区域经纬度 if (this.params.areaCode) { coord = await this.service.districtToCoordinates(this.params.areaCode); if (coord) return coord; coord = await this.service.districtToCoordinates(this.params.areaName); if (coord) return coord; return null; } // 用户搜索了指定位置 if (this.params.longitude && this.params.latitude) { return { longitude: this.params.longitude, latitude: this.params.latitude }; } // 用户搜索了城市 if (this.params.cityName) { coord = await this.service.districtToCoordinates(this.params.cityName); return coord; } // 其余情况则使用用户当前位置查询 return this.currentGeoLocation || null; }; try { const currentCoord = await getCoord(); const coord: IGeolocationParams = { ...currentCoord }; if (this.params.cityName) { coord.cityName = this.params.cityName; } // 获取城市名 if (!coord.cityName) { const response = await this.service.georegeo(coord); if (response && isString(response.city)) { coord.cityName = response.city; } if (!coord.cityName && response && isString(response.province)) { coord.cityName = response.province; } } const hosueList = await this.service.fetchHouseList({ ...coord, allTagIds: this.params.allTagIds, bedNumberGreaterThanEqual: this.params.bedNumberGreaterThanEqual, bizTagIds: this.params.bizTagIds, customTagIds: this.params.customTagIds, distance: 6, pageSize: 30, priceGreaterThanEqual: this.params.priceGreaterThanEqual, priceLessThanEqual: this.params.priceLessThanEqual, roomNumberGreaterThanEqual: this.params.roomNumberGreaterThanEqual, tenantNumberGreaterThanEqual: this.params.tenantNumberGreaterThanEqual, }); this.mapHouseList = hosueList.list; this.mapCoord = coord; return [coord, hosueList.list]; } catch (error) { return [null, []]; } } /** * 通过坐标查询地图上的数据 * * @param {ILocationBaseParams} coord 坐标 * @returns {Promise<[ILocationBaseParams, IHouseDetail[]]>} * @memberof ClientSearch */ public async searchMapWithCoord(coord: ILocationBaseParams): Promise<[ILocationBaseParams | null, IHouseDetail[]]> { try { const hosueList = await this.service.fetchHouseList({ ...coord, allTagIds: this.params.allTagIds, bedNumberGreaterThanEqual: this.params.bedNumberGreaterThanEqual, bizTagIds: this.params.bizTagIds, customTagIds: this.params.customTagIds, distance: 6, pageSize: 30, priceGreaterThanEqual: this.params.priceGreaterThanEqual, priceLessThanEqual: this.params.priceLessThanEqual, roomNumberGreaterThanEqual: this.params.roomNumberGreaterThanEqual, tenantNumberGreaterThanEqual: this.params.tenantNumberGreaterThanEqual, }); this.mapHouseList = hosueList.list; return [coord, hosueList.list]; } catch (error) { return [null, []]; } } /** * 通过业务标签 ID 查询 * * @param {ILocationBaseParams} bizTagIds 标签 * @param {ILocationBaseParams} params 一些额外的参数 * @returns {Promise<[ILocationBaseParams, IHouseDetail[]]>} * @memberof ClientSearch */ public async searchByTagIds(bizTagIds: string, params: HouseListParams): Promise<IHouseDetail[]> { this.clearFilter(); try { this.params = { ...this.params, ...params, allTagIds: bizTagIds, bizTagIds }; const houseList = await this.fetchHouseListWithParams(true); if (!houseList.length) { this.searchRecommendHouses(); } return houseList; } catch (error) { return []; } } /** * 加载指定页的房源数据 */ public loadDataByPageNum(pageNum: number) { this.params.pageNum = pageNum; return this.fetchHouseListWithParams(true); } /** * 加载下一页的房源数据 */ public loadNextPageData() { if (!this.hasNext) return; return this.loadDataByPageNum((this.params.pageNum || 1) + 1); } /** * 加载第一页的房源数据 */ public loadFirstPageData() { return this.loadDataByPageNum(1); } /** * 查询推荐房源,当前查询为空时调用该方法 * * @private 私有方法,无需手动调用 * @returns {Promise<IHouseDetail[]>} * @memberof ClientSearch */ private async searchRecommendHouses(location?: ILocationBaseParams): Promise<IHouseDetail[]> { // 1. 如果有查询城市直接查询当前城市的 // 2. 前一个步骤查询失败,查询当前位置的房源 // 3. 前一个步骤查询失败,通过位置查出当前位置所属城市的房源 // 4. 如果当前城市没有房源,则查询全国房源 const houseList: IHouseDetail[] = []; if (location) { const response = await this.service.fetchHouseList({ cityCode: this.params.cityCode, pageSize: 10, recommend: true, }); houseList.unshift.apply(houseList, response.list); } if (!houseList.length && this.params.cityCode) { const response = await this.service.fetchHouseList({ cityCode: this.params.cityCode, pageSize: 10, recommend: true, }); houseList.unshift.apply(houseList, response.list); } if (!houseList.length && this.currentGeoLocation) { const response = await this.service.fetchHouseList({ ...this.currentGeoLocation, distance: 6, pageSize: 10, recommend: true, }); houseList.unshift.apply(houseList, response.list); } if (!houseList.length && this.currentGeoLocation) { const userCityInfo = await this.service.georegeo(this.currentGeoLocation); if (userCityInfo && isString(userCityInfo.city)) { const response = await this.service.fetchHouseList({ cityName: userCityInfo.city, recommend: true }); houseList.unshift.apply(houseList, response.list); } } if (!houseList.length) { const response = await this.service.fetchHouseList({ recommend: true }); houseList.unshift.apply(houseList, response.list); } this.recommendHouseList = houseList; return houseList; } private async getCoordCityName(coord: ILocationBaseParams): Promise<string> { const response = await this.service.georegeo(coord); if (response && isString(response.city) && response.city) { return response.city; } if (response && isString(response.province) && response.province) { return response.province; } return ''; } private clearParams<K extends keyof HouseListParams>(keys: K[]) { // tslint:disable-next-line:ter-arrow-parens if (!keys) { this.params = {}; return; } keys.forEach(key => { if (typeof Reflect !== 'undefined') { Reflect.deleteProperty(this.params, key); return; } try { delete this.params[key]; } catch (error) { this.params[key] = undefined; } }); } /** * 任何搜索都要清空筛选条件 * * @private * @memberof ClientSearch */ private clearFilter() { this.clearParams([ 'bedNumberGreaterThanEqual', 'roomNumberGreaterThanEqual', 'tenantNumberGreaterThanEqual', 'priceGreaterThanEqual', 'priceLessThanEqual', 'facilities', 'bedNumbers', 'roomNumbers', 'tenantNumbers', 'tenantNumber', 'allTagIds', 'bizTagIds', 'customTagIds', ]); } }