Files
Message-Push-Nest/web/src/components/pages/sendLogs/SendLogs.vue
T
2025-08-10 18:07:38 +08:00

215 lines
7.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { ref, computed, reactive, onMounted } from 'vue'
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import { Input } from '@/components/ui/input'
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/ui/sheet'
import EmptyTableState from '@/components/ui/EmptyTableState.vue'
import Pagination from '@/components/ui/Pagination.vue'
import { useRoute } from 'vue-router';
import { request } from '@/api/api';
// @ts-ignore
import { getPageSize } from '@/util/pageUtils';
interface LogItem {
id: number
task_id: number
task_name: string
log: string
created_on: string
caller_ip?: string
status: number
}
const router = useRoute();
let state = reactive({
tableData: [] as LogItem[],
total: 0,
currPage: 1,
pageSize: getPageSize(),
search: '',
optionValue: '',
})
// 状态过滤
const selectedStatus = ref('all')
// Sheet 相关状态
const isSheetOpen = ref(false)
const selectedLog = ref('')
const selectedTaskName = ref('')
// 总页数
const totalPages = computed(() => Math.ceil(state.total / state.pageSize))
const getStatusText = (status: number) => {
return status === 1 ? '成功' : '失败'
}
// 打开日志详情Sheet
const openLogSheet = (task: LogItem) => {
selectedLog.value = formatLogDisplayHtml(task);
selectedTaskName.value = task.task_name
isSheetOpen.value = true
}
const changePage = async (page: number) => {
if (page >= 1 && page <= totalPages.value) {
state.currPage = page
await queryListData(
state.currPage,
state.pageSize,
state.search,
state.optionValue
)
}
}
// 格式化处理显示的日志文本
const formatLogDisplayHtml = (task: LogItem) => {
let log = task.log;
log += '\n';
if (task.caller_ip) {
log += `调用来源IP${task.caller_ip}`;
};
return log;
}
//触发过滤筛选
const filterFunc = async () => {
await queryListData(state.currPage, state.pageSize, state.search, state.optionValue);
}
// 按状态过滤
const filterByStatus = async (value: any) => {
if (value) {
state.currPage = 1; // 重置到第一页
await queryListData(state.currPage, state.pageSize, state.search, state.optionValue, JSON.stringify({
status: selectedStatus.value === 'all' ? '' : selectedStatus.value
}));
}
}
const queryListData = async (page: number, size: number, name = '', taskid = '', query = '', _status = '') => {
let params: any = { page: page, size: size, name: name, taskid: taskid, query: query };
if (selectedStatus.value !== '' && selectedStatus.value !== 'all') {
params.query = JSON.stringify({
status: selectedStatus.value === 'all' ? '' : selectedStatus.value
})
}
const rsp = await request.get('/sendlogs/list', { params: params });
state.tableData = await rsp.data.data.lists;
// state.tableData = []
state.total = await rsp.data.data.total;
}
onMounted(async () => {
// 页面加载触发日志显示
state.search = router.query.name?.toString() || '';
await queryListData(
1,
state.pageSize,
router.query.name?.toString() || '',
router.query.taskid?.toString() || '',
router.query.query?.toString() || ''
);
});
</script>
<template>
<div class="p-6 w-full max-w-6xl mx-auto space-y-2">
<div class="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
<div class="flex-1 sm:flex-initial">
<Input v-model="state.search" placeholder="搜索任务..." class="w-full sm:w-64" @keyup.enter="filterFunc"
@blur="filterFunc" />
</div>
<div class="flex-1 sm:flex-initial">
<Select v-model="selectedStatus" class="w-full" @update:model-value="filterByStatus">
<SelectTrigger>
<SelectValue placeholder="选择状态" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="all">全部</SelectItem>
<SelectItem value="1">成功</SelectItem>
<SelectItem value="0">失败</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
</div>
<!-- 表格 -->
<Table>
<TableHeader>
<TableRow>
<TableHead class="w-20">ID</TableHead>
<TableHead>任务名称</TableHead>
<TableHead>发信日志</TableHead>
<TableHead>发送时间</TableHead>
<TableHead class="text-center">详情/状态</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<!-- 空数据展示 -->
<TableRow v-if="state.tableData.length === 0">
<TableCell colspan="5" class="text-center py-12">
<EmptyTableState
title="暂无发信日志"
description="还没有任何发信日志记录"
>
<template #icon>
<svg class="w-8 h-8 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
</svg>
</template>
</EmptyTableState>
</TableCell>
</TableRow>
<!-- 数据行 -->
<TableRow v-for="task in state.tableData" :key="task.id">
<TableCell>{{ task.task_id }}</TableCell>
<TableCell>{{ task.task_name }}</TableCell>
<TableCell class="max-w-xs truncate" :title="formatLogDisplayHtml(task)">{{ task.log }}</TableCell>
<TableCell>{{ task.created_on }}</TableCell>
<TableCell class="text-center space-x-2">
<Button size="sm" variant="outline" @click="openLogSheet(task)">查看</Button>
<!-- <Button size="sm" variant="destructive">删除</Button> -->
<Badge :class="task.status === 1 ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-600'">
{{ getStatusText(task.status) }}
</Badge>
</TableCell>
</TableRow>
</TableBody>
</Table>
<!-- 分页 -->
<Pagination
:total="state.total"
:current-page="state.currPage"
:page-size="state.pageSize"
@page-change="changePage"
/>
<!-- 日志详情Sheet -->
<Sheet v-model:open="isSheetOpen" class="w-[700px] sm:w-[1000px] lg:w-[1200px]">
<SheetContent class="w-[700px] sm:w-[1000px] lg:w-[1200px]">
<SheetHeader>
<SheetTitle>{{ selectedTaskName }} - 发信日志详情</SheetTitle>
</SheetHeader>
<div class="mt-4">
<div class="bg-gray-50 p-4 rounded-lg max-h-[82vh] overflow-y-auto break-words">
<pre class="whitespace-pre-wrap text-sm font-mono">{{ selectedLog }}</pre>
</div>
</div>
</SheetContent>
</Sheet>
</div>
</template>