import { Inject, Provide } from '@midwayjs/core';
|
import { BaseService } from '@cool-midway/core';
|
import { InjectEntityModel } from '@midwayjs/typeorm';
|
import { Repository, SelectQueryBuilder } from 'typeorm';
|
import { Context } from '@midwayjs/koa';
|
import { BasicdataSiteEntity } from '../../basicdata/entity/site';
|
import { BasicdataSorterEntity } from '../../basicdata/entity/sorter';
|
import { BasicdataVehicleEntity } from '../../basicdata/entity/vehicle';
|
import { BasicdataWastetypeEntity } from '../../basicdata/entity/wastetype';
|
import { BasicdataIotEntity } from '../../basicdata/entity/iot';
|
import { PushSorterGpsEntity } from '../../push/entity/sortergps';
|
import { PushSorterHealthEntity } from '../../push/entity/sorterhealth';
|
import { PushSorterAlarmEntity } from '../../push/entity/sorteralarm';
|
import { PushVehicleGpsEntity } from '../../push/entity/vehiclegps';
|
import { PushSiteweightEntity } from '../../push/entity/siteweight';
|
import { PushDevicealarmEntity } from '../../push/entity/devicealarm';
|
|
function n(v: any, d = 0) {
|
const x = Number(v);
|
return Number.isFinite(x) ? x : d;
|
}
|
|
@Provide()
|
export class MapsLiveService extends BaseService {
|
@Inject()
|
ctx: Context;
|
|
@InjectEntityModel(BasicdataSiteEntity)
|
siteRepo: Repository<BasicdataSiteEntity>;
|
|
@InjectEntityModel(BasicdataSorterEntity)
|
sorterRepo: Repository<BasicdataSorterEntity>;
|
|
@InjectEntityModel(BasicdataVehicleEntity)
|
vehicleRepo: Repository<BasicdataVehicleEntity>;
|
|
@InjectEntityModel(PushSorterGpsEntity)
|
sorterGps: Repository<PushSorterGpsEntity>;
|
|
@InjectEntityModel(PushSorterHealthEntity)
|
sorterHealthRepo: Repository<PushSorterHealthEntity>;
|
|
@InjectEntityModel(PushSorterAlarmEntity)
|
sorterAlarm: Repository<PushSorterAlarmEntity>;
|
|
@InjectEntityModel(PushVehicleGpsEntity)
|
vehicleGps: Repository<PushVehicleGpsEntity>;
|
|
@InjectEntityModel(PushSiteweightEntity)
|
siteWeightRepo: Repository<PushSiteweightEntity>;
|
|
@InjectEntityModel(PushDevicealarmEntity)
|
deviceAlarm: Repository<PushDevicealarmEntity>;
|
|
@InjectEntityModel(BasicdataIotEntity)
|
iotRepo: Repository<BasicdataIotEntity>;
|
|
private deptIds(): number[] | null {
|
const admin = this.ctx.admin;
|
if (!admin || admin.username === 'admin') return null;
|
return Array.isArray(admin.departmentIds) ? admin.departmentIds.map(Number) : [];
|
}
|
|
private applyDept(qb: SelectQueryBuilder<any>, alias: string) {
|
const ids = this.deptIds();
|
if (ids === null) return qb;
|
if (!ids.length) {
|
qb.andWhere('1 = 0');
|
return qb;
|
}
|
qb.andWhere(`${alias}.departmentId IN (:...deptIds)`, { deptIds: ids });
|
return qb;
|
}
|
|
async sites() {
|
const qb = this.siteRepo
|
.createQueryBuilder('a')
|
.select([
|
'a.id',
|
'a.businessId',
|
'a.businessName',
|
'a.departmentId',
|
'a.siteType',
|
'a.address',
|
'a.leader',
|
'a.longitude',
|
'a.latitude',
|
'a.photo',
|
'a.status',
|
'a.remark',
|
])
|
.where('a.status = :status', { status: 1 })
|
.andWhere('a.longitude IS NOT NULL')
|
.andWhere('a.latitude IS NOT NULL');
|
this.applyDept(qb, 'a');
|
const rows = await qb.getMany();
|
return rows.filter(e => n(e.longitude) && n(e.latitude));
|
}
|
|
async siteWeight(businessId: string, startTime: string, endTime: string) {
|
if (!businessId) return [];
|
const qb = this.siteWeightRepo
|
.createQueryBuilder('a')
|
.leftJoin(BasicdataWastetypeEntity, 'c', 'a.garbageType = c.code')
|
.select('a.id', 'id')
|
.addSelect('a.businessId', 'businessId')
|
.addSelect('a.deviceNo', 'deviceNo')
|
.addSelect('a.uploadTime', 'uploadTime')
|
.addSelect('a.garbageType', 'garbageType')
|
.addSelect('c.name', 'garbageName')
|
.addSelect('a.weight', 'weight')
|
.where('a.businessId = :businessId', { businessId })
|
.andWhere('a.uploadTime BETWEEN :startTime AND :endTime', { startTime, endTime })
|
.orderBy('a.uploadTime', 'DESC')
|
.limit(200);
|
this.applyDept(qb, 'a');
|
return qb.getRawMany();
|
}
|
|
async sorterOnline() {
|
const since = new Date(Date.now() - 15 * 60 * 1000);
|
const qb = this.sorterGps
|
.createQueryBuilder('a')
|
.where('a.uploadTime >= :since', { since })
|
.orderBy('a.uploadTime', 'DESC')
|
.take(4000);
|
this.applyDept(qb, 'a');
|
const rows = await qb.getMany();
|
const latest = new Map<string, PushSorterGpsEntity>();
|
rows.forEach(r => {
|
if (r.idCard && !latest.has(r.idCard)) latest.set(r.idCard, r);
|
});
|
const cards = [...latest.keys()];
|
const sorters = cards.length
|
? await this.sorterRepo
|
.createQueryBuilder('s')
|
.where('s.businessId IN (:...cards)', { cards })
|
.getMany()
|
: [];
|
const sorterMap = new Map(sorters.map(s => [s.businessId, s]));
|
return [...latest.values()].map(g => {
|
const s = sorterMap.get(g.idCard);
|
return {
|
idCard: g.idCard,
|
name: s?.businessName || g.name,
|
phone: s?.phone || '',
|
sex: s?.sex,
|
workSiteId: s?.workSiteId,
|
departmentId: s?.departmentId || g.departmentId,
|
departmentName: g.departmentName,
|
longitude: n(g.longitude),
|
latitude: n(g.latitude),
|
speed: n(g.speed),
|
uploadTime: g.uploadTime,
|
status: s?.status,
|
};
|
});
|
}
|
|
async sorterTrack(idCard: string, startTime: string, endTime: string) {
|
if (!idCard) return [];
|
const qb = this.sorterGps
|
.createQueryBuilder('a')
|
.where('a.idCard = :idCard', { idCard })
|
.andWhere('a.uploadTime BETWEEN :startTime AND :endTime', { startTime, endTime })
|
.andWhere('a.longitude IS NOT NULL')
|
.andWhere('a.latitude IS NOT NULL')
|
.orderBy('a.uploadTime', 'ASC')
|
.take(5000);
|
this.applyDept(qb, 'a');
|
const rows = await qb.getMany();
|
return rows.map(r => ({
|
longitude: n(r.longitude),
|
latitude: n(r.latitude),
|
speed: n(r.speed),
|
time: r.uploadTime,
|
}));
|
}
|
|
async sorterHealth(idCard: string) {
|
if (!idCard) return { recent: [], abnormal: [], alarms: [] };
|
const recentQb = this.sorterHealthRepo
|
.createQueryBuilder('a')
|
.where('a.idCard = :idCard', { idCard })
|
.orderBy('a.uploadTime', 'DESC')
|
.take(20);
|
this.applyDept(recentQb, 'a');
|
const recent = await recentQb.getMany();
|
|
const abQb = this.sorterHealthRepo
|
.createQueryBuilder('a')
|
.where('a.idCard = :idCard', { idCard })
|
.andWhere("a.dataType = '异常'")
|
.orderBy('a.uploadTime', 'DESC')
|
.take(20);
|
this.applyDept(abQb, 'a');
|
const abnormal = await abQb.getMany();
|
|
const alarmQb = this.sorterAlarm
|
.createQueryBuilder('a')
|
.where('a.idCard = :idCard', { idCard })
|
.orderBy('a.uploadTime', 'DESC')
|
.take(20);
|
this.applyDept(alarmQb, 'a');
|
const alarms = await alarmQb.getMany();
|
|
return { recent, abnormal, alarms };
|
}
|
|
async vehicleOnline() {
|
const since = new Date(Date.now() - 15 * 60 * 1000);
|
const qb = this.vehicleGps
|
.createQueryBuilder('a')
|
.where('a.gpsTime >= :since', { since })
|
.andWhere("a.vehicleNo IS NOT NULL AND a.vehicleNo <> ''")
|
.orderBy('a.gpsTime', 'DESC')
|
.take(4000);
|
this.applyDept(qb, 'a');
|
const rows = await qb.getMany();
|
const latest = new Map<string, PushVehicleGpsEntity>();
|
rows.forEach(r => {
|
if (r.vehicleNo && !latest.has(r.vehicleNo)) latest.set(r.vehicleNo, r);
|
});
|
const plates = [...latest.keys()];
|
const vehicles = plates.length
|
? await this.vehicleRepo
|
.createQueryBuilder('v')
|
.where('v.businessId IN (:...plates)', { plates })
|
.getMany()
|
: [];
|
const vehicleMap = new Map(vehicles.map(v => [v.businessId, v]));
|
return [...latest.values()].map(g => {
|
const v = vehicleMap.get(g.vehicleNo);
|
return {
|
vehicleNo: g.vehicleNo,
|
sn: g.sn,
|
vehicleType: v?.vehicleType,
|
capacityTon: v?.capacityTon,
|
departmentId: v?.departmentId || g.departmentId,
|
departmentName: g.departmentName,
|
longitude: n(g.longitude),
|
latitude: n(g.latitude),
|
speed: n(g.speed),
|
direction: g.direction,
|
gpsTime: g.gpsTime,
|
status: v?.status,
|
gpsStatus: g.status,
|
};
|
});
|
}
|
|
async vehicleTrack(vehicleNo: string, startTime: string, endTime: string) {
|
if (!vehicleNo) return [];
|
const qb = this.vehicleGps
|
.createQueryBuilder('a')
|
.where('a.vehicleNo = :vehicleNo', { vehicleNo })
|
.andWhere('a.gpsTime BETWEEN :startTime AND :endTime', { startTime, endTime })
|
.andWhere('a.longitude IS NOT NULL')
|
.andWhere('a.latitude IS NOT NULL')
|
.orderBy('a.gpsTime', 'ASC')
|
.take(5000);
|
this.applyDept(qb, 'a');
|
const rows = await qb.getMany();
|
return rows.map(r => ({
|
longitude: n(r.longitude),
|
latitude: n(r.latitude),
|
speed: n(r.speed),
|
direction: r.direction,
|
time: r.gpsTime,
|
}));
|
}
|
|
async vehicleEvents(vehicleNo: string) {
|
if (!vehicleNo) return [];
|
const iots = await this.iotRepo.find({
|
where: { businessId: vehicleNo },
|
select: ['iotCode', 'iotName', 'iotTypeCode'],
|
});
|
const codes = iots.map(e => e.iotCode).filter(Boolean);
|
if (!codes.length) return [];
|
const nameMap = new Map(iots.map(e => [e.iotCode, e.iotName]));
|
const qb = this.deviceAlarm
|
.createQueryBuilder('a')
|
.where('a.devSerial IN (:...codes)', { codes })
|
.orderBy('a.createTime', 'DESC')
|
.take(30);
|
const rows = await qb.getMany();
|
return rows.map(r => ({
|
...r,
|
deviceName: nameMap.get(r.devSerial) || r.devSerial,
|
}));
|
}
|
}
|