warnings.ts 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import { ApiError, getApiUrl, handleUnauthorized, parseApiResponse, requestApi, type ApiResponse } from './api'
  2. import { getToken } from '@/utils/auth'
  3. export type WarningAction = 'PUBLISH' | 'RECEIVE' | 'START' | 'HANDLE' | 'CLEAR' | 'RETURN'
  4. export interface EarlyWarning {
  5. warningId: string
  6. warningNo: string
  7. warningType?: string
  8. warningTypeName?: string
  9. warningLevel?: string
  10. warningLevelName?: string
  11. warningSpecial?: string
  12. warningContent?: string
  13. deviceCode?: string
  14. deviceName?: string
  15. location?: string
  16. ownershipUnit?: string
  17. publisher?: string
  18. publisherName?: string
  19. handler?: string
  20. handlerName?: string
  21. reviewer?: string
  22. reviewerName?: string
  23. status: string
  24. statusLabel?: string
  25. publishTime?: string
  26. createTime?: string
  27. availableActions?: WarningAction[]
  28. }
  29. export interface WarningDisposal {
  30. disposal_id?: string
  31. disposalId?: string
  32. disposal_type?: string
  33. disposalType?: string
  34. disposalTypeName?: string
  35. disposal_user?: string
  36. disposalUser?: string
  37. disposal_user_name?: string
  38. disposalUserName?: string
  39. disposal_content?: string
  40. disposalContent?: string
  41. create_time?: string
  42. createTime?: string
  43. }
  44. export interface WarningAttachment {
  45. attachmentId: string
  46. attachmentName?: string
  47. attachmentType?: string
  48. attachmentSize?: number
  49. attachmentStage?: string
  50. disposalId?: string
  51. createTime?: string
  52. localUrl?: string
  53. }
  54. export interface WarningDetail {
  55. basicInfo: EarlyWarning
  56. disposalHistory: WarningDisposal[]
  57. attachmentList: WarningAttachment[]
  58. }
  59. export interface WarningParticipant {
  60. userId: number
  61. userName: string
  62. nickName: string
  63. deptId?: number
  64. deptName?: string
  65. }
  66. export interface WarningQuery {
  67. pageNum?: number
  68. pageSize?: number
  69. keyword?: string
  70. status?: string
  71. warningType?: string
  72. warningLevel?: string
  73. }
  74. export interface PageResult<T> { records: T[]; total: number; current: number; size: number; pages?: number }
  75. interface DataResponse<T> extends ApiResponse { data: T }
  76. const BASE = '/api/mobile/warning'
  77. const value = (source: Record<string, unknown>, camel: string, snake: string) => source[camel] ?? source[snake]
  78. function normalizeWarning(source: Record<string, unknown>): EarlyWarning {
  79. return {
  80. ...source,
  81. warningId: String(value(source, 'warningId', 'warning_id') || ''),
  82. warningNo: String(value(source, 'warningNo', 'warning_no') || ''),
  83. warningType: value(source, 'warningType', 'warning_type') as string | undefined,
  84. warningTypeName: value(source, 'warningTypeName', 'warning_type_name') as string | undefined,
  85. warningLevel: value(source, 'warningLevel', 'warning_level') as string | undefined,
  86. warningLevelName: value(source, 'warningLevelName', 'warning_level_name') as string | undefined,
  87. warningSpecial: value(source, 'warningSpecial', 'warning_special') as string | undefined,
  88. warningContent: value(source, 'warningContent', 'warning_content') as string | undefined,
  89. deviceCode: value(source, 'deviceCode', 'device_code') as string | undefined,
  90. deviceName: value(source, 'deviceName', 'device_name') as string | undefined,
  91. ownershipUnit: value(source, 'ownershipUnit', 'ownership_unit') as string | undefined,
  92. publisherName: value(source, 'publisherName', 'publisher_name') as string | undefined,
  93. handlerName: value(source, 'handlerName', 'handler_name') as string | undefined,
  94. reviewerName: value(source, 'reviewerName', 'reviewer_name') as string | undefined,
  95. publishTime: value(source, 'publishTime', 'publish_time') as string | undefined,
  96. createTime: value(source, 'createTime', 'create_time') as string | undefined,
  97. status: String(source.status || ''),
  98. statusLabel: value(source, 'statusLabel', 'status_name') as string | undefined,
  99. availableActions: (source.availableActions || []) as WarningAction[],
  100. }
  101. }
  102. export function getMobileWarnings(query: WarningQuery = {}) {
  103. return requestApi<DataResponse<PageResult<Record<string, unknown>>>>(BASE, { data: query }).then(result => ({ ...result.data, records: result.data.records.map(normalizeWarning) }))
  104. }
  105. export function getMobilePendingWarnings(query: WarningQuery = {}) {
  106. return requestApi<DataResponse<PageResult<Record<string, unknown>>>>(`${BASE}/pending`, { data: query }).then(result => ({ ...result.data, records: result.data.records.map(normalizeWarning) }))
  107. }
  108. export function getMobileWarningDetail(id: string) {
  109. return requestApi<DataResponse<Record<string, unknown>>>(`${BASE}/${encodeURIComponent(id)}`).then(result => {
  110. const data = result.data
  111. return {
  112. basicInfo: normalizeWarning(data.basicInfo as Record<string, unknown>),
  113. disposalHistory: (data.disposalHistory || []) as WarningDisposal[],
  114. attachmentList: (data.attachmentList || []) as WarningAttachment[],
  115. } as WarningDetail
  116. })
  117. }
  118. export const getWarningParticipants = (warningId: string, role: 'handler' | 'reviewer') => requestApi<DataResponse<WarningParticipant[]>>(`${BASE}/participants`, { data: { warningId, role } }).then(result => result.data)
  119. let warningRevision = 0
  120. export const getWarningRevision = () => warningRevision
  121. const post = (id: string, action: string, data: Record<string, unknown>) => requestApi<ApiResponse>(`${BASE}/${encodeURIComponent(id)}/${action}`, { method: 'POST', data }).then(result => {
  122. warningRevision++
  123. return result
  124. })
  125. export const publishWarning = (id: string, handler: string, reviewer: string) => post(id, 'publish', { handler, reviewer })
  126. export const receiveWarning = (id: string, remark: string) => post(id, 'receive', { remark })
  127. export const startWarning = (id: string, remark: string) => post(id, 'start', { remark })
  128. export const processWarning = (id: string, content: string, attachments: string[]) => post(id, 'process', { content, attachments, reasonIds: [] })
  129. export const verifyWarning = (id: string, result: 'CLEAR' | 'RETURN', opinion: string) => post(id, 'verify', { result, opinion })
  130. export function uploadWarningProcessImages(dir: string, filePaths: string[]): Promise<string[]> {
  131. return new Promise((resolve, reject) => {
  132. if (!filePaths.length) { resolve([]); return }
  133. uni.uploadFile({
  134. url: getApiUrl(`/minio/uploads?dir=${encodeURIComponent(dir)}`),
  135. files: filePaths.map(p => ({ name: 'files', uri: p })),
  136. header: { Authorization: `Bearer ${getToken()}` }, timeout: 60000,
  137. success(response) {
  138. try {
  139. const result = parseApiResponse<ApiResponse & { files?: Array<{ relativePath?: string; url?: string }> }>(response.statusCode, response.data)
  140. if (result.code === 200 && Array.isArray(result.files)) {
  141. resolve(result.files.map(f => f.relativePath || f.url).filter(Boolean) as string[])
  142. } else {
  143. reject(new ApiError(result.msg || '图片上传失败', result.code))
  144. }
  145. } catch (error) { reject(error instanceof ApiError ? error : new ApiError('图片上传响应异常')) }
  146. },
  147. fail() { reject(new ApiError('图片上传失败,请重试')) },
  148. })
  149. })
  150. }
  151. export function downloadWarningAttachment(attachmentId: string): Promise<string> {
  152. return new Promise((resolve, reject) => uni.downloadFile({
  153. url: getApiUrl(`${BASE}/attachments/${encodeURIComponent(attachmentId)}`),
  154. header: { Authorization: `Bearer ${getToken()}` }, timeout: 60000,
  155. success(response) {
  156. if (handleUnauthorized(response.statusCode)) reject(new ApiError('登录已失效,请重新登录', 401))
  157. else if (response.statusCode >= 200 && response.statusCode < 300) resolve(response.tempFilePath)
  158. else reject(new ApiError('附件读取失败', response.statusCode))
  159. },
  160. fail() { reject(new ApiError('附件读取失败')) },
  161. }))
  162. }
  163. export const warningStatusText = (status?: string) => ({ DRAFT: '草稿', PENDING: '待接收', RECEIVED: '已接收', PROCESSING: '处置中', HANDLED: '已处置', CLOSED: '已解除' }[status || ''] || '未知')
  164. export const warningStatusTone = (status?: string) => status === 'DRAFT' ? 'gray' : status === 'PENDING' ? 'orange' : status === 'PROCESSING' ? 'purple' : ['HANDLED', 'CLOSED'].includes(status || '') ? 'green' : ''
  165. export function warningTime(time?: string) {
  166. const value = time?.trim().replace('T', ' ')
  167. if (!value) return '—'
  168. return value.replace(/(\d{2}:\d{2}:\d{2})(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?$/, '$1')
  169. }
  170. export const isImageAttachment = (item: WarningAttachment) => /image\//i.test(item.attachmentType || '') || /\.(jpe?g|png|gif|webp)$/i.test(item.attachmentName || '')