🐛 修复车务非必填-1展示,并完善总单调度与运单表单体验
调度页限制上一段到达后才可调度;司机候选项点击展开;车务多模块-1显示为空;同步配载/总单编辑与导入相关优化。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+135
-15
@@ -1,6 +1,56 @@
|
||||
/**
|
||||
* 将高德 Geocoder 结果规范化为地图选址浮层列表数据。
|
||||
* @param {Array|Object} geocodesOrResult geocodes 数组,或含 geocodes/location 的结果对象
|
||||
* 高德地点关键词搜索(Web 服务 v5)。
|
||||
* @see https://restapi.amap.com/v5/place/text
|
||||
* @param {string} keyword 地点关键字
|
||||
* @param {{ key: string, pageSize?: number, pageNum?: number, region?: string, cityLimit?: boolean }} options
|
||||
* @returns {Promise<Array>}
|
||||
*/
|
||||
export function searchAmapPlaceText(keyword, options = {}) {
|
||||
const key = options.key;
|
||||
const pageSize = options.pageSize || 20;
|
||||
const pageNum = options.pageNum || 1;
|
||||
if (!key) {
|
||||
return Promise.reject(new Error('高德地图 Key 未配置'));
|
||||
}
|
||||
const trimmed = String(keyword || '').trim();
|
||||
if (!trimmed) {
|
||||
return Promise.reject(new Error('请输入地址关键词'));
|
||||
}
|
||||
|
||||
const params = new URLSearchParams({
|
||||
key,
|
||||
keywords: trimmed,
|
||||
page_size: String(pageSize),
|
||||
page_num: String(pageNum),
|
||||
show_fields: 'photos',
|
||||
});
|
||||
if (options.region) {
|
||||
params.set('region', options.region);
|
||||
}
|
||||
if (options.cityLimit != null) {
|
||||
params.set('city_limit', options.cityLimit ? 'true' : 'false');
|
||||
}
|
||||
|
||||
return fetch(`https://restapi.amap.com/v5/place/text?${params.toString()}`)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('高德地点搜索请求失败');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
if (String(data?.status) === '1') {
|
||||
return Array.isArray(data.pois) ? data.pois : [];
|
||||
}
|
||||
const error = new Error(data?.info || '高德地点搜索失败');
|
||||
error.code = data?.infocode;
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将高德 Geocoder / place/text 结果规范化为地图选址浮层列表数据。
|
||||
* @param {Array|Object} geocodesOrResult geocodes/pois 数组,或含 geocodes/pois/location 的结果对象
|
||||
* @param {string} keyword 搜索关键词兜底文案
|
||||
* @returns {Array<{id: string|number, name: string, address: string, location: any, photo: string}>}
|
||||
*/
|
||||
@@ -10,25 +60,95 @@ export function normalizeMapSearchResults(geocodesOrResult, keyword = '') {
|
||||
if (Array.isArray(geocodesOrResult)) {
|
||||
list = geocodesOrResult;
|
||||
} else if (geocodesOrResult && typeof geocodesOrResult === 'object') {
|
||||
if (Array.isArray(geocodesOrResult.geocodes)) {
|
||||
if (Array.isArray(geocodesOrResult.pois)) {
|
||||
list = geocodesOrResult.pois;
|
||||
} else if (Array.isArray(geocodesOrResult.geocodes)) {
|
||||
list = geocodesOrResult.geocodes;
|
||||
} else if (geocodesOrResult.location) {
|
||||
list = [geocodesOrResult];
|
||||
}
|
||||
}
|
||||
|
||||
return list.map((item, index) => {
|
||||
const buildingName = pickNamedField(item?.building);
|
||||
const neighborhoodName = pickNamedField(item?.neighborhood);
|
||||
const address = item?.formattedAddress || item?.address || fallback || '-';
|
||||
return {
|
||||
id: item?.id || index,
|
||||
name: buildingName || neighborhoodName || address,
|
||||
address,
|
||||
location: item?.location,
|
||||
photo: item?.photo || item?.image || '',
|
||||
};
|
||||
});
|
||||
return list
|
||||
.map((item, index) => {
|
||||
if (!item) return null;
|
||||
if (isPlacePoi(item)) {
|
||||
const address = buildPoiAddress(item) || fallback || '-';
|
||||
return {
|
||||
id: item.id || index,
|
||||
name: String(item.name || '').trim() || address,
|
||||
address,
|
||||
location: parseMapLocation(item.location),
|
||||
photo: pickPoiPhoto(item),
|
||||
};
|
||||
}
|
||||
|
||||
const buildingName = pickNamedField(item?.building);
|
||||
const neighborhoodName = pickNamedField(item?.neighborhood);
|
||||
const address = item?.formattedAddress || item?.address || fallback || '-';
|
||||
return {
|
||||
id: item?.id || index,
|
||||
name: buildingName || neighborhoodName || address,
|
||||
address,
|
||||
location: parseMapLocation(item?.location),
|
||||
photo: item?.photo || item?.image || '',
|
||||
};
|
||||
})
|
||||
.filter(item => item && item.location);
|
||||
}
|
||||
|
||||
export function parseMapLocation(location) {
|
||||
if (!location) return null;
|
||||
if (typeof location.getLng === 'function' && typeof location.getLat === 'function') {
|
||||
return location;
|
||||
}
|
||||
if (typeof location === 'string') {
|
||||
const parts = location.split(',');
|
||||
const lng = Number(parts[0]);
|
||||
const lat = Number(parts[1]);
|
||||
if (!Number.isFinite(lng) || !Number.isFinite(lat)) return null;
|
||||
return { lng, lat };
|
||||
}
|
||||
if (Number.isFinite(Number(location.lng)) && Number.isFinite(Number(location.lat))) {
|
||||
return { lng: Number(location.lng), lat: Number(location.lat) };
|
||||
}
|
||||
if (
|
||||
Number.isFinite(Number(location.longitude)) &&
|
||||
Number.isFinite(Number(location.latitude))
|
||||
) {
|
||||
return { lng: Number(location.longitude), lat: Number(location.latitude) };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function isPlacePoi(item) {
|
||||
return Boolean(item && item.name && item.location && (item.id || item.typecode || item.adname));
|
||||
}
|
||||
|
||||
function buildPoiAddress(item) {
|
||||
const detail = String(item.address || '').trim();
|
||||
const region = [item.pname, item.cityname, item.adname]
|
||||
.map(value => String(value || '').trim())
|
||||
.filter(Boolean);
|
||||
// 直辖市等场景省市名可能重复
|
||||
const uniqueRegion = region.filter((value, index) => region.indexOf(value) === index);
|
||||
const prefix = uniqueRegion.join('');
|
||||
if (prefix && detail) {
|
||||
if (detail.startsWith(prefix)) return detail;
|
||||
return `${prefix}${detail}`;
|
||||
}
|
||||
return detail || prefix || String(item.name || '').trim();
|
||||
}
|
||||
|
||||
function pickPoiPhoto(item) {
|
||||
const photos = item?.photos;
|
||||
if (Array.isArray(photos) && photos.length) {
|
||||
return photos[0]?.url || '';
|
||||
}
|
||||
if (photos && typeof photos === 'object') {
|
||||
return photos.url || '';
|
||||
}
|
||||
return item?.photo || item?.image || '';
|
||||
}
|
||||
|
||||
function pickNamedField(value) {
|
||||
|
||||
Reference in New Issue
Block a user