Commit 256f4a09 by Leo Zheng

编写了数据图右边部分的数据接口

parent d2a2c5fc
...@@ -3,8 +3,10 @@ import {DataExtractor} from "../../../util/dataExtractor"; ...@@ -3,8 +3,10 @@ import {DataExtractor} from "../../../util/dataExtractor";
export abstract class abstractDataStrategyLeft implements dataStrategy { export abstract class abstractDataStrategyLeft implements dataStrategy {
extractor = DataExtractor.getInstance(); extractor = DataExtractor.getInstance();
static readonly fileName = '票务系统.xlsx'; static readonly FILENAME = '票务系统.xlsx';
static readonly sheetName = '票务系统-订单主表'; static readonly SHEETNAME = '票务系统-订单主表';
static readonly TIMEDIFFERENCE = 8;
execute(params?: any): any { execute(params?: any): any {
} }
......
...@@ -7,7 +7,7 @@ export class sightVisitorFlowByDayStrategy extends abstractDataStrategyLeft { ...@@ -7,7 +7,7 @@ export class sightVisitorFlowByDayStrategy extends abstractDataStrategyLeft {
if (!params || !params.query || !params.query.date) { if (!params || !params.query || !params.query.date) {
throw new Error("Date parameter is required.") throw new Error("Date parameter is required.")
} }
let sightData = this.extractor.getData(sightVisitorFlowByDayStrategy.fileName, sightVisitorFlowByDayStrategy.sheetName); let sightData = this.extractor.getData(sightVisitorFlowByDayStrategy.FILENAME, sightVisitorFlowByDayStrategy.SHEETNAME);
return this.getVisitorFlowByDay(sightData, params.query.date); return this.getVisitorFlowByDay(sightData, params.query.date);
} }
......
...@@ -8,7 +8,7 @@ export class sightVisitorFlowByHourStrategy extends abstractDataStrategyLeft { ...@@ -8,7 +8,7 @@ export class sightVisitorFlowByHourStrategy extends abstractDataStrategyLeft {
if (!params || !params.query || !params.query.date || !params.query.sight) { if (!params || !params.query || !params.query.date || !params.query.sight) {
throw new Error('Date and sight parameters are required'); throw new Error('Date and sight parameters are required');
} }
const sightData = this.extractor.getData(sightVisitorFlowByHourStrategy.fileName, sightVisitorFlowByHourStrategy.sheetName); const sightData = this.extractor.getData(sightVisitorFlowByHourStrategy.FILENAME, sightVisitorFlowByHourStrategy.SHEETNAME);
return mapToObj(this.getVisitorFlowByHour(sightData, params.query.sight, params.query.date)); return mapToObj(this.getVisitorFlowByHour(sightData, params.query.sight, params.query.date));
} }
...@@ -29,12 +29,10 @@ export class sightVisitorFlowByHourStrategy extends abstractDataStrategyLeft { ...@@ -29,12 +29,10 @@ export class sightVisitorFlowByHourStrategy extends abstractDataStrategyLeft {
rowDateString = 'invalid time'; rowDateString = 'invalid time';
} }
const rowSight = row['景点名称']; const rowSight = row['景点名称'];
rowDate.setHours(rowDate.getHours() - 8); rowDate.setHours(rowDate.getHours() - sightVisitorFlowByHourStrategy.TIMEDIFFERENCE);
if (rowDateString == date && rowSight == sight) { if (rowDateString == date && rowSight == sight) {
if (visitorCount.has(rowHour - 8)) { visitorCount.set(rowHour, (visitorCount.get(rowHour) || 0) + 1);
visitorCount.set(rowHour - 8, (visitorCount.get(rowHour) || 0) + 1);
}
} }
}); });
return visitorCount; return visitorCount;
......
...@@ -9,7 +9,7 @@ export class totalVisitorFlowByHourStrategy extends abstractDataStrategyLeft { ...@@ -9,7 +9,7 @@ export class totalVisitorFlowByHourStrategy extends abstractDataStrategyLeft {
if (!params || !params.query || !params.query.date) { if (!params || !params.query || !params.query.date) {
throw new Error('Date parameters are required'); throw new Error('Date parameters are required');
} }
const sightData = this.extractor.getData(totalVisitorFlowByHourStrategy.fileName, totalVisitorFlowByHourStrategy.sheetName); const sightData = this.extractor.getData(totalVisitorFlowByHourStrategy.FILENAME, totalVisitorFlowByHourStrategy.SHEETNAME);
return mapToObj(this.getTotalVisitorFlowByHour(sightData, params.query.date)); return mapToObj(this.getTotalVisitorFlowByHour(sightData, params.query.date));
} }
...@@ -29,12 +29,10 @@ export class totalVisitorFlowByHourStrategy extends abstractDataStrategyLeft { ...@@ -29,12 +29,10 @@ export class totalVisitorFlowByHourStrategy extends abstractDataStrategyLeft {
catch (e) { catch (e) {
rowDateString = 'invalid time'; rowDateString = 'invalid time';
} }
rowDate.setHours(rowDate.getHours() - 8); rowDate.setHours(rowDate.getHours() - totalVisitorFlowByHourStrategy.TIMEDIFFERENCE);
if (rowDateString == date) { if (rowDateString == date) {
if (visitorCount.has(rowHour - 8)) { visitorCount.set(rowHour, (visitorCount.get(rowHour) || 0) + 1);
visitorCount.set(rowHour - 8, (visitorCount.get(rowHour) || 0) + 1);
}
} }
}); });
return visitorCount; return visitorCount;
......
...@@ -8,7 +8,7 @@ export class totalVisitorFlowStrategy extends abstractDataStrategyLeft { ...@@ -8,7 +8,7 @@ export class totalVisitorFlowStrategy extends abstractDataStrategyLeft {
if (!params || !params.query || !params.query.date) { if (!params || !params.query || !params.query.date) {
throw new Error("Date parameter is required.") throw new Error("Date parameter is required.")
} }
let sightData = this.extractor.getData(totalVisitorFlowStrategy.fileName, totalVisitorFlowStrategy.sheetName); let sightData = this.extractor.getData(totalVisitorFlowStrategy.FILENAME, totalVisitorFlowStrategy.SHEETNAME);
return mapToObj(this.getTotalVisitorByDay(sightData, params.query.date)); return mapToObj(this.getTotalVisitorByDay(sightData, params.query.date));
} }
......
import {dataStrategy} from "../dataStrategy";
import {DataExtractor} from "../../../util/dataExtractor";
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
export abstract class abstractDataStrategyRight implements dataStrategy {
extractor = DataExtractor.getInstance();
static readonly FILENAME = '寿州古城.xlsx';
static readonly SHEETNAME = '指挥调度系统';
static readonly TIMEDIFFERENCE = 8;
protected eventData;
constructor() {
this.eventData = this.readDataFromExcel();
}
execute(params?: any): any {
}
protected paramsCheck(params) {
if (!params || !params.query || !params.query.year) {
throw new Error('Year parameters are required');
}
}
protected readDataFromExcel() {
return this.extractor.getData(abstractDataStrategyRight.FILENAME, abstractDataStrategyRight.SHEETNAME);
}
protected registerItems(list: string[]) {
const eventCount: Map<string, number> = new Map();
list.forEach(event => {
eventCount.set(event, 0);
});
return eventCount;
}
protected getListCount(list: string[], target: string, data: any, year: number) {
const count = this.registerItems(list);
data.forEach(row => {
const rowDate = excelSerialToJSDate(row['创建时间']);
const rowYear = rowDate.getFullYear();
if (rowYear == year) {
count.set(row[target], count.get(row[target]) + 1);
}
});
return count;
}
}
\ No newline at end of file
import {abstractDataStrategyRight} from "./abstractDataStrategyRight";
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
import getRandomNumber from "../../../util/randomNumberGenerator";
export class dispatchTimeStrategy extends abstractDataStrategyRight {
execute(params?: any): any {
this.paramsCheck(params);
return this.getAverageDispatchTime(this.eventData, params.query.year);
}
private getAverageDispatchTime(data: any, year: number) {
let count = 0, time = 0;
data.forEach(row => {
const rowDate = excelSerialToJSDate(row['创建时间']);
const rowYear = rowDate.getFullYear();
if (rowYear == year) {
if (row['处置状态'] == '待调度') {
time = getRandomNumber(0.5, 1.7, 1);
count++;
}
}
})
return time / count;
}
}
\ No newline at end of file
import {abstractDataStrategyRight} from "./abstractDataStrategyRight";
import mapToObj from "../../../util/mapToObj";
export class eventCategoryCountStrategy extends abstractDataStrategyRight {
execute(params?: any): any {
this.paramsCheck(params);
const eventList = ['咨询', '求助', '预警系统', '投诉', '指挥调度', '建议']
const target = '事件类型';
return mapToObj(this.getListCount(eventList, target, this.eventData, params.query.year));
}
}
\ No newline at end of file
import {abstractDataStrategyRight} from "./abstractDataStrategyRight";
import mapToObj from "../../../util/mapToObj";
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
export class eventMonthDistributionStrategy extends abstractDataStrategyRight {
execute(params?: any): any{
this.paramsCheck(params);
return mapToObj(this.getEventMonthDistribution(this.eventData, params.query.year));
}
private getEventMonthDistribution(data: any, year: number) {
const eventCount: Map<number, number> = new Map();
for (let month = 1; month <= 12; month++) {
eventCount.set(month, 0);
}
data.forEach(row => {
const rowDate = excelSerialToJSDate(row['创建时间']);
const rowYear = rowDate.getFullYear();
const rowMonth = rowDate.getMonth();
if (rowYear == year) {
eventCount.set(rowMonth + 1, eventCount.get(rowMonth + 1) + 1);
}
});
return eventCount;
}
}
\ No newline at end of file
import {abstractDataStrategyRight} from "./abstractDataStrategyRight";
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
import getRandomNumber from "../../../util/randomNumberGenerator";
import mapToObj from "../../../util/mapToObj";
export class eventProcessingTimeStrategy extends abstractDataStrategyRight {
execute(params?: any): any {
this.paramsCheck(params);
return mapToObj(this.getEventProcessingTime(this.eventData, params.query.year));
}
private getEventProcessingTime(data: any, year: number) {
const statusList = ['调度时长', '处置等待', '处置时长', '办结时长']
const timeMap = this.registerItems(statusList);
let assignCount = 0, waitCount = 0, processCount = 0, finishingCount = 0;
data.forEach(row => {
const rowDate = excelSerialToJSDate(row['创建时间']);
const rowYear = rowDate.getFullYear();
let waitTime, processTime, closeTime;
if (rowYear == year) {
switch (row['处置状态']) {
case '待调度':
const time = getRandomNumber(0.5, 1.7, 1);
timeMap.set('调度时长', timeMap.get('调度时长') + time);
assignCount++;
case '处置中':
waitTime = this.calculateTimeDifference(row['处置时间'], row['创建时间']);
if (isNaN(row['处置时间'])) {
waitTime = 0;
waitCount--;
}
timeMap.set('处置等待', timeMap.get('处置等待') + waitTime);
waitCount++;
case '已处置':
waitTime = this.calculateTimeDifference(row['处置时间'], row['创建时间']);
processTime = this.calculateTimeDifference(row['处置完成时间'], row['处置时间']);
if (isNaN(row['处置时间'])) {
waitTime = 0;
waitCount--;
}
if (isNaN(row['处置完成时间'])) {
processTime = 0;
processCount--;
}
timeMap.set('处置等待', timeMap.get('处置等待') + waitTime);
timeMap.set('处置时长', timeMap.get('处置时长') + processTime);
waitCount++;
processCount++;
case '已办结':
waitTime = this.calculateTimeDifference(row['处置时间'], row['创建时间']);
processTime = this.calculateTimeDifference(row['处置完成时间'], row['处置时间']);
closeTime = this.calculateTimeDifference(row['办结时间'], row['创建时间']);
if (isNaN(row['处置时间'])) {
waitTime = 0;
waitCount--;
}
if (isNaN(row['处置完成时间'])) {
processTime = 0;
processCount--;
}
if (isNaN(row['办结时间'])) {
closeTime = 0;
finishingCount--;
}
timeMap.set('处置等待', timeMap.get('处置等待') + waitTime);
timeMap.set('处置时长', timeMap.get('处置时长') + processTime);
timeMap.set('办结时长', timeMap.get('办结时长') + processTime);
waitCount++;
processCount++;
finishingCount++;
}
}
});
timeMap.set('调度时长', timeMap.get('调度时长') / assignCount);
timeMap.set('处置等待', timeMap.get('处置等待') / waitCount);
timeMap.set('处置时长', timeMap.get('处置时长') / processCount);
timeMap.set('办结时长', timeMap.get('办结时长') / finishingCount);
return timeMap
}
private calculateTimeDifference(start: number, end: number): number {
const time = excelSerialToJSDate(start).getTime() - excelSerialToJSDate(end).getTime();
return time / (1000 * 60);
}
}
\ No newline at end of file
import {abstractDataStrategyRight} from "./abstractDataStrategyRight";
import mapToObj from "../../../util/mapToObj";
export class eventSrcStrategy extends abstractDataStrategyRight {
execute(params?: any): any {
this.paramsCheck(params);
const sourceList = ['景管通', '12301热线', '舆情平台', '电话热线', '指挥调度', '12345热线']
const target = '事件来源';
return mapToObj(this.getListCount(sourceList, target, this.eventData, params.query.year));
}
}
\ No newline at end of file
import {abstractDataStrategyRight} from "./abstractDataStrategyRight";
import mapToObj from "../../../util/mapToObj";
export class eventSubCategoryCountStrategy extends abstractDataStrategyRight {
execute(params?: any): any {
this.paramsCheck(params);
const eventList = ['服务质量', '医疗救助', '纠纷', '环境卫生', '血族调查', '设施设备'];
const target = '事件子类型';
return mapToObj(this.getListCount(eventList, target, this.eventData, params.query.year));
}
}
\ No newline at end of file
import {abstractDataStrategyRight} from "./abstractDataStrategyRight";
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
import mapToObj from "../../../util/mapToObj";
export class eventTimeDistributionStrategy extends abstractDataStrategyRight {
execute(params?: any): any{
this.paramsCheck(params);
return mapToObj(this.getEventTimeDistribution(this.eventData, params.query.year));
}
private getEventTimeDistribution(data: any, year: number) {
const eventCount: Map<number, number> = new Map();
for (let hour = 0; hour < 24; hour++) {
eventCount.set(hour, 0);
}
data.forEach(row => {
const rowDate = excelSerialToJSDate(row['创建时间']);
const rowHour = rowDate.getHours()
const rowYear = rowDate.getFullYear();
rowDate.setHours(rowDate.getHours() - eventTimeDistributionStrategy.TIMEDIFFERENCE);
if (rowYear == year) {
eventCount.set(rowHour, (eventCount.get(rowHour) || 0) + 1);
}
});
return eventCount;
}
}
\ No newline at end of file
import {abstractDataStrategyRight} from "./abstractDataStrategyRight";
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
import mapToObj from "../../../util/mapToObj";
export class getEventCountByYearStrategy extends abstractDataStrategyRight {
execute(params?: any): any {
this.paramsCheck(params);
return mapToObj(this.getEventCountForYear(this.eventData, params.query.year));
}
private getEventCountForYear(data: any, year: number) {
const eventList = ['事件总数', '历史遗留', '办结率'];
const eventCount = this.registerItems(eventList);
let finishedEventCount = 0;
data.forEach(row => {
const rowDate = excelSerialToJSDate(row['创建时间']);
let rowYear;
try {
rowYear = rowDate.getFullYear();
} catch (e) {
rowYear = 0;
}
if (rowYear == year) {
eventCount.set('事件总数', eventCount.get('事件总数') + 1);
if (row['处置状态'] == '已办结') {
finishedEventCount++;
}
}
else if (rowYear == year - 1 && row['处置状态'] != '已办结') {
eventCount.set('历史遗留', eventCount.get('历史遗留') + 1);
}
});
eventCount.set('办结率', finishedEventCount / eventCount.get('事件总数'));
return eventCount;
}
}
\ No newline at end of file
import {abstractDataStrategyRight} from "./abstractDataStrategyRight";
import mapToObj from "../../../util/mapToObj";
export class gridEventCountStrategy extends abstractDataStrategyRight {
execute(params?: any): any {
this.paramsCheck(params);
const gridList = ['寿州全域', '八公山景区', '寿县古城'];
const target = '网格名称';
return mapToObj(this.getListCount(gridList, target, this.eventData, params.query.year));
}
}
\ No newline at end of file
...@@ -8,6 +8,14 @@ import {totalVisitorFlowStrategy} from "./left/totalVisitorFlowStrategy"; ...@@ -8,6 +8,14 @@ import {totalVisitorFlowStrategy} from "./left/totalVisitorFlowStrategy";
import {totalVisitorFlowByHourStrategy} from "./left/totalVisitorFlowByHourStrategy"; import {totalVisitorFlowByHourStrategy} from "./left/totalVisitorFlowByHourStrategy";
import {currentEventStrategy} from "./middle/currentEventStrategy"; import {currentEventStrategy} from "./middle/currentEventStrategy";
import {totalEventCountStrategy} from "./middle/totalEventCountStrategy"; import {totalEventCountStrategy} from "./middle/totalEventCountStrategy";
import {getEventCountByYearStrategy} from "./right/getEventCountByYearStrategy";
import {eventTimeDistributionStrategy} from "./right/eventTimeDistributionStrategy";
import {eventMonthDistributionStrategy} from "./right/eventMonthDistributionStrategy";
import {eventCategoryCountStrategy} from "./right/eventCategoryCountStrategy";
import {eventSubCategoryCountStrategy} from "./right/eventSubCategoryCountStrategy";
import {eventSrcStrategy} from "./right/eventSrcStrategy";
import {gridEventCountStrategy} from "./right/gridEventCountStrategy";
import {eventProcessingTimeStrategy} from "./right/eventProcessingTimeStrategy";
export class strategyFactory { export class strategyFactory {
private static strategies: { [key: string]: new () => dataStrategy } = { private static strategies: { [key: string]: new () => dataStrategy } = {
...@@ -19,7 +27,15 @@ export class strategyFactory { ...@@ -19,7 +27,15 @@ export class strategyFactory {
'totalVisitorFlow': totalVisitorFlowStrategy, 'totalVisitorFlow': totalVisitorFlowStrategy,
'totalVisitorFlowByDay': totalVisitorFlowByHourStrategy, 'totalVisitorFlowByDay': totalVisitorFlowByHourStrategy,
'currentEventStrategy': currentEventStrategy, 'currentEventStrategy': currentEventStrategy,
'totalEventCount': totalEventCountStrategy 'totalEventCount': totalEventCountStrategy,
'getEventCountByYear': getEventCountByYearStrategy,
'getEventTimeDistribution': eventTimeDistributionStrategy,
'getEventMonthDistribution': eventMonthDistributionStrategy,
'getEventCategoryCount': eventCategoryCountStrategy,
'getEventSubCategoryCount': eventSubCategoryCountStrategy,
'getEventSourceCount': eventSrcStrategy,
'getGridEventCount': gridEventCountStrategy,
'getEventProcessingTime': eventProcessingTimeStrategy
}; };
static createStrategy(type: string): dataStrategy { static createStrategy(type: string): dataStrategy {
......
...@@ -23,6 +23,10 @@ export function httpErrorHandler(err, req, res, next) { ...@@ -23,6 +23,10 @@ export function httpErrorHandler(err, req, res, next) {
res.success({success: false, msg: "不支持该请求", code: 505}); res.success({success: false, msg: "不支持该请求", code: 505});
next(); next();
} }
else if (err.message == 'Year parameter is required.') {
res.success({success: false, msg: err.message, code: 506});
next();
}
else { else {
res.success({success:false, msg: err.message, code: 500}); res.success({success:false, msg: err.message, code: 500});
next(); next();
......
export default function getRandomNumber(min: number, max: number, decimalPlaces: number): number {
const randomNum = Math.random() * (max - min) + min;
return Math.round(randomNum * Math.pow(10, decimalPlaces)) / Math.pow(10, decimalPlaces);
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment