| | |
| | | import { UserInfoEntity } from '../../user/entity/info'; |
| | | import { PushVehicleGpsEntity } from '../../push/entity/vehiclegps'; |
| | | import { BaseSysParamEntity } from '../../base/entity/sys/param'; |
| | | import { BaseSysDepartmentEntity } from '../../base/entity/sys/department'; |
| | | |
| | | const WASTE_COLORS: Record<string, string> = { |
| | | SW62: '#16a34a', |
| | |
| | | }; |
| | | } |
| | | |
| | | /** |
| | | * 分类下钻:不传 departmentId 按部门汇总该类指标;传入则下钻该部门下各站点。 |
| | | * metric: weight | value | count | carbon |
| | | */ |
| | | async drill(range: string, code: string, metric: string, departmentId?: number) { |
| | | const dates = this.getRange(range || 'month'); |
| | | const rawCode = String(code || '').toUpperCase(); |
| | | const field = this.resolveDrillField(rawCode, metric); |
| | | const names = await this.wasteNames(); |
| | | const categoryName = names.get(rawCode) || this.defaultWasteName(rawCode); |
| | | const deptId = |
| | | departmentId == null || departmentId === ('' as any) |
| | | ? undefined |
| | | : Number(departmentId); |
| | | const level = Number.isFinite(deptId as number) ? 'site' : 'department'; |
| | | |
| | | if (!field) { |
| | | return { |
| | | level, |
| | | code: rawCode, |
| | | categoryName, |
| | | departmentId: Number.isFinite(deptId as number) ? deptId : null, |
| | | departmentName: null, |
| | | items: [], |
| | | }; |
| | | } |
| | | |
| | | const expr = `SUM(IFNULL(a.${field},0))`; |
| | | const qb = this.dailySite.createQueryBuilder('a'); |
| | | |
| | | let departmentName: string | null = null; |
| | | if (level === 'site') { |
| | | qb.select('a.siteId', 'id') |
| | | .addSelect('a.siteName', 'name') |
| | | .addSelect(expr, 'metricValue') |
| | | .where('a.date BETWEEN :start AND :end', { start: dates.start, end: dates.end }) |
| | | .andWhere('a.departmentId = :deptId', { deptId }) |
| | | .groupBy('a.siteId') |
| | | .addGroupBy('a.siteName'); |
| | | const dept = await this.dailySite.manager |
| | | .createQueryBuilder(BaseSysDepartmentEntity, 'd') |
| | | .select('d.name', 'name') |
| | | .where('d.id = :id', { id: deptId }) |
| | | .getRawOne(); |
| | | departmentName = dept?.name || `部门${deptId}`; |
| | | } else { |
| | | qb.select('a.departmentId', 'id') |
| | | .addSelect(`IFNULL(d.name, CONCAT('部门', a.departmentId))`, 'name') |
| | | .addSelect(expr, 'metricValue') |
| | | .leftJoin(BaseSysDepartmentEntity, 'd', 'd.id = a.departmentId') |
| | | .where('a.date BETWEEN :start AND :end', { start: dates.start, end: dates.end }) |
| | | .groupBy('a.departmentId') |
| | | .addGroupBy('d.name'); |
| | | } |
| | | |
| | | this.applyDept(qb, 'a'); |
| | | const rows = await qb.getRawMany(); |
| | | const absCarbon = metric === 'carbon'; |
| | | const decimals = metric === 'value' || metric === 'count' ? 0 : 1; |
| | | const items = rows |
| | | .map(r => { |
| | | const raw = n(r.metricValue); |
| | | const value = round(absCarbon ? Math.abs(raw) : raw, decimals); |
| | | return { |
| | | id: n(r.id), |
| | | name: String(r.name || (level === 'site' ? `站点${r.id}` : `部门${r.id}`)), |
| | | value, |
| | | }; |
| | | }) |
| | | .filter(e => e.value !== 0) |
| | | .sort((a, b) => b.value - a.value); |
| | | |
| | | const total = items.reduce((s, e) => s + e.value, 0); |
| | | return { |
| | | level, |
| | | code: rawCode, |
| | | categoryName, |
| | | departmentId: Number.isFinite(deptId as number) ? deptId : null, |
| | | departmentName, |
| | | items: items.map(e => ({ |
| | | ...e, |
| | | percent: total ? round((e.value / total) * 100, 1) : 0, |
| | | })), |
| | | }; |
| | | } |
| | | |
| | | private resolveDrillField(code: string, metric: string): string | null { |
| | | const f = WASTE_FIELDS.find(e => e.code === code); |
| | | if (!f) return null; |
| | | if (metric === 'weight') return f.weight; |
| | | if (metric === 'carbon') return f.carbon; |
| | | if (metric === 'count') return f.time; |
| | | if (metric === 'value') return f.sales || null; |
| | | return null; |
| | | } |
| | | |
| | | private deptIds(): number[] | null { |
| | | const admin = this.ctx.admin; |
| | | if (!admin || admin.username === 'admin') return null; |