Commit 8a8b64db by zhengyoujia

Merge branch 'map2' into 'master'

实现图2

See merge request !13
parents 12e6427b 093e6e07
# 寿州古城数据接口
[中文](#中文) [English](#english)
# 中文
## 端点:`/szgc/getdata`
## 参数:
- `content`:
- 左侧API:
- sightVisitorFlowByDay
- gateStatus
- sightVisitorFlowPerHour
- guchengLoad
- totalVisitorFlow
- totalVisitorFlowByDay
- 中间API:
- currentEventStrategy
- totalEventCount
- allEvents
- 右侧API:
- getEventCountByYear
- getEventTimeDistribution
- getEventMonthDistribution
- getEventCategoryCount
- getEventSubCategoryCount
- getEventSourceCount
- getGridEventCount
- getEventProcessingTime
- `date`: 要检索数据的日期。例子: `2023-05-03`
- `sight`: 景点名称。例子: `八公山森林公园`
- `year`:要检索数据的年份。例子:`2023`
## 运行服务器
1. 克隆仓库
2. 在根目录运行:```npm install```
3. 在VSCode编译器里按F5开始运行服务器
## 测试
在根目录运行```npm test```
## 错误代码:
- 501:数据Excel文件不在指定位置
- 502:数据Excel文件找不到需要的表格
- 503:请求内缺少日期参数
- 504:请求内缺少日期或者景点参数
- 505:不支持该请求
- 506:请求内缺少年份参数
- 500:未知错误
# English
## Endpoint: /szgc/getdata
## parameters:
- `content`:
- Left Side API:
- sightVisitorFlowByDay
- gateStatus
- sightVisitorFlowPerHour
- guchengLoad
- totalVisitorFlow
- totalVisitorFlowByDay
- Middle API:
- currentEventStrategy
- totalEventCount
- allEvents
- Right Side API:
- getEventCountByYear
- getEventTimeDistribution
- getEventMonthDistribution
- getEventCategoryCount
- getEventSubCategoryCount
- getEventSourceCount
- getGridEventCount
- getEventProcessingTime
- `date`: The date you are searching. E.g. `2023-05-03`
- `sight`: The name of the sight. E.g. `八公山森林公园`
- `year`:The year you are searching. E.g. `2023`
## Example Request:
- Left Side:
```http://localhost:30016/getdata?content=sightVisitorFlowByDay&date=2023-05-03&sight=八公山森林公园```
- Middle: ```http://localhost:30016/getdata?content=currentEventStrategy&date=2023-05-03```
- Right Side: ```http://localhost:30016/getdata?content=getEventCategoryCount&year=2024```
## How to Run:
1. Clone the Repository (```git clone http://123.207.147.179:8888/chenjinjing/shouzhouServer.git```)
2. In the root directory, run ```npm install```
3. Using VScode IDE, press F5 to start the server.
## Testing
Run ```npm test``` in the root directory
## Error Code:
- 501: The Excel file storing the data is missing
- 502: The Excel sheet doesn't exist in the Excel file (Excel file is corrupted)
- 503: The request is missing parameter date
- 504: The request is missing parameter date and sight
- 505: Unsupported request
- 506: The request is missing parameter year
- 500: Unknown error
\ No newline at end of file
import {gateStatusStrategy} from "../biz/strategies/left/gateStatusStrategy";
import {guchengLoadStrategy} from "../biz/strategies/left/guchengLoadStrategy";
import {gateStatusStrategy} from "../biz/map1/strategies/left/gateStatusStrategy";
import {guchengLoadStrategy} from "../biz/map1/strategies/left/guchengLoadStrategy";
import {DataExtractor} from "../util/dataExtractor";
import {sightVisitorFlowByDayStrategy} from "../biz/strategies/left/sightVisitorFlowByDayStrategy";
import {sightVisitorFlowByHourStrategy} from "../biz/strategies/left/sightVisitorFlowPerHourStrategy";
import {totalVisitorFlowByHourStrategy} from "../biz/strategies/left/totalVisitorFlowByHourStrategy";
import {totalVisitorFlowStrategy} from "../biz/strategies/left/totalVisitorFlowStrategy";
import {sightVisitorFlowByDayStrategy} from "../biz/map1/strategies/left/sightVisitorFlowByDayStrategy";
import {sightVisitorFlowByHourStrategy} from "../biz/map1/strategies/left/sightVisitorFlowPerHourStrategy";
import {totalVisitorFlowByHourStrategy} from "../biz/map1/strategies/left/totalVisitorFlowByHourStrategy";
import {totalVisitorFlowStrategy} from "../biz/map1/strategies/left/totalVisitorFlowStrategy";
import {testDateError, testSightError, testStrategy} from "./utils";
describe('gateStatusTest', () => {
......
import {currentEventStrategy} from "../biz/strategies/middle/currentEventStrategy";
import {currentEventStrategy} from "../biz/map1/strategies/middle/currentEventStrategy";
import {testDateError, testStrategy} from "./utils";
import {allEventDataStrategy} from "../biz/strategies/middle/eventDataStrategy";
import {totalEventCountStrategy} from "../biz/strategies/middle/totalEventCountStrategy";
import {allEventDataStrategy} from "../biz/map1/strategies/middle/eventDataStrategy";
import {totalEventCountStrategy} from "../biz/map1/strategies/middle/totalEventCountStrategy";
describe('currentEvent test', function () {
const strategy = new currentEventStrategy();
......
import {eventCategoryCountStrategy} from "../biz/strategies/right/eventCategoryCountStrategy";
import {eventCategoryCountStrategy} from "../biz/map1/strategies/right/eventCategoryCountStrategy";
import {testStrategy, testYearError} from "./utils";
import {eventMonthDistributionStrategy} from "../biz/strategies/right/eventMonthDistributionStrategy";
import {eventProcessingTimeStrategy} from "../biz/strategies/right/eventProcessingTimeStrategy";
import {eventSrcStrategy} from "../biz/strategies/right/eventSrcStrategy";
import {eventSubCategoryCountStrategy} from "../biz/strategies/right/eventSubCategoryCountStrategy";
import {eventTimeDistributionStrategy} from "../biz/strategies/right/eventTimeDistributionStrategy";
import {getEventCountByYearStrategy} from "../biz/strategies/right/getEventCountByYearStrategy";
import {gridEventCountStrategy} from "../biz/strategies/right/gridEventCountStrategy";
import {eventMonthDistributionStrategy} from "../biz/map1/strategies/right/eventMonthDistributionStrategy";
import {eventProcessingTimeStrategy} from "../biz/map1/strategies/right/eventProcessingTimeStrategy";
import {eventSrcStrategy} from "../biz/map1/strategies/right/eventSrcStrategy";
import {eventSubCategoryCountStrategy} from "../biz/map1/strategies/right/eventSubCategoryCountStrategy";
import {eventTimeDistributionStrategy} from "../biz/map1/strategies/right/eventTimeDistributionStrategy";
import {getEventCountByYearStrategy} from "../biz/map1/strategies/right/getEventCountByYearStrategy";
import {gridEventCountStrategy} from "../biz/map1/strategies/right/gridEventCountStrategy";
const mockParams = {
query: {
......
......@@ -4,7 +4,7 @@
*/
// 导入 strategyFactory,以便根据请求内容创建适当的策略。
import { strategyFactory } from "./strategies/strategyFactory";
import { strategyFactory } from "./strategyFactory";
/**
* Handles the main data retrieval request.
......
......@@ -3,8 +3,8 @@
* 该文件定义了一个抽象类,用于左侧数据策略的基础实现。
*/
import { dataStrategy } from "../dataStrategy";
import { DataExtractor } from "../../../util/dataExtractor";
import { dataStrategy } from "../../../dataStrategy";
import { DataExtractor } from "../../../../util/dataExtractor";
/**
* 抽象数据策略左侧类,所有具体策略类都需要继承该抽象类。
......
......@@ -3,9 +3,10 @@
* 该文件定义了门状态策略的具体实现。
*/
import { randomStatusGenerator } from "../../../util/randomStatusGenerator";
import mapToObj from "../../../util/mapToObj";
import { randomStatusGenerator } from "../../../../util/randomStatusGenerator";
import mapToObj from "../../../../util/mapToObj";
import { abstractDataStrategyLeft } from "./abstractDataStrategyLeft";
import paramChecker from "../../../../util/paramChecker";
/**
* 门状态策略类,继承自 abstractDataStrategyLeft。
......@@ -27,9 +28,7 @@ export class gateStatusStrategy extends abstractDataStrategyLeft {
* @returns 门状态的对象表示。
*/
execute(params?: any): any {
if (!params || !params.query || !params.query.date) {
throw new Error("Date parameter is required.")
}
paramChecker.checkDateParam(params);
this.gateStatusMap.forEach((value, key, map) => {
map.set(key, randomStatusGenerator.getRandomStatus());
});
......
......@@ -4,6 +4,7 @@
*/
import { abstractDataStrategyLeft } from "./abstractDataStrategyLeft";
import paramChecker from "../../../../util/paramChecker";
/**
* 古城负载策略类,继承自 abstractDataStrategyLeft。
......@@ -14,9 +15,7 @@ export class guchengLoadStrategy extends abstractDataStrategyLeft {
* @returns 随机的负载状态。
*/
execute(params?: any): any {
if (!params || !params.query || !params.query.date) {
throw new Error("Date parameter is required.")
}
paramChecker.checkDateParam(params);
return "正常";
}
}
......@@ -3,9 +3,10 @@
* 该文件定义了按天计算的游客流量策略的具体实现。
*/
import { randomStatusGenerator } from "../../../util/randomStatusGenerator";
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
import { randomStatusGenerator } from "../../../../util/randomStatusGenerator";
import excelSerialToJSDate from "../../../../util/excelDateToJSDate";
import { abstractDataStrategyLeft } from "./abstractDataStrategyLeft";
import paramChecker from "../../../../util/paramChecker";
/**
* 按天计算的游客流量策略类,继承自 abstractDataStrategyLeft。
......@@ -17,9 +18,7 @@ export class sightVisitorFlowByDayStrategy extends abstractDataStrategyLeft {
* @returns 每小时的游客流量。
*/
execute(params?: any): any {
if (!params || !params.query || !params.query.date) {
throw new Error("Date parameter is required.");
}
paramChecker.checkDateParam(params);
let sightData = this.extractor.getData(sightVisitorFlowByDayStrategy.FILENAME, sightVisitorFlowByDayStrategy.SHEETNAME);
return this.getVisitorFlowByDay(sightData, params.query.date);
}
......
......@@ -3,9 +3,10 @@
* 该文件定义了每小时计算的游客流量策略的具体实现,获取制定景点在指定日期的每小时游客流量。
*/
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
import mapToObj from "../../../util/mapToObj";
import excelSerialToJSDate from "../../../../util/excelDateToJSDate";
import mapToObj from "../../../../util/mapToObj";
import {abstractDataStrategyLeft} from "./abstractDataStrategyLeft";
import paramChecker from "../../../../util/paramChecker";
/**
* 每小时计算的游客流量策略类,继承自 abstractDataStrategyLeft。
......@@ -18,9 +19,7 @@ export class sightVisitorFlowByHourStrategy extends abstractDataStrategyLeft {
* @returns 指定景点指定日期的每小时的游客流量。
*/
execute(params?: any): any {
if (!params || !params.query || !params.query.date || !params.query.sight) {
throw new Error('Date and sight parameters are required.');
}
paramChecker.checkDateAndSightParam(params);
const sightData = this.extractor.getData(sightVisitorFlowByHourStrategy.FILENAME, sightVisitorFlowByHourStrategy.SHEETNAME);
return mapToObj(this.getVisitorFlowByHour(sightData, params.query.sight, params.query.date));
}
......
......@@ -3,8 +3,9 @@
* 该文件定义了按小时计算的总游客流量策略的具体实现,获取指定日期整个景区的各类人群客流量分布。
*/
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
import excelSerialToJSDate from "../../../../util/excelDateToJSDate";
import { abstractDataStrategyLeft } from "./abstractDataStrategyLeft";
import paramChecker from "../../../../util/paramChecker";
/**
* 按小时计算的总游客流量策略类,继承自 abstractDataStrategyLeft。
......@@ -17,9 +18,7 @@ export class totalVisitorFlowByHourStrategy extends abstractDataStrategyLeft {
* @returns 全景区各类每小时各类游客流量。
*/
execute(params?: any): any {
if (!params || !params.query || !params.query.date) {
throw new Error('Date parameter is required.');
}
paramChecker.checkDateParam(params);
const sightData = this.extractor.getData(totalVisitorFlowByHourStrategy.FILENAME, totalVisitorFlowByHourStrategy.SHEETNAME);
return this.getTotalVisitorFlowByHour(sightData, params.query.date);
}
......
......@@ -3,8 +3,9 @@
* 该文件定义了总游客流量策略的具体实现。
*/
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
import excelSerialToJSDate from "../../../../util/excelDateToJSDate";
import { abstractDataStrategyLeft } from "./abstractDataStrategyLeft";
import paramChecker from "../../../../util/paramChecker";
/**
* 总游客流量策略类,继承自 abstractDataStrategyLeft。
......@@ -17,9 +18,7 @@ export class totalVisitorFlowStrategy extends abstractDataStrategyLeft {
* @returns 每小时的全景区各类游客流量。
*/
execute(params?: any): any {
if (!params || !params.query || !params.query.date) {
throw new Error("Date parameter is required.");
}
paramChecker.checkDateParam(params);
let sightData = this.extractor.getData(totalVisitorFlowStrategy.FILENAME, totalVisitorFlowStrategy.SHEETNAME);
return this.getTotalVisitorByDay(sightData, params.query.date);
}
......
......@@ -3,8 +3,8 @@
* 该文件定义了一个抽象类,用于中间数据策略的基础实现。
*/
import {dataStrategy} from "../dataStrategy";
import {DataExtractor} from "../../../util/dataExtractor";
import {dataStrategy} from "../../../dataStrategy";
import {DataExtractor} from "../../../../util/dataExtractor";
/**
* 抽象数据策略中间层类,所有具体策略类都需要继承该抽象类。
......
......@@ -4,7 +4,7 @@
*/
import { abstractDataStrategyMid } from "./abstractDataStrategyMid";
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
import excelSerialToJSDate from "../../../../util/excelDateToJSDate";
/**
* 事件数据策略类,继承自 abstractDataStrategyMid。
......
......@@ -4,7 +4,7 @@
*/
import {abstractDataStrategyMid} from "./abstractDataStrategyMid";
import mapToObj from "../../../util/mapToObj";
import mapToObj from "../../../../util/mapToObj";
/**
* 总事件计数策略类,继承自 abstractDataStrategyMid。
......
......@@ -3,10 +3,11 @@
* 该文件定义了一个抽象类,用于右侧数据策略的基础实现。
*/
import { dataStrategy } from "../dataStrategy";
import { DataExtractor } from "../../../util/dataExtractor";
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
import { dataStrategy } from "../../../dataStrategy";
import { DataExtractor } from "../../../../util/dataExtractor";
import excelSerialToJSDate from "../../../../util/excelDateToJSDate";
import moment = require("moment");
import paramChecker from "../../../../util/paramChecker";
/**
* 抽象数据策略右侧类,所有右侧具体策略类都需要继承该抽象类。
......@@ -37,12 +38,7 @@ export abstract class abstractDataStrategyRight implements dataStrategy {
* @throws 如果参数无效则抛出错误。
*/
protected paramsCheck(params) {
if (!params || !params.query || !params.query.year) {
throw new Error('Year parameter is required.');
}
if (params.query.year !== 'thisyear' && params.query.year !== 'lastyear') {
throw new Error('Year parameter must be either "thisyear" or "lastyear".');
}
paramChecker.checkDiscreteParam(params, 'year', 'thisyear', 'lastyear');
}
/**
......
......@@ -4,7 +4,7 @@
*/
import {abstractDataStrategyRight} from "./abstractDataStrategyRight";
import mapToObj from "../../../util/mapToObj";
import mapToObj from "../../../../util/mapToObj";
/**
* 事件类别计数策略类,继承自 abstractDataStrategyRight。
......
......@@ -4,8 +4,8 @@
*/
import { abstractDataStrategyRight } from "./abstractDataStrategyRight";
import mapToObj from "../../../util/mapToObj";
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
import mapToObj from "../../../../util/mapToObj";
import excelSerialToJSDate from "../../../../util/excelDateToJSDate";
/**
* 事件按月分布策略类,继承自 abstractDataStrategyRight。
......
......@@ -4,8 +4,8 @@
*/
import { abstractDataStrategyRight } from "./abstractDataStrategyRight";
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
import getRandomNumber from "../../../util/randomNumberGenerator";
import excelSerialToJSDate from "../../../../util/excelDateToJSDate";
import getRandomNumber from "../../../../util/randomNumberGenerator";
/**
* 事件处理时间策略类,继承自 abstractDataStrategyRight。
......
......@@ -4,7 +4,7 @@
*/
import {abstractDataStrategyRight} from "./abstractDataStrategyRight";
import mapToObj from "../../../util/mapToObj";
import mapToObj from "../../../../util/mapToObj";
/**
* 事件来源策略类,继承自 abstractDataStrategyRight。
......
......@@ -4,7 +4,7 @@
*/
import {abstractDataStrategyRight} from "./abstractDataStrategyRight";
import mapToObj from "../../../util/mapToObj";
import mapToObj from "../../../../util/mapToObj";
/**
* 事件子类别计数策略类,继承自 abstractDataStrategyRight。
......
......@@ -4,8 +4,8 @@
*/
import { abstractDataStrategyRight } from "./abstractDataStrategyRight";
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
import mapToObj from "../../../util/mapToObj";
import excelSerialToJSDate from "../../../../util/excelDateToJSDate";
import mapToObj from "../../../../util/mapToObj";
/**
* 事件时间分布策略类,继承自 abstractDataStrategyRight。
......
......@@ -4,7 +4,7 @@
*/
import { abstractDataStrategyRight } from "./abstractDataStrategyRight";
import excelSerialToJSDate from "../../../util/excelDateToJSDate";
import excelSerialToJSDate from "../../../../util/excelDateToJSDate";
import moment = require("moment");
/**
......
......@@ -4,7 +4,7 @@
*/
import {abstractDataStrategyRight} from "./abstractDataStrategyRight";
import mapToObj from "../../../util/mapToObj";
import mapToObj from "../../../../util/mapToObj";
/**
* 按网格统计事件数量策略类,继承自 abstractDataStrategyRight。
......
/**
* abstractDataStrategyLeft.ts
* 该文件定义了一个抽象类,用于左侧数据策略的基础实现。
*/
import { dataStrategy } from "../../../dataStrategy";
import { DataExtractor } from "../../../../util/dataExtractor";
/**
* 抽象数据策略左侧类,所有具体策略类都需要继承该抽象类。
*/
export abstract class abstractDataStrategyLeft implements dataStrategy {
// 实例化数据提取器
extractor = DataExtractor.getInstance();
static readonly FILENAME = '票务系统.xlsx';
static readonly SHEETNAME = '票务系统-订单主表';
/**
* 执行策略的方法,具体实现由子类提供。
* @param params - 可选参数。
*/
abstract execute(params?: any): any;
abstract processData(...param): any;
}
import {abstractDataStrategyLeft} from "./abstractDataStrategyLeft";
import paramChecker from "../../../../util/paramChecker";
export default class ecommerceRankingStrategy extends abstractDataStrategyLeft {
execute(params?: any): any {
paramChecker.checkDiscreteParam(params, 'metric', 'revenue', 'customerPrice');
return this.processData(params.query['metric']);
}
processData(metric: string): any {
const generateRandomValues = (count: number) => {
return Array.from({ length: count }, () => Math.floor(Math.random() * 5000) + 1000);
};
const shopData = generateRandomValues(4);
const productData = generateRandomValues(4);
shopData.sort((a, b) => b - a);
productData.sort((a, b) => b - a);
const formatData = (data: number[], prefix: string) => {
return data.map((value, index) => ({
name: `${prefix}${index + 1}`,
value: `${value}元`
}));
};
const result = {
shops: formatData(shopData, '商家'),
products: formatData(productData, '商品')
};
return result;
}
}
import {abstractDataStrategyLeft} from "./abstractDataStrategyLeft";
import paramChecker from "../../../../util/paramChecker";
import excelSerialToJSDate from "../../../../util/excelDateToJSDate";
export default class revenueAnalysisStrategy extends abstractDataStrategyLeft {
static readonly FILENAME = '票务系统.xlsx';
static readonly SHEETNAME = '票务系统-订单主表';
execute(params?: any): any {
paramChecker.checkDiscreteParam(params, 'timeFrame', '12month', '3year');
const data = this.extractor.getData(revenueAnalysisStrategy.FILENAME, revenueAnalysisStrategy.SHEETNAME);
return this.processData(data, params.query['timeFrame']);
}
processData(data: any, timeFrame: string): any {
const currentDate = new Date();
let startDate = new Date();
if (timeFrame === '12month') {
startDate.setFullYear(currentDate.getFullYear() - 1);
} else if (timeFrame === '3year') {
startDate.setFullYear(currentDate.getFullYear() - 3);
}
const monthlyRevenue: { [key: string]: { ticket: number, ecommerce: number } } = {};
let tempDate = new Date(startDate);
while (tempDate <= currentDate) {
const formattedMonth = `${tempDate.getFullYear().toString().slice(2)}/${(tempDate.getMonth() + 1).toString().padStart(2, '0')}`;
monthlyRevenue[formattedMonth] = { ticket: 0, ecommerce: Math.floor(Math.random() * 50000) + 50000 }; // Random e-commerce revenue
tempDate.setMonth(tempDate.getMonth() + 1);
}
data.forEach(row => {
const rowDate = excelSerialToJSDate(row['游玩时间']);
const rowMonth = `${rowDate.getFullYear().toString().slice(2)}/${(rowDate.getMonth() + 1).toString().padStart(2, '0')}`;
if (rowDate >= startDate && rowDate <= currentDate) {
if (monthlyRevenue[rowMonth]) {
monthlyRevenue[rowMonth].ticket += row['订单金额'];
} else {
monthlyRevenue[rowMonth] = { ticket: row['订单金额'], ecommerce: Math.floor(Math.random() * 50000) + 50000 };
}
}
});
const result = [];
for (let [key, value] of Object.entries(monthlyRevenue)) {
if (value.ticket === 0) {
value.ticket = Math.floor(Math.random() * 100000) + 10000; // Random ticket revenue if zero
}
if (value.ecommerce === 0) {
value.ecommerce = Math.floor(Math.random() * 50000) + 50000; // Random e-commerce revenue if zero
}
result.push({
key,
value: {
ticket: value.ticket,
ecommerce: value.ecommerce
}
});
}
return result;
}
}
import paramChecker from "../../../../util/paramChecker";
import excelSerialToJSDate from "../../../../util/excelDateToJSDate";
import {abstractDataStrategyLeft} from "./abstractDataStrategyLeft";
export default class monthlyVisitorCountStrategy extends abstractDataStrategyLeft {
execute(params?: any): any {
paramChecker.checkDiscreteParam(params, 'timeFrame', '12month', '3year');
let data = this.extractor.getData(monthlyVisitorCountStrategy.FILENAME, monthlyVisitorCountStrategy.SHEETNAME);
return this.processData(data, params.query['timeFrame']);
}
processData(data: any, timeFrame: string) {
const currentDate = new Date();
let startDate = new Date();
if (timeFrame === '12month') {
startDate.setFullYear(currentDate.getFullYear() - 1);
} else if (timeFrame === '3year') {
startDate.setFullYear(currentDate.getFullYear() - 3);
}
const eventCount: Map<string, number> = new Map();
let tempDate = new Date(startDate);
while (tempDate <= currentDate) {
const formattedMonth = `${tempDate.getFullYear().toString().slice(2)}/${(tempDate.getMonth() + 1).toString().padStart(2, '0')}`;
eventCount.set(formattedMonth, 0);
tempDate.setMonth(tempDate.getMonth() + 1);
}
data.forEach(row => {
const rowDate = excelSerialToJSDate(row['游玩时间']);
const rowYear = rowDate.getFullYear();
const rowMonth = rowDate.getMonth() + 1;
const formattedMonth = `${rowYear.toString().slice(2)}/${rowMonth.toString().padStart(2, '0')}`;
if (rowDate >= startDate && rowDate <= currentDate) {
eventCount.set(formattedMonth, (eventCount.get(formattedMonth) || 0) + 1);
}
});
const result = [];
for (let [key, value] of eventCount.entries()) {
if (value === 0) {
value = Math.floor(Math.random() * 3000) + 1;
}
result.push({
key: key,
value: value
});
}
return result;
}
}
import {abstractDataStrategyLeft} from "./abstractDataStrategyLeft";
import paramChecker from "../../../../util/paramChecker";
import excelSerialToJSDate from "../../../../util/excelDateToJSDate";
export default class paymentMethodAnalysisStrategy extends abstractDataStrategyLeft {
static readonly FILENAME = '票务系统.xlsx';
static readonly SHEETNAME = '票务系统-订单主表';
execute(params?: any): any {
paramChecker.checkDiscreteParam(params, 'category', 'total', 'group', 'solo');
paramChecker.checkDiscreteParam(params, 'timeFrame', '12month', '3year');
const data = this.extractor.getData(paymentMethodAnalysisStrategy.FILENAME, paymentMethodAnalysisStrategy.SHEETNAME);
return this.processData(data, params.query['category'], params.query['timeFrame']);
}
processData(data: any, category: string, timeFrame: string): any {
const currentDate = new Date();
let startDate = new Date();
if (timeFrame === '12month') {
startDate.setFullYear(currentDate.getFullYear() - 1);
} else if (timeFrame === '3year') {
startDate.setFullYear(currentDate.getFullYear() - 3);
}
const paymentMethods = {
'现金支付': 0,
'移动支付': 0,
'第三方支付': 0,
'电子支付': 0
};
const totalAmount = {
'现金支付': 0,
'移动支付': 0,
'第三方支付': 0,
'电子支付': 0
};
data.forEach(row => {
const rowDate = excelSerialToJSDate(row['游玩时间']);
if (rowDate >= startDate && rowDate <= currentDate) {
if (category === 'total' ||
(category === 'group' && row['订单游客类型'] === '团队') ||
(category === 'solo' && row['订单游客类型'] === '散客')) {
const paymentType = row['支付类型'];
const amount = row['订单金额'];
if (paymentMethods[paymentType] !== undefined) {
paymentMethods[paymentType] += 1;
totalAmount[paymentType] += amount;
}
}
}
});
let totalTransactions = 0;
Object.keys(paymentMethods).forEach(key => {
if (paymentMethods[key] === 0) {
paymentMethods[key] = Math.floor(Math.random() * 100) + 1;
}
if (totalAmount[key] === 0) {
totalAmount[key] = Math.floor(Math.random() * 50000) + 5000;
}
totalTransactions += paymentMethods[key];
});
const result = Object.entries(paymentMethods).map(([key, count]) => {
const amount = totalAmount[key];
const percentage = totalTransactions > 0 ? ((count / totalTransactions) * 100).toFixed(2) : '0.00';
return {
paymentMethod: key,
amount: parseFloat(amount.toFixed(2)),
percentage: `${percentage}%`
};
});
return result;
}
}
import {abstractDataStrategyLeft} from "./abstractDataStrategyLeft";
export default class sightVisitorRankStrategy extends abstractDataStrategyLeft {
static readonly FILENAME = '票务系统.xlsx';
static readonly SHEETNAME = '票务系统-订单主表';
execute(params?: any): any {
const data = this.extractor.getData(sightVisitorRankStrategy.FILENAME, sightVisitorRankStrategy.SHEETNAME);
return this.processData(data);
}
processData(data: any): any {
const sightCounts: { [key: string]: number } = {};
data.forEach(row => {
const sightName = row['景点名称'];
if (!sightCounts[sightName]) {
sightCounts[sightName] = 0;
}
sightCounts[sightName] += 1;
});
const sortedSights = Object.entries(sightCounts)
.sort(([, a], [, b]) => b - a)
.map(([key, value]) => ({ key, value: value }));
return sortedSights;
}
}
import {abstractDataStrategyLeft} from "./abstractDataStrategyLeft";
import paramChecker from "../../../../util/paramChecker";
export default class ticketSalesAnalysisStrategy extends abstractDataStrategyLeft {
static readonly FILENAME = '票务系统.xlsx';
static readonly SHEETNAME = '票务系统-订单主表';
execute(params?: any): any {
paramChecker.checkDiscreteParam(params, 'metric', 'amount', 'ticketCount');
const data = this.extractor.getData(ticketSalesAnalysisStrategy.FILENAME, ticketSalesAnalysisStrategy.SHEETNAME);
return this.processData(data, params.query['metric']);
}
processData(data: any, metric: string): any {
let totalSales = 0;
let totalCancellations = 0;
let conversionRate = 0;
let totalCheckedIn = 0;
let totalTickets = 0;
let cancellationCount = 0;
data.forEach(row => {
const amount = row['订单金额'];
const isCancelled = row['是否退票'] === '是';
const isCheckedIn = row['是否检票'] === '是';
totalSales += amount;
if (isCancelled) {
totalCancellations += amount;
cancellationCount += 1;
}
if (isCheckedIn) {
totalCheckedIn += amount;
}
totalTickets += 1;
});
if (totalSales > 0) {
conversionRate = (totalCheckedIn / totalSales) * 100;
}
const result = metric === 'amount'
? {
totalSales: parseFloat(totalSales.toFixed(2)),
totalCheckedIn: parseFloat(totalCheckedIn.toFixed(2)),
totalCancellations: parseFloat(totalCancellations.toFixed(2)),
conversionRate: parseFloat(conversionRate.toFixed(2))
}
: {
totalSales: totalTickets,
totalCheckedIn: totalTickets,
totalCancellations: cancellationCount,
conversionRate: parseFloat(conversionRate.toFixed(2))
};
return Object.entries(result).map(([key, value]) => ({ key, value }));
}
}
/**
* abstractDataStrategyLeft.ts
* 该文件定义了一个抽象类,用于左侧数据策略的基础实现。
*/
import { dataStrategy } from "../../../dataStrategy";
import { DataExtractor } from "../../../../util/dataExtractor";
/**
* 抽象数据策略左侧类,所有具体策略类都需要继承该抽象类。
*/
export abstract class abstractDataStrategyMid implements dataStrategy {
// 实例化数据提取器
extractor = DataExtractor.getInstance();
static readonly FILENAME = '票务系统.xlsx';
static readonly SHEETNAME = '票务系统-订单主表';
/**
* 执行策略的方法,具体实现由子类提供。
* @param params - 可选参数。
*/
abstract execute(params?: any): any;
abstract processData(...param): any;
}
import paramChecker from "../../../../util/paramChecker";
import excelSerialToJSDate from "../../../../util/excelDateToJSDate";
import {abstractDataStrategyMid} from "./abstractDataStrategyMid";
export default class leftSideMapDataStrategy extends abstractDataStrategyMid{
execute(params?: any): any {
paramChecker.checkDiscreteParam(params, 'year', 'thisyear', 'lastyear');
const data = this.extractor.getData(leftSideMapDataStrategy.FILENAME, leftSideMapDataStrategy.SHEETNAME);
return this.processData(data, params.query['year']);
}
processData(data: any, year: string): any {
const currentYear = new Date().getFullYear();
const targetYear = year === 'thisyear' ? currentYear : currentYear - 1;
const filteredData = data.filter(row => {
const playTime = excelSerialToJSDate(row['游玩时间']);
return playTime.getFullYear() === targetYear;
});
const totalVisitors = filteredData.length;
const totalTicketRevenue = filteredData.reduce((sum, row) => sum + row['订单金额'], 0);
const totalEcommerceRevenue = Math.floor(Math.random() * 1000000) + 100000; // Random e-commerce revenue
const visitorIncreaseRate = (Math.random() * 5 - 2.5).toFixed(2); // Random rate between -2.5% and +2.5%
const ticketRevenueIncreaseRate = (Math.random() * 5 - 2.5).toFixed(2); // Random rate between -2.5% and +2.5%
const ecommerceRevenueIncreaseRate = (Math.random() * 5 - 2.5).toFixed(2); // Random rate between -2.5% and +2.5%
const randomNonZeroValue = () => Math.floor(Math.random() * 10000) + 100;
const result = {
totalReception: {
total: totalVisitors === 0 ? randomNonZeroValue() : totalVisitors,
IncreaseRate: `${visitorIncreaseRate}%`,
cumulative: `${(Math.random() * 7000000 + 100000).toFixed(0)}人次`
},
ticketRevenue: {
total: totalTicketRevenue === 0 ? (randomNonZeroValue() / 100).toFixed(2) : (totalTicketRevenue / 10000).toFixed(2),
IncreaseRate: `${ticketRevenueIncreaseRate}%`,
cumulative: `${(Math.random() * 7000000 + 100000).toFixed(2)}万元`
},
ecommerceRevenue: {
total: totalEcommerceRevenue === 0 ? (randomNonZeroValue() / 100).toFixed(2) : (totalEcommerceRevenue / 10000).toFixed(2),
IncreaseRate: `${ecommerceRevenueIncreaseRate}%`,
cumulative: `${(Math.random() * 7000000 + 100000).toFixed(2)}万元`
}
};
return result;
}
}
import paramChecker from "../../../../util/paramChecker";
import {abstractDataStrategyMid} from "./abstractDataStrategyMid";
import excelSerialToJSDate from "../../../../util/excelDateToJSDate";
export default class rightSideMapDataStrategy extends abstractDataStrategyMid {
static readonly FILENAME = '票务系统.xlsx';
static readonly SHEETNAME = '票务系统-订单主表';
execute(params?: any): any {
paramChecker.checkDiscreteParam(params, 'year', 'thisyear', 'lastyear');
paramChecker.checkDiscreteParam(params, 'sight', '安丰塘(芍跛)', '清真寺', '孔庙', '汐熙阁', '安徽第一面党旗纪念园', '八公山森林公园', '寿州古城游客中心', '珍珠泉', '随缘堂(周易)');
const data = this.extractor.getData(rightSideMapDataStrategy.FILENAME, rightSideMapDataStrategy.SHEETNAME);
return this.processData(data, params.query['year'], params.query['sight']);
}
processData(data: any, year: string, sight: string): any {
const currentYear = new Date().getFullYear();
const targetYear = year === 'thisyear' ? currentYear : currentYear - 1;
const filteredData = data.filter(row => {
const playTime = excelSerialToJSDate(row['游玩时间']);
return playTime.getFullYear() === targetYear && row['景点名称'] === sight;
});
const totalVisitors = filteredData.length;
const totalTicketRevenue = filteredData.reduce((sum, row) => sum + row['订单金额'], 0);
const totalTicketsSold = filteredData.reduce((sum, row) => sum + (row['订单金额'] > 0 ? 1 : 0), 0); // Assuming each non-zero order amount represents a sold ticket
const randomNonZeroValue = () => Math.floor(Math.random() * 10000) + 100;
const monthlyVisitorTrend = Array.from({ length: 12 }, (_, index) => ({
month: `${targetYear % 100}/${(index + 1).toString().padStart(2, '0')}`,
visitors: randomNonZeroValue()
}));
const result = {
totalVisitors: totalVisitors === 0 ? randomNonZeroValue() : totalVisitors,
totalTicketRevenue: totalTicketRevenue === 0 ? randomNonZeroValue() : totalTicketRevenue,
totalTicketsSold: totalTicketsSold === 0 ? randomNonZeroValue() : totalTicketsSold,
description: '景点介绍 - 随机生成的景点介绍。',
rating: '国家级4A级景区',
tags: ['标签一', '标签二', '标签三', '标签四'],
monthlyVisitorTrend
};
return result;
}
}
import {dataStrategy} from "../../../dataStrategy";
import {DataExtractor} from "../../../../util/dataExtractor";
export abstract class abstractCustomerProfileStrategy implements dataStrategy {
// 实例化数据提取器
extractor = DataExtractor.getInstance();
static readonly FILENAME = '票务系统.xlsx';
static readonly SHEETNAME = '票务系统-游客门票表';
/**
* 执行策略的方法,具体实现由子类提供。
* @param params - 可选参数。
*/
abstract execute(params?: any): any;
abstract processData(...param): any;
}
\ No newline at end of file
import {dataStrategy} from "../../../dataStrategy";
import {DataExtractor} from "../../../../util/dataExtractor";
export abstract class abstractMerchantProfileStrategy implements dataStrategy {
// 实例化数据提取器
extractor = DataExtractor.getInstance();
static readonly FILENAME = '票务系统.xlsx';
static readonly SHEETNAME = '票务系统-游客门票表';
/**
* 执行策略的方法,具体实现由子类提供。
* @param params - 可选参数。
*/
abstract execute(params?: any): any;
abstract processData(...param): any;
}
\ No newline at end of file
import {dataStrategy} from "../../../dataStrategy";
export default class businessStatusStrategy implements dataStrategy{
execute(): any {
return this.processData();
}
processData(): any {
const totalStores = Math.floor(Math.random() * 2000) + 1000;
const openStores = Math.floor(Math.random() * totalStores * 0.8) + 1;
const closedStores = totalStores - openStores;
const result = [
{ key: '门店数', value: totalStores },
{ key: '开店数', value: openStores },
{ key: '关店数', value: closedStores }
];
result.sort((a, b) => b.value - a.value);
return result;
}
}
import {abstractMerchantProfileStrategy} from "./abstractMerchantProfileStrategy";
export default class merchantBusinessStatisticsStrategy extends abstractMerchantProfileStrategy {
execute(): any {
return this.processData();
}
processData(): any {
const totalBusinesses = Math.floor(Math.random() * 2000) + 1000;
const totalShops = Math.floor(Math.random() * 2500) + 1500;
const businessActivityRate = Math.floor(Math.random() * 50) + 50; // Random percentage between 50% and 100%
const result = [
{
key: '营业商家数',
value: totalBusinesses
},
{
key: '营业店铺数',
value: totalShops
},
{
key: '商家动销率',
value: businessActivityRate
}
];
return result;
}
}
export default class monthlyOpeningTrendStrategy {
execute(): any {
return this.generateMonthlyOpeningTrendData();
}
private generateMonthlyOpeningTrendData(): any {
const currentDate = new Date();
const trendData = [];
for (let i = 11; i >= 0; i--) {
const date = new Date(currentDate.getFullYear(), currentDate.getMonth() - i, 1);
const month = `${date.getFullYear().toString().slice(2)}/${(date.getMonth() + 1).toString().padStart(2, '0')}`;
const count = Math.floor(Math.random() * 300) + 100;
trendData.push({
key: month,
value: count
});
}
return trendData;
}
}
export default class storeTypeDistributionStrategy {
execute(): any {
return this.generateStoreTypeData();
}
private generateStoreTypeData(): any {
const totalStores = 1000; // Total number of stores to be randomly distributed
const storeTypes = [
'文化创意',
'特色餐饮',
'茶馆饮品',
'民宿客栈',
'特色工艺品',
'摄影照相',
'体验式商铺'
];
const randomValues = Array.from({ length: storeTypes.length - 1 }, () => Math.floor(Math.random() * totalStores * 0.3));
const remainingValue = totalStores - randomValues.reduce((a, b) => a + b, 0);
randomValues.push(remainingValue);
const result = randomValues.map((value, index) => ({
key: storeTypes[index],
value: value
}));
result.sort((a, b) => b.value - a.value);
return result;
}
}
import paramChecker from "../../../../util/paramChecker";
import {abstractCustomerProfileStrategy} from "./abstractCustomerProfileStrategy";
export default class visitorAgeProfileStrategy extends abstractCustomerProfileStrategy{
execute(params?: any): any {
paramChecker.checkDiscreteParam(params, 'metric', 'ticket', 'ecommerce');
return this.processData(params.query['metric']);
}
processData(type: string): any {
const total = type === 'ticket' ? 1000 : 3429;
// Generate random values for each age group ensuring they sum up to total
const children = Math.floor(Math.random() * (total * 0.2));
const teenagers = Math.floor(Math.random() * (total * 0.2));
const youngAdults = Math.floor(Math.random() * (total * 0.5));
const adults = total - (children + teenagers + youngAdults);
const ageGroups = [
{
key: '儿童',
value: {
count: children,
percent: ((children / total) * 100).toFixed(2) + '%'
}
},
{
key: '少年',
value: {
count: teenagers,
percent: ((teenagers / total) * 100).toFixed(2) + '%'
}
},
{
key: '青年',
value: {
count: youngAdults,
percent: ((youngAdults / total) * 100).toFixed(2) + '%'
}
},
{
key: '老年',
value: {
count: adults,
percent: ((adults / total) * 100).toFixed(2) + '%'
}
}
];
return ageGroups;
}
}
import {abstractCustomerProfileStrategy} from "./abstractCustomerProfileStrategy";
import paramChecker from "../../../../util/paramChecker";
export default class visitorGenderProfileStrategy extends abstractCustomerProfileStrategy {
execute(params?: any): any {
paramChecker.checkDiscreteParam(params, 'metric', 'ecommerce', 'ticket');
const data = this.extractor.getData(visitorGenderProfileStrategy.FILENAME, visitorGenderProfileStrategy.SHEETNAME);
return this.processData(data, params.query['metric']);
}
processData(data: any, type: string): any {
let total = 0, maleCount = 0, femaleCount = 0;
if (type == 'ticket') {
data.forEach((row) => {
total++;
if (row['性别'] === '男') {
maleCount++;
}
else {
femaleCount++;
}
});
} else if (type == 'ecommerce') {
total = 3429;
maleCount = Math.floor(Math.random() * 1700) + 100;
femaleCount = total - maleCount;
}
const result = type === 'ticket' ?{
总游客数: total,
男性游客: maleCount,
女性游客: femaleCount
} : {
总会员数: total,
男性会员: maleCount,
女性会员: femaleCount
}
return Object.entries(result).map(([key, value]) => ({key, value}));
}
}
\ No newline at end of file
import paramChecker from "../../../../util/paramChecker";
import {abstractCustomerProfileStrategy} from "./abstractCustomerProfileStrategy";
export default class visitorHomeProfileStrategy extends abstractCustomerProfileStrategy {
execute(params?: any): any {
paramChecker.checkDiscreteParam(params, 'metric', 'ticket', 'ecommerce');
const data = this.extractor.getData(visitorHomeProfileStrategy.FILENAME, visitorHomeProfileStrategy.SHEETNAME);
return this.processData(params.query['metric'], data);
}
processData(type: string, data: any): any {
const total = type === 'ticket' ? 1000 : 3429;
const cityCounts: { [key: string]: number } = {};
data.forEach((row: any) => {
const city = row['城市'];
if (!cityCounts[city]) {
cityCounts[city] = 0;
}
cityCounts[city] += 1;
});
const totalVisitors = Object.values(cityCounts).reduce((a, b) => a + b, 0);
const scaleFactor = total / totalVisitors;
const result = Object.entries(cityCounts).map(([key, count]) => {
const scaledCount = Math.floor(count * scaleFactor);
return {
key,
value: scaledCount
};
});
const currentTotal = result.reduce((sum, city) => sum + city.value, 0);
if (currentTotal !== total) {
const difference = total - currentTotal;
result[0].value += difference;
}
return result;
}
}
/**
* strategyFactory.ts
* 该文件定义了策略工厂类,用于创建各种数据策略。
*/
import { dataStrategy } from "./dataStrategy";
// 导入具体策略类
import { sightVisitorFlowByDayStrategy } from "./left/sightVisitorFlowByDayStrategy";
import { gateStatusStrategy } from "./left/gateStatusStrategy";
import { sightVisitorFlowByHourStrategy } from "./left/sightVisitorFlowPerHourStrategy";
import { guchengLoadStrategy } from "./left/guchengLoadStrategy";
import { totalVisitorFlowStrategy } from "./left/totalVisitorFlowStrategy";
import { totalVisitorFlowByHourStrategy } from "./left/totalVisitorFlowByHourStrategy";
import { currentEventStrategy } from "./middle/currentEventStrategy";
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";
import {allEventDataStrategy} from "./middle/eventDataStrategy";
/**
* 策略工厂类,用于创建和管理各种数据策略。
*/
export class strategyFactory {
/**
* 存储策略类型与其对应类的映射。
*/
private static strategies: { [key: string]: new () => dataStrategy } = {
'allEvents': allEventDataStrategy,
'sightVisitorFlowByDay': sightVisitorFlowByDayStrategy,
'gateStatus': gateStatusStrategy,
'sightVisitorFlowPerHour': sightVisitorFlowByHourStrategy,
'guchengLoad': guchengLoadStrategy,
'totalVisitorFlow': totalVisitorFlowStrategy,
'totalVisitorFlowByHour': totalVisitorFlowByHourStrategy,
'getCurrentEventCount': currentEventStrategy,
'totalEventCount': totalEventCountStrategy,
'getEventCountByYear': getEventCountByYearStrategy,
'getEventTimeDistribution': eventTimeDistributionStrategy,
'getEventMonthDistribution': eventMonthDistributionStrategy,
'getEventCategoryCount': eventCategoryCountStrategy,
'getEventSubCategoryCount': eventSubCategoryCountStrategy,
'getEventSourceCount': eventSrcStrategy,
'getGridEventCount': gridEventCountStrategy,
'getEventProcessingTime': eventProcessingTimeStrategy,
};
/**
* 创建并返回指定类型的策略实例。
* @param type - 策略类型的字符串标识。
* @returns 创建的策略实例。
* @throws 如果策略类型无效则抛出错误。
*/
static createStrategy(type: string): dataStrategy {
const StrategyClass = this.strategies[type];
if (!StrategyClass) {
throw new Error('Invalid strategy type.');
}
return new StrategyClass();
}
/**
* 注册一个新的策略。
* @param type - 策略类型的字符串标识。
* @param strategy - 策略类。
*/
static registerStrategy(type: string, strategy: new () => dataStrategy) {
this.strategies[type] = strategy;
}
}
/**
* strategyFactory.ts
* 该文件定义了策略工厂类,用于创建各种数据策略。
*/
import { dataStrategy } from "./dataStrategy";
// 导入具体策略类
import { sightVisitorFlowByDayStrategy } from "./map1/strategies/left/sightVisitorFlowByDayStrategy";
import { gateStatusStrategy } from "./map1/strategies/left/gateStatusStrategy";
import { sightVisitorFlowByHourStrategy } from "./map1/strategies/left/sightVisitorFlowPerHourStrategy";
import { guchengLoadStrategy } from "./map1/strategies/left/guchengLoadStrategy";
import { totalVisitorFlowStrategy } from "./map1/strategies/left/totalVisitorFlowStrategy";
import { totalVisitorFlowByHourStrategy } from "./map1/strategies/left/totalVisitorFlowByHourStrategy";
import { currentEventStrategy } from "./map1/strategies/middle/currentEventStrategy";
import { totalEventCountStrategy } from "./map1/strategies/middle/totalEventCountStrategy";
import { getEventCountByYearStrategy } from "./map1/strategies/right/getEventCountByYearStrategy";
import { eventTimeDistributionStrategy } from "./map1/strategies/right/eventTimeDistributionStrategy";
import { eventMonthDistributionStrategy } from "./map1/strategies/right/eventMonthDistributionStrategy";
import { eventCategoryCountStrategy } from "./map1/strategies/right/eventCategoryCountStrategy";
import { eventSubCategoryCountStrategy } from "./map1/strategies/right/eventSubCategoryCountStrategy";
import { eventSrcStrategy } from "./map1/strategies/right/eventSrcStrategy";
import { gridEventCountStrategy } from "./map1/strategies/right/gridEventCountStrategy";
import { eventProcessingTimeStrategy } from "./map1/strategies/right/eventProcessingTimeStrategy";
import {allEventDataStrategy} from "./map1/strategies/middle/eventDataStrategy";
import monthlyVisitorCountStrategy from "./map2/strategies/left/monthlyVisitorCountStrategy";
import sightVisitorRankStrategy from "./map2/strategies/left/sightVisitorRankStrategy";
import monthlyRevenueStrategy from "./map2/strategies/left/monthlyRevenueStrategy";
import ticketRevenueAnalysisStrategy from "./map2/strategies/left/ticketRevenueAnalysisStrategy";
import paymentMethodAnalysisStrategy from "./map2/strategies/left/paymentMethodAnalysisStrategy";
import ecommerceRankingStrategy from "./map2/strategies/left/ecommerceRankingStrategy";
import mapDataStrategy from "./map2/strategies/middle/leftSideMapDataStrategy";
import leftSideMapDataStrategy from "./map2/strategies/middle/leftSideMapDataStrategy";
import rightSideMapDataStrategy from "./map2/strategies/middle/rightSideMapDataStrategy";
import visitorGenderProfileStrategy from "./map2/strategies/right/visitorGenderProfileStrategy";
import visitorAgeProfileStrategy from "./map2/strategies/right/visitorAgeProfileStrategy";
import visitorHomeProfileStrategy from "./map2/strategies/right/visitorHomeProfileStrategy";
import merchantBusinessStatisticsStrategy from "./map2/strategies/right/merchantBusinessStatisticsStrategy";
import businessStatusStrategy from "./map2/strategies/right/businessStatusStrategy";
import storeTypeDistributionStrategy from "./map2/strategies/right/storeTypeDistributionStrategy";
import monthlyOpeningTrendStrategy from "./map2/strategies/right/monthlyOpeningTrendStrategy";
/**
* 策略工厂类,用于创建和管理各种数据策略。
*/
export class strategyFactory {
/**
* 存储策略类型与其对应类的映射。
*/
private static strategies: { [key: string]: new () => dataStrategy } = {
// map 1
//left
'sightVisitorFlowByDay': sightVisitorFlowByDayStrategy,
'gateStatus': gateStatusStrategy,
'sightVisitorFlowPerHour': sightVisitorFlowByHourStrategy,
'guchengLoad': guchengLoadStrategy,
'totalVisitorFlow': totalVisitorFlowStrategy,
'totalVisitorFlowByHour': totalVisitorFlowByHourStrategy,
// mid
'getCurrentEventCount': currentEventStrategy,
'totalEventCount': totalEventCountStrategy,
'allEvents': allEventDataStrategy,
// right
'getEventCountByYear': getEventCountByYearStrategy,
'getEventTimeDistribution': eventTimeDistributionStrategy,
'getEventMonthDistribution': eventMonthDistributionStrategy,
'getEventCategoryCount': eventCategoryCountStrategy,
'getEventSubCategoryCount': eventSubCategoryCountStrategy,
'getEventSourceCount': eventSrcStrategy,
'getGridEventCount': gridEventCountStrategy,
'getEventProcessingTime': eventProcessingTimeStrategy,
// map2
// left
'monthlyVisitorCount': monthlyVisitorCountStrategy,
'sightVisitorRank': sightVisitorRankStrategy,
'monthlyRevenue': monthlyRevenueStrategy,
'ticketRevenueAnalysis': ticketRevenueAnalysisStrategy,
'paymentMethodAnalysis': paymentMethodAnalysisStrategy,
'ecommerceRanking': ecommerceRankingStrategy,
// mid
'leftSideMapData': leftSideMapDataStrategy,
'rightSideMapData': rightSideMapDataStrategy,
// right
'visitorGenderProfile': visitorGenderProfileStrategy,
'visitorAgeProfile': visitorAgeProfileStrategy,
'visitorSourceDistribution' : visitorHomeProfileStrategy,
'merchantBusinessStatistics': merchantBusinessStatisticsStrategy,
'businessStatus': businessStatusStrategy,
'storeTypeDistribution': storeTypeDistributionStrategy,
'monthlyOpeningTrend': monthlyOpeningTrendStrategy
};
/**
* 创建并返回指定类型的策略实例。
* @param type - 策略类型的字符串标识。
* @returns 创建的策略实例。
* @throws 如果策略类型无效则抛出错误。
*/
static createStrategy(type: string): dataStrategy {
const StrategyClass = this.strategies[type];
if (!StrategyClass) {
throw new Error('Invalid strategy type.');
}
return new StrategyClass();
}
/**
* 注册一个新的策略。
* @param type - 策略类型的字符串标识。
* @param strategy - 策略类。
*/
static registerStrategy(type: string, strategy: new () => dataStrategy) {
this.strategies[type] = strategy;
}
}
......@@ -30,6 +30,30 @@ export function httpErrorHandler(err, req, res, next) {
res.success({success: false, msg: err.message, code: 507});
next();
}
else if (err.message == 'timeFrame parameter is required.') {
res.success({success: false, msg: err.message, code: 508});
next();
}
else if (err.message == 'metric parameter is required.') {
res.success({success: false, msg: err.message, code: 509});
next();
}
else if (err.message == 'category parameter is required.') {
res.success({success: false, msg: err.message, code: 510});
next();
}
else if (err.message == 'sight parameter must be one of 安丰塘(芍跛), 清真寺, 孔庙, 汐熙阁, 安徽第一面党旗纪念园, 八公山森林公园, 寿州古城游客中心, 珍珠泉, 随缘堂(周易).') {
res.success({success: false, msg: err.message, code: 511});
next();
}
else if (err.message == 'sight parameter is required.') {
res.success({success: false, msg: err.message, code: 512});
next();
}
else if (err.message == 'metric parameter must be one of ticket, ecommerce.') {
res.success({success: false, msg: err.message, code: 515});
next();
}
else {
res.success({success:false, msg: err.message, code: 500});
next();
......
import * as asyncHandler from 'express-async-handler';
import * as szgcBiz from '../biz/getData';
import * as szgcBiz from '../../biz/getData';
export function setLeftRoutes(httpServer) {
export function setMap1LeftRoutes(httpServer) {
httpServer.get('/szgc/getdata/sightVisitorFlowByDay', asyncHandler((req, res) => szgcBiz.getData(req, res, 'sightVisitorFlowByDay')));
httpServer.get('/szgc/getdata/gateStatus', asyncHandler((req, res) => szgcBiz.getData(req, res, 'gateStatus')));
httpServer.get('/szgc/getdata/sightVisitorFlowPerHour', asyncHandler((req, res) => szgcBiz.getData(req, res, 'sightVisitorFlowPerHour')));
......
import * as asyncHandler from 'express-async-handler';
import * as szgcBiz from '../biz/getData';
import * as szgcBiz from '../../biz/getData';
export function setMiddleRoutes(httpServer) {
export function setMap1MiddleRoutes(httpServer) {
httpServer.get('/szgc/getdata/getCurrentEventCount', asyncHandler((req, res) => szgcBiz.getData(req, res, 'getCurrentEventCount')));
httpServer.get('/szgc/getdata/totalEventCount', asyncHandler((req, res) => szgcBiz.getData(req, res, 'totalEventCount')));
httpServer.get('/szgc/getdata/allEvents', asyncHandler((req, res) => szgcBiz.getData(req, res, 'allEvents')));
......
import * as asyncHandler from 'express-async-handler';
import * as szgcBiz from '../biz/getData';
import * as szgcBiz from '../../biz/getData';
export function setRightRoutes(httpServer) {
export function setMap1RightRoutes(httpServer) {
httpServer.get('/szgc/getdata/getEventCountByYear', asyncHandler((req, res) => szgcBiz.getData(req, res, 'getEventCountByYear')));
httpServer.get('/szgc/getdata/getEventTimeDistribution', asyncHandler((req, res) => szgcBiz.getData(req, res, 'getEventTimeDistribution')));
httpServer.get('/szgc/getdata/getEventMonthDistribution', asyncHandler((req, res) => szgcBiz.getData(req, res, 'getEventMonthDistribution')));
......
import * as asyncHandler from 'express-async-handler';
import * as szgcBiz from '../../biz/getData';
export function setMap2LeftRoutes(httpServer) {
httpServer.get('/szgc/getdata/monthlyVisitorCount', asyncHandler((req, res) => szgcBiz.getData(req, res, 'monthlyVisitorCount')));
httpServer.get('/szgc/getdata/sightVisitorRank', asyncHandler((req, res) => szgcBiz.getData(req, res, 'sightVisitorRank')));
httpServer.get('/szgc/getdata/monthlyRevenue', asyncHandler((req, res) => szgcBiz.getData(req, res, 'monthlyRevenue')));
httpServer.get('/szgc/getdata/ticketRevenueAnalysis', asyncHandler((req, res) => szgcBiz.getData(req, res, 'ticketRevenueAnalysis')));
httpServer.get('/szgc/getdata/paymentMethodAnalysis', asyncHandler((req, res) => szgcBiz.getData(req, res, 'paymentMethodAnalysis')));
httpServer.get('/szgc/getdata/ecommerceRanking', asyncHandler((req, res) => szgcBiz.getData(req, res, 'ecommerceRanking')));
}
\ No newline at end of file
import * as asyncHandler from 'express-async-handler';
import * as szgcBiz from '../../biz/getData';
export function setMap2MiddleRoutes(httpServer) {
httpServer.get('/szgc/getdata/leftSideMapData', asyncHandler((req, res) => szgcBiz.getData(req, res, 'leftSideMapData')));
httpServer.get('/szgc/getdata/rightSideMapData', asyncHandler((req, res) => szgcBiz.getData(req, res, 'rightSideMapData')));
}
import * as asyncHandler from 'express-async-handler';
import * as szgcBiz from '../../biz/getData';
import storeTypeDistributionStrategy from "../../biz/map2/strategies/right/storeTypeDistributionStrategy";
export function setMap2RightRoutes(httpServer) {
httpServer.get('/szgc/getdata/visitorGenderProfile', asyncHandler((req, res) => szgcBiz.getData(req, res, 'visitorGenderProfile')));
httpServer.get('/szgc/getdata/visitorAgeProfile', asyncHandler((req, res) => szgcBiz.getData(req, res, 'visitorAgeProfile')));
httpServer.get('/szgc/getdata/visitorSourceDistribution', asyncHandler((req, res) => szgcBiz.getData(req, res, 'visitorSourceDistribution')));
httpServer.get('/szgc/getdata/merchantBusinessStatistics', asyncHandler((req, res) => szgcBiz.getData(req, res, 'merchantBusinessStatistics')));
httpServer.get('/szgc/getdata/businessStatus', asyncHandler((req, res) => szgcBiz.getData(req, res, 'businessStatus')));
httpServer.get('/szgc/getdata/storeTypeDistribution', asyncHandler((req, res) => szgcBiz.getData(req, res, 'storeTypeDistribution')));
httpServer.get('/szgc/getdata/monthlyOpeningTrend', asyncHandler((req, res) => szgcBiz.getData(req, res, 'monthlyOpeningTrend')));
}
import { setLeftRoutes } from './routerLeft';
import { setMiddleRoutes } from './routerMid';
import { setRightRoutes } from './routerRight';
import { setMap1LeftRoutes } from './map1/routerLeft';
import { setMap1MiddleRoutes } from './map1/routerMid';
import { setMap1RightRoutes } from './map1/routerRight';
import { setMap2LeftRoutes } from './map2/routerLeft';
import {setMap2MiddleRoutes} from "./map2/routerMid";
import {setMap2RightRoutes} from "./map2/routerRight";
import * as szgcBiz from '../biz/getData';
import * as asyncHandler from 'express-async-handler';
export function setRouter(httpServer) {
setLeftRoutes(httpServer);
setMiddleRoutes(httpServer);
setRightRoutes(httpServer);
setMap1LeftRoutes(httpServer);
setMap1MiddleRoutes(httpServer);
setMap1RightRoutes(httpServer);
setMap2LeftRoutes(httpServer);
setMap2MiddleRoutes(httpServer);
setMap2RightRoutes(httpServer);
httpServer.get('/test', szgcBiz.test);
}
export default class paramChecker {
static checkDateParam(params) {
if (!params || !params.query || !params.query.date) {
throw new Error("Date parameter is required.")
}
}
static checkDateAndSightParam(params) {
if (!params || !params.query || !params.query.date || !params.query.sight) {
throw new Error('Date and sight parameters are required.');
}
}
static checkDiscreteParam(params, paramName, ...allowedValues) {
if (!params || !params.query || !params.query[paramName]) {
throw new Error(`${paramName} parameter is required.`);
}
if (!allowedValues.includes(params.query[paramName])) {
throw new Error(`${paramName} parameter must be one of ${allowedValues.join(", ")}.`);
}
}
}
\ 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