import { ApiError, getApiUrl, handleUnauthorized, parseApiResponse, requestApi, type ApiResponse } from './api' import { getToken } from '@/utils/auth' export type WarningAction = 'PUBLISH' | 'RECEIVE' | 'START' | 'HANDLE' | 'CLEAR' | 'RETURN' export interface EarlyWarning { warningId: string warningNo: string warningType?: string warningTypeName?: string warningLevel?: string warningLevelName?: string warningSpecial?: string warningContent?: string deviceCode?: string deviceName?: string location?: string ownershipUnit?: string publisher?: string publisherName?: string handler?: string handlerName?: string reviewer?: string reviewerName?: string status: string statusLabel?: string publishTime?: string createTime?: string availableActions?: WarningAction[] } export interface WarningDisposal { disposal_id?: string disposalId?: string disposal_type?: string disposalType?: string disposalTypeName?: string disposal_user?: string disposalUser?: string disposal_user_name?: string disposalUserName?: string disposal_content?: string disposalContent?: string create_time?: string createTime?: string } export interface WarningAttachment { attachmentId: string attachmentName?: string attachmentType?: string attachmentSize?: number attachmentStage?: string disposalId?: string createTime?: string localUrl?: string } export interface WarningDetail { basicInfo: EarlyWarning disposalHistory: WarningDisposal[] attachmentList: WarningAttachment[] } export interface WarningParticipant { userId: number userName: string nickName: string deptId?: number deptName?: string } export interface WarningQuery { pageNum?: number pageSize?: number keyword?: string status?: string warningType?: string warningLevel?: string } export interface PageResult { records: T[]; total: number; current: number; size: number; pages?: number } interface DataResponse extends ApiResponse { data: T } const BASE = '/api/mobile/warning' const value = (source: Record, camel: string, snake: string) => source[camel] ?? source[snake] function normalizeWarning(source: Record): EarlyWarning { return { ...source, warningId: String(value(source, 'warningId', 'warning_id') || ''), warningNo: String(value(source, 'warningNo', 'warning_no') || ''), warningType: value(source, 'warningType', 'warning_type') as string | undefined, warningTypeName: value(source, 'warningTypeName', 'warning_type_name') as string | undefined, warningLevel: value(source, 'warningLevel', 'warning_level') as string | undefined, warningLevelName: value(source, 'warningLevelName', 'warning_level_name') as string | undefined, warningSpecial: value(source, 'warningSpecial', 'warning_special') as string | undefined, warningContent: value(source, 'warningContent', 'warning_content') as string | undefined, deviceCode: value(source, 'deviceCode', 'device_code') as string | undefined, deviceName: value(source, 'deviceName', 'device_name') as string | undefined, ownershipUnit: value(source, 'ownershipUnit', 'ownership_unit') as string | undefined, publisherName: value(source, 'publisherName', 'publisher_name') as string | undefined, handlerName: value(source, 'handlerName', 'handler_name') as string | undefined, reviewerName: value(source, 'reviewerName', 'reviewer_name') as string | undefined, publishTime: value(source, 'publishTime', 'publish_time') as string | undefined, createTime: value(source, 'createTime', 'create_time') as string | undefined, status: String(source.status || ''), statusLabel: value(source, 'statusLabel', 'status_name') as string | undefined, availableActions: (source.availableActions || []) as WarningAction[], } } export function getMobileWarnings(query: WarningQuery = {}) { return requestApi>>>(BASE, { data: query }).then(result => ({ ...result.data, records: result.data.records.map(normalizeWarning) })) } export function getMobilePendingWarnings(query: WarningQuery = {}) { return requestApi>>>(`${BASE}/pending`, { data: query }).then(result => ({ ...result.data, records: result.data.records.map(normalizeWarning) })) } export function getMobileWarningDetail(id: string) { return requestApi>>(`${BASE}/${encodeURIComponent(id)}`).then(result => { const data = result.data return { basicInfo: normalizeWarning(data.basicInfo as Record), disposalHistory: (data.disposalHistory || []) as WarningDisposal[], attachmentList: (data.attachmentList || []) as WarningAttachment[], } as WarningDetail }) } export const getWarningParticipants = (warningId: string, role: 'handler' | 'reviewer') => requestApi>(`${BASE}/participants`, { data: { warningId, role } }).then(result => result.data) let warningRevision = 0 export const getWarningRevision = () => warningRevision const post = (id: string, action: string, data: Record) => requestApi(`${BASE}/${encodeURIComponent(id)}/${action}`, { method: 'POST', data }).then(result => { warningRevision++ return result }) export const publishWarning = (id: string, handler: string, reviewer: string) => post(id, 'publish', { handler, reviewer }) export const receiveWarning = (id: string, remark: string) => post(id, 'receive', { remark }) export const startWarning = (id: string, remark: string) => post(id, 'start', { remark }) export const processWarning = (id: string, content: string, attachments: string[]) => post(id, 'process', { content, attachments, reasonIds: [] }) export const verifyWarning = (id: string, result: 'CLEAR' | 'RETURN', opinion: string) => post(id, 'verify', { result, opinion }) export function uploadWarningProcessImages(dir: string, filePaths: string[]): Promise { return new Promise((resolve, reject) => { if (!filePaths.length) { resolve([]); return } uni.uploadFile({ url: getApiUrl(`/minio/uploads?dir=${encodeURIComponent(dir)}`), files: filePaths.map(p => ({ name: 'files', uri: p })), header: { Authorization: `Bearer ${getToken()}` }, timeout: 60000, success(response) { try { const result = parseApiResponse }>(response.statusCode, response.data) if (result.code === 200 && Array.isArray(result.files)) { resolve(result.files.map(f => f.relativePath || f.url).filter(Boolean) as string[]) } else { reject(new ApiError(result.msg || '图片上传失败', result.code)) } } catch (error) { reject(error instanceof ApiError ? error : new ApiError('图片上传响应异常')) } }, fail() { reject(new ApiError('图片上传失败,请重试')) }, }) }) } export function downloadWarningAttachment(attachmentId: string): Promise { return new Promise((resolve, reject) => uni.downloadFile({ url: getApiUrl(`${BASE}/attachments/${encodeURIComponent(attachmentId)}`), header: { Authorization: `Bearer ${getToken()}` }, timeout: 60000, success(response) { if (handleUnauthorized(response.statusCode)) reject(new ApiError('登录已失效,请重新登录', 401)) else if (response.statusCode >= 200 && response.statusCode < 300) resolve(response.tempFilePath) else reject(new ApiError('附件读取失败', response.statusCode)) }, fail() { reject(new ApiError('附件读取失败')) }, })) } export const warningStatusText = (status?: string) => ({ DRAFT: '草稿', PENDING: '待接收', RECEIVED: '已接收', PROCESSING: '处置中', HANDLED: '已处置', CLOSED: '已解除' }[status || ''] || '未知') export const warningStatusTone = (status?: string) => status === 'DRAFT' ? 'gray' : status === 'PENDING' ? 'orange' : status === 'PROCESSING' ? 'purple' : ['HANDLED', 'CLOSED'].includes(status || '') ? 'green' : '' export function warningTime(time?: string) { const value = time?.trim().replace('T', ' ') if (!value) return '—' return value.replace(/(\d{2}:\d{2}:\d{2})(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?$/, '$1') } export const isImageAttachment = (item: WarningAttachment) => /image\//i.test(item.attachmentType || '') || /\.(jpe?g|png|gif|webp)$/i.test(item.attachmentName || '')