// 已读取AGENTS.md import * as fs from 'fs'; import * as path from 'path'; /** * 第九十四批:真实距离(LBS)落地闸门。 * 背景:雷达页/接单大厅的「650m / 1.4km / 1.2km内」全部是写死演示值, * orders/activities 也没有经纬度字段,导致「按距离派单」实际不生效。 */ describe('第九十四批真实距离与 LBS 闸门', () => { const root = path.resolve(__dirname, '../../'); const read = (rel: string) => fs.readFileSync(path.join(root, rel), 'utf-8'); const mysql = read('server/src/db/mysql.ts'); const repo = read('server/src/db/repository.ts'); const indexCode = read('server/src/index.ts'); const apiCode = read('pwuniapp/common/api.js'); const radar = read('pwuniapp/pages/expert/radar.vue'); const hall = read('pwuniapp/pages/expert/hall.vue'); const orderCreate = read('pwuniapp/pages/order/create.vue'); const activityCreate = read('pwuniapp/pages/activity/create.vue'); it('订单与组局表必须存储经纬度', () => { expect(mysql).toContain('latitude DECIMAL(10,6)'); expect(mysql).toContain('longitude DECIMAL(10,6)'); expect(mysql).toContain('ALTER TABLE activities ADD COLUMN latitude'); expect(mysql).toContain('ALTER TABLE orders ADD COLUMN latitude'); }); it('服务端按 Haversine 计算距离并返回距离文案', () => { expect(repo).toContain('export function haversineKm'); expect(repo).toContain('export function formatDistanceText'); expect(repo).toContain('distanceText'); expect(repo).toContain('radiusKm'); expect(repo).toContain('async updateOrderGeo'); }); it('派单池接口接收定位并按半径过滤,历史地址走腾讯地理编码兜底', () => { const start = indexCode.indexOf("app.get('/api/orders/pool'"); expect(start).toBeGreaterThan(-1); const block = indexCode.slice(start, start + 2200); expect(block).toContain('req.query.lat'); expect(block).toContain('req.query.radius'); expect(block).toContain('geocodeAddress'); expect(block).toContain('repo.updateOrderGeo'); }); it('逆地址解析接口仅服务端持有 Key,并要求登录', () => { expect(indexCode).toContain("app.get('/api/lbs/reverse'"); expect(indexCode).toContain('resolveTencentMapKey'); expect(indexCode).toContain("resolveSecureUserId(req, Number(req.query.userId || 0), '解析当前位置')"); // Key 不允许出现在小程序端 expect(apiCode).not.toContain('7I4BZ'); }); it('小程序雷达与接单大厅改用真实距离,删除写死演示距离', () => { expect(radar).toContain('getUserLocation'); expect(radar).toContain('p.distanceText'); expect(radar).not.toContain("distance: '650m'"); expect(radar).not.toContain("dist: '1.4km'"); expect(hall).toContain('getUserLocation'); expect(hall).toContain('p.distanceText'); expect(hall).not.toContain("'1.2km内'"); expect(hall).not.toContain("'1.1km'"); }); it('下单/组局在选点后提交经纬度', () => { expect(orderCreate).toContain('pickVenue'); expect(orderCreate).toContain('uni.chooseLocation'); expect(orderCreate).toContain('latitude: isOffline.value ? meetCoords.value.latitude : null'); expect(activityCreate).toContain('form.value.latitude'); expect(apiCode).toContain('latitude: payload.latitude'); }); it('小程序的派单池调用支持携带定位与半径', () => { expect(apiCode).toContain('export async function getOrdersPool(options = {})'); expect(apiCode).toContain('qs.push(`lat=${lat}`, `lng=${lng}`)'); expect(apiCode).toContain('radius=${radius}'); }); it('接单失败不得伪造订单,分类数量必须来自真实数据', () => { expect(radar).not.toContain('buyerId: 2001'); expect(radar).not.toContain("status: '履约中'"); expect(hall).toContain('countByType'); expect(hall).not.toContain('count: 12'); }); });