Files
cpdaily_xiaozhushou/frondend/src/api/ticket.ts
T
becomer 2e2c161770 feat: init cpdaily-xiaozhushou with blue-green deploy
- 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
2026-07-03 15:37:55 +08:00

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',
}