應用 APP 功能實作
This commit is contained in:
@@ -57,6 +57,23 @@ export function AppDetailDialog({ open, onOpenChange, app }: AppDetailDialogProp
|
||||
const { user, addToRecentApps, getAppLikes, incrementViewCount, getViewCount, getAppRating } = useAuth()
|
||||
const [currentRating, setCurrentRating] = useState(getAppRating(app.id.toString()))
|
||||
const [reviewCount, setReviewCount] = useState(0)
|
||||
const [appStats, setAppStats] = useState({
|
||||
basic: {
|
||||
views: 0,
|
||||
likes: 0,
|
||||
rating: 0,
|
||||
reviewCount: 0
|
||||
},
|
||||
usage: {
|
||||
dailyUsers: 0,
|
||||
weeklyUsers: 0,
|
||||
monthlyUsers: 0,
|
||||
totalSessions: 0,
|
||||
topDepartments: [],
|
||||
trendData: []
|
||||
}
|
||||
})
|
||||
const [isLoadingStats, setIsLoadingStats] = useState(false)
|
||||
|
||||
// Date range for usage trends
|
||||
const [startDate, setStartDate] = useState(() => {
|
||||
@@ -88,6 +105,34 @@ export function AppDetailDialog({ open, onOpenChange, app }: AppDetailDialogProp
|
||||
setReviewCount(newReviewCount)
|
||||
}
|
||||
|
||||
// 載入應用統計數據
|
||||
const loadAppStats = async () => {
|
||||
if (!app.id) return
|
||||
|
||||
setIsLoadingStats(true)
|
||||
try {
|
||||
const response = await fetch(`/api/apps/${app.id}/stats`)
|
||||
const data = await response.json()
|
||||
|
||||
if (data.success) {
|
||||
setAppStats(data.data)
|
||||
setCurrentRating(data.data.basic.rating)
|
||||
setReviewCount(data.data.basic.reviewCount)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('載入應用統計數據錯誤:', error)
|
||||
} finally {
|
||||
setIsLoadingStats(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 當對話框打開時載入統計數據
|
||||
React.useEffect(() => {
|
||||
if (open && app.id) {
|
||||
loadAppStats()
|
||||
}
|
||||
}, [open, app.id])
|
||||
|
||||
const handleTryApp = () => {
|
||||
if (user) {
|
||||
addToRecentApps(app.id.toString())
|
||||
@@ -245,19 +290,74 @@ export function AppDetailDialog({ open, onOpenChange, app }: AppDetailDialogProp
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<FavoriteButton appId={app.id.toString()} size="default" showText={true} className="px-6" />
|
||||
<Button
|
||||
onClick={handleTryApp}
|
||||
className="flex-1 bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700"
|
||||
className="bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700"
|
||||
>
|
||||
立即體驗
|
||||
</Button>
|
||||
<FavoriteButton appId={app.id.toString()} size="default" showText={true} className="px-6" />
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="statistics" className="space-y-6">
|
||||
{/* Usage Overview */}
|
||||
{/* 基本統計數據 */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium">總瀏覽量</CardTitle>
|
||||
<Eye className="h-4 w-4 text-blue-500" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-blue-600">
|
||||
{isLoadingStats ? '...' : appStats.basic.views}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">累計瀏覽次數</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium">收藏數</CardTitle>
|
||||
<Heart className="h-4 w-4 text-red-500" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-red-600">
|
||||
{isLoadingStats ? '...' : appStats.basic.likes}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">用戶收藏數量</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium">平均評分</CardTitle>
|
||||
<Star className="h-4 w-4 text-yellow-500" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-yellow-600">
|
||||
{isLoadingStats ? '...' : appStats.basic.rating.toFixed(1)}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">用戶評分</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium">評價數量</CardTitle>
|
||||
<MessageSquare className="h-4 w-4 text-green-500" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-green-600">
|
||||
{isLoadingStats ? '...' : appStats.basic.reviewCount}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">用戶評價總數</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* 使用趨勢 */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
@@ -265,7 +365,9 @@ export function AppDetailDialog({ open, onOpenChange, app }: AppDetailDialogProp
|
||||
<Users className="h-4 w-4 text-blue-500" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">{usageStats.dailyUsers}</div>
|
||||
<div className="text-2xl font-bold">
|
||||
{isLoadingStats ? '...' : appStats.usage.dailyUsers}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">活躍用戶數</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -276,7 +378,9 @@ export function AppDetailDialog({ open, onOpenChange, app }: AppDetailDialogProp
|
||||
<TrendingUp className="h-4 w-4 text-green-500" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">{usageStats.weeklyUsers}</div>
|
||||
<div className="text-2xl font-bold">
|
||||
{isLoadingStats ? '...' : appStats.usage.weeklyUsers}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">週活躍用戶</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -287,7 +391,9 @@ export function AppDetailDialog({ open, onOpenChange, app }: AppDetailDialogProp
|
||||
<BarChart3 className="h-4 w-4 text-purple-500" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">{usageStats.totalSessions.toLocaleString()}</div>
|
||||
<div className="text-2xl font-bold">
|
||||
{isLoadingStats ? '...' : appStats.usage.totalSessions.toLocaleString()}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">累計使用次數</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
Reference in New Issue
Block a user