132 lines
5.2 KiB
TypeScript
132 lines
5.2 KiB
TypeScript
"use client"
|
|
|
|
import { ArrowDownLeft, ArrowUpRight, CreditCard, DollarSign } from "lucide-react"
|
|
import { Badge } from "@/components/ui/badge"
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from "@/components/ui/table"
|
|
import { listTransactions } from "@/lib/api"
|
|
import { useAuthStore } from "@/store/auth"
|
|
import { useOrderStore } from "@/store/orders"
|
|
import { useShopStore } from "@/store/shops"
|
|
|
|
export default function ShopIncomePage() {
|
|
const userId = useAuthStore((state) => state.user?.id)
|
|
const shops = useShopStore((state) => state.shops)
|
|
const orders = useOrderStore((state) => state.orders)
|
|
const shop = shops.find((item) => item.owner.id === userId) ?? shops[0]
|
|
const shopOrders = orders.filter((order) => order.shopId === shop?.id)
|
|
const completedOrders = shopOrders.filter((o) => o.status === "completed")
|
|
const totalIncome = completedOrders.reduce((acc, order) => acc + order.totalPrice, 0)
|
|
|
|
const currentMonth = new Date().getMonth()
|
|
const thisMonthIncome = completedOrders
|
|
.filter((o) => new Date(o.completedAt || "").getMonth() === currentMonth)
|
|
.reduce((acc, order) => acc + order.totalPrice, 0)
|
|
|
|
const pendingSettlement = shopOrders
|
|
.filter((o) => ["in_progress", "pending_close", "pending_review"].includes(o.status))
|
|
.reduce((acc, order) => acc + order.totalPrice, 0)
|
|
|
|
const shopOrderIds = new Set(shopOrders.map((order) => order.id))
|
|
const relatedTransactions = listTransactions().filter((transaction) => {
|
|
if (transaction.type === "withdrawal") return true
|
|
if (transaction.type !== "income") return false
|
|
const match = transaction.description.match(/ord\d+/)
|
|
if (!match) return false
|
|
return shopOrderIds.has(match[0])
|
|
})
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<h1 className="text-2xl font-bold">收入统计</h1>
|
|
|
|
<div className="grid gap-4 sm:grid-cols-3">
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|
<CardTitle className="text-sm font-medium">总收入</CardTitle>
|
|
<DollarSign className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">¥{totalIncome.toFixed(2)}</div>
|
|
</CardContent>
|
|
</Card>
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|
<CardTitle className="text-sm font-medium">本月收入</CardTitle>
|
|
<CreditCard className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">¥{thisMonthIncome.toFixed(2)}</div>
|
|
</CardContent>
|
|
</Card>
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|
<CardTitle className="text-sm font-medium">待结算</CardTitle>
|
|
<ArrowUpRight className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">¥{pendingSettlement.toFixed(2)}</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>交易明细</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>类型</TableHead>
|
|
<TableHead>描述</TableHead>
|
|
<TableHead>金额</TableHead>
|
|
<TableHead>时间</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{relatedTransactions.map((transaction) => (
|
|
<TableRow key={transaction.id}>
|
|
<TableCell>
|
|
<div className="flex items-center gap-2">
|
|
{transaction.amount > 0 ? (
|
|
<ArrowDownLeft className="h-4 w-4 text-green-500" />
|
|
) : (
|
|
<ArrowUpRight className="h-4 w-4 text-red-500" />
|
|
)}
|
|
<Badge variant={transaction.amount > 0 ? "default" : "secondary"}>
|
|
{transaction.type === "topup"
|
|
? "充值"
|
|
: transaction.type === "payment"
|
|
? "支付"
|
|
: transaction.type === "income"
|
|
? "收入"
|
|
: transaction.type === "withdrawal"
|
|
? "提现"
|
|
: "退款"}
|
|
</Badge>
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>{transaction.description}</TableCell>
|
|
<TableCell className={transaction.amount > 0 ? "text-green-600" : "text-red-600"}>
|
|
{transaction.amount > 0 ? "+" : ""}
|
|
{transaction.amount}
|
|
</TableCell>
|
|
<TableCell>{new Date(transaction.createdAt).toLocaleString()}</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
)
|
|
}
|