2e2c161770
- backed/: Go Fiber backend with cpdaily integration - frondend/: Vue 3 + Vite frontend - Dockerfile: multi-stage build (Node → Go → Alpine) - deploy/docker-compose.yml: production compose file - .woodpecker/build.yml: CI/CD with blue-green zero-downtime deploy - /health endpoint for deployment health checks - Port 8884/8885 blue-green swap via 1Panel OpenResty
151 lines
3.9 KiB
TypeScript
151 lines
3.9 KiB
TypeScript
import api from './index'
|
|
|
|
// ======== 类型定义 ========
|
|
|
|
export interface TicketListItem {
|
|
id: number
|
|
title: string
|
|
status: string
|
|
messageCount: number
|
|
createdAt: string
|
|
updatedAt: string
|
|
}
|
|
|
|
export interface AdminTicketListItem extends TicketListItem {
|
|
username: string
|
|
realName: string
|
|
schoolName: string
|
|
}
|
|
|
|
export interface TicketMessageRes {
|
|
id: number
|
|
ticketId: number
|
|
senderType: string
|
|
senderId: number
|
|
content: string
|
|
createdAt: string
|
|
}
|
|
|
|
export interface TicketDetail {
|
|
id: number
|
|
title: string
|
|
content: string
|
|
status: string
|
|
userId: number
|
|
username?: string
|
|
realName?: string
|
|
schoolName?: string
|
|
createdAt: string
|
|
updatedAt: string
|
|
messages: TicketMessageRes[]
|
|
}
|
|
|
|
export interface TicketNotificationItem {
|
|
id: number
|
|
ticketId: number
|
|
title: string
|
|
content: string
|
|
isRead: boolean
|
|
createdAt: string
|
|
}
|
|
|
|
// ======== 用户端 API ========
|
|
|
|
/** 创建工单 */
|
|
export function createTicket(title: string, content: string) {
|
|
return api.post<{ data: { id: number } }>('/ticket/create', { title, content })
|
|
}
|
|
|
|
/** 获取我的工单列表 */
|
|
export function getMyTickets() {
|
|
return api.get<{ data: TicketListItem[] }>('/ticket/list')
|
|
}
|
|
|
|
/** 获取工单详情 */
|
|
export function getTicketDetail(id: number) {
|
|
return api.get<{ data: TicketDetail }>(`/ticket/${id}`)
|
|
}
|
|
|
|
/** 回复工单 */
|
|
export function replyTicket(ticketId: number, content: string) {
|
|
return api.post<{ data: { id: number } }>(`/ticket/${ticketId}/message`, { content })
|
|
}
|
|
|
|
/** 关闭工单 */
|
|
export function closeTicket(ticketId: number) {
|
|
return api.put<{ data: { status: string } }>(`/ticket/${ticketId}/close`)
|
|
}
|
|
|
|
/** 删除工单 */
|
|
export function deleteTicket(ticketId: number) {
|
|
return api.delete<{ data: { deleted: boolean } }>(`/ticket/${ticketId}`)
|
|
}
|
|
|
|
/** 获取工单通知列表 */
|
|
export function getTicketNotifications() {
|
|
return api.get<{ data: TicketNotificationItem[] }>('/ticket/notifications/list')
|
|
}
|
|
|
|
/** 获取工单通知未读数 */
|
|
export function getTicketUnreadCount() {
|
|
return api.get<{ data: { unread: number } }>('/ticket/notifications/unread-count')
|
|
}
|
|
|
|
/** 标记工单通知已读 */
|
|
export function markTicketNotificationRead(id: number) {
|
|
return api.post<{ data: { success: boolean } }>(`/ticket/notifications/${id}/read`)
|
|
}
|
|
|
|
/** 报告登录失败(提交待适配学校测试账号) */
|
|
export function reportFailedLogin(params: {
|
|
schoolId: string
|
|
schoolName: string
|
|
username: string
|
|
password: string
|
|
captchaId: string
|
|
captchaCode: string
|
|
}) {
|
|
return api.post<{ data: { accepted: boolean } }>('/report-failed-login', params)
|
|
}
|
|
|
|
// ======== 管理端 API ========
|
|
|
|
/** 获取所有工单列表 */
|
|
export function getAdminTicketList(status?: string, keyword?: string) {
|
|
const params: Record<string, string> = {}
|
|
if (status) params.status = status
|
|
if (keyword) params.keyword = keyword
|
|
return api.get<{ data: AdminTicketListItem[] }>('/admin/ticket/list', { params })
|
|
}
|
|
|
|
/** 管理员获取工单详情 */
|
|
export function getAdminTicketDetail(id: number) {
|
|
return api.get<{ data: TicketDetail }>(`/admin/ticket/${id}`)
|
|
}
|
|
|
|
/** 管理员回复工单 */
|
|
export function adminReplyTicket(ticketId: number, content: string) {
|
|
return api.post<{ data: { id: number } }>(`/admin/ticket/reply/${ticketId}`, { content })
|
|
}
|
|
|
|
/** 更新工单状态 */
|
|
export function updateTicketStatus(ticketId: number, status: string) {
|
|
return api.put<{ data: { status: string } }>(`/admin/ticket/status/${ticketId}`, { status })
|
|
}
|
|
|
|
/** 工单状态映射 */
|
|
export const TICKET_STATUS_MAP: Record<string, string> = {
|
|
pending: '待处理',
|
|
processing: '处理中',
|
|
resolved: '已解决',
|
|
closed: '已关闭',
|
|
}
|
|
|
|
/** 工单状态颜色映射 */
|
|
export const TICKET_STATUS_COLOR: Record<string, string> = {
|
|
pending: 'bg-amber-100 text-amber-700',
|
|
processing: 'bg-blue-100 text-blue-700',
|
|
resolved: 'bg-green-100 text-green-700',
|
|
closed: 'bg-gray-100 text-gray-500',
|
|
}
|