Compare commits
3 Commits
7f6da1fa10
...
6ef44805f5
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ef44805f5 | |||
| 50c41d8759 | |||
| b21c90c560 |
@@ -60,7 +60,8 @@ export function queryLogs(params: {
|
|||||||
page?: number
|
page?: number
|
||||||
pageSize?: number
|
pageSize?: number
|
||||||
}): Promise<{ lines: string[]; total: number; page: number; pageSize: number }> {
|
}): Promise<{ lines: string[]; total: number; page: number; pageSize: number }> {
|
||||||
return request({ url: `/logs/${params.date}`, data: { ...params, date: undefined } })
|
const { date, ...queryParams } = params
|
||||||
|
return request({ url: `/logs/${date}`, data: queryParams })
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 获取埋点统计 */
|
/** 获取埋点统计 */
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
<text class="card-title">最近7天</text>
|
<text class="card-title">最近7天</text>
|
||||||
<view class="daily-list">
|
<view class="daily-list">
|
||||||
<view v-for="day in stats.daily" :key="day.date" class="daily-item">
|
<view v-for="day in stats.daily" :key="day.date" class="daily-item">
|
||||||
<text class="daily-date">{{ day.date.slice(5) }}</text>
|
<text class="daily-date">{{ formatDate(day.date) }}</text>
|
||||||
<view class="daily-bar">
|
<view class="daily-bar">
|
||||||
<view class="bar-fill" :style="{ width: getBarWidth(day.count) + '%' }"></view>
|
<view class="bar-fill" :style="{ width: getBarWidth(day.count) + '%' }"></view>
|
||||||
</view>
|
</view>
|
||||||
@@ -57,13 +57,14 @@
|
|||||||
<view class="query-section">
|
<view class="query-section">
|
||||||
<view class="query-header">
|
<view class="query-header">
|
||||||
<text class="section-title">事件记录</text>
|
<text class="section-title">事件记录</text>
|
||||||
<view class="filter-tabs">
|
<scroll-view class="filter-tabs" scroll-x>
|
||||||
<view class="filter-tab" :class="{ active: !filterEvent }" @tap="filterEvent = ''">全部</view>
|
<view class="filter-tab" :class="{ active: !filterEvent }" @tap="filterEvent = ''">全部</view>
|
||||||
<view class="filter-tab" :class="{ active: filterEvent === 'page_view' }" @tap="filterEvent = 'page_view'">页面</view>
|
<view class="filter-tab" :class="{ active: filterEvent === 'page_view' }" @tap="filterEvent = 'page_view'">页面</view>
|
||||||
<view class="filter-tab" :class="{ active: filterEvent === 'action' }" @tap="filterEvent = 'action'">操作</view>
|
<view class="filter-tab" :class="{ active: filterEvent === 'action' }" @tap="filterEvent = 'action'">操作</view>
|
||||||
<view class="filter-tab" :class="{ active: filterEvent === 'error' }" @tap="filterEvent = 'error'">错误</view>
|
<view class="filter-tab" :class="{ active: filterEvent === 'error' }" @tap="filterEvent = 'error'">错误</view>
|
||||||
<view class="filter-tab" :class="{ active: filterEvent === 'api_error' }" @tap="filterEvent = 'api_error'">API错误</view>
|
<view class="filter-tab" :class="{ active: filterEvent === 'api_error' }" @tap="filterEvent = 'api_error'">API错误</view>
|
||||||
</view>
|
<view class="filter-tab" :class="{ active: filterEvent === 'app_launch' }" @tap="filterEvent = 'app_launch'">启动</view>
|
||||||
|
</scroll-view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<scroll-view class="event-record-list" scroll-y @scrolltolower="loadMore">
|
<scroll-view class="event-record-list" scroll-y @scrolltolower="loadMore">
|
||||||
@@ -187,6 +188,18 @@ function getEventClass(event: string): string {
|
|||||||
return 'page'
|
return 'page'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 格式化日期(处理 MySQL DATE 类型的 ISO 格式) */
|
||||||
|
function formatDate(dateStr: string): string {
|
||||||
|
if (!dateStr) return ''
|
||||||
|
// 处理 2026-06-08T00:00:00.000Z 格式
|
||||||
|
const datePart = dateStr.split('T')[0]
|
||||||
|
const parts = datePart.split('-')
|
||||||
|
if (parts.length === 3) {
|
||||||
|
return `${parseInt(parts[1])}/${parseInt(parts[2])}`
|
||||||
|
}
|
||||||
|
return dateStr
|
||||||
|
}
|
||||||
|
|
||||||
function formatTime(dateStr: string): string {
|
function formatTime(dateStr: string): string {
|
||||||
const d = new Date(dateStr)
|
const d = new Date(dateStr)
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
@@ -371,7 +384,8 @@ function goBack() {
|
|||||||
.filter-tabs {
|
.filter-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: $space-xs;
|
gap: $space-xs;
|
||||||
flex-wrap: wrap;
|
white-space: nowrap;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-tab {
|
.filter-tab {
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ async function runMigrations(conn: mysql.Connection) {
|
|||||||
content TEXT NOT NULL COMMENT '反馈内容',
|
content TEXT NOT NULL COMMENT '反馈内容',
|
||||||
contact VARCHAR(100) DEFAULT '' COMMENT '联系方式',
|
contact VARCHAR(100) DEFAULT '' COMMENT '联系方式',
|
||||||
status ENUM('pending', 'processed', 'ignored') DEFAULT 'pending' COMMENT '处理状态',
|
status ENUM('pending', 'processed', 'ignored') DEFAULT 'pending' COMMENT '处理状态',
|
||||||
admin_reply TEXT DEFAULT '' COMMENT '管理员回复',
|
admin_reply TEXT COMMENT '管理员回复',
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
INDEX idx_user (user_id),
|
INDEX idx_user (user_id),
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ CREATE TABLE IF NOT EXISTS feedbacks (
|
|||||||
content TEXT NOT NULL COMMENT '反馈内容',
|
content TEXT NOT NULL COMMENT '反馈内容',
|
||||||
contact VARCHAR(100) DEFAULT '' COMMENT '联系方式',
|
contact VARCHAR(100) DEFAULT '' COMMENT '联系方式',
|
||||||
status ENUM('pending', 'processed', 'ignored') DEFAULT 'pending' COMMENT '处理状态',
|
status ENUM('pending', 'processed', 'ignored') DEFAULT 'pending' COMMENT '处理状态',
|
||||||
admin_reply TEXT DEFAULT '' COMMENT '管理员回复',
|
admin_reply TEXT COMMENT '管理员回复',
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
INDEX idx_user (user_id),
|
INDEX idx_user (user_id),
|
||||||
|
|||||||
@@ -157,14 +157,15 @@ router.get('/track/list', requireAdmin, async (req, res) => {
|
|||||||
)
|
)
|
||||||
const total = (countResult as any[])[0].total
|
const total = (countResult as any[])[0].total
|
||||||
|
|
||||||
|
// LIMIT/OFFSET 直接嵌入 SQL(mysql2 execute 对这些参数类型要求严格)
|
||||||
const [rows] = await pool.execute(
|
const [rows] = await pool.execute(
|
||||||
`SELECT t.*, u.nickname
|
`SELECT t.*, u.nickname
|
||||||
FROM track_events t
|
FROM track_events t
|
||||||
LEFT JOIN users u ON t.user_id = u.id
|
LEFT JOIN users u ON t.user_id = u.id
|
||||||
WHERE ${where}
|
WHERE ${where}
|
||||||
ORDER BY t.created_at DESC
|
ORDER BY t.created_at DESC
|
||||||
LIMIT ? OFFSET ?`,
|
LIMIT ${pSize} OFFSET ${offset}`,
|
||||||
[...params, pSize, offset]
|
params
|
||||||
)
|
)
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
|
|||||||
Reference in New Issue
Block a user