client-search
Version:
客户端搜索
633 lines (556 loc) • 17.5 kB
text/typescript
// 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',
]);
}
}