issue-ai/src/app/(app)/tickets/[id]/page.tsx

131 lines
4.3 KiB
TypeScript

'use client'
import { useState, useEffect } from 'react'
import { useParams, useRouter } from 'next/navigation'
import TicketDetail from '@/components/tickets/TicketDetail'
import ProcessForm from '@/components/tickets/ProcessForm'
import { ArrowLeft } from 'lucide-react'
interface HistoryTicket {
id: number
content: string | null
fault_category: string | null
current_status: string
assign_time: string | null
}
export default function TicketDetailPage() {
const params = useParams()
const router = useRouter()
const [data, setData] = useState<any>(null)
const [history, setHistory] = useState<HistoryTicket[]>([])
const [loading, setLoading] = useState(true)
const [showProcessForm, setShowProcessForm] = useState(false)
const [currentUser, setCurrentUser] = useState<{ id: number; display_name: string; role: string } | null>(null)
useEffect(() => {
fetch('/api/auth/me')
.then(r => r.json())
.then(u => { if (u.user) setCurrentUser(u.user) })
.catch(() => {})
}, [])
useEffect(() => {
const id = params.id as string
fetch(`/api/tickets/${id}`)
.then(r => r.json())
.then(d => {
if (d.ticket) {
setData(d)
const ip = d.ticket.device_ip
if (ip) {
fetch(`/api/tickets/by-asset?ip=${encodeURIComponent(ip)}`)
.then(r => r.json())
.then(h => {
const tickets: HistoryTicket[] = (h.tickets || [])
.filter((t: HistoryTicket) => t.id !== d.ticket.id)
.sort((a: HistoryTicket, b: HistoryTicket) => {
const ta = a.assign_time || ''
const tb = b.assign_time || ''
return tb.localeCompare(ta)
})
setHistory(tickets)
})
.catch(() => {})
}
}
})
.catch(() => {})
.finally(() => setLoading(false))
}, [params.id])
if (loading) return <div className="text-center py-12 text-slate-500 dark:text-slate-400">...</div>
if (!data) return <div className="text-center py-12 text-slate-500 dark:text-slate-400"></div>
const ticket = data.ticket
async function handleDelete() {
if (!confirm('确定要删除此工单吗?')) return
try {
const res = await fetch(`/api/tickets/${ticket.id}`, { method: 'DELETE' })
const data = await res.json()
if (res.ok) {
handleBack()
} else {
alert(data.error || '删除失败')
}
} catch (e) {
alert('删除失败:网络错误')
}
}
const isPending = (ticket.current_status === 'open' || ticket.current_status === 'in_progress') && !ticket.close_time
const isAdmin = currentUser?.role === 'admin'
const isCreator = currentUser?.id != null && currentUser.id === ticket.created_by
const canDelete = isAdmin || (isPending && isCreator)
const buttonLabel = ticket.current_status === 'in_progress' ? '继续处理' : '开始处理'
function handleBack() {
if (window.history.length > 1) {
router.back()
} else {
router.push(isPending ? '/tickets/pending' : '/tickets/completed')
}
}
return (
<div className="space-y-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<button onClick={handleBack} className="p-2 rounded-lg text-slate-500 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors">
<ArrowLeft size={20} />
</button>
<h1 className="text-2xl font-bold text-slate-900 dark:text-white"></h1>
</div>
</div>
<TicketDetail
ticket={ticket}
steps={data.steps || []}
assetInfo={data.assetInfo || null}
history={history}
showEdit={isAdmin && !isPending}
showProcess={isPending && !showProcessForm}
processLabel={buttonLabel}
onProcess={() => setShowProcessForm(true)}
onDelete={handleDelete}
canDelete={canDelete}
/>
{showProcessForm && (
<ProcessForm
ticket={ticket}
currentUserDisplayName={currentUser?.display_name || ''}
onSuccess={() => {
router.push('/tickets/completed')
router.refresh()
}}
onCancel={() => setShowProcessForm(false)}
/>
)}
</div>
)
}