index.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. import axios from 'axios'
  2. // ==================== Axios 实例 ====================
  3. const api = axios.create({
  4. baseURL: '/api/v1',
  5. timeout: 30000,
  6. headers: {
  7. 'Content-Type': 'application/json'
  8. }
  9. })
  10. // 请求拦截器 - 自动附加 Token
  11. api.interceptors.request.use(
  12. config => {
  13. const token = localStorage.getItem('accessToken')
  14. if (token) {
  15. config.headers.Authorization = `Bearer ${token}`
  16. }
  17. return config
  18. },
  19. error => Promise.reject(error)
  20. )
  21. // 响应拦截器
  22. api.interceptors.response.use(
  23. response => {
  24. const { data } = response
  25. if (data.code === 200) {
  26. return data.data
  27. }
  28. return Promise.reject(new Error(data.message || '请求失败'))
  29. },
  30. error => {
  31. if (error.response?.status === 401 || error.response?.status === 403) {
  32. localStorage.removeItem('accessToken')
  33. localStorage.removeItem('refreshToken')
  34. localStorage.removeItem('username')
  35. if (!window.location.pathname.includes('/login')) {
  36. window.location.href = '/login'
  37. }
  38. }
  39. const msg = error.response?.data?.message || error.message || '网络错误'
  40. return Promise.reject(new Error(msg))
  41. }
  42. )
  43. // ==================== 认证 API ====================
  44. export const authApi = {
  45. login(data) {
  46. return api.post('/auth/login', { username: data.usernameOrEmail || data.username, password: data.password })
  47. },
  48. logout() {
  49. return api.post('/auth/logout')
  50. },
  51. refreshToken(refreshToken) {
  52. return api.post('/auth/refresh', { refreshToken })
  53. },
  54. getCurrentUser() {
  55. return api.get('/auth/me')
  56. },
  57. getPermissions() {
  58. return api.get('/auth/permissions')
  59. },
  60. changePassword(data) {
  61. return api.put('/auth/password', data)
  62. }
  63. }
  64. // ==================== 项目 API ====================
  65. export const projectApi = {
  66. list(params = {}) {
  67. return api.get('/projects', { params })
  68. },
  69. getById(id) {
  70. return api.get(`/projects/${id}`)
  71. },
  72. create(data) {
  73. return api.post('/projects', data)
  74. },
  75. update(id, data) {
  76. return api.put(`/projects/${id}`, data)
  77. },
  78. delete(id) {
  79. return api.delete(`/projects/${id}`)
  80. },
  81. copy(id) {
  82. return api.post(`/projects/${id}/copy`)
  83. },
  84. archive(id) {
  85. return api.post(`/projects/${id}/archive`)
  86. },
  87. export(id) {
  88. return api.get(`/projects/${id}/export`, { responseType: 'blob' })
  89. },
  90. getDocContent(id) {
  91. return api.get(`/projects/${id}/doc-content`)
  92. }
  93. }
  94. // ==================== 要素 API ====================
  95. export const elementApi = {
  96. list(projectId) {
  97. return api.get(`/projects/${projectId}/elements`)
  98. },
  99. add(projectId, data) {
  100. return api.post(`/projects/${projectId}/elements`, data)
  101. },
  102. update(projectId, elementId, data) {
  103. return api.put(`/projects/${projectId}/elements/${elementId}`, data)
  104. },
  105. delete(projectId, elementId) {
  106. return api.delete(`/projects/${projectId}/elements/${elementId}`)
  107. }
  108. }
  109. // ==================== 要素值 API ====================
  110. export const valueApi = {
  111. list(projectId) {
  112. return api.get(`/projects/${projectId}/values`)
  113. },
  114. getByKey(projectId, elementKey) {
  115. return api.get(`/projects/${projectId}/values/${elementKey}`)
  116. },
  117. update(projectId, elementKey, data) {
  118. return api.put(`/projects/${projectId}/values/${encodeURIComponent(elementKey)}`, data)
  119. },
  120. batchUpdate(projectId, values) {
  121. return api.put(`/projects/${projectId}/values`, values)
  122. }
  123. }
  124. // ==================== 附件 API ====================
  125. export const attachmentApi = {
  126. list(projectId) {
  127. return api.get(`/projects/${projectId}/attachments`)
  128. },
  129. getById(attachmentId) {
  130. return api.get(`/attachments/${attachmentId}`)
  131. },
  132. upload(projectId, file, displayName = null) {
  133. const formData = new FormData()
  134. formData.append('file', file)
  135. if (displayName) {
  136. formData.append('displayName', displayName)
  137. }
  138. return api.post(`/projects/${projectId}/attachments/upload`, formData, {
  139. headers: { 'Content-Type': 'multipart/form-data' }
  140. })
  141. },
  142. delete(attachmentId) {
  143. return api.delete(`/attachments/${attachmentId}`)
  144. },
  145. parse(attachmentId) {
  146. return api.post(`/attachments/${attachmentId}/parse`)
  147. },
  148. saveParsedContent(attachmentId, parsedText) {
  149. return api.put(`/attachments/${attachmentId}/parsed-content`, { parsedText })
  150. },
  151. getParsedText(attachmentId) {
  152. return api.get(`/attachments/${attachmentId}/parsed-text`)
  153. },
  154. parseDocx(file) {
  155. const formData = new FormData()
  156. formData.append('file', file)
  157. return api.post('/tools/parse-docx', formData, {
  158. headers: { 'Content-Type': 'multipart/form-data' },
  159. timeout: 120000
  160. })
  161. },
  162. sort(projectId, orderedIds) {
  163. return api.put(`/projects/${projectId}/attachments/sort`, orderedIds)
  164. },
  165. getDocContent(attachmentId) {
  166. return api.get(`/attachments/${attachmentId}/doc-content`)
  167. }
  168. }
  169. // ==================== 规则 API ====================
  170. export const ruleApi = {
  171. list(projectId) {
  172. return api.get(`/projects/${projectId}/rules`)
  173. },
  174. getById(ruleId) {
  175. return api.get(`/rules/${ruleId}`)
  176. },
  177. create(projectId, data) {
  178. return api.post(`/projects/${projectId}/rules`, data)
  179. },
  180. update(ruleId, data) {
  181. return api.put(`/rules/${ruleId}`, data)
  182. },
  183. delete(ruleId) {
  184. return api.delete(`/rules/${ruleId}`)
  185. },
  186. execute(ruleId) {
  187. return api.post(`/rules/${ruleId}/execute`)
  188. },
  189. batchExecute(projectId) {
  190. return api.post(`/projects/${projectId}/rules/execute`)
  191. }
  192. }
  193. // ==================== 文件 API ====================
  194. export const fileApi = {
  195. upload(file) {
  196. const formData = new FormData()
  197. formData.append('file', file)
  198. return api.post('/files/upload', formData, {
  199. headers: { 'Content-Type': 'multipart/form-data' }
  200. })
  201. },
  202. getDownloadUrl(fileKey) {
  203. return `/api/v1/files/${fileKey}`
  204. },
  205. getPreviewUrl(fileKey) {
  206. return `/api/v1/files/${fileKey}/preview`
  207. },
  208. delete(fileKey) {
  209. return api.delete(`/files/${fileKey}`)
  210. }
  211. }
  212. // ==================== 任务 API ====================
  213. export const taskApi = {
  214. list(params = {}) {
  215. return api.get('/tasks', { params })
  216. },
  217. getById(taskId) {
  218. return api.get(`/tasks/${taskId}`)
  219. },
  220. cancel(taskId) {
  221. return api.post(`/tasks/${taskId}/cancel`)
  222. }
  223. }
  224. // ==================== 用户管理 API ====================
  225. export const userApi = {
  226. list(params = {}) {
  227. return api.get('/users', { params })
  228. },
  229. getById(id) {
  230. return api.get(`/users/${id}`)
  231. },
  232. create(data) {
  233. return api.post('/users', data)
  234. },
  235. update(id, data) {
  236. return api.put(`/users/${id}`, data)
  237. },
  238. delete(id) {
  239. return api.delete(`/users/${id}`)
  240. }
  241. }
  242. // ==================== AI API ====================
  243. export const aiApi = {
  244. extractEntities(data) {
  245. return api.post('/ai/ner', data)
  246. },
  247. chat(data) {
  248. return api.post('/ai/chat', data)
  249. },
  250. suggest(data) {
  251. return api.post('/ai/suggest', data)
  252. },
  253. optimize(data) {
  254. return api.post('/ai/optimize', data)
  255. }
  256. }
  257. // ==================== PDF 解析 API (外部服务) ====================
  258. const parseService = axios.create({
  259. baseURL: 'http://47.108.80.98:4214',
  260. timeout: 120000
  261. })
  262. export const parseApi = {
  263. // 提交 PDF/图片解析任务
  264. submit(file, options = {}) {
  265. const formData = new FormData()
  266. formData.append('file', file)
  267. if (options.backend) formData.append('backend', options.backend)
  268. if (options.remove_watermark) formData.append('remove_watermark', 'true')
  269. if (options.crop_header_footer) formData.append('crop_header_footer', 'true')
  270. if (options.return_images) formData.append('return_images', 'true')
  271. return parseService.post('/pdf_to_markdown', formData, {
  272. headers: { 'Content-Type': 'multipart/form-data' }
  273. }).then(r => r.data)
  274. },
  275. // 查询任务状态
  276. getStatus(taskId) {
  277. return parseService.get(`/task/${taskId}`).then(r => r.data)
  278. },
  279. // 获取解析结果 JSON { markdown, filename }
  280. getResult(taskId) {
  281. return parseService.get(`/task/${taskId}/json`).then(r => r.data)
  282. },
  283. // 下载 markdown 文件
  284. downloadMarkdown(taskId) {
  285. return parseService.get(`/download/${taskId}/markdown`, { responseType: 'blob' }).then(r => r.data)
  286. },
  287. // 下载 zip 包(markdown + 图片)
  288. downloadZip(taskId) {
  289. return parseService.get(`/download/${taskId}/zip`, { responseType: 'blob' }).then(r => r.data)
  290. },
  291. // 获取解析任务的图片 URL 基础路径
  292. getImageBaseUrl(taskId) {
  293. return `http://47.108.80.98:4214/download/${taskId}/images`
  294. }
  295. }
  296. export default api