修复工单、日志、卡密管理页面的分页和筛选功能
- 工单管理:后端添加分页和筛选支持(status, priority, type, 日期范围) - 日志管理:前端使用服务端分页和筛选(后端已支持) - 卡密管理:前端使用服务端分页和筛选(后端已支持) - 所有页面移除前端筛选逻辑,改为服务端筛选 - 修复分页总数与筛选数据不匹配的问题 - 添加watch监听筛选条件变化,自动刷新数据
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"verification-platform-backend/internal/database"
|
"verification-platform-backend/internal/database"
|
||||||
"verification-platform-backend/internal/model"
|
"verification-platform-backend/internal/model"
|
||||||
@@ -49,12 +50,55 @@ func handleGetTicketStats(c *gin.Context) {
|
|||||||
|
|
||||||
func handleGetTickets(c *gin.Context) {
|
func handleGetTickets(c *gin.Context) {
|
||||||
userID := c.GetUint("user_id")
|
userID := c.GetUint("user_id")
|
||||||
|
|
||||||
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||||
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||||||
|
statusFilter := c.Query("status")
|
||||||
|
priorityFilter := c.Query("priority")
|
||||||
|
typeFilter := c.Query("type")
|
||||||
|
createdStartDate := c.Query("created_start_date")
|
||||||
|
createdEndDate := c.Query("created_end_date")
|
||||||
|
updatedStartDate := c.Query("updated_start_date")
|
||||||
|
updatedEndDate := c.Query("updated_end_date")
|
||||||
|
|
||||||
|
query := database.DB.Model(&model.Ticket{}).Where("user_id = ? OR assigned_to = ?", userID, userID)
|
||||||
|
|
||||||
|
if statusFilter != "" {
|
||||||
|
query = query.Where("status = ?", statusFilter)
|
||||||
|
}
|
||||||
|
if priorityFilter != "" {
|
||||||
|
query = query.Where("priority = ?", priorityFilter)
|
||||||
|
}
|
||||||
|
if typeFilter != "" {
|
||||||
|
query = query.Where("type = ?", typeFilter)
|
||||||
|
}
|
||||||
|
if createdStartDate != "" {
|
||||||
|
query = query.Where("created_at >= ?", createdStartDate+" 00:00:00")
|
||||||
|
}
|
||||||
|
if createdEndDate != "" {
|
||||||
|
query = query.Where("created_at <= ?", createdEndDate+" 23:59:59")
|
||||||
|
}
|
||||||
|
if updatedStartDate != "" {
|
||||||
|
query = query.Where("updated_at >= ?", updatedStartDate+" 00:00:00")
|
||||||
|
}
|
||||||
|
if updatedEndDate != "" {
|
||||||
|
query = query.Where("updated_at <= ?", updatedEndDate+" 23:59:59")
|
||||||
|
}
|
||||||
|
|
||||||
|
var total int64
|
||||||
|
query.Count(&total)
|
||||||
|
|
||||||
|
offset := (page - 1) * pageSize
|
||||||
|
|
||||||
var tickets []model.Ticket
|
var tickets []model.Ticket
|
||||||
if err := database.DB.Where("user_id = ? OR assigned_to = ?", userID, userID).
|
if err := query.
|
||||||
Preload("Replies").
|
Preload("Replies").
|
||||||
Preload("Application").
|
Preload("Application").
|
||||||
Preload("User").
|
Preload("User").
|
||||||
Preload("AssignedUser").
|
Preload("AssignedUser").
|
||||||
|
Order("created_at DESC").
|
||||||
|
Offset(offset).
|
||||||
|
Limit(pageSize).
|
||||||
Find(&tickets).Error; err != nil {
|
Find(&tickets).Error; err != nil {
|
||||||
response.Error(c, 500, "获取工单列表失败")
|
response.Error(c, 500, "获取工单列表失败")
|
||||||
return
|
return
|
||||||
@@ -84,8 +128,11 @@ func handleGetTickets(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
response.Success(c, gin.H{
|
response.Success(c, gin.H{
|
||||||
"tickets": result,
|
"tickets": result,
|
||||||
"total": len(result),
|
"total": total,
|
||||||
|
"page": page,
|
||||||
|
"page_size": pageSize,
|
||||||
|
"total_page": (total + int64(pageSize) - 1) / int64(pageSize),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ const cards = ref<Card[]>([])
|
|||||||
const tableRef = ref()
|
const tableRef = ref()
|
||||||
const applications = ref<Application[]>([])
|
const applications = ref<Application[]>([])
|
||||||
const cardTypes = ref<CardType[]>([])
|
const cardTypes = ref<CardType[]>([])
|
||||||
|
const currentPage = ref(1)
|
||||||
|
const pageSize = ref(20)
|
||||||
|
const total = ref(0)
|
||||||
|
|
||||||
const appFilter = ref<string>('')
|
const appFilter = ref<string>('')
|
||||||
const cardTypeFilter = ref<string>('')
|
const cardTypeFilter = ref<string>('')
|
||||||
@@ -56,52 +59,9 @@ const filteredCardTypes = computed(() => {
|
|||||||
return cardTypes.value
|
return cardTypes.value
|
||||||
})
|
})
|
||||||
|
|
||||||
const filteredCards = computed(() => {
|
const unusedCount = computed(() => cards.value.filter(card => card.status === 'unused').length)
|
||||||
let result = cards.value
|
const usedCount = computed(() => cards.value.filter(card => card.status === 'used').length)
|
||||||
|
const bannedCount = computed(() => cards.value.filter(card => card.status === 'banned').length)
|
||||||
if (appFilter.value) {
|
|
||||||
result = result.filter(card => String(card.application_id) === appFilter.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cardTypeFilter.value) {
|
|
||||||
result = result.filter(card => String(card.card_type_id) === cardTypeFilter.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (statusFilter.value) {
|
|
||||||
result = result.filter(card => card.status === statusFilter.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startDate.value) {
|
|
||||||
const fromDateTime = startDate.value.includes('T')
|
|
||||||
? startDate.value.replace('T', ' ')
|
|
||||||
: `${startDate.value} 00:00`
|
|
||||||
result = result.filter(card => card.created_at >= fromDateTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endDate.value) {
|
|
||||||
const toDateTime = endDate.value.includes('T')
|
|
||||||
? endDate.value.replace('T', ' ')
|
|
||||||
: `${endDate.value} 23:59`
|
|
||||||
result = result.filter(card => card.created_at <= toDateTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (searchFilter.value) {
|
|
||||||
const search = searchFilter.value.toLowerCase()
|
|
||||||
result = result.filter(card =>
|
|
||||||
card.card_key?.toLowerCase().includes(search)
|
|
||||||
|| card.application?.name?.toLowerCase().includes(search)
|
|
||||||
|| card.card_type?.name?.toLowerCase().includes(search)
|
|
||||||
|| card.creator?.username?.toLowerCase().includes(search)
|
|
||||||
|| card.app_user?.username?.toLowerCase().includes(search),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
|
|
||||||
const unusedCount = computed(() => filteredCards.value.filter(card => card.status === 'unused').length)
|
|
||||||
const usedCount = computed(() => filteredCards.value.filter(card => card.status === 'used').length)
|
|
||||||
const bannedCount = computed(() => filteredCards.value.filter(card => card.status === 'banned').length)
|
|
||||||
|
|
||||||
const applicationOptions = computed(() => {
|
const applicationOptions = computed(() => {
|
||||||
return applications.value.map(app => ({
|
return applications.value.map(app => ({
|
||||||
@@ -149,16 +109,32 @@ async function fetchCardTypes() {
|
|||||||
async function fetchCards() {
|
async function fetchCards() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
const data = await api.get<any>('/dev/cards')
|
const params = new URLSearchParams()
|
||||||
if (data && typeof data === 'object' && data.cards) {
|
params.append('page', String(currentPage.value))
|
||||||
cards.value = data.cards
|
params.append('page_size', String(pageSize.value))
|
||||||
|
|
||||||
|
if (appFilter.value) {
|
||||||
|
params.append('application_id', appFilter.value)
|
||||||
}
|
}
|
||||||
else if (Array.isArray(data)) {
|
if (cardTypeFilter.value) {
|
||||||
cards.value = data
|
params.append('card_type_id', cardTypeFilter.value)
|
||||||
}
|
}
|
||||||
else {
|
if (statusFilter.value) {
|
||||||
cards.value = []
|
params.append('status', statusFilter.value)
|
||||||
}
|
}
|
||||||
|
if (startDate.value) {
|
||||||
|
params.append('start_date', startDate.value.split('T')[0])
|
||||||
|
}
|
||||||
|
if (endDate.value) {
|
||||||
|
params.append('end_date', endDate.value.split('T')[0])
|
||||||
|
}
|
||||||
|
if (searchFilter.value) {
|
||||||
|
params.append('search', searchFilter.value.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await api.get<{ cards: Card[], total: number }>(`/dev/cards?${params.toString()}`)
|
||||||
|
cards.value = data?.cards || []
|
||||||
|
total.value = data?.total || 0
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('获取卡密列表失败:', error)
|
console.error('获取卡密列表失败:', error)
|
||||||
@@ -281,6 +257,21 @@ onMounted(() => {
|
|||||||
fetchCardTypes()
|
fetchCardTypes()
|
||||||
fetchCards()
|
fetchCards()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch([appFilter, cardTypeFilter, statusFilter, startDate, endDate, searchFilter], () => {
|
||||||
|
currentPage.value = 1
|
||||||
|
fetchCards()
|
||||||
|
})
|
||||||
|
|
||||||
|
const serverPagination = computed(() => ({
|
||||||
|
currentPage: currentPage.value,
|
||||||
|
pageSize: pageSize.value,
|
||||||
|
total: total.value,
|
||||||
|
onChange: (page: number) => {
|
||||||
|
currentPage.value = page
|
||||||
|
fetchCards()
|
||||||
|
},
|
||||||
|
}))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -307,7 +298,7 @@ onMounted(() => {
|
|||||||
</UiCardHeader>
|
</UiCardHeader>
|
||||||
<UiCardContent>
|
<UiCardContent>
|
||||||
<div class="text-2xl font-bold">
|
<div class="text-2xl font-bold">
|
||||||
{{ filteredCards.length }}
|
{{ total }}
|
||||||
</div>
|
</div>
|
||||||
</UiCardContent>
|
</UiCardContent>
|
||||||
</UiCard>
|
</UiCard>
|
||||||
@@ -360,7 +351,8 @@ onMounted(() => {
|
|||||||
<DataTable
|
<DataTable
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
:loading
|
:loading
|
||||||
:data="filteredCards"
|
:data="cards"
|
||||||
|
:server-pagination="serverPagination"
|
||||||
:on-toggle-status="toggleStatus"
|
:on-toggle-status="toggleStatus"
|
||||||
:on-delete="confirmDeleteCard"
|
:on-delete="confirmDeleteCard"
|
||||||
:search-filter="searchFilter"
|
:search-filter="searchFilter"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Activity, CheckCircle, FileText, XCircle } from 'lucide-vue-next'
|
import { Activity, CheckCircle, FileText, XCircle } from 'lucide-vue-next'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
import type { Log } from '@/pages/admin/logs/data/schema'
|
import type { Log } from '@/pages/admin/logs/data/schema'
|
||||||
@@ -21,6 +21,9 @@ interface Application {
|
|||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const logs = ref<Log[]>([])
|
const logs = ref<Log[]>([])
|
||||||
const applications = ref<Application[]>([])
|
const applications = ref<Application[]>([])
|
||||||
|
const currentPage = ref(1)
|
||||||
|
const pageSize = ref(20)
|
||||||
|
const total = ref(0)
|
||||||
|
|
||||||
const appFilter = ref<string>('')
|
const appFilter = ref<string>('')
|
||||||
const typeFilter = ref<string>('')
|
const typeFilter = ref<string>('')
|
||||||
@@ -28,41 +31,9 @@ const statusFilter = ref<string>('')
|
|||||||
const startDate = ref<string>('')
|
const startDate = ref<string>('')
|
||||||
const endDate = ref<string>('')
|
const endDate = ref<string>('')
|
||||||
|
|
||||||
const filteredLogs = computed(() => {
|
const successCount = computed(() => logs.value.filter(log => log.status === 'success').length)
|
||||||
let result = logs.value
|
const failedCount = computed(() => logs.value.filter(log => log.status === 'failed').length)
|
||||||
|
const operationCount = computed(() => logs.value.filter(log => log.log_type === 'operation').length)
|
||||||
if (appFilter.value) {
|
|
||||||
result = result.filter(log => String(log.application_id) === appFilter.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeFilter.value) {
|
|
||||||
result = result.filter(log => log.log_type === typeFilter.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (statusFilter.value) {
|
|
||||||
result = result.filter(log => log.status === statusFilter.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startDate.value) {
|
|
||||||
const fromDateTime = startDate.value.includes('T')
|
|
||||||
? startDate.value.replace('T', ' ')
|
|
||||||
: `${startDate.value} 00:00`
|
|
||||||
result = result.filter(log => log.created_at >= fromDateTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endDate.value) {
|
|
||||||
const toDateTime = endDate.value.includes('T')
|
|
||||||
? endDate.value.replace('T', ' ')
|
|
||||||
: `${endDate.value} 23:59`
|
|
||||||
result = result.filter(log => log.created_at <= toDateTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
|
|
||||||
const successCount = computed(() => filteredLogs.value.filter(log => log.status === 'success').length)
|
|
||||||
const failedCount = computed(() => filteredLogs.value.filter(log => log.status === 'failed').length)
|
|
||||||
const operationCount = computed(() => filteredLogs.value.filter(log => log.log_type === 'operation').length)
|
|
||||||
|
|
||||||
const applicationOptions = computed(() => {
|
const applicationOptions = computed(() => {
|
||||||
return applications.value.map(app => ({
|
return applications.value.map(app => ({
|
||||||
@@ -95,8 +66,29 @@ async function fetchApplications() {
|
|||||||
async function fetchLogs() {
|
async function fetchLogs() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
const data = await api.get<{ logs: Log[] }>('/dev/logs')
|
const params = new URLSearchParams()
|
||||||
|
params.append('page', String(currentPage.value))
|
||||||
|
params.append('page_size', String(pageSize.value))
|
||||||
|
|
||||||
|
if (appFilter.value) {
|
||||||
|
params.append('application_id', appFilter.value)
|
||||||
|
}
|
||||||
|
if (typeFilter.value) {
|
||||||
|
params.append('type', typeFilter.value)
|
||||||
|
}
|
||||||
|
if (statusFilter.value) {
|
||||||
|
params.append('status', statusFilter.value)
|
||||||
|
}
|
||||||
|
if (startDate.value) {
|
||||||
|
params.append('start_date', startDate.value.split('T')[0])
|
||||||
|
}
|
||||||
|
if (endDate.value) {
|
||||||
|
params.append('end_date', endDate.value.split('T')[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await api.get<{ logs: Log[], total: number }>(`/dev/logs?${params.toString()}`)
|
||||||
logs.value = data?.logs || []
|
logs.value = data?.logs || []
|
||||||
|
total.value = data?.total || 0
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('获取日志记录失败:', error)
|
console.error('获取日志记录失败:', error)
|
||||||
@@ -111,6 +103,21 @@ onMounted(() => {
|
|||||||
fetchApplications()
|
fetchApplications()
|
||||||
fetchLogs()
|
fetchLogs()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch([appFilter, typeFilter, statusFilter, startDate, endDate], () => {
|
||||||
|
currentPage.value = 1
|
||||||
|
fetchLogs()
|
||||||
|
})
|
||||||
|
|
||||||
|
const serverPagination = computed(() => ({
|
||||||
|
currentPage: currentPage.value,
|
||||||
|
pageSize: pageSize.value,
|
||||||
|
total: total.value,
|
||||||
|
onChange: (page: number) => {
|
||||||
|
currentPage.value = page
|
||||||
|
fetchLogs()
|
||||||
|
},
|
||||||
|
}))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -130,7 +137,7 @@ onMounted(() => {
|
|||||||
</UiCardHeader>
|
</UiCardHeader>
|
||||||
<UiCardContent>
|
<UiCardContent>
|
||||||
<div class="text-2xl font-bold">
|
<div class="text-2xl font-bold">
|
||||||
{{ filteredLogs.length }}
|
{{ total }}
|
||||||
</div>
|
</div>
|
||||||
</UiCardContent>
|
</UiCardContent>
|
||||||
</UiCard>
|
</UiCard>
|
||||||
@@ -182,7 +189,8 @@ onMounted(() => {
|
|||||||
<UiCardContent class="p-6">
|
<UiCardContent class="p-6">
|
||||||
<DataTable
|
<DataTable
|
||||||
:loading
|
:loading
|
||||||
:data="filteredLogs"
|
:data="logs"
|
||||||
|
:server-pagination="serverPagination"
|
||||||
@refresh="fetchLogs"
|
@refresh="fetchLogs"
|
||||||
>
|
>
|
||||||
<template #filters>
|
<template #filters>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { AlertCircle, CheckCircle, Clock, MessageSquare, Plus } from 'lucide-vue-next'
|
import { AlertCircle, CheckCircle, Clock, MessageSquare, Plus } from 'lucide-vue-next'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { toast } from 'vue-sonner'
|
import { toast } from 'vue-sonner'
|
||||||
@@ -21,6 +21,9 @@ const router = useRouter()
|
|||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const tickets = ref<Ticket[]>([])
|
const tickets = ref<Ticket[]>([])
|
||||||
const tableRef = ref()
|
const tableRef = ref()
|
||||||
|
const currentPage = ref(1)
|
||||||
|
const pageSize = ref(20)
|
||||||
|
const total = ref(0)
|
||||||
|
|
||||||
const statusFilter = ref<string>('')
|
const statusFilter = ref<string>('')
|
||||||
const priorityFilter = ref<string>('')
|
const priorityFilter = ref<string>('')
|
||||||
@@ -35,52 +38,6 @@ const deleteTarget = ref<Ticket | null>(null)
|
|||||||
const batchDeleteDialogOpen = ref(false)
|
const batchDeleteDialogOpen = ref(false)
|
||||||
const batchDeleteIds = ref<(string | number)[]>([])
|
const batchDeleteIds = ref<(string | number)[]>([])
|
||||||
|
|
||||||
const filteredTickets = computed(() => {
|
|
||||||
let result = [...tickets.value]
|
|
||||||
|
|
||||||
if (statusFilter.value) {
|
|
||||||
result = result.filter(t => t.status === statusFilter.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priorityFilter.value) {
|
|
||||||
result = result.filter(t => t.priority === priorityFilter.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeFilter.value) {
|
|
||||||
result = result.filter(t => t.type === typeFilter.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (createdStartDate.value) {
|
|
||||||
const fromDateTime = createdStartDate.value.includes('T')
|
|
||||||
? createdStartDate.value.replace('T', ' ')
|
|
||||||
: `${createdStartDate.value} 00:00`
|
|
||||||
result = result.filter(t => t.created_at >= fromDateTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (createdEndDate.value) {
|
|
||||||
const toDateTime = createdEndDate.value.includes('T')
|
|
||||||
? createdEndDate.value.replace('T', ' ')
|
|
||||||
: `${createdEndDate.value} 23:59`
|
|
||||||
result = result.filter(t => t.created_at <= toDateTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updatedStartDate.value) {
|
|
||||||
const fromDateTime = updatedStartDate.value.includes('T')
|
|
||||||
? updatedStartDate.value.replace('T', ' ')
|
|
||||||
: `${updatedStartDate.value} 00:00`
|
|
||||||
result = result.filter(t => t.updated_at && t.updated_at >= fromDateTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updatedEndDate.value) {
|
|
||||||
const toDateTime = updatedEndDate.value.includes('T')
|
|
||||||
? updatedEndDate.value.replace('T', ' ')
|
|
||||||
: `${updatedEndDate.value} 23:59`
|
|
||||||
result = result.filter(t => t.updated_at && t.updated_at <= toDateTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
|
|
||||||
const openCount = computed(() => tickets.value.filter(t => t.status === 'open').length)
|
const openCount = computed(() => tickets.value.filter(t => t.status === 'open').length)
|
||||||
const pendingCount = computed(() => tickets.value.filter(t => t.status === 'processing').length)
|
const pendingCount = computed(() => tickets.value.filter(t => t.status === 'processing').length)
|
||||||
const resolvedCount = computed(() => tickets.value.filter(t => t.status === 'resolved').length)
|
const resolvedCount = computed(() => tickets.value.filter(t => t.status === 'resolved').length)
|
||||||
@@ -107,8 +64,35 @@ const typeOptions = computed(() => [
|
|||||||
async function fetchTickets() {
|
async function fetchTickets() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
const data = await api.get<{ tickets: Ticket[] }>('/dev/tickets')
|
const params = new URLSearchParams()
|
||||||
|
params.append('page', String(currentPage.value))
|
||||||
|
params.append('page_size', String(pageSize.value))
|
||||||
|
|
||||||
|
if (statusFilter.value) {
|
||||||
|
params.append('status', statusFilter.value)
|
||||||
|
}
|
||||||
|
if (priorityFilter.value) {
|
||||||
|
params.append('priority', priorityFilter.value)
|
||||||
|
}
|
||||||
|
if (typeFilter.value) {
|
||||||
|
params.append('type', typeFilter.value)
|
||||||
|
}
|
||||||
|
if (createdStartDate.value) {
|
||||||
|
params.append('created_start_date', createdStartDate.value.split('T')[0])
|
||||||
|
}
|
||||||
|
if (createdEndDate.value) {
|
||||||
|
params.append('created_end_date', createdEndDate.value.split('T')[0])
|
||||||
|
}
|
||||||
|
if (updatedStartDate.value) {
|
||||||
|
params.append('updated_start_date', updatedStartDate.value.split('T')[0])
|
||||||
|
}
|
||||||
|
if (updatedEndDate.value) {
|
||||||
|
params.append('updated_end_date', updatedEndDate.value.split('T')[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await api.get<{ tickets: Ticket[], total: number }>(`/dev/tickets?${params.toString()}`)
|
||||||
tickets.value = data?.tickets || []
|
tickets.value = data?.tickets || []
|
||||||
|
total.value = data?.total || 0
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('获取工单列表失败:', error)
|
console.error('获取工单列表失败:', error)
|
||||||
@@ -183,6 +167,21 @@ async function handleBatchDelete() {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchTickets()
|
fetchTickets()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch([statusFilter, priorityFilter, typeFilter, createdStartDate, createdEndDate, updatedStartDate, updatedEndDate], () => {
|
||||||
|
currentPage.value = 1
|
||||||
|
fetchTickets()
|
||||||
|
})
|
||||||
|
|
||||||
|
const serverPagination = computed(() => ({
|
||||||
|
currentPage: currentPage.value,
|
||||||
|
pageSize: pageSize.value,
|
||||||
|
total: total.value,
|
||||||
|
onChange: (page: number) => {
|
||||||
|
currentPage.value = page
|
||||||
|
fetchTickets()
|
||||||
|
},
|
||||||
|
}))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -251,7 +250,7 @@ onMounted(() => {
|
|||||||
</UiCardHeader>
|
</UiCardHeader>
|
||||||
<UiCardContent>
|
<UiCardContent>
|
||||||
<div class="text-2xl font-bold">
|
<div class="text-2xl font-bold">
|
||||||
{{ filteredTickets.length }}
|
{{ total }}
|
||||||
</div>
|
</div>
|
||||||
</UiCardContent>
|
</UiCardContent>
|
||||||
</UiCard>
|
</UiCard>
|
||||||
@@ -262,7 +261,8 @@ onMounted(() => {
|
|||||||
<DataTable
|
<DataTable
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
:loading
|
:loading
|
||||||
:data="filteredTickets"
|
:data="tickets"
|
||||||
|
:server-pagination="serverPagination"
|
||||||
:on-update-status="updateTicketStatus"
|
:on-update-status="updateTicketStatus"
|
||||||
:on-view-detail="openTicketDetail"
|
:on-view-detail="openTicketDetail"
|
||||||
:on-delete="confirmDeleteTicket"
|
:on-delete="confirmDeleteTicket"
|
||||||
|
|||||||
Reference in New Issue
Block a user