H5端开店增加获取当前店铺位置
This commit is contained in:
@@ -268,6 +268,18 @@ export class AdminStoresService {
|
||||
const categoryId = BigInt(dto.categoryId);
|
||||
await this.storeCategoryService.assertLeafCategoryId(categoryId);
|
||||
|
||||
const latitude = dto.latitude != null ? Number(dto.latitude) : null;
|
||||
const longitude = dto.longitude != null ? Number(dto.longitude) : null;
|
||||
if ((latitude == null) !== (longitude == null)) {
|
||||
throw new BadRequestException('经纬度须同时提供');
|
||||
}
|
||||
if (
|
||||
latitude != null &&
|
||||
(!Number.isFinite(latitude) || !Number.isFinite(longitude!) || latitude < -90 || latitude > 90)
|
||||
) {
|
||||
throw new BadRequestException('经纬度无效');
|
||||
}
|
||||
|
||||
const openTime = dto.openTime?.trim() || '10:00';
|
||||
const closeTime = dto.closeTime?.trim() || '22:00';
|
||||
const openTime2 = dto.openTime2?.trim() || '';
|
||||
@@ -296,6 +308,7 @@ export class AdminStoresService {
|
||||
closeTime,
|
||||
openTime2: openTime2 || null,
|
||||
closeTime2: closeTime2 || null,
|
||||
...(latitude != null && longitude != null ? { latitude, longitude } : {}),
|
||||
status: 'OPEN',
|
||||
auditStatus: 'APPROVED',
|
||||
auditedAt: new Date(),
|
||||
|
||||
@@ -57,6 +57,14 @@ export class CreateStoreDto {
|
||||
@IsNotEmpty()
|
||||
address: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
latitude?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
longitude?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
intro?: string;
|
||||
|
||||
@@ -28,6 +28,15 @@ function haversineMeters(lat1: number, lng1: number, lat2: number, lng2: number)
|
||||
return 2 * R * Math.asin(Math.min(1, Math.sqrt(a)));
|
||||
}
|
||||
|
||||
function parseOptionalCoord(value: unknown, kind: 'lat' | 'lng' = 'lng'): number | null {
|
||||
if (value == null || value === '') return null;
|
||||
const n = typeof value === 'number' ? value : Number(value);
|
||||
if (!Number.isFinite(n)) return null;
|
||||
if (kind === 'lat' && (n < -90 || n > 90)) return null;
|
||||
if (kind === 'lng' && (n < -180 || n > 180)) return null;
|
||||
return n;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class StoreService {
|
||||
private readonly config = loadAppConfig();
|
||||
@@ -296,6 +305,12 @@ export class StoreService {
|
||||
throw new BadRequestException('门店简介须为 2~500 字');
|
||||
}
|
||||
|
||||
const latitude = parseOptionalCoord(body.latitude, 'lat');
|
||||
const longitude = parseOptionalCoord(body.longitude, 'lng');
|
||||
if ((latitude == null) !== (longitude == null)) {
|
||||
throw new BadRequestException('经纬度须同时提供');
|
||||
}
|
||||
|
||||
const store = await this.prisma.store.create({
|
||||
data: {
|
||||
cityId: city.id,
|
||||
@@ -313,6 +328,7 @@ export class StoreService {
|
||||
closeTime,
|
||||
openTime2: openTime2 || null,
|
||||
closeTime2: closeTime2 || null,
|
||||
...(latitude != null && longitude != null ? { latitude, longitude } : {}),
|
||||
status: this.config.autoApproveStore ? 'OPEN' : 'PAUSED',
|
||||
auditStatus: this.config.autoApproveStore ? 'APPROVED' : 'PENDING',
|
||||
auditedAt: this.config.autoApproveStore ? new Date() : null,
|
||||
@@ -320,7 +336,9 @@ export class StoreService {
|
||||
},
|
||||
});
|
||||
|
||||
await this.ensureStoreCoordinates(store);
|
||||
if (latitude == null || longitude == null) {
|
||||
await this.ensureStoreCoordinates(store);
|
||||
}
|
||||
|
||||
const ossBucket = process.env.OSS_BUCKET ?? 'legacy';
|
||||
|
||||
@@ -500,6 +518,10 @@ export class StoreService {
|
||||
const phone = body.phone !== undefined ? String(body.phone).trim() : undefined;
|
||||
const address = body.address !== undefined ? String(body.address).trim() : undefined;
|
||||
const introRaw = body.intro !== undefined ? String(body.intro).trim() : undefined;
|
||||
const latitude =
|
||||
body.latitude !== undefined ? parseOptionalCoord(body.latitude, 'lat') : undefined;
|
||||
const longitude =
|
||||
body.longitude !== undefined ? parseOptionalCoord(body.longitude, 'lng') : undefined;
|
||||
|
||||
if (name !== undefined && !name) throw new BadRequestException('请填写门店名称');
|
||||
if (phone !== undefined && !/^1\d{10}$/.test(phone)) {
|
||||
@@ -509,16 +531,26 @@ export class StoreService {
|
||||
if (introRaw && (introRaw.length < 2 || introRaw.length > 500)) {
|
||||
throw new BadRequestException('门店简介须为 2~500 字');
|
||||
}
|
||||
if (
|
||||
(latitude !== undefined || longitude !== undefined) &&
|
||||
(latitude == null || longitude == null)
|
||||
) {
|
||||
throw new BadRequestException('经纬度须同时提供');
|
||||
}
|
||||
|
||||
const resubmitAudit = store.auditStatus === 'REJECTED';
|
||||
const hasCoordsUpdate = latitude != null && longitude != null;
|
||||
const updated = await this.prisma.store.update({
|
||||
where: { id: storeId },
|
||||
data: {
|
||||
...(name !== undefined ? { name } : {}),
|
||||
...(phone !== undefined ? { phone } : {}),
|
||||
...(address !== undefined
|
||||
? { address, latitude: null, longitude: null }
|
||||
? hasCoordsUpdate
|
||||
? { address }
|
||||
: { address, latitude: null, longitude: null }
|
||||
: {}),
|
||||
...(hasCoordsUpdate ? { latitude, longitude } : {}),
|
||||
...(introRaw !== undefined ? { intro: introRaw || null } : {}),
|
||||
...(resubmitAudit
|
||||
? {
|
||||
@@ -531,7 +563,7 @@ export class StoreService {
|
||||
},
|
||||
});
|
||||
|
||||
if (address !== undefined) {
|
||||
if (address !== undefined && !hasCoordsUpdate) {
|
||||
await this.ensureStoreCoordinates(updated);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user