diff --git a/apps/admin-web/src/pages/StoresPage.tsx b/apps/admin-web/src/pages/StoresPage.tsx index fbd7215..88ed95f 100644 --- a/apps/admin-web/src/pages/StoresPage.tsx +++ b/apps/admin-web/src/pages/StoresPage.tsx @@ -44,6 +44,42 @@ const CREATE_STEPS = [ { title: '结算资质' }, ]; +/** 用店名 + 地址打开百度地图搜索,便于人工核对经纬度 */ +function openBaiduMapSearch(parts: Array) { + const query = parts.map((p) => String(p || '').trim()).filter(Boolean).join(' '); + if (!query) { + message.warning('请先填写门店名称和地址'); + return; + } + const url = `https://map.baidu.com/search/${encodeURIComponent(query)}/@0,0,12z?querytype=s&da_src=shareurl&wd=${encodeURIComponent(query)}`; + window.open(url, '_blank', 'noopener,noreferrer'); +} + +function fillGeolocation( + setCoords: (lat: number, lng: number) => void, + setLoading: (v: boolean) => void, +) { + if (!navigator.geolocation) { + message.error('当前浏览器不支持定位'); + return; + } + setLoading(true); + navigator.geolocation.getCurrentPosition( + (pos) => { + setCoords(pos.coords.latitude, pos.coords.longitude); + message.success( + `已获取坐标 ${pos.coords.latitude.toFixed(6)}, ${pos.coords.longitude.toFixed(6)}`, + ); + setLoading(false); + }, + (err) => { + message.error(err.message || '定位失败'); + setLoading(false); + }, + { enableHighAccuracy: true, timeout: 10000 }, + ); +} + type StoreMediaItem = { id?: string; bizType?: string; @@ -560,6 +596,8 @@ export default function StoresPage() { coverUrl: d.coverUrl, address: d.address, district: d.district, + latitude: d.latitude != null ? Number(d.latitude) : undefined, + longitude: d.longitude != null ? Number(d.longitude) : undefined, settlementRate: d.settlementRate != null ? Number(d.settlementRate) * 100 : 60, openTime: d.openTime || '10:00', closeTime: d.closeTime || '22:00', @@ -648,13 +686,37 @@ export default function StoresPage() { }} /> @@ -681,6 +743,11 @@ export default function StoresPage() { {String(detail.rejectReason || '—')} ) : null} {String(detail.province)}{String(detail.cityName)}{String(detail.district)}{String(detail.address)} + + {detail.latitude != null && detail.longitude != null + ? `${Number(detail.latitude).toFixed(6)}, ${Number(detail.longitude).toFixed(6)}` + : '未设置'} + {[ detail.openTime && detail.closeTime @@ -741,6 +808,57 @@ export default function StoresPage() { + + + + + + + + + + + + + 打开百度地图核对位置后,将坐标填回上方经纬度 + + @@ -886,34 +1004,31 @@ export default function StoresPage() { + - 可手动填写,或点击定位填入;便于用户端导航与距离 + 可手动填写 / 定位 / 百度地图核对后填入坐标 diff --git a/apps/mini-user/src/pages/order-confirm-pickup/index.tsx b/apps/mini-user/src/pages/order-confirm-pickup/index.tsx index 3ed896b..3704d0c 100644 --- a/apps/mini-user/src/pages/order-confirm-pickup/index.tsx +++ b/apps/mini-user/src/pages/order-confirm-pickup/index.tsx @@ -196,6 +196,11 @@ export default function OrderConfirmPickupPage() { + {!quantityOk ? ( + + {`现场提货至少购买 ${minQty} 瓶,请调整数量`} + + ) : null} @@ -219,7 +224,7 @@ export default function OrderConfirmPickupPage() { ) : null} {msg ? ( - + {msg} ) : null} diff --git a/server/dukang-api/src/modules/ops/admin-stores.service.ts b/server/dukang-api/src/modules/ops/admin-stores.service.ts index 7a53069..e9d3e8d 100644 --- a/server/dukang-api/src/modules/ops/admin-stores.service.ts +++ b/server/dukang-api/src/modules/ops/admin-stores.service.ts @@ -194,6 +194,20 @@ export class AdminStoresService { if (!hoursCheck.ok) throw new BadRequestException(hoursCheck.message); } + const latitude = dto.latitude !== undefined ? (dto.latitude == null ? null : Number(dto.latitude)) : undefined; + const longitude = dto.longitude !== undefined ? (dto.longitude == null ? null : Number(dto.longitude)) : undefined; + if (latitude !== undefined || longitude !== undefined) { + if (latitude == null || longitude == null) { + throw new BadRequestException('经纬度须同时提供'); + } + if (!Number.isFinite(latitude) || latitude < -90 || latitude > 90) { + throw new BadRequestException('纬度无效'); + } + if (!Number.isFinite(longitude) || longitude < -180 || longitude > 180) { + throw new BadRequestException('经度无效'); + } + } + const store = await this.prisma.store.update({ where: { id }, data: { @@ -208,6 +222,7 @@ export class AdminStoresService { ...(dto.openTime2 !== undefined ? { openTime2: dto.openTime2 || null } : {}), ...(dto.closeTime2 !== undefined ? { closeTime2: dto.closeTime2 || null } : {}), ...(dto.avgPrice !== undefined ? { avgPrice: dto.avgPrice } : {}), + ...(latitude != null && longitude != null ? { latitude, longitude } : {}), }, }); diff --git a/server/dukang-api/src/modules/ops/dto/admin-mutate.dto.ts b/server/dukang-api/src/modules/ops/dto/admin-mutate.dto.ts index 47f7aaa..c3e63c7 100644 --- a/server/dukang-api/src/modules/ops/dto/admin-mutate.dto.ts +++ b/server/dukang-api/src/modules/ops/dto/admin-mutate.dto.ts @@ -146,6 +146,14 @@ export class UpdateStoreDto { @IsString() address?: string; + @IsOptional() + @IsNumber() + latitude?: number; + + @IsOptional() + @IsNumber() + longitude?: number; + @IsOptional() @IsString() district?: string;