Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
shouzhouServer
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
chenjinjing
shouzhouServer
Commits
0cadb29f
Commit
0cadb29f
authored
Jul 22, 2024
by
Leo Zheng
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
实现了图二左侧和中部的数据接口
parent
d158dda8
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
448 additions
and
29 deletions
+448
-29
ecommerceRankingStrategy.ts
src/biz/map2/strategies/left/ecommerceRankingStrategy.ts
+35
-0
monthlyRevenueStrategy.ts
src/biz/map2/strategies/left/monthlyRevenueStrategy.ts
+63
-0
monthlyVisitorCountStrategy.ts
src/biz/map2/strategies/left/monthlyVisitorCountStrategy.ts
+1
-1
paymentMethodAnalysisStrategy.ts
...biz/map2/strategies/left/paymentMethodAnalysisStrategy.ts
+78
-0
sightVisitorRankStrategy.ts
src/biz/map2/strategies/left/sightVisitorRankStrategy.ts
+7
-21
ticketRevenueAnalysisStrategy.ts
...biz/map2/strategies/left/ticketRevenueAnalysisStrategy.ts
+58
-0
abstractDataStrategyMid.ts
src/biz/map2/strategies/middle/abstractDataStrategyMid.ts
+24
-0
leftSideMapDataStrategy.ts
src/biz/map2/strategies/middle/leftSideMapDataStrategy.ts
+51
-0
rightSideMapDataStrategy.ts
src/biz/map2/strategies/middle/rightSideMapDataStrategy.ts
+48
-0
abstractCustomerProfileStrategy.ts
.../map2/strategies/right/abstractCustomerProfileStrategy.ts
+18
-0
visitorGenderProfileStrategy.ts
...biz/map2/strategies/right/visitorGenderProfileStrategy.ts
+16
-0
strategyFactory.ts
src/biz/strategyFactory.ts
+19
-2
httpErrorHandler.ts
src/middleware/httpErrorHandler.ts
+20
-0
routerLeft.ts
src/routers/map2/routerLeft.ts
+7
-3
routerMid.ts
src/routers/map2/routerMid.ts
+3
-2
No files found.
src/biz/map2/strategies/left/ecommerceRankingStrategy.ts
0 → 100644
View file @
0cadb29f
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
;
}
}
src/biz/map2/strategies/left/monthlyRevenueStrategy.ts
0 → 100644
View file @
0cadb29f
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
,
ticket
:
value
.
ticket
,
ecommerce
:
value
.
ecommerce
});
}
return
result
;
}
}
src/biz/map2/strategies/left/monthlyVisitorCountStrategy.ts
View file @
0cadb29f
...
@@ -44,7 +44,7 @@ export default class monthlyVisitorCountStrategy extends abstractDataStrategyLef
...
@@ -44,7 +44,7 @@ export default class monthlyVisitorCountStrategy extends abstractDataStrategyLef
}
}
result
.
push
({
result
.
push
({
key
:
key
,
key
:
key
,
value
:
value
.
toString
()
value
:
value
});
});
}
}
...
...
src/biz/map2/strategies/left/paymentMethodAnalysisStrategy.ts
0 → 100644
View file @
0cadb29f
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
;
}
}
src/biz/map2/strategies/left/sightVisitorRankStrategy.ts
View file @
0cadb29f
import
{
abstractDataStrategyLeft
}
from
"./abstractDataStrategyLeft"
;
import
{
abstractDataStrategyLeft
}
from
"./abstractDataStrategyLeft"
;
import
paramChecker
from
"../../../../util/paramChecker"
;
import
excelSerialToJSDate
from
"../../../../util/excelDateToJSDate"
;
export
default
class
sightVisitorRankStrategy
extends
abstractDataStrategyLeft
{
export
default
class
sightVisitorRankStrategy
extends
abstractDataStrategyLeft
{
static
readonly
FILENAME
=
'票务系统.xlsx'
;
static
readonly
FILENAME
=
'票务系统.xlsx'
;
static
readonly
SHEETNAME
=
'票务系统-订单主表'
;
static
readonly
SHEETNAME
=
'票务系统-订单主表'
;
execute
(
params
?:
any
):
any
{
execute
(
params
?:
any
):
any
{
paramChecker
.
checkDiscreteParam
(
params
,
'timeFrame'
,
'12month'
,
'3year'
);
const
data
=
this
.
extractor
.
getData
(
sightVisitorRankStrategy
.
FILENAME
,
sightVisitorRankStrategy
.
SHEETNAME
);
const
data
=
this
.
extractor
.
getData
(
sightVisitorRankStrategy
.
FILENAME
,
sightVisitorRankStrategy
.
SHEETNAME
);
return
this
.
processData
(
data
,
params
.
query
[
'timeFrame'
]
);
return
this
.
processData
(
data
);
}
}
processData
(
data
:
any
,
timeFrame
:
string
):
any
{
processData
(
data
:
any
):
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
sightCounts
:
{
[
key
:
string
]:
number
}
=
{};
const
sightCounts
:
{
[
key
:
string
]:
number
}
=
{};
data
.
forEach
(
row
=>
{
data
.
forEach
(
row
=>
{
const
rowDate
=
excelSerialToJSDate
(
row
[
'游玩时间'
]);
const
sightName
=
row
[
'景点名称'
];
if
(
rowDate
>=
startDate
&&
rowDate
<=
currentDate
)
{
if
(
!
sightCounts
[
sightName
])
{
const
sightName
=
row
[
'景点名称'
];
sightCounts
[
sightName
]
=
0
;
if
(
!
sightCounts
[
sightName
])
{
sightCounts
[
sightName
]
=
0
;
}
sightCounts
[
sightName
]
+=
1
;
}
}
sightCounts
[
sightName
]
+=
1
;
});
});
const
sortedSights
=
Object
.
entries
(
sightCounts
)
const
sortedSights
=
Object
.
entries
(
sightCounts
)
.
sort
(([,
a
],
[,
b
])
=>
b
-
a
)
.
sort
(([,
a
],
[,
b
])
=>
b
-
a
)
.
map
(([
key
,
value
])
=>
({
key
,
value
:
value
.
toString
()
}));
.
map
(([
key
,
value
])
=>
({
key
,
value
:
value
}));
return
sortedSights
;
return
sortedSights
;
}
}
...
...
src/biz/map2/strategies/left/ticketRevenueAnalysisStrategy.ts
0 → 100644
View file @
0cadb29f
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
;
}
if
(
metric
===
'amount'
)
{
return
{
totalSales
:
parseFloat
(
totalSales
.
toFixed
(
2
)),
totalCheckedIn
:
parseFloat
(
totalCheckedIn
.
toFixed
(
2
)),
totalCancellations
:
parseFloat
(
totalCancellations
.
toFixed
(
2
)),
conversionRate
:
parseFloat
(
conversionRate
.
toFixed
(
2
))
};
}
else
{
return
{
totalSales
:
totalTickets
,
totalCheckedIn
:
totalTickets
,
totalCancellations
:
cancellationCount
,
conversionRate
:
parseFloat
(
conversionRate
.
toFixed
(
2
))
};
}
}
}
src/biz/map2/strategies/middle/abstractDataStrategyMid.ts
0 → 100644
View file @
0cadb29f
/**
* 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
;
}
src/biz/map2/strategies/middle/leftSideMapDataStrategy.ts
0 → 100644
View file @
0cadb29f
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
;
}
}
src/biz/map2/strategies/middle/rightSideMapDataStrategy.ts
0 → 100644
View file @
0cadb29f
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
;
}
}
src/biz/map2/strategies/right/abstractCustomerProfileStrategy.ts
0 → 100644
View file @
0cadb29f
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
src/biz/map2/strategies/right/visitorGenderProfileStrategy.ts
0 → 100644
View file @
0cadb29f
import
{
abstractCustomerProfileStrategy
}
from
"./abstractCustomerProfileStrategy"
;
import
paramChecker
from
"../../../../util/paramChecker"
;
export
default
class
visitorGenderProfileStrategy
extends
abstractCustomerProfileStrategy
{
execute
(
params
?:
any
):
any
{
paramChecker
.
checkDiscreteParam
(
params
,
'type'
,
'ecommerce'
,
'ticket'
);
const
data
=
this
.
extractor
.
getData
(
visitorGenderProfileStrategy
.
FILENAME
,
visitorGenderProfileStrategy
.
SHEETNAME
);
return
this
.
processData
(
data
,
params
.
query
[
'type'
]);
}
processData
(
data
:
any
,
type
:
string
):
any
{
}
}
\ No newline at end of file
src/biz/strategyFactory.ts
View file @
0cadb29f
...
@@ -27,6 +27,13 @@ import { eventProcessingTimeStrategy } from "./map1/strategies/right/eventProces
...
@@ -27,6 +27,13 @@ import { eventProcessingTimeStrategy } from "./map1/strategies/right/eventProces
import
{
allEventDataStrategy
}
from
"./map1/strategies/middle/eventDataStrategy"
;
import
{
allEventDataStrategy
}
from
"./map1/strategies/middle/eventDataStrategy"
;
import
monthlyVisitorCountStrategy
from
"./map2/strategies/left/monthlyVisitorCountStrategy"
;
import
monthlyVisitorCountStrategy
from
"./map2/strategies/left/monthlyVisitorCountStrategy"
;
import
sightVisitorRankStrategy
from
"./map2/strategies/left/sightVisitorRankStrategy"
;
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"
;
/**
/**
* 策略工厂类,用于创建和管理各种数据策略。
* 策略工厂类,用于创建和管理各种数据策略。
...
@@ -56,8 +63,18 @@ export class strategyFactory {
...
@@ -56,8 +63,18 @@ export class strategyFactory {
'getEventProcessingTime'
:
eventProcessingTimeStrategy
,
'getEventProcessingTime'
:
eventProcessingTimeStrategy
,
// map2
// map2
'monthlyVisitor'
:
monthlyVisitorCountStrategy
,
'sightVisitorRank'
:
sightVisitorRankStrategy
// left
'monthlyVisitorCount'
:
monthlyVisitorCountStrategy
,
'sightVisitorRank'
:
sightVisitorRankStrategy
,
'monthlyRevenue'
:
monthlyRevenueStrategy
,
'ticketRevenueAnalysis'
:
ticketRevenueAnalysisStrategy
,
'paymentMethodAnalysis'
:
paymentMethodAnalysisStrategy
,
'ecommerceRanking'
:
ecommerceRankingStrategy
,
// mid
'leftSideMapData'
:
leftSideMapDataStrategy
,
'rightSideMapData'
:
rightSideMapDataStrategy
,
};
};
/**
/**
...
...
src/middleware/httpErrorHandler.ts
View file @
0cadb29f
...
@@ -30,6 +30,26 @@ export function httpErrorHandler(err, req, res, next) {
...
@@ -30,6 +30,26 @@ export function httpErrorHandler(err, req, res, next) {
res
.
success
({
success
:
false
,
msg
:
err
.
message
,
code
:
507
});
res
.
success
({
success
:
false
,
msg
:
err
.
message
,
code
:
507
});
next
();
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
{
else
{
res
.
success
({
success
:
false
,
msg
:
err
.
message
,
code
:
500
});
res
.
success
({
success
:
false
,
msg
:
err
.
message
,
code
:
500
});
next
();
next
();
...
...
src/routers/map2/routerLeft.ts
View file @
0cadb29f
...
@@ -2,7 +2,10 @@ import * as asyncHandler from 'express-async-handler';
...
@@ -2,7 +2,10 @@ import * as asyncHandler from 'express-async-handler';
import
*
as
szgcBiz
from
'../../biz/getData'
;
import
*
as
szgcBiz
from
'../../biz/getData'
;
export
function
setMap2LeftRoutes
(
httpServer
)
{
export
function
setMap2LeftRoutes
(
httpServer
)
{
httpServer
.
get
(
'/szgc/getdata/monthlyVisitorCount'
,
asyncHandler
((
req
,
res
)
=>
szgcBiz
.
getData
(
req
,
res
,
'monthlyVisitor'
)));
httpServer
.
get
(
'/szgc/getdata/monthlyVisitorCount'
,
asyncHandler
((
req
,
res
)
=>
szgcBiz
.
getData
(
req
,
res
,
'monthlyVisitorCount'
)));
httpServer
.
get
(
'/szgc/getdate/sightVisitorRank'
,
asyncHandler
((
req
,
res
)
=>
szgcBiz
.
getData
(
req
,
res
,
'sightVisitorRank'
)));
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
src/routers/map2/routerMid.ts
View file @
0cadb29f
...
@@ -2,7 +2,8 @@ import * as asyncHandler from 'express-async-handler';
...
@@ -2,7 +2,8 @@ import * as asyncHandler from 'express-async-handler';
import
*
as
szgcBiz
from
'../../biz/getData'
;
import
*
as
szgcBiz
from
'../../biz/getData'
;
export
function
setMap2MiddleRoutes
(
httpServer
)
{
export
function
setMap2MiddleRoutes
(
httpServer
)
{
httpServer
.
get
(
'/szgc/getdata/getCurrentEventCount'
,
asyncHandler
((
req
,
res
)
=>
szgcBiz
.
getData
(
req
,
res
,
'getCurrentEventCount'
)));
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'
)));
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment