name := "OrderAnalysisTool"
version := "1.0"
scalaVersion := "2.13.12"
libraryDependencies ++= Seq(
"io.circe" %% "circe-core" % "0.14.7",
"io.circe" %% "circe-generic" % "0.14.7",
"io.circe" %% "circe-parser" % "0.14.7"
)
object OrderAnalyzer {
case class Order(
orderId: String,
userId: String,
products: List[Product],
orderTime: LocalDate
) {
def totalAmount: Double = products.map(p => p.quantity * p.unitPrice).sum
}
case class Product(productId: String, quantity: Int, unitPrice: Double)
val sampleData: String = """
[
{
"orderId": "SAMPLE-001",
"userId": "TEST-USER",
"products": [{"productId": "P-001", "quantity": 2, "unitPrice": 99.99}],
"orderTime": "2025-06-01"
},
{
"orderId": "SAMPLE-002",
"userId": "TEST-USER",
"products": [{"productId": "P-002", "quantity": 1, "unitPrice": 499.00}],
"orderTime": "2025-06-05"
}
]
""".stripMargin
def main(args: Array[String]): Unit = {
val parser = new scopt.OptionParser[Config] {
head("OrderAnalyzer", "1.0")
opt[String]('i', "input")
.action((x, c) => c.copy(input = x))
.text("输入JSON文件路径(默认使用内置示例数据)")
opt[String]('o', "output")
.action((x, c) => c.copy(output = x))
.text("输出报告路径")
opt[Int]('d', "days")
.action((x, c) => c.copy(recentDays = x))
.text("近N天订单分析(默认30天)")
}
parser.parse(args, Config("", "", 30)) match {
case Some(config) =>
runAnalysis(config).foreach { result =>
println(s"分析完成,结果已保存至:${config.output}")
generateCsvReport(result)
}
case None =>
}
}
case class Config(input: String, output: String, recentDays: Int)
def runAnalysis(config: Config): Either[String, Map[String, Any]] = {
import io.circe.parser._
import io.circe.generic.auto._
val orders = loadOrders(config.input)
val stats = Map(
"userSpending" -> userStatistics(orders),
"topProducts" -> topSellingProducts(orders),
"monthlyStats" -> monthlyStatistics(orders)
)
val filtered = Map(
"highValue" -> highValueOrders(orders),
"recentOrders" -> recentOrders(orders, config.recentDays)
)
Right(stats ++ filtered)
}
def loadOrders(filePath: String): Either[String, List[Order]] = {
if (filePath.isEmpty) {
println("[提示]使用内置数据...")
parse(sampleData).map(_.asInstanceOf[List[Order]])
} else{
import scala.util.Try
Try {
val source = scala.io.Source.fromFile(filePath)
val json = source.mkString
source.close()
decode[List[Order]](json)
} match {
case scala.util.Success(result) => Right(result)
case scala.util.Failure(e) => Left(s"解析失败: ${e.getMessage}")
}
}
}
def userStatistics(orders: List[Order]): Map[String, Double] = {
orders.groupBy(_.userId)
.view
.mapValues(_.map(_.totalAmount).sum)
.toMap
}
def topSellingProducts(orders: List[Order]): List[(String, Int)] = {
orders.flatMap(_.products)
.groupBy(_.productId)
.view
.mapValues(_.size)
.toList
.sortBy(-_._2)
.take(3)
}
def monthlyStatistics(orders: List[Order]): Map[String, (Int, Double)] = {
orders.groupBy(order =>
s"${order.orderTime.getYear}-${order.orderTime.getMonthValue:02d}"
).view
.mapValues { orders =>
val count = orders.size
val amount = orders.map(_.totalAmount).sum
(count, amount)
}
.toMap
}
def highValueOrders(orders: List[Order]): List[Order] = {
orders.filter(_.totalAmount > 500)
}
def recentOrders(orders: List[Order], days: Int): List[Order] = {
val cutoff = java.time.LocalDate.now.minusDays(days)
orders.filter(_.orderTime.isAfter(cutoff))
}
def generateCsvReport(data: Map[String, Any]): Unit = {
import java.io.PrintWriter
val writer = new PrintWriter(config.output)
writer.println("指标,数值")
data.foreach {
case ("userSpending", m: Map[_, _]) =>
m.foreach { case (k, v) => writer.println(s"用户 $k 消费额,$v") }
case ("topProducts", l: List[_]) =>
l.foreach { case (id, cnt) => writer.println(s"商品 $id 销量,$cnt") }
case ("monthlyStats", m: Map[_, _]) =>
m.foreach { case (k, (cnt, amt)) =>
writer.println(s"月份 $k 订单数,$cnt | 金额,$amt")
}
case _ =>
}
writer.close()
}
}